5.5 KiB
agent
agent is the ecosystem's delegation kernel — the runtime by which an
actor other than the user (an LLM, a macro, a rule, a workflow) can be invoked
from, and participate in, the component ecosystem. It materializes the
delegate semantic family (book ch. 29: ¿quién actúa ahora?).
Doctrine: docs/architecture/agent.md.
Execution record: docs/process/PLAN-agent.md.
The central idea:
surfaces / app
-> ActiveAgent.start({ goal, capabilities, reads, autonomy })
-> EngineAgent runs the delegation (Run = the delegate cycle as states)
-> transport streams turns (own v1 protocol, AG-UI parity baseline)
-> tool-calls execute CAPABILITIES = the providers' own public APIs
-> results, failures→verbs, budgets, journal, trace
-> control ALWAYS returns (returned outcome-typed / cancelled)
The agent knows no components — only capabilities registered per run. The
call path never bifurcates: a capability maps to the provider's existing
public API; the semantic concretion depends on the ACTOR (polymorphic
allowedFamilies → {family:'delegate', verb:'act'} when the invocation
carries the engine-minted actor token).
Surface
createEngineAgent(options)— pure kernel (no runes, no DOM; portable to a server runtime by construction).createActiveAgent(options)/ActiveAgent— reactive session root (ActiveEnginecontract;runs,activeRun,loading).createScriptedAgentTransport(turns)— first-class deterministic transport ($agent/adapters/scripted, outside the barrel): static demos and component tests run REAL engine + REAL providers, no mocks.createOpenAiChatAgentTransport(options)— real-model transport over the OpenAI chat-completions dialect ($agent/adapters/openai-chat, outside the barrel): Ollama / llama.cpp / LM Studio / any compatible proxy. Options:baseUrl(up to/v1) ·model(must support tool calling) ·headers?(proxy auth) ·request?(extra body fields: temperature…) ·fetch?(injectable, tests). Streams SSE into the v1 protocol; owns name sanitization (dotted capability ids), assistanttool_callsre-pairing when replaying the transcript, and splitting calls on servers that re-use stream index 0 (Ollama). Direct browser→localhost is the DEV story; production points at your proxy (the provider key never ships client-side).createMemoryAgentJournal()/createWebStorageAgentJournal(storage)— the WAL run journal (authorizations + acts + closes; orphan detection).toJsonSchema(schema)— sium→JSON Schema projection for model-facing tool declarations. Agent-local today; moves into$siumat the 2nd consumer.
The run machine (D-AG.4)
States are the delegate verbs as custody of control (the model's own
plan→tool→plan loop lives inside acting):
offered → planned → reviewing ⇄ authorized → acting → returned(outcome, reason)
└── cancelled (pre-authorization decline) ▲
escalated (non-terminal: elicitation / insufficient-scope / │
budget-exhausted; auto-returns on timeout) ──────┘
- Authorization is journaled even when automatic (
auto: true). returnedcarriesoutcome: completed | partial | rolled-back | aborted | error+ a typedreason. Mid-sequence hard failure runs the run-scopedrollbackhook (native-history restore) →rolled-back(⚖️3).- User interruption (
stop) = immediate return, never an error.disable()is the global kill switch: every run →returned(aborted, killed).
Budgets (D-AG.5)
maxActs · maxTurns · timeoutMs (wall-clock; needs the timers port) ·
escalationTimeoutMs. Exhaustion escalates (never silence); the
wall-clock cap closes TYPED (budget-exhausted) because it can fire
mid-transport. Failed tool-rounds are bounded (self-correction loop).
Idempotency: duplicate callId returns the cached result, never re-executes.
Client-side budgets are UX courtesy, not a security boundary — the boundary lives where the credential lives (the app's proxy/backend).
Actor minting (⚖️2 / F6b)
One opaque ActorToken per CapabilityCall, minted ONLY here, resolvable ONLY
against this engine's private registry (isAgentActor / resolveActor) — a
structurally-forged object resolves to nothing. Tokens never serialize; the
trace boundary carries a non-authoritative 'agent' label. The nominal TYPE
lives in $libs/actor (a leaf below orca and agent) so envelope types may
name it without an orca→agent cycle.
Contract (§0 row)
Module Requires Optional When missing Error
agent AgentTransport port timers, journal, trace, logger manifest/participation is a NO-OP; AgentTransportMissingError
(app supplies it) components stay 100% functional only on start()
Transport is app-land (the chat precedent). Adapters own their streaming
(fetch/SSE parsing local to the adapter — $http/$connection untouched).
Without timers: wall-clock and escalation timeouts degrade to no-cap
(documented). Without journal/trace: no audit surface, engine unaffected.
Dependencies
$libs/actor (nominal token) · $libs/standard-schema (type-only) ·
$libs/active (ActiveEngine contract) · $libs/logger (Logger type) ·
$sium (introspection for the JSON-Schema projection). No DOM, no uix.