跳至主要内容

Sandbox File Explorer

當 agent 在 sandbox 裡動檔案時,使用者需要看得到那棵樹。SDK 內建一個 File Explorer 側欄: sandbox 下拉選單、以 workingDirectory 為根的延遲展開檔案樹、以 CodeMirror 6 呈現的單檔 檢視(含監看自動重載),以及右鍵選單與剪貼簿式的搬移/複製。

Sandbox File Explorer

當 agent 在 sandbox 裡動檔案時,使用者需要看得到那棵樹。SDK 內建一個 File Explorer 側欄:sandbox 下拉選單、以 workingDirectory 為根的延遲展開檔案樹、以 CodeMirror 6 呈現的單檔檢視(含監看自動重載),以及右鍵選單與剪貼簿式的搬移/複製。

試試看

展開 src/ 或 docs/ → 雙擊檔案開啟 → 直接編輯後存檔 → 右鍵可新增資料夾、刪除、複製貼上。

內建 vs 自行擺放

預設 fileExplorer="builtin":header 上出現資料夾圖示,點了開右側側欄,一切自動接好。設成 "off" 則兩者都不出現,改由你把外露的 <FileExplorerPanel> 擺在任何位置——就像這個示範。

import {
  FileExplorerPanel, useFileExplorerController, AsgardThemeScope,
} from '@asgard-js/react';
import { createSandboxFsProviders } from '@asgard-js/react';

const controller = useFileExplorerController({ open: true });
const fs = createSandboxFsProviders(client);

<Chatbot fileExplorer="off" {...rest} />

<AsgardThemeScope theme={theme}>
  <FileExplorerPanel
    sandboxes={launchedSandboxes}   // 來自 channel.launchedSandboxes$
    controller={controller}
    {...fs}                          // listDir / readFile / saveFile / watchFile…
    onNudge={() => channel.nudge()}   // 喚醒閒置的 sandbox
    nudgeDisabled={isConnecting}
  />
</AsgardThemeScope>

這個示範把 listDir / readFile / saveFile / watchFile 換成瀏覽器記憶體裡的假檔案樹——面板本身不在意資料從哪來,正式環境只要接上 AsgardServiceClient 的 sandbox fs 方法即可(見下方 createSandboxFsProviders)。

File Explorer 載入中…
這個示範用的是假檔案樹

面板把檔案存取當成一組非同步 callback 收下,所以上面的示範把 listDir / readFile / saveFile / watchFile 換成瀏覽器記憶體裡的假樹——延遲展開、編輯、存檔、右鍵操作全都是真的 在跑,只是背後沒有 sandbox。正式環境改接 createSandboxFsProviders 即可。

內建 vs 自行擺放

// 預設:header 出現資料夾圖示,點了開右側側欄,一切自動接好
<Chatbot fileExplorer="builtin" {...rest} />

// 關掉:兩者都不出現,改由你把 <FileExplorerPanel> 擺在任何位置
<Chatbot fileExplorer="off" {...rest} />

相關的 Chatbot props:

Prop用途
fileExplorer'builtin'(預設)或 'off'
autoRevealOnOpenFileCardopen-file 卡片抵達時是否自動展開側欄(預設 true);檔案正在編輯且未存檔時會抑制這個動作
fileExplorerBasePath覆寫樹根的絕對路徑,取代 sandbox 的 workingDirectory

自行擺放

import {
FileExplorerPanel,
useFileExplorerController,
createSandboxFsProviders,
AsgardThemeScope,
} from "@asgard-js/react";

const controller = useFileExplorerController({ open: true });
const fs = createSandboxFsProviders(client);

<Chatbot fileExplorer="off" {...rest} />

<AsgardThemeScope theme={theme}>
<FileExplorerPanel
sandboxes={launchedSandboxes} // 來自 channel.launchedSandboxes$
controller={controller}
{...fs} // listDir / readFile / saveFile / watchFile / mkdir…
onNudge={() => channel.nudge()} // 喚醒閒置的 sandbox
nudgeDisabled={isConnecting}
chrome="card" // 'card' 獨立卡片 / 'flush' 內嵌側欄
/>
</AsgardThemeScope>
一定要包 AsgardThemeScope

面板擺在 <Chatbot> 之外就拿不到聊天外殼掛上的設計 token,會退回淺色預設值。 詳見在聊天外殼之外重建主題

共用的 controller

header 的切換鈕、open-file 交接卡、以及面板本身綁的是同一個 controller:

interface FileExplorerController {
open: boolean;
activeSandboxName: string | null;
requestedFile: RequestedFile | null;
isEditingDirty: boolean; // 檔案有未存檔的修改
openExplorer(): void;
closeExplorer(): void;
toggle(): void;
selectSandbox(sandboxName: string): void;
requestFile(
sandboxName: string,
absolutePath: string,
options?: { reveal?: boolean }, // reveal: false = 只送出 intent,不強拉面板
): void;
setEditingDirty(dirty: boolean): void;
}

requestFile 就是 sandbox://…/open-file 卡片背後呼叫的東西。

檔案存取 provider

面板不在意資料從哪來,只要給它這些函式:

type FsListDir = (sandboxName: string, path: string) => Promise<SandboxFsListResult>;
type FsReadFile = (sandboxName: string, path: string) => Promise<string>;
type FsSaveFile = (sandboxName: string, path: string, content: string) => Promise<void> | void;
// 訂閱單一路徑的變動,回傳退訂函式。事件內容刻意不外露——反正 view 都要重讀。
type FsWatchFile = (sandboxName: string, path: string, onChange: () => void) => () => void;

另有一組選用的異動 callback,沒給的話對應的操作就不會出現在選單裡: mkdirremovecopymoveuploaddownload

createSandboxFsProviders(client, options) 會把 core 的 sandbox fs 方法接成上面這整組—— 圖片檔解析成 data URL 供 <img src> 用,文字檔解成字串。它還會追蹤失敗次數:某個 sandbox 連續失敗到門檻時呼叫 onSandboxUnreachable,讓你把它從下拉選單移除。

Nudge:喚醒閒置的 sandbox

sandbox 閒置關掉之後,面板的空狀態會出現一顆 Nudge 鈕。它送出的是一個隱形的 NUDGE 回合——不會在對話串留下訊息:

await channel.nudge();

nudge 也是一個回合,所以 run 進行中會被直接拒絕。把宿主的「目前有 run 佔住 channel」狀態 傳給 nudgeDisabled,避免使用者按了沒反應。

也看看