Skip to main content

Module subagent

Module subagent 

Source
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:

  • SubAgent wraps an AgentHarness and runs it as a child run one level deeper in the recursion tree than its caller.
  • SubAgentTool adapts a SubAgent into a Tool so a parent agent can invoke another agent exactly like any other tool.
  • SubAgentSession keeps a single SubAgent alive 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:

  1. session.send(state, ctx, vec![Message::user("…")]) — runs the sub-agent over the retained transcript and folds its reply back in.
  2. Inspect the returned AgentRun; obtain human input out-of-band.
  3. 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 Tool adapter).
  • test.rs holds focused tests.

Structs§

SubAgent
A reusable, named child agent built on top of an AgentHarness.
SubAgentSession
A persistent, reusable conversation with a single SubAgent.
SubAgentTool
A Tool adapter that exposes a SubAgent to a parent agent — the surface that turns “agents calling agents” into an ordinary tool call.

Constants§

SUBAGENT_INPUT_FIELD
The argument key a SubAgentTool reads the child input from.