huskies: merge 1127 story Migrate all LLM-invoking transports onto assemble_prompt_context; delete legacy Vec
This commit is contained in:
@@ -13,7 +13,7 @@ use super::super::context::BotContext;
|
||||
use super::super::format::markdown_to_html;
|
||||
use super::super::history::{ConversationEntry, ConversationRole, save_history};
|
||||
|
||||
use super::{format_drained_events, format_user_prompt};
|
||||
use super::format_user_prompt;
|
||||
|
||||
pub(in crate::chat::transport::matrix::bot) async fn handle_message(
|
||||
room_id_str: String,
|
||||
@@ -31,29 +31,6 @@ pub(in crate::chat::transport::matrix::bot) async fn handle_message(
|
||||
guard.get(&room_id).and_then(|conv| conv.session_id.clone())
|
||||
};
|
||||
|
||||
// Drain pipeline and gateway transition events buffered since the last LLM
|
||||
// turn and prepend them as a passive <system-reminder> block so Timmy sees
|
||||
// pipeline activity without requiring a separate message. Sled events come
|
||||
// from `pending_pipeline_events`; gateway events from `pending_gateway_events`.
|
||||
// In practice only one buffer is non-empty (sled mode vs gateway mode).
|
||||
let system_reminder_prefix = {
|
||||
let mut sled_guard = ctx.pending_pipeline_events.lock().await;
|
||||
let mut gtw_guard = ctx.pending_gateway_events.lock().await;
|
||||
let all_lines: Vec<String> = sled_guard.drain(..).chain(gtw_guard.drain(..)).collect();
|
||||
drop(sled_guard);
|
||||
drop(gtw_guard);
|
||||
slog!(
|
||||
"[matrix-bot] drained {} gateway audit lines for LLM context",
|
||||
all_lines.len()
|
||||
);
|
||||
let prefix = format_drained_events(all_lines);
|
||||
slog!(
|
||||
"[matrix-bot] format_drained_events output: {} bytes",
|
||||
prefix.len()
|
||||
);
|
||||
prefix
|
||||
};
|
||||
|
||||
// Pull new pipeline-transition events from the CRDT event log for this
|
||||
// session and atomically advance the high-water marks so the same events
|
||||
// are not re-injected on the next turn.
|
||||
@@ -69,7 +46,7 @@ pub(in crate::chat::transport::matrix::bot) async fn handle_message(
|
||||
String::new()
|
||||
};
|
||||
let prompt = format!(
|
||||
"{system_reminder_prefix}{event_log_ctx}[Your name is {bot_name}. Refer to yourself as {bot_name}, not Claude.]\n{active_project_ctx}\n{}",
|
||||
"{event_log_ctx}[Your name is {bot_name}. Refer to yourself as {bot_name}, not Claude.]\n{active_project_ctx}\n{}",
|
||||
format_user_prompt(&sender, &user_message)
|
||||
);
|
||||
|
||||
|
||||
@@ -11,27 +11,6 @@ pub(super) fn format_user_prompt(sender: &str, message: &str) -> String {
|
||||
format!("{sender}: {message}")
|
||||
}
|
||||
|
||||
/// Drain `lines` into a `<system-reminder>` block for injection at the head of
|
||||
/// the next LLM prompt. Returns an empty string when `lines` is empty.
|
||||
///
|
||||
/// At most 20 lines are shown verbatim; excess lines are replaced with a
|
||||
/// `…and N more` indicator to keep context size bounded.
|
||||
pub(in crate::chat::transport::matrix::bot) fn format_drained_events(lines: Vec<String>) -> String {
|
||||
if lines.is_empty() {
|
||||
return String::new();
|
||||
}
|
||||
const MAX_PIPELINE_EVENTS: usize = 20;
|
||||
let total = lines.len();
|
||||
let shown_count = total.min(MAX_PIPELINE_EVENTS);
|
||||
let shown = lines[..shown_count].join("\n");
|
||||
let tail = if total > MAX_PIPELINE_EVENTS {
|
||||
format!("\n...and {} more", total - MAX_PIPELINE_EVENTS)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
format!("<system-reminder>\n{shown}{tail}\n</system-reminder>\n")
|
||||
}
|
||||
|
||||
/// Matrix event handler for room messages. Each invocation spawns an
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@@ -72,49 +51,6 @@ mod tests {
|
||||
assert!(crate::llm::oauth::extract_login_url_from_error(err).is_none());
|
||||
}
|
||||
|
||||
// -- format_drained_events ----------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn format_drained_events_empty_returns_empty_string() {
|
||||
assert_eq!(format_drained_events(vec![]), String::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_drained_events_wraps_in_system_reminder() {
|
||||
let result = format_drained_events(vec!["audit ts=2026 id=1 event=x".to_string()]);
|
||||
assert!(result.starts_with("<system-reminder>\n"), "got: {result}");
|
||||
assert!(result.ends_with("</system-reminder>\n"), "got: {result}");
|
||||
assert!(
|
||||
result.contains("audit ts=2026 id=1 event=x"),
|
||||
"got: {result}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_drained_events_caps_at_20_with_overflow_indicator() {
|
||||
let lines: Vec<String> = (0..25).map(|i| format!("line {i}")).collect();
|
||||
let result = format_drained_events(lines);
|
||||
assert!(result.contains("...and 5 more"), "got: {result}");
|
||||
assert!(
|
||||
result.contains("line 19"),
|
||||
"last shown line missing; got: {result}"
|
||||
);
|
||||
assert!(
|
||||
!result.contains("line 20"),
|
||||
"line 21 must be hidden; got: {result}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_drained_events_exactly_20_no_overflow_indicator() {
|
||||
let lines: Vec<String> = (0..20).map(|i| format!("line {i}")).collect();
|
||||
let result = format_drained_events(lines);
|
||||
assert!(
|
||||
!result.contains("...and"),
|
||||
"must not show overflow when exactly 20; got: {result}"
|
||||
);
|
||||
}
|
||||
|
||||
// -- bot_name / system prompt -------------------------------------------
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user