per-message context headers, memory notes, conversation continuity
conversations API path now injects per-message context headers with live timestamps, room name, and memory notes. this replaces the template variables in agent instructions which were frozen at creation time. memory notes (topical + recent backfill) loaded before each response in the conversations path — was previously only in the legacy path. context hint seeds new conversations with recent room history after resets, so sol doesn't lose conversational continuity on sneeze. tool call results now logged with preview + length for debugging. reset_all() clears both in-memory and sqlite conversation state.
This commit is contained in:
@@ -146,7 +146,7 @@ impl Responder {
|
||||
messages.push(ChatMessage::new_user_message(&trigger));
|
||||
}
|
||||
|
||||
let tool_defs = ToolRegistry::tool_definitions();
|
||||
let tool_defs = ToolRegistry::tool_definitions(self.tools.has_gitea());
|
||||
let model = Model::new(&self.config.mistral.default_model);
|
||||
let max_iterations = self.config.mistral.max_tool_iterations;
|
||||
|
||||
@@ -199,7 +199,17 @@ impl Responder {
|
||||
.await;
|
||||
|
||||
let result_str = match result {
|
||||
Ok(s) => s,
|
||||
Ok(s) => {
|
||||
let preview: String = s.chars().take(500).collect();
|
||||
info!(
|
||||
tool = tc.function.name.as_str(),
|
||||
id = call_id,
|
||||
result_len = s.len(),
|
||||
result_preview = preview.as_str(),
|
||||
"Tool call result"
|
||||
);
|
||||
s
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(tool = tc.function.name.as_str(), "Tool failed: {e}");
|
||||
format!("Error: {e}")
|
||||
@@ -261,6 +271,7 @@ impl Responder {
|
||||
trigger_body: &str,
|
||||
trigger_sender: &str,
|
||||
room_id: &str,
|
||||
room_name: &str,
|
||||
is_dm: bool,
|
||||
is_spontaneous: bool,
|
||||
mistral: &Arc<mistralai_client::v1::client::Client>,
|
||||
@@ -268,6 +279,7 @@ impl Responder {
|
||||
response_ctx: &ResponseContext,
|
||||
conversation_registry: &ConversationRegistry,
|
||||
image_data_uri: Option<&str>,
|
||||
context_hint: Option<String>,
|
||||
) -> Option<String> {
|
||||
// Apply response delay
|
||||
if !self.config.behavior.instant_responses {
|
||||
@@ -287,20 +299,46 @@ impl Responder {
|
||||
|
||||
let _ = room.typing_notice(true).await;
|
||||
|
||||
// Build the input message (with sender prefix for group rooms)
|
||||
let input_text = if is_dm {
|
||||
// Pre-response memory query (same as legacy path)
|
||||
let memory_notes = self.load_memory_notes(response_ctx, trigger_body).await;
|
||||
|
||||
// Build the input message with dynamic context header.
|
||||
// Agent instructions are static (set at creation), so per-message context
|
||||
// (timestamps, room, members, memory) is prepended to each user message.
|
||||
let now = chrono::Utc::now();
|
||||
let epoch_ms = now.timestamp_millis();
|
||||
let ts_1h = (now - chrono::Duration::hours(1)).timestamp_millis();
|
||||
let ts_yesterday = (now - chrono::Duration::days(1)).timestamp_millis();
|
||||
let ts_last_week = (now - chrono::Duration::days(7)).timestamp_millis();
|
||||
|
||||
let mut context_header = format!(
|
||||
"[context: date={}, epoch_ms={}, ts_1h_ago={}, ts_yesterday={}, ts_last_week={}, room={}, room_name={}]",
|
||||
now.format("%Y-%m-%d"),
|
||||
epoch_ms,
|
||||
ts_1h,
|
||||
ts_yesterday,
|
||||
ts_last_week,
|
||||
room_id,
|
||||
room_name,
|
||||
);
|
||||
|
||||
if let Some(ref notes) = memory_notes {
|
||||
context_header.push('\n');
|
||||
context_header.push_str(notes);
|
||||
}
|
||||
|
||||
let user_msg = if is_dm {
|
||||
trigger_body.to_string()
|
||||
} else {
|
||||
format!("<{}> {}", response_ctx.matrix_user_id, trigger_body)
|
||||
};
|
||||
|
||||
// TODO: multimodal via image_data_uri — Conversations API may support
|
||||
// content parts in entries. For now, append image description request.
|
||||
let input_text = format!("{context_header}\n{user_msg}");
|
||||
let input = ConversationInput::Text(input_text);
|
||||
|
||||
// Send through conversation registry
|
||||
let response = match conversation_registry
|
||||
.send_message(room_id, input, is_dm, mistral)
|
||||
.send_message(room_id, input, is_dm, mistral, context_hint.as_deref())
|
||||
.await
|
||||
{
|
||||
Ok(r) => r,
|
||||
@@ -346,15 +384,23 @@ impl Responder {
|
||||
.await;
|
||||
|
||||
let result_str = match result {
|
||||
Ok(s) => s,
|
||||
Ok(s) => {
|
||||
let preview: String = s.chars().take(500).collect();
|
||||
info!(
|
||||
tool = fc.name.as_str(),
|
||||
id = call_id,
|
||||
result_len = s.len(),
|
||||
result_preview = preview.as_str(),
|
||||
"Tool call result (conversations)"
|
||||
);
|
||||
s
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(tool = fc.name.as_str(), "Tool failed: {e}");
|
||||
format!("Error: {e}")
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
result_entries.push(ConversationEntry::FunctionResult(FunctionResultEntry {
|
||||
tool_call_id: call_id.to_string(),
|
||||
result: result_str,
|
||||
|
||||
Reference in New Issue
Block a user