OpenRouter Support, Insight Chat and User injection #56

Merged
cameron merged 24 commits from 005-llm-client-trait into master 2026-04-26 23:01:35 +00:00
Showing only changes of commit 0e55a6b125 - Show all commits

View File

@@ -1071,8 +1071,13 @@ fn is_rendered(m: &ChatMessage) -> bool {
/// Given a rendered index to start discarding from, find the raw index at /// Given a rendered index to start discarding from, find the raw index at
/// which to truncate. The cut position is the raw length after all prior /// which to truncate. The cut position is the raw length after all prior
/// rendered messages — which also strips any tool-call scaffolding that /// rendered messages — which also strips any tool-call scaffolding that
/// immediately precedes the discarded rendered message. Returns `None` if /// immediately precedes the discarded rendered message.
/// `discard_from_rendered_index` is past the end of the rendered view. ///
/// Discarding *at* the end (`discard == rendered_count`) is a no-op success:
/// returns `Some(messages.len())`. The mobile client hits this when
/// regenerating after a failed turn — its optimistic user bubble lives at
/// the index just past the server's persisted history. Strictly past the end
/// (`discard > rendered_count`) returns `None`.
pub(crate) fn find_raw_cut( pub(crate) fn find_raw_cut(
messages: &[ChatMessage], messages: &[ChatMessage],
discard_from_rendered_index: usize, discard_from_rendered_index: usize,
@@ -1089,10 +1094,8 @@ pub(crate) fn find_raw_cut(
rendered_count += 1; rendered_count += 1;
last_kept_raw_end = i + 1; last_kept_raw_end = i + 1;
} }
if rendered_count == discard_from_rendered_index { if discard_from_rendered_index == rendered_count {
// Discarding past the last rendered message is a no-op, but we return Some(messages.len());
// surface it as "nothing to cut" rather than silent success.
return None;
} }
None None
} }
@@ -1361,4 +1364,18 @@ mod tests {
let msgs = vec![ChatMessage::user("q1"), assistant_text("a1")]; let msgs = vec![ChatMessage::user("q1"), assistant_text("a1")];
assert!(find_raw_cut(&msgs, 5).is_none()); assert!(find_raw_cut(&msgs, 5).is_none());
} }
#[test]
fn rewind_at_end_is_noop_success() {
// Mobile client retries after a failed turn that never persisted —
// its optimistic user bubble's index equals the server's rendered
// count. Should resolve to "no cut" rather than an out-of-range error.
let msgs = vec![
ChatMessage::system("s"),
ChatMessage::user("q1"),
assistant_text("a1"),
];
let cut = find_raw_cut(&msgs, 2).expect("boundary cut should succeed");
assert_eq!(cut, msgs.len());
}
} }