feat: 为 WebSocket 消息添加时间戳字段,确保消息的时间信息可用
This commit is contained in:
parent
02339465b6
commit
bf66c00950
@ -66,6 +66,7 @@ impl OutputAdapter for WebSocketOutputAdapter {
|
||||
outbounds.push(WsOutbound::Error {
|
||||
code: error.code,
|
||||
message: error.message,
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
});
|
||||
return outbounds;
|
||||
}
|
||||
@ -77,7 +78,7 @@ impl OutputAdapter for WebSocketOutputAdapter {
|
||||
id: response.request_id.to_string(),
|
||||
content: msg.content.clone(),
|
||||
role: "assistant".to_string(),
|
||||
attachments: Vec::new(), subagent_task_id: None,
|
||||
attachments: Vec::new(), subagent_task_id: None, timestamp: Some(crate::protocol::now_timestamp()),
|
||||
},
|
||||
MessageKind::Notification => {
|
||||
// 根据元数据判断具体类型
|
||||
@ -97,7 +98,7 @@ impl OutputAdapter for WebSocketOutputAdapter {
|
||||
id: response.request_id.to_string(),
|
||||
content: msg.content.clone(),
|
||||
role: "assistant".to_string(),
|
||||
attachments: Vec::new(), subagent_task_id: None,
|
||||
attachments: Vec::new(), subagent_task_id: None, timestamp: Some(crate::protocol::now_timestamp()),
|
||||
},
|
||||
}
|
||||
} else if let Some(session_id) = response.metadata.get("session_id") {
|
||||
@ -136,7 +137,7 @@ impl OutputAdapter for WebSocketOutputAdapter {
|
||||
id: response.request_id.to_string(),
|
||||
content: msg.content.clone(),
|
||||
role: "assistant".to_string(),
|
||||
attachments: Vec::new(), subagent_task_id: None,
|
||||
attachments: Vec::new(), subagent_task_id: None, timestamp: Some(crate::protocol::now_timestamp()),
|
||||
},
|
||||
}
|
||||
} else if let Some(sessions_json) = response.metadata.get("sessions") {
|
||||
@ -154,7 +155,7 @@ impl OutputAdapter for WebSocketOutputAdapter {
|
||||
id: response.request_id.to_string(),
|
||||
content: msg.content.clone(),
|
||||
role: "assistant".to_string(),
|
||||
attachments: Vec::new(), subagent_task_id: None,
|
||||
attachments: Vec::new(), subagent_task_id: None, timestamp: Some(crate::protocol::now_timestamp()),
|
||||
},
|
||||
}
|
||||
} else if let Some(topics_json) = response.metadata.get("topics") {
|
||||
@ -173,7 +174,7 @@ impl OutputAdapter for WebSocketOutputAdapter {
|
||||
id: response.request_id.to_string(),
|
||||
content: msg.content.clone(),
|
||||
role: "assistant".to_string(),
|
||||
attachments: Vec::new(), subagent_task_id: None,
|
||||
attachments: Vec::new(), subagent_task_id: None, timestamp: Some(crate::protocol::now_timestamp()),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
@ -182,19 +183,20 @@ impl OutputAdapter for WebSocketOutputAdapter {
|
||||
id: response.request_id.to_string(),
|
||||
content: msg.content.clone(),
|
||||
role: "assistant".to_string(),
|
||||
attachments: Vec::new(), subagent_task_id: None,
|
||||
attachments: Vec::new(), subagent_task_id: None, timestamp: Some(crate::protocol::now_timestamp()),
|
||||
}
|
||||
}
|
||||
}
|
||||
MessageKind::Error => WsOutbound::Error {
|
||||
code: "RESPONSE_ERROR".to_string(),
|
||||
message: msg.content.clone(),
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
},
|
||||
_ => WsOutbound::AssistantResponse {
|
||||
id: response.request_id.to_string(),
|
||||
content: msg.content.clone(),
|
||||
role: "assistant".to_string(),
|
||||
attachments: Vec::new(), subagent_task_id: None,
|
||||
attachments: Vec::new(), subagent_task_id: None, timestamp: Some(crate::protocol::now_timestamp()),
|
||||
},
|
||||
};
|
||||
outbounds.push(outbound);
|
||||
|
||||
@ -235,7 +235,8 @@ async fn handle_socket(ws: WebSocket, state: Arc<GatewayState>) {
|
||||
tracing::warn!(error = %e, session_id = %current_session_id, "Failed to handle inbound message");
|
||||
let _ = sender
|
||||
.send(WsOutbound::Error {
|
||||
code: "SESSION_ERROR".to_string(),
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
code:"SESSION_ERROR".to_string(),
|
||||
message: e.to_string(),
|
||||
})
|
||||
.await;
|
||||
@ -245,7 +246,8 @@ async fn handle_socket(ws: WebSocket, state: Arc<GatewayState>) {
|
||||
tracing::warn!(error = %e, "Failed to parse inbound message");
|
||||
let _ = sender
|
||||
.send(WsOutbound::Error {
|
||||
code: "PARSE_ERROR".to_string(),
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
code:"PARSE_ERROR".to_string(),
|
||||
message: e.to_string(),
|
||||
})
|
||||
.await;
|
||||
@ -334,6 +336,7 @@ async fn handle_inbound(
|
||||
// 不是命令,返回错误
|
||||
let _ = sender
|
||||
.send(WsOutbound::Error {
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
code: "INVALID_COMMAND".to_string(),
|
||||
message: "Invalid command payload".to_string(),
|
||||
})
|
||||
@ -343,6 +346,7 @@ async fn handle_inbound(
|
||||
Err(e) => {
|
||||
let _ = sender
|
||||
.send(WsOutbound::Error {
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
code: "PARSE_ERROR".to_string(),
|
||||
message: e.to_string(),
|
||||
})
|
||||
@ -707,6 +711,7 @@ fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option<WsOutbou
|
||||
content: format!("{}\nargs: {}", tool_call.name, tool_call.arguments),
|
||||
role: msg.role.clone(),
|
||||
subagent_task_id: None,
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -717,6 +722,7 @@ fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option<WsOutbou
|
||||
role: msg.role.clone(),
|
||||
attachments: Vec::new(),
|
||||
subagent_task_id: None,
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
})
|
||||
}
|
||||
"tool" => {
|
||||
@ -730,6 +736,7 @@ fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option<WsOutbou
|
||||
role: msg.role.clone(),
|
||||
subagent_task_id: None,
|
||||
duration_ms: msg.tool_duration_ms,
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
}),
|
||||
ToolMessageState::PendingUserAction => Some(WsOutbound::ToolPending {
|
||||
id: msg.id.clone(),
|
||||
@ -739,6 +746,7 @@ fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option<WsOutbou
|
||||
role: msg.role.clone(),
|
||||
resume_hint: "完成外部操作后,直接发一条继续消息即可。".to_string(),
|
||||
subagent_task_id: None,
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -748,6 +756,7 @@ fn chat_message_to_ws_outbound(msg: &crate::bus::ChatMessage) -> Option<WsOutbou
|
||||
role: msg.role.clone(),
|
||||
attachments,
|
||||
subagent_task_id: None,
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
|
||||
@ -2,6 +2,14 @@ pub mod ws_adapter;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 当前时间戳(秒),用于填充消息的 timestamp 字段
|
||||
pub fn now_timestamp() -> i64 {
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs() as i64
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SessionSummary {
|
||||
pub session_id: String,
|
||||
@ -108,6 +116,8 @@ pub enum WsOutbound {
|
||||
attachments: Vec<MediaSummary>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
subagent_task_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
timestamp: Option<i64>,
|
||||
},
|
||||
#[serde(rename = "tool_call")]
|
||||
ToolCall {
|
||||
@ -119,6 +129,8 @@ pub enum WsOutbound {
|
||||
role: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
subagent_task_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
timestamp: Option<i64>,
|
||||
},
|
||||
#[serde(rename = "tool_result")]
|
||||
ToolResult {
|
||||
@ -131,6 +143,8 @@ pub enum WsOutbound {
|
||||
subagent_task_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
duration_ms: Option<u64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
timestamp: Option<i64>,
|
||||
},
|
||||
#[serde(rename = "tool_pending")]
|
||||
ToolPending {
|
||||
@ -142,9 +156,16 @@ pub enum WsOutbound {
|
||||
resume_hint: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
subagent_task_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
timestamp: Option<i64>,
|
||||
},
|
||||
#[serde(rename = "error")]
|
||||
Error { code: String, message: String },
|
||||
Error {
|
||||
code: String,
|
||||
message: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
timestamp: Option<i64>,
|
||||
},
|
||||
#[serde(rename = "task_started")]
|
||||
TaskStarted {
|
||||
task_id: String,
|
||||
|
||||
@ -93,6 +93,7 @@ pub(crate) fn ws_outbound_from_outbound_message(message: &OutboundMessage) -> Ve
|
||||
role: message.role.clone(),
|
||||
attachments,
|
||||
subagent_task_id: message.metadata.get("subagent_task_id").cloned(),
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
}]
|
||||
}
|
||||
OutboundEventKind::ToolCall => vec![WsOutbound::ToolCall {
|
||||
@ -109,6 +110,7 @@ pub(crate) fn ws_outbound_from_outbound_message(message: &OutboundMessage) -> Ve
|
||||
content: message.content.clone(),
|
||||
role: message.role.clone(),
|
||||
subagent_task_id: message.metadata.get("subagent_task_id").cloned(),
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
}],
|
||||
OutboundEventKind::ToolResult => vec![WsOutbound::ToolResult {
|
||||
id: message
|
||||
@ -124,6 +126,7 @@ pub(crate) fn ws_outbound_from_outbound_message(message: &OutboundMessage) -> Ve
|
||||
.metadata
|
||||
.get("tool_duration_ms")
|
||||
.and_then(|v| v.parse().ok()),
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
}],
|
||||
OutboundEventKind::ToolPending => vec![WsOutbound::ToolPending {
|
||||
id: message
|
||||
@ -136,10 +139,12 @@ pub(crate) fn ws_outbound_from_outbound_message(message: &OutboundMessage) -> Ve
|
||||
role: message.role.clone(),
|
||||
resume_hint: TOOL_PENDING_RESUME_HINT.to_string(),
|
||||
subagent_task_id: message.metadata.get("subagent_task_id").cloned(),
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
}],
|
||||
OutboundEventKind::ErrorNotification => vec![WsOutbound::Error {
|
||||
code: "AGENT_ERROR".to_string(),
|
||||
message: message.content.clone(),
|
||||
timestamp: Some(crate::protocol::now_timestamp()),
|
||||
}],
|
||||
OutboundEventKind::TaskStarted => vec![WsOutbound::TaskStarted {
|
||||
task_id: message.metadata.get("task_id").cloned().unwrap_or_default(),
|
||||
|
||||
@ -168,7 +168,7 @@ export function useChat(): UseChatReturn {
|
||||
id: msg.id,
|
||||
role: role as ChatMessage['role'],
|
||||
content: msg.content,
|
||||
timestamp: Date.now(),
|
||||
timestamp: (message as any).timestamp ?? Math.floor(Date.now() / 1000),
|
||||
type: 'message',
|
||||
attachments: msg.attachments,
|
||||
subagentTaskId: msg.subagent_task_id,
|
||||
@ -180,7 +180,7 @@ export function useChat(): UseChatReturn {
|
||||
id: msg.id,
|
||||
role: 'tool',
|
||||
content: msg.content,
|
||||
timestamp: Date.now(),
|
||||
timestamp: (message as any).timestamp ?? Math.floor(Date.now() / 1000),
|
||||
type: 'tool_call',
|
||||
toolName: msg.tool_name,
|
||||
toolCallId: msg.tool_call_id,
|
||||
@ -194,7 +194,7 @@ export function useChat(): UseChatReturn {
|
||||
id: msg.id,
|
||||
role: 'tool',
|
||||
content: msg.content,
|
||||
timestamp: Date.now(),
|
||||
timestamp: (message as any).timestamp ?? Math.floor(Date.now() / 1000),
|
||||
type: 'tool_result',
|
||||
toolName: msg.tool_name,
|
||||
toolCallId: msg.tool_call_id,
|
||||
@ -208,7 +208,7 @@ export function useChat(): UseChatReturn {
|
||||
id: msg.id,
|
||||
role: 'tool',
|
||||
content: `${msg.content}\n\n${msg.resume_hint}`,
|
||||
timestamp: Date.now(),
|
||||
timestamp: (message as any).timestamp ?? Math.floor(Date.now() / 1000),
|
||||
type: 'tool_pending',
|
||||
toolName: msg.tool_name,
|
||||
toolCallId: msg.tool_call_id,
|
||||
@ -220,7 +220,7 @@ export function useChat(): UseChatReturn {
|
||||
id: generateMessageId(),
|
||||
role: 'assistant',
|
||||
content: `Error: ${message.message}`,
|
||||
timestamp: Date.now(),
|
||||
timestamp: (message as any).timestamp ?? Math.floor(Date.now() / 1000),
|
||||
type: 'message',
|
||||
}
|
||||
}
|
||||
@ -394,7 +394,7 @@ export function useChat(): UseChatReturn {
|
||||
id: msg.id,
|
||||
role,
|
||||
content: msg.content,
|
||||
timestamp: Date.now(),
|
||||
timestamp: (message as any).timestamp ?? Math.floor(Date.now() / 1000),
|
||||
type: 'message',
|
||||
attachments: msg.attachments,
|
||||
},
|
||||
@ -411,7 +411,7 @@ export function useChat(): UseChatReturn {
|
||||
id: msg.id,
|
||||
role: 'tool',
|
||||
content: msg.content,
|
||||
timestamp: Date.now(),
|
||||
timestamp: (message as any).timestamp ?? Math.floor(Date.now() / 1000),
|
||||
type: 'tool_call',
|
||||
toolName: msg.tool_name,
|
||||
toolCallId: msg.tool_call_id,
|
||||
@ -430,7 +430,7 @@ export function useChat(): UseChatReturn {
|
||||
id: msg.id,
|
||||
role: 'tool',
|
||||
content: msg.content,
|
||||
timestamp: Date.now(),
|
||||
timestamp: (message as any).timestamp ?? Math.floor(Date.now() / 1000),
|
||||
type: 'tool_result',
|
||||
toolName: msg.tool_name,
|
||||
toolCallId: msg.tool_call_id,
|
||||
@ -449,7 +449,7 @@ export function useChat(): UseChatReturn {
|
||||
id: msg.id,
|
||||
role: 'tool',
|
||||
content: `${msg.content}\n\n${msg.resume_hint}`,
|
||||
timestamp: Date.now(),
|
||||
timestamp: (message as any).timestamp ?? Math.floor(Date.now() / 1000),
|
||||
type: 'tool_pending',
|
||||
toolName: msg.tool_name,
|
||||
toolCallId: msg.tool_call_id,
|
||||
@ -465,7 +465,7 @@ export function useChat(): UseChatReturn {
|
||||
id: generateMessageId(),
|
||||
role: 'assistant',
|
||||
content: (message as { type: 'execution_cancelled'; message: string }).message,
|
||||
timestamp: Date.now(),
|
||||
timestamp: (message as any).timestamp ?? Math.floor(Date.now() / 1000),
|
||||
type: 'message',
|
||||
},
|
||||
])
|
||||
@ -480,7 +480,7 @@ export function useChat(): UseChatReturn {
|
||||
id: generateMessageId(),
|
||||
role: 'assistant',
|
||||
content: `Error: ${message.message}`,
|
||||
timestamp: Date.now(),
|
||||
timestamp: (message as any).timestamp ?? Math.floor(Date.now() / 1000),
|
||||
type: 'message',
|
||||
},
|
||||
])
|
||||
@ -513,7 +513,7 @@ export function useChat(): UseChatReturn {
|
||||
id: generateMessageId(),
|
||||
role: 'user',
|
||||
content,
|
||||
timestamp: Date.now(),
|
||||
timestamp: Math.floor(Date.now() / 1000),
|
||||
type: 'message',
|
||||
attachments: attachments || [],
|
||||
},
|
||||
|
||||
@ -43,6 +43,7 @@ export interface AssistantResponse {
|
||||
role: string
|
||||
attachments?: Attachment[]
|
||||
subagent_task_id?: string
|
||||
timestamp?: number
|
||||
}
|
||||
|
||||
export interface ToolCall {
|
||||
@ -54,6 +55,7 @@ export interface ToolCall {
|
||||
content: string
|
||||
role: string
|
||||
subagent_task_id?: string
|
||||
timestamp?: number
|
||||
}
|
||||
|
||||
export interface ToolResult {
|
||||
@ -65,6 +67,7 @@ export interface ToolResult {
|
||||
role: string
|
||||
subagent_task_id?: string
|
||||
duration_ms?: number
|
||||
timestamp?: number
|
||||
}
|
||||
|
||||
export interface ToolPending {
|
||||
@ -76,12 +79,14 @@ export interface ToolPending {
|
||||
role: string
|
||||
resume_hint: string
|
||||
subagent_task_id?: string
|
||||
timestamp?: number
|
||||
}
|
||||
|
||||
export interface WsError {
|
||||
type: 'error'
|
||||
code: string
|
||||
message: string
|
||||
timestamp?: number
|
||||
}
|
||||
|
||||
export interface TaskStarted {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user