文件 v1.0.9

Execution Engine

所有進入點(TUI、/v1/send/v1/chat/completions、Telegram、Discord、scheduler)走同一套啟動流程:exec.Prepare 從輸入比對 skill,接著 exec.Start 解析呼叫端指名的 skill、發出 skill 與模型選擇事件、透過 ResolveAgent 挑選模型與 fallback,再交給 exec.Execute()exec.Run 已移除,改用 exec.Prepare + exec.Start

exec.Execute() 執行主迴圈,最多 128 次迭代limits.max_tool_iterations)。每次迭代:

  1. 組裝 messages:SystemPrompts + OldHistories + UserInput + ToolHistories
  2. 對所選 provider 呼叫 Agent.Send()
  3. 從 response 解析 tool_calls
  4. 透過 toolCall.go 分派 tool call(three-pass concurrency,見下)
  5. 將結果 append 至 ToolHistories
  6. 當無 tool_calls 剩餘或撞到迭代上限時停止

無 inter-round delay — rate-limit 保護來自 provider round-trip 延遲、per-model cooldown 以及各 tool 的 timeout。

Three-pass tool concurrency

toolCall.go 將每一輪的 tool call 拆成三個序列 pass;只有 Pass 2 會 fan out:

Pass 模式 工作
1 — pre-flight 序列 重複呼叫去重(tool|args hash)、stub-tool 短路、confirm gate、JSON-schema 驗證
2 — execute 對標記 IsConcurrent 的 tool 並行;其餘序列 tools.Execute
3 — commit 序列 落地 sessionData.ToolsToolHistories、更新去重表、寫入結果 cache、發出 EventToolResult

標記為 concurrent 的內建 tool(17 個):read_filesfind_filesfind_toolsfind_notefile_historychat_historyerror_historyfetch_pagesearch_webhttp_requestdownload_filetest_toolcalculatesubagentslist_chatbotsend_to_chatbotreasoning_guidegenerate_audiogenerate_image 不帶此旗標。api_* / script_* / ext_* tool 僅在自身定義宣告時才並行。edit_filerun_command、互動類 tool 以及 MCP tool 一律序列執行。

去重是「每次執行」而非「每個 session」:重複的 tool|args 組合直接回傳先前結果而不再執行,且 edit_file 會使涵蓋其寫入路徑的 read_files 項目失效。另有一層 30 分鐘的結果 cache 存於 ToriiDB(db_0),僅涵蓋 fetch_pagesearch_webhttp_requestGET 呼叫。

Pending registry

internal/runtime/pending.go 是由 prefix 路由的 confirm/ask registry,由主 agent 與任何 in-process subagent 共用。Producer(toolCall confirm、ask_user handler、store_secret handler)呼叫 Ask(ctx, req) 並阻塞於 per-entry buffered=1 的 reply channel。每個前端透過 RegisterListener(prefix) 註冊 listener —— TUI 用 "cli-"、web 儀表板用 "chat-"、Telegram / Discord listener 用 "tg-" / "dc-"(空 prefix 匹配全部)—— 並只透過 PickNext(prefix)PickNextMatch(prefix, accept) 認領匹配的 entry。PickNextFor 已移除,改用 PickNext / PickNextMatch。ctx 取消會移除該 entry,使過期的 producer 絕不浪費一次人為互動。

Gate HasListener(origin) 檢查是否有 prefix 符合該 session 來源(OriginOf 辨識 cli-chat-tg-dc-)的 listener 已註冊。這取代了舊的全域 pending.Active atomic.Bool,讓 TUI、web、Telegram、Discord 的 confirm 流程能並行運作而不互相阻塞。

Send 失敗處理

Agent.Send() 失敗採逐級升高處理,而非盲目重試:

失敗類型 行為
Timeout 於同一模型最多嘗試 MaxSendTimeoutRetries(3)次,間隔 SendTimeoutRetryInterval(15 秒)
Rate limit(HTTP 429 或 rate-limit 訊息) 註冊 30 分鐘 cooldown,於同一模型在 5 秒、10 秒、15 秒後重試;之後切換到下一個 fallback
額度耗盡(HTTP 402 / 403 或額度 / 帳務訊息) 註冊 30 分鐘 cooldown,立即切換到下一個 fallback
Context 長度超出 裁掉最舊的一組對話(compact.TrimFallback)後重送;只有在無可裁剪時才中止
串流中無回應 每 30 秒 health probe(UnresponsiveProbeInterval),探測失敗後每 10 秒重試,失敗 3 次即切換模型
其他錯誤 切換到下一個 fallback 模型;無可用 fallback 時中止

Fallback 候選來自 ResolveAgent 排好的清單。nextAgent 會略過與失敗模型同供應商的模型、以及 context window 小於目前輸入的模型,對每個候選做 health check(HealthCheckTimeout,10 秒),並最多重建清單 3 輪(maxFallbackRounds)。綁定特定模型(auto 以外)的 session 不會 fallback。

切換模型會清空 ToolHistories(或套用 compact.RawToolFallback)、重置去重表並歸零計數器——新模型不會繼承失敗模型的殘留狀態。

跨 turn workdir 重置

Workdir 由每次請求提供,而非從歷史沿用:TUI 傳入自身的工作目錄、/v1/send 解析 work_dir 欄位、subagent 沿用或自行解析。GetSession 每次執行都以該目錄重建 system prompt,因此先前 turn 的 cd 不會保留。

逐則訊息的 metadata header(包在每則 user message 外的時間戳與工作目錄)及其 TUI 剝除函式 stripUserMetaHeader 已移除;system prompt 的 {{.WorkPath}} 行是唯一的 workdir 錨點。


[!NOTE] 本文件由 Claude 讀取完整原始碼後自動生成。

EN