ChatPanel:最上位レイアウトとツール組み立て
ChatPanel は pi-web-ui の最上位 customElement(<pi-chat-panel>)。自身は会話を走らせず、AgentInterface、ArtifactsPanel、toolsFactory を一つにまとめる役を担う。外部から渡された Agent を受け取り、agent-interface 子要素を生成して session を差し、画面幅に応じて artifacts の「並列」と「オーバーレイ」を切り替え、toolsFactory で host が追加の AgentTool を注入できるようにする。
責務
- agent と agentInterface の保持:
@state agent、@state agentInterfaceの 2 フィールド。agentは host から受け取り、agentInterfaceはsetAgent時にdocument.createElementで生成する。packages/web-ui/src/ChatPanel.ts:17-25参照。 - セッションホストの組み立て:
setAgentがAgentInterfaceを作り、enableAttachments/onApiKeyRequired/onBeforeSendなどのコールバックを設定し、agentをsessionとして取り付ける。packages/web-ui/src/ChatPanel.ts:56-85参照。 - artifacts パネルの組み立て:
new ArtifactsPanel()、sandboxUrlProviderの注入、ArtifactsToolRendererを renderer registry に登録。packages/web-ui/src/ChatPanel.ts:86-94参照。 - runtime providers の構築:
runtimeProvidersFactoryが会話履歴中の添付をAttachmentsRuntimeProviderに集約し、読み書き可能なArtifactsRuntimeProviderと合わせて REPL ツールが消費できるようにする。packages/web-ui/src/ChatPanel.ts:96-116参照。 - レスポンシブレイアウト:
windowWidth < 800で overlay、それ以外は 50/50 の並列。artifacts 折りたたみ時は浮动 pill を表示。packages/web-ui/src/ChatPanel.ts:159-208参照。
設計動機
なぜ ArtifactsPanel の組み立てを AgentInterface ではなく ChatPanel に置くのか。artifacts は「会話産物」という別軸の概念で、メッセージリストの描画と切り離したいからだ。AgentInterface はメッセージストリームだけを見て、ArtifactsPanel は artifact メッセージだけを見て自身の artifacts Map を保つ。両者は agent.state 経由でデータを共有するけれど、ライフサイクルも UI 上の位置も異なる。ChatPanel がレイアウト層としてこれらを組み立てると同時に、toolsFactory を host に晒す。これにより host は pi-web-ui のソースを変えずに業務専用ツール(例えばあるアプリの query_database)を注入できる。
BREAKPOINT = 800 は経験値だ。狭画面では artifacts がチャット領域を全画面覆い、2 列とも圧縮されて読めなくなるのを避ける。広画面では並列にして会話しながら産物を眺める。overlay と collapsed は ArtifactsPanel 自身に窓監視させるのではなく、ChatPanel が render で状態に基づいて押し込む。レイアウト判断を最上位に集約するためだ。
主要ファイル
packages/web-ui/src/ChatPanel.ts:17-25—class ChatPanel宣言と状態フィールド。packages/web-ui/src/ChatPanel.ts:36-49—connectedCallback:初期windowWidth、resizeリスナのバインド、flex レイアウトの設定。packages/web-ui/src/ChatPanel.ts:56-85—setAgent前半:AgentInterface生成、session取り付け、コールバックの透過。packages/web-ui/src/ChatPanel.ts:86-116— artifacts panel の組み立て、runtimeProvidersFactoryクロージャ。packages/web-ui/src/ChatPanel.ts:118-157— artifacts 変更コールバックとreconstructFromMessages(履歴メッセージからの artifacts 復元)。packages/web-ui/src/ChatPanel.ts:141-144—toolsFactory呼び出し、[artifactsPanel.tool, ...additionalTools]をagent.state.toolsにセット。packages/web-ui/src/ChatPanel.ts:159-208—render:windowWidth/hasArtifacts/showArtifactsPanelでレイアウトを切り替え、浮动 pill を描画。
setAgent 内での AgentInterface 生成とコールバック注入が、host とセッションホストの継ぎ目になる:
// 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 ツールは常に先頭に置かれる:
// 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 内の状態判定で駆動する:
境界と失敗
- agent 未設定:
renderは「No agent set」をそのまま出し、agentInterfaceが undefined で吹き飛ぶのを防ぐ。packages/web-ui/src/ChatPanel.ts:160-164参照。 - 復元時の自動展開抑制:
reconstructFromMessagesの直前にonArtifactsChangeを一時的に空にし、履歴の artifacts がパネルを勝手に開くのを止める。packages/web-ui/src/ChatPanel.ts:148-151参照。 - artifacts が 0 件:
hasArtifacts=false、showArtifactsPanel=falseになり、pill は描画されず、右側パネルは隠れる。 - 新規 artifact だけ自動展開:
count > artifactCountのときだけshowArtifactsPanelを true にする。既存 artifact が再出現して無理やり開くのを避けるためだ。packages/web-ui/src/ChatPanel.ts:118-127参照。 - resize リスナの後始末:
disconnectedCallbackでwindow.resizeリスナを外し、leak を防ぐ。packages/web-ui/src/ChatPanel.ts:51-54参照。
まとめ
ChatPanel はレイアウト層であり、組み立て工場でもある。AgentInterface、ArtifactsPanel、toolsFactory を組み立て、窓幅でレイアウトを切り替える。内側に入ると AgentInterface セッションホスト、ツール描画の登録仕組みは ツールレンダラーレジストリ を参照。