AI 應用元件
工具權限確認卡
代理請求執行工具時的權限確認卡:顯示工具名與參數摘要,允許、拒絕或永遠允許,決定後收合成一行紀錄。
放在對話訊息流裡、代理要執行有副作用的工具之前出現的授權卡。卡片列出工具名、風險等級、一句話說明與參數摘要,底部提供「拒絕」「永遠允許此工具」「允許」三個選擇;做出決定後,參數區與按鈕列淡出收起,整張卡以 layout 動畫收合成一行紀錄(「已允許:寫入檔案 · src/notes/今日.md」),點一下可重新展開檢視參數。高風險工具會加上紅色色帶、隱藏「永遠允許」並把預設焦點放在「拒絕」;也可以設定倒數秒數,逾時自動視為拒絕。和顯示「執行狀態」的工具呼叫卡互補,這張卡負責「執行前的授權」。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add tool-permission-cardPlayground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
220
0
編輯中的呼叫預設屬性
<ToolPermissionCard/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
安裝
npx webberui@latest add https://webberui.com/r/tool-permission-card.json或在 components.json 設定 registries 後,改用 @webberui/tool-permission-card 安裝。
使用
import { ToolPermissionCard } from "@/components/ui/tool-permission-card";
<ToolPermissionCard
toolName="寫入檔案"
description="代理想在專案中建立一個新檔案"
risk="low"
params={[
{ label: "路徑", value: "src/notes/今日.md", mono: true },
{ label: "大小", value: "1.2 KB" },
]}
onDecision={async (decision) => {
// 把授權結果送回你的代理執行環境;reject 會讓卡片維持待決定
await sendToAgent({ tool: "write_file", decision });
}}
/>Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
toolName | string | — | 工具名稱(例「寫入檔案」) |
toolIcon | ReactNode | 扳手圖示 | 工具圖示 |
description | string | — | 一句話說明代理想做什麼 |
params | ToolPermissionParam[] | [] | 參數摘要;超過 4 列時預設摺疊 |
risk | "low" | "medium" | "high" | "medium" | 風險等級;high 時顯示紅色色帶並隱藏「永遠允許」 |
status | ToolPermissionStatus | — | 受控狀態;未提供時由元件內部管理(非受控) |
defaultStatus | ToolPermissionStatus | "pending" | 非受控模式的初始狀態 |
onStatusChange | (status: ToolPermissionStatus) => void | — | 狀態變動時回呼 |
onDecision | (decision: "allow" | "deny" | "always") => void | Promise<void> | — | 做出決定時回呼;回傳 Promise 時按鈕顯示載入中,resolve 後才收合,reject 則維持待決定 |
allowLabel | string | "允許" | 允許按鈕文字 |
denyLabel | string | "拒絕" | 拒絕按鈕文字 |
alwaysLabel | string | "永遠允許此工具" | 永遠允許按鈕文字 |
hideAlways | boolean | false | 隱藏「永遠允許」按鈕 |
expiresIn | number | 0 | 倒數秒數;歸零時自動視為拒絕,0 表示不倒數 |
collapseDuration | number | 220 | 收合動畫時長(毫秒),同時寫入 --wb-tool-permission-card-duration |
autoFocus | boolean | true | 出現時自動聚焦「允許」(high 風險時聚焦「拒絕」) |
className | string | — | 透傳到最外層容器 |
ToolPermissionStatus 為 "pending" \| "allowed" \| "denied" \| "always"。
ToolPermissionParam
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
label | string | — | 參數名稱(例「路徑」) |
value | string | — | 參數值;過長時截斷,hover 顯示完整內容 |
mono | boolean | false | 以等寬字體顯示(路徑、指令等) |
細節
- 收合動畫:決定瞬間參數區與按鈕列以
AnimatePresence退場(透明度與高度歸零),外層motion.div帶layout,在collapseDuration內以 easeInOut 收成一行;結果圖示(✓/✕/∞)以 spring 從 0.6 倍彈到原尺寸,顏色依結果為 emerald/red/sky。 - 收合後的紀錄列是一顆按鈕,點擊可展開檢視說明與參數;展開內容唯讀,決定不可更改。
onDecision回傳 Promise 時,被按下的按鈕顯示 spinner 並設定aria-busy,其他按鈕暫停使用;Promise reject 時卡片維持待決定,可再按一次。expiresIn倒數以卡片底部的細進度條呈現,最後四分之一轉紅;歸零時呼叫onDecision("deny")並收合為「已拒絕」。- 按鈕 hover 過渡與展開箭頭的旋轉都使用
--wb-tool-permission-card-duration,可在全域覆寫。
可及性
- 卡片為
role="group",以aria-labelledby指向工具名 - 待決定時,焦點在卡片內按 Escape 拒絕;焦點不在按鈕上時按 Enter 允許(焦點在按鈕上時 Enter 交給該按鈕),並含 IME 組字保護
- 預設聚焦「允許」,高風險時改為聚焦「拒絕」,降低誤按的代價;聚焦時不捲動頁面,訊息流裡有多張卡時可用
autoFocus={false}關閉 - 決定後焦點移到收合後的紀錄列(若決定時焦點在卡片內),紀錄列以
aria-expanded標示展開狀態,並以aria-live="polite"宣告「已允許寫入檔案」等結果 - 倒數進度條對輔助科技隱藏,剩餘秒數以 sr-only 文字提供
- 使用者系統開啟「減少動態效果」時,收合不做高度與 layout 動畫、紀錄列以 120ms 淡入直接切換,結果圖示不彈跳,倒數進度條改為數字顯示