Add basic version: SemIf decision engine, urgency queue, skill tree, skill loop, decision log, dream pass, CLI
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
"""The SemIf decision contract shared across the agent.
|
||||
|
||||
A decision is a typed question over a state with declared options; SemIf returns
|
||||
probabilities conditional on exactly the supplied options. These are not
|
||||
calibrated confidence values, so callers treat them as conditional scores.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
import uuid
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any
|
||||
|
||||
|
||||
@dataclass
|
||||
class Option:
|
||||
id: str
|
||||
description: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class DecisionRequest:
|
||||
"""One SemIf decision: state + question + typed options."""
|
||||
|
||||
state: str
|
||||
question: str
|
||||
options: list[Option]
|
||||
id: str = field(default_factory=lambda: uuid.uuid4().hex[:12])
|
||||
|
||||
def to_semif_row(self) -> dict:
|
||||
return {
|
||||
"id": self.id,
|
||||
"state": self.state,
|
||||
"question": self.question,
|
||||
"options": [{"id": o.id, "description": o.description} for o in self.options],
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class DecisionResult:
|
||||
"""The outcome of one SemIf call: probabilities aligned to option ids."""
|
||||
|
||||
request: DecisionRequest
|
||||
option_ids: list[str]
|
||||
probabilities: list[float]
|
||||
extra: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
@property
|
||||
def probs(self) -> dict[str, float]:
|
||||
return dict(zip(self.option_ids, self.probabilities))
|
||||
|
||||
def prob(self, option_id: str) -> float:
|
||||
index = self.option_ids.index(option_id)
|
||||
return self.probabilities[index]
|
||||
|
||||
@property
|
||||
def selected(self) -> str:
|
||||
return max(self.probs, key=self.probs.get)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Request:
|
||||
"""An incoming input to the agent, before it is gated/scored."""
|
||||
|
||||
text: str
|
||||
id: str = field(default_factory=lambda: uuid.uuid4().hex[:12])
|
||||
source: str = "typed"
|
||||
meta: dict[str, Any] = field(default_factory=dict)
|
||||
received_at: float = field(default_factory=time.time)
|
||||
priority: float = 0.5
|
||||
reentries: int = 0
|
||||
resume: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
def copy_for_requeue(self) -> "Request":
|
||||
return Request(
|
||||
text=self.text,
|
||||
id=self.id,
|
||||
source=self.source,
|
||||
meta=dict(self.meta),
|
||||
received_at=self.received_at,
|
||||
priority=self.priority,
|
||||
reentries=self.reentries + 1,
|
||||
resume=dict(self.resume),
|
||||
)
|
||||
Reference in New Issue
Block a user