修复: B-22 前后端状态同步(ai_is_generating IPC+发送前查后端真值)
commands.rs 加 ai_is_generating IPC(读 session.generating)+lib.rs 注册;useAiSend sendMessage 预检先 invoke('ai_is_generating')查后端真值:后端 generating=true 时入队(撞 QUEUE_LIMIT 抛错)+本地 streaming=false 则复位 streaming=true 让用户感知,IPC 失败退化为 false 不阻断。消除前端 streaming 与后端 generating 不同步致预检放行撞拦截。批6 w8qbkxxvz,cargo+vue-tsc 0
This commit is contained in:
@@ -25,6 +25,18 @@ use super::AiChatEvent;
|
|||||||
// 发送 / 审批 / 控制
|
// 发送 / 审批 / 控制
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
|
/// 查询后端真实 generating 状态(B-260615-22:方案 A 发送前 IPC 查后端真值)
|
||||||
|
///
|
||||||
|
/// 前端 `state.streaming` 与后端 `AiSession.generating` 各自维护:
|
||||||
|
/// 后端 loop 异常退出 / AiError 已复位 generating=false 时,前端若仅查本地 streaming
|
||||||
|
/// 可能仍为 true(或反之),预检放行后撞后端 `ai_chat_send` 的 generating 拦截。
|
||||||
|
/// 发送前调此命令取后端真值,据之与本地 streaming 对齐,消除状态不同步。
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn ai_is_generating(state: State<'_, AppState>) -> Result<bool, String> {
|
||||||
|
let session = state.ai_session.lock().await;
|
||||||
|
Ok(session.generating)
|
||||||
|
}
|
||||||
|
|
||||||
/// 发送消息并获取流式 AI 响应
|
/// 发送消息并获取流式 AI 响应
|
||||||
///
|
///
|
||||||
/// 非阻塞:立即返回 "ok",通过 ai-chat-event 事件流式推送
|
/// 非阻塞:立即返回 "ok",通过 ai-chat-event 事件流式推送
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ pub fn run() {
|
|||||||
commands::ai::ai_approve,
|
commands::ai::ai_approve,
|
||||||
commands::ai::ai_pending_tool_calls,
|
commands::ai::ai_pending_tool_calls,
|
||||||
commands::ai::ai_chat_clear,
|
commands::ai::ai_chat_clear,
|
||||||
|
commands::ai::ai_is_generating,
|
||||||
commands::ai::ai_list_providers,
|
commands::ai::ai_list_providers,
|
||||||
commands::ai::ai_save_provider,
|
commands::ai::ai_save_provider,
|
||||||
commands::ai::ai_set_provider,
|
commands::ai::ai_set_provider,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
//! - sendMessage 调 useAiStream.resetStreamWatchdog
|
//! - sendMessage 调 useAiStream.resetStreamWatchdog
|
||||||
//! - drainQueue 在 sendMessage 完成后由 handleEvent(AiCompleted) 调用 — 故 drainQueue 必须为模块级 export
|
//! - drainQueue 在 sendMessage 完成后由 handleEvent(AiCompleted) 调用 — 故 drainQueue 必须为模块级 export
|
||||||
|
|
||||||
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
import { aiApi } from '../../api'
|
import { aiApi } from '../../api'
|
||||||
import { useAppSettingsStore } from '../../stores/appSettings'
|
import { useAppSettingsStore } from '../../stores/appSettings'
|
||||||
import { state } from '../../stores/ai'
|
import { state } from '../../stores/ai'
|
||||||
@@ -32,6 +33,32 @@ export function drainQueue() {
|
|||||||
async function sendMessage(text: string, skill?: string) {
|
async function sendMessage(text: string, skill?: string) {
|
||||||
if (!text.trim()) return
|
if (!text.trim()) return
|
||||||
|
|
||||||
|
// B-260615-22(方案 A):发送前 IPC 查后端真实 generating。
|
||||||
|
// 前端 state.streaming 与后端 AiSession.generating 各自维护:后端 loop 异常退出/
|
||||||
|
// AiError 已复位 generating=false 时,本地 streaming 可能仍为 false(状态不同步),
|
||||||
|
// 仅查本地预检会放行,随后撞 ai_chat_send:45 的 generating 拦截。此处对齐后端真值。
|
||||||
|
let backendGenerating = false
|
||||||
|
try {
|
||||||
|
backendGenerating = await invoke<boolean>('ai_is_generating')
|
||||||
|
} catch {
|
||||||
|
// IPC 失败不阻断发送:退化到仅靠本地 streaming 预检(原行为),让 ai_chat_send 兜底。
|
||||||
|
backendGenerating = false
|
||||||
|
}
|
||||||
|
if (backendGenerating) {
|
||||||
|
if (state.queue.length >= QUEUE_LIMIT) {
|
||||||
|
throw new Error(`待发送队列已满(最多 ${QUEUE_LIMIT} 条)`)
|
||||||
|
}
|
||||||
|
// 后端真在生成但本地 streaming 已复位(false):状态不同步——对齐本地 streaming=true
|
||||||
|
// 让用户感知(禁用输入框等),并入队等待 AiCompleted 续发;不入队则消息静默丢失。
|
||||||
|
if (!state.streaming) {
|
||||||
|
state.streaming = true
|
||||||
|
}
|
||||||
|
state.queue.push({ text: text.trim(), skill: skill || undefined })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 本地 streaming=true 但后端 generating=false(看门狗/AiError 已复位本地,或反向不同步):
|
||||||
|
// 后端可接收,本地直接进入发送(无需复位 streaming)。
|
||||||
// 生成中:进入待发送队列,当前对话完成后(AiCompleted)由 drainQueue 自动续发
|
// 生成中:进入待发送队列,当前对话完成后(AiCompleted)由 drainQueue 自动续发
|
||||||
if (state.streaming) {
|
if (state.streaming) {
|
||||||
if (state.queue.length >= QUEUE_LIMIT) {
|
if (state.queue.length >= QUEUE_LIMIT) {
|
||||||
|
|||||||
Reference in New Issue
Block a user