From 1902e478c997aa0e809588ad036ed7b05047f174 Mon Sep 17 00:00:00 2001 From: hopingmiao <3085273707@qq.com> Date: Thu, 30 Jul 2026 19:53:13 +0800 Subject: [PATCH] feat(settings): configure subagent prompt templates --- crates/agent-gateway/web/src/i18n/config.ts | 6 + .../web/src/lib/settings/index.ts | 5 + .../settings/AgentPromptTemplateModal.tsx | 4 +- .../web/src/pages/settings/AgentsSection.tsx | 134 +++++++++++++++++- .../src/commands/config/settings/agents.rs | 18 ++- .../src/commands/config/settings/db.rs | 31 ++++ .../src/commands/config/settings/mod.rs | 6 +- .../src/commands/config/settings/tests.rs | 114 ++++++++++++++- crates/agent-gui/src/i18n/config.ts | 6 + crates/agent-gui/src/lib/settings/index.ts | 5 + .../agent-gui/src/lib/subagents/agentTool.ts | 6 +- crates/agent-gui/src/lib/subagents/errors.ts | 2 +- crates/agent-gui/src/lib/subagents/roster.ts | 2 +- .../agent-gui/src/lib/subagents/validate.ts | 2 +- .../chat/turns/runAgentConversationTurn.ts | 10 +- .../settings/AgentPromptTemplateModal.tsx | 4 +- .../src/pages/settings/AgentsSection.tsx | 134 +++++++++++++++++- .../agent-turn-cancelled-history.test.mjs | 55 ++++++- .../test/settings/normalization.test.mjs | 60 ++++++-- .../test/subagents/agent-tool.test.mjs | 2 +- .../test/subagents/bus-roster.test.mjs | 5 +- .../test/subagents/validate.test.mjs | 2 +- .../builtin-registry-subagent-mcp.test.mjs | 2 +- 23 files changed, 578 insertions(+), 37 deletions(-) diff --git a/crates/agent-gateway/web/src/i18n/config.ts b/crates/agent-gateway/web/src/i18n/config.ts index 665ded047..4e8a51d53 100644 --- a/crates/agent-gateway/web/src/i18n/config.ts +++ b/crates/agent-gateway/web/src/i18n/config.ts @@ -1601,6 +1601,9 @@ export const translations: Record> = { "settings.agentsShowPrompt": "查看 Prompt", "settings.agentsReady": "可以保存", "settings.agentsRequired": "名称和 Prompt 为必填项", + "settings.agentsSubagentTemplates": "子代理模板", + "settings.agentsSubagentTemplatesHint": + "选择可供子代理按需引用的模板,可同时选择多个;不会改变主代理当前激活的模板。", /* ── Settings SSH ── */ "settings.sshTitle": "SSH", @@ -3839,6 +3842,9 @@ export const translations: Record> = { "settings.agentsShowPrompt": "View Prompt", "settings.agentsReady": "Ready to save", "settings.agentsRequired": "Name and Prompt are required", + "settings.agentsSubagentTemplates": "Subagent Templates", + "settings.agentsSubagentTemplatesHint": + "Choose templates that subagents may reference. Multiple templates can be selected without changing the active main-agent template.", /* ── Settings SSH ── */ "settings.sshTitle": "SSH", diff --git a/crates/agent-gateway/web/src/lib/settings/index.ts b/crates/agent-gateway/web/src/lib/settings/index.ts index 7f3fbeafd..9fb144d34 100644 --- a/crates/agent-gateway/web/src/lib/settings/index.ts +++ b/crates/agent-gateway/web/src/lib/settings/index.ts @@ -245,6 +245,7 @@ export type AgentPromptTemplate = { description: string; prompt: string; enabled: boolean; + availableToSubagents: boolean; }; export type SshAuthType = "password" | "privateKey" | "keyboardInteractive"; @@ -1501,6 +1502,10 @@ export function normalizeAgentPromptTemplate(input: unknown): AgentPromptTemplat description: normalizeOptionalText(obj.description), prompt: normalizeOptionalText(obj.prompt), enabled: obj.enabled === true, + availableToSubagents: + typeof obj.availableToSubagents === "boolean" + ? obj.availableToSubagents + : obj.enabled === true, }; } diff --git a/crates/agent-gateway/web/src/pages/settings/AgentPromptTemplateModal.tsx b/crates/agent-gateway/web/src/pages/settings/AgentPromptTemplateModal.tsx index 9768844b9..9b26dd583 100644 --- a/crates/agent-gateway/web/src/pages/settings/AgentPromptTemplateModal.tsx +++ b/crates/agent-gateway/web/src/pages/settings/AgentPromptTemplateModal.tsx @@ -10,9 +10,11 @@ import { useLocale } from "../../i18n"; import type { AgentPromptTemplate } from "../../lib/settings"; import { useModalMotion } from "../../lib/shared/modalMotion"; +type AgentPromptTemplateContent = Pick; + type AgentPromptTemplateModalProps = { initialData?: AgentPromptTemplate; - onSave: (data: Omit) => void; + onSave: (data: AgentPromptTemplateContent) => void; onClose: () => void; }; diff --git a/crates/agent-gateway/web/src/pages/settings/AgentsSection.tsx b/crates/agent-gateway/web/src/pages/settings/AgentsSection.tsx index 49767647c..950e1ca93 100644 --- a/crates/agent-gateway/web/src/pages/settings/AgentsSection.tsx +++ b/crates/agent-gateway/web/src/pages/settings/AgentsSection.tsx @@ -1,6 +1,18 @@ +import { Popover } from "@base-ui/react"; import { useState } from "react"; import { createPortal } from "react-dom"; -import { BookOpen, Eye, FileText, Pencil, Plus, Trash2, X } from "../../components/icons"; +import { + BookOpen, + Bot, + Check, + ChevronDown, + Eye, + FileText, + Pencil, + Plus, + Trash2, + X, +} from "../../components/icons"; import { Button } from "../../components/ui/button"; import { useLocale } from "../../i18n"; @@ -33,7 +45,7 @@ export function AgentsSection(props: SettingsSectionProps) { setEditingTemplate(null); } - function handleSave(data: Omit) { + function handleSave(data: Pick) { setSettings((prev) => { if (editingTemplate) { return updateAgents( @@ -48,6 +60,7 @@ export function AgentsSection(props: SettingsSectionProps) { id: createUuid(), ...data, enabled: false, + availableToSubagents: false, }; return updateAgents(prev, [...prev.agents, newTemplate]); }); @@ -76,8 +89,24 @@ export function AgentsSection(props: SettingsSectionProps) { ); } + function handleToggleAvailableToSubagents(id: string) { + setSettings((prev) => + updateAgents( + prev, + prev.agents.map((template) => + template.id === id + ? { ...template, availableToSubagents: !template.availableToSubagents } + : template, + ), + ), + ); + } + const templates = settings.agents; const enabledCount = templates.filter((template) => template.enabled).length; + const subagentTemplateCount = templates.filter( + (template) => template.availableToSubagents, + ).length; return ( <> @@ -112,6 +141,13 @@ export function AgentsSection(props: SettingsSectionProps) { ) : null} ) : null} + {templates.length > 0 ? ( + + ) : null}