Execute parsed plans with SubAgents.
Takes a normalized PtcRunner.Plan and executes each task in dependency order,
using SubAgents for each task. Results flow between tasks via template expansion.
Parallel Execution
Tasks are grouped into phases by dependency level. Within each phase, all tasks execute in parallel. Phases execute sequentially.
Error Handling
Each task can specify on_failure:
:stop(default) - Stop execution on failure:skip- Log and continue with other tasks:retry- Retry up tomax_retriestimes before failing:replan- On deliberate agent failure via(fail "reason"), trigger replanning
Example
{:ok, plan} = PtcRunner.Plan.parse(llm_generated_plan)
{:ok, results} = PtcRunner.PlanRunner.execute(plan,
llm: my_llm,
base_tools: %{
"search" => &MyApp.search/1,
"fetch" => &MyApp.fetch/1
}
)Result Flow
Task results are available to subsequent tasks via the results map:
- In task input:
"Analyze {{results.research_task.data}}" - Previous task outputs are automatically injected
Options
llm- Required. LLM callback for all agentsllm_registry- Optional map of atom -> llm callbackbase_tools- Tool implementations (map of name -> function)available_tools- Tool descriptions (map of name -> description string). Used to enrich raw function tools with signatures so the LLM knows how to call them. Format:"Description. Input: {param: type}. Output: {field: type}"timeout- Per-task sandbox timeout in ms (default: 30_000)pmap_timeout- Per-pmap/pcalls task timeout in ms (default: same astimeout). Increase for LLM-backed tools.max_turns- Max turns per agent (default: 5)max_concurrency- Max parallel tasks per phase (default: 10)reviews- Map of task_id => decision for human review tasks (default: %{})initial_results- Pre-populated results map (default: %{}). Tasks with IDs already in this map are skipped. Used for replanning - pass completed results from previous execution to avoid re-running successful tasks.on_event- Optional callback for task lifecycle events. Receives tuples like{:task_started, %{task_id: id, attempt: n}},{:task_succeeded, %{...}}, etc.builtin_tools- List of builtin tool families to enable for PTC-Lisp agents (default:[]). Available::grep(adds grep and grep-n tools). Only injected for agents running in:ptc_lispoutput mode.quality_gate- Enable pre-flight data sufficiency check before tasks with dependencies (default:false). When enabled, a lightweight SubAgent validates upstream results before each dependent task. On failure, triggers{:replan_required, context}.quality_gate_llm- Optional separate LLM callback for quality gate checks. Falls back to the mainllmif not provided.
Human Review Tasks
Plans can include type: "human_review" tasks that pause execution until
a human provides a decision. When encountered:
- First invocation returns
{:waiting, pending_reviews, partial_results} - Application presents review to human, collects decision
- Re-invoke with
reviews: %{"task_id" => decision}to continue
Example:
# First call - hits human review, pauses
{:waiting, pending, results} = PlanRunner.execute(plan, llm: llm)
# Collect human decision (app-specific)
decision = get_human_decision(hd(pending))
# Continue with the decision
{:ok, final_results} = PlanRunner.execute(plan,
llm: llm,
reviews: Map.put(results, hd(pending).task_id, decision)
)
Summary
Functions
Execute a parsed plan.
Types
@type execute_result() :: {:ok, %{required(String.t()) => term()}} | {:error, String.t(), %{required(String.t()) => term()}, term()} | {:waiting, [pending_review()], %{required(String.t()) => term()}} | {:replan_required, replan_context()}
@type result() :: %{ task_id: String.t(), status: :ok | :error, value: term(), duration_ms: non_neg_integer() }
Functions
@spec execute( PtcRunner.Plan.t(), keyword() ) :: execute_result()
Execute a parsed plan.
Runs tasks in parallel phases (respecting dependencies). Each task's results are available to subsequent tasks via template expansion.
Parameters
plan- Parsed%Plan{}structopts- Execution options
Returns
{:ok, results}- Map of task_id to task result value{:error, failed_task_id, partial_results, reason}- First critical failure with partial results{:waiting, pending_reviews, partial_results}- Paused at human review{:replan_required, context}- Verification failed with:replanstrategy