自行停靠 run-chrome
Task Check List 與子代理清單 屬於 run 層級的介面——它們描述的是整個回合的狀態,不是某一則訊息。所以 SDK 把它們停靠在 一條固定區裡:位於對話串的捲動框之外、輸入框之上。
自行停靠 run-chrome
預設情況下,Task Check List 與子代理面板由 SDK 停靠在對話串與輸入框之間的固定區。把 hideRunChrome 設成 true 就不再渲染內建面板,改由你用外露的 <TaskList> / <SubagentList> 擺在版面任何位置——例如右側欄或另一個分頁。
import {
Chatbot, TaskList, SubagentList, AsgardThemeScope,
} from '@asgard-js/react';
import { deriveTasks, deriveSubagents } from '@asgard-js/core';
// conversation 來自 useAsgardContext()
const tasks = deriveTasks(conversation);
const subagents = deriveSubagents(conversation);
<Chatbot hideRunChrome {...rest} />
<AsgardThemeScope theme={myTheme}>
<SubagentList subagents={subagents} locale="zh-TW" />
<TaskList tasks={tasks} locale="zh-TW" />
</AsgardThemeScope>面板在 <Chatbot> 之外,拿不到聊天外殼掛上的設計 token,所以要用 <AsgardThemeScope> 包起來,否則會退回淺色預設值。
為什麼在捲動框之外
早期這兩個面板渲染在對話串的尾端,跟著訊息一起捲。結果是:串流進行中對話不斷長高、又自動 捲到底,面板就被推來推去。移到固定區之後,串流時它們穩穩待在原地。
固定區還有兩個規則:
- 封頂在內容區高度的 50%,超過就自己內部捲動——對話區永遠保得住另一半
- 完全沒有面板時整條不存在、不占位,輸入框直接貼齊最後一則訊息
換成自己擺
<Chatbot hideRunChrome {...rest} />
設成 true 之後內建面板不再渲染,你可以把外露的 <TaskList> / <SubagentList> 放到
版面任何位置——右側欄、抽屜、另一個分頁都行。
import { TaskList, SubagentList, AsgardThemeScope } from "@asgard-js/react";
import { deriveTasks, deriveSubagents } from "@asgard-js/core";
// conversation 來自 useAsgardContext()
const tasks = deriveTasks(conversation);
const subagents = deriveSubagents(conversation);
<AsgardThemeScope theme={theme}>
<SubagentList subagents={subagents} locale="zh-TW" />
<TaskList tasks={tasks} locale="zh-TW" />
</AsgardThemeScope>
AsgardThemeScope面板放在 <Chatbot> 之外就拿不到聊天外殼掛上的設計 token,會退回淺色預設值。
詳見在聊天外殼之外重建主題。
資料從哪來
兩個面板都收純陣列,跟 SDK 的狀態沒有耦合:
function TaskList(props: { tasks: Task[]; locale?: Locale }): ReactNode;
function SubagentList(props: { subagents: Subagent[]; locale?: Locale }): ReactNode;
deriveTasks / deriveSubagents 從 Conversation 折出這兩份資料。想訂閱而不是每次重算的話,
core 另有 createDerivedStores,並附 tasksEqual / subagentsEqual 供比較。
import {
deriveTasks, deriveSubagents,
tasksEqual, subagentsEqual,
createDerivedStores,
} from "@asgard-js/core";
型別
interface Task {
id: string;
subject: string; // 名詞形標題,非進行中時顯示
activeForm?: string; // 進行式標籤,進行中時優先顯示
description?: string; // 展開後的完整說明
status: "pending" | "in_progress" | "completed";
}
interface Subagent {
parentToolUseId: string; // 對應鍵=派出它的 Agent 工具呼叫
agentId?: string;
subagentType?: string; // 例如 general-purpose
description?: string;
status: "running" | "completed" | "failed" | "cancelled";
summary?: string;
tools: SubagentToolCall[]; // 這個子代理自己跑的工具
}
子代理的終止狀態只來自 subagent.complete 事件——不會從 Agent 工具呼叫本身的完成推斷
(非同步子代理的工具呼叫會以 async_launched 提早完成)。
也看看
- Task Check List、子代理清單 — 內建版本
- 在聊天外殼之外重建主題
- 多語系 — 面板各自的
locale - Headless 模式 — 完全自己畫