From 63936e30163b5b16bb793bd3e35c9311cb050142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9D=E5=B0=98?= <237809796@qq.com> Date: Mon, 29 Jun 2026 12:59:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D:=20=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E6=B0=B8=E4=B9=85=E8=BD=AC=E5=9C=88=E5=92=8C?= =?UTF-8?q?=E7=AD=89=E5=BE=85=E8=AE=A1=E6=95=B0=E4=B8=8D=E5=81=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:审批 IPC 成功返回后,前端等待后端事件(AiApprovalResult/ AiToolCallCompleted)来更新工具卡片状态和复位 loading。但如果 后端事件因时序问题未及时到达,或 findToolCall 找不到工具卡片, loading 永不复位,按钮一直转圈,等待计数也不停。 修复:审批 IPC 成功返回后立即乐观更新状态: - 通过/批准:工具卡片改为执行中(后端正在执行工具) - 拒绝:工具卡片改为已拒绝 - 同时从待审批列表移除(不等后端事件来移) 后端事件仍会到达作为二次确认(幂等覆盖,无副作用)。 --- src/composables/ai/useAiApproval.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/composables/ai/useAiApproval.ts b/src/composables/ai/useAiApproval.ts index 8e50b2a..bd984ae 100644 --- a/src/composables/ai/useAiApproval.ts +++ b/src/composables/ai/useAiApproval.ts @@ -70,6 +70,19 @@ async function approveToolCall(toolCallId: string, approved: boolean, decision?: } else { await aiApi.approve(toolCallId, approved) } + // IPC 成功返回 = 后端已处理(执行工具/拒绝/写入白名单 + emit 事件 + try_continue)。 + // 乐观更新 tc.status,不依赖后端事件来复位 loading(后端事件可能在 IPC 返回前后任意时刻到达, + // 且 findToolCall 若因时序找不到 tc 会致 loading 永不复位)。 + // approve/authorize 通过 → running(后端正在执行工具);deny/reject → rejected(后端已记审计)。 + if (tc) { + const isDeny = isPathKind ? (decision === 'deny') : !approved + tc.status = isDeny ? 'rejected' : 'running' + if (isDeny) { + tc.result = t('ai.aiTool.rejectedHint') + } + } + // 同步从 pendingApprovals 移除(不等后端 AiApprovalResult 事件来移,防 loading 卡死) + state.pendingApprovals = state.pendingApprovals.filter(p => p.id !== toolCallId) } catch (e) { // IPC 未送达:用户已点过按钮,清看门狗(避免 130s 后误触发假错误)再回滚到失败态 // TD-260621-03 per-conv:清审批 tc 所属会话的 timer(与上方 reset 同 conv,对称成对)。