修复: AI 对话/工具可靠性(sanitize 三元组 + G2 签名重复 + handshake 不杀 loop + 空 tool_call id 兜底)
治 5 个对话停止/工具失败根因:sanitize 三元组按 id 配对治 400;G2 探索熔断从结果空 改签名重复判定(治误停正常探索);handshake 删越权强杀活 loop(generating 归 guard 单源); 空 tool_call id 兜底 gen_<index>(治 SenseNova 工具结果路由错位)。
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::provider::{StreamChunk, TokenUsage, ToolCallDelta};
|
||||
use crate::provider::{tool_call_id_or_fallback, StreamChunk, TokenUsage, ToolCallDelta};
|
||||
|
||||
// ============================================================
|
||||
// OpenAI API 请求/响应结构体
|
||||
@@ -211,11 +211,20 @@ pub(crate) fn apply_openai_sse(data: &str, usage_accum: &mut Option<TokenUsage>)
|
||||
|
||||
let tool_calls = choice.delta.tool_calls.map(|tcs| {
|
||||
tcs.into_iter()
|
||||
.map(|tc| ToolCallDelta {
|
||||
index: tc.index,
|
||||
id: tc.id,
|
||||
function_name: tc.function.as_ref().and_then(|f| f.name.clone()),
|
||||
function_arguments: tc.function.and_then(|f| f.arguments),
|
||||
.map(|tc| {
|
||||
// CR-空 id:流式 chunk 的 id 可能为 Some("")(SenseNova 兼容缺陷)。
|
||||
// 仅对「provider 显式给了 id 字段」的 chunk 做兜底——None(OpenAI
|
||||
// 协议:仅首 chunk 携带 id,后续 chunk 无 id)保持 None,避免
|
||||
// 覆盖首 chunk 的权威 id。Some("") → `gen_stream_{index}` fallback,
|
||||
// Some(非空) → 原样。下游 stream_recv 按 index 累积,draft.id 透传
|
||||
// 至 ToolCall.id(accumulate_tool_calls 仅 Some 覆盖,None 不动)。
|
||||
let id = tc.id.map(|raw| tool_call_id_or_fallback(&raw, tc.index as usize, "gen_stream"));
|
||||
ToolCallDelta {
|
||||
index: tc.index,
|
||||
id,
|
||||
function_name: tc.function.as_ref().and_then(|f| f.name.clone()),
|
||||
function_arguments: tc.function.and_then(|f| f.arguments),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user