huskies: merge 828
This commit is contained in:
@@ -7,6 +7,7 @@ use crate::llm::types::{Message, Role, ToolDefinition};
|
||||
use crate::slog;
|
||||
use crate::state::SessionState;
|
||||
use crate::store::StoreOps;
|
||||
use chrono::Utc;
|
||||
use serde::Deserialize;
|
||||
|
||||
const MAX_TURNS: usize = 30;
|
||||
@@ -32,6 +33,17 @@ pub struct ChatResult {
|
||||
pub session_id: Option<String>,
|
||||
}
|
||||
|
||||
/// Prepend an ISO-8601 UTC timestamp to the content of the last user message.
|
||||
///
|
||||
/// Only the most-recent user message is annotated so that prior turns in the
|
||||
/// conversation history are not re-stamped on every call. Assistant, system,
|
||||
/// and tool messages are left untouched.
|
||||
fn inject_received_at(messages: &mut [Message], ts: &str) {
|
||||
if let Some(msg) = messages.iter_mut().rev().find(|m| m.role == Role::User) {
|
||||
msg.content = format!("[{ts}] {}", msg.content);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_anthropic_api_key_impl(store: &dyn StoreOps) -> Result<String, String> {
|
||||
match store.get(KEY_ANTHROPIC_API_KEY) {
|
||||
Some(value) => {
|
||||
@@ -103,7 +115,7 @@ pub fn cancel_chat(state: &SessionState) -> Result<(), String> {
|
||||
/// Run a multi-turn chat with tool calling against the configured provider.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn chat<F, U, T, A>(
|
||||
messages: Vec<Message>,
|
||||
mut messages: Vec<Message>,
|
||||
config: ProviderConfig,
|
||||
state: &SessionState,
|
||||
store: &dyn StoreOps,
|
||||
@@ -121,6 +133,12 @@ where
|
||||
use crate::llm::providers::anthropic::AnthropicProvider;
|
||||
use crate::llm::providers::ollama::OllamaProvider;
|
||||
|
||||
// Stamp the current user message with the wall-clock time at the transport
|
||||
// boundary (i.e. when this function is entered, which is immediately after
|
||||
// the WebSocket frame is received — before any LLM invocation).
|
||||
let received_at = Utc::now().format("%Y-%m-%dT%H:%M:%SZ").to_string();
|
||||
inject_received_at(&mut messages, &received_at);
|
||||
|
||||
let _ = state.cancel_tx.send(false);
|
||||
let mut cancel_rx = state.cancel_rx.clone();
|
||||
cancel_rx.borrow_and_update();
|
||||
@@ -474,6 +492,85 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// inject_received_at
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn inject_timestamp_into_last_user_message() {
|
||||
let mut messages = vec![Message {
|
||||
role: Role::User,
|
||||
content: "hello".to_string(),
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
}];
|
||||
inject_received_at(&mut messages, "2026-04-28T10:30:00Z");
|
||||
assert_eq!(messages[0].content, "[2026-04-28T10:30:00Z] hello");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inject_timestamp_only_last_user_message() {
|
||||
let mut messages = vec![
|
||||
Message {
|
||||
role: Role::User,
|
||||
content: "first".to_string(),
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
},
|
||||
Message {
|
||||
role: Role::Assistant,
|
||||
content: "reply".to_string(),
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
},
|
||||
Message {
|
||||
role: Role::User,
|
||||
content: "second".to_string(),
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
},
|
||||
];
|
||||
inject_received_at(&mut messages, "2026-04-28T10:30:00Z");
|
||||
// Only the last user message is stamped.
|
||||
assert_eq!(messages[0].content, "first");
|
||||
assert_eq!(messages[1].content, "reply");
|
||||
assert_eq!(messages[2].content, "[2026-04-28T10:30:00Z] second");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inject_timestamp_skips_assistant_messages() {
|
||||
let mut messages = vec![Message {
|
||||
role: Role::Assistant,
|
||||
content: "bot reply".to_string(),
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
}];
|
||||
inject_received_at(&mut messages, "2026-04-28T10:30:00Z");
|
||||
// No user message — nothing changes.
|
||||
assert_eq!(messages[0].content, "bot reply");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inject_timestamp_does_not_stamp_system_messages() {
|
||||
let mut messages = vec![
|
||||
Message {
|
||||
role: Role::System,
|
||||
content: "sys".to_string(),
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
},
|
||||
Message {
|
||||
role: Role::User,
|
||||
content: "hello".to_string(),
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
},
|
||||
];
|
||||
inject_received_at(&mut messages, "2026-04-28T10:30:00Z");
|
||||
assert_eq!(messages[0].content, "sys");
|
||||
assert_eq!(messages[1].content, "[2026-04-28T10:30:00Z] hello");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// cancel_chat
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user