From c307cd3a7cceca9d507bcc0825811c3b8a6493cf Mon Sep 17 00:00:00 2001 From: kurihada Date: Sun, 14 Dec 2025 22:12:36 +0800 Subject: [PATCH] =?UTF-8?q?refactor(agent):=20=E5=B0=86=20Summary=20Model?= =?UTF-8?q?=20=E6=94=B9=E9=80=A0=E4=B8=BA=E5=86=85=E7=BD=AE=20Sub=20Agent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 扩展 AgentMode 类型添加 'internal' 模式 - 新增 summary agent preset (claude-3-5-haiku) - AgentRegistry 添加 getInternal/listInternalAgents 方法 - CompressionManager 添加 setSummaryModelFromAgentConfig - Agent 构造函数改用 Registry 配置初始化 Summary 模型 - 清理旧的 SummaryConfig 配置系统 - UI AgentsPanel 分离显示 System/Preset/Custom agents - UI AgentEditor 为 internal agent 显示简化编辑界面 --- packages/core/src/agent/presets/index.ts | 4 +- packages/core/src/agent/presets/summary.ts | 20 ++ packages/core/src/agent/registry.ts | 24 +- packages/core/src/agent/types.ts | 3 +- packages/core/src/context/manager.ts | 28 ++ packages/core/src/core/agent.ts | 43 ++- packages/core/src/index.ts | 4 +- packages/core/src/utils/config.ts | 64 ---- .../tests/unit/agent/presets/index.test.ts | 8 +- packages/core/tests/unit/core/agent.test.ts | 1 + packages/server/src/agent/adapter.ts | 79 ----- packages/server/src/agent/index.ts | 4 - packages/server/src/index.ts | 3 - packages/server/src/routes/config.ts | 72 ----- packages/ui/src/api/client.ts | 30 +- packages/ui/src/api/types.ts | 25 +- packages/ui/src/components/AgentEditor.tsx | 284 ++++++++++-------- packages/ui/src/components/AgentsPanel.tsx | 74 +++-- packages/ui/src/components/ConfigPanel.tsx | 155 +--------- packages/ui/src/index.ts | 8 +- 20 files changed, 339 insertions(+), 594 deletions(-) create mode 100644 packages/core/src/agent/presets/summary.ts diff --git a/packages/core/src/agent/presets/index.ts b/packages/core/src/agent/presets/index.ts index 7208a9c..b9aa1f4 100644 --- a/packages/core/src/agent/presets/index.ts +++ b/packages/core/src/agent/presets/index.ts @@ -5,6 +5,7 @@ import { codeReviewerAgent } from './code-reviewer.js'; import { buildAgent } from './build.js'; import { planAgent } from './plan.js'; import { visionAgent } from './vision.js'; +import { summaryAgent } from './summary.js'; /** * 预设 Agent 集合 @@ -16,6 +17,7 @@ export const presetAgents: Record> = { build: buildAgent, plan: planAgent, vision: visionAgent, + summary: summaryAgent, }; /** @@ -32,4 +34,4 @@ export function isPresetAgent(name: string): boolean { return name in presetAgents; } -export { generalAgent, exploreAgent, codeReviewerAgent, buildAgent, planAgent, visionAgent }; +export { generalAgent, exploreAgent, codeReviewerAgent, buildAgent, planAgent, visionAgent, summaryAgent }; diff --git a/packages/core/src/agent/presets/summary.ts b/packages/core/src/agent/presets/summary.ts new file mode 100644 index 0000000..c6c8718 --- /dev/null +++ b/packages/core/src/agent/presets/summary.ts @@ -0,0 +1,20 @@ +import type { AgentInfo } from '../types.js'; + +/** + * Summary Agent + * 内部 Agent,用于对话压缩时生成摘要 + * 推荐使用成本较低的模型 + */ +export const summaryAgent: Omit = { + description: '对话压缩摘要生成(内部使用)', + mode: 'internal', + model: { + provider: 'anthropic', + model: 'claude-3-5-haiku-20241022', + }, + tools: { + enabled: [], // 无工具,纯文本生成 + noTask: true, + }, + maxSteps: 1, +}; diff --git a/packages/core/src/agent/registry.ts b/packages/core/src/agent/registry.ts index 96947e0..3ed5488 100644 --- a/packages/core/src/agent/registry.ts +++ b/packages/core/src/agent/registry.ts @@ -61,16 +61,36 @@ export class AgentRegistry { /** * 列出可作为子 Agent 的 Agent(供 Task 工具使用) + * 排除 primary 和 internal 模式 */ listSubagents(): AgentInfo[] { - return this.list().filter((a) => a.mode !== 'primary'); + return this.list().filter((a) => a.mode !== 'primary' && a.mode !== 'internal'); } /** * 列出可作为主交互 Agent 的 Agent(供 /agent 命令使用) + * 排除 internal 模式 */ listPrimaryAgents(): AgentInfo[] { - return this.list().filter((a) => a.mode !== 'subagent'); + return this.list().filter((a) => a.mode !== 'subagent' && a.mode !== 'internal'); + } + + /** + * 获取内部 Agent(internal 模式) + */ + getInternal(name: string): AgentInfo | undefined { + const agent = this.get(name); + if (agent?.mode === 'internal') { + return agent; + } + return undefined; + } + + /** + * 列出所有内部 Agent + */ + listInternalAgents(): AgentInfo[] { + return this.list().filter((a) => a.mode === 'internal'); } /** diff --git a/packages/core/src/agent/types.ts b/packages/core/src/agent/types.ts index a9f1267..e36b569 100644 --- a/packages/core/src/agent/types.ts +++ b/packages/core/src/agent/types.ts @@ -9,8 +9,9 @@ export type { PermissionAction, PermissionRule }; * - primary: 主 Agent,用户直接使用 * - subagent: 子 Agent,由 Task 工具调用 * - all: 两种方式都可以 + * - internal: 内部使用,不对外暴露(如 Summary Agent) */ -export type AgentMode = 'primary' | 'subagent' | 'all'; +export type AgentMode = 'primary' | 'subagent' | 'all' | 'internal'; /** * Agent Bash 权限配置 diff --git a/packages/core/src/context/manager.ts b/packages/core/src/context/manager.ts index 6f26de7..ab5157b 100644 --- a/packages/core/src/context/manager.ts +++ b/packages/core/src/context/manager.ts @@ -9,6 +9,8 @@ import { CompressionStatus, DEFAULT_COMPRESSION_CONFIG, } from './types.js'; +import type { AgentModelConfig } from '../agent/types.js'; +import { getProviderRegistry } from '../provider/index.js'; /** * 压缩管理器 @@ -41,6 +43,32 @@ export class CompressionManager { this.summaryModel = model; } + /** + * 从 Agent 配置设置摘要模型 + * @param config Agent 的模型配置 + * @param apiKey API Key + * @param baseUrl 可选的 Base URL + */ + setSummaryModelFromAgentConfig( + config: AgentModelConfig, + apiKey: string, + baseUrl?: string + ): void { + const registry = getProviderRegistry(); + const provider = config.provider || 'anthropic'; + const modelName = config.model || 'claude-3-5-haiku-20241022'; + + try { + const getModel = registry.getModelFactory(provider, { + apiKey, + baseUrl, + }); + this.summaryModel = getModel(modelName); + } catch (error) { + console.warn('[CompressionManager] Failed to create summary model:', error); + } + } + /** * 获取用于摘要生成的模型 * 优先使用专用摘要模型,无则使用主模型 diff --git a/packages/core/src/core/agent.ts b/packages/core/src/core/agent.ts index cf1d83e..5564449 100644 --- a/packages/core/src/core/agent.ts +++ b/packages/core/src/core/agent.ts @@ -18,8 +18,8 @@ import { } from '../context/index.js'; import type { AgentInfo, ImageData } from '../agent/types.js'; import { agentRegistry, AgentExecutor } from '../agent/index.js'; -import { loadVisionConfig, loadSummaryConfig } from '../utils/config.js'; -import { getProviderRegistry } from '../provider/index.js'; +import { loadVisionConfig } from '../utils/config.js'; +import { getProviderRegistry, resolveApiKey } from '../provider/index.js'; import { getHookManager } from '../hooks/index.js'; import { getGitManager } from '../git/index.js'; @@ -62,15 +62,38 @@ export class Agent { // 设置主模型(作为摘要模型的后备) this.compressionManager.setModel(this.getModel(config.model)); - // 加载摘要模型配置(可选,用于降低压缩成本) - const summaryConfig = loadSummaryConfig(); - if (summaryConfig) { - const summaryModelFactory = providerRegistry.getModelFactory(summaryConfig.provider, { - apiKey: summaryConfig.apiKey, - baseUrl: summaryConfig.baseUrl, - }); - this.compressionManager.setSummaryModel(summaryModelFactory(summaryConfig.model)); + // 从 Agent Registry 加载 Summary Agent 配置 + this.initSummaryModel(config, providerRegistry); + } + + /** + * 从 Agent Registry 初始化 Summary 模型 + */ + private initSummaryModel( + config: AgentConfig, + providerRegistry: ReturnType + ): void { + // 获取 Summary Agent(internal 模式) + const summaryAgentInfo = agentRegistry.getInternal('summary'); + if (!summaryAgentInfo?.model) { + return; } + + const modelConfig = summaryAgentInfo.model; + // 确定 provider(默认使用主配置的 provider) + const provider = modelConfig.provider || config.provider; + + // 从 ProviderRegistry 获取 API Key + const providerConfig = providerRegistry.getConfig(provider); + const apiKey = resolveApiKey(providerConfig) || config.apiKey; + + if (!apiKey) { + return; + } + + // 设置 Summary 模型 + const baseUrl = providerConfig?.baseUrl; + this.compressionManager.setSummaryModelFromAgentConfig(modelConfig, apiKey, baseUrl); } /** diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index feb98f0..5852784 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,7 +1,7 @@ export { Agent } from './core/agent.js'; export { toolRegistry, todoManager, initTaskContext, updateTaskDescription, updateSkillDescription } from './tools/index.js'; -export { loadConfig, saveConfig, getConfig, loadVisionConfig, loadSummaryConfig } from './utils/config.js'; -export type { VisionConfig, SummaryConfig } from './utils/config.js'; +export { loadConfig, saveConfig, getConfig, loadVisionConfig } from './utils/config.js'; +export type { VisionConfig } from './utils/config.js'; // Context compression export { diff --git a/packages/core/src/utils/config.ts b/packages/core/src/utils/config.ts index d2c0e3e..4125523 100644 --- a/packages/core/src/utils/config.ts +++ b/packages/core/src/utils/config.ts @@ -19,11 +19,6 @@ interface StoredConfig { visionModel?: string; /** Vision 专用的 Base URL(用于 OpenAI 兼容的 Vision 服务) */ visionBaseUrl?: string; - // Summary 配置(用于对话压缩摘要生成) - summaryProvider?: ProviderType; - summaryModel?: string; - /** Summary 专用的 Base URL(用于 OpenAI 兼容的 Summary 服务) */ - summaryBaseUrl?: string; } // Vision 配置接口 @@ -35,15 +30,6 @@ export interface VisionConfig { baseUrl?: string; } -// Summary 配置接口(用于对话压缩摘要生成) -export interface SummaryConfig { - provider: ProviderType; - apiKey: string; - model: string; - /** 自定义 Base URL(用于 OpenAI 兼容的 Summary 服务) */ - baseUrl?: string; -} - // 默认模型配置 const DEFAULT_MODELS: Record = { anthropic: 'claude-sonnet-4-20250514', @@ -58,13 +44,6 @@ const DEFAULT_VISION_MODELS: Record = { openai: 'gpt-4o', }; -// 默认 Summary 模型(推荐使用成本较低的模型) -const DEFAULT_SUMMARY_MODELS: Record = { - anthropic: 'claude-3-5-haiku-20241022', - deepseek: 'deepseek-chat', - openai: 'gpt-4o-mini', -}; - // 默认系统提示词 const DEFAULT_SYSTEM_PROMPT = `你是一个运行在终端中的 AI 编程助手。你可以帮助用户: - 读取和写入文件 @@ -167,49 +146,6 @@ export function loadVisionConfig(): VisionConfig | null { }; } -/** - * 加载 Summary 配置 - * Summary 用于对话压缩时生成摘要,推荐使用成本较低的小模型 - * 通过 ProviderRegistry 获取 API Key - */ -export function loadSummaryConfig(): SummaryConfig | null { - // 从配置文件读取 - const storedConfig = getConfig(); - - // 如果没有任何 summary 相关配置,返回 null(使用主模型) - const hasSummaryConfig = storedConfig.summaryProvider || storedConfig.summaryModel; - - if (!hasSummaryConfig) { - return null; - } - - // 确定 summary provider(默认使用主配置的 provider) - const mainProvider = storedConfig.provider || 'anthropic'; - const finalProvider = storedConfig.summaryProvider || mainProvider; - - // 通过 ProviderRegistry 获取 API Key - const providerConfig = providerRegistry.getConfig(finalProvider); - const finalApiKey = resolveApiKey(providerConfig); - - // 如果没有 API Key,返回 null - if (!finalApiKey) { - return null; - } - - // 确定模型 - const finalModel = storedConfig.summaryModel || DEFAULT_SUMMARY_MODELS[finalProvider]; - - // 确定 baseUrl - const finalBaseUrl = storedConfig.summaryBaseUrl || providerConfig?.baseUrl; - - return { - provider: finalProvider, - apiKey: finalApiKey, - model: finalModel, - baseUrl: finalBaseUrl, - }; -} - // 保存配置 export function saveConfig(config: Partial): void { // 确保目录存在 diff --git a/packages/core/tests/unit/agent/presets/index.test.ts b/packages/core/tests/unit/agent/presets/index.test.ts index c446a99..ca062c1 100644 --- a/packages/core/tests/unit/agent/presets/index.test.ts +++ b/packages/core/tests/unit/agent/presets/index.test.ts @@ -14,7 +14,7 @@ import { describe('Agent Presets - 预设 Agent', () => { describe('presetAgents 集合', () => { it('包含所有预设 Agent', () => { - expect(Object.keys(presetAgents)).toHaveLength(6); + expect(Object.keys(presetAgents)).toHaveLength(7); // includes summary agent }); it('包含 general Agent', () => { @@ -67,7 +67,7 @@ describe('Agent Presets - 预设 Agent', () => { it('返回正确数量', () => { const names = getPresetAgentNames(); - expect(names).toHaveLength(6); + expect(names).toHaveLength(7); // general, explore, code-review, frontend, backend, vision, summary }); }); @@ -192,9 +192,9 @@ describe('Agent Presets - 预设 Agent', () => { }); }); - it('mode 值是 subagent 或 primary', () => { + it('mode 值是有效的 AgentMode', () => { Object.entries(presetAgents).forEach(([name, agent]) => { - expect(['subagent', 'primary'], `${name} mode 无效`).toContain(agent.mode); + expect(['subagent', 'primary', 'all', 'internal'], `${name} mode 无效`).toContain(agent.mode); }); }); }); diff --git a/packages/core/tests/unit/core/agent.test.ts b/packages/core/tests/unit/core/agent.test.ts index 2334ef4..77a3444 100644 --- a/packages/core/tests/unit/core/agent.test.ts +++ b/packages/core/tests/unit/core/agent.test.ts @@ -38,6 +38,7 @@ vi.mock('ai', () => ({ vi.mock('../../../src/agent/index.js', () => ({ agentRegistry: { get: vi.fn(), + getInternal: vi.fn(() => null), // Returns null by default - no summary agent configured }, AgentExecutor: vi.fn().mockImplementation(() => ({ execute: vi.fn().mockResolvedValue({ diff --git a/packages/server/src/agent/adapter.ts b/packages/server/src/agent/adapter.ts index 7ff6d1b..5565cd9 100644 --- a/packages/server/src/agent/adapter.ts +++ b/packages/server/src/agent/adapter.ts @@ -76,16 +76,6 @@ interface PermissionManager { setAskCallback(callback: (ctx: unknown) => Promise<{ allow: boolean; remember?: boolean }>): void; } -/** - * Summary 配置接口 - */ -export interface SummaryConfig { - provider: string; - apiKey: string; - model: string; - baseUrl?: string; -} - /** * Core 模块接口 */ @@ -94,7 +84,6 @@ interface CoreModule { toolRegistry: ToolRegistry; loadConfig: () => unknown; saveConfig: (config: Record) => void; - loadSummaryConfig: () => SummaryConfig | null; getPermissionManager: (projectRoot?: string) => PermissionManager; } @@ -443,71 +432,3 @@ export async function compressContext( } } -// ============================================================================ -// 摘要配置 API -// ============================================================================ - -/** - * 摘要配置(不含 API Key 明文) - */ -export interface SummaryConfigInfo { - provider?: string; - model?: string; - hasApiKey: boolean; - baseUrl?: string; -} - -/** - * 获取摘要配置 - */ -export function getSummaryConfig(): SummaryConfigInfo | null { - if (!coreModule) { - return null; - } - - const config = coreModule.loadSummaryConfig(); - if (!config) { - return { - hasApiKey: false, - }; - } - - return { - provider: config.provider, - model: config.model, - hasApiKey: !!config.apiKey, - baseUrl: config.baseUrl, - }; -} - -/** - * 更新摘要配置 - */ -export function updateSummaryConfig(config: { - provider?: string; - model?: string; - apiKey?: string; - baseUrl?: string; -}): boolean { - if (!coreModule) { - return false; - } - - // 构建要保存的配置 - const saveData: Record = {}; - if (config.provider !== undefined) { - saveData.summaryProvider = config.provider; - } - if (config.model !== undefined) { - saveData.summaryModel = config.model; - } - if (config.apiKey !== undefined) { - saveData.summaryApiKey = config.apiKey; - } - if (config.baseUrl !== undefined) { - saveData.summaryBaseUrl = config.baseUrl; - } - - coreModule.saveConfig(saveData); - return true; -} diff --git a/packages/server/src/agent/index.ts b/packages/server/src/agent/index.ts index 60ae1d1..3a80e7e 100644 --- a/packages/server/src/agent/index.ts +++ b/packages/server/src/agent/index.ts @@ -15,12 +15,8 @@ export { // 上下文压缩相关 getContextUsage, compressContext, - getSummaryConfig, - updateSummaryConfig, // 类型导出 type TokenUsage, type CompressionResult, type ContextUsageInfo, - type SummaryConfigInfo, - type SummaryConfig, } from './adapter.js'; diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index b6677d6..ab61210 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -258,12 +258,9 @@ export { cancelProcessing, getContextUsage, compressContext, - getSummaryConfig, - updateSummaryConfig, type TokenUsage, type CompressionResult, type ContextUsageInfo, - type SummaryConfigInfo, } from './agent/index.js'; export { initAuth, diff --git a/packages/server/src/routes/config.ts b/packages/server/src/routes/config.ts index b7a7c32..91dcba3 100644 --- a/packages/server/src/routes/config.ts +++ b/packages/server/src/routes/config.ts @@ -5,11 +5,6 @@ */ import { Hono } from 'hono'; -import { - getSummaryConfig, - updateSummaryConfig, - type SummaryConfigInfo, -} from '../agent/adapter.js'; export const configRouter = new Hono(); @@ -102,70 +97,3 @@ export function getConfig(): ServerConfig { export function setConfig(config: Partial): void { serverConfig = { ...serverConfig, ...config }; } - -// ============================================================================ -// 摘要配置 API -// ============================================================================ - -/** - * GET /config/summary - 获取摘要模型配置 - */ -configRouter.get('/summary', (c) => { - const config = getSummaryConfig(); - - if (!config) { - // Core 模块不可用 - return c.json({ - success: true, - data: { - hasApiKey: false, - } as SummaryConfigInfo, - }); - } - - return c.json({ - success: true, - data: config, - }); -}); - -/** - * PUT /config/summary - 更新摘要模型配置 - */ -configRouter.put('/summary', async (c) => { - try { - const body = await c.req.json(); - - const success = updateSummaryConfig({ - provider: body.provider, - model: body.model, - apiKey: body.apiKey, - baseUrl: body.baseUrl, - }); - - if (!success) { - return c.json( - { - success: false, - error: 'Core module not available', - }, - 500 - ); - } - - // 返回更新后的配置(不含 API Key) - const config = getSummaryConfig(); - return c.json({ - success: true, - data: config, - }); - } catch (error) { - return c.json( - { - success: false, - error: error instanceof Error ? error.message : 'Invalid input', - }, - 400 - ); - } -}); diff --git a/packages/ui/src/api/client.ts b/packages/ui/src/api/client.ts index 2375507..5c776c1 100644 --- a/packages/ui/src/api/client.ts +++ b/packages/ui/src/api/client.ts @@ -45,11 +45,9 @@ import type { CustomProviderDefinition, ProviderConfig, ConnectionTestResult, - // Context & Summary types + // Context types ContextUsageInfo, CompressionResult, - SummaryConfigInfo, - SummaryConfigInput, } from './types.js'; // Re-export types @@ -124,8 +122,6 @@ export type { CompressionStatus, CompressionType, CompressionResult, - SummaryConfigInfo, - SummaryConfigInput, } from './types.js'; // API Configuration @@ -976,27 +972,3 @@ export async function compressContext( }> { return request('POST', `/sessions/${encodeURIComponent(sessionId)}/compress`, options || {}); } - -/** - * 获取摘要模型配置 - */ -export async function getSummaryConfig(): Promise<{ - success: boolean; - data?: SummaryConfigInfo; - error?: string; -}> { - return request('GET', '/config/summary'); -} - -/** - * 更新摘要模型配置 - */ -export async function updateSummaryConfig( - config: SummaryConfigInput -): Promise<{ - success: boolean; - data?: SummaryConfigInfo; - error?: string; -}> { - return request('PUT', '/config/summary', config); -} diff --git a/packages/ui/src/api/types.ts b/packages/ui/src/api/types.ts index d163e13..553bff6 100644 --- a/packages/ui/src/api/types.ts +++ b/packages/ui/src/api/types.ts @@ -280,7 +280,7 @@ export interface HookTestResult { // ============ Agent 相关 ============ /** Agent 运行模式 */ -export type AgentMode = 'primary' | 'subagent' | 'all'; +export type AgentMode = 'primary' | 'subagent' | 'all' | 'internal'; /** Agent 模型配置 */ export interface AgentModelConfig { @@ -756,26 +756,3 @@ export interface CompressionResult { summaryTokens?: number; } -/** 摘要模型配置信息(不含 API Key 明文) */ -export interface SummaryConfigInfo { - /** 提供商类型 */ - provider?: string; - /** 模型名称 */ - model?: string; - /** 是否已配置 API Key */ - hasApiKey: boolean; - /** 服务地址 */ - baseUrl?: string; -} - -/** 摘要模型配置输入 */ -export interface SummaryConfigInput { - /** 提供商类型 */ - provider?: string; - /** 模型名称 */ - model?: string; - /** API Key */ - apiKey?: string; - /** 服务地址 */ - baseUrl?: string; -} diff --git a/packages/ui/src/components/AgentEditor.tsx b/packages/ui/src/components/AgentEditor.tsx index fc75793..02cd98f 100644 --- a/packages/ui/src/components/AgentEditor.tsx +++ b/packages/ui/src/components/AgentEditor.tsx @@ -12,6 +12,7 @@ import { ChevronDown, ChevronRight, AlertCircle, + Lock, } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; import { toast } from 'sonner'; @@ -93,6 +94,9 @@ export function AgentEditor({ const [name, setName] = useState(defaultName); const [description, setDescription] = useState(''); const [mode, setMode] = useState('primary'); + + // 是否为内部 Agent(Internal Agent 只能编辑模型配置) + const isInternalAgent = mode === 'internal'; const [prompt, setPrompt] = useState(''); const [maxSteps, setMaxSteps] = useState(undefined); @@ -298,12 +302,26 @@ export function AgentEditor({ )}

- + {isInternalAgent ? ( + + ) : ( + + )} {isNewAgent ? 'Create Agent' : `Edit: ${agentName}`} + {isInternalAgent && ( + + System + + )}

{copyFrom && (

Copying from: {copyFrom}

)} + {isInternalAgent && ( +

+ System agents can only modify model configuration +

+ )}
- {/* Mode */} -
- -
- {(['primary', 'subagent', 'all'] as const).map((m) => ( - - ))} + {/* Mode - 不为内部 Agent 显示 */} + {!isInternalAgent && ( +
+ +
+ {(['primary', 'subagent', 'all'] as const).map((m) => ( + + ))} +
+

+ {mode === 'primary' + ? 'Can be used as the main agent' + : mode === 'subagent' + ? 'Can only be spawned by other agents' + : 'Can be used in both modes'} +

-

- {mode === 'primary' - ? 'Can be used as the main agent' - : mode === 'subagent' - ? 'Can only be spawned by other agents' - : 'Can be used in both modes'} -

-
+ )} + + {/* Internal Mode 显示只读标签 */} + {isInternalAgent && ( +
+ +
+ + Internal (System Agent) +
+

+ System agents are used internally and cannot be called directly +

+
+ )}
- {/* System Prompt */} - -
-