cargo fmt

This commit is contained in:
2026-04-14 03:13:36 +09:00
parent 7ec6e88605
commit a0a9df11c0
45 changed files with 389 additions and 351 deletions
+1 -1
View File
@@ -41,6 +41,7 @@ use tracing_subscriber::EnvFilter;
use clap::{Parser, ValueEnum};
use llm_worker::{
Worker,
interceptor::{Interceptor, PostToolAction, ToolResultInfo},
llm_client::{
LlmClient,
providers::{
@@ -48,7 +49,6 @@ use llm_worker::{
openai::OpenAIClient,
},
},
interceptor::{Interceptor, PostToolAction, ToolResultInfo},
timeline::{Handler, TextBlockEvent, TextBlockKind, ToolUseBlockEvent, ToolUseBlockKind},
};
use llm_worker_macros::tool_registry;
+1 -1
View File
@@ -9,8 +9,8 @@ use std::sync::Arc;
use async_trait::async_trait;
use crate::tool::{Tool, ToolCall, ToolMeta, ToolResult};
use crate::Item;
use crate::tool::{Tool, ToolCall, ToolMeta, ToolResult};
// =============================================================================
// Action Enums
+2 -2
View File
@@ -43,8 +43,8 @@ mod worker;
pub(crate) mod callback;
pub mod event;
pub mod llm_client;
pub mod interceptor;
pub mod llm_client;
pub mod prune;
pub mod state;
pub mod timeline;
@@ -53,7 +53,7 @@ pub mod tool_server;
pub use callback::{TextBlockScope, ToolUseBlockScope};
pub use handler::ToolUseBlockStart;
pub use message::{ContentPart, Item, Message, Role};
pub use interceptor::Interceptor;
pub use message::{ContentPart, Item, Message, Role};
pub use tool::{ToolCall, ToolResult};
pub use worker::{RunOutput, ToolRegistryError, Worker, WorkerConfig, WorkerError, WorkerResult};
@@ -182,7 +182,10 @@ impl AnthropicScheme {
}
Item::ToolResult {
call_id, summary, content, ..
call_id,
summary,
content,
..
} => {
// Flush pending assistant parts first
if !pending_assistant_parts.is_empty() {
@@ -257,7 +257,10 @@ impl GeminiScheme {
}
Item::ToolResult {
call_id, summary, content, ..
call_id,
summary,
content,
..
} => {
// Flush pending model parts first
if !pending_model_parts.is_empty() {
@@ -212,7 +212,10 @@ impl OpenAIScheme {
}
Item::ToolResult {
call_id, summary, content, ..
call_id,
summary,
content,
..
} => {
// Flush pending tool calls before tool result
self.flush_pending_assistant(
+4 -1
View File
@@ -191,7 +191,10 @@ mod tests {
assert_eq!(count, 2);
for item in &items {
if let Item::ToolResult { summary, content, .. } = item {
if let Item::ToolResult {
summary, content, ..
} = item
{
if summary == "s1" || summary == "s2" {
assert!(content.is_none(), "old content should be projected out");
} else {
+1 -7
View File
@@ -56,13 +56,7 @@ impl From<String> for ToolOutput {
}
} else {
let lines = s.lines().count();
let first_line: String = s
.lines()
.next()
.unwrap_or("")
.chars()
.take(80)
.collect();
let first_line: String = s.lines().next().unwrap_or("").chars().take(80).collect();
let summary = format!("{lines} lines | {first_line}");
ToolOutput {
summary,
+6 -5
View File
@@ -65,10 +65,7 @@ impl ToolServerHandle {
}
/// Queue many tool factories for deferred initialization.
pub(crate) fn register_tools(
&self,
factories: impl IntoIterator<Item = WorkerToolDefinition>,
) {
pub(crate) fn register_tools(&self, factories: impl IntoIterator<Item = WorkerToolDefinition>) {
let mut guard = self.pending.lock().unwrap_or_else(|e| e.into_inner());
guard.extend(factories);
}
@@ -110,7 +107,11 @@ impl ToolServerHandle {
}
/// Execute a tool by name.
pub async fn call_tool(&self, name: &str, input_json: &str) -> Result<ToolOutput, ToolServerError> {
pub async fn call_tool(
&self,
name: &str,
input_json: &str,
) -> Result<ToolOutput, ToolServerError> {
let tool = {
let guard = self.tools.lock().unwrap_or_else(|e| e.into_inner());
let (_, tool) = guard
+37 -70
View File
@@ -7,24 +7,23 @@ use tracing::{debug, info, trace, warn};
use crate::{
Item,
llm_client::{ClientError, ConfigWarning, LlmClient, Request, RequestConfig, ToolDefinition},
interceptor::{
DefaultInterceptor, Interceptor, PostToolAction, PreRequestAction, PreToolAction,
PromptAction, ToolCallInfo, ToolResultInfo, TurnEndAction,
},
state::{Locked, Mutable, WorkerState},
callback::{
ClosureMetaHandler, ClosureTextBlockHandler, ClosureToolUseBlockHandler, TextBlockScope,
ToolUseBlockScope,
},
handler::{ErrorKind, StatusKind, ToolUseBlockStart, UsageKind},
timeline::{TextBlockCollector, Timeline, ToolCallCollector},
interceptor::{
DefaultInterceptor, Interceptor, PostToolAction, PreRequestAction, PreToolAction,
PromptAction, ToolCallInfo, ToolResultInfo, TurnEndAction,
},
llm_client::{ClientError, ConfigWarning, LlmClient, Request, RequestConfig, ToolDefinition},
state::{Locked, Mutable, WorkerState},
timeline::event::{ErrorEvent, StatusEvent, UsageEvent},
timeline::{TextBlockCollector, Timeline, ToolCallCollector},
tool::{ToolCall, ToolDefinition as WorkerToolDefinition, ToolError, ToolResult},
tool_server::{ToolServer, ToolServerHandle},
};
/// Worker errors
#[derive(Debug, thiserror::Error)]
pub enum WorkerError {
@@ -53,7 +52,6 @@ pub enum ToolRegistryError {
DuplicateName(String),
}
/// Worker configuration
#[derive(Debug, Clone, Default)]
pub struct WorkerConfig {
@@ -61,7 +59,6 @@ pub struct WorkerConfig {
_private: (),
}
/// Worker execution result (status)
#[derive(Debug)]
pub enum WorkerResult {
@@ -95,7 +92,6 @@ enum ToolExecutionResult {
Paused,
}
/// Central component for managing LLM interactions
///
/// Receives input from the user, sends requests to the LLM, and
@@ -172,7 +168,6 @@ pub struct Worker<C: LlmClient, S: WorkerState = Mutable> {
_state: PhantomData<S>,
}
impl<C: LlmClient, S: WorkerState> Worker<C, S> {
fn reset_interruption_state(&mut self) {
self.last_run_interrupted = false;
@@ -214,10 +209,9 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
&mut self,
setup: impl FnMut(&mut TextBlockScope) + Send + Sync + 'static,
) {
self.timeline
.on_text_block(ClosureTextBlockHandler {
setup: Box::new(setup),
});
self.timeline.on_text_block(ClosureTextBlockHandler {
setup: Box::new(setup),
});
}
/// Register a tool use block observer with scoped callbacks.
@@ -240,17 +234,13 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
&mut self,
setup: impl FnMut(&ToolUseBlockStart, &mut ToolUseBlockScope) + Send + Sync + 'static,
) {
self.timeline
.on_tool_use_block(ClosureToolUseBlockHandler {
setup: Box::new(setup),
});
self.timeline.on_tool_use_block(ClosureToolUseBlockHandler {
setup: Box::new(setup),
});
}
/// Register a usage event callback.
pub fn on_usage(
&mut self,
callback: impl FnMut(&UsageEvent) + Send + Sync + 'static,
) {
pub fn on_usage(&mut self, callback: impl FnMut(&UsageEvent) + Send + Sync + 'static) {
self.timeline.on_usage(ClosureMetaHandler {
callback,
_kind: PhantomData::<UsageKind>,
@@ -258,10 +248,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
}
/// Register a status event callback.
pub fn on_status(
&mut self,
callback: impl FnMut(&StatusEvent) + Send + Sync + 'static,
) {
pub fn on_status(&mut self, callback: impl FnMut(&StatusEvent) + Send + Sync + 'static) {
self.timeline.on_status(ClosureMetaHandler {
callback,
_kind: PhantomData::<StatusKind>,
@@ -269,10 +256,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
}
/// Register an error event callback.
pub fn on_error(
&mut self,
callback: impl FnMut(&ErrorEvent) + Send + Sync + 'static,
) {
pub fn on_error(&mut self, callback: impl FnMut(&ErrorEvent) + Send + Sync + 'static) {
self.timeline.on_error(ClosureMetaHandler {
callback,
_kind: PhantomData::<ErrorKind>,
@@ -280,18 +264,12 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
}
/// Register a turn-start callback (receives 0-based turn number).
pub fn on_turn_start(
&mut self,
callback: impl Fn(usize) + Send + Sync + 'static,
) {
pub fn on_turn_start(&mut self, callback: impl Fn(usize) + Send + Sync + 'static) {
self.turn_start_cbs.push(Box::new(callback));
}
/// Register a turn-end callback (receives 0-based turn number).
pub fn on_turn_end(
&mut self,
callback: impl Fn(usize) + Send + Sync + 'static,
) {
pub fn on_turn_end(&mut self, callback: impl Fn(usize) + Send + Sync + 'static) {
self.turn_end_cbs.push(Box::new(callback));
}
@@ -735,9 +713,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
// prunable candidates whose estimated savings meet the
// threshold. Worker does not own usage history itself; the
// estimator is injected by the layer that does.
if let (Some(config), Some(estimator)) =
(&self.prune_config, &self.savings_estimator)
{
if let (Some(config), Some(estimator)) = (&self.prune_config, &self.savings_estimator) {
let candidates =
crate::prune::prunable_indices(&request_context, config.protected_turns);
if !candidates.is_empty() {
@@ -745,8 +721,7 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
let last = *candidates.last().unwrap() + 1;
let savings = estimator(&request_context, first..last);
if savings >= config.min_savings {
let pruned =
crate::prune::project(&mut request_context, &candidates);
let pruned = crate::prune::project(&mut request_context, &candidates);
if pruned > 0 {
debug!(
pruned,
@@ -817,7 +792,11 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
if let Some(max) = self.max_turns {
if self.turn_count >= max as usize {
info!(turn_count = self.turn_count, max_turns = max, "Turn limit reached");
info!(
turn_count = self.turn_count,
max_turns = max,
"Turn limit reached"
);
self.last_run_interrupted = false;
return Ok(WorkerResult::LimitReached);
}
@@ -911,10 +890,8 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
content,
));
} else {
self.history.push(Item::tool_result(
&result.tool_use_id,
&result.summary,
));
self.history
.push(Item::tool_result(&result.tool_use_id, &result.summary));
}
}
Ok(None)
@@ -925,10 +902,8 @@ impl<C: LlmClient, S: WorkerState> Worker<C, S> {
}
}
}
}
impl<C: LlmClient> Worker<C, Mutable> {
/// Create a new Worker (in Mutable state)
pub fn new(client: C) -> Self {
@@ -975,10 +950,7 @@ impl<C: LlmClient> Worker<C, Mutable> {
}
/// Register multiple tool factories for deferred initialization.
pub fn register_tools(
&mut self,
factories: impl IntoIterator<Item = WorkerToolDefinition>,
) {
pub fn register_tools(&mut self, factories: impl IntoIterator<Item = WorkerToolDefinition>) {
self.tool_server.register_tools(factories);
}
@@ -1086,45 +1058,38 @@ impl<C: LlmClient> Worker<C, Mutable> {
///
/// Available only in Mutable state.
pub fn history_mut(&mut self) -> &mut Vec<Item> {
&mut self.history
}
/// Set history
pub fn set_history(&mut self, items: Vec<Item>) {
self.history = items;
}
/// Add an item to history (builder pattern)
pub fn with_item(mut self, item: Item) -> Self {
self.history.push(item);
self
}
/// Add an item to history
pub fn push_item(&mut self, item: Item) {
self.history.push(item);
}
/// Add multiple items to history (builder pattern)
pub fn with_items(mut self, items: impl IntoIterator<Item = Item>) -> Self {
self.history.extend(items);
self
}
/// Add multiple items to history
pub fn extend_history(&mut self, items: impl IntoIterator<Item = Item>) {
self.history.extend(items);
}
/// Clear history
pub fn clear_history(&mut self) {
self.history.clear();
}
@@ -1156,13 +1121,13 @@ impl<C: LlmClient> Worker<C, Mutable> {
///
/// Subsequent runs can use [`Worker<C, Locked>::run()`] directly.
/// To edit state between turns, call [`unlock()`](Worker::unlock) first.
pub async fn run(
self,
user_input: impl Into<String>,
) -> Result<RunOutput<C>, WorkerError> {
pub async fn run(self, user_input: impl Into<String>) -> Result<RunOutput<C>, WorkerError> {
let mut locked = self.lock();
let result = locked.run(user_input).await?;
Ok(RunOutput { worker: locked, result })
Ok(RunOutput {
worker: locked,
result,
})
}
/// Resume from Paused, consuming self and transitioning to Locked.
@@ -1171,7 +1136,10 @@ impl<C: LlmClient> Worker<C, Mutable> {
pub async fn resume(self) -> Result<RunOutput<C>, WorkerError> {
let mut locked = self.lock();
let result = locked.resume().await?;
Ok(RunOutput { worker: locked, result })
Ok(RunOutput {
worker: locked,
result,
})
}
/// Lock and transition to Locked state
@@ -1216,7 +1184,6 @@ impl<C: LlmClient> Worker<C, Mutable> {
}
}
impl<C: LlmClient> Worker<C, Locked> {
/// Execute a turn
///
@@ -8,8 +8,10 @@ use std::time::{Duration, Instant};
use async_trait::async_trait;
use llm_worker::Worker;
use llm_worker::interceptor::{
Interceptor, PostToolAction, PreToolAction, ToolCallInfo, ToolResultInfo,
};
use llm_worker::llm_client::event::{Event, ResponseStatus, StatusEvent};
use llm_worker::interceptor::{Interceptor, PostToolAction, PreToolAction, ToolCallInfo, ToolResultInfo};
use llm_worker::tool::{Tool, ToolDefinition, ToolError, ToolMeta, ToolOutput};
mod common;
+18 -4
View File
@@ -77,8 +77,14 @@ async fn test_basic_tool_generation() {
let result = tool.execute(r#"{"message": "World"}"#).await;
assert!(result.is_ok(), "Should execute successfully");
let output = result.unwrap();
assert!(output.summary.contains("Hello"), "Output should contain prefix");
assert!(output.summary.contains("World"), "Output should contain message");
assert!(
output.summary.contains("Hello"),
"Output should contain prefix"
);
assert!(
output.summary.contains("World"),
"Output should contain message"
);
}
#[tokio::test]
@@ -94,7 +100,11 @@ async fn test_multiple_arguments() {
let result = tool.execute(r#"{"a": 10, "b": 20}"#).await;
assert!(result.is_ok());
let output = result.unwrap();
assert!(output.summary.contains("30"), "Should contain sum: {:?}", output);
assert!(
output.summary.contains("30"),
"Should contain sum: {:?}",
output
);
}
#[tokio::test]
@@ -168,7 +178,11 @@ async fn test_result_return_type_success() {
let result = tool.execute(r#"{"value": 42}"#).await;
assert!(result.is_ok(), "Should succeed for positive value");
let output = result.unwrap();
assert!(output.summary.contains("Valid"), "Should contain Valid: {:?}", output);
assert!(
output.summary.contains("Valid"),
"Should contain Valid: {:?}",
output
);
}
#[tokio::test]
+1 -1
View File
@@ -11,9 +11,9 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use async_trait::async_trait;
use common::MockLlmClient;
use llm_worker::Item;
use llm_worker::{Worker, WorkerError};
use llm_worker::llm_client::event::{Event, ResponseStatus, StatusEvent};
use llm_worker::tool::{Tool, ToolDefinition, ToolError, ToolMeta, ToolOutput};
use llm_worker::{Worker, WorkerError};
// =============================================================================
// Mutable State Tests