重构: F-09 batch4 启用多会话上线(决策e真并发·F-09完整)
- IPC签名加conv_id: ai_is_generating/ai_chat_send/ai_chat_force_send/ai_chat_stop + 内部移除active一致性校验(后台conv可操作) - 删switch readonly分支 + 删ai_conversation_create强制结束旧loop(决策e,切走旧loop不退出) - 删双写桥接+顶层字段: messages/generating/stop_flag/notify/iteration_used/agent_language/model_override/session_trust全删,per_conv唯一真相源 + 删双写代码(全模块)+ 删fallback读 + pending_approvals retain目标conv - 前端: api/ai.ts+useAiSend/useAiWindow传conv_id 保留: session_state(SW预留标allow)/readonly(前端不读);零调用方预留按用户指导保留 主代兜底: cargo check --workspace 0 + vue-tsc 0 + test 98 + grep顶层删除/per_conv唯一印证 F-09完整(batch1 PerConvState+batch2迁移+batch5限流调整+batch8恢复+batch4上线);双会话人工验收留用户
This commit is contained in:
@@ -10,24 +10,28 @@ export const aiApi = {
|
||||
* F-260614-05 Phase 2c: parts 透传给后端 ai_chat_send → user_parts → provider vision 端点。
|
||||
* parts 为空/undefined → 后端走 user() 纯文本(向后兼容)。
|
||||
*/
|
||||
sendMessage(message: string, language?: string, skill?: string, modelOverride?: string | null, parts?: ContentPart[]): Promise<string> {
|
||||
sendMessage(message: string, language?: string, skill?: string, modelOverride?: string | null, parts?: ContentPart[], conversationId?: string | null): Promise<string> {
|
||||
return invoke('ai_chat_send', {
|
||||
message,
|
||||
language: language || 'zh-CN',
|
||||
skill: skill || null,
|
||||
modelOverride: modelOverride || null,
|
||||
parts: parts && parts.length > 0 ? parts : null,
|
||||
// F-260616-09 B 批4(决策 e):传 conv_id,操作指定 conv 的 per_conv(不依赖 active 单值)。
|
||||
conversationId: conversationId || null,
|
||||
})
|
||||
},
|
||||
|
||||
/** 强制发送(B-260616-02: 复位 generating 残留后走 send 同款流程);parts 透传同 sendMessage。 */
|
||||
forceSend(message: string, language?: string, skill?: string, modelOverride?: string | null, parts?: ContentPart[]): Promise<string> {
|
||||
forceSend(message: string, language?: string, skill?: string, modelOverride?: string | null, parts?: ContentPart[], conversationId?: string | null): Promise<string> {
|
||||
return invoke('ai_chat_force_send', {
|
||||
message,
|
||||
language: language || 'zh-CN',
|
||||
skill: skill || null,
|
||||
modelOverride: modelOverride || null,
|
||||
parts: parts && parts.length > 0 ? parts : null,
|
||||
// F-260616-09 B 批4(决策 e):传 conv_id,强制复位+发送仅作用于目标 conv。
|
||||
conversationId: conversationId || null,
|
||||
})
|
||||
},
|
||||
|
||||
@@ -91,9 +95,21 @@ export const aiApi = {
|
||||
return invoke('ai_chat_clear')
|
||||
},
|
||||
|
||||
/** 停止当前生成 */
|
||||
stopChat(): Promise<void> {
|
||||
return invoke('ai_chat_stop')
|
||||
/**
|
||||
* 停止当前生成。
|
||||
* F-260616-09 B 批4(决策 e):传 convId,停止仅作用于目标 conv(不杀其他后台 conv 的 loop)。
|
||||
* convId 省略时后端 fallback active conv。
|
||||
*/
|
||||
stopChat(convId?: string | null): Promise<void> {
|
||||
return invoke('ai_chat_stop', { conversationId: convId || null })
|
||||
},
|
||||
|
||||
/**
|
||||
* 查询后端真实 generating 状态(B-260615-22:发送前 IPC 查后端真值)。
|
||||
* F-260616-09 B 批4(决策 e):传 convId 精确查指定 conv;省略时后端 fallback active conv。
|
||||
*/
|
||||
isGenerating(convId?: string | null): Promise<boolean> {
|
||||
return invoke('ai_is_generating', { conversationId: convId || null })
|
||||
},
|
||||
|
||||
// ── F-15 阶段2: 手动上下文管理(清空 / 压缩) ──
|
||||
|
||||
@@ -121,9 +121,10 @@ async function doSend(text: string, skill?: string, force = false, parts?: Conte
|
||||
const override = modelOverride.value
|
||||
if (force) {
|
||||
// F-05 Phase 2c: 透传 parts(图片)给后端 ai_chat_force_send,多模态全链生效
|
||||
await aiApi.forceSend(text.trim(), lang, skill, override, parts)
|
||||
// F-260616-09 B 批4(决策 e):传 activeConversationId,操作指定 conv 的 per_conv。
|
||||
await aiApi.forceSend(text.trim(), lang, skill, override, parts, state.activeConversationId)
|
||||
} else {
|
||||
await aiApi.sendMessage(text.trim(), lang, skill, override, parts)
|
||||
await aiApi.sendMessage(text.trim(), lang, skill, override, parts, state.activeConversationId)
|
||||
}
|
||||
} catch (e) {
|
||||
// IPC 失败(spawn 前/provider 配置错等):回滚 streaming 防光标卡死 + 移除 user 消息与空气泡占位;
|
||||
@@ -310,9 +311,10 @@ async function sendMessage(text: string, skill?: string, forceMode = false, part
|
||||
}
|
||||
|
||||
// B-260615-22(方案 A):发送前 IPC 查后端真实 generating。
|
||||
// F-260616-09 B 批4(决策 e):传 activeConversationId 精确查当前 conv(不读全局单值)。
|
||||
let backendGenerating = false
|
||||
try {
|
||||
backendGenerating = await invoke<boolean>('ai_is_generating')
|
||||
backendGenerating = await invoke<boolean>('ai_is_generating', { conversationId: state.activeConversationId || null })
|
||||
} catch {
|
||||
backendGenerating = false
|
||||
}
|
||||
@@ -495,7 +497,8 @@ async function stopChat() {
|
||||
// 后端 agentic.rs:190 emit AiCompleted 注释明确「保证前端收事件时后端已可接下一条,队列续发不被拒」;
|
||||
// 当前未完成回复已入库(agentic.rs:185 save_conversation)保留为截断回复。
|
||||
try {
|
||||
await aiApi.stopChat()
|
||||
// F-260616-09 B 批4(决策 e):传 activeConversationId,停止仅作用于当前 conv。
|
||||
await aiApi.stopChat(state.activeConversationId)
|
||||
} catch (e) {
|
||||
// stop 信号未送达后端:重启看门狗(后端继续生成时活跃事件会重置它,真 hang 则 130s 后兜底收尾),
|
||||
// 避免后端仍在跑却无任何恢复路径(原 clearStreamWatchdog 已把兜底关掉)。
|
||||
|
||||
@@ -116,9 +116,10 @@ export async function restoreGeneratingState(opts?: { fromMainPanel?: boolean })
|
||||
const gen = fromMainPanel ? state.activeConversationId : localStorage.getItem('df-ai-gen')
|
||||
if (!gen) return false
|
||||
// 核对后端 ai_is_generating 真值
|
||||
// F-260616-09 B 批4(决策 e):传 gen(目标 conv)精确查,不读全局单值。
|
||||
let backendGenerating = false
|
||||
try {
|
||||
backendGenerating = await invoke<boolean>('ai_is_generating')
|
||||
backendGenerating = await invoke<boolean>('ai_is_generating', { conversationId: gen })
|
||||
} catch (e) {
|
||||
console.error('[AI] restoreGeneratingState: 核对 ai_is_generating 失败,跳过重建生成态', e)
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user