feat: 添加 session_id 支持到 OutboundMessage,优化会话管理
This commit is contained in:
parent
0095ace411
commit
025c0b5d7f
@ -251,7 +251,12 @@ impl InboundMessage {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct OutboundMessage {
|
pub struct OutboundMessage {
|
||||||
pub channel: String,
|
pub channel: String,
|
||||||
|
/// 消息发送目标 ID(如飞书 open_id、微信 chat_id)
|
||||||
|
/// 注意:这始终是原始入站消息的 chat_id,不会被修改为会话 ID
|
||||||
pub chat_id: String,
|
pub chat_id: String,
|
||||||
|
/// 内部会话 ID(对应 sessions.id)
|
||||||
|
/// 用于会话管理和消息持久化,与消息发送目标无关
|
||||||
|
pub session_id: Option<String>,
|
||||||
pub content: String,
|
pub content: String,
|
||||||
pub reply_to: Option<String>,
|
pub reply_to: Option<String>,
|
||||||
pub media: Vec<MediaItem>,
|
pub media: Vec<MediaItem>,
|
||||||
@ -281,6 +286,7 @@ impl OutboundMessage {
|
|||||||
pub fn assistant(
|
pub fn assistant(
|
||||||
channel: impl Into<String>,
|
channel: impl Into<String>,
|
||||||
chat_id: impl Into<String>,
|
chat_id: impl Into<String>,
|
||||||
|
session_id: Option<String>,
|
||||||
content: impl Into<String>,
|
content: impl Into<String>,
|
||||||
reply_to: Option<String>,
|
reply_to: Option<String>,
|
||||||
metadata: HashMap<String, String>,
|
metadata: HashMap<String, String>,
|
||||||
@ -288,6 +294,7 @@ impl OutboundMessage {
|
|||||||
Self {
|
Self {
|
||||||
channel: channel.into(),
|
channel: channel.into(),
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
|
session_id,
|
||||||
content: content.into(),
|
content: content.into(),
|
||||||
reply_to,
|
reply_to,
|
||||||
media: Vec::new(),
|
media: Vec::new(),
|
||||||
@ -303,11 +310,12 @@ impl OutboundMessage {
|
|||||||
pub fn scheduler_notification(
|
pub fn scheduler_notification(
|
||||||
channel: impl Into<String>,
|
channel: impl Into<String>,
|
||||||
chat_id: impl Into<String>,
|
chat_id: impl Into<String>,
|
||||||
|
session_id: Option<String>,
|
||||||
content: impl Into<String>,
|
content: impl Into<String>,
|
||||||
reply_to: Option<String>,
|
reply_to: Option<String>,
|
||||||
metadata: HashMap<String, String>,
|
metadata: HashMap<String, String>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut message = Self::assistant(channel, chat_id, content, reply_to, metadata);
|
let mut message = Self::assistant(channel, chat_id, session_id, content, reply_to, metadata);
|
||||||
message.event_kind = OutboundEventKind::SchedulerNotification;
|
message.event_kind = OutboundEventKind::SchedulerNotification;
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
@ -315,11 +323,12 @@ impl OutboundMessage {
|
|||||||
pub fn error_notification(
|
pub fn error_notification(
|
||||||
channel: impl Into<String>,
|
channel: impl Into<String>,
|
||||||
chat_id: impl Into<String>,
|
chat_id: impl Into<String>,
|
||||||
|
session_id: Option<String>,
|
||||||
content: impl Into<String>,
|
content: impl Into<String>,
|
||||||
reply_to: Option<String>,
|
reply_to: Option<String>,
|
||||||
metadata: HashMap<String, String>,
|
metadata: HashMap<String, String>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut message = Self::assistant(channel, chat_id, content, reply_to, metadata);
|
let mut message = Self::assistant(channel, chat_id, session_id, content, reply_to, metadata);
|
||||||
message.event_kind = OutboundEventKind::ErrorNotification;
|
message.event_kind = OutboundEventKind::ErrorNotification;
|
||||||
message
|
message
|
||||||
}
|
}
|
||||||
@ -327,6 +336,7 @@ impl OutboundMessage {
|
|||||||
pub fn tool_call(
|
pub fn tool_call(
|
||||||
channel: impl Into<String>,
|
channel: impl Into<String>,
|
||||||
chat_id: impl Into<String>,
|
chat_id: impl Into<String>,
|
||||||
|
session_id: Option<String>,
|
||||||
message_id: impl Into<String>,
|
message_id: impl Into<String>,
|
||||||
tool_name: impl Into<String>,
|
tool_name: impl Into<String>,
|
||||||
tool_arguments: serde_json::Value,
|
tool_arguments: serde_json::Value,
|
||||||
@ -338,6 +348,7 @@ impl OutboundMessage {
|
|||||||
Self {
|
Self {
|
||||||
channel: channel.into(),
|
channel: channel.into(),
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
|
session_id,
|
||||||
content,
|
content,
|
||||||
reply_to,
|
reply_to,
|
||||||
media: Vec::new(),
|
media: Vec::new(),
|
||||||
@ -353,6 +364,7 @@ impl OutboundMessage {
|
|||||||
pub fn tool_result(
|
pub fn tool_result(
|
||||||
channel: impl Into<String>,
|
channel: impl Into<String>,
|
||||||
chat_id: impl Into<String>,
|
chat_id: impl Into<String>,
|
||||||
|
session_id: Option<String>,
|
||||||
tool_call_id: impl Into<String>,
|
tool_call_id: impl Into<String>,
|
||||||
tool_name: impl Into<String>,
|
tool_name: impl Into<String>,
|
||||||
content: impl Into<String>,
|
content: impl Into<String>,
|
||||||
@ -365,6 +377,7 @@ impl OutboundMessage {
|
|||||||
Self {
|
Self {
|
||||||
channel: channel.into(),
|
channel: channel.into(),
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
|
session_id,
|
||||||
content,
|
content,
|
||||||
reply_to,
|
reply_to,
|
||||||
media: Vec::new(),
|
media: Vec::new(),
|
||||||
@ -380,6 +393,7 @@ impl OutboundMessage {
|
|||||||
pub fn tool_pending(
|
pub fn tool_pending(
|
||||||
channel: impl Into<String>,
|
channel: impl Into<String>,
|
||||||
chat_id: impl Into<String>,
|
chat_id: impl Into<String>,
|
||||||
|
session_id: Option<String>,
|
||||||
tool_call_id: impl Into<String>,
|
tool_call_id: impl Into<String>,
|
||||||
tool_name: impl Into<String>,
|
tool_name: impl Into<String>,
|
||||||
content: impl Into<String>,
|
content: impl Into<String>,
|
||||||
@ -392,6 +406,7 @@ impl OutboundMessage {
|
|||||||
Self {
|
Self {
|
||||||
channel: channel.into(),
|
channel: channel.into(),
|
||||||
chat_id: chat_id.into(),
|
chat_id: chat_id.into(),
|
||||||
|
session_id,
|
||||||
content,
|
content,
|
||||||
reply_to,
|
reply_to,
|
||||||
media: Vec::new(),
|
media: Vec::new(),
|
||||||
@ -407,6 +422,7 @@ impl OutboundMessage {
|
|||||||
pub fn from_chat_message(
|
pub fn from_chat_message(
|
||||||
channel: &str,
|
channel: &str,
|
||||||
chat_id: &str,
|
chat_id: &str,
|
||||||
|
session_id: Option<String>,
|
||||||
reply_to: Option<String>,
|
reply_to: Option<String>,
|
||||||
metadata: &HashMap<String, String>,
|
metadata: &HashMap<String, String>,
|
||||||
message: &ChatMessage,
|
message: &ChatMessage,
|
||||||
@ -419,6 +435,7 @@ impl OutboundMessage {
|
|||||||
outbound.push(Self::assistant(
|
outbound.push(Self::assistant(
|
||||||
channel.to_string(),
|
channel.to_string(),
|
||||||
chat_id.to_string(),
|
chat_id.to_string(),
|
||||||
|
session_id.clone(),
|
||||||
message.content.clone(),
|
message.content.clone(),
|
||||||
reply_to.clone(),
|
reply_to.clone(),
|
||||||
metadata.clone(),
|
metadata.clone(),
|
||||||
@ -429,6 +446,7 @@ impl OutboundMessage {
|
|||||||
Self::tool_call(
|
Self::tool_call(
|
||||||
channel.to_string(),
|
channel.to_string(),
|
||||||
chat_id.to_string(),
|
chat_id.to_string(),
|
||||||
|
session_id.clone(),
|
||||||
tool_call.id.clone(),
|
tool_call.id.clone(),
|
||||||
tool_call.name.clone(),
|
tool_call.name.clone(),
|
||||||
tool_call.arguments.clone(),
|
tool_call.arguments.clone(),
|
||||||
@ -441,6 +459,7 @@ impl OutboundMessage {
|
|||||||
vec![Self::assistant(
|
vec![Self::assistant(
|
||||||
channel.to_string(),
|
channel.to_string(),
|
||||||
chat_id.to_string(),
|
chat_id.to_string(),
|
||||||
|
session_id,
|
||||||
message.content.clone(),
|
message.content.clone(),
|
||||||
reply_to,
|
reply_to,
|
||||||
metadata.clone(),
|
metadata.clone(),
|
||||||
@ -455,6 +474,7 @@ impl OutboundMessage {
|
|||||||
ToolMessageState::Completed => vec![Self::tool_result(
|
ToolMessageState::Completed => vec![Self::tool_result(
|
||||||
channel.to_string(),
|
channel.to_string(),
|
||||||
chat_id.to_string(),
|
chat_id.to_string(),
|
||||||
|
session_id,
|
||||||
message.tool_call_id.clone().unwrap_or_default(),
|
message.tool_call_id.clone().unwrap_or_default(),
|
||||||
message.tool_name.clone().unwrap_or_default(),
|
message.tool_name.clone().unwrap_or_default(),
|
||||||
message.content.clone(),
|
message.content.clone(),
|
||||||
@ -464,6 +484,7 @@ impl OutboundMessage {
|
|||||||
ToolMessageState::PendingUserAction => vec![Self::tool_pending(
|
ToolMessageState::PendingUserAction => vec![Self::tool_pending(
|
||||||
channel.to_string(),
|
channel.to_string(),
|
||||||
chat_id.to_string(),
|
chat_id.to_string(),
|
||||||
|
session_id,
|
||||||
message.tool_call_id.clone().unwrap_or_default(),
|
message.tool_call_id.clone().unwrap_or_default(),
|
||||||
message.tool_name.clone().unwrap_or_default(),
|
message.tool_name.clone().unwrap_or_default(),
|
||||||
message.content.clone(),
|
message.content.clone(),
|
||||||
@ -562,6 +583,7 @@ mod tests {
|
|||||||
TEST_CHANNEL,
|
TEST_CHANNEL,
|
||||||
"chat-1",
|
"chat-1",
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
&HashMap::new(),
|
&HashMap::new(),
|
||||||
&message,
|
&message,
|
||||||
);
|
);
|
||||||
@ -599,6 +621,7 @@ mod tests {
|
|||||||
TEST_CHANNEL,
|
TEST_CHANNEL,
|
||||||
"chat-1",
|
"chat-1",
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
&HashMap::new(),
|
&HashMap::new(),
|
||||||
&message,
|
&message,
|
||||||
);
|
);
|
||||||
@ -618,6 +641,7 @@ mod tests {
|
|||||||
TEST_CHANNEL,
|
TEST_CHANNEL,
|
||||||
"chat-1",
|
"chat-1",
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
&HashMap::new(),
|
&HashMap::new(),
|
||||||
&message,
|
&message,
|
||||||
);
|
);
|
||||||
@ -639,6 +663,7 @@ mod tests {
|
|||||||
TEST_CHANNEL,
|
TEST_CHANNEL,
|
||||||
"chat-1",
|
"chat-1",
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
&HashMap::new(),
|
&HashMap::new(),
|
||||||
&message,
|
&message,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -119,6 +119,7 @@ mod tests {
|
|||||||
.send(OutboundMessage::assistant(
|
.send(OutboundMessage::assistant(
|
||||||
"cli",
|
"cli",
|
||||||
"session-1",
|
"session-1",
|
||||||
|
None, // session_id
|
||||||
"hello",
|
"hello",
|
||||||
None,
|
None,
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
@ -143,6 +144,7 @@ mod tests {
|
|||||||
.send(OutboundMessage::assistant(
|
.send(OutboundMessage::assistant(
|
||||||
"cli",
|
"cli",
|
||||||
"session-1",
|
"session-1",
|
||||||
|
None, // session_id
|
||||||
"hello",
|
"hello",
|
||||||
None,
|
None,
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
|
|||||||
@ -114,6 +114,7 @@ impl AgentExecutionService {
|
|||||||
OutboundMessage::from_chat_message(
|
OutboundMessage::from_chat_message(
|
||||||
request.channel_name,
|
request.channel_name,
|
||||||
request.chat_id,
|
request.chat_id,
|
||||||
|
None, // session_id
|
||||||
None,
|
None,
|
||||||
request.metadata,
|
request.metadata,
|
||||||
message,
|
message,
|
||||||
|
|||||||
@ -125,32 +125,23 @@ impl InboundProcessor {
|
|||||||
let cmd_ctx = crate::command::context::CommandContext::new(&inbound.channel, &inbound.channel)
|
let cmd_ctx = crate::command::context::CommandContext::new(&inbound.channel, &inbound.channel)
|
||||||
.with_session_id(&inbound.chat_id);
|
.with_session_id(&inbound.chat_id);
|
||||||
|
|
||||||
// 记录是否是创建会话命令(用于后续自动切换)
|
// 记录是否是创建会话命令(用于后续处理)
|
||||||
let is_create_session = matches!(cmd, Command::CreateSession { .. });
|
let _is_create_session = matches!(cmd, Command::CreateSession { .. });
|
||||||
|
|
||||||
let response = self.command_router.dispatch_with_response(cmd, cmd_ctx).await;
|
let response = self.command_router.dispatch_with_response(cmd, cmd_ctx).await;
|
||||||
|
|
||||||
// 发送响应给用户
|
// 发送响应给用户
|
||||||
if response.success {
|
if response.success {
|
||||||
// 如果是创建会话,更新 chat_id 到新会话
|
|
||||||
let target_chat_id = if let Some(session_id) = response.metadata.get("session_id") {
|
|
||||||
if is_create_session {
|
|
||||||
// 自动切换到新会话
|
|
||||||
session_id.clone()
|
|
||||||
} else {
|
|
||||||
inbound.chat_id.clone()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
inbound.chat_id.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
// 提取响应消息
|
// 提取响应消息
|
||||||
|
// chat_id 保持为 inbound.chat_id(飞书 open_id)
|
||||||
|
// session_id 放入 metadata 用于会话管理
|
||||||
for msg in &response.messages {
|
for msg in &response.messages {
|
||||||
if let Err(error) = self
|
if let Err(error) = self
|
||||||
.bus
|
.bus
|
||||||
.publish_outbound(OutboundMessage::assistant(
|
.publish_outbound(OutboundMessage::assistant(
|
||||||
inbound.channel.clone(),
|
inbound.channel.clone(),
|
||||||
target_chat_id.clone(),
|
inbound.chat_id.clone(),
|
||||||
|
response.metadata.get("session_id").cloned(),
|
||||||
msg.content.clone(),
|
msg.content.clone(),
|
||||||
None,
|
None,
|
||||||
inbound.forwarded_metadata.clone(),
|
inbound.forwarded_metadata.clone(),
|
||||||
@ -166,6 +157,7 @@ impl InboundProcessor {
|
|||||||
.publish_outbound(OutboundMessage::assistant(
|
.publish_outbound(OutboundMessage::assistant(
|
||||||
inbound.channel.clone(),
|
inbound.channel.clone(),
|
||||||
inbound.chat_id.clone(),
|
inbound.chat_id.clone(),
|
||||||
|
response.metadata.get("session_id").cloned(),
|
||||||
format!("Error [{}]: {}", error.code, error.message),
|
format!("Error [{}]: {}", error.code, error.message),
|
||||||
None,
|
None,
|
||||||
inbound.forwarded_metadata.clone(),
|
inbound.forwarded_metadata.clone(),
|
||||||
@ -216,6 +208,7 @@ impl InboundProcessor {
|
|||||||
.publish_outbound(OutboundMessage::error_notification(
|
.publish_outbound(OutboundMessage::error_notification(
|
||||||
inbound.channel,
|
inbound.channel,
|
||||||
inbound.chat_id,
|
inbound.chat_id,
|
||||||
|
None, // session_id
|
||||||
error.to_string(),
|
error.to_string(),
|
||||||
None,
|
None,
|
||||||
metadata,
|
metadata,
|
||||||
|
|||||||
@ -79,6 +79,7 @@ impl EmittedMessageHandler for BusToolCallEmitter {
|
|||||||
for outbound in OutboundMessage::from_chat_message(
|
for outbound in OutboundMessage::from_chat_message(
|
||||||
&self.channel_name,
|
&self.channel_name,
|
||||||
&self.chat_id,
|
&self.chat_id,
|
||||||
|
None, // session_id
|
||||||
None,
|
None,
|
||||||
&self.metadata,
|
&self.metadata,
|
||||||
&message,
|
&message,
|
||||||
|
|||||||
@ -47,6 +47,7 @@ impl SessionMessageSender for BusSessionMessageSender {
|
|||||||
.publish_outbound(OutboundMessage::assistant(
|
.publish_outbound(OutboundMessage::assistant(
|
||||||
channel_name.to_string(),
|
channel_name.to_string(),
|
||||||
chat_id.to_string(),
|
chat_id.to_string(),
|
||||||
|
None, // session_id
|
||||||
text,
|
text,
|
||||||
None,
|
None,
|
||||||
metadata.clone(),
|
metadata.clone(),
|
||||||
@ -68,6 +69,7 @@ impl SessionMessageSender for BusSessionMessageSender {
|
|||||||
let mut outbound = OutboundMessage::assistant(
|
let mut outbound = OutboundMessage::assistant(
|
||||||
channel_name.to_string(),
|
channel_name.to_string(),
|
||||||
chat_id.to_string(),
|
chat_id.to_string(),
|
||||||
|
None, // session_id
|
||||||
String::new(),
|
String::new(),
|
||||||
None,
|
None,
|
||||||
metadata.clone(),
|
metadata.clone(),
|
||||||
|
|||||||
@ -201,6 +201,7 @@ mod tests {
|
|||||||
let message = OutboundMessage::tool_call(
|
let message = OutboundMessage::tool_call(
|
||||||
"cli",
|
"cli",
|
||||||
"session-1",
|
"session-1",
|
||||||
|
None, // session_id
|
||||||
"call-1",
|
"call-1",
|
||||||
"calculator",
|
"calculator",
|
||||||
json!({"expression": "1 + 1"}),
|
json!({"expression": "1 + 1"}),
|
||||||
|
|||||||
@ -409,6 +409,7 @@ impl Scheduler {
|
|||||||
.publish_outbound(OutboundMessage::error_notification(
|
.publish_outbound(OutboundMessage::error_notification(
|
||||||
channel,
|
channel,
|
||||||
chat_id,
|
chat_id,
|
||||||
|
None, // session_id
|
||||||
format!(
|
format!(
|
||||||
"定时任务执行失败:{}\n{}",
|
"定时任务执行失败:{}\n{}",
|
||||||
job.id,
|
job.id,
|
||||||
@ -904,6 +905,7 @@ fn build_outbound_message(job: &RuntimeJob) -> anyhow::Result<OutboundMessage> {
|
|||||||
Ok(OutboundMessage::scheduler_notification(
|
Ok(OutboundMessage::scheduler_notification(
|
||||||
channel,
|
channel,
|
||||||
chat_id,
|
chat_id,
|
||||||
|
None, // session_id
|
||||||
content.to_string(),
|
content.to_string(),
|
||||||
job.target.reply_to.clone(),
|
job.target.reply_to.clone(),
|
||||||
metadata,
|
metadata,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user