Toolnexus.Agents (toolnexus v0.12.0)

Copy Markdown View Source

Sub-agents — the Level-1 surface over the agent runtime (SPEC §7D).

One axiom: an Agent is a Tool — (system prompt × a filtered toolkit view × the §8 client loop), invocable as a uniform Toolnexus.Tool. One new noun: agent/2. Everything compiles to the six runtime verbs.

explore = Toolnexus.Agents.agent("explore", does: "read-only research", uses: %{tools: [lookup]})

coder =
  Toolnexus.Agents.agent("coder",
    does: "implements changes",
    soul_file: "AGENTS.md",
    team: [explore]
  )

r = Toolnexus.Agents.run(coder, [transport: transport, llm: %{model: "gpt-4o-mini"}], "fix the failing test")
r.text

as_tool/2 is the bridge the other way: it turns an agent into a %Toolnexus.Tool{} for the classic API's extra tools. If the agent suspends durably (§10), the tool result carries metadata.pending, and a §10 retry with ctx.answer resumes it — agent suspension and tool suspension are the same machinery.

Summary

Functions

The one new noun. Spec fields (§7D Level-1 surface)

The bridge: an Agent IS a Tool — drop it into the classic API's extra tools.

Collect this agent + its whole team graph into a runtime registry — the transitive closure of the entry agent's team graph; unreachable agents are not present (§7D team scoping).

Level 1: one-shot — build a runtime, run the agent to completion, tear down.

Functions

agent(name, spec)

@spec agent(String.t(), keyword() | map()) :: Toolnexus.Agents.AgentDef.t()

The one new noun. Spec fields (§7D Level-1 surface):

  • :does — required routing description (advertised to delegating parents)
  • :uses — toolkit view, %{tools: [%Toolnexus.Tool{}]}
  • :soul — inline system prompt, or :soul_file — path to read it from
  • :team — list of agent/2 values this agent may delegate to via task (children never inherit delegation — recursion is opt-in per definition)
  • :budget%{max_turns, max_tokens, max_tool_calls, max_wall_ms, max_children, max_concurrent, max_depth}
  • :model — default "inherit" (the runtime's llm.model)
  • :wait_for — §10 interpreter authority ((Request -> Answer))
  • :on_spawn / :on_close — lifecycle callbacks
  • :hooks / :on_metric — the §8 seams for THIS agent's turns; each replaces the runtime-wide value (never merged). A §7F compactor rides :hooks.

as_tool(a, rt_opts)

The bridge: an Agent IS a Tool — drop it into the classic API's extra tools.

A durable suspension surfaces as a §10 pending tool result; the client's retry-with-ctx.answer re-runs the agent with that Answer as its interpreter.

registry(a, acc \\ %{})

@spec registry(Toolnexus.Agents.AgentDef.t(), map()) :: map()

Collect this agent + its whole team graph into a runtime registry — the transitive closure of the entry agent's team graph; unreachable agents are not present (§7D team scoping).

run(a, rt_opts, prompt)

@spec run(Toolnexus.Agents.AgentDef.t(), keyword() | map(), String.t()) :: map()

Level 1: one-shot — build a runtime, run the agent to completion, tear down.

rt_opts are Toolnexus.Agents.Runtime options (:transport, :llm, ...). Returns %{text, is_error, status, pending, turns, total_tokens}. When the run suspends durably (status: "pending"), the live runtime rides along under :runtime so the host can Runtime.resume/2 and must shut it down itself; otherwise the runtime is already torn down.