跳转至

Agents

Auto-generated from source docstrings (mkdocstrings). The complete public contract is agentmaker.__all__ plus each subpackage __all__.

agentmaker.agents

agentmaker.agents: Agent base + execution primitive + the strategies.

BaseAgent (base.py): the unified run / resume template (guardrails + persistence + HITL resume) plus the three sub-agent delegation methods. Single-loop Agent (agent.py): the one "model calls tools in a loop" execution primitive (native function-calling); the spec menu's "chat" maps to it and "react" is its preset. Orchestration recipes (workflows subpackage): PlanAgent / ReflectionAgent, strategies whose control flow is in code, driving an internal Agent for each step's work. Multi-agent orchestration (multi_agent subpackage): AgentTool, wrapping one Agent as a Tool (orchestrator-worker).

Agent is the single-loop class (agent.py); to write a new strategy, inherit BaseAgent (base.py).

BaseAgent

BaseAgent(name: str, llm: LLMClient, system_prompt: Optional[str] = None, *, session_store: Optional[SessionStore] = None, scope: Optional[Scope] = None, checkpoint_store: Optional[CheckpointStore] = None, input_guardrails: Optional[list[Guardrail]] = None, output_guardrails: Optional[list[Guardrail]] = None, hooks: Optional[list[Hook]] = None, run_policy: Optional[RunPolicy] = None, harness_config: Optional[HarnessConfig] = None, prompts=None, on_pending: str = 'error', as_child: bool = False)

Shared base for all agents. Subclasses must implement at least one of _arun (async-native) or _run (synchronous).

Parameters:

Name Type Description Default
name str

Agent name, used for identification / debugging.

required
llm LLMClient

LLM client the agent uses to call the model.

required
system_prompt Optional[str]

System prompt defining the agent's persona and behavior; optional.

None
session_store Optional[SessionStore]

Optional session persistence store. When attached, history is persisted per scope and loaded per scope at each run to resume (the store is the single source of truth and supports cross-process access), so a long-running daemon does not lose conversations on restart. When absent, history is per-scope and in-process (lost on restart).

None
scope Optional[Scope]

The default scope the session belongs to (identifies session / user via retrieval.Scope); run / resume can override it per call, so one Agent instance can serve multiple sessions (history is isolated per scope). Defaults to an empty scope.

None
checkpoint_store Optional[CheckpointStore]

Optional execution-state checkpoint store (CheckpointStore, agentmaker.runtime.execution). Attaching one enables execution-state persistence, shared across three use cases: (1) HITL async approval (high-risk tools suspend, run returns an Interrupt, resume(decision) continues); (2) crash recovery / (3) long-task resume (a checkpoint is saved each step, resume() continues after a process restart). Strategies that support resume implement _adrive.

None
input_guardrails Optional[list[Guardrail]]

Optional list of input guardrails. Checked against user input before run; a tripped guardrail raises GuardrailTripwireError.

None
output_guardrails Optional[list[Guardrail]]

Optional list of output guardrails. Checked against the final output before persisting history; a trip raises (the blocked turn is not recorded). The rules are app business logic.

None
hooks Optional[list[Hook]]

Optional list of lifecycle hooks (Hook, agentmaker.runtime.hooks); observe-only. Run-level events (run start / end, guardrail, suspend, error, etc.) are fired by this base; model/tool-level events (calling the model / executing tools) are fired by each strategy's Harness. Zero overhead when none are attached.

None
run_policy Optional[RunPolicy]

Optional run governance (RunPolicy, agentmaker.runtime.execution). When attached, a single run is bounded by wall-time / LLM-call count / tool-call count / token limits plus cooperative cancellation (gated at each call site in the Harness); exceeding a limit / cancellation raises RunLimitExceeded / RunCancelled to abort the turn. Counted independently per run (resume is a new turn). Unbounded when absent. Warning: nested runs (delegated via AgentTool, or a Plan / Reflection sub-executor) inherit the outermost policy's global counters; a run_policy attached to a sub-agent does not take effect within the parent run (a warning is emitted). To bound sub-tasks, set the global limits on the parent Agent's run_policy.

None
prompts

Optional prompt registry (PromptRegistry). If not passed, a copy of DEFAULT_PROMPTS is made at construction (isolated per instance, so update_prompts only affects this agent and its harness / sub-agents, without mutating the global registry / other agents).

None
on_pending str

Policy for running again when the same scope already has a pending-approval checkpoint (requires checkpoint_store): "error" (default) raises SessionError to prevent a new run silently overwriting the pending action (making the approval request vanish); "discard" drops the old pending action and continues the new run.

'error'
as_child bool

Set True when acting as an internal sub-agent of an orchestration strategy (Plan / Reflection, etc.). It declares two semantics at once: (1) run-level hooks do not fire at the child layer (the parent strategy fires them once, avoiding repetition on every sub-step); the passed hooks are still forwarded via _harness_hooks to the inner Harness to observe model/tool-level events; (2) checkpoints are not self-cleared (_defer_checkpoint_clear); the parent strategy clears them explicitly via clear_checkpoint after committing its own progress, guaranteeing "parent commits before child cleanup" and eliminating the unrecoverable state where the parent is awaiting but the child's checkpoint has been cleared.

False

arun async

arun(input_text: str, *, scope=None, trace_carrier=None, **kwargs)

Process one input and return a reply (template method: the run boundary shared by all strategies): input guardrails -> strategy logic _arun -> output guardrails -> persist history.

Subclasses only implement _arun (pure generation); this method funnels the "run boundary" cross-cutting concerns (guardrails and history persistence) so every strategy gets them for free, mirroring the OpenAI Agents SDK where guardrails are declared on the agent and enforced by a single execution layer (rather than reimplemented in each strategy). The return type matches _arun (usually str; a validated model instance when output_schema is passed; an Interrupt on HITL suspend, in which case history is not persisted, the state has already been saved into the CheckpointStore by the strategy, awaiting resume).

Parameters:

Name Type Description Default
input_text str

The user's raw input text.

required
scope

The session identifier for this call; defaults to self.scope. History is loaded / saved by it (one instance can serve multiple sessions).

None
trace_carrier

Optional upstream W3C trace carrier (e.g. {"traceparent": request-header}). Useful only when an OTelExporter(carrier_provider=...) is attached, letting this run's spans join the app's cross-service trace. When absent, spans are attributed by the OTel current context (no regression).

None
**kwargs

Passed through to _arun (e.g. verbose, output_schema, temperature).

{}

run

run(input_text: str, *, scope=None, trace_carrier=None, **kwargs)

Synchronous facade over arun (driven by aio.run_sync). In environments with a running event loop (async / Jupyter / FastAPI), await arun instead.

aresume async

aresume(decision: Optional[bool] = None, *, scope=None, trace_carrier=None, **kwargs)

Resume an unfinished run from a checkpoint: reload the execution state -> (for HITL) inject the decision -> continue from the breakpoint.

Two kinds of resume share this entry: - HITL: decision is a bool. Approve (True) executes the suspended high-risk action / reject (False) skips it and feeds the result back so the model reroutes. - Crash recovery / long-task resume: decision is omitted (None). No decision is injected; it simply continues from the last checkpoint (a suspended high-risk action re-suspends and returns an Interrupt awaiting approval again, rather than being mistaken for a rejection).

Funneled in the base: reload ExecutionState -> (as needed) inject the decision -> call the strategy's _adrive to continue -> teardown (on completion: output guardrails + persist history + clear checkpoint; on re-suspend: return a new Interrupt). Input guardrails are not re-checked (the first run already checked them); it does not go through _scaffold, so resume continues the run_id / step from before the suspend and does not re-fire on_run_start.

Parameters:

Name Type Description Default
decision Optional[bool]

The HITL decision. A bool (True approve / False reject) decides all pending actions of this turn uniformly; a dict {call_id: bool} decides per call_id (used when one suspend has multiple pending actions, see Interrupt.pendings); None is a crash-recovery resume (no decision injected).

None
scope

The session identifier; defaults to self.scope.

None
trace_carrier

Optional upstream W3C trace carrier (the traceparent of this resume request); not persisted with the checkpoint, passed by the app on each resume.

None
**kwargs

Passed through to the strategy's _adrive.

{}

Returns:

Type Description

str (the final reply, and history persisted) or Interrupt (a high-risk action is still

awaiting approval during resume, re-suspended).

resume

resume(decision: Optional[bool] = None, *, scope=None, trace_carrier=None, **kwargs)

Synchronous facade over aresume (driven by aio.run_sync).

clear_checkpoint async

clear_checkpoint(scope=None) -> None

Explicitly clear a scope's checkpoint (ignoring the defer flag), and cascade-clear the internal sub-agents' derived child-scope checkpoints.

For a parent strategy to clean up sub-agent checkpoints after committing its own progress, and for a user to manually clear a stuck suspended task: cascading ensures it does not clear only the parent and leave child checkpoints orphaned (the next sub-agent arun / delegation hitting _guard_pending permanently jams). A sub-agent without a checkpoint_store is a no-op each.

Parameters:

Name Type Description Default
scope

The session identifier to clear; defaults to self.scope.

None

add_message async

add_message(message: Message, scope=None)

Append one message to the conversation history by scope (a single-message convenience over add_messages).

Parameters:

Name Type Description Default
message Message

The message to append.

required
scope

The session identifier; defaults to self.scope.

None

add_messages async

add_messages(messages: list[Message], scope=None)

Append multiple messages to the conversation history by scope atomically; with a session_store it goes through its aappend_many (single transaction, avoiding a half-turn), otherwise the in-process dict[scope] is extended once. This is the single funnel point for session persistence (the async real body, using a* so as not to block the event loop).

Parameters:

Name Type Description Default
messages list[Message]

The list of messages to append.

required
scope

The session identifier; defaults to self.scope.

None

clear_history

clear_history(scope=None)

Clear a scope's conversation history; with a session_store, clear its persisted record, otherwise clear the in-process dict[scope].

Parameters:

Name Type Description Default
scope

The session identifier; defaults to self.scope.

None

get_history

get_history(scope=None) -> list[Message]

Return a deep copy of a scope's conversation history, so external mutations (including changing a Message's content / metadata) do not affect internal state.

Parameters:

Name Type Description Default
scope

The session identifier; defaults to self.scope.

None

Returns:

Type Description
list[Message]

list[Message]: A deep copy of the history message list (Message is a mutable dataclass, so

list[Message]

a shallow copy would not prevent field mutation).

The synchronous public facade (funneling to the async real body _history_for via run_sync): in environments with a running event loop (async / Jupyter / FastAPI), use await agent._history_for(scope) instead (same limitation as the run/resume synchronous facades).

get_prompts

get_prompts() -> dict

List all built-in prompts this agent currently uses, as {key: text} (from the shared self.prompts).

For inspection / export: first see which prompts the framework builds in, what their keys are called, and what they look like, then decide which to override (see agentmaker/doc/prompts.md).

update_prompts

update_prompts(updates) -> None

Override built-in prompts: updates may be {key: new-text} (per key) or another PromptRegistry (a whole swap, e.g. changing language).

Modifies self.prompts in place: this agent's harness and internal sub-agents share the same copy, so one change takes effect across the whole chain. Each override is validated to ensure "the placeholders + protocol tokens are still present", raising PromptError if any is missing. It is isolated per instance by default (a copy of DEFAULT_PROMPTS is made at construction when prompts= is not passed), so this method only changes this agent's chain and does not affect other agents / independently constructed tools / the process-wide global. To change language / wording process-wide, explicitly call DEFAULT_PROMPTS.override(pack) before creating any component.

Boundaries: (1) an already-created tool's overall description is a construction-time snapshot and does not change with this override (the parameter descriptions do change live), so changing language / tool-related prompts should be done before creating tools (use packs' chinese_registry(), or override first then build tools), otherwise the same tool's schema shows a half-mixed state of "overall intro in the old language, parameter descriptions in the new". (2) After the default isolation, a tool constructed separately (not passed the same prompts) has its wording determined by the tool's own prompts and does not change with this agent's update_prompts: to keep the tool and agent in sync, pass the same PromptRegistry to both, or use a global override.

Agent

Agent(name: str, llm: LLMClient, system_prompt: Optional[str] = None, *, tools=None, tool_registry: Optional[ToolRegistry] = None, max_turns: int = 10, compactor: Optional[HistoryCompactor] = None, confirm: Optional[ConfirmCallback] = None, permissions=None, reducer: Optional[ReducerConfig] = None, tool_retriever: Optional[ToolRetriever] = None, context_builder: Optional[ContextBuilder] = None, sources: Optional[list[ContextSource]] = None, window_budget=None, token_counter: TokenCounter = count_tokens, tracer=None, hooks=None, run_policy=None, session_store=None, scope=None, checkpoint_store=None, input_guardrails=None, output_guardrails=None, prompts=None, on_pending: str = 'error', as_child: bool = False)

Bases: BaseAgent

Single-loop Agent: one input -> model-tool loop -> reply; with no tools it is plain question-answering. Automatically maintains multi-turn history per scope.

llm: LLM client.
system_prompt: System prompt defining the persona; optional (if omitted, no system message is sent).
tools: Convenience entry point: a list[Tool] (including @tool-decorated function objects) or a
    ToolRegistry, normalized into a registry internally via ToolRegistry.from_tools. Use it for a
    one-line start in simple cases; mutually exclusive with tool_registry (passing both raises ValueError).
tool_registry: Tool registry (advanced case: reuse the same registry or customize prompts).
    Passing it enables the tool loop; omitting it means plain question-answering.
max_turns: The maximum number of model turns in the loop, to prevent repeated calls from
    spinning into an infinite loop (must be a positive integer, default 10, since tool tasks
    often need multiple turns).
compactor: Optional history compactor (HistoryCompactor); once attached, cross-turn session
    history is automatically summarized and compacted when it exceeds a threshold.
confirm: Confirmation callback for high-risk tools (tool, params) -> bool; if omitted, it
    safely refuses (returns a readable error fed back to the model, without blocking on stdin).
    In CLI / teaching scenarios pass agentmaker.runtime.cli_confirm explicitly for command-line
    y/n; in server scenarios configure HITL (checkpoint_store).
permissions: Optional tool permissions (ToolPermissions, allow/deny lists); denied tools are
    rejected directly at the execution gate.
reducer: Optional trajectory-trimming knob (ReducerConfig); when this turn's tool trajectory
    overflows the window, keep recent units and summarize the earlier ones.
tool_retriever: Optional Tool-RAG (ToolRetriever); selects only the relevant subset of tools for
    this turn's input (saves tokens when there are many tools).
context_builder + sources: Optional memory/RAG injection; each turn retrieves by input and
    assembles a guardrailed system block for injection.
window_budget: Optional window-budgeting knob (WindowBudgetConfig); unifies budgeting across
    retrieval blocks, trajectory, and output reservation.
token_counter: Pluggable token counter (default count_tokens); the harness uses it to estimate
    tool overhead and to trim trajectories. For consistent accounting throughout, pass the same
    token_counter to your ContextBuilder / HistoryCompactor as well (the Agent does not silently
    override the counters they already carry).
session_store / scope: Session persistence (see BaseAgent); once attached, history is resumed
    per scope and persisted automatically.
checkpoint_store: Optional checkpoint store; once attached, enables HITL suspend/resume plus
    crash recovery (saved at every step).
input_guardrails / output_guardrails / hooks / run_policy / prompts / on_pending: see BaseAgent.
as_child: Set True when acting as an orchestration recipe's internal sub-agent (see BaseAgent:
    run-level hooks do not fire and checkpoint cleanup is left to the parent).

astream_run async

astream_run(input_text: str, *, scope=None, buffer_output: bool = False, trace_carrier=None, **kwargs)

Streaming question-answering (the real async implementation): yields reply text piece by piece.

Shares the base _scaffold (run context with scope + run-level hooks + exception routing). The output-side duties run inside the generator body only after the stream drains naturally: output guardrails -> one atomic history save -> on_run_end. If the consumer breaks early (break / aclose), none of the three happen (GeneratorExit is a BaseException and does not reach on_error), but the harness-level finally accounting always runs.

Tool loop: when the agent has registered tools, this runs the same model-tool loop as arun but with every model turn streamed -- text deltas are yielded as they arrive (including text preceding a tool call, matching common chat UIs), tools execute between turns (before_tool/after_tool hooks fire as usual), and the final no-tool-call turn's text is the answer. Unlike arun, the streaming loop does NOT support HITL suspend/resume or checkpoints: a tool that requires confirmation uses its synchronous confirm (ApprovalRequired propagates as an error in persistent setups) -- use arun when you need suspend semantics. History save matches arun: one atomic user + final-assistant turn (tool trajectories are not persisted to session history).

Output guardrail vs. streaming trade-off (buffer_output): - Default buffer_output=False: yield as it generates, check the guardrail on the final answer only after the stream drains. Content already emitted cannot be recalled (a tripped guardrail can only raise after the fact, it cannot stop text that already reached the consumer). - buffer_output=True: accumulate the full output first, run the output guardrail, and only after it passes release it piece by piece. With a tool loop this buffers ALL streamed text across turns and releases it only after the final answer passes the guardrail (tools still execute live in between).

Parameters:

Name Type Description Default
input_text str

User input (str, or a multimodal content-part list).

required
scope

This session's identifier; defaults to self.scope.

None
buffer_output bool

See above; default False (immediate streaming, guardrail checked after the fact).

False
trace_carrier

Optional upstream W3C trace carrier (see the same-named arg on arun); only useful when an OTelExporter(carrier_provider=...) is attached.

None
**kwargs

Passed through to the LLM streaming interface.

{}

stream_run

stream_run(input_text: str, *, scope=None, **kwargs)

Synchronous facade for astream_run (pumped via aio.iter_sync): returns a sync generator that yields piece by piece. Drain it explicitly or close it (e.g. contextlib.closing); in an async environment use astream_run instead.

RunResult dataclass

RunResult(final_output: Any = None, status: RunStatus = 'completed', interrupt: Optional[Interrupt] = None, usage: RunUsage = RunUsage(), new_messages: tuple[Message, ...] = (), run_id: Optional[str] = None)

Unified return envelope for run / arun / resume / aresume: bundles final output + whether a human-approval interrupt occurred + usage + new messages this turn into one object (rather than returning a bare string), turning a suspension from a silent accident into an explicitly checkable state.

Consumption template

r = agent.run("...") if r.interrupted: handle(r.interrupt) # HITL: take the suspended state to resume else: use(r.final_output) # completed: take the final output (str or structured instance)

Attributes:

Name Type Description
final_output Any

the completed state's final output (str, or a structured instance when output_schema was passed); None when suspended.

status RunStatus

"completed" or "interrupted".

interrupt Optional[Interrupt]

the suspended state's Interrupt (the pending action + the resume scope); None when completed.

usage RunUsage

usage snapshot of this run (RunUsage).

new_messages tuple[Message, ...]

messages newly added and stored in history this turn (user + assistant); empty when suspended.

run_id Optional[str]

this run's trace correlation id.

interrupted property

interrupted: bool

Whether this is a HITL suspended state (status == "interrupted").

RunUsage dataclass

RunUsage(llm_calls: int = 0, tool_calls: int = 0, total_tokens: int = 0)

Usage snapshot of a single run (for cost accounting / limit observability).

Attributes:

Name Type Description
llm_calls int

total LLM calls accumulated over this run.

tool_calls int

tool calls actually executed during this run.

total_tokens int

total tokens accumulated over this run (sum of usage.total_tokens across each LLM response).

PlanAgent

PlanAgent(name: str, llm: LLMClient, system_prompt: Optional[str] = None, *, tool_registry: Optional[ToolRegistry] = None, max_turns: int = 3, confirm: Optional[ConfirmCallback] = None, tracer=None, permissions=None, hooks=None, run_policy=None, session_store=None, scope=None, checkpoint_store=None, input_guardrails=None, output_guardrails=None, tool_retriever=None, context_builder=None, sources=None, reducer=None, window_budget=None, token_counter: TokenCounter = count_tokens, prompts=None)

Bases: BaseAgent

Plan-and-Solve orchestration recipe: plan (structured step breakdown) -> delegate step-by-step execution to an internal Agent -> synthesize the answer.

tool_registry: If passed, every execution step can call tools; without it, execution is pure reasoning (keyword-only).
max_turns: Upper bound on the tool-loop turns for each sub-step executor (the internal single-loop Agent), default 3 (not the number of plan steps).
tool_retriever / context_builder / sources: Context engineering, passed through to each step's executor; the Plan's own
    planning and synthesis calls also inject a memory/RAG block.
confirm / permissions / checkpoint_store: Passed through to the executor; with a checkpoint_store attached, high-risk tools
    during a step suspend/resume via HITL (the Plan main loop catches and propagates the Interrupt upward).
reducer / window_budget: Window-governance knobs, given to Plan's own Harness (when history overflows the window it is trimmed
    against the window budget) and also passed through to each step's executor (whose tool-trajectory trimming is likewise bound by these two knobs).
Other parameters are the same as BaseAgent.

ReflectionAgent

ReflectionAgent(name: str, llm: LLMClient, system_prompt: Optional[str] = None, *, max_turns: int = 3, tracer=None, hooks=None, run_policy=None, session_store=None, scope=None, input_guardrails=None, output_guardrails=None, tool_registry: Optional[ToolRegistry] = None, confirm: Optional[ConfirmCallback] = None, permissions=None, checkpoint_store=None, tool_retriever=None, context_builder=None, sources=None, reducer=None, window_budget=None, token_counter: TokenCounter = count_tokens, prompts=None)

Bases: BaseAgent

Reflection orchestration recipe: draft -> (reflect -> refine) xN, until the critique signals "best reached" or max_turns is hit. Optionally verifies with tools in the critique step.

tool_registry: Optional tool table; if passed, the critique step can call tools to verify facts / arithmetic. Without it, critique is pure self-reflection.
confirm / permissions / checkpoint_store: Passed through to the critique-executor; with a checkpoint_store attached, critique's
    high-risk tools suspend/resume via HITL (the Reflection main loop propagates the Interrupt upward).
tool_retriever: Passed through to the critique-executor (selects a relevant subset when critique has many tools).
context_builder + sources: memory/RAG injection; splices the retrieval block into the prompt in the draft / refine steps (the generation step benefits most).
reducer / window_budget: Window-governance knobs, given to Reflection's own Harness (when the reflection trajectory overflows the
    window it is trimmed against the window budget, keeping the latest answer plus the critique's key points) and also passed
    through to the critique-executor (whose verification trajectory is likewise bound).
Other parameters are the same as BaseAgent.

AgentSpec dataclass

AgentSpec(name: str, strategy: Literal['chat', 'react', 'reflection', 'plan'] = 'chat', model: Optional[Union[str, LLMClient]] = None, instructions: Optional[str] = None, tools: Optional[Union[list, ToolRegistry]] = None, scope: Optional[Scope] = None, session_store: Optional[SessionStore] = None, checkpoint_store: Optional[CheckpointStore] = None, tracer: Optional[Tracer] = None, input_guardrails: Optional[list[Guardrail]] = None, output_guardrails: Optional[list[Guardrail]] = None, hooks: Optional[list[Hook]] = None, run_policy: Optional[RunPolicy] = None, confirm: Optional[ConfirmCallback] = None, permissions: Optional[ToolPermissions] = None, max_turns: Optional[int] = None, compactor: Optional[HistoryCompactor] = None, tool_retriever: Optional[ToolRetriever] = None, context_builder: Optional[ContextBuilder] = None, sources: Optional[list[ContextSource]] = None, reducer: Optional['ReducerConfig'] = None, window_budget: Optional['WindowBudgetConfig'] = None, token_counter: 'TokenCounter' = count_tokens, prompts: Optional['PromptRegistry'] = None)

Declaratively aggregates every configurable point of an agent; strategy picks the paradigm, build_agent constructs from it.

The fields are a superset across strategies: common fields (including the memory/RAG injection context_builder+sources and the Tool-RAG tool_retriever) apply to the relevant strategies, while strategy-specific fields (compactor is chat-only, the single-loop Agent) only take effect on strategies that support them. Setting one on an unsupported strategy is rejected by build_agent (fail loud).

AgentTool

AgentTool(agent: BaseAgent, *, name: Optional[str] = None, description: Optional[str] = None, scope: Optional[Scope] = None, prompts=None)

Bases: Tool

Adapt an agent into a Tool: the main agent calls it to delegate one subtask and gets the result back (the main agent keeps control).

name: Tool name, defaults to agent.name; set it explicitly to disambiguate sub-agents that share a name.
description: Tool description telling the orchestrating LLM what this sub-agent is good at and when to delegate to it; defaults to a value generated from agent.name.
scope: The session ownership used when delegating to the sub-agent (advanced override: pin the sub-agent
    to a fixed scope). Defaults to None, in which case the parent agent's current run scope is picked up
    automatically (propagated through the run context, see _effective_scope), so that even when "one
    AgentTool instance serves multiple parent sessions" the sub-agent's history / memory stays isolated
    per parent session and never bleeds across them; if the parent has no run context (rare, calling the
    tool bare) it falls back to the sub-agent's own default scope. Pass this explicitly only when you
    genuinely need to pin the sub-agent to a specific scope.

get_parameters

get_parameters() -> list[ToolParameter]

Declare parameters: a single task string (the self-contained subtask handed to the sub-agent).

run

run(parameters: dict) -> ToolResponse

Synchronous delegation: hand the task to the sub-agent, run it, and return its reply (normalized into a ToolResponse via _textualize).

arun async

arun(parameters: dict) -> ToolResponse

Native async delegation: await the sub-agent's arun (a truly async strategy runs async, otherwise its arun auto-dispatches to a thread pool).

build_agent

build_agent(spec: AgentSpec) -> BaseAgent

Construct the matching strategy agent based on spec.strategy.

str -> "provider:model" (e.g. "deepseek:deepseek-v4-flash", split into

LLMClient(provider, model=right_half)); a bare provider name (no colon, e.g. "deepseek") is still treated as a provider (using the .env key + the provider's default model); an LLMClient instance -> used directly (lets you pin model / key / base_url); None -> LLMClient() default.

tools: list[Tool] -> build a new ToolRegistry and register them / ToolRegistry -> used as-is / None -> no tools. A field unsupported by the strategy that is set to a non-default value raises ValueError (avoids the silent "set but had no effect" trap).

Returns:

Name Type Description
BaseAgent BaseAgent

the constructed strategy instance (single-loop Agent (chat/react) / ReflectionAgent / PlanAgent).