AgentSession:編碼 Agent 的編排層
AgentSession 是 pi-coding-agent 裡最重的一層——它不直接跑 LLM,也不直接渲染 UI,而是夾在兩者中間:對上,接收使用者輸入和 UI 事件;對下,驅動 pi-agent-core 的 Agent 跑迴圈。模型註冊、工具定義、系統提示建構、上下文壓縮、失敗重試、訊息排隊,都歸它管。可以把它理解成「把通用 Agent 包裝成一個有狀態、可恢復、帶技能和工具的編碼助手」的組裝車間。
職責
AgentSession 做四件事:
- 組裝:
AgentSessionConfig裡塞進Agent實例、模型註冊表、工具定義、擴充執行時、系統提示建構子,建構時掛上beforeToolCall/afterToolCall鉤子和事件訂閱。見packages/coding-agent/src/core/agent-session.ts:313-330。 - 接收輸入:
prompt(text)是主入口,處理/斜線命令、展開檔案型提示範本、把文字轉成AgentMessage[],再交給底層Agent。見packages/coding-agent/src/core/agent-session.ts:967-1000。 - 事件轉發:訂閱
Agent的事件串流,重新包裝成AgentSessionEvent發給上層 UI。見packages/coding-agent/src/core/agent-session.ts:330-335。 - 排隊與重試:串流輸出期間使用者繼續打字時,按
streamingBehavior決定走steer(插話)還是followUp(排隊),而不是簡單丟棄或阻塞。見packages/coding-agent/src/core/agent-session.ts:1181-1296。
設計動機
為什麼不直接讓 UI 呼叫 Agent.prompt?因為編碼助手需要一堆「通用 Agent 不管」的橫切邏輯:斜線命令(/model、/settings)、提示範本展開、模型/API key 校驗、上下文超長時的自動壓縮、工具呼叫前後的鑑權與遙測。把這些塞進 Agent 會讓通用迴圈變重;放到 UI 層又會在 print 模式、rpc 模式、擴充裡重複實作。AgentSession 抽出來當唯一入口,三種執行模式共用同一套編排邏輯,UI 只管渲染事件。
關鍵檔案
packages/coding-agent/src/core/agent-session.ts:121-149—AgentSessionEvent與AgentSessionConfig類型,定義事件形狀和組裝介面。packages/coding-agent/src/core/agent-session.ts:244-253—class AgentSession宣告與內部狀態欄位。packages/coding-agent/src/core/agent-session.ts:313-335— 建構子:掛beforeToolCall/afterToolCall鉤子,訂閱Agent事件。packages/coding-agent/src/core/agent-session.ts:379-435— 工具呼叫前後的鉤子實作,做鑑權和事件重發。packages/coding-agent/src/core/agent-session.ts:967-1109—prompt主流程:命令分派、範本展開、this.agent.prompt(messages)。packages/coding-agent/src/core/agent-session.ts:1181-1296—steer/followUp排隊語意。packages/coding-agent/src/core/agent-session.ts:1317-1389—sendUserMessage(程式化入口)與abort。packages/coding-agent/src/core/agent-session.ts:713-743—subscribe,UI 透過它拿事件。
建構子裡掛鉤子和訂閱,是整個編排的起點:
// packages/coding-agent/src/core/agent-session.ts:313-335
constructor(config: AgentSessionConfig) {
// ... 存 config,初始化狀態 ...
this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);
// ... 略 ...
}prompt 把使用者文字變成 AgentMessage[] 後交給底層 Agent:
// packages/coding-agent/src/core/agent-session.ts:1107-1112
try {
await this.agent.prompt(messages);
} catch (error) {
// ... 失敗處理 ...
}資料流
使用者在 TUI 編輯器按 Enter → InteractiveMode.defaultEditor.onSubmit → session.prompt(text):
串流期間使用者繼續打字時,prompt 不會硬塞,而是分流:
邊界與失敗
- 斜線命令衝突:擴充註冊的命令在串流中也能即時執行(自己管 LLM 互動),不走排隊。若命令無法排隊會直接拋錯,見
packages/coding-agent/src/core/agent-session.ts:1255-1259。 - 模型/key 缺失:非串流路徑會校驗模型和 API key,缺失時拋錯而非發空請求。
- 壓縮中止:
abort會同時取消主迴圈、壓縮控制器、分支摘要控制器,見packages/coding-agent/src/core/agent-session.ts:1744-1752。 - 重試:
Agent.emit()同步呼叫_handleAgentEvent,而prompt()會waitForRetry(),失敗後由重試邏輯決定是否重新發輪。
小結
AgentSession 是編碼助手的「組裝車間 + 事件匯流排」:組裝 Agent、轉發事件、排隊插話、管工具鉤子。往上看是 InteractiveMode/runPrintMode/runRpcMode 三種 UI 模式,往下看是 pi-agent-core 的通用迴圈。組裝細節看 createAgentSession 組裝,底層迴圈看 雙層 while 主迴圈。