修复: 审批按钮永久转圈和等待计数不停

根因:审批 IPC 成功返回后,前端等待后端事件(AiApprovalResult/
AiToolCallCompleted)来更新工具卡片状态和复位 loading。但如果
后端事件因时序问题未及时到达,或 findToolCall 找不到工具卡片,
loading 永不复位,按钮一直转圈,等待计数也不停。

修复:审批 IPC 成功返回后立即乐观更新状态:
- 通过/批准:工具卡片改为执行中(后端正在执行工具)
- 拒绝:工具卡片改为已拒绝
- 同时从待审批列表移除(不等后端事件来移)

后端事件仍会到达作为二次确认(幂等覆盖,无副作用)。
This commit is contained in:
2026-06-29 12:59:45 +08:00
parent 7a2a2e13a2
commit 63936e3016

View File

@@ -70,6 +70,19 @@ async function approveToolCall(toolCallId: string, approved: boolean, decision?:
} else { } else {
await aiApi.approve(toolCallId, approved) 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) { } catch (e) {
// IPC 未送达:用户已点过按钮,清看门狗(避免 130s 后误触发假错误)再回滚到失败态 // IPC 未送达:用户已点过按钮,清看门狗(避免 130s 后误触发假错误)再回滚到失败态
// TD-260621-03 per-conv:清审批 tc 所属会话的 timer(与上方 reset 同 conv,对称成对)。 // TD-260621-03 per-conv:清审批 tc 所属会话的 timer(与上方 reset 同 conv,对称成对)。