PtcRunner.SubAgent.Compiler (PtcRunner v0.4.1)

View Source

Compilation logic for SubAgents.

This module provides the compile/2 function that transforms a SubAgent into a CompiledAgent by running it once with an LLM to derive the PTC-Lisp program. The resulting CompiledAgent can then be executed many times without further LLM calls.

See PtcRunner.SubAgent.compile/2 for the public API.

Summary

Functions

Compiles a SubAgent into a reusable PTC-Lisp function.

Functions

compile(agent, opts)

@spec compile(
  PtcRunner.SubAgent.t(),
  keyword()
) :: {:ok, PtcRunner.SubAgent.CompiledAgent.t()} | {:error, PtcRunner.Step.t()}

Compiles a SubAgent into a reusable PTC-Lisp function.

The LLM is called once during compilation to derive the logic. The resulting CompiledAgent can then be executed many times without further LLM calls, making it efficient for processing many items with deterministic logic.

Restrictions

Only agents with pure tools can be compiled. Agents with LLM-dependent tools will raise ArgumentError:

  • LLMTool - requires LLM at execution time
  • SubAgentTool - requires LLM at execution time

Options

  • llm - Required. LLM callback used once during compilation. Can be a function or atom.
  • llm_registry - Required if llm is an atom. Maps atoms to LLM callbacks.
  • sample - Optional sample data to help LLM understand the input structure (default: %{})

Returns

  • {:ok, CompiledAgent.t()} - Successfully compiled agent
  • {:error, Step.t()} - Compilation failed (agent execution failed)

Examples

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 (ctx/double {:n ctx/n})})|} end
iex> {:ok, compiled} = PtcRunner.SubAgent.Compiler.compile(agent, llm: mock_llm, sample: %{n: 5})
iex> compiled.signature
"(n :int) -> {result :int}"
iex> is_binary(compiled.source)
true
iex> is_function(compiled.execute, 1)
true
iex> result = compiled.execute.(%{n: 10})
iex> result.return.result
20

Rejects agents with LLM-dependent tools:

iex> alias PtcRunner.SubAgent.LLMTool
iex> tools = %{"classify" => LLMTool.new(prompt: "Classify {{x}}", signature: "(x :string) -> :string")}
iex> agent = PtcRunner.SubAgent.new(prompt: "Process {{item}}", signature: "(item :string) -> {category :string}", tools: tools)
iex> PtcRunner.SubAgent.Compiler.compile(agent, llm: fn _ -> {:ok, ""} end)
** (ArgumentError) cannot compile agent with LLM-dependent tool: classify