arcane-os 0.5.10 → 0.5.12

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 (54) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +117 -26
  3. package/browser-runtime/ai/browser-speech-providers.mjs +1 -1
  4. package/docs/architecture.md +303 -0
  5. package/docs/compatibility.md +38 -0
  6. package/docs/event-manager.md +263 -0
  7. package/docs/platform-targets.md +104 -0
  8. package/docs/publishing.md +126 -0
  9. package/docs/reference/README.md +206 -0
  10. package/docs/reference/ai/browser-speech.md +879 -0
  11. package/docs/reference/ai/browser-wasm.md +637 -0
  12. package/docs/reference/ai/twin-cloud.md +156 -0
  13. package/docs/reference/arcane-ollama.md +288 -0
  14. package/docs/reference/availability-and-normalization.md +224 -0
  15. package/docs/reference/behavioral-testing.md +129 -0
  16. package/docs/reference/cli.md +820 -0
  17. package/docs/reference/core/README.md +61 -0
  18. package/docs/reference/core/arcane-ai-contracts.md +906 -0
  19. package/docs/reference/core/arcane-api.md +601 -0
  20. package/docs/reference/core/arcane-entities.md +59 -0
  21. package/docs/reference/core/arcane-events.md +134 -0
  22. package/docs/reference/core/ollama-module.md +181 -0
  23. package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +1909 -0
  24. package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +1057 -0
  25. package/docs/reference/core/reference/arcane-api/core-and-events.md +320 -0
  26. package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +610 -0
  27. package/docs/reference/core/reference/arcane-api/namespaces.md +1157 -0
  28. package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +1423 -0
  29. package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +315 -0
  30. package/docs/reference/event-manager.md +1409 -0
  31. package/docs/reference/inventory/package-api.json +3194 -0
  32. package/docs/reference/inventory/runtime-components.json +1015 -0
  33. package/docs/reference/inventory/runtime-entities.json +25 -0
  34. package/docs/reference/inventory/runtime-modules.json +1367 -0
  35. package/docs/reference/mail.md +309 -0
  36. package/docs/reference/protocols.md +749 -0
  37. package/docs/reference/runtime-components.md +1532 -0
  38. package/docs/reference/runtime-entities.md +305 -0
  39. package/docs/reference/runtime-modules.md +3310 -0
  40. package/docs/reference/sdk-api.md +6733 -0
  41. package/docs/roadmap.md +79 -0
  42. package/docs/work-amplification.md +66 -0
  43. package/examples/wasm-ai-demo/README.md +80 -0
  44. package/examples/wasm-ai-demo/app.js +787 -0
  45. package/examples/wasm-ai-demo/index.html +343 -0
  46. package/examples/wasm-ai-demo/profile-tools.js +217 -0
  47. package/examples/wasm-ai-demo/profiles/BOSS.Modelfile +106 -0
  48. package/examples/wasm-ai-demo/profiles/PreCrisis.Modelfile +693 -0
  49. package/examples/wasm-ai-demo/rag/boss-library.json +3006 -0
  50. package/examples/wasm-ai-demo/rag.js +295 -0
  51. package/examples/wasm-ai-demo/server.mjs +71 -0
  52. package/package.json +10 -1
  53. package/runtime/arcane/modules/AI.js +60 -11
  54. package/runtime/arcane/modules/AIProviderRuntime.js +26 -5
@@ -0,0 +1,637 @@
1
+ # Browser-WASM local AI
2
+
3
+ Use this browser-only entrypoint when an application deliberately owns a local
4
+ GGUF model authority and wants provider-neutral LLM lifecycle, chat, streaming,
5
+ cancellation, and structural tool-call results without an Arcane Core host.
6
+ For ordinary hosted applications, start with the [Arcane AI
7
+ contracts](../core/arcane-ai-contracts.md) and `globalThis.Arcane.ai`. This
8
+ page is the focused local-browser path beneath the normalized AI decision
9
+ guide.
10
+
11
+ The wiring example assumes a scaffolded or materialized Arcane application
12
+ using the current checkout's runtime tree and browser import map.
13
+ `arcane/DBOPFS` is a managed browser-map specifier, not an npm package export.
14
+ See [browser runtime delivery](../protocols.md#browser-runtime-delivery) before
15
+ using the example in a custom host or bundler.
16
+
17
+ ```javascript
18
+ import DBOPFS from 'arcane/DBOPFS';
19
+ import {
20
+ createArcaneAI,
21
+ createBrowserModelSource,
22
+ createBrowserWasmLlmProvider,
23
+ createDbopfsModelStore
24
+ } from 'arcane-os/ai/browser-wasm';
25
+
26
+ const MODEL = {
27
+ id:'my-reviewed-model',
28
+ files:[{
29
+ name:'model-q4-00001-of-00002.gguf',
30
+ url:'https://models.example/revisions/4f7c/model-q4-00001-of-00002.gguf'
31
+ },{
32
+ name:'model-q4-00002-of-00002.gguf',
33
+ url:'https://models.example/revisions/4f7c/model-q4-00002-of-00002.gguf'
34
+ }]
35
+ };
36
+
37
+ const dbopfs = globalThis.dbopfs || new DBOPFS({applicationId:'my-app'});
38
+ await dbopfs.readyPromise;
39
+ const source = createBrowserModelSource(MODEL);
40
+ const store = createDbopfsModelStore({dbopfs});
41
+ const provider = createBrowserWasmLlmProvider({sources:[source], store});
42
+ const ai = createArcaneAI({
43
+ provider,
44
+ loadPolicy:'manual'
45
+ });
46
+
47
+ // Put this behind an explicit user action: it can download every declared file.
48
+ async function loadReviewedModel() {
49
+ return ai.load({threads:1, contextTokens:4096});
50
+ }
51
+ ```
52
+
53
+ The browser-WASM runtime closure packages the upstream
54
+ `@wllama/wllama` `3.6.0` ESM and WebAssembly runtime plus the Wllama and
55
+ llama.cpp MIT license texts. It
56
+ packages no model weights, default model catalog, CDN fallback, native
57
+ provider, speech synthesis, or transcription. The sibling
58
+ [`arcane-os/ai/browser-speech`](browser-speech.md) entrypoint supplies speech
59
+ provider mechanisms but still no runtime/model content. Callers supply every
60
+ model source. Each file needs only a name and HTTPS URL. A positive optional
61
+ `bytes` value supplies observational progress and transport-planning metadata;
62
+ it never validates, admits, identifies, or decides cache reuse for content.
63
+
64
+ ## Lifecycle at a glance
65
+
66
+ `createArcaneAI()` owns one LLM controller. Its default `loadPolicy` is
67
+ `on-demand`; the first request may download and initialize the model. Use
68
+ `manual` when a user action, resource review, or progress UI must precede load.
69
+
70
+ | Operation | Result |
71
+ | --- | --- |
72
+ | `ai.status()` | Mutable `{llm: status}` snapshot. |
73
+ | `ai.load(options)` | Flat LLM status after load. |
74
+ | `ai.llm.chat(request)` / `ai.fetchRequest(request)` | Validated OpenAI-like completion. |
75
+ | `ai.llm.stream(request)` | Mutable async-iterator handle with `result` and `cancel(reason)`. |
76
+ | `ai.streamRequest(request)` | Consumes the stream, publishes every choice's ordinary content/reasoning in provider order, and returns complete JSON text for a multi-choice terminal completion, one structural-call array for selected tool output, or ordinary single-choice text. |
77
+ | `ai.createChatSession(options)` | Asynchronously resolves `Promise<PersistentAIChatSession>` bound to this exact controller; caller-supplied `chat` is rejected. |
78
+ | `ai.unload()` | Cancels active work, releases the Wllama session, and returns flat unloaded status; the DBOPFS cache remains. |
79
+ | `ai.dispose()` | Permanently disposes the controller; explicit `store.remove(source)` is required to delete cached model content. |
80
+
81
+ The controller emits `statechange` and `progress` through
82
+ `addEventListener()`, `removeEventListener()`, or `on()`. Event `detail` is the
83
+ current mutable status snapshot. Provider states are `unloaded`, `loading`, `ready`,
84
+ `unloading`, and `error`.
85
+
86
+ Browser-WASM model loads report `cache-check`, `download`, and `initialize`
87
+ phases. Download records preserve the ordered model-file fields `completed`,
88
+ `total`, and `unit:'files'`. They add `loadedBytes`, `totalBytes`,
89
+ `remainingBytes`, `bytesPerSecond`, `etaSeconds`, `activeTransfers`,
90
+ `transferLimit`, and `transferMode`. `loadedBytes` is aggregate downloaded or
91
+ restored progress for the current install. Active partial writes count while
92
+ they are staged, then are removed from that total if their transfer fails;
93
+ completed shards or Range parts reused from an interrupted attempt remain
94
+ counted. Unknown totals, remaining counts, rates, and ETAs are `null`;
95
+ once known, byte values and seconds are nonnegative numbers. `activeTransfers`
96
+ is the current transfer-worker count, `transferLimit` is the selected concurrency
97
+ bound, and `transferMode` identifies `probing`, `files`, `ranges`, or `single`.
98
+ The store coalesces chunk-driven changes on a 250 ms cadence and publishes
99
+ immediately when download starts, the transfer plan or total becomes known,
100
+ active-worker count changes, and the download completes. At known completion, remaining bytes and ETA are zero
101
+ and active transfers are zero. Applications format the raw measures into B,
102
+ KB, MB, GB, transfer-rate, and duration labels.
103
+
104
+ While a load remains active, the provider also repeats its current record every
105
+ five seconds with `heartbeat:true` and an updated `elapsedMs`. A heartbeat
106
+ confirms that the owned operation is still active; it does not invent
107
+ additional transferred content.
108
+
109
+ The DBOPFS store uses one bounded transfer axis. Ordered multi-file GGUF sets
110
+ download several members concurrently and preserve completed shards across a
111
+ retry. Each active member negotiates HTTP Range support. A split member uses at
112
+ most one Range worker while a single-member source may use up to
113
+ `downloadConcurrency` Range workers (four by default), so file and Range
114
+ workers are never multiplied. A usable total from `Content-Range` or the
115
+ optional descriptor `bytes` divides that member into deterministic contiguous
116
+ parts of roughly 4 MB each, up to 4,096 parts. Each exact completed part is
117
+ committed separately in OPFS, so retry or refresh fetches only the small
118
+ in-flight parts plus any other missing parts; the ordered parts are exposed to
119
+ Wllama as one logical model Blob. Range offsets remain transport-local; only
120
+ aggregate transfer telemetry is public.
121
+
122
+ ## Model selection, optional hardening, and cache
123
+
124
+ The canonical model descriptor is
125
+ `{id, files:[{name?,url,bytes?},...]}`. The ordered `files` array is nonempty;
126
+ names and URLs are unique. Each URL must be absolute HTTPS without credentials
127
+ or a fragment. An optional positive safe-integer `bytes` value is used only for
128
+ progress and HTTP Range planning. Missing or unusable metadata never blocks a
129
+ download, and a declared value is not a content-length check.
130
+
131
+ Fetch follows HTTPS redirects and records the requested and final HTTPS URL. A
132
+ redirect that leaves HTTPS is rejected as an unavoidable transport-safety
133
+ boundary.
134
+
135
+ App, provider/model-binding, and load-operation options may use the same
136
+ plain-JavaScript shape:
137
+
138
+ ```javascript
139
+ {security:{secure:true}}
140
+ ```
141
+
142
+ The SDK default is `secure:false`. Omitted security leaves ordinary model
143
+ loading fully functional. `secure:true` records only an
144
+ application-selected hardening intent in this development contract. It does
145
+ not activate the historical checking machinery; that implementation remains
146
+ disabled and requires a separate review with the user before it can run.
147
+ Neither path performs byte-limit, hash, digest, content-identity, freeze, or
148
+ admission work. Observational byte counting and exact HTTP Range framing remain
149
+ transport-local. A load succeeds only after Wllama reports that the model is
150
+ loaded.
151
+
152
+ The DBOPFS adapter commits each complete member or Range part independently and
153
+ exposes only a complete ordered model set as a cache hit.
154
+ `load({offline:true})` never performs a model request; it uses a compatible
155
+ cached entry or rejects with `ARCANE_AI_MODEL_OFFLINE_MISS`.
156
+
157
+ ```javascript
158
+ const {security, cache} = ai.status().llm;
159
+ console.log(security.secure); // false unless explicitly selected
160
+ console.log(cache);
161
+ ```
162
+
163
+ Applications remain responsible for model selection and license compliance.
164
+
165
+ `localOnly:true` describes inference after load. It does not mean a cache miss
166
+ cannot download. Source downloads use CORS, omit credentials and referrer,
167
+ disable HTTP caching, and honor `AbortSignal`.
168
+
169
+ On Windows desktop Chromium browsers, observing a WebGPU adapter may open one
170
+ flags page and show one advisory per page session. The notice names only
171
+ **Force High Performance GPU** (`#force-high-performance-gpu`), conditional on
172
+ the computer having multiple GPUs, and asks the user to completely close and
173
+ reopen their browser after enabling it. It applies to any observed GPU vendor;
174
+ an Intel identity alone does not establish that an adapter is integrated or
175
+ slower, and the browser does not expose a reliable machine-wide GPU count.
176
+
177
+ An identified Microsoft Edge, Brave, Opera, or Vivaldi receives its own
178
+ `edge://`, `brave://`, `opera://`, or `vivaldi://` flags address. Chrome,
179
+ Chromium, and browsers that conceal their brand receive
180
+ `about://flags/#force-high-performance-gpu`, which the browser rewrites to its
181
+ own flags page, with neutral browser wording. Only the current browser's one
182
+ address appears. Firefox, Safari, non-Windows platforms, and mobile browsers
183
+ receive no flag notice. The notice does not suggest unrelated WebGPU, ANGLE,
184
+ Vulkan, rasterization, or blocklist flags.
185
+
186
+ The Windows selection workaround is documented by
187
+ [Chrome](https://developer.chrome.com/docs/web-platform/webgpu/troubleshooting-tips#Windows-specific_limitations).
188
+ Other Chromium browsers inherit that flag; the per-vendor addresses and generic
189
+ `about://` rewrite follow the
190
+ [Chromium browser-flags guide](https://developer.chrome.com/blog/browser-flags/).
191
+ [Vivaldi masks its browser identity by default](https://help.vivaldi.com/developers/web/vivaldi-user-agent-and-client-hints-user-agent/),
192
+ so a Chrome user-agent token is not proof that the current browser is Chrome.
193
+ This source-based guidance is not a live GPU-selection test of every browser
194
+ release. The advisory does not change settings, prove another or faster adapter
195
+ exists, inspect the flag's current value, or make a failed load succeed. If the
196
+ browser blocks opening an internal page, the alert retains the copyable address.
197
+
198
+ ## Streaming, cancellation, and tools
199
+
200
+ ```javascript
201
+ async function streamLocalSummaryAfterUserChoice(cancelButton) {
202
+ // The selected browser-WASM model must already be ready.
203
+ if (!cancelButton?.addEventListener) {
204
+ throw new TypeError('A cancel button is required.');
205
+ }
206
+ const abort = new AbortController();
207
+ const stream = ai.llm.stream({
208
+ localOnly:true,
209
+ signal:abort.signal,
210
+ messages:[{role:'user', content:'Summarize this text.'}]
211
+ });
212
+
213
+ const cancel = () => abort.abort('user cancelled');
214
+ cancelButton.addEventListener('click', cancel, {once:true});
215
+ try {
216
+ for await (const chunk of stream) renderChunk(chunk);
217
+ const completion = await stream.result;
218
+ renderCompletion(completion);
219
+ } catch (error) {
220
+ if (error?.code !== 'ARCANE_AI_REQUEST_ABORTED') throw error;
221
+ renderCancelled();
222
+ } finally {
223
+ cancelButton.removeEventListener('click', cancel);
224
+ }
225
+ }
226
+ ```
227
+
228
+ An active cancellation rejects as `ARCANE_AI_REQUEST_ABORTED`. Requests are
229
+ serialized; provider status exposes `busy` and `queued`. Supported request
230
+ generation fields include temperature, top-K, top-P, min-P, repeat penalty,
231
+ and seed. Load settings separately include
232
+ `contextTokens`, `batchTokens`, `microBatchTokens`, `threads`, and GPU-layer
233
+ count. The shipped runtime always sets `gpuLayers: 99999`: WebGPU and proved
234
+ full offload are mandatory, and there is no CPU fallback. Secure context and
235
+ WebGPU/full-offload availability remain browser platform requirements;
236
+ cross-origin isolation and coarse hardware fields remain observations.
237
+
238
+ Tool definitions, tool choice, parallel-tool-call preference, and JSON or JSON
239
+ Schema structured-output requests are passed to Wllama. Returned tool calls are
240
+ validated and surfaced as structural data. Every function declaration requires
241
+ `parameters.properties.message` with `{type:'string',minLength:1}` and includes
242
+ `message` in its `required` list. Every emitted argument JSON object contains
243
+ that nonempty user-facing progress or next-step text; exact IDs, names, and
244
+ argument strings remain intact. The SDK never invokes a handler or executes a
245
+ tool. Application code chooses whether to execute, then records the exact
246
+ matching executed, declined, cancelled, or not-executed `role:'tool'` result
247
+ with nonblank user-facing content before another user turn. High-level sessions accept per-turn request options,
248
+ so visibility-only consumers can select `toolChoice:'none'` for the continuation
249
+ after a not-executed result without calling Wllama directly. Streaming sessions
250
+ buffer a structural call until its exact ID, type, name, and argument string
251
+ match the terminal response; omission or divergence rejects with
252
+ `AI_CHAT_STREAM_TOOL_CALL_MISMATCH` before the call is published or persisted.
253
+ Ordinary iteration exposes only text/reasoning chunks; raw structural deltas
254
+ remain internal until the complete terminal result validates. Explicit
255
+ `onResponse` or inspection consumers retain the complete raw terminal response.
256
+
257
+ ## Errors and unavailable states
258
+
259
+ Invalid configuration can throw `TypeError` or `RangeError`. Operational
260
+ failures expose a stable `.code`; the internal error class is not exported.
261
+ Handle the narrow code needed by the current operation and treat other failures
262
+ as unavailable.
263
+
264
+ | Area | Stable codes |
265
+ | --- | --- |
266
+ | Source and download | `ARCANE_AI_MODEL_SOURCE_INVALID`, `ARCANE_AI_MODEL_SOURCE_UNAVAILABLE`, `ARCANE_AI_MODEL_DOWNLOAD_FAILED`, `ARCANE_AI_MODEL_REDIRECT_BLOCKED` |
267
+ | Cache and storage | `ARCANE_AI_MODEL_CACHE_REJECTED`, `ARCANE_AI_MODEL_OFFLINE_MISS`, `ARCANE_AI_STORAGE_UNAVAILABLE`, `ARCANE_AI_STORAGE_READ_FAILED`, `ARCANE_AI_STORAGE_DELETE_FAILED` |
268
+ | Lifecycle | `ARCANE_AI_UNAVAILABLE`, `ARCANE_AI_NOT_READY`, `ARCANE_AI_MODEL_NOT_READY`, `ARCANE_AI_LOAD_FAILED`, `ARCANE_AI_UNLOAD_FAILED`, `ARCANE_AI_DISPOSE_FAILED`, `ARCANE_AI_DISPOSED`, `ARCANE_AI_OPERATION_SUPERSEDED` |
269
+ | Requests | `ARCANE_AI_REQUEST_ABORTED`, `ARCANE_AI_REQUEST_FAILED`, `ARCANE_AI_RUNTIME_BUSY`, `ARCANE_AI_INVALID_PROVIDER_RESULT`, `ARCANE_AI_TOOL_CALL_INVALID`, `ARCANE_AI_TOOL_MESSAGE_REQUIRED`, `ARCANE_AI_INVALID_TOOL_MESSAGE`, `ARCANE_AI_TOOL_RESULT_REQUIRED`, `ARCANE_AI_LOCAL_ONLY_UNAVAILABLE`, `ARCANE_AI_ADAPTER_PROTOCOL_MISMATCH` |
270
+ | Persistent sessions | `AI_CHAT_INVALID_TOOL_CALL`, `AI_CHAT_INVALID_TOOL_MESSAGE`, `AI_CHAT_TOOL_MESSAGE_REQUIRED`, `AI_CHAT_TOOL_RESULT_REQUIRED`, `AI_CHAT_INCOHERENT_PERSISTENCE`, `AI_CHAT_STREAM_TOOL_CALL_MISMATCH`, `AI_CHAT_TRANSACTION_SETTLED` |
271
+ | Provider/2 adapter | `ARCANE_AI_MODEL_AUTHORITY_REQUIRED`, `ARCANE_AI_PROVIDER_ROLE_MISMATCH`, `ARCANE_AI_PROVIDER_PROGRESS_INVALID`, `ARCANE_AI_PROVIDER_STATUS_INVALID`, `ARCANE_AI_PROVIDER_OPERATION_UNAVAILABLE` |
272
+ | WebGPU and model availability | `ARCANE_AI_WEBGPU_REQUIRED`, `ARCANE_AI_WEBGPU_API_UNAVAILABLE`, `ARCANE_AI_WEBGPU_EVIDENCE_INVALID`, `ARCANE_AI_MODEL_FULL_OFFLOAD_UNPROVEN`, `ARCANE_AI_MODEL_WEBGPU_REQUIREMENT_FAILED`, `ARCANE_AI_MODEL_GPU_MEMORY_INSUFFICIENT`, `ARCANE_AI_MODEL_RELOAD_REQUIRED`, `ARCANE_AI_LOAD_PLAN_RELOAD_REQUIRED` |
273
+ | Worker cleanup and recovery | `ARCANE_AI_WORKER_TERMINATION_UNCONFIRMED`, `ARCANE_AI_COMPLETION_RECOVERY_UNCONFIRMED` |
274
+ | Diagnostics | `ARCANE_AI_PROBE_FAILED` |
275
+
276
+ Capability and status records also carry stable reason codes. These observations
277
+ are not all thrown errors: positive and unknown states let an application
278
+ explain why load is available, blocked, or not yet measured without guessing.
279
+
280
+ | Observation | Status/reason codes |
281
+ | --- | --- |
282
+ | Browser prerequisites | `ARCANE_AI_WEBASSEMBLY_UNAVAILABLE`, `ARCANE_AI_OPFS_UNAVAILABLE`, `ARCANE_AI_SECURE_CONTEXT_REQUIRED` |
283
+ | Positive cache/storage state | `ARCANE_AI_MODEL_CACHE_COMPLETE`, `ARCANE_AI_STORAGE_CAPACITY_AVAILABLE` |
284
+ | WebGPU execution evidence | `ARCANE_AI_WEBGPU_EXECUTION_OBSERVED`, `ARCANE_AI_WEBGPU_EXECUTION_UNOBSERVED` |
285
+ | Provider and runtime failure state | `ARCANE_AI_PROVIDER_UNAVAILABLE`, `ARCANE_AI_RUNTIME_FAILED` |
286
+
287
+ `capabilities()` reports browser observations such as WebAssembly, OPFS,
288
+ WebGPU API presence, WebGPU operation, secure context, cross-origin
289
+ isolation, and hardware concurrency. `navigator.gpu` alone is not operational
290
+ evidence. The authoritative runtime can operate without cross-origin isolation,
291
+ so that flag is not a hard gate; secure context and WebGPU/full-offload support
292
+ are platform requirements. `probe()` exercises packaged Wllama backend
293
+ operations only while unloaded; it does not download a model.
294
+
295
+ ## BROWSER_WASM_RUNTIME_AUTHORITY
296
+
297
+ ### Overview
298
+
299
+ Mutable metadata for the shipped browser runtime. Its protocol is
300
+ `arcane-ai-browser-wasm/2`; the direct provider uses
301
+ `arcane-ai-adapter/1` and `adaptV1LlmProvider()` projects it into
302
+ `arcane-ai-provider/2`. It records Wllama `3.6.0`, the embedded llama.cpp
303
+ revision, licenses, and the disabled compatibility-runtime and
304
+ remote-model-helper policy.
305
+
306
+ ### Value and import
307
+
308
+ ```text
309
+ const BROWSER_WASM_RUNTIME_AUTHORITY
310
+ ```
311
+
312
+ ### Availability and normalization
313
+
314
+ **Browser metadata; safely inspectable without loading a model.** The value is
315
+ metadata, not a provider instance, model catalog, or capability grant.
316
+
317
+ ### Example
318
+
319
+ ```javascript
320
+ import {BROWSER_WASM_RUNTIME_AUTHORITY} from 'arcane-os/ai/browser-wasm';
321
+
322
+ console.log(BROWSER_WASM_RUNTIME_AUTHORITY.protocol);
323
+ console.log(BROWSER_WASM_RUNTIME_AUTHORITY.package.version); // 3.6.0
324
+ ```
325
+
326
+ ## completeValueText()
327
+
328
+ ### Overview
329
+
330
+ Returns complete caller content as text. Strings are returned unchanged;
331
+ supported non-string values become readable JSON text. Cycles use `$ref`
332
+ records, and special primitives, maps, sets, dates, regular expressions,
333
+ functions, symbols, typed views, array buffers, and accessors retain explicit
334
+ representations.
335
+
336
+ ### Signature and result
337
+
338
+ ```text
339
+ completeValueText(value)
340
+ ```
341
+
342
+ The function returns one complete string. It reads ordinary data descriptors
343
+ without invoking accessors and records repeated object references by their
344
+ first traversal location.
345
+
346
+ ### Availability and normalization
347
+
348
+ **Compatible JavaScript module host.** This is a pure value-to-text helper. It
349
+ does not require a provider, model, cache, storage, WebAssembly, or browser
350
+ capability.
351
+
352
+ ### Example
353
+
354
+ ```javascript
355
+ import {completeValueText} from 'arcane-os/ai/browser-wasm';
356
+
357
+ const status = new Map([
358
+ ['state','ready'],
359
+ ['roles',new Set(['llm'])]
360
+ ]);
361
+ console.log(completeValueText(status));
362
+ ```
363
+
364
+ ## createArcaneAI()
365
+
366
+ ### Overview
367
+
368
+ Creates the application-facing AI API module around a provider or an existing
369
+ LLM controller. Use this as the primary browser-local API; construct the source,
370
+ store, and Wllama provider beneath it.
371
+
372
+ ### Signature and result
373
+
374
+ ```text
375
+ createArcaneAI({ llm=null, provider=null, loadPolicy='on-demand', security }={})
376
+ ```
377
+
378
+ At least one `llm` or `provider` is required; when both are supplied, `llm`
379
+ takes precedence. `loadPolicy` is `on-demand` or `manual`. The mutable result
380
+ contains `llm`, `runtime`, `createChatSession`, `status`, `load`,
381
+ `unload`, `probe`, `fetchRequest`, `streamRequest`, and `dispose`.
382
+ `security` carries only the app-level boolean `secure` intent inherited by
383
+ provider loads. The SDK default is `secure:false`; `ai.load({security})` can
384
+ override that intent for the operation, but no checking implementation runs
385
+ until a separately authorized review enables one.
386
+
387
+ When `llm` is an existing `ModelController`, that controller keeps the security
388
+ and load policy with which it was created. This function
389
+ does not reapply its `loadPolicy` argument in that case, and supplying `security` alongside the
390
+ existing controller throws `TypeError`. Passing a provider instead creates a
391
+ new controller with the requested policy and security.
392
+
393
+ ### Availability and normalization
394
+
395
+ **Browser.** It normalizes provider lifecycle and request observation without
396
+ selecting a model, changing browser permissions, contacting Arcane Core, or
397
+ creating a fallback provider.
398
+
399
+ ### Example
400
+
401
+ ```javascript
402
+ const ai = createArcaneAI({provider, loadPolicy:'manual'});
403
+ async function loadCachedModelAfterUserChoice() {
404
+ const off = ai.llm.on('statechange', event => renderStatus(event.detail));
405
+ try {
406
+ return await ai.load({offline:true});
407
+ } finally {
408
+ off();
409
+ }
410
+ }
411
+ ```
412
+
413
+ `await ai.createChatSession(options)` dynamically creates a
414
+ [`PersistentAIChatSession`](../runtime-modules.md#persistentaichatsessionjs)
415
+ whose AI API is permanently bound to this controller. `options` must
416
+ be a plain object and must not contain `chat`; this prevents a session from
417
+ claiming the controller's lifecycle while sending its turns through another
418
+ provider.
419
+
420
+ ## createBrowserModelSource()
421
+
422
+ ### Overview
423
+
424
+ Validates a caller-owned canonical ordered multi-file descriptor and creates
425
+ the cancellable HTTPS download source accepted by this provider.
426
+
427
+ ### Signature and result
428
+
429
+ ```text
430
+ createBrowserModelSource(descriptor, { fetchImpl=null }={})
431
+ ```
432
+
433
+ The mutable source includes `kind`, the canonical descriptor fields,
434
+ `descriptor`, and `open(memberIndex=0,{signal})`. An omitted index selects the
435
+ first member. The method returns the complete readable response body,
436
+ requested/final URLs, nullable observed `contentLength`, and `cancel()`; caching
437
+ and the store's private per-member Range negotiation remain store-owned.
438
+
439
+ ### Availability and normalization
440
+
441
+ **Browser Fetch with CORS.** URL and optional metadata syntax are normalized.
442
+ Declared and observed lengths feed only progress and transport planning.
443
+ Ordinary source loading performs no expected-length, hash, digest, receipt,
444
+ freeze, content-identity, admission, or cache-reuse checks.
445
+
446
+ ### Example
447
+
448
+ ```javascript
449
+ const source = createBrowserModelSource(MODEL);
450
+ console.log(source.id, source.files);
451
+ ```
452
+
453
+ ## createBrowserWasmLlmProvider()
454
+
455
+ ### Overview
456
+
457
+ Creates the local-only Wllama provider from genuine source and store objects
458
+ created by this module. Structural lookalikes are rejected.
459
+
460
+ ### Signature and result
461
+
462
+ ```text
463
+ createBrowserWasmLlmProvider({ sources, store, loadDefaults={}, security, logger=console }={})
464
+ ```
465
+
466
+ `sources` is a nonempty array of unique SDK-created model sources. Its first
467
+ entry is the default model. The mutable result exposes protocol and provider
468
+ identity, default model metadata,
469
+ `catalog`, `capabilities`, `status`, `load`, `unload`, `chat`, `stream`,
470
+ `streamChat`, `use`, `probe`, and `dispose`. Direct provider `load()` selects a
471
+ catalog model and returns `{model,status}`;
472
+ the public AI API module's `ai.load()` returns the flat controller status.
473
+ Direct `load({onProgress})` forwards the same additive file and byte progress
474
+ records used by the controller and provider/2 adapter.
475
+ Provider `security` carries the provider/model-binding `secure` intent. Direct
476
+ `provider.load({security})` and `ai.load({security})` supply the operation
477
+ intent. They do not activate checking in the ordinary development contract.
478
+
479
+ ### Availability and normalization
480
+
481
+ **Browser secure context with WebAssembly, OPFS/DBOPFS, WebGPU, and full-offload
482
+ support.** Inference is local after a successful Wllama load.
483
+ The runtime forces `gpuLayers: 99999`; callers cannot select CPU or partial
484
+ offload. Status discloses the optional `secure` intent, capability state,
485
+ storage/model compatibility, and lifecycle state; it does not claim that
486
+ hardening ran.
487
+
488
+ ### Example
489
+
490
+ ```javascript
491
+ const provider = createBrowserWasmLlmProvider({
492
+ sources:[source],
493
+ store,
494
+ loadDefaults:{threads:1, contextTokens:4096}
495
+ });
496
+ console.log(provider.status().state); // unloaded
497
+ ```
498
+
499
+ ## createDbopfsModelStore()
500
+
501
+ ### Overview
502
+
503
+ Adapts an existing DBOPFS instance without renaming or replacing its public
504
+ methods. The adapter owns model-file caching and complete-set exposure.
505
+
506
+ ### Signature and result
507
+
508
+ ```text
509
+ createDbopfsModelStore({ dbopfs, tableName='arcane_ai_browser_models', estimateStorage=null, downloadConcurrency=4 }={})
510
+ ```
511
+
512
+ The optional `estimateStorage()` function supplies browser storage availability
513
+ when the default estimator is unavailable or an application owns a more precise
514
+ quota view. `downloadConcurrency` must be a positive safe integer and bounds
515
+ the selected file or Range worker pool; the default is four. The mutable result
516
+ contains `kind`, `tableName`, `downloadConcurrency`, the original `adapter`,
517
+ and `ready`, `install`, `ensure`, and `remove`. `ensure()` preserves the complete
518
+ ordered model set and reports whether it was cached or installed.
519
+ `install(source,{signal,onProgress})` and
520
+ `ensure(source,{signal,onProgress,offline})` publish `cache-check` and
521
+ `download` records using ordered file counts plus aggregate transfer telemetry
522
+ when `onProgress` is supplied. Chunk-driven changes are coalesced on a 250 ms
523
+ cadence, with immediate boundary records at start, plan/total discovery,
524
+ active-worker changes, and completion. Multi-file sources use up to that many concurrent member workers
525
+ while retaining descriptor order, preserve completed members and completed
526
+ Range parts within members across an interrupted attempt, and fetch only
527
+ missing work on retry. A complete set of optional member
528
+ `bytes` values makes aggregate total and remaining progress available from the
529
+ start; otherwise those fields remain `null` until an honest aggregate total is
530
+ known. Each missing source member first requests `bytes=0-0`. If a followed
531
+ redirect turns that probe into a full `200`, the source probes the final URL directly;
532
+ confirmed support cancels the original body and starts parallel Range workers,
533
+ while refusal keeps the original full response as the single-fetch fallback. A
534
+ valid `Content-Range`, or optional descriptor `bytes` when that header is not
535
+ exposed, supplies the total for deterministic resumable Range parts of roughly
536
+ 4 MB each, up to 4,096 parts. Without an observable or declared total, the store falls back to one full fetch and
537
+ uses its readable `Content-Length` when available. A later non-206,
538
+ contradictory exposed Range response, or incorrectly framed Range body fails
539
+ rather than silently assembling a partial model. A transfer failure lets peer
540
+ transfers settle; explicit cancellation stops active transfers. Both preserve
541
+ completed members and exact Range parts for retry, while unfinished active
542
+ parts restart after refresh. A complete whole member supersedes its current
543
+ Range fragments.
544
+ Cleanup failure is warned without replacing a usable model. Zero-length abandoned entries are removed
545
+ because Wllama cannot consume an empty model Blob or File.
546
+
547
+ ### Availability and normalization
548
+
549
+ **Browser with a ready DBOPFS instance and OPFS.** Cache metadata is not a
550
+ transferable capability token or proof of model license rights.
551
+
552
+ ### Example
553
+
554
+ ```javascript
555
+ const store = createDbopfsModelStore({dbopfs});
556
+ async function loadCachedModelAfterUserChoice() {
557
+ await store.ready();
558
+ const cached = await store.ensure(source,{offline:true});
559
+ console.log(cached ? 'cached model' : 'cache miss');
560
+ }
561
+ ```
562
+
563
+ ## adaptV1LlmProvider()
564
+
565
+ ### Overview
566
+
567
+ Projects one compatible v1 browser-WASM provider into the same provider/2 LLM
568
+ role used by `AIProviderRuntime.js`. It checks the v1 protocol, required methods,
569
+ and local-only capability. The adapter does
570
+ not change the wrapped provider, download a model, execute a tool, or create a
571
+ fallback.
572
+
573
+ ### Signature and result
574
+
575
+ ```text
576
+ adaptV1LlmProvider(provider)
577
+ ```
578
+
579
+ The mutable result exposes `{protocol:'arcane-ai-provider/2',role:'llm',id,
580
+ localOnly:true,catalog,inspect,status,load,request,unload,dispose}`. Inspection
581
+ returns `arcane-ai-model-authority/1` only for an exact catalog selection.
582
+ `request()` supports `chat` and `stream` and preserves structural tool data.
583
+ Both operations validate request history and tool declarations before provider
584
+ dispatch, then validate every terminal choice and required nonempty
585
+ `arguments.message`. The adapter drains the private provider stream regardless
586
+ of whether the consumer iterates first or awaits `result` first. Its ordinary
587
+ iterator receives complete nonstructural content/reasoning projections from
588
+ every choice in FIFO order, while structural deltas remain private until the
589
+ complete terminal `result` validates. A terminal-only structural call is valid;
590
+ any call observed during streaming must preserve its choice, ordered position,
591
+ ID, type, name, exact argument string, and extension fields in the terminal
592
+ envelope. Consumer `return()` starts observed provider cancellation immediately
593
+ and completes the iterator return without waiting for provider cleanup. The
594
+ terminal `result` retains provider settlement, and a later
595
+ cancellation/iterator-return failure is reported completely to the developer
596
+ console.
597
+
598
+ ### Availability and normalization
599
+
600
+ The adapter is available anywhere the caller can supply a compatible
601
+ `arcane-ai-browser-wasm/1` provider object. It performs only the versioned
602
+ provider-shape normalization into `arcane-ai-provider/2`. The v1 ingress,
603
+ terminal result, cancellation, and ordinary iterator projection use the same
604
+ structural-message contract; the wrapper does not create a
605
+ runtime, choose or download a model, grant host capability, change local-only
606
+ behavior, or make an arbitrary provider authoritative. Provider lifecycle,
607
+ cancellation, catalog selection, and failures remain owned by the wrapped
608
+ provider and are forwarded through the normalized role contract.
609
+
610
+ ### Example
611
+
612
+ ```javascript
613
+ import {adaptV1LlmProvider} from 'arcane-os/ai/browser-wasm';
614
+ import {getAIProviderRuntime} from 'arcane/AIProviderRuntime';
615
+
616
+ const runtime = getAIProviderRuntime();
617
+ const release = runtime.register(adaptV1LlmProvider(provider));
618
+ // Configure an exact llm route before load/use. Release registration at teardown.
619
+ release();
620
+ ```
621
+
622
+ ## Related reference
623
+
624
+ - [Canonical `createArcaneAI()` entry](../sdk-api.md#createarcaneai) and the
625
+ sibling [`BROWSER_WASM_RUNTIME_AUTHORITY`](../sdk-api.md#browserwasmruntimeauthority),
626
+ [`adaptV1LlmProvider()`](../sdk-api.md#adaptv1llmprovider),
627
+ [`completeValueText()`](../sdk-api.md#completevaluetext),
628
+ [`createBrowserModelSource()`](../sdk-api.md#createbrowsermodelsource),
629
+ [`createBrowserWasmLlmProvider()`](../sdk-api.md#createbrowserwasmllmprovider),
630
+ and [`createDbopfsModelStore()`](../sdk-api.md#createdbopfsmodelstore) entries
631
+ - [Browser-local normalization boundary](../availability-and-normalization.md#browser-local-provider-adapter)
632
+ - [Browser runtime delivery](../protocols.md#browser-runtime-delivery)
633
+ - [Browser-WASM behavior evidence](../behavioral-testing.md#behavioral-coverage-model)
634
+ - [DBOPFS runtime module](../runtime-modules.md#dbopfsjs)
635
+ - [Browser speech providers](browser-speech.md)
636
+ - [Provider-neutral AI runtime](../runtime-modules.md#aiproviderruntimejs)
637
+ - [Persistent chat](../runtime-modules.md#persistentaichatsessionjs)