symfonic.agent.facade¶
facade ¶
Capability-composed Agent: one provider, optional behavior as capabilities.
Implements T2.1.1's FAC-4…FAC-9 and LIF-1…LIF-5.
Agent ¶
Agent(model_provider: Any, *, instructions: str | None = None, model: str | ModelConfig | None = None, tools: Sequence[Any] = (), capabilities: Sequence[CapabilityConfig] = (), max_model_rounds: int | None = None)
Bases: AgentContinuationMixin
A stateless, tool-capable agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model_provider
|
Any
|
Any object satisfying |
required |
instructions
|
str | None
|
The system prompt, used verbatim. |
None
|
tools
|
Sequence[Any]
|
A |
()
|
capabilities
|
Sequence[CapabilityConfig]
|
The typed optional-behavior seam. Absence means
disabled; there are no boolean feature flags. Anything with a
|
()
|
max_model_rounds
|
int | None
|
How many provider round trips one |
None
|
Construction validates and stores, and does nothing else (FAC-8): no
connection, no task, no file, no environment read, no chat model. The
first side effect of an Agent is the provider call inside run().
That is what makes async with and close() optional (LIF-1) — an
agent that acquired nothing leaks nothing.
One instance may serve unlimited concurrent run/stream calls on
one event loop, because no per-invocation state is stored on it (FAC-9).
It is not documented as safe to share across event loops.
Source code in src/symfonic/agent/facade.py
capabilities
property
¶
Names actually folded into this agent's invocation plan.
composition_manifest
property
¶
Payload-free attestation of the capability fold this agent retained.
close
async
¶
Release facade-owned resources. Idempotent, and never raises.
In W1 the facade owns nothing, so this only marks the instance closed.
It never closes anything the adopter passed in — the provider outlives
the agent. An in-flight run() is allowed to finish; close()
does not cancel it (LIF-4).
Source code in src/symfonic/agent/facade.py
run
async
¶
run(prompt: str, *, attachments: Sequence[Attachment] = (), history: Sequence[Message] = (), state: Mapping[str, Any] | None = None, session_id: str = '', output_type: type[BaseModel] | None = None) -> AgentResult[Any]
Run one non-streaming turn.
history is how a stateless agent takes a second turn: the adopter
holds the transcript and passes result.messages back.
Source code in src/symfonic/agent/facade.py
stream ¶
stream(prompt: str, *, attachments: Sequence[Attachment] = (), history: Sequence[Message] = (), state: Mapping[str, Any] | None = None, session_id: str = '', output_type: type[BaseModel] | None = None) -> AsyncIterator[AgentEvent]
Run one streaming turn.
A plain def, not an async generator function, on purpose: an async
generator defers argument validation to the first __anext__, which
would surface a ConfigurationError after the caller believed the
stream had started. This validates eagerly and raises at the call site,
while async for event in agent.stream(...) still reads identically
(EVT-8).