From 90cc71a4105915adea63b870004b5464b3e14e1a Mon Sep 17 00:00:00 2001 From: "hanzhi.421" Date: Tue, 8 Sep 2026 17:32:45 +0800 Subject: [PATCH 1/4] feat(studio): wake sleeping agents on demand --- frontend/README.md | 21 ++ frontend/src/adk/sandbox.ts | 4 +- frontend/src/i18n/resources/en-US/adk.json | 8 +- .../src/i18n/resources/en-US/newChat.json | 4 +- .../src/i18n/resources/en-US/sandbox.json | 9 +- frontend/src/i18n/resources/en-US/ui.json | 8 +- frontend/src/i18n/resources/zh-CN/adk.json | 8 +- .../src/i18n/resources/zh-CN/newChat.json | 4 +- .../src/i18n/resources/zh-CN/sandbox.json | 9 +- frontend/src/i18n/resources/zh-CN/ui.json | 8 +- frontend/src/ui/MyAgents.css | 11 + frontend/src/ui/MyAgents.tsx | 20 +- frontend/src/ui/SandboxAgentDetails.css | 8 + frontend/src/ui/SandboxAgentDetails.tsx | 26 +- .../ui/new-chat-modes/NewChatAgentPicker.tsx | 13 +- .../new-chat-modes/new-chat-agent-picker.css | 8 + frontend/tests/myAgents.test.mjs | 4 +- frontend/tests/sandboxThreadsClient.test.mjs | 36 +++ frontend/tests/sleepingAgentDetails.test.mjs | 89 ++++++ tests/cli/test_frontend_sandbox.py | 206 ++++++++++++-- veadk/cli/agentkit_session_metadata.py | 24 +- veadk/cli/frontend_sandbox.py | 232 ++++++++-------- .../{index-BQ3Jlms4.js => index-Mm_t7siF.js} | 256 +++++++++--------- ...CDk5_bn9.js => CodeDiffEditor-wiFmB4Gb.js} | 2 +- ...z4.js => MarkdownPromptEditor-CzED5mmY.js} | 2 +- .../{arc-DGTOgxTF.js => arc-BzyJ3IwP.js} | 2 +- ...hannel-DfHivBFg.js => channel-lutLakht.js} | 2 +- ...ex.es-G-8ONtfx.js => index.es-B_KFTR_b.js} | 2 +- ...n-p0Atyszt.js => jspdf.es.min-C26di6L1.js} | 6 +- ...{linear-CkyiAPab.js => linear-BqwNPwRj.js} | 2 +- ...{index-CO3TlFA0.css => index-DZzWuy85.css} | 2 +- ...f4.js => abnfDiagram-N423BO3Z-Briq3cng.js} | 2 +- ... architectureDiagram-T3A2C74G-CAQ9h7vQ.js} | 2 +- ...p.js => blockDiagram-VBNYF7ZC-B3lMihZA.js} | 2 +- ...QBQD.js => c4Diagram-5PPSVZJV-BLiTZU3y.js} | 2 +- ...BQh-E85-.js => chunk-2GRJ4B5K-DPoYqqWk.js} | 2 +- ...CRuiqFDw.js => chunk-2Q5K7J3B-Z7NjwzP-.js} | 2 +- ...C8ooCALw.js => chunk-5RXB4S5H-DqRGvg9X.js} | 2 +- ...C9U2OySo.js => chunk-5VM5RSS4-Dm30z_dJ.js} | 2 +- ...BUnMe2Ee.js => chunk-6Q2QTUOP-DM1-Iecx.js} | 2 +- ...Ex0T-RY8.js => chunk-GF5L2VYU-MtkaUvfd.js} | 2 +- ...hhQuACJs.js => chunk-JWPE2WC7-2ehhPGoP.js} | 2 +- ...B8gh2sAS.js => chunk-KBJHAD2P-Bss_OA_r.js} | 2 +- ...DvFneOOt.js => chunk-RYQCIY6F-xcTnbe8k.js} | 2 +- ...DPuleV9y.js => chunk-XXDRQBXY-Dx7EqXCE.js} | 2 +- .../mermaid/classDiagram-JCYQIIEL-BYAKv_on.js | 1 - .../mermaid/classDiagram-JCYQIIEL-D2BSvBqN.js | 1 + .../classDiagram-v2-OCEON4UE-BYAKv_on.js | 1 - .../classDiagram-v2-OCEON4UE-D2BSvBqN.js | 1 + ...7.js => cose-bilkent-JH36ORCC-C6mxHZz0.js} | 2 +- ...swHHSi.js => cynefin-OW5HDTMX-Bgk9Fktk.js} | 2 +- ...js => cynefinDiagram-MW4NZA55-CkFb1mta.js} | 2 +- ...B5myTIBI.js => dagre-VZM6K2ZE-0UQAaUo1.js} | 2 +- ...GoU6Z-.js => diagram-7IWD3JNH-CRuqNsDe.js} | 2 +- ...t2r-rW.js => diagram-B4RE2ZJO-6PukEZ9p.js} | 2 +- ...TbcVni.js => diagram-LBJQPF4R-CsXPaEWt.js} | 2 +- ...OFN8pM.js => diagram-Q27KOJAE-B2QYy4c0.js} | 2 +- ...c5MJrP.js => diagram-UB23O5K3-CG0bJKm4.js} | 2 +- ...jw.js => ebnfDiagram-BXEA7PRR-DE7aluRR.js} | 2 +- ...zH1V.js => erDiagram-JOGREHBK-Kd3OSKxv.js} | 2 +- ...8s.js => flowDiagram-UKHOOZJN-Bu25q4Ig.js} | 2 +- ...3.js => ganttDiagram-PKOTCBZU-Dsi9OR14.js} | 2 +- ...s => gitGraphDiagram-DS77QQ5N-D0O2PLrN.js} | 2 +- ...Xf.js => infoDiagram-6WML65LV-CYjidIr3.js} | 2 +- ...s => ishikawaDiagram-WSZJBQD7-CC02W5B-.js} | 2 +- ...js => journeyDiagram-NVQOT4AX-B2jnt5to.js} | 2 +- ...=> kanban-definition-27J2QSJJ-CdB6oP42.js} | 2 +- ...e-CbFLL6RY.js => mermaid.core-Bnu8DfDx.js} | 8 +- ...> mindmap-definition-FAOFIHXS-BdE7QFkX.js} | 2 +- ...RJj.js => pegDiagram-VL7TDLO6-D9LDSuMb.js} | 2 +- ...Y4u.js => pieDiagram-7S7Q4E2Y-B1Uhf1yH.js} | 2 +- ...s => quadrantDiagram-CIZ2JOQS-CL0G-yZN.js} | 2 +- ...s => railroadDiagram-AXF67PYL-DRTSH-ts.js} | 2 +- ...> requirementDiagram-LRYGKXZP-B2EwdOJG.js} | 2 +- ....js => sankeyDiagram-W5VNT64P-D8fR6_px.js} | 2 +- ...s => sequenceDiagram-SI44F4Z6-hWLozATl.js} | 2 +- ...gp.js => sizeCapture-X5ZJPWSS-CH6p3yJY.js} | 2 +- ...K.js => stateDiagram-OKZ733FA-CwjeaU5t.js} | 2 +- .../stateDiagram-v2-UEYNNEHI-BMEr5td6.js | 1 + .../stateDiagram-v2-UEYNNEHI-RFKb0Bt4.js | 1 - ...zXab.js => swimlanes-SLNWSIFB-DihlBCmu.js} | 4 +- .../swimlanesDiagram-ULZ7WXOC-C6kXkYU-.js | 8 + .../swimlanesDiagram-ULZ7WXOC-D1tHG20c.js | 8 - ... timeline-definition-Z64GVDOM-C9l92Tjf.js} | 2 +- ...MH.js => vennDiagram-T6HMQDX7-DQr6mw5G.js} | 2 +- ...js => wardleyDiagram-T6FBY63Y-AypstLgg.js} | 2 +- ...js => xychartDiagram-ELKLHX3M-QbxBF0DD.js} | 2 +- veadk/webui/index.html | 4 +- veadk/webui/website-integration.js | 84 +++--- 89 files changed, 824 insertions(+), 426 deletions(-) create mode 100644 frontend/tests/sleepingAgentDetails.test.mjs rename veadk/webui/assets/app/{index-BQ3Jlms4.js => index-Mm_t7siF.js} (84%) rename veadk/webui/assets/chunks/{CodeDiffEditor-CDk5_bn9.js => CodeDiffEditor-wiFmB4Gb.js} (99%) rename veadk/webui/assets/chunks/{MarkdownPromptEditor-Bbb9CZz4.js => MarkdownPromptEditor-CzED5mmY.js} (99%) rename veadk/webui/assets/chunks/{arc-DGTOgxTF.js => arc-BzyJ3IwP.js} (98%) rename veadk/webui/assets/chunks/{channel-DfHivBFg.js => channel-lutLakht.js} (53%) rename veadk/webui/assets/chunks/{index.es-G-8ONtfx.js => index.es-B_KFTR_b.js} (99%) rename veadk/webui/assets/chunks/{jspdf.es.min-p0Atyszt.js => jspdf.es.min-C26di6L1.js} (99%) rename veadk/webui/assets/chunks/{linear-CkyiAPab.js => linear-BqwNPwRj.js} (98%) rename veadk/webui/assets/styles/{index-CO3TlFA0.css => index-DZzWuy85.css} (56%) rename veadk/webui/assets/visualizations/mermaid/{abnfDiagram-N423BO3Z-nw01orf4.js => abnfDiagram-N423BO3Z-Briq3cng.js} (86%) rename veadk/webui/assets/visualizations/mermaid/{architectureDiagram-T3A2C74G-DhEE-z50.js => architectureDiagram-T3A2C74G-CAQ9h7vQ.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{blockDiagram-VBNYF7ZC-Db-F-mPp.js => blockDiagram-VBNYF7ZC-B3lMihZA.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{c4Diagram-5PPSVZJV-DDMlQBQD.js => c4Diagram-5PPSVZJV-BLiTZU3y.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{chunk-2GRJ4B5K-BQh-E85-.js => chunk-2GRJ4B5K-DPoYqqWk.js} (93%) rename veadk/webui/assets/visualizations/mermaid/{chunk-2Q5K7J3B-CRuiqFDw.js => chunk-2Q5K7J3B-Z7NjwzP-.js} (66%) rename veadk/webui/assets/visualizations/mermaid/{chunk-5RXB4S5H-C8ooCALw.js => chunk-5RXB4S5H-DqRGvg9X.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{chunk-5VM5RSS4-C9U2OySo.js => chunk-5VM5RSS4-Dm30z_dJ.js} (83%) rename veadk/webui/assets/visualizations/mermaid/{chunk-6Q2QTUOP-BUnMe2Ee.js => chunk-6Q2QTUOP-DM1-Iecx.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{chunk-GF5L2VYU-Ex0T-RY8.js => chunk-GF5L2VYU-MtkaUvfd.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{chunk-JWPE2WC7-hhQuACJs.js => chunk-JWPE2WC7-2ehhPGoP.js} (78%) rename veadk/webui/assets/visualizations/mermaid/{chunk-KBJHAD2P-B8gh2sAS.js => chunk-KBJHAD2P-Bss_OA_r.js} (87%) rename veadk/webui/assets/visualizations/mermaid/{chunk-RYQCIY6F-DvFneOOt.js => chunk-RYQCIY6F-xcTnbe8k.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{chunk-XXDRQBXY-DPuleV9y.js => chunk-XXDRQBXY-Dx7EqXCE.js} (53%) delete mode 100644 veadk/webui/assets/visualizations/mermaid/classDiagram-JCYQIIEL-BYAKv_on.js create mode 100644 veadk/webui/assets/visualizations/mermaid/classDiagram-JCYQIIEL-D2BSvBqN.js delete mode 100644 veadk/webui/assets/visualizations/mermaid/classDiagram-v2-OCEON4UE-BYAKv_on.js create mode 100644 veadk/webui/assets/visualizations/mermaid/classDiagram-v2-OCEON4UE-D2BSvBqN.js rename veadk/webui/assets/visualizations/mermaid/{cose-bilkent-JH36ORCC-Buwf2Ky7.js => cose-bilkent-JH36ORCC-C6mxHZz0.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{cynefin-OW5HDTMX-nnswHHSi.js => cynefin-OW5HDTMX-Bgk9Fktk.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{cynefinDiagram-MW4NZA55-CFhrG3VU.js => cynefinDiagram-MW4NZA55-CkFb1mta.js} (98%) rename veadk/webui/assets/visualizations/mermaid/{dagre-VZM6K2ZE-B5myTIBI.js => dagre-VZM6K2ZE-0UQAaUo1.js} (97%) rename veadk/webui/assets/visualizations/mermaid/{diagram-7IWD3JNH-CkGoU6Z-.js => diagram-7IWD3JNH-CRuqNsDe.js} (96%) rename veadk/webui/assets/visualizations/mermaid/{diagram-B4RE2ZJO-B_t2r-rW.js => diagram-B4RE2ZJO-6PukEZ9p.js} (97%) rename veadk/webui/assets/visualizations/mermaid/{diagram-LBJQPF4R-B3TbcVni.js => diagram-LBJQPF4R-CsXPaEWt.js} (94%) rename veadk/webui/assets/visualizations/mermaid/{diagram-Q27KOJAE-B5OFN8pM.js => diagram-Q27KOJAE-B2QYy4c0.js} (98%) rename veadk/webui/assets/visualizations/mermaid/{diagram-UB23O5K3-CXc5MJrP.js => diagram-UB23O5K3-CG0bJKm4.js} (95%) rename veadk/webui/assets/visualizations/mermaid/{ebnfDiagram-BXEA7PRR-CRo_Ixjw.js => ebnfDiagram-BXEA7PRR-DE7aluRR.js} (87%) rename veadk/webui/assets/visualizations/mermaid/{erDiagram-JOGREHBK-Cs8mzH1V.js => erDiagram-JOGREHBK-Kd3OSKxv.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{flowDiagram-UKHOOZJN-BVN7QA8s.js => flowDiagram-UKHOOZJN-Bu25q4Ig.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{ganttDiagram-PKOTCBZU-DxE60Pk3.js => ganttDiagram-PKOTCBZU-Dsi9OR14.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{gitGraphDiagram-DS77QQ5N-t-EjQ10r.js => gitGraphDiagram-DS77QQ5N-D0O2PLrN.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{infoDiagram-6WML65LV-YvlC2IXf.js => infoDiagram-6WML65LV-CYjidIr3.js} (69%) rename veadk/webui/assets/visualizations/mermaid/{ishikawaDiagram-WSZJBQD7-Cwg2UYvf.js => ishikawaDiagram-WSZJBQD7-CC02W5B-.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{journeyDiagram-NVQOT4AX-DZzBSvNW.js => journeyDiagram-NVQOT4AX-B2jnt5to.js} (98%) rename veadk/webui/assets/visualizations/mermaid/{kanban-definition-27J2QSJJ-19IRMlWl.js => kanban-definition-27J2QSJJ-CdB6oP42.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{mermaid.core-CbFLL6RY.js => mermaid.core-Bnu8DfDx.js} (98%) rename veadk/webui/assets/visualizations/mermaid/{mindmap-definition-FAOFIHXS-BhSjSCng.js => mindmap-definition-FAOFIHXS-BdE7QFkX.js} (98%) rename veadk/webui/assets/visualizations/mermaid/{pegDiagram-VL7TDLO6-Dj9sNRJj.js => pegDiagram-VL7TDLO6-D9LDSuMb.js} (87%) rename veadk/webui/assets/visualizations/mermaid/{pieDiagram-7S7Q4E2Y-BBVURY4u.js => pieDiagram-7S7Q4E2Y-B1Uhf1yH.js} (96%) rename veadk/webui/assets/visualizations/mermaid/{quadrantDiagram-CIZ2JOQS-vLBYy8fJ.js => quadrantDiagram-CIZ2JOQS-CL0G-yZN.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{railroadDiagram-AXF67PYL-DVp5IK1D.js => railroadDiagram-AXF67PYL-DRTSH-ts.js} (84%) rename veadk/webui/assets/visualizations/mermaid/{requirementDiagram-LRYGKXZP-SKzBhgIJ.js => requirementDiagram-LRYGKXZP-B2EwdOJG.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{sankeyDiagram-W5VNT64P-CqNlgMFX.js => sankeyDiagram-W5VNT64P-D8fR6_px.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{sequenceDiagram-SI44F4Z6-BdwxgfmL.js => sequenceDiagram-SI44F4Z6-hWLozATl.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{sizeCapture-X5ZJPWSS-E0K3iAgp.js => sizeCapture-X5ZJPWSS-CH6p3yJY.js} (87%) rename veadk/webui/assets/visualizations/mermaid/{stateDiagram-OKZ733FA-DZafORPK.js => stateDiagram-OKZ733FA-CwjeaU5t.js} (96%) create mode 100644 veadk/webui/assets/visualizations/mermaid/stateDiagram-v2-UEYNNEHI-BMEr5td6.js delete mode 100644 veadk/webui/assets/visualizations/mermaid/stateDiagram-v2-UEYNNEHI-RFKb0Bt4.js rename veadk/webui/assets/visualizations/mermaid/{swimlanes-SLNWSIFB-fZKzzXab.js => swimlanes-SLNWSIFB-DihlBCmu.js} (99%) create mode 100644 veadk/webui/assets/visualizations/mermaid/swimlanesDiagram-ULZ7WXOC-C6kXkYU-.js delete mode 100644 veadk/webui/assets/visualizations/mermaid/swimlanesDiagram-ULZ7WXOC-D1tHG20c.js rename veadk/webui/assets/visualizations/mermaid/{timeline-definition-Z64GVDOM-CBxtB95K.js => timeline-definition-Z64GVDOM-C9l92Tjf.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{vennDiagram-T6HMQDX7-D-Tm2LMH.js => vennDiagram-T6HMQDX7-DQr6mw5G.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{wardleyDiagram-T6FBY63Y-tCsDQKx9.js => wardleyDiagram-T6FBY63Y-AypstLgg.js} (99%) rename veadk/webui/assets/visualizations/mermaid/{xychartDiagram-ELKLHX3M-i_2UPGnz.js => xychartDiagram-ELKLHX3M-QbxBF0DD.js} (99%) diff --git a/frontend/README.md b/frontend/README.md index 9a9467625..e3e2a07d3 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -945,3 +945,24 @@ it natively. Each component lives in its own self-registering directory under view, so a catalog/renderer mismatch never breaks the page. To add a component, drop a folder there (frontend) and declare it in the agent's catalog (backend — see `veadk.a2ui.BaseA2UICatalog`). + +### Sleeping agents + +Agent categories query live Sessions and Session snapshots without restoring them, +including legacy requests with `autoResumeSnapshots=true`. Studio presents the +latest saved record for each logical agent as a sleeping card, unless a live +Session already represents it. Snapshot `SessionMetadata` supplies its display +name, creator and agent kind, including on SDK versions that omit this field. +Owners can list, wake and delete their own records; administrators can also manage +legacy records without owner metadata. Records with a different agent kind are +excluded when kinds share a Tool. + +Opening a sleeping agent explicitly restores it and then opens its normal entry +point. The UI explains the wait using “waking” language and permits retry after a +failure. Same-agent wake requests are serialized within a service instance, and +retries check for an existing live Session. This is not a distributed lock. +Deleting a sleeping agent requires confirmation and sends `ToolId` and `SnapshotId` +to `DeleteSessionSnapshot`; it deletes the selected saved record only. If that +logical agent has older records, the next latest record can appear on refresh. +Failed records remain visible for deletion but cannot be opened. The UI uses +agent terminology rather than exposing these control-plane resource types. diff --git a/frontend/src/adk/sandbox.ts b/frontend/src/adk/sandbox.ts index b635f00a5..76d496d0a 100644 --- a/frontend/src/adk/sandbox.ts +++ b/frontend/src/adk/sandbox.ts @@ -697,8 +697,8 @@ function parseSnapshot( } function sandboxListUrl(base: string, options?: SandboxListOptions): string { - if (!options?.autoResumeSnapshots) return base; - const params = new URLSearchParams({ autoResumeSnapshots: "true" }); + if (options?.autoResumeSnapshots === undefined) return base; + const params = new URLSearchParams({ autoResumeSnapshots: String(options.autoResumeSnapshots) }); return `${base}?${params.toString()}`; } diff --git a/frontend/src/i18n/resources/en-US/adk.json b/frontend/src/i18n/resources/en-US/adk.json index 24cfc4487..11e8747bc 100644 --- a/frontend/src/i18n/resources/en-US/adk.json +++ b/frontend/src/i18n/resources/en-US/adk.json @@ -237,7 +237,7 @@ "sandbox": { "status": { "ready": "Ready", - "wakeable": "Wakeable", + "wakeable": "Asleep", "creating": "Creating", "starting": "Starting", "pending": "Pending", @@ -276,9 +276,9 @@ "missingSessionForTerminal": "The AgentKit session for the terminal is missing.", "openTerminalFailed": "Unable to open the {{kind}} terminal.", "deleteAgentFailed": "Unable to delete the {{kind}} agent.", - "missingSnapshot": "The AgentKit snapshot to wake is missing.", - "resumeSnapshotFailed": "Unable to wake the agent from its snapshot. Try again later.", - "deleteSnapshotFailed": "Unable to delete the agent snapshot.", + "missingSnapshot": "The agent to wake was not found.", + "resumeSnapshotFailed": "Unable to wake the agent. Try again later.", + "deleteSnapshotFailed": "Unable to delete the agent. Try again later.", "missingSessionToConnect": "The AgentKit session to connect is missing.", "connectCodexFailed": "Unable to connect to the Codex agent. Try again later.", "sessionNotReady": "The AgentKit session is not ready. Current status: {{status}}.", diff --git a/frontend/src/i18n/resources/en-US/newChat.json b/frontend/src/i18n/resources/en-US/newChat.json index 122213cfc..e0c290b41 100644 --- a/frontend/src/i18n/resources/en-US/newChat.json +++ b/frontend/src/i18n/resources/en-US/newChat.json @@ -77,7 +77,9 @@ "loadType": "Load {{type}}", "connectGeneral": "Connect to General Agent", "openLocal": "Open local Agent", - "openType": "Open {{type}}" + "openType": "Open {{type}}", + "sleepingHint": "This agent is asleep. Waking it before opening may take some time.", + "wakingHint": "Waking the agent. This may take some time." }, "skill": { "spaceAria": "Skill spaces", diff --git a/frontend/src/i18n/resources/en-US/sandbox.json b/frontend/src/i18n/resources/en-US/sandbox.json index 079bf8634..6998a5f0c 100644 --- a/frontend/src/i18n/resources/en-US/sandbox.json +++ b/frontend/src/i18n/resources/en-US/sandbox.json @@ -143,7 +143,7 @@ }, "agentDetails": { "back": "Back to Agents", - "subtitle": "{{agent}} AgentKit Session details", + "subtitle": "{{agent}} agent details", "type": "Agent type", "status": "Status", "createdBy": "Created by", @@ -161,9 +161,12 @@ "wake": "Wake Agent", "open": "Open Agent", "deleteTitle": "Delete Agent?", - "deleteDescription": "This will delete “{{name}}” and its AgentKit {{resource}}. This action cannot be undone.", + "deleteDescription": "Delete “{{name}}” and its saved data? This cannot be undone.", "deleting": "Deleting…", - "confirmDelete": "Delete" + "confirmDelete": "Delete", + "sleepingHint": "This agent is asleep. Waking it before opening may take some time.", + "wakingHint": "Waking the agent. This may take some time.", + "agentId": "Agent ID" }, "agentWorkspace": { "back": "Back to Agents", diff --git a/frontend/src/i18n/resources/en-US/ui.json b/frontend/src/i18n/resources/en-US/ui.json index 10dcbee2b..73382617c 100644 --- a/frontend/src/i18n/resources/en-US/ui.json +++ b/frontend/src/i18n/resources/en-US/ui.json @@ -1338,7 +1338,7 @@ "remainingTime": "Time remaining", "expiringSoon": "Expiring soon", "sandboxRemaining": "{{hours}} hr {{minutes}} min", - "wakeable": "Wakeable", + "wakeable": "Asleep", "neverExpires": "Never expires", "editDraftNamed": "Edit draft {{name}}", "viewProgress": "View progress", @@ -1381,7 +1381,7 @@ }, "sandboxStatus": { "ready": "Ready", - "wakeable": "Wakeable", + "wakeable": "Asleep", "creating": "Creating", "starting": "Starting", "initializing": "Starting", @@ -1394,7 +1394,9 @@ "deleting": "Deleting", "deleted": "Deleted", "unknown": "Unknown status" - } + }, + "sleepingHint": "This agent is asleep. Waking it before opening may take some time.", + "wakingHint": "Waking the agent. This may take some time." }, "skillCenter": { "library": "Skill library", diff --git a/frontend/src/i18n/resources/zh-CN/adk.json b/frontend/src/i18n/resources/zh-CN/adk.json index 8114e2b99..9475a42ca 100644 --- a/frontend/src/i18n/resources/zh-CN/adk.json +++ b/frontend/src/i18n/resources/zh-CN/adk.json @@ -237,7 +237,7 @@ "sandbox": { "status": { "ready": "就绪", - "wakeable": "可唤醒", + "wakeable": "已休眠", "creating": "创建中", "starting": "启动中", "pending": "等待中", @@ -276,9 +276,9 @@ "missingSessionForTerminal": "缺少要打开 Terminal 的 AgentKit Session。", "openTerminalFailed": "无法打开 {{kind}} Terminal。", "deleteAgentFailed": "无法删除 {{kind}} 智能体。", - "missingSnapshot": "缺少要唤醒的 AgentKit Snapshot。", - "resumeSnapshotFailed": "无法从快照唤醒智能体,请稍后重试。", - "deleteSnapshotFailed": "无法删除智能体快照。", + "missingSnapshot": "未找到要唤醒的智能体。", + "resumeSnapshotFailed": "无法唤醒智能体,请稍后重试。", + "deleteSnapshotFailed": "无法删除智能体,请稍后重试。", "missingSessionToConnect": "缺少要连接的 AgentKit Session。", "connectCodexFailed": "无法连接 Codex 智能体,请稍后重试。", "sessionNotReady": "AgentKit Session 尚未就绪,当前状态:{{status}}。", diff --git a/frontend/src/i18n/resources/zh-CN/newChat.json b/frontend/src/i18n/resources/zh-CN/newChat.json index 5693ae261..16ac5976c 100644 --- a/frontend/src/i18n/resources/zh-CN/newChat.json +++ b/frontend/src/i18n/resources/zh-CN/newChat.json @@ -77,7 +77,9 @@ "loadType": "加载 {{type}}", "connectGeneral": "连接通用智能体", "openLocal": "打开本地智能体", - "openType": "打开 {{type}}" + "openType": "打开 {{type}}", + "sleepingHint": "该智能体已休眠,进入时需要唤醒,可能需要一些时间。", + "wakingHint": "正在唤醒智能体,可能需要一些时间。" }, "skill": { "spaceAria": "技能空间", diff --git a/frontend/src/i18n/resources/zh-CN/sandbox.json b/frontend/src/i18n/resources/zh-CN/sandbox.json index ddabf50db..e7d356f83 100644 --- a/frontend/src/i18n/resources/zh-CN/sandbox.json +++ b/frontend/src/i18n/resources/zh-CN/sandbox.json @@ -143,7 +143,7 @@ }, "agentDetails": { "back": "返回智能体列表", - "subtitle": "{{agent}} AgentKit Session 详情", + "subtitle": "{{agent}} 智能体详情", "type": "智能体类型", "status": "状态", "createdBy": "创建人", @@ -161,9 +161,12 @@ "wake": "唤醒智能体", "open": "打开智能体", "deleteTitle": "删除智能体?", - "deleteDescription": "将删除“{{name}}”及其 AgentKit {{resource}},此操作无法撤销。", + "deleteDescription": "将删除“{{name}}”及其保存的数据,此操作无法撤销。", "deleting": "删除中…", - "confirmDelete": "确认删除" + "confirmDelete": "确认删除", + "sleepingHint": "该智能体已休眠,进入时需要唤醒,可能需要一些时间。", + "wakingHint": "正在唤醒智能体,可能需要一些时间。", + "agentId": "智能体 ID" }, "agentWorkspace": { "back": "返回智能体列表", diff --git a/frontend/src/i18n/resources/zh-CN/ui.json b/frontend/src/i18n/resources/zh-CN/ui.json index fe5d03f78..c7d7e7bc3 100644 --- a/frontend/src/i18n/resources/zh-CN/ui.json +++ b/frontend/src/i18n/resources/zh-CN/ui.json @@ -1338,7 +1338,7 @@ "remainingTime": "剩余时间", "expiringSoon": "即将清空", "sandboxRemaining": "{{hours}} 小时 {{minutes}} 分钟", - "wakeable": "可唤醒", + "wakeable": "已休眠", "neverExpires": "永不过期", "editDraftNamed": "编辑草稿 {{name}}", "viewProgress": "查看进度", @@ -1381,7 +1381,7 @@ }, "sandboxStatus": { "ready": "就绪", - "wakeable": "可唤醒", + "wakeable": "已休眠", "creating": "创建中", "starting": "启动中", "initializing": "启动中", @@ -1394,7 +1394,9 @@ "deleting": "删除中", "deleted": "已删除", "unknown": "未知状态" - } + }, + "sleepingHint": "该智能体已休眠,进入时需要唤醒,可能需要一些时间。", + "wakingHint": "正在唤醒智能体,可能需要一些时间。" }, "skillCenter": { "library": "技能库", diff --git a/frontend/src/ui/MyAgents.css b/frontend/src/ui/MyAgents.css index 682017d03..ecea1c113 100644 --- a/frontend/src/ui/MyAgents.css +++ b/frontend/src/ui/MyAgents.css @@ -374,3 +374,14 @@ } } + +.my-agent-wake-note { + margin: 8px 0 0; + color: hsl(var(--muted-foreground)); + font-size: 12px; + line-height: 1.5; +} + +.my-agent-wake-note[role="alert"] { + color: hsl(var(--destructive)); +} diff --git a/frontend/src/ui/MyAgents.tsx b/frontend/src/ui/MyAgents.tsx index 47035bac1..b261f5bd3 100644 --- a/frontend/src/ui/MyAgents.tsx +++ b/frontend/src/ui/MyAgents.tsx @@ -1,3 +1,4 @@ +import { TextShimmer } from "./text-shimmer/TextShimmer"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import type { SVGProps } from "react"; import { EmptyMessage } from "@openai/apps-sdk-ui/components/EmptyMessage"; @@ -349,6 +350,7 @@ function AgentCard({ compatibility, onRetryCompatibility, connecting, + connectError, connected, deploymentTask, nowMs, @@ -363,6 +365,7 @@ function AgentCard({ compatibility?: RuntimeCompatibility; onRetryCompatibility?: (agent: MyAgentCardData) => void; connecting?: boolean; + connectError?: string; connected?: boolean; deploymentTask?: DeploymentTaskUpdate; nowMs: number; @@ -388,13 +391,13 @@ function AgentCard({ else onViewDetails?.(agent); return; } - if (!actionable) return; + if (!actionable && !agent.sandbox) return; if (deploymentTask) onViewDeploymentTask?.(deploymentTask); else onViewDetails?.(agent); }; const cardTargetEnabled = agent.draft ? Boolean(deploymentTask ? onViewDeploymentTask : onViewDetails) - : actionable && Boolean(deploymentTask ? onViewDeploymentTask : onViewDetails); + : (actionable || Boolean(agent.sandbox)) && Boolean(deploymentTask ? onViewDeploymentTask : onViewDetails); const cardTargetLabel = agent.draft ? deploymentTask ? t("myAgents.viewDeploymentProgress", { name: agent.name }) @@ -588,6 +591,10 @@ function AgentCard({ ) : null} /> + {connectError ?

{connectError}

: null} + {wakeable && actionable ?

+ {connecting ? {t("myAgents.wakingHint")} : t("myAgents.sleepingHint")} +

: null} {!agent.sandbox ? ( {agent.description} ) : null} @@ -670,6 +677,7 @@ export function MyAgents({ const [loadingSandboxAgents, setLoadingSandboxAgents] = useState(false); const [sandboxError, setSandboxError] = useState(""); const [connectingAgentId, setConnectingAgentId] = useState(""); + const [connectErrors, setConnectErrors] = useState>({}); const [runtimeCompatibility, setRuntimeCompatibility] = useState< Record >({}); @@ -902,11 +910,11 @@ export function MyAgents({ const sessions = type === "codex" ? await sandboxClient.listSessions({ signal: controller.signal, - autoResumeSnapshots: true, + autoResumeSnapshots: false, }) : await sandboxClient.listAgentSessions(type, { signal: controller.signal, - autoResumeSnapshots: true, + autoResumeSnapshots: false, }); if (sandboxRequestRef.current !== requestId) return; setSandboxAgents(sessions.map((session) => sandboxToAgent(session, t))); @@ -1000,6 +1008,7 @@ export function MyAgents({ const useAgent = useCallback(async (agent: MyAgentCardData) => { if (connectingAgentId) return; setConnectingAgentId(agent.id); + setConnectErrors((current) => ({ ...current, [agent.id]: "" })); try { await new Promise((resolve) => requestAnimationFrame(() => resolve())); if (agent.sandbox) { @@ -1007,6 +1016,8 @@ export function MyAgents({ } else { await onUseAgent(agent); } + } catch (cause) { + setConnectErrors((current) => ({ ...current, [agent.id]: cause instanceof Error ? cause.message : String(cause) })); } finally { setConnectingAgentId(""); } @@ -1320,6 +1331,7 @@ export function MyAgents({ } } : undefined} connecting={agent.id === connectingAgentId} + connectError={connectErrors[agent.id]} connected={agent.runtime?.runtimeId === connectedRuntimeId} onEditDraft={onEditDraft} onDeleteDraft={setDraftToDelete} diff --git a/frontend/src/ui/SandboxAgentDetails.css b/frontend/src/ui/SandboxAgentDetails.css index 204fb87bb..c1c9fd3de 100644 --- a/frontend/src/ui/SandboxAgentDetails.css +++ b/frontend/src/ui/SandboxAgentDetails.css @@ -151,3 +151,11 @@ border-bottom: 0; } } + +.sandbox-agent-wake-note { + margin: 0; + padding: 12px 24px; + color: hsl(var(--muted-foreground)); + font-size: 13px; + line-height: 1.5; +} diff --git a/frontend/src/ui/SandboxAgentDetails.tsx b/frontend/src/ui/SandboxAgentDetails.tsx index b974d9a74..e4a29dee3 100644 --- a/frontend/src/ui/SandboxAgentDetails.tsx +++ b/frontend/src/ui/SandboxAgentDetails.tsx @@ -1,3 +1,4 @@ +import { TextShimmer } from "./text-shimmer/TextShimmer"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { sandboxStatusLabel, type SandboxAgentResource } from "../adk/sandbox"; @@ -94,23 +95,15 @@ export function SandboxAgentDetails({
{t("agentDetails.type")}
{label}
{t("agentDetails.status")}
{sandboxStatusLabel(session.status)}
{t("agentDetails.createdBy")}
{session.createdBy?.trim() || t("common.unknownSource")}
-
-
{wakeable ? t("agentDetails.snapshotStatus") : t("agentDetails.toolType")}
-
{wakeable ? session.snapshotStatus || "—" : session.toolType || "—"}
-
{t("agentDetails.createdAt")}
{formatDate(session.createdAt, locale)}
-
-
{wakeable ? t("agentDetails.snapshotReason") : t("agentDetails.expiresAt")}
-
{wakeable ? session.reason || "—" : formatDate(session.expireAt, locale)}
-
-
-
{t(wakeable ? "agentDetails.snapshotId" : "agentDetails.sessionId")}
-
{wakeable ? session.snapshotId : resourceId}
-
- {wakeable && session.sourceSessionId ? ( -
{t("agentDetails.sourceSessionId")}
{session.sourceSessionId}
- ) : null} + {!wakeable ?
{t("agentDetails.expiresAt")}
{formatDate(session.expireAt, locale)}
: null} +
{t("agentDetails.agentId")}
{resourceId}
+ {wakeable && session.status.toLowerCase() === "wakeable" ? ( +

+ {opening ? {t("agentDetails.wakingHint")} : t("agentDetails.sleepingHint")} +

+ ) : null}