文件 v0.30.0

Execution Engine

每個請求在 exec.Execute() 中執行主迴圈,最多 128 次迭代。每次迭代:

  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、更新去重表、發出 EventToolResult

標記為 concurrent 的 tool:read_fileslist_filesglob_filessearch_filesfetch_pagesearch_websearch_google_newssend_http_requestdownload_filetranscribe_mediacalculateinvoke_subagentlist_subagent_sessionssearch_chat_historysearch_error_historyread_errorremember_errorlist_ragsearch_raglist_chatbotlist_toolssearch_toolslist_schedulelist_revisionsreasoning_guidewrite_skillwrite_tool。write 類檔案 tool、run_command、互動類 tool、api_* / script_* / ext_* 以及 MCP tool 一律序列執行。

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

Pending registry

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

Gate pending.HasListener(sessionID) 檢查是否有匹配 prefix 的 listener 為該 session 註冊。這取代了舊的全域 pending.Active atomic.Bool,讓 Telegram、Discord、CLI 的 confirm 流程能並行運作而不互相阻塞。

Send 失敗處理

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

失敗類型 行為
Timeout 對同一模型重試至 MaxSendTimeoutRetries(3 次),間隔 SendTimeoutRetryInterval
Rate limit / cooldown 規則辨識的上游狀態 對該模型註冊 30 分鐘 cooldown,接著切換到下一個 fallback
Context 長度超出 裁掉最舊的一組對話(compact.TrimFallback)後重送;只有在無可裁剪時才中止
其他錯誤 切換到下一個 fallback 模型;無可用 fallback 時中止

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

跨 turn workdir 重置

每則新的 user message 會重建 Executor,並透過 os.Getwd()data.WorkDir 重置為 process cwd — 被 cd 改動的 workdir 不會跨 turn 保留。兩道護欄防止 LLM 從歷史推斷出過期的 workdir:

TUI 透過 stripUserMetaHeader 在視覺上剝除該 wrapper;LLM 仍原樣收到。


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

EN