Expand description
First-class sub-agents with recursion-depth tracking.
This is the harness’s flagship recursion surface: it lets one agent run
another agent as a child of itself, so a language model orchestrating tools
is, transparently, a language model orchestrating other models. It is the
concrete “agents calling agents” mechanism behind the crate’s
recursive-language-model framing — the in-harness analogue of the graph-side
crate::graph::subgraph recursion.
This module provides the agent-calling-agent compositional primitive:
SubAgentwraps anAgentHarnessand runs it as a child run one level deeper in the recursion tree than its caller.SubAgentTooladapts aSubAgentinto aToolso a parent agent can invoke another agent exactly like any other tool.SubAgentSessionkeeps a singleSubAgentalive across multiple turns, reusing the same harness while accumulating the conversation transcript — the post-completion, human-in-the-loop reuse primitive.
§Reuse vs. steering
There are two ways an orchestrator keeps a sub-agent “in play” across human input:
- Reuse (
SubAgentSession): the child run completes, the orchestrator obtains human input, then calls the same sub-agent again carrying the prior transcript. Nothing is killed or restarted. - Steering (
crate::harness::steering): an orchestrator/human injects commands into a still-running agent at safe checkpoints.
SubAgentSession implements the first. The flow is:
session.send(state, ctx, vec![Message::user("…")])— runs the sub-agent over the retained transcript and folds its reply back in.- Inspect the returned
AgentRun; obtain human input out-of-band. session.send(state, ctx, vec![Message::user(human_reply)])— the same sub-agent answers with the full prior context still in the transcript.
Every send after the first emits AgentEvent::SubAgentReused so the reuse
is visible alongside the per-send
SubAgentStarted/SubAgentCompleted
bracket.
§Depth tracking
Every run carries a depth in its RunConfig (top-level runs are depth
0). When a sub-agent is invoked at parent_depth, its child run is created
at parent_depth + 1. The depth cap is
RunLimits::max_depth
(default RunLimits::DEFAULT_MAX_DEPTH,
i.e. 8), read from the child harness’s RunPolicy.
If the child depth would exceed the cap, the invocation fails fast with
TinyAgentsError::SubAgentDepth before any model call — a deterministic,
cheap guard against unbounded recursion.
§Observability
Each invocation emits AgentEvent::SubAgentStarted and
AgentEvent::SubAgentCompleted (carrying the sub-agent name and child
depth). When invoked with a shared EventSink — via
SubAgent::invoke_with_events or SubAgent::invoke_in_parent — the child
run’s own events also flow onto the parent sink, so a parent observer sees
the full nested run tree.
§Layout
- [
types] holds the public type definitions. - This file holds the impls (constructors, the invoke methods, and the
Tooladapter). test.rsholds focused tests.
Structs§
- SubAgent
- A reusable, named child agent built on top of an
AgentHarness. - SubAgent
Session - A persistent, reusable conversation with a single
SubAgent. - SubAgent
Tool - A
Tooladapter that exposes aSubAgentto a parent agent — the surface that turns “agents calling agents” into an ordinary tool call.
Constants§
- SUBAGENT_
INPUT_ FIELD - The argument key a
SubAgentToolreads the child input from.