新增: Phase3 EventBus Value载荷+桥接层

- EventBus 载荷改 serde_json::Value(D2 全19变体透传),删 AiBusEvent 强类型子集
- 新增 publish_event(AiChatEvent) helper(内部 to_value→publish,供 emit 双写)
- 新增 remote_bridge.rs 桥接层(MiniCommand→Tauri command 路由+R1 同conv并发兜底)
- agentic/mod.rs 11处 AiBusEvent→AiChatEvent 迁移(Error/Completed/Round)
This commit is contained in:
lxy
2026-06-22 03:06:28 +08:00
parent 8ccdce282c
commit 0fb5af50c7
4 changed files with 750 additions and 172 deletions
+20 -13
View File
@@ -39,8 +39,6 @@ use df_storage::models::AiProviderRecord;
use crate::state::{AppState, LlmConcurrency};
use crate::commands::ai::event_bus::AiBusEvent;
use super::audit::process_tool_calls;
use super::compress::compress_via_llm;
use super::conversation::{save_conversation, TokenAccumulator};
@@ -523,8 +521,9 @@ pub(crate) async fn run_agentic_loop(
});
// L3 emit 双写(2026-06-22):关键 AiError publish 到事件总线,供跨模块订阅。
// EVENT_BUS_ENABLED 门控在 publish 内部(false 静默丢弃),无消费者时空转不报错。
let _ = app_handle.state::<AppState>().ai_event_bus.publish(AiBusEvent::Error {
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiError {
error: msg,
error_type: None,
conversation_id: Some(conv_id.clone()),
});
return;
@@ -541,8 +540,9 @@ pub(crate) async fn run_agentic_loop(
conversation_id: Some(conv_id.clone()),
});
// L3 emit 双写:超时 AiError publish 到事件总线(同上,门控在 publish 内)。
let _ = app_handle.state::<AppState>().ai_event_bus.publish(AiBusEvent::Error {
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiError {
error: err_msg,
error_type: None,
conversation_id: Some(conv_id.clone()),
});
return;
@@ -713,10 +713,11 @@ pub(crate) async fn run_agentic_loop(
// generating 复位后再 emit Completed:保证前端收事件时后端已可接下一条(发送队列续发不被"正在生成中"拒绝)
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiCompleted { total_tokens: usage.total_tokens, prompt_tokens: tokens.prompt(), completion_tokens: tokens.completion(), incomplete: None, conversation_id: Some(conv_id.clone()) });
// L3 emit 双写:入口 stop 的 AiCompleted publish 到事件总线(EVENT_BUS_ENABLED 门控在 publish 内)。
let _ = app_handle.state::<AppState>().ai_event_bus.publish(AiBusEvent::Completed {
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiCompleted {
total_tokens: usage.total_tokens,
prompt_tokens: tokens.prompt(),
completion_tokens: tokens.completion(),
incomplete: None,
conversation_id: Some(conv_id.clone()),
});
return;
@@ -806,7 +807,7 @@ pub(crate) async fn run_agentic_loop(
conversation_id: Some(conv_id.clone()),
});
// L3 emit 双写:AiAgentRound publish 到事件总线(EVENT_BUS_ENABLED 门控在 publish 内)。
let _ = app_handle.state::<AppState>().ai_event_bus.publish(AiBusEvent::Round {
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiAgentRound {
round: round_n,
conversation_id: Some(conv_id.clone()),
});
@@ -1174,8 +1175,9 @@ pub(crate) async fn run_agentic_loop(
conversation_id: Some(conv_id.clone()),
});
// L3 emit 双写:Fatal AiError publish 到事件总线(门控在 publish 内)。
let _ = app_handle.state::<AppState>().ai_event_bus.publish(AiBusEvent::Error {
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiError {
error,
error_type: None,
conversation_id: Some(conv_id.clone()),
});
return;
@@ -1203,8 +1205,9 @@ pub(crate) async fn run_agentic_loop(
conversation_id: Some(conv_id.clone()),
});
// L3 emit 双写:全 candidate 耗尽 AiError publish 到事件总线(门控在 publish 内)。
let _ = app_handle.state::<AppState>().ai_event_bus.publish(AiBusEvent::Error {
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiError {
error: err_msg,
error_type: None,
conversation_id: Some(conv_id.clone()),
});
return;
@@ -1262,10 +1265,11 @@ pub(crate) async fn run_agentic_loop(
incomplete: Some(true),
});
// L3 emit 双写:MidStream 保文 AiCompleted publish 到事件总线(门控在 publish 内)。
let _ = app_handle.state::<AppState>().ai_event_bus.publish(AiBusEvent::Completed {
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiCompleted {
total_tokens: usage.total_tokens,
prompt_tokens: tokens.prompt(),
completion_tokens: tokens.completion(),
incomplete: None,
conversation_id: Some(conv_id.clone()),
});
return;
@@ -1329,10 +1333,11 @@ pub(crate) async fn run_agentic_loop(
// generating 复位后再 emit Completed:保证前端收事件时后端已可接下一条(发送队列续发不被"正在生成中"拒绝)
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiCompleted { total_tokens: usage.total_tokens, prompt_tokens: tokens.prompt(), completion_tokens: tokens.completion(), incomplete: None, conversation_id: Some(conv_id.clone()) });
// L3 emit 双写:stream 后 stop 的 AiCompleted publish 到事件总线(门控在 publish 内)。
let _ = app_handle.state::<AppState>().ai_event_bus.publish(AiBusEvent::Completed {
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiCompleted {
total_tokens: usage.total_tokens,
prompt_tokens: tokens.prompt(),
completion_tokens: tokens.completion(),
incomplete: None,
conversation_id: Some(conv_id.clone()),
});
return;
@@ -1524,10 +1529,11 @@ pub(crate) async fn run_agentic_loop(
let _ = app_handle.emit("ai-chat-event", AiChatEvent::AiCompleted { total_tokens: usage_total, prompt_tokens: tokens.prompt(), completion_tokens: tokens.completion(), incomplete: None, conversation_id: Some(conv_id.clone()) });
// L3 emit 双写:正常完成 AiCompleted publish 到事件总线(EVENT_BUS_ENABLED 门控在 publish 内,
// 无消费者空转留批3 真实消费者接入)。AiTextDelta/AiToolCall* 高频事件不双写(无消费者空转)。
let _ = app_handle.state::<AppState>().ai_event_bus.publish(AiBusEvent::Completed {
let _ = app_handle.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiCompleted {
total_tokens: usage_total,
prompt_tokens: tokens.prompt(),
completion_tokens: tokens.completion(),
incomplete: None,
conversation_id: Some(conv_id.clone()),
});
}
@@ -1654,8 +1660,9 @@ pub(crate) async fn try_continue_agent_loop(
conversation_id: Some(conv_id.to_string()),
});
// L3 emit 双写:try_continue provider-Err AiError publish 到事件总线(门控在 publish 内)。
let _ = app.state::<AppState>().ai_event_bus.publish(AiBusEvent::Error {
let _ = app.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiError {
error: e,
error_type: None,
conversation_id: Some(conv_id.to_string()),
});
return;
@@ -1723,7 +1730,7 @@ pub(crate) async fn try_continue_agent_loop(
conversation_id: Some(conv_id_owned.clone()),
});
// L3 emit 双写:try_continue 续跑 AiAgentRound publish 到事件总线(门控在 publish 内)。
let _ = app.state::<AppState>().ai_event_bus.publish(AiBusEvent::Round {
let _ = app.state::<AppState>().ai_event_bus.publish_event(AiChatEvent::AiAgentRound {
round: 0,
conversation_id: Some(conv_id_owned.clone()),
});