优化: aichat 体验收尾(useAiEvents拆分4子域 + AIC-FIX P1队列/mutex/缓存 + i18n残留抽取)
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
//! 工具事件域 — handleToolEvent
|
||||
//!
|
||||
//! 处理:AiToolCallStarted / AiToolCallCompleted / AiToolAutoApproved / AiApprovalRequired / AiApprovalResult。
|
||||
//! 依赖方向:本模块 → aiShared / useAiPendingState(叶子)/ useAiStream,不导入任何同级子 composable。
|
||||
|
||||
import { emit } from '@tauri-apps/api/event'
|
||||
import { state } from '@/stores/ai'
|
||||
import { t } from '@/i18n/i18n-helpers'
|
||||
import { findToolCall, clearApprovalTimer, startApprovalTimer, startToolSlowTimer, clearToolSlowTimer } from './aiShared'
|
||||
import { removePendingDirAuth } from './useAiPendingState'
|
||||
import { clearStreamWatchdog } from './useAiStream'
|
||||
import type { AiChatEvent, AiToolCallInfo } from '@/api/types'
|
||||
|
||||
/** tool 域:工具卡片状态流转/会话级信任/审批。返回 true=已处理。 */
|
||||
export function handleToolEvent(event: AiChatEvent): boolean {
|
||||
switch (event.type) {
|
||||
case 'AiToolCallStarted': {
|
||||
const info: AiToolCallInfo = {
|
||||
id: event.id,
|
||||
name: event.name,
|
||||
args: event.args,
|
||||
status: 'running',
|
||||
}
|
||||
// 同 id 重复 Started 不重复 push(provider id 不稳,防残留 running 空卡)
|
||||
if (!findToolCall(event.id)) {
|
||||
const lastMsg = state.messages[state.messages.length - 1]
|
||||
if (lastMsg && lastMsg.role === 'assistant') {
|
||||
lastMsg.toolCalls = lastMsg.toolCalls || []
|
||||
lastMsg.toolCalls.push(info)
|
||||
}
|
||||
}
|
||||
// 工具开始执行即挂慢执行计时器(超时仅 toast,不动 running 态)
|
||||
startToolSlowTimer(event.id, event.name)
|
||||
return true
|
||||
}
|
||||
|
||||
case 'AiToolCallCompleted': {
|
||||
const tc = findToolCall(event.id)
|
||||
if (tc) {
|
||||
tc.status = 'completed'
|
||||
tc.result = event.result
|
||||
}
|
||||
state.completedTools++ // 进度条计数器
|
||||
state.pendingApprovals = state.pendingApprovals.filter(p => p.id !== event.id)
|
||||
clearToolSlowTimer(event.id)
|
||||
// 工具结束(无论审批通过后执行还是被拒),清审批超时计时器
|
||||
clearApprovalTimer(event.id)
|
||||
return true
|
||||
}
|
||||
|
||||
case 'AiToolAutoApproved': {
|
||||
// 会话级信任:经事件总线桥接弹本地 toast(composable 无组件上下文)
|
||||
void emit('ai-tool-auto-approved-toast', { tool: event.tool, dir: event.dir })
|
||||
return true
|
||||
}
|
||||
|
||||
case 'AiApprovalRequired': {
|
||||
clearStreamWatchdog(event.conversation_id || undefined) // 等用户审批,不计整流超时
|
||||
const info: AiToolCallInfo = {
|
||||
id: event.id,
|
||||
name: event.name,
|
||||
args: event.args,
|
||||
status: 'pending_approval',
|
||||
kind: event.kind ?? 'risk',
|
||||
// reason 必须写入 info,否则浮窗 ApprovalPopup 的 tc.reason 永远空(审批说明丢失)
|
||||
reason: event.reason,
|
||||
conversationId: event.conversation_id ?? state.activeConversationId ?? undefined,
|
||||
}
|
||||
state.pendingApprovals.push(info)
|
||||
const tc = findToolCall(event.id)
|
||||
if (tc) {
|
||||
tc.status = 'pending_approval'
|
||||
tc.reason = event.reason
|
||||
// write_file 审批注入行级 diff(旧文件 vs 新内容),前端审批卡预览
|
||||
if (event.diff) tc.diff = event.diff
|
||||
}
|
||||
// 进入审批等待 → 取消该工具慢执行计时器(审批耗时由用户主导,非执行慢),再启动审批超时计时器
|
||||
clearToolSlowTimer(event.id)
|
||||
startApprovalTimer(event.id, event.name, 'risk')
|
||||
// 通知 ToolCardList 展开折叠组 + scroll(pending 卡落折叠分组不可见时)
|
||||
void emit('ai-pending-arrived', { toolCallId: event.id })
|
||||
return true
|
||||
}
|
||||
|
||||
case 'AiApprovalResult': {
|
||||
if (!event.approved) {
|
||||
const tc = findToolCall(event.id)
|
||||
if (tc) {
|
||||
tc.status = 'rejected'
|
||||
tc.result = t('ai.aiTool.rejectedHint')
|
||||
}
|
||||
state.pendingApprovals = state.pendingApprovals.filter(p => p.id !== event.id)
|
||||
clearToolSlowTimer(event.id)
|
||||
clearApprovalTimer(event.id)
|
||||
} else {
|
||||
// 审批通过 → 工具重回执行态,重启慢执行计时器;对称清审批超时计时器防到点误拒
|
||||
startToolSlowTimer(event.id, findToolCall(event.id)?.name || '')
|
||||
clearApprovalTimer(event.id)
|
||||
}
|
||||
// 路径授权挂起的工具收到 ApprovalResult → 按 id 移除该条(数组化后只清这一条)
|
||||
removePendingDirAuth(event.id)
|
||||
return true
|
||||
}
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user