From a93a7fa7fcaaed8e5cf4c7da2d8926d357a059ca Mon Sep 17 00:00:00 2001 From: evanlowe <62918515+evanlowe@users.noreply.github.com> Date: Tue, 28 Jul 2026 18:15:08 +0800 Subject: [PATCH 1/5] feat(studio): add paginated agent catalog --- frontend/src/App.tsx | 144 +++- frontend/src/adk/connections.ts | 5 +- frontend/src/create/AgentBuildCanvas.css | 35 +- frontend/src/create/AgentBuildCanvas.tsx | 14 +- frontend/src/create/CustomCreate.css | 1 + frontend/src/create/CustomCreate.tsx | 4 +- frontend/src/styles.css | 55 ++ frontend/src/ui/AgentWorkspace.css | 54 ++ frontend/src/ui/AgentWorkspace.tsx | 51 +- frontend/src/ui/MyAgents.css | 286 +++++++ frontend/src/ui/MyAgents.tsx | 428 +++++++++++ frontend/src/ui/Navbar.tsx | 28 +- frontend/src/ui/Sidebar.tsx | 6 +- frontend/tests/agentBuildCanvas.test.mjs | 36 +- frontend/tests/agentWorkspace.test.mjs | 54 +- .../tests/manageAgentsConnection.test.mjs | 8 +- frontend/tests/myAgents.test.mjs | 142 ++++ frontend/tests/newChatComposerLayout.test.mjs | 3 +- frontend/tests/sessionHeader.test.mjs | 18 +- frontend/tests/skillCreateMode.test.mjs | 7 +- frontend/tests/studioAccess.test.mjs | 2 +- tests/cli/test_studio_rbac.py | 4 + veadk/cli/cli_frontend.py | 68 +- ...tor-CFQnxy69.js => CodeEditor-D7V-15-X.js} | 2 +- ...TD.js => MarkdownPromptEditor-Oc7pxbkE.js} | 2 +- veadk/webui/assets/index-B7PFhrJy.js | 713 ----------------- veadk/webui/assets/index-CCwvwDB6.css | 10 + veadk/webui/assets/index-DIXpawNo.css | 10 - veadk/webui/assets/index-DnlZA5Rc.js | 718 ++++++++++++++++++ veadk/webui/index.html | 4 +- 30 files changed, 2075 insertions(+), 837 deletions(-) create mode 100644 frontend/src/ui/MyAgents.css create mode 100644 frontend/src/ui/MyAgents.tsx create mode 100644 frontend/tests/myAgents.test.mjs rename veadk/webui/assets/{CodeEditor-CFQnxy69.js => CodeEditor-D7V-15-X.js} (99%) rename veadk/webui/assets/{MarkdownPromptEditor-BE_OXaTD.js => MarkdownPromptEditor-Oc7pxbkE.js} (99%) delete mode 100644 veadk/webui/assets/index-B7PFhrJy.js create mode 100644 veadk/webui/assets/index-CCwvwDB6.css delete mode 100644 veadk/webui/assets/index-DIXpawNo.css create mode 100644 veadk/webui/assets/index-DnlZA5Rc.js diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 0ff43fa7..b276ce92 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -76,6 +76,7 @@ import { AgentWorkspace, type WorkspaceAgentDraft, } from "./ui/AgentWorkspace"; +import { MyAgents, type MyAgentCardData } from "./ui/MyAgents"; import { SearchView } from "./ui/Search"; import { buildAgentEntries, @@ -955,6 +956,7 @@ export default function App() { const [focusedWorkspaceCaseKind, setFocusedWorkspaceCaseKind] = useState<"good" | "bad">("good"); const [feedbackTargetEventId, setFeedbackTargetEventId] = useState(""); + const [myAgents, setMyAgents] = useState(false); // A search result may belong to a different agent; remember it so the // agent-switch effect opens it instead of resetting to a fresh chat. const pendingOpenRef = useRef<{ app: string; sid: string } | null>(null); @@ -981,6 +983,8 @@ export default function App() { } | null>(null); const [focusedDeploymentTaskId, setFocusedDeploymentTaskId] = useState(""); const [focusedWorkspaceAgentId, setFocusedWorkspaceAgentId] = useState(""); + const [agentDetailTarget, setAgentDetailTarget] = + useState(null); // Shown when the user clicks the breadcrumb root to leave a create mode; // warns that the in-progress draft will be discarded. const [confirmLeave, setConfirmLeave] = useState(false); @@ -1368,6 +1372,15 @@ export default function App() { setUserInfo(id.info); setLocalMode(!!id.local); setAuthStatus(id.status); + if (id.status === "authenticated") { + setCreateView(null); + setSkillCenter(false); + setAddAgent(false); + setAddMenu(false); + setSearchView(false); + setManageAgents(false); + setMyAgents(true); + } }) .catch((error) => { setAuthError(error instanceof Error ? error.message : String(error)); @@ -1492,7 +1505,7 @@ export default function App() { }, []); useEffect(() => { - if (!access || !uiConfigLoaded || defaultViewAppliedRef.current) return; + if (!access || !uiConfigLoaded || defaultViewAppliedRef.current || myAgents) return; defaultViewAppliedRef.current = true; if (defaultView === "addAgent" && access.capabilities.createAgents) { setCreateView(null); @@ -1502,7 +1515,7 @@ export default function App() { setAddAgent(false); setAddMenu(true); } - }, [access, defaultView, uiConfigLoaded]); + }, [access, defaultView, myAgents, uiConfigLoaded]); useEffect(() => { if (!access) return; @@ -1562,6 +1575,7 @@ export default function App() { setSearchView(false); setManageAgents(false); startNewChat(); + setMyAgents(true); setUserId(name); setUserInfo({ name }); setLocalMode(true); @@ -2634,16 +2648,68 @@ export default function App() { setConnections(loadConnections()); viewSidRef.current = ""; setSessionId(""); + setMyAgents(false); setAppName(id); }; - const talkToWorkspaceAgent = (id: string) => { + const openAgentCreateFromMyAgents = () => { + if (!canCreateAgents) { + setError("当前账号没有添加 Agent 的权限。"); + return; + } + setMyAgents(false); + setManageAgents(false); + setImportedDraft(null); + setCreateView(null); + setAddMenu(true); + setError(""); + }; + + const connectMyAgent = async (agent: MyAgentCardData) => { + if (!agent.runtime) return; + try { + const agentId = await connectRuntime( + agent.runtime.runtimeId, + agent.name, + agent.runtime.region, + agent.runtime.currentVersion, + ); + setConnections(loadConnections()); + setAgentDetailTarget(null); + setMyAgents(false); + setManageAgents(false); + startNewChat(); + setAppName(agentId); + } catch (cause) { + setError(cause instanceof Error ? cause.message : String(cause)); + } + }; + + const openMyAgentDetails = (agent: MyAgentCardData) => { + if (!agent.runtime) return; + setAgentDetailTarget(agent); + setFocusedWorkspaceAgentId(""); + setMyAgents(false); + setManageAgents(true); + setError(""); + }; + + const openMyAgentsPage = () => { + if (sandboxSession) exitSandboxSession(); + viewSidRef.current = ""; + setSessionId(""); setCreateView(null); setSkillCenter(false); setAddAgent(false); setAddMenu(false); setSearchView(false); setManageAgents(false); + setAgentDetailTarget(null); + setMyAgents(true); + setError(""); + }; + + const talkToWorkspaceAgent = (id: string) => { setFeedbackCaseReturnAgentId(""); setFeedbackTargetEventId(""); selectAgent(id); @@ -2656,6 +2722,18 @@ export default function App() { selectAgent(id); }; + const detailAgentEntry: AgentEntry | null = agentDetailTarget?.runtime + ? { + id: `detail:${agentDetailTarget.runtime.runtimeId}`, + label: agentDetailTarget.name, + app: agentDetailTarget.name, + remote: true, + runtimeId: agentDetailTarget.runtime.runtimeId, + region: agentDetailTarget.runtime.region, + currentVersion: agentDetailTarget.runtime.currentVersion, + } + : null; + return (
{ @@ -2681,6 +2761,8 @@ export default function App() { setAddAgent(false); setAddMenu(false); setManageAgents(false); + setAgentDetailTarget(null); + setMyAgents(false); setSearchView(true); setError(""); }} @@ -2697,6 +2779,8 @@ export default function App() { setAddAgent(false); setSearchView(false); setManageAgents(false); + setAgentDetailTarget(null); + setMyAgents(false); setCreateView(null); setImportedDraft(null); setAddMenu(true); @@ -2709,6 +2793,8 @@ export default function App() { setAddMenu(false); setSearchView(false); setManageAgents(false); + setAgentDetailTarget(null); + setMyAgents(false); setSkillCenter(true); setError(""); }} @@ -2723,24 +2809,14 @@ export default function App() { setSkillCenter(false); setSearchView(false); setManageAgents(false); + setAgentDetailTarget(null); + setMyAgents(false); setSessionId(""); setAddMenu(false); setAddAgent(true); setError(""); }} - onManageAgents={() => { - if (sandboxSession) exitSandboxSession(); - viewSidRef.current = ""; - setSessionId(""); - setCreateView(null); - setSkillCenter(false); - setAddAgent(false); - setAddMenu(false); - setSearchView(false); - setManageAgents(true); - setError(""); - void refreshAgentLibrary(); - }} + onMyAgents={openMyAgentsPage} onPickSession={(id) => { setCreateView(null); setSkillCenter(false); @@ -2748,6 +2824,8 @@ export default function App() { setAddMenu(false); setSearchView(false); setManageAgents(false); + setAgentDetailTarget(null); + setMyAgents(false); setError(""); pickSession(id); }} @@ -2869,11 +2947,7 @@ export default function App() { onRemoveAttachment={removeDraftAttachment} newChatMode={sandboxSession ? "agent" : newChatMode} newChatLayout={!sandboxSession && turns.length === 0 && skillJob === null} - showModeSelector={ - !sandboxSession && - turns.length === 0 && - skillJob === null - } + showModeSelector={false} temporaryEnabled={newChatCapabilities.temporaryEnabled} skillCreateEnabled={newChatCapabilities.skillCreateEnabled} onModeChange={(mode) => { @@ -2916,12 +2990,21 @@ export default function App() { localApps={apps} currentRuntime={currentRuntime} runtimeScope={access.capabilities.runtimeScope} + onBrowseAgents={openMyAgentsPage} title={ - showAddMenu + myAgents + ? "智能体" + : showAddMenu ? "添加 Agent" : showAddAgent ? "添加 AgentKit 智能体" - : undefined + : showManageAgents + ? agentDetailTarget + ? agentDetailTarget.name + : focusedWorkspaceAgentId + ? labelOf(focusedWorkspaceAgentId) + : "智能体详情" + : undefined } titleLeading={ turns.length > 0 && @@ -2932,6 +3015,7 @@ export default function App() { !skillCenter && !searchView && !showManageAgents && + !myAgents && visibleCreateView === null && appName ? (