1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//! Capability traits for the agent loop runtime.
//!
//! Each trait represents a single infrastructure capability that the
//! agent loop can depend on. [`LoopRuntime`](crate::runtime::LoopRuntime)
//! implements all of them, but consumers can narrow their bounds to
//! only the capabilities they need.
//!
//! # Traits
//!
//! | Trait | Purpose |
//! |-------|---------|
//! | [`Observable`] | Lifecycle event observation |
//! | [`Detectable`] | Loop and convergence detection |
//! | [`FallbackCapable`] | Model fallback / circuit breaker |
//! | [`Compactable`] | Context compaction |
//! | [`StreamCapable`] | Resilient LLM streaming |
//! | [`Hookable`] | Bidirectional lifecycle hooks |
//! | [`PipelineAware`] | Middleware pipeline dispatch |
//! | [`HealthTrackable`] | Per-tool health monitoring *(requires `tool_health` feature)* |
//!
//! # When to use
//!
//! Use these traits as bounds when you need a specific capability
//! without pulling in the full [`LoopRuntime`](crate::runtime::LoopRuntime):
//!
//! ```rust,ignore
//! fn check_patterns(runtime: &impl Detectable) {
//! let pattern = runtime.detection().record_tool_call("Read", hash);
//! }
//! ```
use Arc;
use crateContextManager;
use crateDetectionManager;
use crateFallbackManager;
use crateHookExecutor;
use crateToolPipeline;
use crateObserverHost;
use crateStreamHandler;
use crateToolHealthRegistry;
// ==================================================
// Capability Traits
// ==================================================
/// Capability to emit lifecycle events to registered observers.
///
/// Observers receive read-only notifications at well-defined hook points
/// in the agent loop. They cannot influence control flow — for that, see
/// [`Hookable`].
///
/// # Implementors
///
/// - [`LoopRuntime`](crate::runtime::LoopRuntime) — the framework's default implementation.
///
/// # When to use
///
/// Use this trait bound when you need to notify observers of lifecycle
/// events but don't need any other infrastructure capabilities.
///
/// ```rust,ignore
/// fn process_turn(runtime: &impl Observable) {
/// runtime.observers().on_turn_start(&ctx);
/// // ... do work ...
/// runtime.observers().on_turn_end(&ctx);
/// }
/// ```
/// Capability to detect repetitive loops and semantic convergence.
///
/// Loop detection catches when the agent repeats the same tool operations
/// in a cycle. Convergence detection catches when successive assistant
/// responses become semantically similar. Both are handled by
/// [`DetectionManager`].
///
/// # Implementors
///
/// - [`LoopRuntime`](crate::runtime::LoopRuntime) — the framework's default implementation.
///
/// # When to use
///
/// Use this trait bound when you need to record operations or responses
/// and check whether a loop or convergence pattern has been detected.
///
/// ```rust,ignore
/// fn check_patterns(runtime: &impl Detectable) {
/// let pattern = runtime.detection().record_tool_call("Read", hash);
/// if let DetectedPattern::LoopDetected { .. } = pattern {
/// // intervention needed
/// }
/// }
/// ```
/// Capability to fall back to an alternate model when the primary fails.
///
/// Wraps a [`FallbackManager`] that acts as a circuit breaker: after
/// consecutive API failures exceed a threshold, requests are rerouted
/// to a fallback model until the primary stabilises.
///
/// # Implementors
///
/// - [`LoopRuntime`](crate::runtime::LoopRuntime) — the framework's default implementation.
///
/// # When to use
///
/// Use this trait bound when you need to record API failures or check
/// whether the circuit breaker has tripped.
///
/// ```rust,ignore
/// fn handle_stream_error(runtime: &impl FallbackCapable) {
/// let tripped = runtime.fallback().record_api_failure();
/// if tripped {
/// if let Some(model) = runtime.fallback().fallback_model() {
/// // switch to fallback model
/// }
/// }
/// }
/// ```
/// Capability to compact conversation context when token usage exceeds a threshold.
///
/// When a [`ContextManager`] is configured, the loop checks token usage
/// after each turn and triggers compaction when usage exceeds the
/// configured threshold. Compaction replaces conversation messages with
/// a compressed version, preserving the most recent context.
///
/// # Implementors
///
/// - [`LoopRuntime`](crate::runtime::LoopRuntime) — the framework's default implementation.
///
/// # When to use
///
/// Use this trait bound when you need to inspect or trigger context
/// compaction during the agent loop. Useful for custom loop
/// implementations that need to manage the context window directly.
/// Capability to stream LLM responses with retry, timeout, and fallback.
///
/// When a [`StreamHandler`] is configured, the loop delegates streaming
/// to it instead of using the basic inline logic. The handler provides
/// automatic retries, per-event timeouts, and fallback to non-streaming
/// mode.
///
/// # Implementors
///
/// - [`LoopRuntime`](crate::runtime::LoopRuntime) — the framework's default implementation.
///
/// # When to use
///
/// Use this trait bound when you need to access the stream handler for
/// resilient streaming. Useful for custom loop implementations
/// that need to control streaming behaviour (timeouts, retries, fallback
/// to non-streaming mode).
/// Capability to run bidirectional hooks that can block actions.
///
/// Hooks differ from observers ([`Observable`]) in that they return
/// [`HookAction`](crate::hooks::HookAction) to control whether an action
/// proceeds. The executor stops at the first hook that returns a blocking
/// result.
///
/// # Implementors
///
/// - [`LoopRuntime`](crate::runtime::LoopRuntime) — the framework's default implementation.
///
/// # When to use
///
/// Use this trait bound when you need to run hooks before or after
/// tool dispatch, compaction, or session start/end.
/// Capability to dispatch tools through a middleware pipeline.
///
/// When a pipeline is configured, tool calls flow through middleware
/// layers (timeouts, output limiting, etc.) before reaching the registry.
///
/// # Implementors
///
/// - [`LoopRuntime`](crate::runtime::LoopRuntime) — the framework's default implementation.
///
/// # When to use
///
/// Use this trait bound when you need to dispatch a tool call through
/// optional middleware.
///
/// ```rust,ignore
/// async fn dispatch(runtime: &impl PipelineAware, ctx: ToolDispatchContext) {
/// if let Some(pipeline) = runtime.pipeline() {
/// pipeline.invoke(ctx).await
/// } else {
/// // direct dispatch
/// }
/// }
/// ```
/// Capability to track per-tool health with circuit breakers.
///
/// Records success/failure and latency for every tool dispatch.
/// Tools that exceed the failure threshold have their circuit breaker
/// opened, blocking subsequent calls until recovery.
///
/// *Requires `tool_health` feature.*
///
/// # Implementors
///
/// - [`LoopRuntime`](crate::runtime::LoopRuntime) — the framework's default implementation.