# `PtcRunner.SubAgent.Loop.ToolNormalizer`
[🔗](https://github.com/andreasronge/ptc_runner/blob/main/lib/ptc_runner/sub_agent/loop/tool_normalizer.ex#L1)

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:
1. Handle return value normalization (`{:ok, value}`, `{:error, reason}`, or raw values)
2. Emit telemetry events on tool start/stop
3. 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

# `build_child_trace_context`

```elixir
@spec build_child_trace_context(map()) :: {map() | nil, String.t() | nil}
```

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 trace
- `parent_span_id`: Current span ID from the parent (via Telemetry)
- `depth`: Parent's depth + 1

# `normalize`

```elixir
@spec normalize(map(), map(), PtcRunner.SubAgent.Definition.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 definition
- `state` - Current loop state (for context inheritance)
- `agent` - Parent agent (for telemetry metadata)

## Returns

Map of tool names to wrapped executable functions.

# `normalize`

```elixir
@spec normalize(map(), map(), PtcRunner.SubAgent.Definition.t(), keyword()) :: map()
```

# `wrap_builtin_llm_query`

```elixir
@spec wrap_builtin_llm_query(String.t(), map()) :: function()
```

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`.

# `wrap_llm_tool`

```elixir
@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_return`

```elixir
@spec wrap_return(String.t(), function()) :: function()
```

Wrap a regular tool function to handle various return formats.

Converts:
- `{:ok, value}` -> `value`
- `{:error, reason}` -> raises with error message
- `value` -> `value` (pass-through)

# `wrap_sub_agent_tool`

```elixir
@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:
1. Starts a new TraceLog session for the child (creating a physical trace file)
2. Returns a special map with `__child_trace_id__` so callers can collect trace IDs

# `wrap_with_telemetry`

```elixir
@spec wrap_with_telemetry(
  String.t(),
  function(),
  PtcRunner.SubAgent.Definition.t(),
  String.t() | nil
) ::
  function()
```

Wrap a tool function with telemetry events.

Emits `[:sub_agent, :tool, :start]` and `[:sub_agent, :tool, :stop]` events.
Uses `agent_name` and `agent_id` for v2 flat trace format.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
