PtcRunner

View Source

Hex.pm Docs CI Hex Downloads License GitHub

A BEAM-native Elixir library for Programmatic Tool Calling (PTC). Execute LLM-generated programs that orchestrate tools and transform data safely inside sandboxed processes.

What is PTC?

Programmatic Tool Calling is an execution model where an LLM writes small programs to process data, rather than making individual tool calls. Instead of returning large datasets to the model (which bloats context), the model generates a program that calls tools, filters/transforms results, and returns only the final answer.

The pattern was introduced by Anthropic in their blog posts on advanced tool use and code execution with MCP.

Quick Example

iex> tools = %{
...>   "get_expenses" => fn _args ->
...>     [
...>       %{"category" => "travel", "amount" => 500},
...>       %{"category" => "food", "amount" => 50},
...>       %{"category" => "travel", "amount" => 200}
...>     ]
...>   end
...> }
iex> program = ~S|{"program": {"op": "pipe", "steps": [
...>   {"op": "call", "tool": "get_expenses"},
...>   {"op": "filter", "where": {"op": "eq", "field": "category", "value": "travel"}},
...>   {"op": "sum", "field": "amount"}
...> ]}}|
iex> {:ok, result, _memory_delta, _new_memory} = PtcRunner.Json.run(program, tools: tools)
iex> result
700

PTC-Lisp (same result, more compact):

iex> tools = %{"get-expenses" => fn _args ->
...>   [%{"category" => "travel", "amount" => 500},
...>    %{"category" => "food", "amount" => 50},
...>    %{"category" => "travel", "amount" => 200}]
...> end}
iex> program = ~S|(->> (call "get-expenses" {}) (filter (where :category = "travel")) (sum-by :amount))|
iex> {:ok, result, _, _} = PtcRunner.Lisp.run(program, tools: tools)
iex> result
700

Why PTC?

Traditional tool calling requires multiple LLM round-trips:

LLM  get_employees()  LLM  filter(dept=eng)  LLM  avg(salary)  LLM

With PTC, the LLM writes one program executed locally:

(->> (call "get-employees" {}) (filter (where :department = "engineering")) (avg-by :salary))

Benchmark snapshot (DeepSeek V3.2, 15 queries, 2500 records):

DSLPassedAvg AttemptsCost
PTC-JSON15/151.3$0.002
PTC-Lisp14/151.2$0.002

Small sample—see Performance and Use Cases for methodology.

Two DSLs — same engine, same operations:

  • PTC-JSON — Easy to generate and validate
  • PTC-Lisp — 8x fewer output tokens, Clojure-compatible

Installation

def deps do
  [{:ptc_runner, "~> 0.3"}]
end

Features

  • Two DSLs: JSON (verbose, universal) and Lisp (compact, LLM-friendly)
  • Safe: Fixed operations, no arbitrary code execution
  • Fast: Isolated BEAM processes with configurable timeout (1s) and memory (10MB) limits
  • Simple: No external dependencies (Python, containers, etc.)
  • Cost-efficient: Tested with budget models (DeepSeek 3.2, Gemini 2.5 Flash)
  • Retry-friendly: Structured errors with actionable messages for LLM retry loops
  • Stateful: Context refs enable persistent memory across agentic loop iterations

Documentation

License

MIT