mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-25 14:53:34 +00:00
fix(engine): route messages to correct conversation by thread scope
Messages sent from a new conversation in the gateway always appeared in the default assistant conversation because handle_with_engine ignored the thread_id from the frontend. Two fixes: 1. Engine conversation scoping — when the message carries a thread_id (from the frontend's conversation picker), use it as part of the engine conversation key: "gateway:<thread_id>" instead of just "gateway". This creates a distinct engine conversation per v1 thread, so messages don't cross-contaminate. 2. V1 dual-write targeting — write user messages and assistant responses to the v1 conversation matching the thread_id (via ensure_conversation), not the hardcoded assistant conversation. Falls back to the assistant conversation when no thread_id is present (e.g., default chat). Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
This commit is contained in:
+49
-16
@@ -790,10 +790,21 @@ pub async fn handle_with_engine(
|
||||
// Reset the per-step call counter so each thread starts fresh
|
||||
state.effect_adapter.reset_call_count();
|
||||
|
||||
// Get or create conversation for this channel+user
|
||||
// Scope the engine conversation by (channel, user, thread).
|
||||
// When the frontend sends a thread_id (user created a new conversation),
|
||||
// use it as part of the channel key so each v1 thread maps to a distinct
|
||||
// engine conversation. Without this, all threads share one conversation
|
||||
// and messages appear in the wrong place.
|
||||
let scope = message.conversation_scope();
|
||||
let channel_key = match scope {
|
||||
Some(tid) => format!("{}:{}", message.channel, tid),
|
||||
None => message.channel.clone(),
|
||||
};
|
||||
|
||||
// Get or create conversation for this scoped channel+user
|
||||
let conv_id = state
|
||||
.conversation_manager
|
||||
.get_or_create_conversation(&message.channel, &message.user_id)
|
||||
.get_or_create_conversation(&channel_key, &message.user_id)
|
||||
.await
|
||||
.map_err(|e| engine_err("conversation error", e))?;
|
||||
|
||||
@@ -813,14 +824,26 @@ pub async fn handle_with_engine(
|
||||
.await
|
||||
.map_err(|e| engine_err("thread error", e))?;
|
||||
|
||||
if let Some(ref db) = state.db
|
||||
&& let Ok(conv_id_v1) = db
|
||||
.get_or_create_assistant_conversation(&message.user_id, &message.channel)
|
||||
.await
|
||||
{
|
||||
let _ = db
|
||||
.add_conversation_message(conv_id_v1, "user", content)
|
||||
.await;
|
||||
// Dual-write to v1 database so the gateway history API shows messages.
|
||||
// Use the thread-scoped conversation (from thread_id) when available,
|
||||
// falling back to the default assistant conversation.
|
||||
if let Some(ref db) = state.db {
|
||||
let v1_conv_id = if let Some(tid) = scope
|
||||
&& let Ok(uuid) = uuid::Uuid::parse_str(tid)
|
||||
{
|
||||
// Ensure the v1 conversation exists for this thread
|
||||
let _ = db
|
||||
.ensure_conversation(uuid, &message.channel, &message.user_id, Some(tid))
|
||||
.await;
|
||||
Some(uuid)
|
||||
} else {
|
||||
db.get_or_create_assistant_conversation(&message.user_id, &message.channel)
|
||||
.await
|
||||
.ok()
|
||||
};
|
||||
if let Some(cid) = v1_conv_id {
|
||||
let _ = db.add_conversation_message(cid, "user", content).await;
|
||||
}
|
||||
}
|
||||
|
||||
debug!(thread_id = %thread_id, "engine v2: thread spawned");
|
||||
@@ -878,16 +901,26 @@ async fn await_thread_outcome(
|
||||
.map_err(|e| engine_err("conversation error", e))?;
|
||||
|
||||
if let Some(ref db) = state.db
|
||||
&& let Ok(conv_id_v1) = db
|
||||
.get_or_create_assistant_conversation(&message.user_id, &message.channel)
|
||||
.await
|
||||
&& let ThreadOutcome::Completed {
|
||||
response: Some(ref text),
|
||||
} = outcome
|
||||
{
|
||||
let _ = db
|
||||
.add_conversation_message(conv_id_v1, "assistant", text)
|
||||
.await;
|
||||
// Write response to the correct v1 conversation (thread-scoped or assistant)
|
||||
let scope = message.conversation_scope();
|
||||
let v1_conv_id = if let Some(tid) = scope
|
||||
&& let Ok(uuid) = uuid::Uuid::parse_str(tid)
|
||||
{
|
||||
Some(uuid)
|
||||
} else {
|
||||
db.get_or_create_assistant_conversation(&message.user_id, &message.channel)
|
||||
.await
|
||||
.ok()
|
||||
};
|
||||
if let Some(cid) = v1_conv_id {
|
||||
let _ = db
|
||||
.add_conversation_message(cid, "assistant", text)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref sse) = state.sse
|
||||
|
||||
Reference in New Issue
Block a user