mod common;
use common::MockLlmClient;
use llm_worker::Worker;
use llm_worker::llm_client::event::{Event, ResponseStatus, StatusEvent};
use llm_worker::{Message, MessageContent};
#[test]
fn test_mutable_set_system_prompt() {
let client = MockLlmClient::new(vec![]);
let mut worker = Worker::new(client);
assert!(worker.get_system_prompt().is_none());
worker.set_system_prompt("You are a helpful assistant.");
assert_eq!(
worker.get_system_prompt(),
Some("You are a helpful assistant.")
);
}
#[test]
fn test_mutable_history_manipulation() {
let client = MockLlmClient::new(vec![]);
let mut worker = Worker::new(client);
assert!(worker.history().is_empty());
worker.push_message(Message::user("Hello"));
worker.push_message(Message::assistant("Hi there!"));
assert_eq!(worker.history().len(), 2);
worker.history_mut().push(Message::user("How are you?"));
assert_eq!(worker.history().len(), 3);
worker.clear_history();
assert!(worker.history().is_empty());
let messages = vec![Message::user("Test"), Message::assistant("Response")];
worker.set_history(messages);
assert_eq!(worker.history().len(), 2);
}
#[test]
fn test_mutable_builder_pattern() {
let client = MockLlmClient::new(vec![]);
let worker = Worker::new(client)
.system_prompt("System prompt")
.with_message(Message::user("Hello"))
.with_message(Message::assistant("Hi!"))
.with_messages(vec![
Message::user("How are you?"),
Message::assistant("I'm fine!"),
]);
assert_eq!(worker.get_system_prompt(), Some("System prompt"));
assert_eq!(worker.history().len(), 4);
}
#[test]
fn test_mutable_extend_history() {
let client = MockLlmClient::new(vec![]);
let mut worker = Worker::new(client);
worker.push_message(Message::user("First"));
worker.extend_history(vec![
Message::assistant("Response 1"),
Message::user("Second"),
Message::assistant("Response 2"),
]);
assert_eq!(worker.history().len(), 4);
}
#[test]
fn test_lock_transition() {
let client = MockLlmClient::new(vec![]);
let mut worker = Worker::new(client);
worker.set_system_prompt("System");
worker.push_message(Message::user("Hello"));
worker.push_message(Message::assistant("Hi"));
let locked_worker = worker.lock();
assert_eq!(locked_worker.get_system_prompt(), Some("System"));
assert_eq!(locked_worker.history().len(), 2);
assert_eq!(locked_worker.locked_prefix_len(), 2);
}
#[test]
fn test_unlock_transition() {
let client = MockLlmClient::new(vec![]);
let mut worker = Worker::new(client);
worker.push_message(Message::user("Hello"));
let locked_worker = worker.lock();
let mut worker = locked_worker.unlock();
worker.push_message(Message::assistant("Hi"));
worker.clear_history();
assert!(worker.history().is_empty());
}
#[tokio::test]
async fn test_mutable_run_updates_history() {
let events = vec![
Event::text_block_start(0),
Event::text_delta(0, "Hello, I'm an assistant!"),
Event::text_block_stop(0, None),
Event::Status(StatusEvent {
status: ResponseStatus::Completed,
}),
];
let client = MockLlmClient::new(events);
let mut worker = Worker::new(client);
let result = worker.run("Hi there").await;
assert!(result.is_ok());
let history = worker.history();
assert_eq!(history.len(), 2);
assert!(matches!(
&history[0].content,
MessageContent::Text(t) if t == "Hi there"
));
assert!(matches!(
&history[1].content,
MessageContent::Text(t) if t == "Hello, I'm an assistant!"
));
}
#[tokio::test]
async fn test_locked_multi_turn_history_accumulation() {
let client = MockLlmClient::with_responses(vec![
vec![
Event::text_block_start(0),
Event::text_delta(0, "Nice to meet you!"),
Event::text_block_stop(0, None),
Event::Status(StatusEvent {
status: ResponseStatus::Completed,
}),
],
vec![
Event::text_block_start(0),
Event::text_delta(0, "I can help with that."),
Event::text_block_stop(0, None),
Event::Status(StatusEvent {
status: ResponseStatus::Completed,
}),
],
]);
let worker = Worker::new(client).system_prompt("You are helpful.");
let mut locked_worker = worker.lock();
assert_eq!(locked_worker.locked_prefix_len(), 0);
let result1 = locked_worker.run("Hello!").await;
assert!(result1.is_ok());
assert_eq!(locked_worker.history().len(), 2);
let result2 = locked_worker.run("Can you help me?").await;
assert!(result2.is_ok());
assert_eq!(locked_worker.history().len(), 4);
let history = locked_worker.history();
assert!(matches!(&history[0].content, MessageContent::Text(t) if t == "Hello!"));
assert!(matches!(&history[1].content, MessageContent::Text(t) if t == "Nice to meet you!"));
assert!(matches!(&history[2].content, MessageContent::Text(t) if t == "Can you help me?"));
assert!(matches!(&history[3].content, MessageContent::Text(t) if t == "I can help with that."));
}
#[tokio::test]
async fn test_locked_prefix_len_tracking() {
let client = MockLlmClient::with_responses(vec![
vec![
Event::text_block_start(0),
Event::text_delta(0, "Response 1"),
Event::text_block_stop(0, None),
Event::Status(StatusEvent {
status: ResponseStatus::Completed,
}),
],
vec![
Event::text_block_start(0),
Event::text_delta(0, "Response 2"),
Event::text_block_stop(0, None),
Event::Status(StatusEvent {
status: ResponseStatus::Completed,
}),
],
]);
let mut worker = Worker::new(client);
worker.push_message(Message::user("Pre-existing message 1"));
worker.push_message(Message::assistant("Pre-existing response 1"));
assert_eq!(worker.history().len(), 2);
let mut locked_worker = worker.lock();
assert_eq!(locked_worker.locked_prefix_len(), 2);
locked_worker.run("New message").await.unwrap();
assert_eq!(locked_worker.history().len(), 4); assert_eq!(locked_worker.locked_prefix_len(), 2); }
#[tokio::test]
async fn test_turn_count_increment() {
let client = MockLlmClient::with_responses(vec![
vec![
Event::text_block_start(0),
Event::text_delta(0, "Turn 1"),
Event::text_block_stop(0, None),
Event::Status(StatusEvent {
status: ResponseStatus::Completed,
}),
],
vec![
Event::text_block_start(0),
Event::text_delta(0, "Turn 2"),
Event::text_block_stop(0, None),
Event::Status(StatusEvent {
status: ResponseStatus::Completed,
}),
],
]);
let mut worker = Worker::new(client);
assert_eq!(worker.turn_count(), 0);
worker.run("First").await.unwrap();
assert_eq!(worker.turn_count(), 1);
worker.run("Second").await.unwrap();
assert_eq!(worker.turn_count(), 2);
}
#[tokio::test]
async fn test_unlock_edit_relock() {
let client = MockLlmClient::with_responses(vec![vec![
Event::text_block_start(0),
Event::text_delta(0, "Response"),
Event::text_block_stop(0, None),
Event::Status(StatusEvent {
status: ResponseStatus::Completed,
}),
]]);
let worker = Worker::new(client)
.with_message(Message::user("Hello"))
.with_message(Message::assistant("Hi"));
let locked = worker.lock();
assert_eq!(locked.locked_prefix_len(), 2);
let mut unlocked = locked.unlock();
unlocked.clear_history();
unlocked.push_message(Message::user("Fresh start"));
let relocked = unlocked.lock();
assert_eq!(relocked.history().len(), 1);
assert_eq!(relocked.locked_prefix_len(), 1);
}
#[test]
fn test_system_prompt_preserved_in_locked_state() {
let client = MockLlmClient::new(vec![]);
let worker = Worker::new(client).system_prompt("Important system prompt");
let locked = worker.lock();
assert_eq!(locked.get_system_prompt(), Some("Important system prompt"));
let unlocked = locked.unlock();
assert_eq!(
unlocked.get_system_prompt(),
Some("Important system prompt")
);
}
#[test]
fn test_system_prompt_change_after_unlock() {
let client = MockLlmClient::new(vec![]);
let worker = Worker::new(client).system_prompt("Original prompt");
let locked = worker.lock();
let mut unlocked = locked.unlock();
unlocked.set_system_prompt("New prompt");
assert_eq!(unlocked.get_system_prompt(), Some("New prompt"));
let relocked = unlocked.lock();
assert_eq!(relocked.get_system_prompt(), Some("New prompt"));
}