跳至主要内容

REFERENCE

SDK 範例

@asgard-js/core 與 @asgard-js/react 的用法與可以直接操作的範例。

sandbox:// 交接卡

Agent 在 sandbox 裡開了一個瀏覽器工作階段、產出了一份檔案、或整理出一整個資料夾時,需要一個 方式把使用者交接過去。做法是讓附件卡片的 defaultAction 指向 sandbox:// 這個自訂 scheme。

SDK 會在走到「開新分頁」的預設行為之前攔截它,解析成一個具型別的 intent,再交給對應的 處理器。原始的 sandbox:// URI 永遠不會被丟進 window.open()。

  1. URI 格式​

    sandbox://<sandboxName>/<action>?<query>

    目前支援三個 action:

    URI解析結果
    sandbox://sbx-a/open-browser{ kind: 'open-browser', sandboxName: 'sbx-a' }
    sandbox://sbx-a/open-file?absolute_path=%2Fhome%2Fuser%2Freport.md{ kind: 'open-file', sandboxName: 'sbx-a', absolutePath: '/home/user/report.md' }
    sandbox://sbx-a/open-folder?absolute_path=%2Fwork%2Foutput{ kind: 'open-folder', sandboxName: 'sbx-a', absolutePath: '/work/output' }

    absolute_path 必須做 URL 編碼(絕對路徑裡有很多 /)。

  2. 為什麼資料夾要自己一個 action​

    檔案和資料夾的終點不一樣:檔案進檢視器(讀內容,再掛上變更追蹤),資料夾只把樹展開到 那一層、選取它,不讀內容也不追蹤變更。

    那為什麼不共用 open-file、讓面板自己判斷?因為卡片抵達的當下,面板還沒列過那一層,它分不出 這個路徑是檔案還是目錄。「先當檔案試、失敗再退回目錄」也不是可行的替代方案——後端對目錄的 fs/file 會回 500,fs/watch 的連線則直接被切斷。所以終點由卡片自己說明;這也是 RequestedFile.kind 為必填的原因。

    兩種卡共用同一個自動展開開關

    卡片到站時要不要順便把內建側欄拉出來,兩種卡看的都是 autoRevealOnOpenFileCard(預設 true)。名稱裡的 OpenFileCard 早於資料夾卡存在,為相容而保留——「卡片可不可以把面板拉 出來」是同一個問題,不需要兩個旗標。

  3. 接手處理​

    三個 action 都可以由整合方覆寫:

    <Chatbot
    config={{ botProviderEndpoint: "..." }}
    customChannelId="my-channel"
    // 有給就以你的為準;沒給則走 SDK 預設(取一次性 URL 後開新分頁)
    onSandboxOpenBrowser={(sandboxName) => { /* … */ }}
    // open-file 的目的地通常是 File Explorer 的檢視器
    onSandboxOpenFile={(sandboxName, absolutePath) => {
    controller.requestFile(sandboxName, absolutePath);
    }}
    // open-folder 的目的地是檔案樹,不是檢視器
    onSandboxOpenFolder={(sandboxName, absolutePath) => {
    controller.requestFolder(sandboxName, absolutePath);
    }}
    // 預設處理器開分頁的目標,預設 '_blank'
    sandboxBrowserOpenTarget="_blank"
    // 想真的接管 open-file 就一定要加這行,理由見下方
    fileExplorer="off"
    />
    三個 handler 的語意不一樣

    onSandboxOpenBrowser 是真的二選一:有給就以你的為準,沒給才走 SDK 預設。

    onSandboxOpenFile 和 onSandboxOpenFolder 都不是。 它們是「加上去」而不是「取代掉」——你的 handler 會被呼叫,但內建的 File Explorer 側欄同時也照樣會被拉開,因為 那段邏輯只看 fileExplorer prop,不看你有沒有給 callback。而 fileExplorer 預設就是 'builtin'。

    結果是你自己的 controller 和 Chatbot 內部的 controller 會同時收到同一個 requestFile 或 requestFolder。要真的接管,必須另外把 fileExplorer 設成 "off"。

  4. 自己解析​

    resolveSandboxUri 也可以單獨使用——例如你自己渲染卡片的時候:

    import { resolveSandboxUri } from "@asgard-js/core";

    const intent = resolveSandboxUri(uri);

    if (intent === null) {
    // 不是 sandbox://、action 不認得、或缺 absolute_path
    // → 當成一般卡片處理,絕對不要 window.open() 原始 URI
    }

    回傳型別:

    type SandboxUriIntent =
    | { kind: "open-browser"; sandboxName: string }
    | { kind: "open-file"; sandboxName: string; absolutePath: string }
    | { kind: "open-folder"; sandboxName: string; absolutePath: string };
    備註

    解析用的是手寫 regex 而不是 new URL()。絕對路徑帶有大量 /,而 WHATWG URL parser 對 非特殊 scheme 的 host 大小寫處理並不可靠;query 的部分仍交給 URLSearchParams 解碼。

  5. 一般連結不受影響​

    https:// 之類的 defaultAction 完全照舊走正常開連結行為——攔截只發生在 sandbox://。

  6. 也看看​

準備好開始了嗎?

想知道 Asgard 怎麼用在你的團隊?跟我們聊聊。

聯絡我們