#[non_exhaustive]pub enum LoopEvent {
Show 15 variants
TextDelta(String),
ReasoningDelta(String),
ToolCallStart {
index: u32,
id: String,
name: String,
},
ToolCallDelta {
index: u32,
json_chunk: String,
},
ToolCallComplete {
index: u32,
call: ToolCall,
},
Usage(Usage),
IterationStart {
iteration: u32,
message_count: usize,
},
ToolExecutionStart {
call_id: String,
tool_name: String,
arguments: Value,
},
ToolExecutionEnd {
call_id: String,
tool_name: String,
result: ToolResult,
duration: Duration,
},
ToolResultProcessed {
tool_name: String,
original_tokens: u32,
processed_tokens: u32,
},
ToolResultExtracted {
tool_name: String,
original_tokens: u32,
extracted_tokens: u32,
},
ToolResultCached {
tool_name: String,
original_tokens: u32,
summary_tokens: u32,
},
ObservationsMasked {
masked_count: usize,
tokens_saved: u32,
},
LoopDetected {
tool_name: String,
consecutive_count: u32,
action: LoopAction,
},
Done(ToolLoopResult),
}Expand description
Unified event emitted during tool loop execution.
LoopEvent merges LLM streaming events (text deltas, tool call fragments)
with loop-level lifecycle events (iteration boundaries, tool execution
progress) into a single stream. This gives consumers a complete, ordered
view of everything happening inside the loop.
The stream terminates with Done carrying the final
ToolLoopResult.
§Example
use llm_stack::tool::{tool_loop_stream, ToolLoopConfig, LoopEvent};
use futures::StreamExt;
use std::sync::Arc;
let mut stream = tool_loop_stream(provider, registry, params, ToolLoopConfig::default(), Arc::new(()));
while let Some(event) = stream.next().await {
match event.unwrap() {
LoopEvent::TextDelta(text) => print!("{text}"),
LoopEvent::IterationStart { iteration, .. } => {
println!("\n--- Iteration {iteration} ---");
}
LoopEvent::ToolExecutionStart { tool_name, .. } => {
println!("[calling {tool_name}...]");
}
LoopEvent::ToolExecutionEnd { tool_name, duration, .. } => {
println!("[{tool_name} completed in {duration:?}]");
}
LoopEvent::Done(result) => {
println!("\nDone: {:?}", result.termination_reason);
break;
}
_ => {}
}
}Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
TextDelta(String)
A fragment of the model’s text output.
ReasoningDelta(String)
A fragment of the model’s reasoning (chain-of-thought) output.
ToolCallStart
Announces that a new tool call has started.
Fields
ToolCallDelta
A JSON fragment of the tool call’s arguments.
Fields
ToolCallComplete
The fully assembled tool call, ready to execute.
Fields
Usage(Usage)
Token usage information for this LLM call.
IterationStart
A new iteration of the tool loop is starting.
Fields
ToolExecutionStart
About to execute a tool.
When parallel_tool_execution is true, events arrive in completion
order (whichever tool finishes first), not the order the LLM listed
the calls. Use call_id to correlate start/end pairs.
Fields
ToolExecutionEnd
Tool execution completed.
When parallel_tool_execution is true, events arrive in completion
order. Use call_id to correlate with the corresponding
ToolExecutionStart.
Fields
result: ToolResultThe result from the tool.
ToolResultProcessed
A tool result was post-processed (compressed, truncated, etc.).
Emitted when a ToolResultProcessor
modifies a tool’s output before it enters the conversation context.
Use this for monitoring compression ratios and token savings.
Fields
ToolResultExtracted
A tool result was semantically extracted (condensed by an LLM).
Emitted when a ToolResultExtractor
condenses a large tool result into task-relevant content using an
async extraction call (typically a fast/cheap LLM like Haiku).
Fields
ToolResultCached
A tool result was cached out-of-context.
Emitted when a ToolResultCacher stores
an oversized result externally and replaces it with a compact summary.
Fields
ObservationsMasked
Old tool results were masked before an LLM call.
Emitted when observation masking replaces old tool results with compact placeholders to reduce context size. The full results may still be available in the result cache.
Fields
LoopDetected
A tool call loop was detected.
Emitted when the same tool is called with identical arguments
for threshold consecutive times. Only emitted when
LoopDetectionConfig is configured.
Fields
action: LoopActionThe action being taken in response.
Done(ToolLoopResult)
The loop has finished. Carries the final ToolLoopResult
with the accumulated response, usage, iteration count, and
termination reason.