Initial commit: add .gitignore and README
Some checks failed
Tests / test (3.10) (push) Has been cancelled
Tests / test (3.11) (push) Has been cancelled
Tests / test (3.12) (push) Has been cancelled
Tests / lint (push) Has been cancelled
Tests / docker (push) Has been cancelled

This commit is contained in:
defiQUG
2026-02-09 21:51:42 -08:00
commit c052b07662
3146 changed files with 808305 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
"""Structured schemas for tasks, messages, plans, self-improvement, and AGI."""
from fusionagi.schemas.task import Task, TaskState, TaskPriority
from fusionagi.schemas.messages import AgentMessage, AgentMessageEnvelope
from fusionagi.schemas.plan import Plan, PlanStep
from fusionagi.schemas.recommendation import (
Recommendation,
RecommendationKind,
TrainingSuggestion,
TrainingSuggestionKind,
)
from fusionagi.schemas.goal import Goal, GoalBudget, GoalStatus, Blocker, Checkpoint
from fusionagi.schemas.grounding import Citation, GroundedClaim
from fusionagi.schemas.skill import Skill, SkillKind, SkillVersionInfo
from fusionagi.schemas.audit import AuditEntry, AuditEventType
from fusionagi.schemas.policy import PolicyRule, PolicyEffect
from fusionagi.schemas.world_model import StateTransition, UncertaintyInfo
from fusionagi.schemas.head import HeadId, HeadClaim, HeadRisk, HeadOutput
from fusionagi.schemas.witness import AgreementMap, TransparencyReport, FinalResponse
from fusionagi.schemas.commands import UserIntent, ParsedCommand, parse_user_input
from fusionagi.schemas.atomic import (
AtomicUnitType,
RelationType,
AtomicSemanticUnit,
SemanticRelation,
DecompositionResult,
)
__all__ = [
"Task",
"TaskState",
"TaskPriority",
"AgentMessage",
"AgentMessageEnvelope",
"Plan",
"PlanStep",
"Recommendation",
"RecommendationKind",
"TrainingSuggestion",
"TrainingSuggestionKind",
"Goal",
"GoalBudget",
"GoalStatus",
"Blocker",
"Checkpoint",
"Citation",
"GroundedClaim",
"Skill",
"SkillKind",
"SkillVersionInfo",
"AuditEntry",
"AuditEventType",
"PolicyRule",
"PolicyEffect",
"StateTransition",
"UncertaintyInfo",
"HeadId",
"HeadClaim",
"HeadRisk",
"HeadOutput",
"AgreementMap",
"TransparencyReport",
"FinalResponse",
"UserIntent",
"ParsedCommand",
"parse_user_input",
"AtomicUnitType",
"RelationType",
"AtomicSemanticUnit",
"SemanticRelation",
"DecompositionResult",
]

View File

@@ -0,0 +1,65 @@
"""Atomic semantic units for Super Big Brain: tokenless, addressable context."""
from enum import Enum
from typing import Any
from pydantic import BaseModel, Field
class AtomicUnitType(str, Enum):
"""Type of atomic semantic unit."""
FACT = "fact"
INTENT = "intent"
ASSUMPTION = "assumption"
CONSTRAINT = "constraint"
RELATIONSHIP = "relationship"
QUESTION = "question"
class RelationType(str, Enum):
"""Type of relation between atomic units."""
CAUSAL = "causal"
TEMPORAL = "temporal"
LOGICAL = "logical"
ANALOGICAL = "analogical"
CONTRADICTS = "contradicts"
SUPPORTS = "supports"
class AtomicSemanticUnit(BaseModel):
"""Atomic semantic unit: irreducible fact, intent, assumption, or constraint."""
unit_id: str = Field(..., min_length=1, description="Unique identifier")
content: str = Field(..., min_length=1, description="Unit content")
type: AtomicUnitType = Field(..., description="Unit type")
confidence: float = Field(default=1.0, ge=0.0, le=1.0, description="Confidence in [0, 1]")
parent_id: str | None = Field(default=None, description="Parent unit in decomposition tree")
source_ref: str | None = Field(default=None, description="Source reference")
metadata: dict[str, Any] = Field(default_factory=dict)
class SemanticRelation(BaseModel):
"""Relation between two atomic semantic units."""
from_id: str = Field(..., min_length=1)
to_id: str = Field(..., min_length=1)
relation_type: RelationType = Field(...)
class DecompositionResult(BaseModel):
"""Result of recursive decomposition: atomic units and relations."""
units: list[AtomicSemanticUnit] = Field(default_factory=list)
relations: list[SemanticRelation] = Field(default_factory=list)
depth: int = Field(default=0, ge=0, description="Maximum decomposition depth")
__all__ = [
"AtomicUnitType",
"RelationType",
"AtomicSemanticUnit",
"SemanticRelation",
"DecompositionResult",
]

View File

@@ -0,0 +1,38 @@
"""Audit log schemas for AGI governance."""
from datetime import datetime, timezone
from enum import Enum
from typing import Any
from pydantic import BaseModel, Field
def _utc_now() -> datetime:
return datetime.now(timezone.utc)
class AuditEventType(str, Enum):
"""Type of auditable event."""
DECISION = "decision"
TOOL_CALL = "tool_call"
DATA_SOURCE = "data_source"
STATE_CHANGE = "state_change"
TASK_SUBMIT = "task_submit"
TASK_COMPLETE = "task_complete"
OVERRIDE = "override"
POLICY_CHECK = "policy_check"
OTHER = "other"
class AuditEntry(BaseModel):
"""Single audit log entry: every material decision, tool call, source, outcome."""
entry_id: str = Field(..., min_length=1)
event_type: AuditEventType = Field(default=AuditEventType.OTHER)
actor: str = Field(default="", description="Agent or system component")
task_id: str | None = Field(default=None)
action: str = Field(default="")
payload: dict[str, Any] = Field(default_factory=dict)
outcome: str = Field(default="")
timestamp: datetime = Field(default_factory=_utc_now)

View File

@@ -0,0 +1,93 @@
"""Interaction commands and user intent for Dvādaśa UX."""
import re
from enum import Enum
from typing import Any
from pydantic import BaseModel, Field
from fusionagi.schemas.head import HeadId
class UserIntent(str, Enum):
"""User intent derived from commands or natural input."""
NORMAL = "normal"
HEAD_STRATEGY = "head_strategy"
SHOW_DISSENT = "show_dissent"
RERUN_RISK = "rerun_risk"
EXPLAIN_REASONING = "explain_reasoning"
SOURCES = "sources"
# Command patterns: /command [arg] or /command \n prompt
_COMMAND_PATTERNS: list[tuple[re.Pattern[str], UserIntent]] = [
(re.compile(r"^/head\s+(\w+)(?:\s+(.+))?\s*$", re.I | re.DOTALL), UserIntent.HEAD_STRATEGY),
(re.compile(r"^/show\s+dissent(?:\s+(.+))?\s*$", re.I | re.DOTALL), UserIntent.SHOW_DISSENT),
(re.compile(r"^/rerun\s+risk(?:\s+(.+))?\s*$", re.I | re.DOTALL), UserIntent.RERUN_RISK),
(re.compile(r"^/explain\s+reasoning(?:\s+(.+))?\s*$", re.I | re.DOTALL), UserIntent.EXPLAIN_REASONING),
(re.compile(r"^/sources(?:\s+(.+))?\s*$", re.I | re.DOTALL), UserIntent.SOURCES),
]
class ParsedCommand(BaseModel):
"""Parsed user command with intent and optional arguments."""
intent: UserIntent = Field(..., description="Detected intent")
head_id: HeadId | None = Field(default=None, description="For HEAD_STRATEGY: which head")
raw_input: str = Field(default="", description="Original user input")
cleaned_prompt: str = Field(default="", description="Prompt with command stripped if applicable")
def parse_user_input(text: str) -> ParsedCommand:
"""
Parse user input to detect commands and extract intent.
Examples:
"/head strategy" -> HEAD_STRATEGY, head_id=STRATEGY
"/show dissent" -> SHOW_DISSENT
"What is X?" -> NORMAL, cleaned_prompt="What is X?"
"""
stripped = (text or "").strip()
if not stripped:
return ParsedCommand(
intent=UserIntent.NORMAL,
raw_input=stripped,
cleaned_prompt=stripped,
)
for pattern, intent in _COMMAND_PATTERNS:
match = pattern.match(stripped)
if match:
head_id = None
cleaned = ""
if intent == UserIntent.HEAD_STRATEGY:
arg = (match.group(1) or "").lower()
rest = match.group(2) if match.lastindex and match.lastindex >= 2 else None
cleaned = (rest or "").strip()
try:
head_id = HeadId(arg)
except ValueError:
head_id = None
else:
rest = match.group(1) if match.lastindex and match.lastindex >= 1 else None
cleaned = (rest or "").strip()
return ParsedCommand(
intent=intent,
head_id=head_id,
raw_input=stripped,
cleaned_prompt=cleaned,
)
return ParsedCommand(
intent=UserIntent.NORMAL,
raw_input=stripped,
cleaned_prompt=stripped,
)
__all__ = [
"UserIntent",
"ParsedCommand",
"parse_user_input",
]

70
fusionagi/schemas/goal.py Normal file
View File

@@ -0,0 +1,70 @@
"""Goal and budget schemas for AGI executive layer."""
from datetime import datetime, timezone
from enum import Enum
from typing import Any
from pydantic import BaseModel, Field, field_validator
def _utc_now() -> datetime:
return datetime.now(timezone.utc)
class GoalStatus(str, Enum):
"""Goal lifecycle status."""
ACTIVE = "active"
ACHIEVED = "achieved"
ABANDONED = "abandoned"
BLOCKED = "blocked"
SUSPENDED = "suspended"
class GoalBudget(BaseModel):
"""Time and compute budget for a goal/task."""
time_seconds: float | None = Field(default=None, ge=0, description="Max wall-clock seconds")
compute_budget: float | None = Field(default=None, ge=0, description="Max compute units (e.g. token budget)")
started_at: datetime | None = Field(default=None, description="When execution started")
class Blocker(BaseModel):
"""Reason a task or goal is stuck."""
blocker_id: str = Field(..., min_length=1)
task_id: str = Field(..., min_length=1)
reason: str = Field(default="")
dependency_step_id: str | None = Field(default=None)
reported_at: datetime = Field(default_factory=_utc_now)
class Checkpoint(BaseModel):
"""Resumable point in task execution."""
checkpoint_id: str = Field(..., min_length=1)
task_id: str = Field(..., min_length=1)
step_ids_completed: list[str] = Field(default_factory=list)
state_snapshot: dict[str, Any] = Field(default_factory=dict)
created_at: datetime = Field(default_factory=_utc_now)
class Goal(BaseModel):
"""Explicit goal with objectives, priorities, constraints, and budget."""
goal_id: str = Field(..., min_length=1)
objective: str = Field(..., min_length=1)
constraints: list[str] = Field(default_factory=list)
priority: int = Field(default=0, ge=0, le=10)
status: GoalStatus = Field(default=GoalStatus.ACTIVE)
budget: GoalBudget | None = Field(default=None)
metadata: dict[str, Any] = Field(default_factory=dict)
created_at: datetime = Field(default_factory=_utc_now)
updated_at: datetime | None = Field(default=None)
@field_validator("goal_id", "objective")
@classmethod
def validate_non_whitespace(cls, v: str) -> str:
if not v.strip():
raise ValueError("Field cannot be empty or whitespace")
return v

View File

@@ -0,0 +1,30 @@
"""Grounding schemas: citations, sources, show-your-work for AGI verification."""
from datetime import datetime, timezone
from typing import Any
from pydantic import BaseModel, Field
def _utc_now() -> datetime:
return datetime.now(timezone.utc)
class Citation(BaseModel):
"""Reference to a source supporting a claim."""
source_id: str = Field(..., min_length=1, description="e.g. doc id, URL, trace step")
excerpt: str = Field(default="", description="Relevant excerpt or quote")
confidence: float = Field(default=1.0, ge=0.0, le=1.0)
metadata: dict[str, Any] = Field(default_factory=dict)
class GroundedClaim(BaseModel):
"""A claim with citations and optional show-your-work trace."""
claim_id: str = Field(..., min_length=1)
claim: str = Field(..., min_length=1)
citations: list[Citation] = Field(default_factory=list)
reasoning_trace: list[dict[str, Any]] = Field(default_factory=list, description="Show-your-work steps")
confidence: float = Field(default=1.0, ge=0.0, le=1.0)
created_at: datetime = Field(default_factory=_utc_now)

61
fusionagi/schemas/head.py Normal file
View File

@@ -0,0 +1,61 @@
"""Dvādaśa head output schemas: claims, risks, structured outputs per head."""
from enum import Enum
from typing import Any
from pydantic import BaseModel, Field
from fusionagi.schemas.grounding import Citation
class HeadId(str, Enum):
"""Identifiers for the 11 content heads plus Witness meta-controller."""
LOGIC = "logic"
RESEARCH = "research"
SYSTEMS = "systems"
STRATEGY = "strategy"
PRODUCT = "product"
SECURITY = "security"
SAFETY = "safety"
RELIABILITY = "reliability"
COST = "cost"
DATA = "data"
DEVEX = "devex"
WITNESS = "witness"
class HeadClaim(BaseModel):
"""Atomic statement from a head with confidence and evidence."""
claim_text: str = Field(..., min_length=1, description="The atomic claim statement")
confidence: float = Field(..., ge=0.0, le=1.0, description="Confidence in [0, 1]")
evidence: list[Citation] = Field(default_factory=list, description="Citations, tool results, reasoning steps")
assumptions: list[str] = Field(default_factory=list, description="Assumptions made")
class HeadRisk(BaseModel):
"""Risk or failure mode identified by a head."""
description: str = Field(..., min_length=1, description="Description of the risk")
severity: str = Field(default="medium", description="low, medium, high, critical")
class HeadOutput(BaseModel):
"""Structured output from a Dvādaśa head."""
head_id: HeadId = Field(..., description="Which head produced this")
summary: str = Field(..., min_length=1, description="13 sentence summary")
claims: list[HeadClaim] = Field(default_factory=list, description="Atomic claims with confidence")
risks: list[HeadRisk] = Field(default_factory=list, description="Failure modes identified")
questions: list[str] = Field(default_factory=list, description="Only if absolutely necessary")
recommended_actions: list[str] = Field(default_factory=list, description="Suggested next steps")
tone_guidance: str = Field(default="", description="For persona consistency")
__all__ = [
"HeadId",
"HeadClaim",
"HeadRisk",
"HeadOutput",
]

View File

@@ -0,0 +1,94 @@
"""Agent message schema: sender, recipient, intent, payload, confidence/uncertainty."""
from datetime import datetime
from typing import Any
from pydantic import BaseModel, Field, field_validator
from fusionagi._time import utc_now
class AgentMessage(BaseModel):
"""
Structured message between agents.
Includes validation for:
- Non-empty sender, recipient, and intent
- Confidence in valid [0, 1] range
"""
sender: str = Field(..., min_length=1, description="Agent id of sender")
recipient: str = Field(..., min_length=1, description="Agent id of recipient")
intent: str = Field(..., min_length=1, description="Message intent e.g. plan_ready, execute_step")
payload: dict[str, Any] = Field(default_factory=dict, description="Message payload")
confidence: float | None = Field(default=None, ge=0.0, le=1.0, description="Optional confidence [0,1]")
uncertainty: str | None = Field(default=None, description="Optional uncertainty note")
timestamp: datetime = Field(default_factory=utc_now, description="Message timestamp")
@field_validator("sender", "recipient", "intent")
@classmethod
def validate_non_whitespace(cls, v: str) -> str:
"""Validate string fields are not just whitespace."""
if not v.strip():
raise ValueError("Field cannot be empty or whitespace")
return v
@field_validator("confidence")
@classmethod
def validate_confidence(cls, v: float | None) -> float | None:
"""Validate confidence is in [0, 1] range."""
if v is not None and (v < 0.0 or v > 1.0):
raise ValueError("confidence must be between 0 and 1")
return v
class AgentMessageEnvelope(BaseModel):
"""
Top-level envelope for agent messages; can carry task context.
The envelope wraps a message and provides additional context:
- task_id: Associates the message with a specific task
- correlation_id: Enables request/response tracking
"""
message: AgentMessage = Field(..., description="The wrapped message")
task_id: str | None = Field(default=None, description="Associated task id if any")
correlation_id: str | None = Field(default=None, description="For request/response correlation")
@property
def sender(self) -> str:
"""Convenience accessor for message sender."""
return self.message.sender
@property
def recipient(self) -> str:
"""Convenience accessor for message recipient."""
return self.message.recipient
@property
def intent(self) -> str:
"""Convenience accessor for message intent."""
return self.message.intent
def create_response(
self,
intent: str,
payload: dict[str, Any] | None = None,
confidence: float | None = None,
) -> "AgentMessageEnvelope":
"""
Create a response envelope to this message.
Swaps sender/recipient and preserves task_id and correlation_id.
"""
return AgentMessageEnvelope(
message=AgentMessage(
sender=self.message.recipient,
recipient=self.message.sender,
intent=intent,
payload=payload or {},
confidence=confidence,
),
task_id=self.task_id,
correlation_id=self.correlation_id,
)

201
fusionagi/schemas/plan.py Normal file
View File

@@ -0,0 +1,201 @@
"""Plan schema: steps with ids, dependencies, optional fallback paths with validation."""
from typing import Any
from pydantic import BaseModel, Field, field_validator, model_validator
class PlanStep(BaseModel):
"""
Single step in a plan.
Validation:
- id and description must be non-empty
"""
id: str = Field(..., min_length=1, description="Step identifier")
description: str = Field(..., min_length=1, description="What to do")
dependencies: list[str] = Field(default_factory=list, description="Step ids that must complete first")
tool_name: str | None = Field(default=None, description="Optional tool to invoke")
tool_args: dict[str, Any] = Field(default_factory=dict, description="Optional tool arguments")
metadata: dict[str, Any] = Field(default_factory=dict, description="Extra data")
@field_validator("id", "description")
@classmethod
def validate_non_whitespace(cls, v: str) -> str:
"""Validate string fields are not just whitespace."""
if not v.strip():
raise ValueError("Field cannot be empty or whitespace")
return v
class Plan(BaseModel):
"""
Plan graph: steps and optional fallback paths.
Validation:
- No duplicate step IDs
- All dependency references must be valid step IDs
- All fallback path references must be valid step IDs
- No circular dependencies
"""
steps: list[PlanStep] = Field(default_factory=list, description="Ordered steps")
fallback_paths: list[list[str]] = Field(default_factory=list, description="Alternative step sequences")
metadata: dict[str, Any] = Field(default_factory=dict, description="Plan-level metadata")
@model_validator(mode="after")
def validate_plan(self) -> "Plan":
"""Validate the entire plan structure."""
step_ids = {s.id for s in self.steps}
# Check for duplicate step IDs
if len(step_ids) != len(self.steps):
seen = set()
duplicates = []
for s in self.steps:
if s.id in seen:
duplicates.append(s.id)
seen.add(s.id)
raise ValueError(f"Duplicate step IDs: {duplicates}")
# Check all dependency references are valid
for step in self.steps:
invalid_deps = [d for d in step.dependencies if d not in step_ids]
if invalid_deps:
raise ValueError(
f"Step '{step.id}' has invalid dependencies: {invalid_deps}"
)
# Check all fallback path references are valid
for i, path in enumerate(self.fallback_paths):
invalid_refs = [ref for ref in path if ref not in step_ids]
if invalid_refs:
raise ValueError(
f"Fallback path {i} has invalid step references: {invalid_refs}"
)
# Check for circular dependencies
cycles = self._find_cycles()
if cycles:
raise ValueError(f"Circular dependencies detected: {cycles}")
return self
def _find_cycles(self) -> list[list[str]]:
"""Find circular dependencies in the plan graph using DFS."""
# Build adjacency list
graph: dict[str, list[str]] = {s.id: list(s.dependencies) for s in self.steps}
cycles = []
visited = set()
rec_stack = set()
path = []
def dfs(node: str) -> bool:
visited.add(node)
rec_stack.add(node)
path.append(node)
for neighbor in graph.get(node, []):
if neighbor not in visited:
if dfs(neighbor):
return True
elif neighbor in rec_stack:
# Found cycle
cycle_start = path.index(neighbor)
cycles.append(path[cycle_start:] + [neighbor])
return True
path.pop()
rec_stack.remove(node)
return False
for step_id in graph:
if step_id not in visited:
dfs(step_id)
return cycles
def step_ids(self) -> list[str]:
"""Return step ids in order."""
return [s.id for s in self.steps]
def get_step(self, step_id: str) -> PlanStep | None:
"""Get a step by ID."""
for step in self.steps:
if step.id == step_id:
return step
return None
def get_dependencies(self, step_id: str) -> list[PlanStep]:
"""Get all dependency steps for a given step."""
step = self.get_step(step_id)
if not step:
return []
return [s for s in self.steps if s.id in step.dependencies]
def get_dependents(self, step_id: str) -> list[PlanStep]:
"""Get all steps that depend on the given step."""
return [s for s in self.steps if step_id in s.dependencies]
def topological_order(self) -> list[str]:
"""
Return step IDs in topological order (dependencies first).
Uses Kahn's algorithm.
"""
# Build in-degree map
in_degree = {s.id: len(s.dependencies) for s in self.steps}
# Build adjacency list (reverse direction for dependents)
dependents: dict[str, list[str]] = {s.id: [] for s in self.steps}
for step in self.steps:
for dep in step.dependencies:
if dep in dependents:
dependents[dep].append(step.id)
# Start with nodes that have no dependencies
queue = [sid for sid, deg in in_degree.items() if deg == 0]
result = []
while queue:
node = queue.pop(0)
result.append(node)
for dependent in dependents.get(node, []):
in_degree[dependent] -= 1
if in_degree[dependent] == 0:
queue.append(dependent)
# Add any remaining nodes (would indicate cycles, but we validate above)
remaining = [sid for sid in in_degree if sid not in result]
result.extend(remaining)
return result
def to_dict(self) -> dict[str, Any]:
"""Serialize for message payload / state."""
return {
"steps": [s.model_dump() for s in self.steps],
"fallback_paths": self.fallback_paths,
"metadata": self.metadata,
}
@classmethod
def from_dict(cls, d: dict[str, Any]) -> "Plan":
"""Deserialize from dict. Steps may be dicts (validated) or PlanStep instances."""
if not isinstance(d, dict):
raise TypeError(f"Plan.from_dict expects dict, got {type(d).__name__}")
raw_steps = d.get("steps", [])
steps: list[PlanStep] = []
for s in raw_steps:
if isinstance(s, PlanStep):
steps.append(s)
elif isinstance(s, dict):
steps.append(PlanStep.model_validate(s))
else:
raise TypeError(f"Step must be dict or PlanStep, got {type(s).__name__}")
return cls(
steps=steps,
fallback_paths=d.get("fallback_paths", []),
metadata=d.get("metadata", {}),
)

View File

@@ -0,0 +1,29 @@
"""Policy engine schemas: hard constraints independent of LLM."""
from datetime import datetime, timezone
from enum import Enum
from typing import Any
from pydantic import BaseModel, Field
def _utc_now() -> datetime:
return datetime.now(timezone.utc)
class PolicyEffect(str, Enum):
"""Allow or deny."""
ALLOW = "allow"
DENY = "deny"
class PolicyRule(BaseModel):
"""Single policy rule: condition -> effect."""
rule_id: str = Field(..., min_length=1)
effect: PolicyEffect = Field(...)
condition: dict[str, Any] = Field(default_factory=dict, description="e.g. tool_name, domain, data_class")
reason: str = Field(default="")
priority: int = Field(default=0, ge=0, description="Higher = evaluated first")
created_at: datetime = Field(default_factory=_utc_now)

View File

@@ -0,0 +1,92 @@
"""Schemas for self-improvement: recommendations and training suggestions."""
from datetime import datetime, timezone
from enum import Enum
from typing import Any
from pydantic import BaseModel, Field, field_validator
def _utc_now() -> datetime:
"""Return current UTC time (timezone-aware)."""
return datetime.now(timezone.utc)
class RecommendationKind(str, Enum):
"""Type of auto-generated recommendation."""
NEXT_ACTION = "next_action"
TRAINING_TARGET = "training_target"
TOOL_ADDITION = "tool_addition"
STRATEGY_CHANGE = "strategy_change"
GUARDRAIL_UPDATE = "guardrail_update"
OTHER = "other"
class Recommendation(BaseModel):
"""
Auto-generated recommendation from reflection and lessons.
Used by the auto-recommend/suggest pipeline.
"""
kind: RecommendationKind = Field(
default=RecommendationKind.OTHER,
description="Category of recommendation",
)
title: str = Field(..., min_length=1, description="Short title")
description: str = Field(default="", description="Detailed description")
payload: dict[str, Any] = Field(default_factory=dict, description="Structured data")
source_task_id: str | None = Field(default=None, description="Task that triggered this")
priority: int = Field(default=0, ge=0, le=10, description="0=low, 10=critical")
created_at: datetime = Field(default_factory=_utc_now, description="Creation time")
@field_validator("title")
@classmethod
def validate_title(cls, v: str) -> str:
"""Ensure title is not just whitespace."""
if not v.strip():
raise ValueError("title cannot be empty or whitespace")
return v
class TrainingSuggestionKind(str, Enum):
"""Type of auto-training suggestion."""
HEURISTIC_UPDATE = "heuristic_update"
PROMPT_TUNING = "prompt_tuning"
FINE_TUNE_DATASET = "fine_tune_dataset"
STRATEGY_PARAM = "strategy_param"
OTHER = "other"
class TrainingSuggestion(BaseModel):
"""
Auto-generated training suggestion from reflection and failures.
Can be applied (e.g. heuristic update) or emitted for external training pipelines.
"""
kind: TrainingSuggestionKind = Field(
default=TrainingSuggestionKind.OTHER,
description="Type of training",
)
key: str = Field(..., min_length=1, description="Target key (e.g. heuristic name)")
value: Any = Field(..., description="Value to apply or dataset description")
source_task_id: str | None = Field(default=None, description="Task that triggered this")
reason: str = Field(default="", description="Why this suggestion was generated")
created_at: datetime = Field(default_factory=_utc_now, description="Creation time")
@field_validator("key")
@classmethod
def validate_key(cls, v: str) -> str:
"""Ensure key is not just whitespace."""
if not v.strip():
raise ValueError("key cannot be empty or whitespace")
return v
__all__ = [
"Recommendation",
"RecommendationKind",
"TrainingSuggestion",
"TrainingSuggestionKind",
]

View File

@@ -0,0 +1,52 @@
"""Skill schemas for AGI skill library and compilation."""
from datetime import datetime, timezone
from enum import Enum
from typing import Any
from pydantic import BaseModel, Field, field_validator
def _utc_now() -> datetime:
return datetime.now(timezone.utc)
class SkillKind(str, Enum):
"""Type of skill."""
WORKFLOW = "workflow"
PROCEDURE = "procedure"
TOOL_NATIVE = "tool_native"
COMPOSITE = "composite"
class Skill(BaseModel):
"""Reusable skill: declarative description + executable steps."""
skill_id: str = Field(..., min_length=1)
name: str = Field(..., min_length=1)
description: str = Field(default="")
kind: SkillKind = Field(default=SkillKind.WORKFLOW)
steps: list[dict[str, Any]] = Field(default_factory=list, description="Declarative steps (plan-like)")
tool_names: list[str] = Field(default_factory=list, description="Tools this skill uses")
version: int = Field(default=1, ge=1)
metadata: dict[str, Any] = Field(default_factory=dict)
created_at: datetime = Field(default_factory=_utc_now)
@field_validator("skill_id", "name")
@classmethod
def validate_non_whitespace(cls, v: str) -> str:
if not v.strip():
raise ValueError("Field cannot be empty or whitespace")
return v
class SkillVersionInfo(BaseModel):
"""Version and performance tracking for a skill."""
skill_id: str = Field(..., min_length=1)
version: int = Field(..., ge=1)
success_count: int = Field(default=0, ge=0)
failure_count: int = Field(default=0, ge=0)
last_success_at: datetime | None = Field(default=None)
regression_test_ids: list[str] = Field(default_factory=list)

106
fusionagi/schemas/task.py Normal file
View File

@@ -0,0 +1,106 @@
"""Task schema: goal, constraints, priority, state with validation."""
from datetime import datetime
from enum import Enum
from typing import Any
from pydantic import BaseModel, Field, field_validator, model_validator
from fusionagi._time import utc_now
class TaskState(str, Enum):
"""Lifecycle state of a task."""
PENDING = "pending"
ACTIVE = "active"
COMPLETED = "completed"
FAILED = "failed"
CANCELLED = "cancelled"
class TaskPriority(str, Enum):
"""Task priority level."""
LOW = "low"
NORMAL = "normal"
HIGH = "high"
CRITICAL = "critical"
# Valid state transitions for validation
VALID_TASK_TRANSITIONS: dict[TaskState, set[TaskState]] = {
TaskState.PENDING: {TaskState.ACTIVE, TaskState.CANCELLED},
TaskState.ACTIVE: {TaskState.COMPLETED, TaskState.FAILED, TaskState.CANCELLED},
TaskState.COMPLETED: set(), # Terminal
TaskState.FAILED: {TaskState.PENDING, TaskState.CANCELLED}, # Allow retry
TaskState.CANCELLED: set(), # Terminal
}
class Task(BaseModel):
"""
Task representation for orchestration.
Includes validation for:
- Non-empty task_id and goal
- Timestamps for tracking
- State transition helpers
"""
task_id: str = Field(..., min_length=1, description="Unique task identifier")
goal: str = Field(..., min_length=1, description="High-level goal description")
constraints: list[str] = Field(default_factory=list, description="Constraints to respect")
priority: TaskPriority = Field(default=TaskPriority.NORMAL, description="Task priority")
state: TaskState = Field(default=TaskState.PENDING, description="Current task state")
metadata: dict[str, Any] = Field(default_factory=dict, description="Optional extra data")
created_at: datetime = Field(default_factory=utc_now, description="Creation timestamp")
updated_at: datetime | None = Field(default=None, description="Last update timestamp")
model_config = {"frozen": False}
@field_validator("task_id")
@classmethod
def validate_task_id(cls, v: str) -> str:
"""Validate task_id is not just whitespace."""
if not v.strip():
raise ValueError("task_id cannot be empty or whitespace")
return v
@field_validator("goal")
@classmethod
def validate_goal(cls, v: str) -> str:
"""Validate goal is not just whitespace."""
if not v.strip():
raise ValueError("goal cannot be empty or whitespace")
return v
def can_transition_to(self, new_state: TaskState) -> bool:
"""Check if transitioning to new_state is valid."""
if new_state == self.state:
return True
allowed = VALID_TASK_TRANSITIONS.get(self.state, set())
return new_state in allowed
def transition_to(self, new_state: TaskState) -> "Task":
"""
Create a new Task with the new state.
Raises:
ValueError: If the transition is not allowed.
"""
if not self.can_transition_to(new_state):
raise ValueError(
f"Invalid state transition: {self.state.value} -> {new_state.value}"
)
return self.model_copy(update={"state": new_state, "updated_at": utc_now()})
@property
def is_terminal(self) -> bool:
"""Check if task is in a terminal state."""
return self.state in (TaskState.COMPLETED, TaskState.CANCELLED)
@property
def is_active(self) -> bool:
"""Check if task is currently active."""
return self.state == TaskState.ACTIVE

View File

@@ -0,0 +1,50 @@
"""Witness output schemas: agreement map, transparency report, final response."""
from typing import Any
from pydantic import BaseModel, Field
class AgreementMap(BaseModel):
"""Map of agreed vs disputed claims from heads."""
agreed_claims: list[dict[str, Any]] = Field(
default_factory=list,
description="Claims with consensus support",
)
disputed_claims: list[dict[str, Any]] = Field(
default_factory=list,
description="Conflicting or contested claims",
)
confidence_score: float = Field(..., ge=0.0, le=1.0, description="Overall confidence [0, 1]")
class TransparencyReport(BaseModel):
"""Transparency report produced by Witness."""
head_contributions: list[dict[str, Any]] = Field(
default_factory=list,
description="Per-head contribution (head_id, summary, key_claims)",
)
agreement_map: AgreementMap = Field(..., description="Agreed and disputed claims")
safety_report: str = Field(default="", description="High-level safety/compliance summary")
confidence_score: float = Field(..., ge=0.0, le=1.0, description="Overall confidence [0, 1]")
class FinalResponse(BaseModel):
"""Final user-facing response from Witness arbitration."""
final_answer: str = Field(..., min_length=1, description="Composed narrative answer")
transparency_report: TransparencyReport = Field(..., description="Full transparency payload")
head_contributions: list[dict[str, Any]] = Field(
default_factory=list,
description="Which heads contributed (12 lines each)",
)
confidence_score: float = Field(..., ge=0.0, le=1.0, description="Overall confidence [0, 1]")
__all__ = [
"AgreementMap",
"TransparencyReport",
"FinalResponse",
]

View File

@@ -0,0 +1,29 @@
"""World model schemas: state transitions, rollouts, uncertainty for AGI."""
from datetime import datetime, timezone
from typing import Any
from pydantic import BaseModel, Field
def _utc_now() -> datetime:
return datetime.now(timezone.utc)
class StateTransition(BaseModel):
"""Causal transition: action -> resulting state."""
from_state: dict[str, Any] = Field(default_factory=dict)
action: str = Field(default="")
action_args: dict[str, Any] = Field(default_factory=dict)
to_state: dict[str, Any] = Field(default_factory=dict)
confidence: float = Field(default=1.0, ge=0.0, le=1.0)
class UncertaintyInfo(BaseModel):
"""Explicit uncertainty: confidence, risk, expected value."""
confidence: float = Field(default=1.0, ge=0.0, le=1.0)
risk_level: str = Field(default="low", description="e.g. low, medium, high")
expected_value: float | None = Field(default=None)
rationale: str = Field(default="")