feat(core): 增强 Plan Agent 支持细粒度 bash 权限和模式切换

- Plan Agent 细粒度 bash 权限:允许只读命令 (ls, grep, git log 等),
  禁止危险操作 (rm, mv, git commit 等)
- 新增 plan_mode_respond 工具:结构化输出计划、进度和探索状态
- Agent.switchMode() 方法:支持 Build ↔ Plan 模式切换保留对话历史
- WebSocket mode_switch 消息:支持运行时动态切换模式
- 更新 Plan Agent prompt 引导使用 plan_mode_respond 工具
This commit is contained in:
2025-12-15 20:51:57 +08:00
parent f238368f87
commit 35d87a04fb
8 changed files with 355 additions and 20 deletions
+6
View File
@@ -59,6 +59,9 @@ import {
undoTool,
} from './checkpoint/index.js';
// Plan 工具
import { planModeRespondTool } from './plan/index.js';
// 所有工具列表(用于注册)
const allToolsWithMetadata: ToolWithMetadata[] = [
// 核心工具 (deferLoading: false)
@@ -112,6 +115,9 @@ const allToolsWithMetadata: ToolWithMetadata[] = [
checkpointListTool,
checkpointDiffTool,
checkpointRestoreTool,
// Plan 工具 (deferLoading: true - 仅 Plan 模式)
planModeRespondTool,
];
// 注册所有工具到 registry
+7
View File
@@ -0,0 +1,7 @@
/**
* Plan 工具模块
*
* Plan 模式专用工具集合
*/
export { planModeRespondTool } from './plan_mode_respond.js';
@@ -0,0 +1,144 @@
/**
* Plan Mode Respond Tool
*
* Plan 模式专用响应工具,用于结构化输出计划和进度信息。
* 参考 OpenCode 的 plan_mode_respond 实现。
*
* 特性:
* - response: 输出计划内容
* - needs_more_exploration: 标记是否需要更多探索
* - task_progress: 报告任务进度 (0-100)
*/
import type { ToolWithMetadata } from '../types.js';
import type { ToolResult } from '../../types/index.js';
/**
* 生成进度条字符串
*/
function generateProgressBar(progress: number): string {
const total = 20;
const filled = Math.round((progress / 100) * total);
const empty = total - filled;
return '[' + '='.repeat(filled) + ' '.repeat(empty) + ']';
}
/**
* Plan Mode 响应工具
*/
export const planModeRespondTool: ToolWithMetadata = {
name: 'plan_mode_respond',
description: `Plan 模式专用响应工具。使用此工具输出结构化的计划和进度信息。
使用场景:
- 完成探索后输出实现计划
- 报告需要更多探索(设置 needs_more_exploration: true
- 更新任务进度
参数说明:
- response (必需): 计划内容、分析结果或回复
- needs_more_exploration (可选): 是否需要继续探索。设为 true 表示当前信息不足
- task_progress (可选): 任务完成进度 (0-100)。0=刚开始,50=进行中,100=完成
示例:
1. 输出初步分析:
plan_mode_respond({
response: "## 现状分析\\n代码结构如下...",
needs_more_exploration: true,
task_progress: 30
})
2. 输出最终计划:
plan_mode_respond({
response: "## 实现方案\\n### 步骤 1: ...",
needs_more_exploration: false,
task_progress: 100
})`,
metadata: {
name: 'plan_mode_respond',
category: 'agent',
description: 'Plan 模式结构化响应工具',
keywords: ['plan', 'respond', 'response', 'progress', '计划', '响应', '进度'],
deferLoading: true, // 仅在 Plan 模式下加载
},
parameters: {
response: {
type: 'string',
description: '计划内容、分析结果或回复',
required: true,
},
needs_more_exploration: {
type: 'boolean',
description: '是否需要更多探索。设为 true 表示当前信息不足,需要继续调研',
required: false,
},
task_progress: {
type: 'number',
description: '任务完成进度 (0-100)。0=刚开始,50=进行中,100=完成',
required: false,
},
},
async execute(params: Record<string, unknown>): Promise<ToolResult> {
const {
response,
needs_more_exploration = false,
task_progress,
} = params as {
response: string;
needs_more_exploration?: boolean;
task_progress?: number;
};
// 验证参数
if (!response || typeof response !== 'string') {
return {
success: false,
output: '',
error: 'response 参数是必需的,且必须是字符串',
};
}
if (task_progress !== undefined) {
if (typeof task_progress !== 'number' || task_progress < 0 || task_progress > 100) {
return {
success: false,
output: '',
error: 'task_progress 必须是 0-100 之间的数字',
};
}
}
// 构建结构化输出
const output: string[] = [];
// 添加进度信息
if (task_progress !== undefined) {
const progressBar = generateProgressBar(task_progress);
output.push(`[进度: ${task_progress}%] ${progressBar}`);
output.push('');
}
// 添加响应内容
output.push(response);
// 添加探索状态
if (needs_more_exploration) {
output.push('');
output.push('---');
output.push('[状态: 需要更多探索]');
}
return {
success: true,
output: output.join('\n'),
metadata: {
needs_more_exploration,
task_progress,
type: 'plan_response',
},
};
},
};