优化: 会话状态 per-conv 化与交互守卫
- 待审批跨会话 per-conv 合并,审批类事件全局放行 - 看门狗/重试计数/流式残段按会话键控迁移 - 输入草稿与子代理完成卡数据按会话隔离 - 切换兜底 activeId,收敛守卫防幽灵气泡 - 发送错误按限流/额度/网络分类文案
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
//! 流式事件域 — handleStreamingEvent
|
||||
//!
|
||||
//! 处理:AiTextDelta / AiAgentRound / AiHeartbeat / AiStreamRetry / AiMaxRoundsReached / AiDirAuthRequired。
|
||||
//! 处理:AiTextDelta / AiAgentRound / AiHeartbeat / AiStreamRetry / AiDirAuthRequired。
|
||||
//! AiMaxRoundsReached 不处理:后端达 max 已改 AiCompleted(incomplete=true) 自动完成(暂停态
|
||||
//! 语义已废),该事件后端零 emit;pendingMaxRounds/MaxRoundsCard 续停操作卡为遗留死链待清理。
|
||||
//! 依赖方向:本模块 → aiShared / useAiPendingState(叶子)/ useAiStream,不导入任何同级子 composable。
|
||||
//! _lastDelta 去重 Map 与 flushCurrentText 因跨域共用已下沉 aiShared,这里仅经 accessor 读写。
|
||||
|
||||
@@ -8,8 +10,8 @@ import { emit } from '@tauri-apps/api/event'
|
||||
import { useAppSettingsStore } from '@/stores/appSettings'
|
||||
import { state } from '@/stores/ai'
|
||||
import { t } from '@/i18n/i18n-helpers'
|
||||
import { nextMsgId, findToolCall, startApprovalTimer, clearToolSlowTimer, getLastDelta, setLastDelta, flushCurrentText } from './aiShared'
|
||||
import { resetTextIdleTimer, clearTextIdleTimer, pendingMaxRounds, pendingDirAuths, pushPendingDirAuth } from './useAiPendingState'
|
||||
import { nextMsgId, findToolCall, startApprovalTimer, clearToolSlowTimer, getLastDelta, setLastDelta, flushCurrentText, addPendingApproval } from './aiShared'
|
||||
import { resetTextIdleTimer, clearTextIdleTimer, pendingDirAuths, pushPendingDirAuth } from './useAiPendingState'
|
||||
import { clearStreamWatchdog } from './useAiStream'
|
||||
import type { AiChatEvent, AiMessage, MessageId } from '@/api/types'
|
||||
|
||||
@@ -21,7 +23,7 @@ function isUnifiedApproval(): boolean {
|
||||
return appSettings.get<boolean>('df-ai-unified-approval', true)
|
||||
}
|
||||
|
||||
/** streaming 域:流式文本累积/新轮/心跳/重试/max 轮暂停。返回 true=已处理。 */
|
||||
/** streaming 域:流式文本累积/新轮/心跳/重试。返回 true=已处理。 */
|
||||
export function handleStreamingEvent(event: AiChatEvent): boolean {
|
||||
switch (event.type) {
|
||||
case 'AiTextDelta': {
|
||||
@@ -84,33 +86,25 @@ export function handleStreamingEvent(event: AiChatEvent): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
case 'AiMaxRoundsReached': {
|
||||
// 达 max 暂停态(后端仍 generating=true):看门狗不计整流超时(clear),挂起 convId 驱动操作卡。
|
||||
// 无 convId 时保留原值兜底(达 max 事件理论上必带 convId,缺失默认当前活跃会话)。
|
||||
clearStreamWatchdog(event.conversation_id || undefined)
|
||||
pendingMaxRounds.value = event.conversation_id || state.activeConversationId || pendingMaxRounds.value
|
||||
return true
|
||||
}
|
||||
|
||||
case 'AiDirAuthRequired': {
|
||||
// 路径授权挂起(后端 generating 保持 true,等用户决策):看门狗跳过 reset,由本 case clear。
|
||||
clearStreamWatchdog(event.conversation_id || undefined)
|
||||
clearToolSlowTimer(event.id)
|
||||
// 统一审批模型开:path 挂起归一进 pendingApprovals(kind='path'),ToolCard 内联审批。
|
||||
// 同 id 幂等(provider id 不稳或重发时不重复 push 防残留卡)。
|
||||
// 统一审批模型开:path 挂起归一进待审批集合(kind='path'),ToolCard 内联审批。
|
||||
// per-conv 归会话追加(同 id 幂等):跨会话事件互不覆盖;首次到达才做工具卡改写等一次性副作用。
|
||||
if (isUnifiedApproval()) {
|
||||
if (!state.pendingApprovals.some(p => p.id === event.id)) {
|
||||
state.pendingApprovals.push({
|
||||
id: event.id,
|
||||
name: event.tool,
|
||||
args: { path: event.path },
|
||||
status: 'pending_approval',
|
||||
kind: 'path',
|
||||
dir: event.dir,
|
||||
path: event.path,
|
||||
conversationId: event.conversation_id ?? state.activeConversationId ?? undefined,
|
||||
reason: t('aiChat.dirAuthHint', { tool: event.tool, path: event.path }),
|
||||
})
|
||||
const added = addPendingApproval({
|
||||
id: event.id,
|
||||
name: event.tool,
|
||||
args: { path: event.path },
|
||||
status: 'pending_approval',
|
||||
kind: 'path',
|
||||
dir: event.dir,
|
||||
path: event.path,
|
||||
conversationId: event.conversation_id ?? state.activeConversationId ?? undefined,
|
||||
reason: t('aiChat.dirAuthHint', { tool: event.tool, path: event.path }),
|
||||
})
|
||||
if (added) {
|
||||
// 同步改对应工具卡的 tc,让 ToolCard 显 path 类审批按钮(once/always/deny)
|
||||
const tc = findToolCall(event.id)
|
||||
if (tc) {
|
||||
|
||||
Reference in New Issue
Block a user