A compiled SubAgent with pre-derived PTC-Lisp logic.
Created via SubAgent.compile/2, this struct stores PTC-Lisp code derived
once by an LLM. The compiled agent can then be executed many times without
further LLM calls, making it efficient for processing many items with
deterministic logic.
Use Cases
- Processing batch data with consistent logic (e.g., scoring reports)
- Orchestrating SubAgentTools with deterministic control flow
- Workflows where the logic is derived once and reused many times
Tool Support
- Pure Elixir tools - Supported, executed directly
LLMTool- NOT supported (raises ArgumentError at compile time)SubAgentTool- Supported, requiresllmoption at execute time
When executing a compiled agent with SubAgentTools, pass the LLM at runtime:
compiled.execute.(%{topic: "cats"}, llm: runtime_llm)Runtime Options
The execute function accepts optional keyword arguments:
llm- Required if agent has SubAgentTools. LLM for child agents.llm_registry- Map of atom to LLM functions (if SubAgentTools use atom LLMs)_nesting_depth- Inherited context depth (used when nested in another agent)_remaining_turns- Inherited turn budget_mission_deadline- Inherited mission deadline
See SubAgent.compile/2 for compilation details.
Fields
source- Inspectable PTC-Lisp source code (String)signature- Functional contract copied from agent (String)execute- Pre-bound executor function(map(), keyword() -> result)metadata- Compilation metadata (seemetadata/0)field_descriptions- Descriptions for signature fields (Map, optional)llm_required?- Whether the agent requires an LLM at runtime
Examples
Compile and execute:
iex> tools = %{"double" => fn %{"n" => n} -> n * 2 end}
iex> agent = PtcRunner.SubAgent.new(
...> prompt: "Double the input number {{n}}",
...> signature: "(n :int) -> {result :int}",
...> tools: tools,
...> max_turns: 1
...> )
iex> mock_llm = fn _ -> {:ok, ~S|(return {:result (tool/double {:n data/n})})|} end
iex> {:ok, compiled} = PtcRunner.SubAgent.compile(agent, llm: mock_llm, sample: %{n: 5})
iex> compiled.signature
"(n :int) -> {result :int}"
iex> compiled.source
~S|(return {:result (tool/double {:n data/n})})|
iex> compiled.llm_required?
false
iex> result = compiled.execute.(%{n: 10}, [])
iex> result.return.result
20
Summary
Functions
Wraps a compiled agent as a callable tool.
Types
@type metadata() :: %{ compiled_at: DateTime.t(), tokens_used: non_neg_integer(), turns: pos_integer(), llm_model: String.t() | nil }
Metadata captured during compilation.
Fields:
compiled_at- UTC timestamp when compilation completedtokens_used- Total tokens consumed during compilationturns- Number of LLM turns used during compilationllm_model- Model identifier if available from LLM response
@type t() :: %PtcRunner.SubAgent.CompiledAgent{ execute: (map(), keyword() -> PtcRunner.Step.t()), field_descriptions: map() | nil, llm_required?: boolean(), metadata: metadata(), signature: String.t() | nil, source: String.t() }
CompiledAgent struct.
Fields:
source- PTC-Lisp program source codesignature- Type signature for inputs/outputsexecute- Function that executes the program(map(), keyword() -> Step.t())metadata- Compilation metadatafield_descriptions- Descriptions for signature fieldsllm_required?- Whether the agent requires an LLM at runtime
Functions
@spec as_tool(t()) :: %{ type: :compiled, execute: (map() -> PtcRunner.Step.t()), signature: String.t() | nil }
Wraps a compiled agent as a callable tool.
The resulting tool can be used in parent agents. When called, it executes the compiled PTC-Lisp program without making any LLM calls.
Note: The returned tool has a 1-arity execute function for compatibility with dynamic agents. Compiled agents with SubAgentTools should not be used as tools in dynamic agents (they require runtime LLM options that can't be passed through the 1-arity interface).
Examples
iex> tools = %{"double" => fn %{"n" => n} -> n * 2 end}
iex> agent = PtcRunner.SubAgent.new(
...> prompt: "Double {{n}}",
...> signature: "(n :int) -> {result :int}",
...> tools: tools,
...> max_turns: 1
...> )
iex> mock_llm = fn _ -> {:ok, ~S|(return {:result (tool/double {:n data/n})})|} end
iex> {:ok, compiled} = PtcRunner.SubAgent.compile(agent, llm: mock_llm, sample: %{n: 1})
iex> tool = PtcRunner.SubAgent.CompiledAgent.as_tool(compiled)
iex> tool.type
:compiled
iex> result = tool.execute.(%{n: 5})
iex> result.return.result
10