Skip to Content
API 參考Agent toolkit

Agent toolkit

Agent 不會打 /private/module/sandbox REST 來提交。它呼叫 src/components/tools/custom/sandbox/factory.py 的五個 LangGraph 工具。前端從不直接呼叫這些工具。前端要做的是:在房間啟用 job、在對話裡呈現 requires_confirmation 提案,然後用租戶 run API 輪詢得到的 run_id。

啟用條件

tool_loader 才是準則(factory 開頭寫「與 job_list 無關」是過時的)。五個工具只有在以下全部成立時才會載入:

  1. 房間的 jobs 清單含 ChatroomJobType.SANDBOX("sandbox")。
  2. 有 SANDBOX_ENABLED、DB、可信 principal、簽過名的 turn context。

開了 job 也會加上 protocol prompt,並把五個工具釘成 critical,避免被剪掉。

用既有的聊天室 jobs API 開啟(不在 /private/module/sandbox 底下):

PATCH /private/chatrooms/setting/jobs/{chatroom_id} { "jobs": ["sandbox", ...] }

認證是聊天室管理員階梯,失敗是 403,不是 sandbox 404。jobs: null 回到舊的自動偵測。jobs 沒設的房間永遠不會出現在 GET /private/chatrooms/by_job/sandbox。

那條路由的 OpenAPI 說明在有效的 job 類型裡列有 sandbox,ChatroomJobsPayload 也吃 ChatroomJobType,包含 "sandbox"。

列出明確開了這個 job 的房間:

GET /private/chatrooms/by_job/sandbox GET /private/chatrooms/by_job/sandbox/numOfData

Query:department_id?、offset、limit 1–100 預設 100、order asc|desc。省略 department_id → 已加入的房間。有設 → 該部門的房間(部門不在公司裡 → 404)。收藏的房間排前面。

建構時只捕捉伺服器 tuple (company_id, chatroom_id, principal_type, principal_id, persisted_human_message_id, signed_turn_receipt)。模型參數從不提供 turn 身份。

某個具體目錄任務能不能跑,需要 live share 且 此房間的啟用開關(granted-jobs)。task.agent_enabled 是舊的父層旗標,不會把任務放進 Agent 目錄。房間開了 "sandbox" job 但沒啟用任何任務,選單是空的。開了 ChatroomJobType.sandbox 不會讓每個已授予任務可跑 — 房間仍必須 POST .../granted-jobs/{task_id}/enable。Agent 選單與呼叫者身分無關(與 GET .../menu 同一份)。見 任務受眾。

外部通道(LINE/LINE 群/LINE room/Messenger/Instagram)的 principal_type=social_media_client,用 pipeline 解析出的 client id。內部聊天用已驗證的 user_id。

五個工具

工具名參數(模型可見)回傳
sandbox_job_menupage_size(預設 20,1..100)、page_token?、query?(≤256)此房已採用的精確版本目錄。沒有腳本。
sandbox_submit_job依 mode 分流——見下直接 run、確認提案,或 replay。
sandbox_submitted_jobspage_size、page_token?此 principal 待確認提案(含 proposal_receipt)與近期 runs。沒有 output/log/secret/URL。
sandbox_job_statusrun_id、wait_seconds 0..60、artifact_page_token?狀態 + 有界、不可信預覽。
sandbox_cancel_jobrun_id?取消自己的 run;省略則取消此 principal 待確認提案。Manager 身分不會擴大擁有範圍(A-011)。

選單項目帶了 REST 選單 job-contract 欄位裡的兩個(見 Schemas):input_schema(呼叫 sandbox_submit_job 前先驗證 input——不合格在提交時會是 422 input_schema_violation)與 secret_slots[](逐 slot 的 borrower/owner 履行狀態)。Agent 選單完全不帶 runtime_contract——這個欄位只存在於 GET /tasks/{id}/versions/{vid}(owner 看得到真實 work_command)與 POST .../input-preview(同樣);REST 的 GET .../menu 自己的 runtime_contract 不論呼叫者是誰都是預設 fallback,所以它也不是能拿到真值的來源(見 Schemas)。

工具結果是 JSON 字串。錯誤:

{ "status": "error", "error": "<code>", "message": "..." }
error何時
unauthorized重新授權/擁有權失敗(SandboxAgentAuthError),或提交遇到 401/403 拒絕(例如 Command 輸出的規則)
validation_error工具參數不合法,或提交遇到 400/409/422 拒絕
forged_receipt收據不是簽過名的多段格式(必須含 4 個點)
not_found過期、別人的、隱藏、同一輪,或已用過的收據
confirmation_rejected其他閉形式確認失敗
already_committed此提案已經變成 run
proposal_not_pending狀態不是 prepared
same_turn確認的 HumanMessage 就是起源那一輪
not_later確認訊息不是嚴格較晚
receipt_reused這一輪確認已經 commit 過另一個提案
retryable暫時性 commit 失敗;提案留在 prepared,收據可重用
confirmation_input_unavailable後一輪已驗證,但耐久 input 重放失敗(沒抓到/R2 讀不到/digest 不符/不是 JSON)。不建 run;提案留在 prepared。 Agent 可再 mode=commit。
provider_unavailable控制面不可用,或工具沒有對應到其他代碼的提交拒絕——包括佇列的 429(sandbox_queued_run_limit,以及地端部署的 queue_full)。什麼都沒排入
internal_error未預期;message 是泛用句

sandbox_submit_job

mode="request"

必填:task_version_id、input(canonical JSON)。可選:timeout_seconds。禁止: proposal_receipt。

  • 版本 requires_confirmation=false、沒有宣告表格 writeback 的 output_policy,且 principal 可執行 → 伺服器提交 run(submission_source="agent")並回 run。
  • 版本帶 Command 輸出政策(custom_table_command,v5.21.0)且 requires_confirmation=false,同樣直接提交:伺服器先暫存確切的輸入位元組再提交,不經提案回合。若 Command 輸出的規則拒絕這次提交,403(例如 principal 是外部通道的 client、不是使用者)會以 unauthorized 回來,422(Command 不存在或不符)是 validation_error,503 的金鑰錯誤是 provider_unavailable。見任務輸出交給自訂表格 Command。
  • requires_confirmation=true——或版本宣告了表格 writeback 的 output_policy(custom_table_writeback,一律視為需確認等級)→ 伺服器建立 prepared 提案,取代此 principal 其他待處理提案,並回:
{ "kind": "prepared", "proposal_id": "...", "proposal_receipt": "<signed multi-segment token>", "summary": "...", "requires_confirmation": true, "task_id": "...", "task_version_id": "..." }

proposal_receipt 對模型是不透明的。只傳一個裸 id 會被判 forged_receipt。

mode="commit"

必填:只有 proposal_receipt。禁止: task_version_id、input、timeout_seconds、region、profile、cost、ENV、version。

必須是之後的 HumanMessage 輪次。Factory 在帶外附上新的 signed turn receipt。同一輪、隱藏、較舊、別人的、偽造、重用的收據一律失敗(not_found/forged_receipt)。

成功:{ "status": "ok", "kind": "submitted", "run_id": "...", "proposal_id": "...", "submission_source": "agent", "task_id": "...", "task_version_id": "...", "run_status": "queued" }。

回應遺失、同一組 winning pair 重送:{ "kind": "replay", "run_id": "..." }。

準備時拿到的 proposal_receipt 不一定能活過後面幾輪。sandbox_submitted_jobs 會為每個待確認提案重簽一張收據——mode=commit 用那張,不要用你快取的準備收據。

若確認已驗證、但原始 input 無法從耐久儲存重放,commit 回 confirmation_input_unavailable,提案留著。不要自己編 input。

前端該知道的 TTL

常數值意義
PROPOSAL_TTL_SECONDS1800(30 分)已準備提案過期 → expired。
TURN_RECEIPT_TTL_SECONDS600(10 分)簽過名的 HumanMessage 收據壽命。
MAX_STATUS_WAIT_SECONDS60sandbox_job_status.wait_seconds 上限。不套用到 REST 輪詢。

對話裡的自然語言「好」只決定 agent 要不要呼叫 mode=commit。伺服器仍要求另一則之後的可信 HumanMessage 收據。

sandbox_job_status 預覽(T-002)

這是唯一把顧客 output/log 位元組交給模型的面。REST GET .../content 只有旗標。

預覽上限形狀
Output≤64 KiB 前綴(MAX_OUTPUT_PREVIEW_UTF8_BYTES){ untrusted: true, label: "untrusted_customer_output", truncated, byte_length, text, content_kind: "customer_data", not_instructions: true }
Log≤16 KiB head+tail(MAX_LOG_PREVIEW_UTF8_BYTES)同樣框線,欄位是 head/tail,label: "untrusted_customer_log"
Artifacts≤20 筆 metadata(ARTIFACT_LIST_PAGE_SIZE)id, relative_path, byte_size, digest, declared_content_type。沒有 signed URL/object key。

R2 不可用時 lane 退化成 { available: bool } 佔位。job_status 仍回狀態。把巢狀顧客文字當資料,永遠不當指令。

wait_seconds 與 artifact_page_token 兩個都是 v1 no-op(db_lane.job_status 同一行 del wait_seconds, artifact_page_token)。產出物預覽永遠只回前 ≤20 筆、沒有翻頁——回應裡的 truncated/total_reported 是唯一能看出有列被截掉的訊號。不要等這個工具。前端仍輪詢 GET /chatrooms/{id}/runs/{run_id} 直到 terminal_at。

前端要做的事

  1. 提供房間設定,對 PATCH /private/chatrooms/setting/jobs/{id} 在 jobs 裡放 "sandbox"。用 GET /private/chatrooms/by_job/sandbox 列這些房間。
  2. 在房間設定列出 GET .../granted-jobs,讓房間管理者啟用/停用。在任務編輯器顯示 requires_confirmation(不要把 agent_enabled 當 Agent 開關)。
  3. 當 assistant 輪出現 prepared 提案,渲染 summary,等下一則人類訊息。不要做一個打 sandbox 端點的 REST 確認/拒絕按鈕——沒有那個端點。
  4. Commit 之後拿 run_id,走 執行 API 輪詢。
  5. sandbox_submitted_jobs 只給 agent 用來找回收據。沒有 REST 提案列表。

人類使用者仍用 POST /chatrooms/{id}/runs 提交。兩條路最後都是同一個 SandboxRunDetailResponse(submission_source 不同)。

相關

Last updated on