Skip to content

ChatPanel:頂層布局與工具裝配

源码版本v0.73.1

ChatPanelpi-web-ui 的頂層 customElement(<pi-chat-panel>)。它本身不跑會話,而是把 AgentInterfaceArtifactsPaneltoolsFactory 幾樣東西拼到一起:接收外部傳進來的 Agent,建立 agent-interface 子元素並賦上 session,根據螢幕寬度在「並排」和「覆蓋」兩種 artifacts 布局間切換,呼叫 toolsFactory 讓宿主注入額外的 AgentTool

職責

  1. 持有 agent 與 agentInterface:@state agent@state agentInterface 兩個欄位,agent 由 host 傳入,agentInterfacesetAgentdocument.createElement 建立,見 packages/web-ui/src/ChatPanel.ts:17-25
  2. 裝配會話宿主:setAgent 建立 AgentInterface、設定 enableAttachments/onApiKeyRequired/onBeforeSend 等回呼,把 agent 作為 session 掛上去,見 packages/web-ui/src/ChatPanel.ts:56-85
  3. 裝配 artifacts 面板:new ArtifactsPanel()、注入 sandboxUrlProvider、註冊 ArtifactsToolRenderer 到 renderer registry,見 packages/web-ui/src/ChatPanel.ts:86-94
  4. 建構 runtime providers:runtimeProvidersFactory 把會話歷史裡的附件聚合成 AttachmentsRuntimeProvider,加上可讀寫的 ArtifactsRuntimeProvider,供 REPL 工具消費,見 packages/web-ui/src/ChatPanel.ts:96-116
  5. 響應式布局:windowWidth < 800 切到 overlay,否則並排 50/50,artifacts 折疊時顯示浮動 pill,見 packages/web-ui/src/ChatPanel.ts:159-208

設計動機

為什麼把 ArtifactsPanel 的裝配放在 ChatPanel 而不是 AgentInterface?因為 artifacts 是「會話產物」維度的概念,與渲染訊息列表解耦:AgentInterface 只看訊息流,ArtifactsPanel 只看 artifact 訊息並維護自己的 artifacts Map。兩者都透過 agent.state 共享資料,但生命週期、UI 位置都不同。ChatPanel 作為布局層把它們組裝起來,同時把 toolsFactory 暴露給 host,讓 host 能注入業務專屬工具(比如某個 app 的 query_database),而不需要改 pi-web-ui 原始碼。

BREAKPOINT = 800 是經驗值:窄螢幕下 artifacts 全屏覆蓋聊天區,避免兩列都被擠壓到不可讀;寬螢幕下並排顯示便於邊聊邊看產物。overlaycollapsedChatPanelrender 裡根據狀態推到 ArtifactsPanel,而不是讓 panel 自己監聽視窗,這樣布局決策集中在頂層。

關鍵檔案

setAgentAgentInterface 的建立與回呼注入,是 host 與會話宿主的接縫:

typescript
// packages/web-ui/src/ChatPanel.ts:74-84
this.agentInterface = document.createElement("agent-interface") as AgentInterface;
this.agentInterface.session = agent;
this.agentInterface.enableAttachments = true;
this.agentInterface.enableModelSelector = true;
this.agentInterface.enableThinkingSelector = true;
this.agentInterface.showThemeToggle = false;
this.agentInterface.onApiKeyRequired = config?.onApiKeyRequired;
this.agentInterface.onModelSelect = config?.onModelSelect;
this.agentInterface.onBeforeSend = config?.onBeforeSend;
this.agentInterface.onCostClick = config?.onCostClick;

toolsFactory 讓 host 注入額外工具,而 artifacts 工具始終第一個被加入:

typescript
// packages/web-ui/src/ChatPanel.ts:141-144
const additionalTools =
    config?.toolsFactory?.(agent, this.agentInterface, this.artifactsPanel, runtimeProvidersFactory) || [];
const tools = [this.artifactsPanel.tool, ...additionalTools];
this.agent.state.tools = tools;

資料流

setAgent 一條主線把 host 傳入的 Agent 裝配成可用的 UI:

布局切換由 render 裡的狀態判斷驅動:

邊界與失敗

小結

ChatPanel 是布局層 + 裝配車間:裝配 AgentInterfaceArtifactsPaneltoolsFactory,按視窗寬度切布局。往裡看是 AgentInterface 會話宿主,工具渲染的註冊機制看 工具渲染器註冊表