- Implemented `Edit` and `McpAdd` commands in the command parser and handler. - Added a new `stream` module to the runtime for handling streaming events. - Enhanced `SseParser` to parse usage information from SSE events. - Introduced `ToolCallAccumulator` for tracking tool calls independently. - Updated `AppStateRest` to include `app_config` and `MiscState` to track `effort_level` and `selected_index`. - Modified `LlmClient` to support streaming responses with usage tracking. - Improved error handling and retry logic in the streaming API calls. - Added tests for new features and improved markdown rendering in the chat view.
79 lines
2.1 KiB
Rust
79 lines
2.1 KiB
Rust
use super::turn::ParsedToolCall;
|
|
use serde_json::{json, Value};
|
|
|
|
/// Standalone tool-call delta accumulator, functionally equivalent to the accumulation
|
|
/// logic built into `StreamedTurn::apply_event`. Reserved for callers that want to track
|
|
/// tool-call deltas independently of a full `StreamedTurn` (e.g. a lighter-weight preview).
|
|
#[allow(dead_code)]
|
|
pub struct ToolCallAccumulator {
|
|
calls: Vec<ParsedToolCall>,
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
impl ToolCallAccumulator {
|
|
pub fn new() -> Self {
|
|
ToolCallAccumulator { calls: Vec::new() }
|
|
}
|
|
|
|
pub fn add_delta(
|
|
&mut self,
|
|
index: usize,
|
|
id: Option<&str>,
|
|
name: Option<&str>,
|
|
arguments_delta: &str,
|
|
) {
|
|
while self.calls.len() <= index {
|
|
self.calls.push(ParsedToolCall {
|
|
id: String::new(),
|
|
name: String::new(),
|
|
arguments: String::new(),
|
|
is_complete: false,
|
|
});
|
|
}
|
|
let tc = &mut self.calls[index];
|
|
if let Some(new_id) = id {
|
|
if !new_id.is_empty() {
|
|
tc.id = new_id.to_string();
|
|
}
|
|
}
|
|
if let Some(new_name) = name {
|
|
if !new_name.is_empty() {
|
|
tc.name = new_name.to_string();
|
|
}
|
|
}
|
|
tc.arguments.push_str(arguments_delta);
|
|
}
|
|
|
|
pub fn calls(&self) -> &[ParsedToolCall] {
|
|
&self.calls
|
|
}
|
|
|
|
pub fn is_complete(&self) -> bool {
|
|
!self.calls.is_empty() && self.calls.iter().all(|tc| !tc.name.is_empty() && !tc.arguments.is_empty())
|
|
}
|
|
|
|
pub fn reset(&mut self) {
|
|
self.calls.clear();
|
|
}
|
|
|
|
pub fn pending_args(&self) -> Vec<Value> {
|
|
self.calls
|
|
.iter()
|
|
.filter(|tc| !tc.name.is_empty())
|
|
.map(|tc| {
|
|
json!({
|
|
"tool_call_id": tc.id,
|
|
"name": tc.name,
|
|
"arguments": tc.arguments,
|
|
})
|
|
})
|
|
.collect()
|
|
}
|
|
}
|
|
|
|
impl Default for ToolCallAccumulator {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|