Planck.Agent.ToolRunner (Planck.Agent v0.1.11)

Copy Markdown View Source

Tracks in-flight tool executions and handles the full tool execution pipeline: resolution, argument validation, safe execution, and loop detection.

loop_counts persists across tool batches within the same user turn and resets when a new user turn begins (do_run_llm with :new_turn).

Summary

Functions

Kill all in-flight tool task processes.

Return true when all tool calls have completed.

Mark a tool call as done.

Return an empty runner.

Start a new tool batch while preserving loop_counts from the previous batch.

Resolve, wrap, and track a tool call. Returns {updated_runner, wrapped_fn}.

Register a set of running tool tasks.

Types

t()

@type t() :: %Planck.Agent.ToolRunner{
  loop_counts: %{optional({String.t(), non_neg_integer()}) => non_neg_integer()},
  results: list(),
  running: %{required(String.t()) => %{name: String.t(), pid: pid()}}
}
  • :running — map of call_id => %{name: name, pid: pid} for in-flight tools
  • :results — accumulated {call_id, result} pairs as tools complete
  • :loop_counts — consecutive call counts keyed by {tool_name, args_hash}; persists across tool batches within a user turn, reset on new turns

Functions

cancel_all(runner)

@spec cancel_all(t()) :: :ok

Kill all in-flight tool task processes.

done?(runner)

@spec done?(t()) :: boolean()

Return true when all tool calls have completed.

mark_done(runner, call_id, result)

@spec mark_done(t(), String.t(), term()) :: {:ok, t()} | :not_running

Mark a tool call as done.

Returns {:ok, updated_runner} or :not_running when call_id is not in the running set (stale result after an abort).

new()

@spec new() :: t()

Return an empty runner.

next_batch(runner, entries)

@spec next_batch(t(), [{String.t(), String.t(), pid()}]) :: t()

Start a new tool batch while preserving loop_counts from the previous batch.

Used for tool continuations within the same user turn so loop detection accumulates across multiple LLM rounds.

prepare_call(runner, tools, agent_id, name, call_id, args)

@spec prepare_call(
  t(),
  %{required(String.t()) => Planck.Agent.Tool.t()},
  String.t(),
  String.t(),
  String.t(),
  map()
) :: {t(), (-> {:ok, String.t()} | {:error, term()})}

Resolve, wrap, and track a tool call. Returns {updated_runner, wrapped_fn}.

Looks up the tool by name, records the call for loop detection, and returns a zero-arg closure that:

  • Validates arguments against the tool schema
  • Executes safely, catching all exceptions and normalising them to strings
  • Appends a loop nudge to binary results when consecutive identical calls reach @loop_threshold

start(entries)

@spec start([{String.t(), String.t(), pid()}]) :: t()

Register a set of running tool tasks.