AgentEngine.Turn (agent_engine v0.2.0)

Copy Markdown View Source

Host-owned, single-agent turn.

turn/3 advances an AgentEngine.Session by one exchange — it appends the user message (or host-resolved tool results), calls the host-supplied LLM function once, and records the assistant reply. It is distilled from the public turn/recomposition path of host applications: one LLM call per invocation, then either a completed reply or a suspension awaiting tool results. AgentEngine never executes host tools and performs no provider routing — the :llm function is the host's seam for both.

Frozen success shape

{:ok, content, updated_runtime, signals}

The shape is frozen and must not change without a major version bump:

  • content — the assistant's final text (a binary), or nil when the turn suspended awaiting tool results.
  • updated_runtime — an AgentEngine.Turn.Runtime that embeds the advanced AgentEngine.Session plus the working transcript, so a suspended turn can be resumed by passing it back into turn/3.
  • signals — a list produced by the optional :extract_signals callback, defaulting to [] when no extractor is supplied.

Tool-call round trip

When the LLM requests tool calls, the turn suspends:

{:ok, nil, runtime, []}

The host executes the calls, then resumes by passing the runtime back with :tool_results:

Turn.turn(runtime, nil, llm: llm, tool_results: results)

If a new user message is submitted while tool calls are still pending, the turn refuses with {:error, {:tool_results_required, ids}}.

Options

  • :llm (required) — (messages, llm_opts) -> {:ok, response} | {:error, term()} where response is an LlmCore.LLM.Response (or any map with content and tool_calls fields). messages is the normalized transcript.

  • :tools — list of LlmToolkit.Tool structs forwarded to the LLM (default []). AgentEngine advertises them generically; it never runs them.
  • :tool_results — list of LlmToolkit.Tool.Result structs (or maps) used to resume a suspended turn (default []).
  • :system_prompt — optional system message prepended once to a fresh transcript.
  • :llm_opts — extra keyword options merged into the LLM call options.
  • :extract_signals — optional (content -> [term()]) callback applied to the final assistant content. Absent extractor ⇒ signals == [].

Summary

Types

llm()

@type llm() :: ([map()], keyword() -> {:ok, map() | struct()} | {:error, term()})

opts()

@type opts() :: [
  llm: llm(),
  tools: [LlmToolkit.Tool.t()],
  tool_results: [map() | struct()],
  system_prompt: String.t(),
  llm_opts: keyword(),
  extract_signals: signal_extractor() | nil
]

signal_extractor()

@type signal_extractor() :: (String.t() | nil -> [term()])

Functions

turn(session_or_runtime, user_message, opts)

@spec turn(
  AgentEngine.Session.t() | AgentEngine.Turn.Runtime.t(),
  String.t() | nil,
  opts()
) ::
  {:ok, String.t() | nil, AgentEngine.Turn.Runtime.t(), [term()]}
  | {:error, term()}

Run a single agent turn.

Accepts either a bare AgentEngine.Session (for the first turn of a conversation) or a previously returned AgentEngine.Turn.Runtime (to continue). Returns the frozen success shape, or an error.