fix(protocol): TopicTokenStats 补齐 cached_tokens 字段,修复前端缓存占比恒为 0
根因:command 层与 protocol 层存在两个同名 TopicTokenStats 结构体,websocket 适配器做 JSON 往返时 protocol 版缺 cached_tokens 字段,serde 反序列化静默丢弃。后端解析/存库/聚合均正常(DB 实测 8832/13916 命中),仅传输层断链。补字段并加往返回归测试固化两结构体对齐不变量。
This commit is contained in:
parent
011b23b54e
commit
ca7dcabbde
@ -54,6 +54,11 @@ pub struct TopicTokenStats {
|
|||||||
pub prompt_tokens: u64,
|
pub prompt_tokens: u64,
|
||||||
pub completion_tokens: u64,
|
pub completion_tokens: u64,
|
||||||
pub total_tokens: u64,
|
pub total_tokens: u64,
|
||||||
|
/// 累计缓存命中的输入 tokens 数(老数据为 0)。
|
||||||
|
/// 缺失此字段会导致 command 层序列化的 JSON 在此被静默丢弃(serde 忽略未知字段),
|
||||||
|
/// 前端缓存占比恒为 0——两结构体字段必须保持对齐。
|
||||||
|
#[serde(default)]
|
||||||
|
pub cached_tokens: u64,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub last_prompt_tokens: Option<u32>,
|
pub last_prompt_tokens: Option<u32>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@ -357,3 +362,35 @@ pub fn serialize_inbound(msg: &WsInbound) -> Result<String, serde_json::Error> {
|
|||||||
pub fn serialize_outbound(msg: &WsOutbound) -> Result<String, serde_json::Error> {
|
pub fn serialize_outbound(msg: &WsOutbound) -> Result<String, serde_json::Error> {
|
||||||
serde_json::to_string(msg)
|
serde_json::to_string(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// 回归测试:command 层 TopicTokenStats 序列化的 JSON 必须能无损还原到
|
||||||
|
/// protocol 层同名结构体(websocket 适配器走这条 JSON 往返路径)。
|
||||||
|
///
|
||||||
|
/// 历史缺陷:protocol 版曾缺 cached_tokens 字段,serde 反序列化时静默丢弃,
|
||||||
|
/// 导致前端缓存占比恒为 0(后端解析、存库、聚合全部正常)。
|
||||||
|
/// 两结构体字段必须保持对齐,此测试固化该不变量。
|
||||||
|
#[test]
|
||||||
|
fn test_topic_token_stats_roundtrip_preserves_cached_tokens() {
|
||||||
|
let command_stats = crate::command::handlers::list_topics::TopicTokenStats {
|
||||||
|
prompt_tokens: 13916,
|
||||||
|
completion_tokens: 80,
|
||||||
|
total_tokens: 13996,
|
||||||
|
cached_tokens: 8832,
|
||||||
|
last_prompt_tokens: Some(6971),
|
||||||
|
context_window_tokens: 131072,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 模拟 websocket 适配器的实际路径:command JSON → protocol 结构体
|
||||||
|
let json = serde_json::to_string(&command_stats).unwrap();
|
||||||
|
let protocol_stats: TopicTokenStats = serde_json::from_str(&json).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(protocol_stats.cached_tokens, 8832);
|
||||||
|
assert_eq!(protocol_stats.prompt_tokens, 13916);
|
||||||
|
assert_eq!(protocol_stats.last_prompt_tokens, Some(6971));
|
||||||
|
assert_eq!(protocol_stats.context_window_tokens, 131072);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user