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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.3
4
+
5
+ - Made shared voice transcription consume authoritative sticky STT state,
6
+ expose explicit selected-unloaded activation, and keep recording disabled
7
+ until the selected route is genuinely ready and non-busy.
8
+ - Added owned cancellation and current-operation guards across microphone
9
+ permission, recording, transcription, save, completion, transcript
10
+ replacement, synchronous public events, teardown, and stale settlement.
11
+ - Centralized the shared STT activation control in
12
+ `createSTTActivationController()` without automatic downloads, hidden
13
+ provider selection, or application policy.
14
+
15
+ ## 0.2.2
16
+
17
+ - Corrected latest-request-wins ownership so each newly admitted AI request
18
+ aborts and settles the prior provider operation, revalidates role readiness,
19
+ and prevents stale results from restoring superseded state.
20
+ - Made speech startup and controls explicitly lifecycle-owned: STT startup is
21
+ opt-in, selected-unloaded STT exposes user activation and cancellation,
22
+ caller abort reaches shared transcription, and TTS mute/unmute owns its load,
23
+ cancellation, playback, and unload sequence.
24
+ - Kept positive speech readiness bound to admitted sticky provider state while
25
+ exposing truthful capability-only legacy OpenAI, Ollama, and Core speech
26
+ routes without downloads, hidden provider selection, model authority, or
27
+ fallback.
28
+ - Preserved the existing shared Blob/File STT and WAV TTS request shapes at the
29
+ browser-provider boundary, with explicit decode/format errors and
30
+ provider/model-owned TTS voice defaults.
31
+
3
32
  ## 0.2.1
4
33
 
5
34
  - Added explicit selected-unloaded chat activation, truthful legacy Cloud/Core
package/README.md CHANGED
@@ -19,7 +19,7 @@ version-locked SDK runtime, while an integrated Arcane checkout uses its live
19
19
  `arcane/` runtime. Both profiles preserve the same app URLs, theme, packaging,
20
20
  event, cancellation, and browser run contracts.
21
21
 
22
- This checkout defines the `0.2.1` SDK contract. Applications pin one exact npm
22
+ This checkout defines the `0.2.3` SDK contract. Applications pin one exact npm
23
23
  version and lockfile; registry state is deliberately not baked into immutable
24
24
  application artifacts.
25
25
 
@@ -132,7 +132,7 @@ uses the same controller for automatic memory extraction.
132
132
  Create a new repository-shaped Arcane application with the exact stable SDK:
133
133
 
134
134
  ```bash
135
- npx arcane-os@0.2.1 new my-app --path ./my-app --target portable --git
135
+ npx arcane-os@0.2.3 new my-app --path ./my-app --target portable --git
136
136
  cd my-app
137
137
  npm install
138
138
  npm run check
@@ -143,7 +143,7 @@ To enroll an existing repository, install the exact SDK and initialize only
143
143
  missing Arcane files:
144
144
 
145
145
  ```bash
146
- npm install --save-dev --save-exact arcane-os@0.2.1
146
+ npm install --save-dev --save-exact arcane-os@0.2.3
147
147
  npm exec -- arcane init my-app --target portable
148
148
  ```
149
149
 
@@ -159,7 +159,7 @@ npm exec -- arcane-os targets
159
159
  No global SDK install or standalone Arcane CLI is required. The application
160
160
  repository's exact npm dependency and lockfile own the CLI and toolchain version.
161
161
 
162
- Use `npx arcane-os@0.2.1` for the initial bootstrap because it names this npm
162
+ Use `npx arcane-os@0.2.3` for the initial bootstrap because it names this npm
163
163
  package explicitly; bare `npx arcane` outside an installed project could resolve
164
164
  a different package. Both installed commands invoke the same headless toolchain.
165
165
  Project-local npm scripts use the SDK pinned by that app's `package-lock.json`,
@@ -180,7 +180,7 @@ node ./bin/arcane.mjs new local-app --path ../local-app --target portable --git
180
180
 
181
181
  # From the generated app repository
182
182
  cd ../local-app
183
- npm install --save-dev --save-exact ../arcane-os-sdk/arcane-os-0.2.1.tgz
183
+ npm install --save-dev --save-exact ../arcane-os-sdk/arcane-os-0.2.3.tgz
184
184
  npm run check
185
185
  npm ci
186
186
  ```
@@ -191,7 +191,7 @@ still verifies the installed package name and exact version, the locked runtime
191
191
  identity, and the runtime bytes. Local directory `file:` dependencies are not
192
192
  accepted because npm may install them as links; use a packed `.tgz`. A GitHub
193
193
  runner also needs that tarball at the locked path. After publication, replace
194
- the local declaration with the exact `arcane-os@0.2.1` registry package and
194
+ the local declaration with the exact `arcane-os@0.2.3` registry package and
195
195
  commit the regenerated lock.
196
196
 
197
197
  Generated repositories use `npm ci --ignore-scripts` in CI. Run dependency
@@ -304,7 +304,7 @@ recorded length through a final identity check; an appended byte, concurrent
304
304
  growth, path replacement, or hard link fails closed. NFC paths use defined
305
305
  UTF-8 byte ordering, covered by one pinned golden bundle digest on every
306
306
  supported Node/runner combination. This SDK accepts only the explicitly listed
307
- `0.2.1` bundle generation; structural validity does not imply cross-SDK
307
+ `0.2.3` bundle generation; structural validity does not imply cross-SDK
308
308
  compatibility, and a release with zero payload bytes cannot be created. Portable
309
309
  path validation rejects file/directory prefix conflicts, case-colliding prefix
310
310
  spellings, and Windows device aliases including superscript COM/LPT digits.
@@ -350,7 +350,7 @@ package installation, or assertions.
350
350
 
351
351
  ## Current target support
352
352
 
353
- Version `0.2.1` exposes one browser target and five explicitly paired
353
+ Version `0.2.3` exposes one browser target and five explicitly paired
354
354
  native development targets: a verified non-runnable portable directory, a
355
355
  Windows x64 unsigned-local-test EXE bundle, Linux x64 and Linux ARM64
356
356
  unsigned-local-test DEBs, and an Android development-signed APK. The
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "builder": "arcane-sdk-browser-runtime-v1",
4
- "sdkVersion": "0.2.1",
4
+ "sdkVersion": "0.2.3",
5
5
  "source": {
6
6
  "authority": "arcane-os-sdk",
7
7
  "repository": "https://github.com/TheWizardNexus/arcane-os-sdk.git",
@@ -29,8 +29,8 @@
29
29
  ]
30
30
  },
31
31
  "fileCount": 25,
32
- "totalBytes": 9279974,
33
- "contentSha256": "a9715c4b3aef70ec4042e4738089568d6588877b29582e0f758ed83897b6814f",
32
+ "totalBytes": 9280047,
33
+ "contentSha256": "3c82ed11b24c7b7b91b62f6dc52e0b1dcd444112a29cd48413eedc008380eb61",
34
34
  "files": [
35
35
  {
36
36
  "path": "ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json",
@@ -57,8 +57,8 @@
57
57
  "path": "ai/browser-speech-providers.mjs",
58
58
  "sourcePath": "browser-runtime/ai/browser-speech-providers.mjs",
59
59
  "provenance": "sdk-source-identity",
60
- "bytes": 25982,
61
- "sha256": "65e0a8da2bcd46b11c3ea2ca496105875977decc53d4e4c94ca56949dbb569b1"
60
+ "bytes": 26055,
61
+ "sha256": "6a2c0caa227d78028f42434b86231236055f0cfe0e3d6b71a4f651f7005a2614"
62
62
  },
63
63
  {
64
64
  "path": "ai/browser-speech.mjs",
@@ -449,6 +449,7 @@ function createBrowserSpeechProvider({
449
449
  providerId,
450
450
  role,
451
451
  localOnly: true,
452
+ ...(role === "tts" ? { defaultVoice: authority.defaultVoice } : {}),
452
453
  repository: authority.repository,
453
454
  revision: authority.revision,
454
455
  runtime: authority.runtime,
@@ -200,7 +200,7 @@ length with an EOF growth probe, and rechecked by handle and pathname identity.
200
200
  Every cumulative path prefix has one case-folded spelling and one file/directory
201
201
  kind; prefix topology conflicts and the complete portable Windows device-name
202
202
  set fail before creation or admission.
203
- The current SDK admits only the explicitly compatible `0.2.1` bundle
203
+ The current SDK admits only the explicitly compatible `0.2.3` bundle
204
204
  generation and rejects zero-byte payload releases.
205
205
 
206
206
  Promotion retains any prior output as an identity-bound backup until the new
@@ -320,7 +320,7 @@ through SDK-bound verified readers rather than accepting a mutable source path
320
320
  as authority. Build completion requires provider verification, and later
321
321
  verify/run calls receive the exact artifact receipt.
322
322
 
323
- The SDK `0.2.1` runtime requires Arcane `0.8.12` or newer. Compatibility
323
+ The SDK `0.2.3` runtime requires Arcane `0.8.12` or newer. Compatibility
324
324
  is contractual rather than exact-version pinning: the prepared Core must meet
325
325
  the highest minimum declared by the runtime, selected app, and bundled app
326
326
  dependencies; keep each app's Arcane protocol generation; and provide every
@@ -26,25 +26,27 @@ high-level page links to the relevant deep section instead of repeating it.
26
26
  | Load a reusable HTML component | [Runtime component catalog](runtime-components.md) |
27
27
  | Call `globalThis.Arcane` | [Arcane Core API](core/arcane-api.md) |
28
28
  | Subscribe to native events | [Arcane event reference](core/arcane-events.md) |
29
- | Use provider-neutral AI | [Arcane AI contracts](core/arcane-ai-contracts.md) |
29
+ | Use provider-neutral AI lifecycle, chat, speech, persistence, or document context | [Normalized AI](#normalized-ai) |
30
30
  | Run a caller-authenticated local LLM in the browser | [Browser-WASM local AI](ai/browser-wasm.md) |
31
+ | Run caller-authenticated Whisper or Kokoro in the browser | [Browser speech providers](ai/browser-speech.md) |
31
32
  | Use Arcane Ollama | [Arcane Ollama guide](arcane-ollama.md) |
32
33
  | Understand transports and protocol switching | [Protocol and host architecture](protocols.md) |
33
34
  | Run contract and behavior tests | [Behavioral testing](behavioral-testing.md) |
34
35
 
35
36
  ## Version scope and provenance
36
37
 
37
- This repository contains two related, explicitly versioned surfaces:
38
+ This repository contains explicitly versioned surfaces with different owners:
38
39
 
39
40
  | Surface | Source identity | Meaning |
40
41
  | --- | --- | --- |
41
- | SDK and CLI | `arcane-os` `0.1.2` | The Node.js toolchain plus the browser-only `arcane-os/ai/browser-wasm` entrypoint in this checkout. |
42
- | Browser runtime | Arcane OS commit `567ad110bf57a1c2d4a3daa22ae93716cc5f4d7e`, bundle `0.8.12`, protocol `arcane/1` | The exact 155-file runtime snapshot shipped under `runtime/`. |
42
+ | SDK and CLI | `arcane-os` `0.2.3` | The Node.js toolchain plus the browser-only `arcane-os/ai/browser-wasm` and `arcane-os/ai/browser-speech` entrypoints in this checkout. |
43
+ | Browser runtime | SDK source commit `f97ac4f2e7cc92a00a3a466c38a67446dd112acf`, SDK `0.2.3`, protocol `arcane/1` | The SDK-canonical exact 160-file runtime shipped under `runtime/`; Arcane OS commit `c540014afe69f14cf5ae60493b7295f36dbcec64` is legacy projection provenance, not a second source authority. |
44
+ | Browser SDK runtime | SDK source commit `f97ac4f2e7cc92a00a3a466c38a67446dd112acf`, SDK `0.2.3` | The exact 25-file authenticated browser closure: EventManager/DOM instrumentation and pinned event dependencies, Wllama runtime assets, and SDK browser speech provider/store/Worker mechanisms. It contains no model weights or speech adapter/model bytes. |
43
45
  | Core reference snapshot | Arcane OS commit `567ad110bf57a1c2d4a3daa22ae93716cc5f4d7e`, protocol `arcane/1` | The application-facing Core contract derived into `docs/reference/core/`. Canonical inventory and focused-member content was verified unchanged at Arcane OS `main` commit `13f3ce0ae34f77a3495331c8b4c30b1bb105f8ed`; SDK-local provenance, link, and package-boundary annotations are added explicitly. |
44
46
 
45
- The runtime receipt and Core reference remain distinct evidence even though
46
- they currently share one pinned upstream source identity. A browser module's
47
- bytes come from the generated runtime receipt. A native build selects one
47
+ The SDK runtime receipt and Core reference are distinct evidence and have
48
+ different current authorities. A browser module's bytes come from the SDK
49
+ runtime receipt. A native build selects one
48
50
  explicit Arcane OS checkout and Core. This SDK version accepts that selection
49
51
  only after its current native plan checks the exact declared protocol, version,
50
52
  features, capabilities, methods, provider contract, and identity-bound
@@ -56,6 +58,32 @@ See [Core reference provenance](core/README.md) for the imported inventory and
56
58
  the exact distinction between a documentation snapshot and shipped runtime
57
59
  bytes.
58
60
 
61
+ ## Published 0.2.2
62
+
63
+ The published package is exactly `arcane-os@0.2.2` from source commit
64
+ `d5326d206bf0bec6ad82d53605e666841aa79899`. The npm `latest` dist-tag resolves
65
+ to `0.2.2`; the separate `dev` dist-tag remains `0.1.0-dev.5`.
66
+
67
+ The admission-aware `voice-transcription.html` lifecycle and shared
68
+ `createSTTActivationController()` contract documented below are newer canonical
69
+ source. They are not package authority in `0.2.2`; consumers require a fresh
70
+ numeric publication before relying on them.
71
+
72
+ | Evidence | Exact value |
73
+ | --- | --- |
74
+ | npm integrity | `sha512-JnLzZ4+FqX9tMgRv8HMcaCPSFx3xNNRf8BF8T03fD2ymg2g8cIGZRdD/3Tbd9PLtpx1PIKCpxz6nCP6ztnu1Nw==` |
75
+ | npm shasum | `0b0d314acce48dcb5518470cd45a54221589d4d4` |
76
+ | Immutable release tarball | `arcane-os-0.2.2.manifest.json`; artifact `9631659213`; 6,993,999 bytes; SHA-256 `e0fe1a556b603f67f5e3c142be7154b433312d3c0f3b58632df2e7fc43cc0ca7` |
77
+ | GitHub release | [`0.2.2`](https://github.com/TheWizardNexus/arcane-os-sdk/releases/tag/0.2.2) (tag and title are both exactly `0.2.2`) |
78
+ | Hosted source/artifact gate | [Check run 33034955277](https://github.com/TheWizardNexus/arcane-os-sdk/actions/runs/33034955277) |
79
+ | Trusted publication | [Run 33035086265](https://github.com/TheWizardNexus/arcane-os-sdk/actions/runs/33035086265) |
80
+
81
+ The npm SLSA provenance binds the published package to that exact source commit
82
+ and `.github/workflows/publish-dev.yml`. Hashes prove byte identity or
83
+ consistency; provenance establishes the recorded source/workflow relationship.
84
+ Neither claim alone proves browser hardware support, native admission, or a
85
+ particular application's provider/model policy.
86
+
59
87
  ## MDN-style page contract
60
88
 
61
89
  Public reference entries follow the established Arcane documentation model:
@@ -74,11 +102,12 @@ Public reference entries follow the established Arcane documentation model:
74
102
 
75
103
  ## Public runtime inventory
76
104
 
77
- The package exposes 163 semantic JavaScript records across 12 JavaScript
105
+ The package exposes 169 semantic JavaScript records across 13 JavaScript
78
106
  entrypoints, plus eight JSON Schemas, its exact runtime manifest, and package
79
107
  metadata. Ten entrypoints are Node.js control-plane surfaces,
80
108
  `arcane-os/event-manager` runs in Node and browsers, and
81
- `arcane-os/ai/browser-wasm` is browser-only. The [machine-readable package
109
+ `arcane-os/ai/browser-wasm` plus `arcane-os/ai/browser-speech` are browser-only.
110
+ The [machine-readable package
82
111
  inventory](inventory/package-api.json) and [SDK member reference](sdk-api.md)
83
112
  are checked bidirectionally against every declared JavaScript export.
84
113
 
@@ -87,7 +116,7 @@ download, install, or self-update.
87
116
 
88
117
  The synchronized browser payload exposes:
89
118
 
90
- - 78 JavaScript module artifacts under `runtime/arcane/modules/`, including
119
+ - 83 JavaScript module artifacts under `runtime/arcane/modules/`, including
91
120
  ESM modules, classic vendor globals, one worker protocol, and one Node-oriented
92
121
  mail transport;
93
122
  - 15 shared entity modules under `runtime/arcane/entities/`;
@@ -100,6 +129,43 @@ vendor support files that are not ESM imports. The runtime manifest remains the
100
129
  byte-level source of truth; the catalogs explain what those bytes let a
101
130
  developer do.
102
131
 
132
+ ## Normalized AI
133
+
134
+ Portable applications start with the provider-neutral runtime rather than an
135
+ Ollama, Wllama, Whisper, Kokoro, native, or cloud transport:
136
+
137
+ | Need | Public surface | Availability |
138
+ | --- | --- | --- |
139
+ | Select, load, unload, inspect, cancel, and use LLM/STT/TTS independently | [`AIProviderRuntime.js`](runtime-modules.md#aiproviderruntimejs) | Cross-host controller; each registered provider declares its own host requirements. |
140
+ | Observe sticky role state and startup settlement | [`AIRuntimeState.js`](runtime-modules.md#airuntimestatejs) | Cross-host EventTarget state; observation grants no authority. |
141
+ | Offer explicit selected-model start/cancel UI | [`chat.html`](runtime-components.md#chathtml), [`speech.html`](runtime-components.md#speechhtml), and [`voice-transcription.html`](runtime-components.md#voice-transcriptionhtml) | Browser/native WebView components; user activation emits a cancelable request before any LLM or STT load intent, and recording stays disabled without sticky ready STT. |
142
+ | Use Core-normalized chat | [`globalThis.Arcane.ai`](core/arcane-ai-contracts.md) | Native/Core only when separately admitted. |
143
+ | Run a caller-selected GGUF LLM locally | [`arcane-os/ai/browser-wasm`](ai/browser-wasm.md) | Browser secure context with WebGPU/full-offload evidence, WebAssembly, and OPFS/DBOPFS. |
144
+ | Run caller-selected Whisper/Kokoro locally | [`arcane-os/ai/browser-speech`](ai/browser-speech.md) | Browser with DBOPFS, Web Locks, Workers, and caller-supplied immutable runtime/model bytes. |
145
+ | Add bounded persistent history and memory | [`PersistentAIChatSession.js`](runtime-modules.md#persistentaichatsessionjs) | Browser/native WebView runtime with ChatEntity/DBOPFS and a configured chat function. |
146
+ | Add explicit document search/context | [`DBOPFSDocumentLibrary.js`](runtime-modules.md#dbopfsdocumentlibraryjs) | Existing DBOPFS-style adapter; search occurs only after the app calls it or deliberately wires its context builder into chat. |
147
+
148
+ There is no automatic local-to-cloud, browser-to-Core, provider-to-provider, or
149
+ storage fallback. Tool calls remain structural data until application-owned
150
+ policy and code decide whether to execute them. App prompts, model defaults,
151
+ profiles, tools, business policy, and private data remain app-owned.
152
+
153
+ An explicitly selected but unloaded model is not “ready.” `chat.html` keeps
154
+ Send disabled and exposes a visible keyboard-operable LLM Start/Try again or
155
+ Cancel loading control. `speech.html` and `voice-transcription.html` keep their
156
+ recording operations unavailable and share the equivalent Start
157
+ transcription/Try again/Cancel loading control for STT. Applications can
158
+ override `requestAIActivation(intent)` or `requestSTTActivation(intent)`, or
159
+ cancel the corresponding activation-request event. Imports and state
160
+ observation emit no lifecycle intent, and default
161
+ `startTranscription=false` does not request an STT startup load or begin an
162
+ automatic model download. It does not unload a role started independently.
163
+ Compatibility availability never creates ready STT/TTS state without an
164
+ admitted, loaded provider. Shared STT cancel/destroy propagates an owned signal,
165
+ and TTS Mute/Unmute updates the shared lifecycle owner. The selected TTS
166
+ provider/model catalog owns its default voice; a saved OpenAI voice is not
167
+ forwarded to another provider route.
168
+
103
169
  ## Authority and feature detection
104
170
 
105
171
  The presence of a JavaScript function is not permission to use it. Native
@@ -113,9 +179,9 @@ as package admission. Each method rechecks native policy at invocation time.
113
179
 
114
180
  ## Source, receipts, and licensing
115
181
 
116
- - [Pinned upstream ARCANE-OS source](https://github.com/TheWizardNexus/ARCANE-OS/tree/567ad110bf57a1c2d4a3daa22ae93716cc5f4d7e)
117
- - [Exact runtime release manifest](../../runtime/ARCANE_RUNTIME_RELEASE.json)
118
- - [Reviewed runtime source pin](../../tools/runtime-source.json)
182
+ - [Exact SDK runtime release manifest](../../runtime/ARCANE_RUNTIME_RELEASE.json)
183
+ - [SDK runtime authority record](../../tools/runtime-source.json)
184
+ - [Exact browser AI runtime receipt](../../browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json)
119
185
  - [AGPL license](../../LICENSE)
120
186
  - [Commercial-license notice](../../COMMERCIAL-LICENSE.md)
121
187
  - [Third-party and distribution notice](../../NOTICE)
@@ -0,0 +1,336 @@
1
+ # Browser speech providers
2
+
3
+ `arcane-os/ai/browser-speech` is the shipped browser-only provider package for
4
+ caller-supplied Whisper speech-to-text and Kokoro text-to-speech runtimes. It
5
+ implements the same provider-neutral role contract used by
6
+ `AIProviderRuntime.js`; it does not ship model weights, runtime adapter bytes,
7
+ voices, download URLs, a catalog, or a cloud fallback.
8
+
9
+ Use this page when an application deliberately owns browser-local speech model
10
+ and runtime selection. For ordinary application AI lifecycle and status, start
11
+ with the [normalized AI guide](../README.md#normalized-ai) and
12
+ [`AIProviderRuntime.js`](../runtime-modules.md#aiproviderruntimejs).
13
+
14
+ ## Availability
15
+
16
+ | Host | Availability | Notes |
17
+ | --- | --- | --- |
18
+ | Browser | Shipped | Requires DBOPFS/OPFS, Web Locks, Workers, Fetch or an injected fetch function, Blob/File, and object URLs. |
19
+ | Native WebView | Conditional | Works only when the WebView exposes the same browser APIs and the application admits every artifact. This does not invoke Core speech. |
20
+ | Node | Importable, execution unavailable | The ESM subpath is exported, but `0.2.2` publishes no Node speech storage, Worker, audio-decoder, or execution adapter. |
21
+ | Cloud | Not provided | A cloud speech provider can implement `arcane-ai-provider/2`, but this package never selects one. |
22
+
23
+ Browser speech is independent from `arcane-os/ai/browser-wasm`: the Wllama
24
+ entrypoint owns the LLM role, while this entrypoint owns optional STT and TTS
25
+ providers. Each role loads, unloads, reports status, cancels, and recovers
26
+ independently.
27
+
28
+ ## Import
29
+
30
+ ```javascript
31
+ import {
32
+ BROWSER_SPEECH_ARTIFACT_PROTOCOL,
33
+ createBrowserKokoroProvider,
34
+ createBrowserSpeechAuthority,
35
+ createBrowserWhisperProvider,
36
+ createDbopfsSpeechArtifactStore
37
+ } from 'arcane-os/ai/browser-speech';
38
+ ```
39
+
40
+ The entrypoint exports exactly those five names. Importing it downloads no
41
+ model and starts no Worker.
42
+
43
+ ## `BROWSER_SPEECH_ARTIFACT_PROTOCOL`
44
+
45
+ The constant is exactly `"arcane-ai-browser-speech-artifacts/1"`. It identifies
46
+ an SDK-created artifact store; it is not model authority, a capability grant,
47
+ or evidence that a cache is complete.
48
+
49
+ ## `createBrowserSpeechAuthority()`
50
+
51
+ ```text
52
+ createBrowserSpeechAuthority({
53
+ providerId,
54
+ role,
55
+ model,
56
+ runtime,
57
+ security
58
+ } = {})
59
+ ```
60
+
61
+ Validates and freezes one caller-owned model/runtime declaration. Construction
62
+ binds the declared identities and descriptor rules; actual downloaded or cached
63
+ runtime-graph closure is validated by `store.prepare()` before a Worker starts.
64
+
65
+ ### Authority input
66
+
67
+ | Field | Contract |
68
+ | --- | --- |
69
+ | `providerId` | Trimmed 1–128 character provider identity. |
70
+ | `role` | Exactly `"stt"` or `"tts"`. |
71
+ | `model.id` | Caller-owned model identity. |
72
+ | `model.repository` | Immutable logical repository identity; the SDK does not resolve it. |
73
+ | `model.revision` | Caller-pinned revision. Every model URL must contain this revision or its supplied SHA-256. |
74
+ | `model.files` | Nonempty unique `{path,url,bytes?,sha256?,mediaType?}[]`. Paths are normalized relative paths; URLs are immutable HTTPS or same-origin URLs without credentials/fragments. |
75
+ | `model.defaultVoice` | Required only for TTS. |
76
+ | `runtime.adapter` | Exactly `"transformers-whisper"` for STT or `"kokoro-js"` for TTS. |
77
+ | `runtime.version` / `runtime.revision` | Caller-pinned runtime identity. |
78
+ | `runtime.entry` | Path of one JavaScript module in `runtime.files`. |
79
+ | `runtime.files` | Nonempty immutable runtime closure. The entry module must be self-contained: undeclared imports, re-exports, executable strings, alternate transports, and child workers are rejected. |
80
+ | `security` | Closed `{secure?,checks?:{byteLength?,sha256?}}` artifact policy. Disabled checks are disclosed rather than silently claimed. |
81
+
82
+ The result is a frozen `arcane-ai-model-authority/1` record. The SDK owns the
83
+ validation rules; the application owns every model/runtime choice, license,
84
+ revision, URL, hash, voice, and business policy.
85
+
86
+ Provider security resolves each field independently in this order: SDK default,
87
+ `appSecurity`, provider `security`, then `load({security})`. The SDK default is
88
+ `secure:false`. After resolution, each omitted check defaults to the effective
89
+ `secure` value; an explicit `checks.byteLength` or `checks.sha256` boolean
90
+ overrides that default. An enabled check requires the corresponding `bytes` or
91
+ `sha256` field on every admitted artifact and fails closed when evidence is
92
+ missing or mismatched. A disabled check never becomes a claim that bytes were
93
+ verified. Direct `store.prepare()` has only its supplied security scope above
94
+ the SDK default because it is not bound to a provider.
95
+
96
+ ## `createDbopfsSpeechArtifactStore()`
97
+
98
+ ```text
99
+ createDbopfsSpeechArtifactStore({
100
+ dbopfs,
101
+ tableName = 'arcane_ai_browser_speech',
102
+ fetchImpl = null,
103
+ objectUrlFactory = null
104
+ } = {})
105
+ ```
106
+
107
+ Adapts an existing DBOPFS instance into an authority-scoped store. The returned
108
+ frozen object exposes `{protocol,tableName,prepare,remove}`.
109
+
110
+ `prepare(authority,{signal,onProgress,offline=false,security})`:
111
+
112
+ 1. obtains an exclusive Web Lock for the exact authority;
113
+ 2. admits a complete cached manifest when every record still matches;
114
+ 3. otherwise, unless `offline:true`, downloads every declared file without
115
+ credentials;
116
+ 4. enforces enabled byte-length and SHA-256 checks;
117
+ 5. validates the closed runtime module graph;
118
+ 6. commits `arcane.ai.browser-speech.assets.v1` only after every file succeeds;
119
+ 7. returns materialized object URLs plus a `release()` callback.
120
+
121
+ An installation or cache-validation failure removes incomplete stored state for
122
+ that authority. A request or provider-use failure does not imply cache removal.
123
+ `offline:true` never falls back to network and rejects with
124
+ `ARCANE_AI_ARTIFACT_OFFLINE_MISS` when no admitted cache exists.
125
+
126
+ ## `createBrowserWhisperProvider()`
127
+
128
+ ```text
129
+ createBrowserWhisperProvider({
130
+ id = 'arcane-browser-whisper',
131
+ localOnly = true,
132
+ model,
133
+ runtime,
134
+ appSecurity,
135
+ security,
136
+ store,
137
+ offline = false
138
+ } = {})
139
+ ```
140
+
141
+ Returns a frozen `arcane-ai-provider/2` object for role `stt`. The provider
142
+ surface is `{protocol,role,id,localOnly,catalog,inspect,status,load,request,
143
+ unload,dispose}`.
144
+
145
+ The only request operation is `transcribe`:
146
+
147
+ ```javascript
148
+ async function transcribeAfterUserChoice(provider, pcmFloat32, signal) {
149
+ // The admitted Whisper provider must already be ready.
150
+ const result = await provider.request({
151
+ role: 'stt',
152
+ operation: 'transcribe',
153
+ signal,
154
+ payload: {
155
+ audio: pcmFloat32,
156
+ sampleRate: 16_000
157
+ }
158
+ });
159
+
160
+ console.log(result.text);
161
+ }
162
+ ```
163
+
164
+ `audio` must be a `Float32Array` sampled at exactly 16,000 Hz. The provider-native
165
+ provider result is a structured `{text}` record transferred by Worker
166
+ `postMessage`; the client does not re-freeze that cloned record. The same
167
+ provider also accepts the shared AI.js STT
168
+ payload `{audio:Blob|File,mimeType,model}`. It verifies `model`, decodes the
169
+ browser audio to authoritative 16 kHz mono PCM, and then enters the same provider-native
170
+ provider operation. Decode support and failure remain explicit.
171
+
172
+ ## `createBrowserKokoroProvider()`
173
+
174
+ ```text
175
+ createBrowserKokoroProvider({
176
+ id = 'arcane-browser-kokoro',
177
+ localOnly = true,
178
+ model,
179
+ runtime,
180
+ appSecurity,
181
+ security,
182
+ store,
183
+ offline = false
184
+ } = {})
185
+ ```
186
+
187
+ Returns the same provider/2 lifecycle for role `tts`. The only request
188
+ operation is `synthesize`:
189
+
190
+ ```javascript
191
+ async function synthesizeAfterUserChoice(provider, signal) {
192
+ // The admitted Kokoro provider must already be ready.
193
+ const result = await provider.request({
194
+ role: 'tts',
195
+ operation: 'synthesize',
196
+ signal,
197
+ payload: {
198
+ text: 'Hello from Arcane.',
199
+ voice: 'caller-owned-voice-id',
200
+ speed: 1
201
+ }
202
+ });
203
+
204
+ console.log(result.audio, result.sampleRate, result.voice);
205
+ }
206
+ ```
207
+
208
+ `speed` must be greater than zero and at most four. Omitted `voice` selects the
209
+ caller-supplied `model.defaultVoice`. The provider-native result is the structured
210
+ `{audio:Float32Array,sampleRate:24000,voice}` record transferred by Worker
211
+ `postMessage`; the client does not re-freeze that cloned record. The shared
212
+ AI.js TTS payload is
213
+ `{model,input,responseFormat,voice?,speed?}`. Only `responseFormat:"wav"` is
214
+ admitted; the provider maps it to `{text,voice,speed}` and returns frozen
215
+ `{audio:Uint8Array,contentType:"audio/wav"}` containing 24 kHz mono PCM.
216
+ Shared AI.js synthesis reads the selected model's catalog default and never
217
+ replaces it with a voice saved for a different provider route.
218
+
219
+ ## Lifecycle and status
220
+
221
+ Whisper and Kokoro use the same independent state machine:
222
+
223
+ | Operation | Behavior |
224
+ | --- | --- |
225
+ | `catalog()` | Returns the single caller-admitted model descriptor. TTS exposes its admitted `defaultVoice`; STT has no voice field. |
226
+ | `inspect(selection,{signal})` | Returns `{available:true,authority}` only for the exact provider/model/local selection; mismatch returns an unavailable record. |
227
+ | `status()` | Returns `{role,providerId,modelId,state,loaded,busy,generation,errorCode,cache}`. |
228
+ | `load(context)` | Requires `{role,selection,progress,signal?,security?}`, admits/cache-materializes artifacts, creates one role Worker, and loads the adapter. Compatible repeated loads coalesce. |
229
+ | `request(context)` | Runs exactly one STT or TTS operation. A provider rejects concurrent use with `ARCANE_AI_PROVIDER_BUSY`. |
230
+ | `unload()` | Aborts active load/use, terminates the Worker, releases object URLs, and returns `unloaded`. |
231
+ | `dispose()` | Completes unload and permanently returns `disposed`. |
232
+
233
+ Cancellation after a Worker request begins terminates that Worker slot and
234
+ returns the provider to `unloaded`; a later request requires a fresh load. A
235
+ shared STT request can instead be aborted while the browser is still decoding
236
+ its `Blob` or `File`, before Worker use begins. That request rejects with
237
+ `ARCANE_AI_REQUEST_ABORTED`, but the loaded Worker remains intact and the
238
+ provider stays `ready`. Worker crash/message failures become explicit error
239
+ state. No result is retried through another provider.
240
+
241
+ Register the providers with the projected
242
+ [`AIProviderRuntime`](../runtime-modules.md#aiproviderruntimejs) to normalize
243
+ selection, startup, application calls, and
244
+ [`AIRuntimeState`](../runtime-modules.md#airuntimestatejs) observation. The
245
+ provider objects themselves do not expose an event target.
246
+
247
+ ```javascript
248
+ async function loadSpeechProviderAfterUserChoice(provider) {
249
+ const selection = {
250
+ providerId: provider.id,
251
+ modelId: provider.catalog()[0].id,
252
+ localOnly: true
253
+ };
254
+ return provider.load({
255
+ role: provider.role,
256
+ selection,
257
+ progress(update) {
258
+ console.info(update.phase, update.completed, update.total);
259
+ }
260
+ });
261
+ }
262
+ ```
263
+
264
+ The example only defines the operation; invoke it from an explicit user action
265
+ after showing the admitted runtime/model and download policy. Requests are
266
+ valid only after that load resolves successfully. Applications
267
+ register and configure browser-speech providers on the shared runtime. `AI.js`
268
+ obtains that singleton and translates its existing browser speech request shapes
269
+ at this one provider boundary; it does not register providers, choose
270
+ authorities, or trigger a hidden model download.
271
+
272
+ ## Errors
273
+
274
+ | Code | Meaning |
275
+ | --- | --- |
276
+ | `ARCANE_AI_MODEL_AUTHORITY_REQUIRED` | Selection or authority does not match the provider. |
277
+ | `ARCANE_AI_INVALID_REQUEST` | Role, operation, audio, text, voice, or speed is invalid. |
278
+ | `ARCANE_AI_NOT_READY` | Use was requested before a successful load. |
279
+ | `ARCANE_AI_PROVIDER_BUSY` | The role already has an active request. |
280
+ | `ARCANE_AI_PROVIDER_DISPOSED` | Load/use was requested after disposal. |
281
+ | `ARCANE_AI_REQUEST_ABORTED` | The caller's AbortSignal cancelled work. |
282
+ | `ARCANE_AI_OPERATION_SUPERSEDED` | A newer unload/load/dispose generation replaced the operation. |
283
+ | `ARCANE_AI_ARTIFACT_SOURCE_INVALID` | Artifact bytes or body shape are not readable. |
284
+ | `ARCANE_AI_ARTIFACT_SOURCE_UNAVAILABLE` | Fetch is unavailable. |
285
+ | `ARCANE_AI_ARTIFACT_DOWNLOAD_FAILED` | Network or HTTP download failed. |
286
+ | `ARCANE_AI_ARTIFACT_SOURCE_CHANGED` | Redirect/final URL differs from the admitted immutable URL. |
287
+ | `ARCANE_AI_ARTIFACT_SIZE_MISMATCH` | Enabled byte-length evidence differs. |
288
+ | `ARCANE_AI_ARTIFACT_DIGEST_MISMATCH` | Enabled SHA-256 evidence differs. |
289
+ | `ARCANE_AI_ARTIFACT_CACHE_REJECTED` | DBOPFS did not preserve the completed file. |
290
+ | `ARCANE_AI_ARTIFACT_OFFLINE_MISS` | Strict offline use has no admitted complete cache. |
291
+ | `ARCANE_AI_STORAGE_BUSY` | Another context owns the same authority lock. |
292
+ | `ARCANE_AI_STORAGE_UNAVAILABLE` / `ARCANE_AI_STORAGE_READ_FAILED` / `ARCANE_AI_STORAGE_DELETE_FAILED` | The selected DBOPFS store is unavailable or could not read/delete the authority. |
293
+ | `ARCANE_AI_RUNTIME_MODULE_GRAPH_UNDECLARED` | Runtime code leaves the closed self-contained module grammar. |
294
+ | `ARCANE_AI_WORKER_CRASHED` / `ARCANE_AI_WORKER_MESSAGE_ERROR` | The isolated adapter Worker failed. |
295
+ | `ARCANE_AI_ADAPTER_PROTOCOL_MISMATCH` | The Worker/client/provider protocol is not the SDK-owned contract. |
296
+ | `ARCANE_AI_PROVIDER_LOAD_FAILED` / `ARCANE_AI_PROVIDER_REQUEST_FAILED` / `ARCANE_AI_PROVIDER_UNAVAILABLE` | Adapter load/request failed or the admitted runtime did not expose the requested provider. |
297
+ | `ARCANE_AI_INVALID_PROVIDER_RESULT` | Whisper/Kokoro returned a result outside the normalized contract. |
298
+ | `ARCANE_AI_UNDECLARED_ARTIFACT` | The runtime requested a file outside its admitted closure. |
299
+ | `ARCANE_AI_AUDIO_DECODE_UNAVAILABLE` / `ARCANE_AI_AUDIO_DECODE_FAILED` | Shared Blob/File STT cannot obtain a browser decoder or cannot produce nonempty 16 kHz mono PCM. |
300
+ | `ARCANE_AI_UNSUPPORTED_RESPONSE_FORMAT` | Shared TTS requested a format other than `wav`. |
301
+
302
+ ## Security and ownership
303
+
304
+ - The SDK contains no speech model or adapter runtime bytes in this entrypoint.
305
+ - The application must verify the license and authority for every supplied byte.
306
+ - URLs never carry credentials; fetch uses `credentials: "omit"`.
307
+ - Mutable `main`, `master`, and `latest` paths are rejected.
308
+ - The completion manifest is consistency evidence for the admitted DBOPFS
309
+ bytes. It is not publisher authenticity by itself.
310
+ - The runtime entry is isolated in a Worker and limited to its declared
311
+ artifact closure.
312
+ - Tool calls are an LLM concern; speech providers execute no application tool.
313
+ - A native `Arcane.speech` service is a different privileged host path. This
314
+ browser package neither calls it nor inherits its capability admission.
315
+
316
+ <details>
317
+ <summary>Protocol details</summary>
318
+
319
+ The artifact store identifies itself as
320
+ `arcane-ai-browser-speech-artifacts/1`. Authorities use
321
+ `arcane-ai-model-authority/1`. Providers implement `arcane-ai-provider/2` with
322
+ roles `stt` and `tts`; their only operations are `transcribe` and `synthesize`.
323
+ The Worker client additionally binds exact role, operation, request IDs, and
324
+ generation so stale or cross-role messages cannot settle current work.
325
+
326
+ </details>
327
+
328
+ ## Related
329
+
330
+ - [Normalized AI](../README.md#normalized-ai)
331
+ - [Browser-WASM LLM](browser-wasm.md)
332
+ - [AIProviderRuntime.js](../runtime-modules.md#aiproviderruntimejs)
333
+ - [AIRuntimeState.js](../runtime-modules.md#airuntimestatejs)
334
+ - [PersistentAIChatSession.js](../runtime-modules.md#persistentaichatsessionjs)
335
+ - [Availability and normalization](../availability-and-normalization.md)
336
+ - [Protocol architecture](../protocols.md#portable-ai-provider-runtime)