diff --git a/src/renderer/components/chat-area.ts b/src/renderer/components/chat-area.ts index 0db8429..f356f1c 100644 --- a/src/renderer/components/chat-area.ts +++ b/src/renderer/components/chat-area.ts @@ -136,6 +136,8 @@ export function renderMessages(): void { for (let i = 0; i < msgs.length; i++) { const msg = msgs[i]; + // 跳过 system 消息(Plan Mode 进度等内部状态消息不展示给用户) + if (msg.role === 'system') continue; // 只跳过既无内容也无 think 也无工具的空消息 if (msg.role === 'assistant' && !msg.content && !msg.think && (!msg.toolCalls || msg.toolCalls.length === 0)) continue; appendMessageDOM(msgs[i], i); diff --git a/src/renderer/components/input-area.ts b/src/renderer/components/input-area.ts index 9c38998..c8b3d3f 100644 --- a/src/renderer/components/input-area.ts +++ b/src/renderer/components/input-area.ts @@ -634,16 +634,8 @@ async function handleRetry(): Promise { // renderMessages 统一渲染 session 数据,先清掉流式 placeholder 避免 DOM 重复 clearMessagesDOM(); renderMessages(); - // ── 保存 Plan Mode 最终进度到会话(供下一轮 Loop 注入)── - const lastPlanStatus = state.get('_lastPlanStatus', ''); - if (lastPlanStatus) { - state.set('_lastPlanStatus', ''); - state.update(KEYS.CURRENT_SESSION, (s: any) => ({ - ...s, - messages: [...s.messages, { role: 'system', content: lastPlanStatus, timestamp: Date.now() }], - updatedAt: Date.now() - })); - } + // ── 消费 _lastPlanStatus(不再保存为 session 消息,避免 system 消息渲染到聊天界面)── + state.set('_lastPlanStatus', ''); await saveCurrentSession(); } }); @@ -1352,16 +1344,8 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio renderMessages(); - // ── 保存 Plan Mode 最终进度到会话(供下一轮 Loop 注入)── - const lastPlanStatus2 = state.get('_lastPlanStatus', ''); - if (lastPlanStatus2) { - state.set('_lastPlanStatus', ''); - state.update(KEYS.CURRENT_SESSION, (session: any) => ({ - ...session, - messages: [...session.messages, { role: 'system', content: lastPlanStatus2, timestamp: Date.now() }], - updatedAt: Date.now() - })); - } + // ── 消费 _lastPlanStatus(不再保存为 session 消息,避免 system 消息渲染到聊天界面)── + state.set('_lastPlanStatus', ''); await saveCurrentSession(); } }); diff --git a/src/renderer/services/agent-engine.ts b/src/renderer/services/agent-engine.ts index 0e42fab..51742ef 100644 --- a/src/renderer/services/agent-engine.ts +++ b/src/renderer/services/agent-engine.ts @@ -2035,6 +2035,30 @@ async function handleReflecting( return; } + // ── 异常3: 模型说了要做但没调用工具 → 注入提醒再给一次机会 ── + // 场景:AI 回复"我来写入文件"但未发出 write_file 工具调用 + if (ctx.toolCalls.length === 0 && ctx.content.trim() && ctx.loopCount <= 3) { + const text = ctx.content.toLowerCase(); + const actionHints: Array<{ pattern: RegExp; tool: string; hint: string }> = [ + { pattern: /写入|写文件|写入文件|保存.*文件|创建.*文件|生成.*文件|输出.*文件|write.*file/i, tool: 'write_file', hint: '你提到了写入/创建文件,但没有调用 write_file 工具。请直接调用 write_file 工具执行写入操作。' }, + { pattern: /搜索|查找|搜一下|查一下|检索|search/i, tool: 'web_search', hint: '你提到了搜索,但没有调用 web_search 工具。请直接调用 web_search 工具执行搜索。' }, + { pattern: /抓取|获取.*内容|fetch|获取.*网页/i, tool: 'web_fetch', hint: '你提到了抓取网页,但没有调用 web_fetch 工具。请直接调用 web_fetch 工具获取网页内容。' }, + { pattern: /运行.*命令|执行.*命令|run.*command/i, tool: 'run_command', hint: '你提到了运行命令,但没有调用 run_command 工具。请直接调用 run_command 工具执行命令。' }, + { pattern: /下载/i, tool: 'download_file', hint: '你提到了下载,但没有调用 download_file 工具。请直接调用 download_file 工具执行下载。' }, + ]; + const matched = actionHints.find(h => h.pattern.test(text) && !ctx.allToolRecords.some(r => r.name === h.tool)); + if (matched) { + logWarn(`Reflecting: 检测到"说了做但没做" → ${matched.tool},注入提醒`); + ctx.messages.push({ + role: 'user', + content: matched.hint, + ephemeral: true, + }); + transition(ctx, S.THINKING); + return; + } + } + // ── 本轮调用了工具 → 模型需要处理工具结果 → 继续循环 ── if (ctx.toolCalls.length > 0) { transition(ctx, S.THINKING);