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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
//! Inference engine layer (`shared/api`). A provider-agnostic contract
//! ([`EngineBackend`]/[`Embedder`] in [`contract`]) and its implementations, grouped
//! by family: [`openai`] (local/external `llama-server`, OpenAI cloud via
//! Responses), [`anthropic`] (Claude, Messages API), [`gemini`] (Gemini, native
//! generateContent), [`managed`] (launching a child `llama-server`).
//! See spec §6 and [ADR 0004](../../../docs/decisions/0004-engine-contract-multi-provider.md).
// Production since the demo mode (`mindfork demo`) boots on it; tests were
// the original and remain the main consumer.
// Stage-0 live probe for `/continue` (docs/research/continue-generation.md §7).
// Stage-0 live probe for the two-agent dialogue
// (docs/research/two-agent-dialogue.md §5).
// The one-shot SSE server the clients' stream tests share.
pub
pub use AnthropicClient;
pub use ;
pub use GeminiClient;
pub use ;
pub use ;
/// A client to a live OpenAI-compatible server for the `#[ignore]` smokes,
/// named by a pair of env variables: the URL and an **optional** Bearer key —
/// plus an **optional** model name, on the same naming convention.
///
/// `None` when the URL variable is unset — the smoke skips, as before. An unset
/// or empty key variable sends no `Authorization` header, i.e. byte-for-byte the
/// previous behaviour against a local `llama-server`; setting it lets the same
/// smokes run against an authenticated server (a hosted endpoint, a proxy). See
/// [docs/history/remote-e2e-hf.md](../../../docs/history/remote-e2e-hf.md) §5.
///
/// The **model** is what makes the whole live set usable against a *gateway*
/// (OpenRouter, LiteLLM, `llama-server --router`): those route on the request's
/// `model` and answer `400 "model name is missing"` without one
/// ([docs/research/external-model-name.md](../../../docs/research/external-model-name.md) §2.3),
/// so every smoke here — engine, orchestrator e2e, embedder — used to be a
/// single-model stack's privilege. Unset, nothing is sent and the request is
/// byte-identical to before (docs/research/openrouter-external.md §8).
pub
/// The model variable's name for the stack named by `url_var`, derived rather
/// than passed: the seventeen call sites already spell the pair by convention
/// (`MINDFORK_ENGINE_URL` + `MINDFORK_ENGINE_KEY`), and a third argument at each
/// of them would buy nothing the convention does not already guarantee.
/// `MINDFORK_ENGINE_URL` → `MINDFORK_ENGINE_MODEL`, and a suffixed stack keeps
/// its suffix: `MINDFORK_EMBED_URL_ALT` → `MINDFORK_EMBED_MODEL_ALT`.
/// The `Authorization` header for a smoke that speaks to the engine **directly**
/// rather than through [`OpenAiClient`] — a probe reading a field the client
/// drops (`timings`), or one composing a request body by hand.
///
/// The same rule as [`live_client`]: no key variable, no header, i.e. byte for
/// byte the previous behaviour against a local `llama-server`. It exists because
/// the first gpt-oss dispatch found four such smokes answering `401` on the
/// rented gate — they had been written against an unauthenticated LAN stand and
/// had never met an authenticated server (docs/research/e2e-gpt-oss-120b.md).
pub
/// The stack under test has **no vision projector to give**, and the run says so
/// in writing.
///
/// Three smokes need a projector and *fail loudly rather than skip* against a
/// text-only server, deliberately: a vision smoke that quietly passes on a blind
/// model is worse than none ([docs/lessons.md](../../../docs/lessons.md) §9).
/// That rule assumes the stack could have been given one — the gate's two chat
/// models both ship a projector in the same repository as their weights, so a
/// blind run there is a misconfiguration, which is exactly what the rule is
/// meant to catch.
///
/// A gate model that has no projector in existence (`gpt-oss-120b` is text-only)
/// falls outside the assumption rather than outside the rule. So it is declared:
/// `MINDFORK_LIVE_TEXT_ONLY=1` turns those three smokes into skips and changes
/// nothing else. It is set by the model record that knows it is blind, never by
/// the standard gate, and every skip prints the variable's name — a skip the run
/// has to ask for, by name, in the log, is not the silent pass the rule guards
/// against. See docs/research/e2e-gpt-oss-120b.md §7 (fork F3).
pub
/// The stack under test serves a model whose weights are **split across several
/// files**, and the run says so.
///
/// The declaration is what makes the check worth anything. A smoke that merely
/// asserted "the reported name has no part number" would pass on every
/// single-file stack without ever meeting a split one — which is where the
/// gate stood until `gpt-oss-120b` joined it: [`crate::shared::gguf`] parses,
/// rebuilds and strips the `-00001-of-00002` tail, and every assertion about it
/// was a unit test over strings.
///
/// So `MINDFORK_LIVE_SPLIT_MODEL=1` says "this server is holding a split model",
/// and the smoke that reads it **fails rather than skips** if the server turns
/// out to report a plain file — the same discipline as the vision smokes
/// ([docs/lessons.md](../../../docs/lessons.md) §9), for the same reason: a
/// declaration that is quietly wrong is worse than no declaration.
/// See docs/research/e2e-gpt-oss-120b.md §6 (T2).
pub
/// The fixture every provider's vision smoke sends: a 512×512 blue field with a large
/// white square in the middle, as base64 png (spec §9.10).
///
/// Generated rather than committed, and geometric rather than photographic, for the same
/// reason the compaction smokes plant an invented code: the assertion has to be something
/// no model could answer from pretraining, and something two humans would describe the
/// same way. One helper for all four smokes so the four wire formats are compared on
/// identical bytes — if one provider disagrees, the difference is the format, not the
/// picture.
pub
/// What every vision smoke asks, and what its answer has to contain. Kept next to the
/// fixture so a change to the picture cannot drift away from the question about it.
pub const VISION_PROMPT: &str = "What is the background colour of this image, and what shape is in the centre? \
Answer in a few words.";
/// The fixture the **tool-result** image smokes send: a green field with a large white
/// circle, as base64 png (spec §9.10).
///
/// Deliberately a *different* shape and colour from [`blue_square_png_base64`], and the
/// reason is recorded in docs/research/mcp-tool-images.md §2.1: with a blue-square
/// fixture every arm answered "blue background, white square" — including a control that
/// was sent **no image at all**. The model was answering the question, not the picture.
/// A fixture a plausible guess does not match is what makes these smokes able to fail.
pub
/// What a tool-result image smoke asks about [`green_circle_png_base64`].
pub const TOOL_VISION_PROMPT: &str = "What is the background colour of the screenshot, and what shape is in the centre? \
Answer briefly.";
/// Asserts an answer really describes [`green_circle_png_base64`] — and, for the control
/// arm, that it does **not**.
///
/// The control is the whole point: a model that cannot see the image still answers
/// confidently (measured: "light blue background, white five-pointed star"), so a smoke
/// without one passes on a feature that never worked.
pub
/// Asserts a vision answer really describes [`blue_square_png_base64`].
///
/// Both halves matter: a model that sees nothing still tends to produce a fluent
/// sentence, and one that only guesses "blue" from the prompt's wording would miss the
/// shape. Requiring both is what makes the smoke fail when an image never arrives.
pub