v1.3.8

Execution Engine

Last updated


Every session-backed entry point (TUI, which since v1.2.0 sends its runs to the daemon over the Unix socket instead of executing them itself, /v1/send, pending resume, Telegram, Discord) goes through the same startup: exec.Prepare matches a skill from the input, then exec.Run resolves a skill named by the caller, emits the skill and model selection events, picks the model and its fallbacks through exec/model.Route, and hands off to exec.Execute(). Subagents and the scheduler call exec.Run directly with isSub=true and skip exec.Prepare; the stateless /v1/chat/completions skips both and calls exec.Execute() itself. exec.Start was renamed exec.Run in v1.2.1, and ResolveAgent became exec/model.Route in the same release. Since v1.1.0 reasoning is a per-session setting: when it is auto (or unset) the selector inside exec/model.Route also decides the reasoning level from the kind of work, and the global auto_reasoning switch was removed. Auto routing never selects a pass-tier model, even when the message names it, and such models are left out of the fallback list; only a session pinned to one, or a caller passing it as the explicit model, runs it.
exec.Execute() runs the main loop for up to 256 iterations (limits.max_tool_iterations; 128 before v1.1.2). Each iteration:
  1. Assemble messages: SystemPrompts + ContextHistories (guardrail refusals dropped) + the turn context, if any + UserMessage + ToolHistories (ContextHistories and UserMessage were OldHistories and UserInput before v1.2.1) — appended in that order, never rewritten mid-run, so the prompt-cache prefix stays stable. Since v1.3.7 the instructions connected MCP servers send are rendered inside the main system prompt, ahead of the guardrail block, instead of riding as a second system message, and the system prompt templates are English-only. Since v1.2.0 the turn context is one user message built each turn by assignTurnContext: the work directory (not for stateless /v1/chat/completions runs), the names of the tools to call through run_tool (since v1.3.7 MCP tools grouped by server as mcp__<server>__{a, b}), the skill list (omitted when run_skill is excluded), the background tasks this same task still has running (since v1.3.7, so a resumed turn knows which results are still on their way), the rolling summary as a Prior summary JSON block (since v1.3.7; it used to be a separate message between the history and the turn context), and the CLAUDE.md / AGENTS.md guide when the guide toggle is on; these used to sit in the system prompt, where every change reset the cache. The permission mode is no longer stated there or in the system prompt (Removed in v1.3.7). Since v1.3.7 the summary's key_decisions, past_discussions and current_discussion entries are first filtered by the decision model down to those relevant to the request — every entry is kept without a decision model or when the call fails, and the summary is left out when none is relevant — and the rules for using it live in the system prompt. Since v1.3.1, when a decision model is set, two more checks run in parallel with that one before the loop starts: one adds a tool-gap line telling the model to call reasoning_guide(topics=["tool_generate"]) first when the request needs a capability no available tool provides (skipped when reasoning_guide or edit_tool is excluded), and the other drops skills it judges unrelated to the request from the skill list (a failed check keeps every skill)
  2. Call Agent.Send() on the chosen provider
  3. Parse tool_calls from the response
  4. Dispatch the tool calls through toolCall.go (see Tool Dispatch)
  5. Append results to ToolHistories; images returned by tools follow the round's results there as one user message (since v1.1.1 — they used to be injected into UserInput, which rewrote the cached prefix)
  6. Stop when no tool_calls remain or the iteration limit is hit

Since v1.3.0 a TUI run can leave work in the background, since v1.3.2 through background_command and background_subagents; both are excluded from the run unless the request comes from the TUI (cli- origin with no deliver target). run_command_background was renamed background_command (Removed in v1.3.2); run_websocket and the subagents background: true mode were dropped (Removed in v1.3.2): use background_command and background_subagents instead. Since v1.3.8 the task ends normally even while they run: reports reach it while it is running or pending, and once it has ended a finished group runs its objective and next as a new task; the task staying pending for its background work was Removed in v1.3.8 — see Pending Tasks and Cancellation.
Each Send writes one row to the SQLite usage table (model, input / output / cache-write / cache-hit tokens, elapsed time); since v1.0.26 the row also records the IDs of the tool calls that response requested. Since v1.1.0 the completion event no longer carries the remaining provider quota; GET /v1/providers/quota serves it on request.
There is no inter-round delay — rate-limit protection comes from provider round-trip latency, per-model cooldown, and per-tool timeouts.

Cross-turn workdir reset


The workdir is supplied per request, not carried over from history: the TUI passes its own working directory, /v1/send resolves the work_dir field, and subagents inherit or resolve theirs. Since v1.2.0 it is written into the turn context on every run, not into the system prompt, so the cached system prefix survives a directory change; a directory mentioned in an earlier turn does not carry over through history.
  • Turn context — a Work directory: ... line stating that this directory is authoritative for this turn, that earlier ones in history are ignored, and that run_command already starts there. Stateless /v1/chat/completions runs keep the line in their own system prompt instead
  • TUI — the user sets the directory with Shift+P (an absolute path, ~/..., or a path relative to the current one; it must exist), and every later request carries it. Removed in v1.3.0: the agent's cd through run_command and the workdir frame that pushed the new directory to the TUI; run_command now rejects cd and points to absolute paths or ['sh','-c','cd <dir> && <command>'] for a single command

The per-message metadata header (timestamp + working directory wrapped around each user message) and its TUI stripper stripUserMetaHeader were removed; the turn-context work directory line is the only workdir anchor.
中文