Agents
An agent is an Agent(...) call. Pass keyword arguments; build() forwards the ones you set to
the Agents SDK constructor and drops the rest so the SDK keeps its own defaults.
from agentdeck import Agent
support = Agent(
name="Support",
instructions="Answer customer questions. One short paragraph, no bullet lists.",
model="gpt-4.1-mini",
model_settings={"temperature": 0.2},
)name is required — it is also the registry key a Deck resolves, e.g. deck.run("Support", …).
What you did not write
No registration, no runner wiring, no provider setup, no session plumbing. The same agent is reachable one-shot, as a conversation, streamed, over HTTP, and as another agent’s tool:
import asyncio
from agentdeck import Deck
from agentdeck.core import MessageCompleted, RunCompleted, TextDelta
async def main() -> None:
async with Deck.from_project() as deck:
await deck.run("Support", "where is my order?") # one-shot
await deck.run("Support", "where is my order?", session_id="wa-123") # remembers
async for event in deck.stream("Support", "and now?", session_id="wa-123"): # streams
# `type(event)` is always `Event` — the envelope. The discriminator is
# `event.payload`, whose own `kind` is what the union matched on; an
# unfamiliar kind still parses (as `UnknownEvent`), so a default case
# tolerates it instead of crashing on a newer writer.
match event.payload:
case TextDelta(text=text):
print(text, end="", flush=True)
case MessageCompleted():
print()
case RunCompleted(usage=usage):
print(f"[{usage.input_tokens}+{usage.output_tokens} tokens]")
case _:
pass
asyncio.run(main())The configuration surface
| Argument | Purpose |
|---|---|
instructions | the system prompt: role, priorities, tool rules, output expectations |
model | per-agent override; None uses the OPENAI_MODEL setting |
model_settings | forwarded to agents.ModelSettings(**model_settings) — temperature, token budget, parallel tool calls |
tools | plain functions (compiled at build()), already-built SDK tool objects, or a Workflow to expose as a tool — see Definitions |
handoffs | peers this agent can transfer the conversation to |
handoff_description | how this agent describes itself to a peer deciding whether to hand off |
output_type | a Pydantic model for structured final output; None for free text |
skills | names resolved against the owning Deck’s skills= roots — see Skills |
mcp | names resolved against the owning Deck’s mcp= file — the agent says which, the file owns transport |
hooks | an AgentHooks instance for telemetry and bookkeeping |
base | a reusable AgentDeclaration subclass to inherit defaults from — see Definitions |
Handoffs by name
handoffs accepts a built Agent, or a string registry name resolved against the whole
catalog at Deck.build(). Two agents can hand off to each other without importing each other,
and mutual handoffs resolve without recursing forever:
# .agentdeck/agents/triage/agent.py
from agentdeck import Agent
triage = Agent(
name="Triage",
instructions="Route billing questions to Billing, everything else to Support.",
handoffs=["Billing", "Support"],
)An unknown name raises NotFoundError naming the agents that do exist.
Structured output
Pass a Pydantic model for a strict JSON schema where every field is required. If a smaller chat-completions model stalls trying to fill every field, wrap it to keep defaults optional:
from agents import AgentOutputSchema
from pydantic import BaseModel
from agentdeck import Agent
class Verdict(BaseModel):
approved: bool
reason: str = ""
reviewer = Agent(
name="Reviewer",
instructions="Approve or reject the request.",
output_type=AgentOutputSchema(Verdict, strict_json_schema=False),
)MCP servers degrade instead of crashing
build() is deliberately network-free — it registers the server specs but connects nothing, so
every mcp= name compiles against known-but-not-yet-connected servers. Connecting happens when
the Deck opens (async with Deck.from_project() as deck, its __aenter__), right after which
every already-compiled agent’s MCP status is re-resolved against what actually connected. A
server that failed to connect at that point is dropped from that agent’s tools, with a banner
prepended to its instructions naming what’s missing — it costs that agent the toolset, not the
whole process.
Next: give an agent deterministic, non-sandboxed powers with skills.