跳至主要内容

自行停靠 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 / deriveSubagentsConversation 折出這兩份資料。想訂閱而不是每次重算的話, 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 提早完成)。

也看看