arcane-os 0.64.0 → 0.66.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +1 -1
  3. package/browser-runtime/ai/browser-decisions.mjs +3 -2
  4. package/browser-runtime/ai/decision-runtime.mjs +14 -24
  5. package/browser-runtime/core/client.mjs +62 -5
  6. package/docs/guides/native-whisper-openvino.md +334 -0
  7. package/docs/publishing.md +39 -0
  8. package/docs/reference/README.md +11 -1
  9. package/docs/reference/ai/browser-decisions.md +7 -4
  10. package/docs/reference/arcane-ollama.md +1 -1
  11. package/docs/reference/codex-app-server.md +269 -0
  12. package/docs/reference/core-client.md +60 -2
  13. package/docs/reference/core-development.md +157 -0
  14. package/docs/reference/core-native-packaging.md +13 -0
  15. package/docs/reference/core-repositories.md +232 -4
  16. package/docs/reference/git-text-snapshot.md +15 -1
  17. package/docs/reference/inventory/package-api.json +174 -6
  18. package/docs/reference/inventory/runtime-modules.json +8 -6
  19. package/docs/reference/local-ai.md +80 -3
  20. package/docs/reference/local-image-generation.md +5 -0
  21. package/docs/reference/local-image-sdxl.md +1 -1
  22. package/docs/reference/local-whisper.md +7 -1
  23. package/docs/reference/mcp-stdio.md +263 -0
  24. package/docs/reference/native-speech.md +6 -0
  25. package/docs/reference/runtime-components.md +18 -1
  26. package/docs/reference/runtime-modules.md +10 -2
  27. package/docs/reference/sdk-api.md +346 -4
  28. package/package.json +6 -2
  29. package/runtime/arcane/modules/AI.js +156 -13
  30. package/runtime/arcane/modules/Ollama.js +1 -1
  31. package/runtime/arcane/modules/OllamaModelIdentifier.js +13 -0
  32. package/schemas/arcane-app.schema.json +8 -1
  33. package/schemas/arcane-package.schema.json +8 -1
  34. package/src/codex/app-server.mjs +845 -0
  35. package/src/core/development.mjs +457 -0
  36. package/src/core/repositories.mjs +178 -9
  37. package/src/core/services/local-ai.mjs +80 -10
  38. package/src/dev-server.mjs +3 -2
  39. package/src/git-identity.mjs +132 -0
  40. package/src/git-text-snapshot.mjs +5 -3
  41. package/src/index.mjs +1 -0
  42. package/src/local-ai/dev.mjs +80 -426
  43. package/src/local-ai/whisper/config.mjs +31 -3
  44. package/src/local-ai/whisper/index.mjs +62 -5
  45. package/src/local-ai/whisper/install.mjs +72 -14
  46. package/src/local-ai/whisper/native/main.cpp +33 -2
  47. package/src/local-ai/whisper/openvino-build.mjs +138 -0
  48. package/src/mcp/stdio-server.mjs +579 -0
  49. package/src/native/portable-layout.mjs +3 -1
  50. package/src/toolchain.mjs +19 -8
@@ -1,7 +1,7 @@
1
1
  # Local AI through Core
2
2
 
3
- Core owns native llama.cpp and Ollama processes, ONNX worker sessions and
4
- selected local image generation. The browser retains its own
3
+ Core owns native llama.cpp and Ollama processes, ONNX worker sessions,
4
+ selected local image generation and retained Whisper transcription. The browser retains its own
5
5
  Wllama and ONNX implementations, and can also use an explicitly connected Core
6
6
  when that system service is available. Runtime installation, model loading and
7
7
  inference are separate operations.
@@ -43,7 +43,7 @@ preserved when its version cannot be established.
43
43
 
44
44
  Both public application/package schemas accept `stable-diffusion.cpp` as a
45
45
  string or runtime-record ID. Its record additionally accepts `backend`
46
- (`auto`, `cpu` or `metal`) and `models`, an array of `sd14`, `flux2-klein-4b` or
46
+ (`auto`, `cpu` or `metal`) and `models`, an array of `sd14`, `flux2-klein-4b`, `sdxl-base-1.0` or
47
47
  complete model descriptors. Omitted image version selects `master-929-3f8527a`; omitted backend
48
48
  selects `auto`; omitted models leaves model selection empty. Windows/Linux
49
49
  distribution defaults use CPU; the selected universal Mac archive supports
@@ -55,6 +55,37 @@ The [FLUX.2 Klein 4B guide](local-image-flux.md) describes its diffusion model,
55
55
  VAE and Qwen text-conditioning resources, four-step defaults and `txt2img`
56
56
  operation. Each model retains its own supported operation set.
57
57
 
58
+ The [SDXL Base 1.0 guide](local-image-sdxl.md) describes its complete checkpoint,
59
+ embedded text encoders and original VAE, 1024-by-1024 default canvas and
60
+ `txt2img` operation. Selecting a family retains the shared native context,
61
+ progress, cancellation and complete PNG result contract.
62
+
63
+ For native transcription, select a `whisper.cpp` runtime record with a `models`
64
+ array and an explicit `modelId` when selecting more than one model. For example,
65
+ `{id: 'whisper.cpp', backend: 'auto', models: ['whisper-small'], modelId: 'whisper-small'}`
66
+ selects the multilingual small model. Installation prepares its native
67
+ libraries, persistent SDK helper, FFmpeg decoder and selected model files;
68
+ loading and transcription remain separate operations. Development and native
69
+ assembly compose it through the shared speech service without changing the
70
+ browser's selected STT route. See [native Whisper](local-whisper.md) for the
71
+ complete configuration, platform, media and shutdown contracts.
72
+
73
+ Adding `encoder: 'openvino-npu'` selects the optional Intel NPU audio encoder
74
+ with a separately selected CUDA or CPU decoder. The Windows x64 precompiled
75
+ runtime uses paired GGML/XML/BIN model resources and the computer's installed
76
+ compatible Intel NPU driver. See the [Intel NPU Whisper guide](../guides/native-whisper-openvino.md)
77
+ for preparation, observed initialization, cancellation/reload and custom
78
+ runtime production. Omitting the encoder retains ordinary Whisper preparation.
79
+
80
+ The selected model stays loaded across recordings. An eligible native
81
+ accelerated failure may drain that helper and retry the same complete recording
82
+ once on the prepared CPU backend. That accepted request retains its actual
83
+ request identity while `recovering` is unloaded and busy; new inference remains
84
+ blocked until actual readiness. Cancellation, unload, close, replacement and
85
+ transport loss retain their owning cancellation behavior. A terminal engine
86
+ failure reaches the original request as its actual error rather than a
87
+ fabricated readiness success. See [native speech reconciliation](native-speech.md).
88
+
58
89
  `llamaCpp` accepts `url`, `model`, `modelsDirectory`, and an `args` string array.
59
90
  `model` selects a single GGUF file; `modelsDirectory` selects llama.cpp router
60
91
  mode. Paths resolve from the application root. Ollama accepts `url`,
@@ -193,6 +224,52 @@ Those methods use Ollama's native API. Streaming uses the existing
193
224
  such as selection, settings and brain creation remain with their existing
194
225
  owners; they are separate from this runtime service.
195
226
 
227
+ ### Selected Ollama model readiness
228
+
229
+ The built-in `OLLAMA` LLM provider loads its selected model through Ollama's
230
+ empty `generate` request and separately confirms that selected model in
231
+ `running()` (`/api/ps`). A model catalog entry, a connected bridge, and a
232
+ successful preload response alone do not establish a ready model. Ollama's
233
+ empty preload response echoes the requested name; resident snapshots use its
234
+ shortest tagged name. Comparison applies Ollama's default `registry.ollama.ai`
235
+ host, `library` namespace and `latest` tag, so `moon-raccoon` and
236
+ `registry.ollama.ai/library/moon-raccoon:latest` identify the same resident
237
+ model. This comparison leaves outbound model names and payloads unchanged.
238
+ The provider preserves Ollama's configured/default retention duration.
239
+
240
+ Core refreshes and emits `localai.state` after its Ollama generation, chat,
241
+ embedding and catalog-changing operations, including a failed or cancelled
242
+ operation while the service remains available. Explicit `running()` inspection
243
+ also publishes the actual resident-model snapshot. An SDK-owned process exit
244
+ publishes its unavailable state through the existing process owner.
245
+ Successes and failures belong to their observation order and engine lifetime;
246
+ an older observation cannot replace newer state or a recovered engine's state.
247
+ The complete current failure remains available through the owning state surface.
248
+
249
+ The LLM provider subscribes before loading and retains that observation while
250
+ loaded. An observed selected-model unload, replacement, unavailable service or
251
+ service error revokes readiness and cancels the active request through the shared
252
+ AI runtime. Each inference checks current residency before dispatch and again
253
+ before accepting its terminal result. These `running({signal})` calls carry the
254
+ owning request's cancellation through Core to `/api/ps`. Streaming chunks still
255
+ arrive immediately through their existing path. Explicit provider unloading sends Ollama's
256
+ `keep_alive: 0` release request; another client can independently reload a model.
257
+
258
+ Ollama's documented public API exposes resident snapshots, not an ongoing
259
+ resident-model event subscription. Core adds no timer polling. External changes
260
+ between observations, including idle eviction or another client's model load,
261
+ remain unobserved until a subsequent owned operation or explicit inspection.
262
+ There is also an upstream race between a snapshot and the following request;
263
+ these checks do not claim an atomic reservation of the daemon's model state.
264
+ Applications consume the shared provider lifecycle rather than treating a stale
265
+ idle snapshot as proof for their next inference. `Ollama.readiness()` remains a
266
+ service-connectivity result and does not establish selected-model readiness.
267
+
268
+ Upstream references: [resident models](https://docs.ollama.com/api/ps),
269
+ [model-name defaults and comparison](https://github.com/ollama/ollama/blob/main/types/model/name.go),
270
+ [preload response and resident-name handling](https://github.com/ollama/ollama/blob/main/server/routes.go),
271
+ [preload and retention](https://docs.ollama.com/faq#how-can-i-preload-a-model-into-ollama-to-get-faster-response-times).
272
+
196
273
  ## Browser llama.cpp provider
197
274
 
198
275
  ```js
@@ -47,6 +47,11 @@ four-step defaults and the advertised `txt2img` operation. Keep each model's
47
47
  supported operations distinct: selecting FLUX does not enable reference-image
48
48
  editing or imply the same input path as SD1.4 img2img.
49
49
 
50
+ `sdxl-base-1.0` selects the complete SDXL Base checkpoint, including its text
51
+ encoders and original VAE. Its [family guide](local-image-sdxl.md) covers the
52
+ single model resource, 1024-by-1024 default canvas and native sampling defaults.
53
+ It advertises `txt2img`; selecting it does not enable an editing operation.
54
+
50
55
  The first published distribution path selects CPU on Windows and Linux.
51
56
  On macOS, `auto` selects the same upstream universal runtime's built-in Metal
52
57
  backend, with CPU fallback; explicit `cpu` remains available. A caller-supplied
@@ -38,7 +38,7 @@ selection alone does not establish actual execution on any device.
38
38
  ## Prepare the checkpoint and generate an image
39
39
 
40
40
  The single `model` resource is the official
41
- [sd_xl_base_1.0.safetensors checkpoint](https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/462165984030d82259a11f4367a4eed129e94a7b/sd_xl_base_1.0.safetensors)
41
+ [`sd_xl_base_1.0.safetensors` checkpoint](https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/462165984030d82259a11f4367a4eed129e94a7b/sd_xl_base_1.0.safetensors)
42
42
  at revision `462165984030d82259a11f4367a4eed129e94a7b`. It includes the text
43
43
  encoders, denoiser and original VAE. Standalone base generation uses this one
44
44
  resource; a refiner, separate VAE, LoRA or Python converter is unnecessary for
@@ -7,6 +7,12 @@ the model or recording files are reused. The browser's existing
7
7
  `AI.fetchSTT(audioFile, signal)` and Core `speech.transcribe` routes retain the
8
8
  application's selected model and cancellation signal.
9
9
 
10
+ For the optional Intel NPU encoder, add `encoder: "openvino-npu"` to the
11
+ runtime record. The [Intel NPU guide](../guides/native-whisper-openvino.md)
12
+ covers the Windows x64 precompiled distribution, paired GGML/XML/BIN model
13
+ resources, independent CUDA/CPU decoding and joined cancellation. Omitting
14
+ `encoder` preserves the ordinary runtime and model selection below.
15
+
10
16
  ## Select the runtime and model
11
17
 
12
18
  An application's `arcane-app.json` selects native speech alongside its other
@@ -130,7 +136,7 @@ prepared descriptor returned by `ensureLocalAIRuntimes`; alternatively,
130
136
 
131
137
  | Member | Contract |
132
138
  | --- | --- |
133
- | `current()` | Returns `providerId`, selected `modelId`, lifecycle `state`, `loaded`, `busy`, correlated `requestId` or null, requested/observed backend, evidence and any error. |
139
+ | `current()` | Returns `providerId`, selected `modelId`, lifecycle `state`, `loaded`, `busy`, correlated `requestId` or null, `requestedBackend`, `observedBackend`, `backendEvidence`, `requestedEncoder`, `observedEncoder`, `encoderEvidence` and any error. Encoder initialization evidence is separate from decoder evidence. |
134
140
  | `subscribe(listener, {replay = true, signal} = {})` | Immediately replays current state by default and returns an unsubscribe function. |
135
141
  | `load({modelId, signal} = {})` | Prepares the runtime if necessary, then waits for actual native model readiness. With no selected model it remains unloaded. |
136
142
  | `transcribe(request, {signal, onProgress, requestId} = {})` | Consumes the complete `audioBase64` recording. Optional `language` defaults to native automatic detection; `translate: true` selects Whisper's translation operation. `model` must match the loaded model. Optional `requestId` carries the caller's existing operation identity through lifecycle snapshots as separate control information; it does not alter the recording or request payload. |
@@ -0,0 +1,263 @@
1
+ # MCP STDIO server
2
+
3
+ Expose application-owned tools and static resources to an MCP client with
4
+ `arcane-os/mcp/stdio`. This optional Node entrypoint owns one JSON-RPC session,
5
+ UTF-8 newline framing, discovery, request correlation, cooperative cancellation,
6
+ and graceful drain. The application owns its launch command, tool definitions,
7
+ resource contents, business behavior, and underlying service lifetime.
8
+
9
+ Availability: Node on Windows, Linux, and macOS, using the package's supported
10
+ Node version. Android requires a host that supplies the same Node stream and
11
+ process environment. Importing the entrypoint starts no process or listener.
12
+ It is separate from the native Core `arcane/1` transport and its Content-Length
13
+ frames; the two stream formats are not interchangeable.
14
+
15
+ ## createMcpStdioServer
16
+
17
+ ```javascript
18
+ import {createMcpStdioServer} from 'arcane-os/mcp/stdio';
19
+
20
+ const menu = {
21
+ content: 'Moon soup\nExtra tentacles available.',
22
+ message: {chef: 'Octopus', open: true}
23
+ };
24
+
25
+ const server = createMcpStdioServer(
26
+ {
27
+ serverInfo: {name: 'moon-pantry', version: '1.0.0'},
28
+ instructions: 'Ask moon.menu for the complete lunar dinner menu.',
29
+ tools: [
30
+ {
31
+ name: 'moon.menu',
32
+ description: 'Read the complete lunar dinner menu.',
33
+ inputSchema: {type: 'object'},
34
+ annotations: {readOnlyHint: true},
35
+ handler: readMenu
36
+ }
37
+ ],
38
+ resources: [
39
+ {
40
+ uri: 'pantry://menu',
41
+ name: 'menu',
42
+ title: 'Lunar dinner menu',
43
+ mimeType: 'application/json',
44
+ handler: readMenuResource
45
+ }
46
+ ]
47
+ }
48
+ );
49
+
50
+ function readMenu(args, {signal}) {
51
+ signal.throwIfAborted();
52
+ return {
53
+ content: [{type: 'text', text: JSON.stringify(menu)}],
54
+ structuredContent: menu
55
+ };
56
+ }
57
+
58
+ function readMenuResource({uri}, {signal}) {
59
+ signal.throwIfAborted();
60
+ return {
61
+ contents: [{uri, mimeType: 'application/json', text: JSON.stringify(menu)}]
62
+ };
63
+ }
64
+
65
+ server.start();
66
+ try {
67
+ await server.closed;
68
+ } catch {
69
+ // The adapter already sent its diagnostic to stderr.
70
+ process.exitCode = 1;
71
+ }
72
+ ```
73
+
74
+ Save this in the consuming application and configure the MCP client's subprocess
75
+ command as `node` with that application's script path. Client configuration
76
+ file formats and process launch policy remain client-owned. Change `menu` to
77
+ change the complete result; no model, repository, or native host is needed for
78
+ this example.
79
+
80
+ The application explicitly converts its domain record into an MCP result.
81
+ The SDK does not guess from `content`, `message`, or other domain field names.
82
+ The serialized text in this example is an application-selected representation;
83
+ the SDK never adds it automatically.
84
+
85
+ ### Parameters
86
+
87
+ `createMcpStdioServer(options)` returns a server object synchronously.
88
+
89
+ | Option | Contract |
90
+ | --- | --- |
91
+ | `serverInfo` | Required MCP implementation object with `name` and `version` strings. Optional MCP implementation fields are passed through. |
92
+ | `instructions` | Optional complete instruction string returned by initialization. |
93
+ | `tools` | Optional static array; each entry is a complete MCP tool descriptor plus `handler(args, context)`. Defaults to `[]`. Tool names identify handlers exactly and must be unique. |
94
+ | `resources` | Optional static array; each entry is a complete MCP resource descriptor plus `handler(params, context)`. Defaults to `[]`. Each resource requires `uri` and `name`; URIs identify handlers exactly and must be unique. |
95
+ | `onDiagnostic` | Optional error observer. Omit it for complete error text on the selected stderr stream. It may return a promise, which participates in drain. Observer failures are reported to stderr and retained by `closed`. |
96
+
97
+ The factory captures catalog entries at construction. Discovery preserves
98
+ descriptor fields, including authored schemas, descriptions, annotations,
99
+ icons, and metadata; only the local `handler` function is omitted. No tool
100
+ arguments, descriptions, schemas, resources, or result content are injected,
101
+ trimmed, rewritten, or shortened. Supply JSON-serializable protocol values.
102
+
103
+ The SDK checks the request envelope and required result container. It does not
104
+ provide a general JSON Schema evaluator. The application supplies a valid
105
+ `inputSchema` object, owns the handler's input semantics, and ensures any
106
+ declared `outputSchema` matches its structured result. This adapter does not
107
+ implement task-augmented execution; descriptors must describe ordinary tool
108
+ execution.
109
+
110
+ ### Handler inputs and results
111
+
112
+ Tool handlers receive `params.arguments` unchanged. Omitted arguments become
113
+ an empty object as the protocol's no-argument case. Resource handlers receive
114
+ the complete `resources/read` params object, including its exact `uri` and
115
+ any metadata. A handler may return its result directly or return a promise.
116
+
117
+ Each handler receives a context with:
118
+
119
+ - `signal`: its own request's `AbortSignal`;
120
+ - `requestId`: the original string or integer ID, including numeric zero;
121
+ - `method`: `tools/call` or `resources/read`;
122
+ - `params`: the complete request params object;
123
+ - `clientInfo` and `clientCapabilities`: the client's initialization objects.
124
+
125
+ A tool handler returns an explicit MCP `CallToolResult`, including a `content`
126
+ array and optional `structuredContent`, `isError`, `_meta`, or other protocol
127
+ fields. All supplied content blocks and JSON fields pass through. Resource
128
+ handlers return an explicit `ReadResourceResult` with a `contents` array;
129
+ complete text or already encoded binary resource contents pass through.
130
+ The application creates these protocol result objects deliberately. A plain
131
+ domain object with `content: 'some text'` is not a `CallToolResult` and produces
132
+ an internal protocol error rather than being silently converted.
133
+
134
+ For a domain failure, return a complete `CallToolResult` with `isError: true`.
135
+ An ordinary exception thrown by a tool handler becomes an `isError: true`
136
+ text result containing the exception's complete message, and the complete
137
+ exception is also reported through diagnostics. Throw `McpProtocolError` for
138
+ an explicit JSON-RPC failure. Other resource or adapter exceptions produce
139
+ `-32603` and a diagnostic; malformed result containers and non-serializable
140
+ results also produce `-32603`.
141
+ Custom fields on an ordinary thrown error remain in diagnostics unless the
142
+ application explicitly maps its known outcome to `structuredContent` in an
143
+ `isError: true` tool result.
144
+
145
+ ## start
146
+
147
+ `server.start({input, output, error})` attaches to caller-owned Node streams and
148
+ returns the same server. Defaults are `process.stdin`, `process.stdout`, and
149
+ `process.stderr`. Start each server exactly once with an open readable input and
150
+ open writable output/diagnostic streams. Output and diagnostics must be separate
151
+ streams. Byte-mode input preserves split UTF-8 sequences; a stream already
152
+ decoded into strings remains responsible for its own decoding.
153
+
154
+ Messages are processed as their newline arrives, without waiting for EOF. A
155
+ final complete JSON record is also accepted when EOF arrives without its final
156
+ newline. LF and CRLF transport endings are accepted. JSON escaping preserves
157
+ embedded line breaks in the decoded payload. Malformed JSON receives `-32700`;
158
+ its complete original line is included in diagnostics. Invalid UTF-8 fails at
159
+ the decoder and closes the transport with the complete affected input chunks
160
+ and pending decoded text in its diagnostic error.
161
+
162
+ Requests execute independently, including overlapping calls to one tool.
163
+ Only complete output writes are ordered, waiting for each Node write callback
164
+ before sending the next record. An error, close, or finish event during a pending
165
+ output or diagnostic write settles that write as failed even when its callback
166
+ never arrives; a later callback cannot settle it again. The application decides
167
+ whether its own data access requires narrower serialization. The adapter adds
168
+ no process-wide queue.
169
+
170
+ Only JSON-RPC messages are written to `output`. Application handlers and their
171
+ dependencies must also reserve stdout for protocol traffic; use stderr or the
172
+ application's diagnostic owner for logs. The adapter does not replace global
173
+ console functions.
174
+
175
+ ## cancel
176
+
177
+ `server.cancel(requestId, reason)` requests cooperative cancellation and returns
178
+ `true` only when an active cancellable handler was signalled. String and numeric
179
+ IDs remain distinct. Unknown, completed, already cancelled, and initialization
180
+ requests return `false`. The same behavior handles client
181
+ `notifications/cancelled` messages. Late results from cancelled work have no
182
+ protocol response, as described by the
183
+ [MCP cancellation contract](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/cancellation).
184
+
185
+ The handler must pass its signal to its actual I/O or computation and release
186
+ owned resources. Signalling does not prove external work stopped. The adapter
187
+ retains the handler promise until it really settles; a handler that ignores
188
+ cancellation can keep drain and close pending.
189
+
190
+ ## drain
191
+
192
+ `await server.drain()` waits for accepted handlers, diagnostic observers, and
193
+ output write callbacks to settle. It does not stop input or abort requests, so
194
+ newly accepted work can extend the wait. Use `close()` when input must first
195
+ stop. Tool and request errors are delivered as protocol outcomes; transport and
196
+ diagnostic delivery failures are retained by `closed`.
197
+
198
+ ## close
199
+
200
+ `await server.close({cancelPending: false})` stops reading, pauses the input,
201
+ drains accepted work and writes, detaches the adapter's stream listeners, and
202
+ settles `closed`. It is idempotent. Normal input EOF follows this same graceful
203
+ path. Explicit `cancelPending: true` aborts pending work instead; repeated close
204
+ may request cancellation while an earlier graceful close is draining.
205
+
206
+ Stream failures request cancellation, report diagnostics, and reject `closed`
207
+ after owned work settles. An input closed without EOF is a transport failure.
208
+ The adapter does not end or destroy caller streams, terminate the process,
209
+ install process signal handlers, start an application host, or close
210
+ application services. The launcher owns those actions after the adapter drains.
211
+
212
+ ## closed
213
+
214
+ `server.closed` is a promise for actual session cleanup. It resolves after a
215
+ normal close or EOF and rejects with an `AggregateError` when transport or
216
+ diagnostic delivery failed. Observe it even when the initiating caller continues
217
+ other work. Request failures alone do not close the session.
218
+
219
+ ## `MCP_PROTOCOL_VERSION`
220
+
221
+ `MCP_PROTOCOL_VERSION` is exactly `'2025-11-25'`. Initialization always returns
222
+ that supported version. A client proposing another version must accept this
223
+ profile or disconnect. This is the initialize/initialized STDIO profile;
224
+ support for later discovery-based profiles is not implied. See the normative
225
+ [lifecycle](https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle)
226
+ and [STDIO transport](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports).
227
+
228
+ Supported requests are `initialize`, `ping`, `tools/list`, `tools/call`,
229
+ `resources/list`, `resources/read`, and `resources/templates/list` (an empty
230
+ template catalog). Tools and resources capabilities are advertised when their
231
+ catalogs are nonempty. Lists return their complete catalogs without pagination;
232
+ supplying a cursor receives `-32602`. Send `notifications/initialized` after
233
+ the initialization response before ordinary operations.
234
+
235
+ There are no prompts, subscriptions, list-change events, MCP logging requests,
236
+ server-to-client requests, sampling, elicitation, task augmentation, HTTP
237
+ transport, or automatic client configuration. Unknown methods return `-32601`;
238
+ notifications never receive responses. JSON-RPC batches are not part of this
239
+ profile. IDs must be strings or integers and are unique for the session.
240
+
241
+ The result shapes follow the official
242
+ [tool](https://modelcontextprotocol.io/specification/2025-11-25/server/tools)
243
+ and [resource](https://modelcontextprotocol.io/specification/2025-11-25/server/resources)
244
+ contracts. This narrow adapter does not claim every optional MCP capability.
245
+
246
+ ## McpProtocolError
247
+
248
+ `new McpProtocolError(code, message, data)` represents an explicit protocol
249
+ failure. `code` is a JSON-RPC integer, `message` is its complete string, and
250
+ optional `data` is JSON-serializable protocol detail. It extends `Error` and
251
+ exposes `name`, `code`, `message`, and optional `data`.
252
+
253
+ The adapter uses `-32700` for malformed JSON, `-32600` for invalid requests,
254
+ `-32601` for unknown methods, `-32602` for malformed params or unknown tools,
255
+ `-32603` for internal failures, and `-32002` for a missing resource. Its
256
+ `-32000` lifecycle error requests initialization before ordinary operations.
257
+
258
+ ## Evidence boundary
259
+
260
+ `test/mcp-stdio-server.test.mjs` contains focused in-memory stream fixtures for
261
+ these contracts. Authored fixtures and source review do not establish an
262
+ executed client integration or platform run. Run local tests only under the
263
+ applicable explicit testing or selected-output authority.
@@ -26,6 +26,12 @@ selection, supported formats, and native process ownership remain with the
26
26
  selected engine and its host composition. Browser-only operation remains
27
27
  independent of this native service.
28
28
 
29
+ The SDK's [retained Whisper engine](local-whisper.md) supplies native STT.
30
+ Its optional [Intel NPU encoder](../guides/native-whisper-openvino.md) uses the
31
+ same service, readiness events, complete request/result contract and cancellation
32
+ path. The host selects that encoder and its paired model resources; the browser
33
+ continues calling `speech.transcribe` without loading native libraries itself.
34
+
29
35
  ## Startup and status
30
36
 
31
37
  `start(context)` subscribes to each configured engine and starts their loads
@@ -1742,6 +1742,14 @@ owner, and the voice control retains its state-specific labels and retry action.
1742
1742
  Desktop speech and the dedicated `voice-transcription.html` component retain their
1743
1743
  existing behavior.
1744
1744
 
1745
+ An already accepted file transcription retains its exact owned runtime
1746
+ operation through the same provider/model's unloaded, busy `recovering` state
1747
+ or correlated pending error. This preserves the actual RPC result or failure;
1748
+ it does not enable another recording. Unload, close, provider/model replacement,
1749
+ transport loss and caller cancellation still invalidate owned work. Native Web
1750
+ Speech microphone capture keeps its independent readiness and final/interim
1751
+ cancellation lifetime. See [native speech recovery](native-speech.md).
1752
+
1745
1753
  On desktop, the Hold to talk control remains disabled unless sticky STT state
1746
1754
  is `ready`, the role is not busy, and microphone capture is available. For an explicitly
1747
1755
  selected STT route, a separate keyboard-operable control presents Start
@@ -2115,7 +2123,16 @@ Unknown provider/runtime diagnostics remain complete in the developer console
2115
2123
  and error events, while controls use generic visible outcomes unless the Error
2116
2124
  owner explicitly marks nonblank copy with `userSafe:true`.
2117
2125
 
2118
- For the default manual mode, if sticky readiness is lost during microphone acquisition, capture, or the STT
2126
+ An already accepted file transcription can continue through the exact same
2127
+ provider/model/runtime operation's unloaded, busy recovery or pending-error
2128
+ state. This uses the real runtime operation ID rather than the component's local
2129
+ counter; another request supplies no continuation authority. New recording and
2130
+ transcription remain readiness-gated, and actual unload, close, replacement,
2131
+ transport loss or cancellation still ends the owned request. The same shared
2132
+ rule applies to an active continuous file-transcription job. Native Web Speech
2133
+ capture retains its separate readiness, stop/final-drain and interim ownership.
2134
+
2135
+ Outside that exact continuing request, if sticky readiness is lost during microphone acquisition, capture, or the STT
2119
2136
  request, the component invalidates the session, aborts the owned request signal,
2120
2137
  releases media, discards late completion, and emits
2121
2138
  `speech-transcription-cancelled`. Its source-local reason is
@@ -3227,9 +3227,17 @@ Validates and canonicalizes the syntax of Ollama model identifiers without grant
3227
3227
 
3228
3228
  ### Public surface
3229
3229
 
3230
- `normalizeOllamaModelIdentifier()`, `isOllamaModelIdentifier()`.
3230
+ `normalizeOllamaModelIdentifier()`, `isOllamaModelIdentifier()`,
3231
+ `sameOllamaModelIdentifier(left, right)`.
3231
3232
 
3232
- Exact exports: `isOllamaModelIdentifier`, `normalizeOllamaModelIdentifier`.
3233
+ Exact exports: `isOllamaModelIdentifier`, `normalizeOllamaModelIdentifier`,
3234
+ `sameOllamaModelIdentifier`.
3235
+
3236
+ The comparison helper applies Ollama's default registry (`registry.ollama.ai`),
3237
+ namespace (`library`) and tag (`latest`) with case-insensitive name comparison.
3238
+ It compares a selected name with resident-model names without rewriting either
3239
+ string or any outbound payload; different explicit hosts, namespaces or tags
3240
+ remain distinct. The existing identifier-validation functions are unchanged.
3233
3241
 
3234
3242
  ### Availability and normalization
3235
3243