Tool preparation and wrapping for SubAgent execution.
This module normalizes tools from various formats into executable functions and wraps them with telemetry events for observability.
Tool Types
SubAgentTool- Wrapped child agents that inherit context and limits- Function/1 - Direct tool functions that receive args map
- Other values - Passed through unchanged
Wrapping Behavior
Tool functions are wrapped to:
- Handle return value normalization (
{:ok, value},{:error, reason}, or raw values) - Emit telemetry events on tool start/stop
- Inherit runtime context for nested SubAgents
Trace Propagation
When trace_context is present in state, child SubAgentTool executions receive a child trace context with:
- New unique trace_id for the child's trace file
- Parent's current span_id as parent_span_id
- Incremented depth for visualization
Summary
Functions
Build a child trace context from the parent state.
Normalize tools map to convert SubAgentTool instances into executable functions.
Wrap the builtin llm-query tool.
Wrap an LLMTool in a function closure that executes an ephemeral single-shot SubAgent.
Wrap a regular tool function to handle various return formats.
Wrap a SubAgentTool in a function closure that executes the child agent.
Wrap a tool function with telemetry events.
Functions
Build a child trace context from the parent state.
Returns {child_trace_context, child_trace_id} or {nil, nil} if tracing
is not enabled.
The child trace context includes:
trace_id: New unique ID for this child's traceparent_span_id: Current span ID from the parent (via Telemetry)depth: Parent's depth + 1
@spec normalize(map(), map(), PtcRunner.SubAgent.t()) :: map()
Normalize tools map to convert SubAgentTool instances into executable functions.
Each tool is wrapped with telemetry events and return value normalization.
Parameters
tools- Map of tool name to tool definitionstate- Current loop state (for context inheritance)agent- Parent agent (for telemetry metadata)
Returns
Map of tool names to wrapped executable functions.
Wrap the builtin llm-query tool.
Splits args into control keys (:prompt, :signature, :llm, :response_template)
and template args (everything else). Constructs an ephemeral %LLMTool{} and
delegates to execute_llm_json/4.
@spec wrap_llm_tool(String.t(), PtcRunner.SubAgent.LLMTool.t(), map()) :: function()
Wrap an LLMTool in a function closure that executes an ephemeral single-shot SubAgent.
The wrapped function:
- Resolves LLM from tool config or inherits from parent
- Creates a single-shot SubAgent with
output: :text - Inherits system limits (nesting_depth, remaining_turns, mission_deadline)
- Creates a child trace file when parent has tracing enabled
Wrap a regular tool function to handle various return formats.
Converts:
{:ok, value}->value{:error, reason}-> raises with error messagevalue->value(pass-through)
@spec wrap_sub_agent_tool(String.t(), PtcRunner.SubAgent.SubAgentTool.t(), map()) :: function()
Wrap a SubAgentTool in a function closure that executes the child agent.
The wrapped function:
- Resolves LLM in priority order: agent.llm > bound_llm > parent's llm
- Inherits llm_registry, nesting_depth, remaining_turns, and mission_deadline
- Creates a child trace file when parent has tracing enabled
- Returns the child agent's return value or raises on failure
When trace_context is present in state, the wrapped function:
- Starts a new TraceLog session for the child (creating a physical trace file)
- Returns a special map with
__child_trace_id__so callers can collect trace IDs
@spec wrap_with_telemetry(String.t(), function(), PtcRunner.SubAgent.t()) :: function()
Wrap a tool function with telemetry events.
Emits [:sub_agent, :tool, :start] and [:sub_agent, :tool, :stop] events.