arcane-os 0.2.1 → 0.2.3

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 (30) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +8 -8
  3. package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +5 -5
  4. package/browser-runtime/ai/browser-speech-providers.mjs +1 -0
  5. package/docs/architecture.md +2 -2
  6. package/docs/reference/README.md +79 -13
  7. package/docs/reference/ai/browser-speech.md +336 -0
  8. package/docs/reference/ai/browser-wasm.md +207 -82
  9. package/docs/reference/availability-and-normalization.md +33 -4
  10. package/docs/reference/behavioral-testing.md +4 -1
  11. package/docs/reference/cli.md +29 -10
  12. package/docs/reference/core/arcane-ai-contracts.md +43 -9
  13. package/docs/reference/inventory/package-api.json +110 -14
  14. package/docs/reference/inventory/runtime-components.json +42 -14
  15. package/docs/reference/inventory/runtime-modules.json +118 -13
  16. package/docs/reference/protocols.md +264 -38
  17. package/docs/reference/runtime-components.md +177 -21
  18. package/docs/reference/runtime-modules.md +449 -13
  19. package/docs/reference/sdk-api.md +626 -85
  20. package/package.json +1 -1
  21. package/runtime/ARCANE_RUNTIME_RELEASE.json +19 -19
  22. package/runtime/arcane/components/chat.html +17 -52
  23. package/runtime/arcane/components/speech.html +109 -29
  24. package/runtime/arcane/components/voice-transcription.html +437 -68
  25. package/runtime/arcane/modules/AI.js +556 -128
  26. package/runtime/arcane/modules/AIProviderRuntime.js +299 -30
  27. package/runtime/arcane/modules/AIRuntimeState.js +23 -4
  28. package/runtime/arcane/modules/ComponentContracts.js +272 -0
  29. package/runtime/arcane/modules/LocalAIReadinessController.js +1 -1
  30. package/schemas/arcane-lock.schema.json +2 -2
@@ -1,13 +1,21 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "source": {
4
- "commit": "567ad110bf57a1c2d4a3daa22ae93716cc5f4d7e",
5
- "bundleVersion": "0.8.12",
4
+ "authority": "sdk-canonical",
5
+ "repository": "https://github.com/TheWizardNexus/arcane-os-sdk.git",
6
+ "commit": "f97ac4f2e7cc92a00a3a466c38a67446dd112acf",
7
+ "path": "runtime/arcane",
8
+ "sdkVersion": "0.2.3",
9
+ "legacyProjection": {
10
+ "repository": "https://github.com/TheWizardNexus/ARCANE-OS.git",
11
+ "commit": "c540014afe69f14cf5ae60493b7295f36dbcec64",
12
+ "bundleVersion": "0.8.12"
13
+ },
6
14
  "protocol": "arcane/1"
7
15
  },
8
- "artifactCount": 80,
9
- "javascriptArtifactCount": 78,
10
- "esmExportCount": 282,
16
+ "artifactCount": 85,
17
+ "javascriptArtifactCount": 83,
18
+ "esmExportCount": 319,
11
19
  "artifacts": [
12
20
  {
13
21
  "file": "runtime/arcane/modules/AI.js",
@@ -18,9 +26,9 @@
18
26
  ],
19
27
  "summary": "Provider-selectable chat, speech-to-text, text-to-speech, tool calling, structured output, streaming, and queued audio playback.",
20
28
  "availability": "Browser + native bridge + cloud",
21
- "protocol": "OpenAI HTTPS, Arcane.ollama, Arcane.speech, Android WebView bridge",
22
- "normalization": "High-level chat/speech behavior is normalized; provider diagnostics and media errors remain mixed.",
23
- "surface": "default `AI`; `setAI()`, `streamRequest()`, `streamMessage()`, `fetchRequest()`, `fetch()`, `streamTTS()`, `finishTTS()`, `fetchSTT()`, `stopAudio()`, `resumeAudio()`, `playAudio()`; installs `window.ai` and emits `ai-ready`."
29
+ "protocol": "AIProviderRuntime arcane-ai-provider/2 routes, OpenAI HTTPS, Arcane.ollama, Arcane.speech, Android WebView bridge",
30
+ "normalization": "High-level chat/speech behavior, truthful legacy-route readiness, and shared browser speech request/result conversion are normalized; provider diagnostics and media errors remain mixed.",
31
+ "surface": "default `AI`; `providerRuntime`; `setAI()`, `configureProviders()`, `transitionAI()`, `transitionProviders()`, `startProviders()`, `setSpeechMuted()`, `streamRequest()`, `streamMessage()`, `fetchRequest()`, `fetch()`, `streamTTS()`, `finishTTS()`, `fetchSTT()`, `stopAudio()`, `resumeAudio()`, `playAudio()`; consumes `user-entity-loaded` and `arcane-ollama-ready`, installs `window.ai`, and emits `ai-ready`."
24
32
  },
25
33
  {
26
34
  "file": "runtime/arcane/modules/AIPreferenceRuntime.js",
@@ -51,6 +59,24 @@
51
59
  "normalization": "Fully normalized frozen tuple.",
52
60
  "surface": "`AI_PREFERENCE_SLOT_KEYS`, `normalizeAIPreferenceTuple()`, `aiPreferenceTuplesEqual()`."
53
61
  },
62
+ {
63
+ "file": "runtime/arcane/modules/AIProviderRuntime.js",
64
+ "name": "AIProviderRuntime.js",
65
+ "kind": "esm",
66
+ "exports": [
67
+ "AI_MODEL_AUTHORITY_PROTOCOL",
68
+ "AI_PROVIDER_PROTOCOL",
69
+ "AI_PROVIDER_RUNTIME_PROTOCOL",
70
+ "AIProviderRuntime",
71
+ "aiProviderRuntime",
72
+ "getAIProviderRuntime"
73
+ ],
74
+ "summary": "Provider-neutral selection, lifecycle, routing, startup, request, streaming, cancellation, and independent LLM/STT/TTS state.",
75
+ "availability": "Cross-host in-process runtime; registered providers remain browser, native, or cloud specific",
76
+ "protocol": "arcane-ai-runtime/2, arcane-ai-provider/2, arcane-ai-model-authority/1",
77
+ "normalization": "Normalizes immutable per-role routes, lifecycle/status, cancellation, streaming cleanup, and local-only selection without creating a fallback.",
78
+ "surface": "Protocol constants; singleton-only `AIProviderRuntime`; `aiProviderRuntime`; `getAIProviderRuntime()`; provider registration/configuration, lifecycle, request, stream, speech, cancellation, and mute controls."
79
+ },
54
80
  {
55
81
  "file": "runtime/arcane/modules/AIResponseLength.js",
56
82
  "name": "AIResponseLength.js",
@@ -84,6 +110,32 @@
84
110
  "normalization": "Normalized frozen allowlist audit.",
85
111
  "surface": "`auditAIResponseLinks()`, `extractAIResponseLinks()`, `normalizeAIResponseLink()`, `decodeHTMLCharacterReferences()`."
86
112
  },
113
+ {
114
+ "file": "runtime/arcane/modules/AIRuntimeState.js",
115
+ "name": "AIRuntimeState.js",
116
+ "kind": "esm",
117
+ "exports": [
118
+ "AI_RUNTIME_INTENT_EVENT",
119
+ "AI_RUNTIME_PROTOCOL",
120
+ "AI_RUNTIME_ROLES",
121
+ "AI_RUNTIME_STARTUP_EVENT",
122
+ "AI_RUNTIME_STATES",
123
+ "AI_RUNTIME_STATE_EVENT",
124
+ "aiRuntimeEvents",
125
+ "getAIRuntimeState",
126
+ "publishAIRuntimeRoleState",
127
+ "publishAIRuntimeRolesState",
128
+ "requestAIRuntimeIntent",
129
+ "startAIRuntime",
130
+ "subscribeAIRuntimeIntents",
131
+ "subscribeAIRuntimeState"
132
+ ],
133
+ "summary": "Sticky immutable LLM, speech-to-text, and text-to-speech lifecycle snapshots, intents, subscriptions, and startup-settlement barriers.",
134
+ "availability": "Cross-host in-process state contract; actual role readiness remains provider specific",
135
+ "protocol": "arcane-ai-runtime-state/1 over EventTarget",
136
+ "normalization": "Closed role records and monotonic revisions normalize state across providers; subscriptions never grant authority or load a provider.",
137
+ "surface": "Protocol/event/state constants; `aiRuntimeEvents`; snapshot, subscribe, publish, intent, and `startAIRuntime()` functions."
138
+ },
87
139
  {
88
140
  "file": "runtime/arcane/modules/AnsiText.js",
89
141
  "name": "AnsiText.js",
@@ -355,6 +407,7 @@
355
407
  "VOICE_MESSAGES",
356
408
  "appendTranscription",
357
409
  "applyMarkdownFormat",
410
+ "createSTTActivationController",
358
411
  "effectiveDashboardVisibility",
359
412
  "normalizeChartOptions",
360
413
  "normalizeChartRows",
@@ -365,11 +418,11 @@
365
418
  "normalizeMarkdownOptions",
366
419
  "normalizeVoiceOptions"
367
420
  ],
368
- "summary": "Owns normalized configuration/value contracts shared by chart, dashboard, Markdown, and voice components.",
369
- "availability": "Cross-host",
421
+ "summary": "Owns normalized configuration/value contracts and shared explicit STT activation behavior for chart, dashboard, Markdown, and voice components.",
422
+ "availability": "Cross-host with an injected event constructor outside DOM hosts",
370
423
  "protocol": "In-process only",
371
- "normalization": "Fully normalized labels, rows, definitions, visibility, formats, editor and voice options.",
372
- "surface": "Six constant sets and twelve normalization/formatting helpers."
424
+ "normalization": "Fully normalized labels, rows, definitions, visibility, formats, editor and voice options, plus capability-neutral STT activation intent and presentation state.",
425
+ "surface": "Constant sets plus normalization, formatting, and explicit STT activation helpers."
373
426
  },
374
427
  {
375
428
  "file": "runtime/arcane/modules/ConfiguredAIChatSession.js",
@@ -382,7 +435,7 @@
382
435
  "availability": "Native bridge by default; cross-host with injected chat",
383
436
  "protocol": "Arcane.ai.chat or injected provider",
384
437
  "normalization": "Normalized session/result; provider rejection preserved.",
385
- "surface": "default `ConfiguredAIChatSession`; `history()`, `clear()`, `send()`."
438
+ "surface": "default `ConfiguredAIChatSession`; constructor accepts bounded coherent `initialMessages` plus configuration; `history()`, `clear()`, `prepare()`, `send()`; prior normalized and exactly-one-choice OpenAI-compatible responses normalize to one frozen session result."
386
439
  },
387
440
  {
388
441
  "file": "runtime/arcane/modules/ConversationActionItems.js",
@@ -515,6 +568,22 @@
515
568
  "normalization": "App scope normalized; DOM/storage errors preserved.",
516
569
  "surface": "default `DBOPFS`; installs `window.dbopfs`, emits `dbopfs-ready`; table/file/backup APIs."
517
570
  },
571
+ {
572
+ "file": "runtime/arcane/modules/DBOPFSDocumentLibrary.js",
573
+ "name": "DBOPFSDocumentLibrary.js",
574
+ "kind": "esm",
575
+ "exports": [
576
+ "DBOPFSDocumentLibrary",
577
+ "createDBOPFSDocumentLibrary",
578
+ "default",
579
+ "normalizeDBOPFSDocumentSchema"
580
+ ],
581
+ "summary": "Application-defined document corpus bootstrap, caller-source evaluation, atomic DBOPFS generations, bounded lexical search, and untrusted request-context construction.",
582
+ "availability": "Browser or compatible host with an existing DBOPFS-style database adapter",
583
+ "protocol": "Existing DBOPFS get/set/getAllKeys/delete methods; no new storage protocol",
584
+ "normalization": "Preserves DBOPFS method semantics, commits a completion manifest last, validates every stored generation, exposes explicit reject or preserve-readable read-failure policy, and labels retrieved context as untrusted data.",
585
+ "surface": "`DBOPFSDocumentLibrary`, `createDBOPFSDocumentLibrary()`, `normalizeDBOPFSDocumentSchema()`; `schema`, `bootstrap()`, `search()`, `evaluate()`, `buildContext()`, and `createContextBuilder()`."
586
+ },
518
587
  {
519
588
  "file": "runtime/arcane/modules/DBOPFSWorker.js",
520
589
  "name": "DBOPFSWorker.js",
@@ -557,6 +626,27 @@
557
626
  "normalization": "Strict normalized selection and coded errors.",
558
627
  "surface": "default `DirectoryPicker`, `normalizeDirectoryPickerOptions()`, `normalizeDirectorySelection()`."
559
628
  },
629
+ {
630
+ "file": "runtime/arcane/modules/DocumentLexicalSearch.js",
631
+ "name": "DocumentLexicalSearch.js",
632
+ "kind": "esm",
633
+ "exports": [
634
+ "DOCUMENT_SEARCH_FIELD_ORDER",
635
+ "DocumentLexicalSearch",
636
+ "createDocumentLexicalIndex",
637
+ "default",
638
+ "documentContextExcerpt",
639
+ "documentSearchTokens",
640
+ "normalizedDocumentSearchText",
641
+ "scoreDocumentBody",
642
+ "scoreDocumentLexicalIndex"
643
+ ],
644
+ "summary": "Dependency-free deterministic document indexing, ranked metadata/body search, bounded excerpts, and stable tie-breaking.",
645
+ "availability": "Cross-host in-process only",
646
+ "protocol": "In-process immutable record contract",
647
+ "normalization": "Normalizes text and filters, preserves deterministic field priority, and returns frozen results without network, storage, or provider side effects.",
648
+ "surface": "Search-field constant; `DocumentLexicalSearch`; index/token/score/excerpt helpers; `rank()` and bounded `search()`."
649
+ },
560
650
  {
561
651
  "file": "runtime/arcane/modules/DocumentNavigation.js",
562
652
  "name": "DocumentNavigation.js",
@@ -851,6 +941,21 @@
851
941
  "normalization": "Provider data normalized to entities; transport errors mixed.",
852
942
  "surface": "Endpoint constants, default provider, `mapForecast()`; search/load methods and lifecycle events."
853
943
  },
944
+ {
945
+ "file": "runtime/arcane/modules/PersistentAIChatSession.js",
946
+ "name": "PersistentAIChatSession.js",
947
+ "kind": "esm",
948
+ "exports": [
949
+ "PersistentAIChatSession",
950
+ "createPersistentAIChatSession",
951
+ "default"
952
+ ],
953
+ "summary": "Composes bounded configured chat with an existing ChatEntity so each user, assistant, and structural tool turn has an explicit persistence policy.",
954
+ "availability": "Browser or native WebView with the projected ChatEntity, DBOPFS, and a configured chat function or normalized Arcane.ai surface",
955
+ "protocol": "Existing ChatEntity/DBOPFS methods plus provider-neutral chat request/result records",
956
+ "normalization": "Preserves existing chat/history/memory semantics, commits live context atomically, and keeps durable persistence coherent across structural tool-call/result pairs.",
957
+ "surface": "Default/named `PersistentAIChatSession`, `createPersistentAIChatSession()`; `create()`, `chatEntity`, `fileName`, `ready()`, `history()`, `settleMemory()`, and `send()`."
958
+ },
854
959
  {
855
960
  "file": "runtime/arcane/modules/PreferenceStore.js",
856
961
  "name": "PreferenceStore.js",
@@ -1,27 +1,27 @@
1
1
  # Protocol and host architecture
2
2
 
3
3
  This is the deep reference behind the compact availability notes elsewhere.
4
- Application developers normally call one documented API and do not choose a
5
- wire protocol directly.
4
+ Application developers should start with the
5
+ [availability and normalization guide](availability-and-normalization.md), call
6
+ one documented API, and treat the protocols below as implementation detail.
6
7
 
7
8
  ## Layer map
8
9
 
9
10
  ```text
10
11
  application code
11
- |-- Node SDK API ---------------- arcane-cli-events/1 + SDK receipts
12
- |-- EventManager ---------------- synchronous bus + arcane-event-stack/1
13
- |
14
- `-- renderer ESM / globalThis.Arcane
15
- |-- standalone browser ----- standard Web APIs / allowed HTTPS
16
- |-- development host ------- development HTTP bridge
17
- |-- Microsoft NT native ---- WebView2 host bridge
18
- |-- Linux native ----------- WebKitGTK host bridge
19
- `-- Android native --------- Android WebView message bridge
20
- |
21
- `-- Arcane Core/provider boundary
22
- |-- platform services
23
- |-- ArcaneOllama loopback service
24
- `-- explicitly selected cloud APIs
12
+ |-- Node SDK API ----------------- arcane-cli-events/1 + SDK receipts
13
+ |-- EventManager ----------------- synchronous bus + arcane-event-stack/1
14
+ |-- browser-local AI ------------- WebGPU/WASM/Workers/DBOPFS; no Core grant
15
+ `-- globalThis.Arcane
16
+ |-- development host -------- development HTTP bridge
17
+ |-- Microsoft NT native ----- WebView2 host bridge
18
+ |-- Linux native ------------ WebKitGTK host bridge
19
+ `-- Android native ---------- Android WebView message bridge
20
+ |
21
+ `-- Arcane Core/provider boundary
22
+ |-- platform services
23
+ |-- ArcaneOllama loopback service
24
+ `-- explicitly selected cloud APIs
25
25
  ```
26
26
 
27
27
  Each downward boundary can add authority and platform capability. None can be
@@ -103,25 +103,43 @@ imports such as:
103
103
  import ollama from 'arcane/Ollama';
104
104
  ```
105
105
 
106
- The authenticated physical-v1 tree lives entirely beneath `arcane/`. It
107
- contains 155 pinned Arcane runtime files plus 18 SDK browser-runtime files:
108
- 173 files in all. Runtime `strong-type` 1.1 stays under
109
- `arcane/dependencies/strong-type/`; the focused SDK event surface lives under
110
- `arcane/sdk/`, with `event-pubsub` 6.1 and its sibling `strong-type` 2.0 under
111
- `arcane/sdk/dependencies/`. This URL-key separation prevents the runtime and SDK
112
- dependency versions from aliasing one another. Development serves the selected
113
- app plus that authenticated tree. Packaging copies the same map, app entry, and
114
- physical bytes into `dist/<id>`; targets never resolve through the consumer
115
- workspace's root `node_modules/`.
116
-
117
- In SDK `0.1.2`, the generated map has exactly 86 entries: 73 named
118
- `arcane/*` modules, nine `arcane/entities/*` modules, and these four focused or
119
- compatibility mappings:
106
+ The authenticated physical-v1 tree lives entirely beneath `arcane/`. SDK
107
+ `0.2.3` projects it from two canonical release receipts:
108
+
109
+ | Canonical receipt | Source authority and protocol | Receipt inventory |
110
+ | --- | --- | --- |
111
+ | `runtime/ARCANE_RUNTIME_RELEASE.json` | `sdk-canonical`; `arcane/1`; builder `arcane-sdk-runtime-v1` | 160 files; 3,655,536 bytes; content SHA-256 `f96a27bd79a809201708f73ca729bc60ab02696daf619365f77267a28b47b4b3` |
112
+ | `browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json` | `arcane-os-sdk`; `arcane-sdk-browser-runtime/1`; builder `arcane-sdk-browser-runtime-v1` | 25 files; 9,280,047 bytes; content SHA-256 `3c82ed11b24c7b7b91b62f6dc52e0b1dcd444112a29cd48413eedc008380eb61` |
113
+
114
+ The runtime receipt is the current byte authority. Its Arcane OS
115
+ `c540014afe69f14cf5ae60493b7295f36dbcec64` / bundle `0.8.12` record is
116
+ `legacyProjection` provenance, not a second or newer runtime authority. The
117
+ browser receipt binds `event-pubsub` `6.1.0`, `strong-type` `2.0.0`, and
118
+ `@wllama/wllama` `3.6.0`, as well as the browser entry
119
+ `arcane-os/event-manager`. Runtime dependencies stay under
120
+ `arcane/dependencies/`; the SDK event and browser-AI closure stays under
121
+ `arcane/sdk/`. This URL-key separation prevents runtime and SDK dependency
122
+ versions from aliasing one another.
123
+
124
+ Those two receipt inventories contain 185 entries in total. That sum is a
125
+ release-inventory fact, not an import-map entry count and not an assertion about
126
+ one maintained example. The `0.2.3` map deterministically roots every admitted
127
+ top-level runtime ESM plus the authenticated SDK browser roots, then follows
128
+ those roots for runtime entities and dependency compatibility. Application
129
+ source imports do not select the 91 entries. Its public operation receipt is the
130
+ authority for the exact `imports`, `entryCount`, and `excludedModules`;
131
+ reached-file traversal is internal and is not exposed in that receipt. The
132
+ managed graph exposes `arcane-os/event-manager`, `arcane-os/ai/browser-wasm`,
133
+ and `arcane-os/ai/browser-speech`; dependency compatibility mappings are added
134
+ only when authenticated runtime or SDK root traversal observes them.
135
+
136
+ The focused physical targets remain stable when their bindings are reached:
120
137
 
121
138
  | Browser specifier | Physical target |
122
139
  | --- | --- |
123
140
  | `arcane-os/event-manager` | `./arcane/sdk/event-manager.mjs` |
124
141
  | `arcane-os/ai/browser-wasm` | `./arcane/sdk/ai/browser-wasm.mjs` |
142
+ | `arcane-os/ai/browser-speech` | `./arcane/sdk/ai/browser-speech.mjs` |
125
143
  | `event-pubsub` | `./arcane/sdk/dependencies/event-pubsub/index.js` |
126
144
  | `./node_modules/strong-type/index.js` | `./arcane/dependencies/strong-type/index.js` |
127
145
 
@@ -129,7 +147,50 @@ There is no `arcane-os` package-root mapping, bare `strong-type` mapping, or
129
147
  catch-all `arcane/` prefix. Host-internal `CaseEvidenceIndexer.js` is explicitly
130
148
  excluded; classic scripts, workers, stylesheets, and other non-ESM assets use
131
149
  their documented URL or host loading contract rather than invented package
132
- bindings.
150
+ bindings. Development serves the selected app plus the authenticated tree.
151
+ Packaging copies the same map, app entry, and physical bytes into `dist/<id>`;
152
+ targets never resolve through the consumer workspace's root `node_modules/`.
153
+
154
+ `generateImportMap()` is an internal toolchain operation, not a package export.
155
+ Its package path accepts the configured entry plus the deterministic included
156
+ `.html`/`.htm` document inventory. One transaction writes the artifact and the
157
+ same managed JSON into every admitted document. The receipt binds
158
+ `documentPaths`, `documentCount`, and `files`: artifact first, configured entry
159
+ second, then additional documents as `role:"document"`. The public CLI keeps
160
+ its existing two-option command and supplies only the selected entry; packaging
161
+ owns multi-page discovery.
162
+
163
+ An external package and development server expose the authenticated runtime
164
+ inventory at `/ARCANE_RUNTIME_PROJECTION.json`:
165
+
166
+ ```javascript
167
+ {
168
+ schemaVersion: 1,
169
+ kind: 'arcane-app-runtime-projection',
170
+ sdkVersion,
171
+ pathPrefix: 'arcane/',
172
+ fileCount,
173
+ totalBytes,
174
+ contentSha256,
175
+ files: [{path, bytes, sha256}]
176
+ }
177
+ ```
178
+
179
+ The projection contains public paths relative to its declared
180
+ `pathPrefix:'arcane/'` (for example, `modules/...` and `sdk/...`), byte lengths,
181
+ and SHA-256 values and is itself bound by the packaged release inventory. It does
182
+ not expose the private `/ARCANE_APP_RELEASE.json` or replace the underlying
183
+ runtime/browser receipts. Missing, changed, forged, duplicated, or internally
184
+ inconsistent projection data fails `ARCANE_RUNTIME_PROJECTION_INVALID`.
185
+
186
+ External `validateWorkspace()` results also expose a frozen `sdkInstallation`
187
+ authority with exactly `dependencyName`, `packageSource`,
188
+ `canonicalPackageRoot`, `packageName`, `packageVersion`, `runtimeRoot`,
189
+ `browserRuntimeRoot`, `runtimeManifest`, and `browserRuntimeManifest`. A
190
+ workspace may use the canonical dependency name or one exact npm alias such as
191
+ `npm:arcane-os@0.2.3`; the physical package manifest must still identify
192
+ exactly as `arcane-os@0.2.3`. Canonical-plus-alias duplicates, multiple aliases,
193
+ links/junctions, indirect package roots, or version drift fail closed.
133
194
 
134
195
  The imported module can be pure browser logic, standard-Web-API logic, or a
135
196
  client of `globalThis.Arcane`. Import-map resolution is not a new Arcane wire
@@ -164,24 +225,28 @@ heartbeat is event telemetry only and never regenerates browser state.
164
225
  </details>
165
226
 
166
227
  <details>
167
- <summary>SDK browser-runtime admission and exact receipt fields</summary>
228
+ <summary>SDK 0.2.3 browser-runtime admission and exact receipt fields</summary>
168
229
 
169
230
  `arcane.lock.json.sdkBrowserRuntime` persists the trusted manifest path,
170
231
  `manifestSha256`, `contentSha256`, `builder`, `sdkVersion`, and `source` record.
171
- For SDK `0.1.2` those identities are:
232
+ For SDK `0.2.3`, the manifest itself records:
172
233
 
173
234
  ```text
174
235
  manifest: node_modules/arcane-os/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json
175
- manifestSha256: 88395493b411fd5461fbb2bb065ae2b745f6d1672f796583fd248ec97f71f4f7
176
- contentSha256: 5e03f45a732db51cb5a2b2193cc79ecda34501d07a9b2e82e794e5fa37d55d00
236
+ fileCount: 25
237
+ totalBytes: 9280047
238
+ contentSha256: 3c82ed11b24c7b7b91b62f6dc52e0b1dcd444112a29cd48413eedc008380eb61
177
239
  builder: arcane-sdk-browser-runtime-v1
178
- sdkVersion: 0.1.2
240
+ sdkVersion: 0.2.3
179
241
  source.protocol: arcane-sdk-browser-runtime/1
180
242
  source.browserEntry: arcane-os/event-manager
181
243
  ```
182
244
 
183
- The `source` record also binds the `arcane-os-sdk` authority/repository and the
184
- exact `event-pubsub` 6.1.0 and `strong-type` 2.0.0 package identities. Before a
245
+ The verifier computes `manifestSha256` over the exact installed manifest and
246
+ binds that value in its process-local receipt and the workspace lock; it must
247
+ not be substituted with `contentSha256`. The `source` record also binds the
248
+ `arcane-os-sdk` authority/repository and the exact `event-pubsub` 6.1.0,
249
+ `strong-type` 2.0.0, and `@wllama/wllama` 3.6.0 package identities. Before a
185
250
  workspace tree is admitted, the same-process verifier returns
186
251
  `schemaVersion`, `kind`, `canonicalLocation`, `rootIdentity`, `manifestPath`,
187
252
  `manifestSha256`, `manifestIdentity`, `builder`, `sdkVersion`, `source`,
@@ -192,6 +257,167 @@ does not recreate authority.
192
257
 
193
258
  </details>
194
259
 
260
+ ## Portable AI provider runtime
261
+
262
+ Application code should select a normalized role, not an internal protocol.
263
+ The exported
264
+ [`getAIProviderRuntime()` singleton](runtime-modules.md#aiproviderruntimejs)
265
+ comes from authenticated runtime bytes and owns independent `llm`, `stt`, and
266
+ `tts` selections. SDK `0.2.3` ships browser-WASM LLM and browser
267
+ speech provider/2 adapters and also adapts selected legacy OpenAI LLM/STT/TTS,
268
+ Core-backed Ollama LLM, and admitted Core speech STT/TTS routes into provider/2;
269
+ other native, Core, or cloud routes require an externally supplied compatible
270
+ adapter. The singleton itself is not an authentication or capability token. It
271
+ normalizes inspection, model authority,
272
+ load/unload/dispose, cancellation, stream cleanup, status, and startup
273
+ barriers. Each selected provider retains its real execution requirements.
274
+ `localOnly` fails closed, and failure in one role never authorizes a Core,
275
+ cloud, or different-provider fallback.
276
+
277
+ For a browser-only LLM,
278
+ [`arcane-os/ai/browser-wasm`](ai/browser-wasm.md) exposes `createArcaneAI()`
279
+ and an adapter into the same provider-neutral lifecycle. For browser speech,
280
+ [`arcane-os/ai/browser-speech`](ai/browser-speech.md) creates independent
281
+ Whisper STT and Kokoro TTS providers that register directly with the normalized
282
+ runtime. The SDK supplies mechanism; applications retain model/runtime choice,
283
+ provenance, licenses, prompts, tools, voices, and disclosure policy.
284
+
285
+ ### Browser-WASM LLM lifecycle
286
+
287
+ The shipped browser receipt contains the authenticated Wllama JavaScript/WASM
288
+ engine and its provider/cache/controller mechanism. It contains no model
289
+ weights, default model catalog, CDN fallback, native provider, speech model, or
290
+ application profile. The caller supplies each model as a source authority with
291
+ a nonempty ordered file list, so monolithic and split GGUF models use the same
292
+ contract. HTTPS redirects are followed and the final HTTPS URL is recorded.
293
+ Exact bytes are bound only by the optional expected byte lengths and SHA-256
294
+ values whose matching fieldwise security checks are enabled.
295
+
296
+ On load, the DBOPFS store admits all ordered members and commits the completion
297
+ manifest last. A normal cache miss may fetch only the caller-supplied immutable
298
+ HTTPS sources; `offline:true` performs no model request and admits only a
299
+ compatible completed cache, otherwise it rejects with
300
+ `ARCANE_AI_MODEL_OFFLINE_MISS`. Unload releases the active Wllama session but
301
+ does not silently delete the app-owned cache.
302
+
303
+ SDK `0.2.3` requires WebGPU. Load requests full offload with exactly 99,999 GPU
304
+ layers and admits the model only after observing an adapter, full layer offload,
305
+ buffer and queue work, and a settled fence. `navigator.gpu` presence alone is
306
+ not readiness. There is no CPU fallback, partial-offload success mode, or
307
+ silent switch to native/Core/cloud inference.
308
+
309
+ ### Browser speech lifecycle
310
+
311
+ The browser-speech package contains plain-JavaScript authority, DBOPFS store,
312
+ provider, client, and Worker machinery. It supplies no Whisper or Kokoro
313
+ runtime adapter bytes, model weights, voice bytes, download URL, catalog, or
314
+ cloud fallback. The caller must provide a closed immutable runtime/model
315
+ declaration for each role. Construction validates and freezes its declared
316
+ identity; preparation validates the actual downloaded or cached closed runtime
317
+ graph. The SDK downloads only declared files when permitted, commits its
318
+ completion manifest last, and removes incomplete stored state after a
319
+ cache/install failure. `offline:true` never uses the
320
+ network and rejects a cache miss with `ARCANE_AI_ARTIFACT_OFFLINE_MISS`.
321
+
322
+ Whisper `stt` and Kokoro `tts` each own catalog, inspect, status, load, request,
323
+ unload, and dispose state. They load, cancel, unload, fail, and recover
324
+ independently from the LLM and from one another. Cancellation after Worker use
325
+ begins terminates that role's Worker slot and returns the provider to unloaded;
326
+ a later use must load it again. If shared STT `Blob` decoding is cancelled
327
+ before Worker use, the request rejects while the loaded provider remains ready.
328
+ Speech failure neither disables text chat nor retries through another local,
329
+ native, or cloud provider.
330
+
331
+ ### Persistent chat and document context
332
+
333
+ The SDK runtime owns
334
+ [`DBOPFSDocumentLibrary`](runtime-modules.md#dbopfsdocumentlibraryjs),
335
+ [`DocumentLexicalSearch`](runtime-modules.md#documentlexicalsearchjs), and
336
+ [`PersistentAIChatSession`](runtime-modules.md#persistentaichatsessionjs).
337
+ Document bootstrap is explicit and schema-driven, commits a completed
338
+ generation last, and returns bounded search results with partial read failures
339
+ disclosed. `evaluate()` can instead score a caller-owned source set without
340
+ persisting its bodies, under separate corpus/scoring/output/document budgets.
341
+ A chat session never searches the corpus unless the application
342
+ deliberately wires a document context builder into the request; generated
343
+ document context remains labeled untrusted.
344
+
345
+ Persistent chat maintains bounded live model context plus `ChatEntity`
346
+ history/memory according to the caller's persistence choice. A turn with
347
+ `persist:false` remains coherent in the live session without entering durable
348
+ history or memory. `createArcaneAI(...).createChatSession(options)` binds the
349
+ session and automatic memory work to that same selected LLM controller; it does
350
+ not select a second provider or storage fallback.
351
+
352
+ ### Cancellation and structural tools
353
+
354
+ Cancellation is part of the provider lifecycle, not just a UI decision.
355
+ `AbortSignal`, the normalized role cancel operation, and stream-handle
356
+ `cancel(reason)` propagate to the selected provider. Browser-WASM inference
357
+ requires positive llama cancellation acknowledgement when cancellation is
358
+ required. Browser speech cancellation terminates a Worker only after Worker use
359
+ has begun; cancellation during shared browser decoding leaves the loaded Worker
360
+ ready. Unload always cancels active role work before releasing that role's
361
+ execution state, and superseded late results are rejected rather than committed
362
+ or retried through another provider.
363
+
364
+ Interactive request ownership is latest-request-wins independently for each
365
+ role. A new valid request that reaches admission aborts the active role request
366
+ and waits for its provider promise settlement; stream replacement additionally
367
+ requires confirmed bounded handle cleanup. Only the newest waiting request may
368
+ start after settlement, and request-specific generations prevent superseded
369
+ callbacks from clearing or restoring newer state. The runtime revalidates
370
+ selected-provider readiness and never reloads, switches, or falls back
371
+ implicitly. Generic provider-promise settlement is not a claim that underlying
372
+ work stopped; only a provider's documented positive acknowledgement or
373
+ destructive worker teardown can prove that stronger fact.
374
+
375
+ `startAIRuntime({startTranscription:false})` is the default startup boundary for
376
+ STT. It declines to request a startup STT load; it does not unload a role already
377
+ started through another explicit lifecycle action. A selected unloaded
378
+ transcription provider remains selected and unloaded until a user lifecycle
379
+ intent or explicit `startTranscription:true` opt-in asks the provider owner to
380
+ load it. Neither state observation nor either shared speech component imports a
381
+ model or selects a fallback. `speech.html` and `voice-transcription.html` consume
382
+ one shared `createSTTActivationController()` contract for selected, unloaded,
383
+ loading, unloading, error, and ready presentation plus cancelable user intent.
384
+ Both keep capture fail-closed until sticky STT state is exactly ready.
385
+
386
+ Each shared speech component owns an `AbortController` for its STT request and
387
+ passes its signal through `AI.fetchSTT()`. `voice-transcription.html` also adds
388
+ that signal to the existing injected `transcribe(file,context)` callback
389
+ context. Cancel, readiness loss, superseding capture, and component teardown
390
+ abort the owned signal and suppress late delivery. Whether the provider's
391
+ underlying computation stops remains governed by its own cancellation contract.
392
+ User TTS unmute calls `AI.setSpeechMuted(false)` before
393
+ or with its load intent so the runtime records the unmuted lifecycle preference;
394
+ mute calls `AI.setSpeechMuted(true)`, cancels active synthesis, and unloads TTS.
395
+ The selected TTS model catalog owns `defaultVoice`. AI.js uses a saved OpenAI
396
+ voice only for the OpenAI route and never forwards it to Core or browser Kokoro.
397
+
398
+ LLM tool calls are structural result data only. The SDK never executes a
399
+ handler. The application owns schema validation, authorization, side-effect
400
+ policy, dispatch, and the matching tool-result turn.
401
+
402
+ <details>
403
+ <summary>Portable AI protocol disclosure</summary>
404
+
405
+ The normalized runtime protocol is `arcane-ai-runtime/2`; registered adapters
406
+ implement `arcane-ai-provider/2` and must prove matching
407
+ `arcane-ai-model-authority/1` inspection before load. The browser-WASM component
408
+ receipt is `arcane-ai-browser-wasm/2`; its direct controller adapter uses
409
+ `arcane-ai-adapter/1`, and `adaptV1LlmProvider()` projects that surface into the
410
+ provider/2 LLM role. Browser speech stores identify themselves as
411
+ `arcane-ai-browser-speech-artifacts/1`; that identifier describes the store
412
+ contract, not a model authority, capability grant, or complete-cache receipt.
413
+
414
+ These identifiers normalize lifecycle records. They do not erase provider
415
+ availability: browser providers still require their browser capabilities,
416
+ native providers still require an admitted host and Core method, and cloud
417
+ providers still require explicit selection, network policy, and credentials.
418
+
419
+ </details>
420
+
195
421
  ## Arcane application protocol
196
422
 
197
423
  `globalThis.Arcane.protocol` is `arcane/1`. The shared API wraps transport