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
+30 -1
View File
@@ -6,7 +6,7 @@
import type { WSContext } from 'hono/ws';
import { getSessionManager } from './session/manager.js';
import { processMessage, cancelProcessing } from './agent/index.js';
import { processMessage, cancelProcessing, getOrCreateAgent } from './agent/index.js';
import { handlePermissionResponse, setSessionAutoApprove } from './permission/handler.js';
import type { ClientMessage, ServerMessage } from './types.js';
@@ -172,6 +172,35 @@ export async function handleWebSocketMessage(
break;
}
case 'mode_switch': {
// 动态模式切换(Build ↔ Plan
const mode = message.payload?.agentMode as 'build' | 'plan' | undefined;
if (mode === 'build' || mode === 'plan') {
try {
const agent = await getOrCreateAgent(sessionId);
if (agent && typeof agent.switchMode === 'function') {
agent.switchMode(mode, true); // 保留对话历史
broadcastToSession(sessionId, {
type: 'mode_switched',
sessionId,
payload: { mode },
});
console.log(`[WS] Mode switched for session ${sessionId}: ${mode}`);
} else {
console.warn(`[WS] Agent does not support switchMode for session ${sessionId}`);
}
} catch (error) {
console.error(`[WS] Failed to switch mode for session ${sessionId}:`, error);
broadcastToSession(sessionId, {
type: 'error',
sessionId,
payload: { message: 'Failed to switch mode' },
});
}
}
break;
}
default:
ws.send(
JSON.stringify({