From bfe3bc63b3627051d5652c69e7424babfb26733d Mon Sep 17 00:00:00 2001 From: kurihada Date: Thu, 11 Dec 2025 13:19:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20/agent=20=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E6=94=AF=E6=8C=81=E4=BA=A4=E4=BA=92=E5=BC=8F=E5=88=87?= =?UTF-8?q?=E6=8D=A2=20Agent=20=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 AgentRegistry 添加 listPrimaryAgents() 方法 - 在 Agent 类添加 setAgentMode/getAgentMode 方法 - 在 TerminalUI 实现 /agent 命令: - /agent 显示当前模式和可用列表 - /agent 切换到指定 Agent - /agent default 切换回默认模式 - 提示符显示当前 Agent 模式(如 @plan You >) - 为 build Agent 添加 prompt 配置 --- src/agent/presets/build.ts | 14 ++++++ src/agent/registry.ts | 7 +++ src/core/agent.ts | 34 +++++++++++++++ src/ui/terminal.ts | 87 +++++++++++++++++++++++++++++++++----- 4 files changed, 131 insertions(+), 11 deletions(-) diff --git a/src/agent/presets/build.ts b/src/agent/presets/build.ts index 776b485..8cb5c69 100644 --- a/src/agent/presets/build.ts +++ b/src/agent/presets/build.ts @@ -7,5 +7,19 @@ import type { AgentInfo } from '../types.js'; export const buildAgent: Omit = { description: '构建模式,拥有完整权限执行编码任务', mode: 'primary', + prompt: `你是一个高效的软件工程师。你的任务是直接执行编码任务。 + +工作原则: +1. 先理解需求,必要时阅读相关代码 +2. 直接执行修改,不要等待确认 +3. 修改完成后进行测试验证 +4. 保持代码质量,遵循项目规范 + +你拥有完整的文件系统和 bash 权限,可以: +- 创建、修改、删除文件 +- 执行 bash 命令(构建、测试等) +- 使用 git 进行版本控制 + +始终保持专注和高效,直接解决问题。`, maxSteps: 30, }; diff --git a/src/agent/registry.ts b/src/agent/registry.ts index c355c8c..96947e0 100644 --- a/src/agent/registry.ts +++ b/src/agent/registry.ts @@ -66,6 +66,13 @@ export class AgentRegistry { return this.list().filter((a) => a.mode !== 'primary'); } + /** + * 列出可作为主交互 Agent 的 Agent(供 /agent 命令使用) + */ + listPrimaryAgents(): AgentInfo[] { + return this.list().filter((a) => a.mode !== 'subagent'); + } + /** * 动态注册 Agent(运行时) */ diff --git a/src/core/agent.ts b/src/core/agent.ts index 8527d16..bc98088 100644 --- a/src/core/agent.ts +++ b/src/core/agent.ts @@ -17,6 +17,7 @@ import { type TokenUsage, type CompressionConfig, } from '../context/index.js'; +import type { AgentInfo } from '../agent/types.js'; // Provider 工厂函数类型 type ProviderFactory = (apiKey: string) => (model: string) => LanguageModel; @@ -53,6 +54,9 @@ export class Agent { // 压缩管理器 private compressionManager: CompressionManager; + // 当前 Agent 模式(null 表示默认模式) + private currentAgentMode: AgentInfo | null = null; + constructor(config: AgentConfig, compressionConfig?: Partial) { this.config = config; @@ -354,4 +358,34 @@ export class Agent { type: result.type, }; } + + /** + * 切换 Agent 模式 + */ + setAgentMode(agent: AgentInfo | null): void { + this.currentAgentMode = agent; + + // 如果切换了 Agent,更新 system prompt + if (agent?.prompt) { + // 追加 Agent 的 prompt 到系统 prompt + this.config = { + ...this.config, + systemPrompt: agent.prompt, + }; + } + } + + /** + * 获取当前 Agent 模式 + */ + getAgentMode(): AgentInfo | null { + return this.currentAgentMode; + } + + /** + * 获取当前 Agent 名称 + */ + getAgentModeName(): string { + return this.currentAgentMode?.name ?? 'default'; + } } diff --git a/src/ui/terminal.ts b/src/ui/terminal.ts index d303c88..be9dd4a 100644 --- a/src/ui/terminal.ts +++ b/src/ui/terminal.ts @@ -1,6 +1,7 @@ import * as readline from 'readline'; import chalk from 'chalk'; import type { Agent } from '../core/agent.js'; +import { agentRegistry } from '../agent/index.js'; export class TerminalUI { private agent: Agent; @@ -28,11 +29,12 @@ export class TerminalUI { console.log(chalk.cyan('║') + chalk.gray(' Powered by DeepSeek / Claude ') + chalk.cyan('║')); console.log(chalk.cyan('╚════════════════════════════════════════╝\n')); console.log(chalk.gray('输入你的问题,或使用以下命令:')); - console.log(chalk.yellow(' /help') + chalk.gray(' - 显示帮助')); - console.log(chalk.yellow(' /clear') + chalk.gray(' - 清空对话历史')); - console.log(chalk.yellow(' /compact') + chalk.gray(' - 压缩对话历史')); - console.log(chalk.yellow(' /context') + chalk.gray(' - 查看上下文使用情况')); - console.log(chalk.yellow(' /exit') + chalk.gray(' - 退出程序')); + console.log(chalk.yellow(' /help') + chalk.gray(' - 显示帮助')); + console.log(chalk.yellow(' /agent') + chalk.gray(' - 切换 Agent 模式')); + console.log(chalk.yellow(' /clear') + chalk.gray(' - 清空对话历史')); + console.log(chalk.yellow(' /compact') + chalk.gray(' - 压缩对话历史')); + console.log(chalk.yellow(' /context') + chalk.gray(' - 查看上下文使用情况')); + console.log(chalk.yellow(' /exit') + chalk.gray(' - 退出程序')); console.log(''); } @@ -56,10 +58,70 @@ export class TerminalUI { return colorFn(`[${used}/${limit}]`); } + // 处理 /agent 命令 + private handleAgentCommand(args: string): boolean { + const agentName = args.trim(); + + // 无参数:显示当前模式和可用 Agent + if (!agentName) { + const currentMode = this.agent.getAgentModeName(); + const availableAgents = agentRegistry.listPrimaryAgents(); + + console.log(chalk.cyan('\n🤖 Agent 模式:')); + console.log(chalk.white(` 当前: ${currentMode === 'default' ? chalk.green('default (通用助手)') : chalk.yellow(currentMode)}`)); + console.log(''); + console.log(chalk.white(' 可用 Agent:')); + console.log(chalk.gray(' • default - 通用编程助手')); + for (const agent of availableAgents) { + const marker = agent.name === currentMode ? chalk.green(' ✓') : ''; + console.log(chalk.gray(` • ${agent.name} - ${agent.description}${marker}`)); + } + console.log(''); + console.log(chalk.gray(' 用法: /agent 切换到指定 Agent')); + console.log(chalk.gray(' /agent default 切换回默认模式')); + console.log(''); + return true; + } + + // 切换到默认模式 + if (agentName === 'default') { + this.agent.setAgentMode(null); + console.log(chalk.green('\n✓ 已切换到 default (通用助手) 模式\n')); + return true; + } + + // 切换到指定 Agent + const agent = agentRegistry.get(agentName); + if (!agent) { + const availableNames = ['default', ...agentRegistry.listPrimaryAgents().map(a => a.name)]; + console.log(chalk.red(`\n✗ 未找到 Agent: ${agentName}`)); + console.log(chalk.gray(` 可用: ${availableNames.join(', ')}\n`)); + return true; + } + + // 检查是否为 subagent 模式(不能作为主交互 Agent) + if (agent.mode === 'subagent') { + console.log(chalk.yellow(`\n⚠ Agent "${agentName}" 是 subagent 模式,只能通过 task 工具调用`)); + console.log(chalk.gray(' 提示: 使用 /agent 查看可交互的 Agent 列表\n')); + return true; + } + + this.agent.setAgentMode(agent); + console.log(chalk.green(`\n✓ 已切换到 ${agent.name} 模式`)); + console.log(chalk.gray(` ${agent.description}\n`)); + return true; + } + // 处理特殊命令 private async handleCommand(input: string): Promise { const command = input.toLowerCase().trim(); + // 检查 /agent 命令(带参数) + if (command.startsWith('/agent')) { + const args = input.substring(6).trim(); + return this.handleAgentCommand(args); + } + switch (command) { case '/help': console.log(chalk.cyan('\n📖 帮助信息:')); @@ -70,11 +132,12 @@ export class TerminalUI { console.log(chalk.gray(' • 回答编程问题')); console.log(''); console.log(chalk.white(' 命令:')); - console.log(chalk.gray(' • /help - 显示此帮助')); - console.log(chalk.gray(' • /clear - 清空对话历史')); - console.log(chalk.gray(' • /compact - 压缩对话历史,释放上下文空间')); - console.log(chalk.gray(' • /context - 显示当前上下文使用情况')); - console.log(chalk.gray(' • /exit - 退出程序')); + console.log(chalk.gray(' • /help - 显示此帮助')); + console.log(chalk.gray(' • /agent - 切换 Agent 模式')); + console.log(chalk.gray(' • /clear - 清空对话历史')); + console.log(chalk.gray(' • /compact - 压缩对话历史,释放上下文空间')); + console.log(chalk.gray(' • /context - 显示当前上下文使用情况')); + console.log(chalk.gray(' • /exit - 退出程序')); console.log(''); return true; @@ -136,7 +199,9 @@ export class TerminalUI { // 显示带上下文使用情况的提示符 const contextInfo = this.formatContextUsage(); - this.rl.question(`${contextInfo} ${chalk.green('You >')} `, (answer) => { + const agentMode = this.agent.getAgentModeName(); + const agentIndicator = agentMode === 'default' ? '' : chalk.magenta(`@${agentMode} `); + this.rl.question(`${contextInfo} ${agentIndicator}${chalk.green('You >')} `, (answer) => { resolve(answer ?? ''); }); });