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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
//! Type definitions for the harness runtime facade.
//!
//! [`AgentHarness`] is the re-entrant runtime that the whole recursive
//! architecture stands inside: parent agents, nested sub-agents, subgraph
//! nodes, and model-authored blueprints all execute against the same composed
//! registries, middleware, and policy, so recursion reuses one runtime instead
//! of forking new ones. [`RunPolicy`] is the cross-cutting policy that runtime
//! enforces on every (parent or nested) run.
//!
//! [`RunPolicy`] is the declarative bundle of cross-cutting policy applied to
//! every run a harness drives (limits, retry, fallback, and a default response
//! format). [`AgentHarness`] is the high-level facade that wires a model
//! registry, a tool registry, a middleware stack, and a policy into a single
//! ergonomic entry point for the agent loop.
//!
//! All public items are re-exported through [`super`] so callers import from
//! `crate::harness::runtime` directly. Implementations and tests live in the
//! sibling `mod.rs` and `test.rs`.
use Arc;
use crate;
use crateRunLimits;
use crateMiddlewareStack;
use crate;
use crate;
use crateToolRegistry;
/// Declarative, run-scoped policy shared by every invocation of an
/// [`AgentHarness`].
///
/// A `RunPolicy` carries the four cross-cutting concerns the agent loop needs
/// to bound and steer a run:
///
/// - `limits`: hard caps (model calls, tool calls, wall-clock) enforced
/// fail-closed by the loop.
/// - `retry`: exponential-backoff retry policy applied to each model call.
/// - `fallback`: optional ordered chain of model names to try when the current
/// model exhausts its retries.
/// - `default_response_format`: when set, attached to every [`crate::harness::model::ModelRequest`]
/// the loop builds; a [`ResponseFormat::JsonSchema`] also drives structured
/// output extraction on the final response.
///
/// [`RunPolicy::default`] yields the crate-default limits and retry policy, no
/// fallback chain, no response format, and a [`CachePolicy`] whose response
/// caching is enabled — caching only takes effect once a [`ResponseCache`] is
/// actually attached via [`AgentHarness::with_response_cache`], so the default
/// is safe even without a cache.
/// How the agent loop reacts when the model calls a tool that is not
/// registered.
///
/// The default is [`UnknownToolPolicy::Fail`], preserving the historical
/// fail-fast behavior. The recoverable variants let a run keep going so the
/// model can correct itself — each recovery still consumes a tool-call budget
/// slot, so [`RunLimits::max_tool_calls`] bounds any unknown-tool loop.
/// How the agent loop reacts when the model calls a *registered* tool with
/// arguments that fail schema validation.
///
/// The default is [`InvalidArgsPolicy::Fail`], preserving the historical
/// fail-fast behavior where a missing `required` field, wrong type, or bad
/// `enum` aborts the whole turn. The recoverable variant lets a run keep going
/// so the model can self-correct — the recovery still consumes a tool-call
/// budget slot, so [`RunLimits::max_tool_calls`] bounds any invalid-args loop.
/// Mirrors [`UnknownToolPolicy`] for the schema-validation seam.
/// Controls whether the agent loop captures model and tool **payloads**
/// (prompt/completion text, tool arguments/results) onto the
/// [`AgentEvent::ModelCompleted`][crate::harness::events::AgentEvent::ModelCompleted]
/// and [`AgentEvent::ToolCompleted`][crate::harness::events::AgentEvent::ToolCompleted]
/// events it emits.
///
/// The observability layer is **payload-free by default**: events carry only
/// ids, counters, and usage so privacy-sensitive deployments never journal or
/// export prompt text or tool I/O. Opt in per-family here to surface the request
/// messages + completion (`model_io`) and tool arguments + result (`tool_io`) so
/// downstream exporters — notably the Langfuse exporter — can populate the
/// Input/Output panels of a generation or tool observation.
///
/// Captured payloads flow through the same event pipeline as everything else, so
/// a [`RedactingSink`][crate::harness::observability::RedactingSink] configured
/// with secret substrings still masks them before they reach a journal or
/// exporter.
/// High-level facade that composes model selection, tool execution, middleware,
/// and run policy behind one builder and runs the default agent loop.
///
/// `AgentHarness` is generic over the application `State` (shared, read-only
/// data threaded into every model and tool call) and the run-context data type
/// `Ctx` (defaults to `()`), which is moved into the [`crate::harness::context::RunContext`]
/// for the duration of a run.
///
/// The registries, middleware stack, and policy are kept crate-private; build a
/// harness with [`AgentHarness::new`] and the `register_*` / `push_middleware` /
/// `with_policy` builder methods, and read them back through the accessor
/// methods. The agent loop itself is implemented in
/// [`crate::harness::agent_loop`].
///
/// # Example
///
/// ```
/// use std::sync::Arc;
/// use tinyagents::harness::providers::MockModel;
/// use tinyagents::harness::runtime::AgentHarness;
///
/// let mut harness: AgentHarness<()> = AgentHarness::new();
/// harness.register_model("mock", Arc::new(MockModel::constant("hello")));
/// assert_eq!(harness.models().default_name(), Some("mock"));
/// ```