arcane-os 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +8 -8
  3. package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +29 -22
  4. package/browser-runtime/ai/ARCANE_AI_BROWSER_SPEECH_COMPONENTS.json +203 -0
  5. package/browser-runtime/ai/browser-kokoro-worker.mjs +11 -2
  6. package/browser-runtime/ai/browser-speech-artifacts.mjs +3230 -397
  7. package/browser-runtime/ai/browser-speech-providers.mjs +1141 -157
  8. package/browser-runtime/ai/browser-speech.mjs +2 -0
  9. package/browser-runtime/ai/browser-whisper-worker.mjs +11 -2
  10. package/browser-runtime/ai/model-controller.mjs +285 -95
  11. package/browser-runtime/ai/speech-worker-client.mjs +247 -32
  12. package/browser-runtime/ai/speech-worker-runtime.mjs +2310 -167
  13. package/browser-runtime/event-manager.mjs +1097 -1
  14. package/docs/architecture.md +2 -2
  15. package/docs/event-manager.md +155 -27
  16. package/docs/reference/README.md +27 -27
  17. package/docs/reference/ai/browser-speech-package-authority.json +835 -0
  18. package/docs/reference/ai/browser-speech.md +1162 -246
  19. package/docs/reference/ai/browser-wasm.md +18 -7
  20. package/docs/reference/availability-and-normalization.md +6 -3
  21. package/docs/reference/behavioral-testing.md +29 -6
  22. package/docs/reference/cli.md +117 -9
  23. package/docs/reference/core/arcane-ai-contracts.md +1 -1
  24. package/docs/reference/event-manager.md +577 -32
  25. package/docs/reference/inventory/package-api.json +478 -2
  26. package/docs/reference/inventory/runtime-components.json +108 -44
  27. package/docs/reference/inventory/runtime-modules.json +131 -53
  28. package/docs/reference/mail.md +316 -0
  29. package/docs/reference/protocols.md +157 -43
  30. package/docs/reference/runtime-components.md +258 -83
  31. package/docs/reference/runtime-modules.md +613 -77
  32. package/docs/reference/sdk-api.md +1014 -25
  33. package/package.json +5 -4
  34. package/runtime/ARCANE_RUNTIME_RELEASE.json +145 -140
  35. package/runtime/arcane/components/app-bar.html +34 -13
  36. package/runtime/arcane/components/assistant-panel.html +110 -57
  37. package/runtime/arcane/components/calculator.html +7 -4
  38. package/runtime/arcane/components/chart.html +58 -17
  39. package/runtime/arcane/components/chat.html +606 -136
  40. package/runtime/arcane/components/conversation-view.html +13 -6
  41. package/runtime/arcane/components/dashboard-config.html +96 -59
  42. package/runtime/arcane/components/data-maintenance.html +69 -14
  43. package/runtime/arcane/components/data-view.html +53 -7
  44. package/runtime/arcane/components/directory-picker.html +118 -32
  45. package/runtime/arcane/components/document-inspector.html +47 -10
  46. package/runtime/arcane/components/file-drop.html +81 -35
  47. package/runtime/arcane/components/file-inspector.html +72 -22
  48. package/runtime/arcane/components/file-manager.html +374 -79
  49. package/runtime/arcane/components/integration-settings.html +12 -5
  50. package/runtime/arcane/components/local-ai-status.html +48 -19
  51. package/runtime/arcane/components/markdown-document.html +161 -68
  52. package/runtime/arcane/components/markdown-editor.html +110 -33
  53. package/runtime/arcane/components/media-embed.html +8 -5
  54. package/runtime/arcane/components/modal.html +15 -5
  55. package/runtime/arcane/components/output-panel.html +28 -23
  56. package/runtime/arcane/components/preferences-form.html +22 -4
  57. package/runtime/arcane/components/record-timeline.html +18 -2
  58. package/runtime/arcane/components/relationship-board.html +23 -3
  59. package/runtime/arcane/components/screen-capture.html +10 -4
  60. package/runtime/arcane/components/source-code-viewer.html +76 -9
  61. package/runtime/arcane/components/source-explanation.html +23 -3
  62. package/runtime/arcane/components/speech.html +462 -384
  63. package/runtime/arcane/components/summary-strip.html +22 -11
  64. package/runtime/arcane/components/table.html +39 -21
  65. package/runtime/arcane/components/task-progress.html +79 -21
  66. package/runtime/arcane/components/terminal-workspace.html +7 -4
  67. package/runtime/arcane/components/theme-editor.html +7 -3
  68. package/runtime/arcane/components/unified-inbox.html +9 -4
  69. package/runtime/arcane/components/voice-transcription.html +639 -98
  70. package/runtime/arcane/components/weather-widget.html +5 -3
  71. package/runtime/arcane/components/web-navigator.html +48 -8
  72. package/runtime/arcane/entities/Chat.js +1 -1
  73. package/runtime/arcane/entities/User.js +110 -23
  74. package/runtime/arcane/modules/AI.js +2109 -130
  75. package/runtime/arcane/modules/AIProviderRuntime.js +720 -13
  76. package/runtime/arcane/modules/AIRuntimeState.js +109 -52
  77. package/runtime/arcane/modules/ApiModelDatabase.js +390 -17
  78. package/runtime/arcane/modules/BrowserTestSuite.js +205 -28
  79. package/runtime/arcane/modules/CalculatorEngine.js +63 -3
  80. package/runtime/arcane/modules/CommunicationAppController.js +588 -28
  81. package/runtime/arcane/modules/CommunicationHub.js +590 -10
  82. package/runtime/arcane/modules/ComponentContracts.js +470 -0
  83. package/runtime/arcane/modules/ConversationTimebox.js +152 -33
  84. package/runtime/arcane/modules/DBLS.js +40 -7
  85. package/runtime/arcane/modules/DBOPFS.js +35 -11
  86. package/runtime/arcane/modules/DataMaintenance.js +12 -2
  87. package/runtime/arcane/modules/Errors.js +65 -7
  88. package/runtime/arcane/modules/HTMLImport.js +198 -14
  89. package/runtime/arcane/modules/LocalAIReadinessController.js +208 -29
  90. package/runtime/arcane/modules/Mail.js +738 -115
  91. package/runtime/arcane/modules/MailOutbox.mjs +1395 -0
  92. package/runtime/arcane/modules/MailTransport.mjs +197 -39
  93. package/runtime/arcane/modules/Ollama.js +36 -1
  94. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +583 -7
  95. package/runtime/arcane/modules/PreferenceStore.js +367 -33
  96. package/runtime/arcane/modules/RecordReviewStore.js +322 -23
  97. package/runtime/arcane/modules/ScreenCapture.js +1397 -15
  98. package/runtime/arcane/modules/SpeechPlayback.js +438 -41
  99. package/runtime/arcane/modules/TerminalClient.js +277 -12
  100. package/runtime/arcane/modules/ThemeBootstrap.js +80 -6
  101. package/runtime/arcane/modules/ThemeManager.js +39 -7
  102. package/runtime/arcane/modules/TimeGuard.js +131 -20
  103. package/runtime/arcane/modules/WaitForComponent.js +386 -33
  104. package/schemas/arcane-lock.schema.json +2 -2
  105. package/src/cli/main.mjs +435 -9
  106. package/src/event-manager.mjs +1097 -1
  107. package/src/import-map.mjs +21 -3
  108. package/src/index.mjs +13 -0
  109. package/src/installed-sdk-runtime.mjs +112 -0
  110. package/src/mail-api.mjs +22 -0
  111. package/src/mail-credentials.mjs +667 -0
  112. package/src/mail-server.mjs +1769 -0
  113. package/src/mail.mjs +261 -0
  114. package/src/sdk-browser-runtime.mjs +85 -41
  115. package/src/testing-loader.mjs +7 -0
  116. package/src/toolchain.mjs +3 -0
  117. package/src/workspace.mjs +1 -1
@@ -13,6 +13,29 @@ Apps import renderer ESM from `/arcane/modules/<file>`. Classic scripts, the OPF
13
13
  - **Cloud** means the module can call an explicitly configured remote provider; it never implies automatic local-to-cloud fallback.
14
14
  - **Node**, **worker**, and **vendor** identify specialized runtimes.
15
15
 
16
+ ## Runtime semantic events and teardown
17
+
18
+ SDK runtime modules publish semantic state and lifecycle occurrences through the
19
+ one branded, versioned `globalThis.arcaneEvents` authority in each JavaScript
20
+ realm. A class can retain its existing `EventTarget` or `on()` compatibility
21
+ surface, but that surface delegates to a `createArcaneEventSource()` view scoped
22
+ by the module's source and instance identifiers; it does not own a second event
23
+ bus, listener `Map`, or listener `Set`. Every canonical occurrence and every
24
+ one-way DOM compatibility projection carries an occurrence ID. DOM input events
25
+ remain local UI/platform input, and projected DOM `CustomEvent`s must not be
26
+ mirrored back into the canonical source.
27
+
28
+ `arcaneEvents.subscribe(type,handler,{once,signal})` and source-scoped
29
+ `subscribe()`/`on()` registrations return one idempotent unsubscribe function
30
+ (also exposed as `.dispose`). The singleton's legacy `on()`/`once()` methods are
31
+ chainable compatibility APIs that return the manager; lifecycle-owned consumers
32
+ use `subscribe()`. Instance `dispose()`/`destroy()` methods remove owned
33
+ listeners, abort owned work, suppress stale settlement, and dispose the instance
34
+ source. Module-lifetime singleton sources instead expose a focused module
35
+ teardown function where teardown is supported. Event publication is synchronous
36
+ and observational; promises, `AbortSignal`, and `createEventQueue` continue to
37
+ own asynchronous work, cancellation, and backpressure.
38
+
16
39
  ## Canonical inventory
17
40
 
18
41
  | Module | Kind | Capability | Availability | Normalization |
@@ -41,7 +64,7 @@ Apps import renderer ESM from `/arcane/modules/<file>`. Classic scripts, the OPF
41
64
  | [`CommunicationHub.js`](#communicationhubjs) | esm | Fans out provider refresh/send operations and aggregates normalized threads/messages. | Cross-host with injected providers | Normalized aggregates; refresh contains per-provider failures. |
42
65
  | [`CommunicationPreferences.js`](#communicationpreferencesjs) | esm | Stores app-scoped, non-secret communication provider preferences. | Browser / native WebView hybrid | Normalized preference record; storage failures mixed. |
43
66
  | [`CommunicationProviderRegistry.js`](#communicationproviderregistryjs) | esm | Registers and queries validated provider definitions, channels, and required methods. | Cross-host | Strict normalized registry. |
44
- | [`ComponentContracts.js`](#componentcontractsjs) | esm | Owns normalized configuration/value contracts shared by chart, dashboard, Markdown, and voice components. | Cross-host | Fully normalized labels, rows, definitions, visibility, formats, editor and voice options. |
67
+ | [`ComponentContracts.js`](#componentcontractsjs) | esm | Owns normalized configuration/value contracts and shared explicit STT activation behavior for chart, dashboard, Markdown, and voice components. | Cross-host | Fully normalized labels, rows, definitions, visibility, formats, editor and voice options, plus capability-neutral STT activation intent and presentation state. |
45
68
  | [`ConfiguredAIChatSession.js`](#configuredaichatsessionjs) | esm | Owns bounded in-memory AI turns, context construction, response-length instruction, and atomic history commit. | Native bridge by default; cross-host with injected chat | Normalized session/result; provider rejection preserved. |
46
69
  | [`ConversationActionItems.js`](#conversationactionitemsjs) | esm | Normalizes, creates, updates, remembers, selects, and formats bounded conversation action items. | Cross-host | Fully normalized status/base/presentation contract. |
47
70
  | [`ConversationClosingReport.js`](#conversationclosingreportjs) | esm | Defines the closing-report tool, instruction, result normalizer, call classifier, and formatter. | Cross-host | Fully normalized report contract. |
@@ -64,6 +87,7 @@ Apps import renderer ESM from `/arcane/modules/<file>`. Classic scripts, the OPF
64
87
  | [`LocalAIReadiness.js`](#localaireadinessjs) | esm | Derives selected AI requirements and returns a frozen readiness/recovery report across browser, desktop, and Android modes. | Browser/native hybrid | Fully normalized report and stable error codes; browsers never probe Ollama. |
65
88
  | [`LocalAIReadinessController.js`](#localaireadinesscontrollerjs) | esm | Coordinates local-AI status component checks, ensured recovery, availability projection, and teardown. | Browser/native hybrid | Normalized controller state and change events. |
66
89
  | [`Mail.js`](#mailjs) | esm | Builds bounded reports and prefers the native mail capability with an explicit HTTP transport fallback. | Browser/native hybrid + cloud | Mail inputs/results normalized; transport failures mixed. |
90
+ | [`MailOutbox.mjs`](#mailoutboxmjs) | esm | Persists bounded mail reports before delivery and normalizes idempotent enqueue, retry, reconciliation, and invalid-record maintenance. | Browser/native WebView or compatible injected host | Frozen records, bounded work, cancellation, and lifecycle states normalized; storage, lock, and delivery failures coded. |
67
91
  | [`MailTransport.mjs`](#mailtransportmjs) | esm | Sends one bounded mail report to a normalized HTTP(S) endpoint with timeout and response-size limits. | Browser/server with fetch + cloud | Normalized endpoint/timeout/size errors; remote detail bounded. |
68
92
  | [`Marked.min.js`](#markedminjs) | esm | Vendored Marked 18.0.5 Markdown lexer, parser, renderer, extension, and walk-token API. | Cross-host vendor module | Vendor-native Marked contract. |
69
93
  | [`MD.js`](#mdjs) | esm | Renders Markdown with Marked and exposes a DOM-sanitized projection. | Browser / native WebView | Raw Marked behavior plus Arcane sanitization; parse errors vendor-native. |
@@ -111,10 +135,13 @@ Provider-selectable chat, speech-to-text, text-to-speech, tool calling, structur
111
135
 
112
136
  ### Public surface
113
137
 
114
- default `AI`; read-only `providerRuntime`; `setAI()`, `configureProviders()`, `transitionAI()`,
115
- `transitionProviders()`, `startProviders()`, `setSpeechMuted()`,
138
+ default `AI`; read-only `providerRuntime`, `browserSpeechConfiguration`, and
139
+ `browserSpeechDescriptor`; `configureBrowserSpeech(configuration,{signal})`,
140
+ `disposeBrowserSpeech({signal})`, `setAI()`, `configureProviders()`,
141
+ `configureSpeechProviders()`, `transitionAI()`, `transitionProviders()`,
142
+ `transitionSpeechProviders()`, `startProviders()`, `setSpeechMuted()`,
116
143
  `streamRequest()`, `streamMessage()`, `fetchRequest()`, `fetch()`,
117
- `streamTTS()`, `finishTTS()`, `fetchSTT()`, `stopAudio()`, `resumeAudio()`,
144
+ `streamTTS()`, `finishTTS()`, `fetchTTS()`, `fetchSTT()`, `stopAudio()`, `resumeAudio()`,
118
145
  `playAudio()`; consumes `user-entity-loaded` and `arcane-ollama-ready`,
119
146
  installs `window.ai`, and emits `ai-ready`.
120
147
 
@@ -138,18 +165,200 @@ the exact selected provider/model catalog `defaultVoice`; a saved OpenAI voice
138
165
  is used only by the selected OpenAI adapter and is never forwarded to another
139
166
  provider route.
140
167
 
168
+ `configureSpeechProviders({stt,tts})` commits only the two speech routes and
169
+ leaves the current LLM route and sticky lifecycle record unchanged. Both speech
170
+ roles must be unloaded and own no request, load, unload, or dispose operation.
171
+ `transitionSpeechProviders({stt,tts})` stops queued audio, explicitly unloads
172
+ only STT and TTS, then commits that same closed speech route record. Neither
173
+ method loads a model, selects a fallback, or changes caller-owned model or voice
174
+ policy.
175
+
141
176
  `startProviders({startMuted=true,startTranscription=false,signal=null}={})`
142
177
  starts text chat without requesting an STT load by default; it does not undo an
143
- already ready or independently loading role. Callers must opt into eager STT
144
- startup with `startTranscription:true` or publish the explicit user activation
145
- intent exposed by the shared speech component. `setSpeechMuted(false)` records
146
- the shared unmuted lifecycle preference before loading TTS, while
178
+ already ready or independently loading LLM or STT role. Its default
179
+ `startMuted:true` path cancels active TTS work and unloads TTS. Callers must opt
180
+ into eager STT startup with `startTranscription:true` or publish the explicit
181
+ user activation intent exposed by the shared speech component.
182
+ `setSpeechMuted(false)` records the public unmuted state only after the selected
183
+ TTS route reaches ready; a failed load leaves the public state muted. In contrast,
147
184
  `setSpeechMuted(true)` cancels active TTS work and unloads that role.
185
+ `fetchTTS({model,voice,input,responseFormat,speed},signal)` accepts the public
186
+ provider-neutral synthesis shape, requires any explicit model to match the
187
+ admitted route, and admits an omitted voice only from the selected model
188
+ catalog's `defaultVoice`. An omitted response format preserves the instance's
189
+ existing `audioFormat` for a compatibility-only catalog. When the selected model
190
+ declares `speech.responseFormats`, that setting is used only when admitted; if
191
+ the setting is the legacy `opus` default and the model rejects it, the catalog's
192
+ `speech.defaultResponseFormat` is used, while any other unsupported setting is
193
+ rejected. It propagates the caller-owned signal and returns a playable `Blob`;
194
+ it does not independently choose a provider, cloud fallback, model, runtime, or
195
+ voice policy for the application. Existing `streamTTS()` and `finishTTS()` use
196
+ this same request boundary.
148
197
  `fetchSTT(audioFile,responseHandler,signal)` propagates the caller-owned signal;
198
+ provider routes accept a `Blob` or `File` directly and leave media decoding,
199
+ PCM normalization, and WAV construction to the selected shared provider;
149
200
  delivery suppression is guaranteed after abort, while underlying provider-stop
150
201
  claims remain limited to that provider's cancellation contract.
151
202
 
152
- Exact exports: `default`.
203
+ #### Browser speech configuration
204
+
205
+ The caller constructs a frozen authority record for one or both roles and
206
+ retains ownership of it. This example configures both:
207
+
208
+ ```javascript
209
+ import AI, {
210
+ AI_BROWSER_SPEECH_CONFIGURATION_PROTOCOL
211
+ } from '/arcane/modules/AI.js';
212
+
213
+ const speechConfiguration = Object.freeze({
214
+ protocol: AI_BROWSER_SPEECH_CONFIGURATION_PROTOCOL,
215
+ id: 'app-speech-authority',
216
+ dbopfs,
217
+ tableName: 'browser-speech-artifacts', // optional
218
+ stt: Object.freeze({
219
+ providerId: 'app-whisper',
220
+ graph: sttGraph,
221
+ security: Object.freeze({secure: true}),
222
+ offline: false
223
+ }),
224
+ tts: Object.freeze({
225
+ providerId: 'app-kokoro',
226
+ graph: ttsGraph,
227
+ security: Object.freeze({secure: true}),
228
+ offline: false
229
+ })
230
+ });
231
+
232
+ const ai = new AI(/* existing application AI preferences */);
233
+ const descriptor = await ai.configureBrowserSpeech(
234
+ speechConfiguration,
235
+ {signal}
236
+ );
237
+
238
+ // Configuration does not load either role. Activate only from an explicit UI.
239
+ await ai.providerRuntime.load('stt', {signal});
240
+ await ai.setSpeechMuted(false); // loads the selected TTS role, then unmutes
241
+
242
+ // Teardown unloads, unregisters, and disposes only this SDK-owned configuration.
243
+ await ai.disposeBrowserSpeech({signal});
244
+ ```
245
+
246
+ The record must be a frozen plain data record with exactly
247
+ `{protocol,id,dbopfs,tableName?,stt?,tts?}` and at least one role. Each supplied
248
+ frozen role is exactly `{providerId,graph,security,offline}` or
249
+ `{providerId,model,runtime,security?,offline}`. The graph and direct authority
250
+ forms are mutually exclusive; `providerId` and `id` are trimmed 1-128 character
251
+ strings, `graph` is the role-matching frozen graph returned by the SDK browser
252
+ speech artifact API, graph `security` must explicitly select `secure:true`, and
253
+ `offline` is boolean. The direct form forwards its
254
+ caller-selected model, runtime, and optional security descriptors to the shared
255
+ provider. In warn-first mode it may use an empty `model.files` inventory and a
256
+ version-pinned upstream `runtime.wasmPaths`; secure graph mode remains the
257
+ closed, content-addressed path. The application chooses every artifact,
258
+ immutable graph or direct model/runtime authority, provider ID, offline policy,
259
+ sample rate, and TTS default voice. `configureBrowserSpeech()` imports the shared
260
+ browser-speech module, creates one DBOPFS store, constructs and registers the
261
+ supplied Whisper and/or Kokoro provider/2 instances, atomically replaces only
262
+ the supplied STT/TTS routes, and returns a frozen descriptor. An initial or
263
+ later call may supply only `stt` or only `tts`; the omitted external Cloud/Core
264
+ role remains unchanged and is not claimed as SDK browser-provider ownership.
265
+ A partial replacement of an existing browser-managed record retains the same
266
+ `dbopfs` and `tableName`, carries every omitted managed browser provider and
267
+ route unchanged, and unregisters and disposes only the replaced provider after
268
+ commit. Supplying both roles remains one atomic replacement. Applications do not register those
269
+ providers, decode `Blob`/`File` data into PCM, construct WAV, select Worker URLs,
270
+ or reproduce DBOPFS cache or artifact verification logic.
271
+
272
+ The returned descriptor is exactly `{protocol,configurationId,stt,tts}`; an
273
+ external, unmanaged role is `null`. A managed STT descriptor is
274
+ `{role:'stt',providerId,modelId,artifactGraphId?,offline}`; TTS adds
275
+ `defaultVoice`. `artifactGraphId` is present only for the graph form.
276
+ `browserSpeechConfiguration` returns the exact caller-owned record when no
277
+ managed role is carried. After a partial replacement that carries another
278
+ managed role, it returns a frozen merged record with the replacement call's
279
+ `id` and the carried role's unchanged authority. It is non-null only while the
280
+ SDK still owns every represented browser provider and route;
281
+ `browserSpeechDescriptor` returns that descriptor on the same condition.
282
+ Configuration never loads a role, auto-downloads, selects an alternative
283
+ provider/model/runtime/voice, or falls back to cloud/browser speech.
284
+
285
+ Calling `configureBrowserSpeech()` again with the same active record for every
286
+ supplied role is an idempotent descriptor read. A different call is serialized,
287
+ aborts the prior owned operation, unloads only the replaced speech roles, atomically
288
+ replaces provider ownership/routes, and suppresses stale settlement. A
289
+ single-role replacement does not reconstruct, unregister, dispose, or reroute
290
+ the omitted role or change its ready/selected state, provider identity,
291
+ operation generation, or lifecycle. STT-only replacement also preserves TTS
292
+ mute and playback state; TTS replacement invalidates current TTS speech control
293
+ before replacing that role. The caller's signal is
294
+ forwarded and detached on settlement. Cancellation proves delivery suppression,
295
+ not that provider work stopped beyond the provider's own cancellation contract.
296
+ Once SDK-owned browser speech is active, synchronous route mutation fails with
297
+ `ARCANE_AI_BROWSER_SPEECH_ASYNC_TRANSITION_REQUIRED`; use an asynchronous
298
+ transition method or await `disposeBrowserSpeech()`.
299
+
300
+ Browser speech publishes these exact event values through the AI instance's
301
+ canonical event source. Public consumers use
302
+ `arcaneEvents.subscribe(type,handler,{signal})`; `handler(occurrence)` receives
303
+ the frozen canonical occurrence and can correlate `source:'ai'`, `instanceId`,
304
+ and `operationId`:
305
+
306
+ | Constant member | Stable value |
307
+ | --- | --- |
308
+ | `configurationStarted` | `ai-browser-speech-configuration-started` |
309
+ | `configured` | `ai-browser-speech-configured` |
310
+ | `configurationCancelled` | `ai-browser-speech-configuration-cancelled` |
311
+ | `configurationError` | `ai-browser-speech-configuration-error` |
312
+ | `disposed` | `ai-browser-speech-disposed` |
313
+
314
+ Canonical public details are frozen and contain `configurationId`, optional
315
+ `descriptor`, optional exact `code`, and `reason`. The private source-local
316
+ compatibility view also carries the caller-owned configuration and optional
317
+ error, but `AI` does not expose that source handle and the global occurrence
318
+ does not publish those private values. Reasons are exactly `speech-configuration-added`,
319
+ `speech-configuration-replaced`, `speech-configuration-cancelled`,
320
+ `speech-configuration-disposed`, `speech-configuration-contract-mismatch`,
321
+ `speech-configuration-async-transition-required`,
322
+ `speech-operation-options-contract-mismatch`,
323
+ `speech-operation-sequence-exhausted`, `speech-module-import-rejected`,
324
+ `speech-artifact-store-construction-rejected`,
325
+ `speech-provider-construction-rejected`, `speech-provider-disposal-rejected`,
326
+ `speech-provider-route-ownership-mismatch`,
327
+ `speech-provider-unregistration-rejected`, `speech-route-commit-rejected`,
328
+ `speech-route-rollback-rejected`, and `speech-route-view-update-rejected`.
329
+ Their corresponding exact public codes are the values of
330
+ `AI_BROWSER_SPEECH_ERROR_CODES`: `ARCANE_AI_BROWSER_SPEECH_CONFIGURATION_CANCELLED`,
331
+ `ARCANE_AI_BROWSER_SPEECH_CONFIGURATION_SUPERSEDED`,
332
+ `ARCANE_AI_BROWSER_SPEECH_CONFIGURATION_CONTRACT_MISMATCH`,
333
+ `ARCANE_AI_BROWSER_SPEECH_ASYNC_TRANSITION_REQUIRED`,
334
+ `ARCANE_AI_BROWSER_SPEECH_OPERATION_OPTIONS_CONTRACT_MISMATCH`,
335
+ `ARCANE_AI_BROWSER_SPEECH_OPERATION_SEQUENCE_EXHAUSTED`,
336
+ `ARCANE_AI_BROWSER_SPEECH_MODULE_IMPORT_REJECTED`,
337
+ `ARCANE_AI_BROWSER_SPEECH_ARTIFACT_STORE_CONSTRUCTION_REJECTED`,
338
+ `ARCANE_AI_BROWSER_SPEECH_PROVIDER_CONSTRUCTION_REJECTED`,
339
+ `ARCANE_AI_BROWSER_SPEECH_PROVIDER_DISPOSAL_REJECTED`,
340
+ `ARCANE_AI_BROWSER_SPEECH_PROVIDER_ROUTE_OWNERSHIP_MISMATCH`,
341
+ `ARCANE_AI_BROWSER_SPEECH_PROVIDER_UNREGISTRATION_REJECTED`,
342
+ `ARCANE_AI_BROWSER_SPEECH_ROUTE_COMMIT_REJECTED`,
343
+ `ARCANE_AI_BROWSER_SPEECH_ROUTE_ROLLBACK_REJECTED`, and
344
+ `ARCANE_AI_BROWSER_SPEECH_ROUTE_VIEW_UPDATE_REJECTED`.
345
+
346
+ `fetchTTS()` rejects malformed request/signal/input/model/voice/format/speed
347
+ boundaries with `ARCANE_AI_TTS_REQUEST_INVALID`,
348
+ `ARCANE_AI_TTS_SIGNAL_INVALID`, `ARCANE_AI_TTS_INPUT_INVALID`,
349
+ `ARCANE_AI_TTS_MODEL_INVALID`, `ARCANE_AI_TTS_MODEL_REQUIRED`,
350
+ `ARCANE_AI_TTS_MODEL_SELECTION_MISMATCH`, `ARCANE_AI_TTS_VOICE_INVALID`,
351
+ `ARCANE_AI_TTS_VOICE_REQUIRED`, `ARCANE_AI_TTS_RESPONSE_FORMAT_INVALID`, or
352
+ `ARCANE_AI_TTS_SPEED_INVALID`; a non-playable provider result is
353
+ `ARCANE_AI_TTS_PROVIDER_AUDIO_INVALID`. `fetchSTT()` uses
354
+ `ARCANE_AI_STT_RESPONSE_HANDLER_INVALID`, `ARCANE_AI_STT_SIGNAL_INVALID`, and
355
+ `ARCANE_AI_STT_PROVIDER_TRANSCRIPT_INVALID` at those exact boundaries. Owned
356
+ request abortion is `ARCANE_AI_REQUEST_ABORTED`.
357
+
358
+ Exact exports: `AI_BROWSER_SPEECH_CONFIGURATION_PROTOCOL`,
359
+ `AI_BROWSER_SPEECH_ERROR_CODES`, `AI_BROWSER_SPEECH_EVENT_TYPES`,
360
+ `AI_BROWSER_SPEECH_REASONS`, `AI_INITIALIZATION_ERROR_CODES`,
361
+ `AI_INITIALIZATION_REASONS`, `AI_READY_EVENT`, and `default`.
153
362
 
154
363
  ### Availability and normalization
155
364
 
@@ -160,11 +369,7 @@ Arcane.speech, and the Android WebView bridge. [Deep protocol details](protocols
160
369
 
161
370
  ### Example
162
371
 
163
- ```javascript
164
- import * as module from '/arcane/modules/AI.js';
165
-
166
- console.log(Object.keys(module));
167
- ```
372
+ The configuration example above is the minimal one-time application flow.
168
373
 
169
374
  ## AIPreferenceRuntime.js
170
375
 
@@ -226,20 +431,73 @@ shape, but application code uses the exported singleton returned by
226
431
 
227
432
  ### Public surface
228
433
 
229
- Exact exports: `AI_PROVIDER_PROTOCOL`, `AI_PROVIDER_RUNTIME_PROTOCOL`,
230
- `AI_MODEL_AUTHORITY_PROTOCOL`, `AIProviderRuntime`, `aiProviderRuntime`, and
434
+ Exact exports: `AI_MODEL_AUTHORITY_PROTOCOL`, `AI_PROVIDER_PROTOCOL`,
435
+ `AI_PROVIDER_RUNTIME_PROTOCOL`, `AIProviderRuntime`, `aiProviderRuntime`, and
231
436
  `getAIProviderRuntime`.
232
437
 
233
- The singleton exposes provider registration, closed three-role configuration,
234
- catalog and status inspection, `start()`, independent `load()`, `unload()`,
235
- `dispose()`, and `cancel()` operations, plus `chat()`, `stream()`,
236
- `transcribe()`, `synthesize()`, and `setSpeechMuted()`. Provider payloads must
438
+ The singleton exposes read-only `protocol`, `configured`, and `speechMuted`;
439
+ `register(provider)`; `unregister(role,providerId,expectedProvider=null)`;
440
+ `hasProvider(role,providerId)`; `ownsProvider(role,expectedProvider)`;
441
+ `providerIdentity(role,providerId)`; `selection(role,options={})`;
442
+ `ownsSelection(role,providerId,options={})`;
443
+ `validateConfiguration(value)`; `validateSpeechConfiguration(value)`;
444
+ `configure(value)`; `configureSpeech(value)`;
445
+ `replaceSpeechProvider(role,value)`; `replaceSpeechProviders(value)`;
446
+ `configureFromTuple(tuple)`;
447
+ `status(role=null)`; `catalog(role)`;
448
+ `inspect(role,options={})`; `start(options)`; `load(role,options={})`;
449
+ `unload(role,options={})`; `dispose(role,options={})`;
450
+ `disposeAll(options={})`; `cancel(role)`; `request(role,options={})`;
451
+ `chat(payload,options={})`; `stream(payload,options={})`;
452
+ `transcribe(payload,options={})`; `synthesize(payload,options={})`; and
453
+ `setSpeechMuted(muted)`. Provider payloads must
237
454
  be data-only; callbacks, accessors, symbols, cycles, and excessive nesting are
238
455
  rejected at the provider boundary.
239
456
 
240
- `start({startMuted=true,startTranscription=false,signal=null}={})` waits for
241
- prior speech-state and role unload work, applies the requested initial mute
242
- state, and returns the `startAIRuntime()` control handle
457
+ Selection options admit `localOnly=false`; inspection admits
458
+ `{localOnly=false,signal=null}`; startup admits
459
+ `{startMuted=true,startTranscription=false,signal=null}` (including an omitted
460
+ `options` value); load admits `{signal=null,localOnly=false}`; unload, dispose,
461
+ and dispose-all admit `{signal=null}`. Request requires the exact
462
+ `{operation,payload,localOnly,signal}` options record; the four role-specific
463
+ request helpers admit `{localOnly=false,signal=null}`. Configuration `value`
464
+ records are the closed `{llm,stt,tts}`, `{stt,tts}`, or
465
+ `{provider,routes,expectedProvider}` and
466
+ `{providers,routes,expectedProviders}` shapes described below.
467
+ `configureFromTuple()` accepts exactly six provider/model preference entries.
468
+
469
+ `register()` returns the provider's single unregister closure; caller-
470
+ registered providers remain caller-owned. The high-level
471
+ `AI.configureBrowserSpeech()` boundary is different: AI constructs, registers,
472
+ atomically replaces, unregisters, and disposes those two SDK-owned providers.
473
+ `status()` is the sticky frozen AIRuntimeState snapshot (or one role record),
474
+ while `catalog()` synchronously returns frozen provider/model admissions and
475
+ never loads or downloads a model. `load()` forwards provider progress into the
476
+ sticky role record; `unload()` and `dispose()` abort owned work, await exposed
477
+ settlement, and verify provider status before publishing terminal state.
478
+
479
+ `validateSpeechConfiguration(value)` returns one frozen two-role selection
480
+ record without committing it, where `value` is the closed `{stt,tts}` record.
481
+ `configureSpeech(value)` accepts the same record, requires both speech roles to
482
+ own no ready/load/unload/dispose or request work, commits only STT/TTS, restores
483
+ muted speech admission, and returns the frozen selection record. The current LLM
484
+ routes, selection, readiness, operation generation, and sticky state remain
485
+ unchanged. A malformed top-level, route, or selection record preserves the
486
+ compatibility code
487
+ `ARCANE_AI_PROVIDER_RUNTIME_INVALID` and adds exact reason
488
+ `speech-configuration-contract-mismatch`; runtime-disposed, reentrant,
489
+ role-busy, and provider-locality failures retain their existing exact codes.
490
+
491
+ `replaceSpeechProvider(role,value)` accepts only `stt` or `tts` and atomically
492
+ replaces exactly that unloaded role using the closed
493
+ `{provider,routes,expectedProvider}` record. A null `provider` with empty routes
494
+ removes that role and requires its exact non-null expected provider. The method preserves the omitted role's
495
+ provider registration, routes, selection, readiness, generation, sticky state,
496
+ owned lifecycle work, and TTS mute state. `replaceSpeechProviders(value)` keeps
497
+ the existing atomic two-role boundary for a coordinated STT/TTS replacement.
498
+
499
+ `start(options)` waits for prior speech-state and role unload work, applies the
500
+ requested initial mute state, and returns the `startAIRuntime()` control handle
243
501
  `{barrier,settled,cancel}`. Startup does not request selected STT unless the
244
502
  caller explicitly opts in; it does not force an independently active STT role
245
503
  back to unloaded. The barrier and settled promises describe provider-startup
@@ -259,15 +517,16 @@ request ownership is active.
259
517
 
260
518
  ### Availability and normalization
261
519
 
262
- **Cross-host runtime with provider-specific execution.** Published SDK `0.2.1`
263
- ships the browser-WASM LLM and browser Whisper/Kokoro adapters but predates the
264
- legacy speech adapters described above. Current source also supplies the narrow
265
- AI.js legacy OpenAI/Ollama/Core-speech adapters; other native, Core, or cloud
266
- adapters may be supplied externally only when they implement the same
520
+ **Cross-host runtime with provider-specific execution.** The SDK source ships
521
+ the browser-WASM LLM and browser Whisper/Kokoro adapters and supplies the
522
+ narrow AI.js legacy OpenAI/Ollama/Core-speech adapters; other native, Core, or
523
+ cloud adapters may be supplied externally only when they implement the same
267
524
  `arcane-ai-provider/2` boundary. A
268
525
  provider must prove a matching `arcane-ai-model-authority/1` inspection before load.
269
526
  `localOnly` routing fails closed; it never selects a cloud or non-local route as
270
- a fallback. Role lifecycle and stream cleanup are normalized, while the
527
+ a fallback. A missing or mismatched explicit local-only route rejects load or
528
+ request admission with `AI_LOCAL_MODEL_REQUIRED`. Role lifecycle and stream
529
+ cleanup are normalized, while the
271
530
  selected provider retains its own capability, permission, download, and model
272
531
  requirements. [Deep protocol details](protocols.md#portable-ai-provider-runtime).
273
532
 
@@ -338,15 +597,21 @@ observable without exposing provider transports in application code.
338
597
 
339
598
  ### Public surface
340
599
 
341
- Exact exports: `AI_RUNTIME_PROTOCOL`, `AI_RUNTIME_STATE_EVENT`,
342
- `AI_RUNTIME_INTENT_EVENT`, `AI_RUNTIME_STARTUP_EVENT`, `AI_RUNTIME_ROLES`,
343
- `AI_RUNTIME_STATES`, `aiRuntimeEvents`, `getAIRuntimeState()`,
344
- `subscribeAIRuntimeState()`, `publishAIRuntimeRoleState()`,
345
- `publishAIRuntimeRolesState()`, `requestAIRuntimeIntent()`,
346
- `subscribeAIRuntimeIntents()`, and `startAIRuntime()`.
600
+ Exact exports: `AI_RUNTIME_INTENT_EVENT`, `AI_RUNTIME_PROTOCOL`,
601
+ `AI_RUNTIME_ROLES`, `AI_RUNTIME_STARTUP_EVENT`, `AI_RUNTIME_STATES`,
602
+ `AI_RUNTIME_STATE_EVENT`, `aiRuntimeEvents`, `getAIRuntimeState`,
603
+ `publishAIRuntimeRoleState`, `publishAIRuntimeRolesState`,
604
+ `requestAIRuntimeIntent`, `startAIRuntime`, `subscribeAIRuntimeIntents`, and
605
+ `subscribeAIRuntimeState`.
347
606
 
348
607
  Each role record is exactly `{role,state,providerId,modelId,localOnly,loaded,
349
608
  busy,operationId,progress,error}`.
609
+ `subscribeAIRuntimeState(listener,{signal=null,emitCurrent=true})` installs its
610
+ subscription and synchronously replays the current frozen snapshot by default;
611
+ `subscribeAIRuntimeIntents(listener,{signal=null})` is future-only. Both return
612
+ one idempotent unsubscribe/dispose closure. `aiRuntimeEvents` is a deprecated,
613
+ state-free EventTarget compatibility view over the same canonical source; it is
614
+ not a second authority and owns no listener registry.
350
615
  `startAIRuntime({startMuted=true,startTranscription=false,signal})` returns
351
616
  `{barrier,settled,cancel}`: `barrier` settles for text chat, while `settled`
352
617
  covers every requested role. Muted startup does not request TTS, and STT startup
@@ -363,6 +628,11 @@ does not grant a native capability, prove browser support, or load a provider.
363
628
  `arcane-ai-runtime-startup-settled` reports the LLM/text-chat `barrier`.
364
629
  Await the returned `handle.settled` promise for every role requested by that
365
630
  startup; the all-role settlement has no separate public event.
631
+ Intent records are exactly `{role,action,reason}` where roles are `llm`, `stt`,
632
+ or `tts`; actions are `load`, `unload`, or `dispose`; and reasons are `startup`,
633
+ `user`, or `teardown`. Invalid closed records fail with the stable prefix
634
+ `ARCANE_AI_RUNTIME_STATE_INVALID`; startup cancellation is an `AbortError` with
635
+ code `ARCANE_AI_REQUEST_ABORTED`.
366
636
 
367
637
  ### Example
368
638
 
@@ -413,7 +683,8 @@ Fetches an injectable HTTP JSON model with parser, cache, redacted public endpoi
413
683
 
414
684
  default `ApiModelDatabase`; `setEndpoint()`, `fetch()`, `cached()`; emits `api-model-request`, `api-model-success`, and `api-model-error`.
415
685
 
416
- Exact exports: `appendParameters`, `default`, `publicEndpoint`.
686
+ Exact exports: `API_MODEL_ERRORS`, `API_MODEL_EVENTS`, `appendParameters`,
687
+ `default`, `publicEndpoint`.
417
688
 
418
689
  ### Availability and normalization
419
690
 
@@ -581,7 +852,9 @@ Runs a fixed sequential browser test list with cooperative abort, per-test timeo
581
852
 
582
853
  default `BrowserTestSuite`; `list()`, `run()`; emits suite/test start/result/complete events.
583
854
 
584
- Exact exports: `assertionError`, `default`, `skipError`.
855
+ Exact exports: `BROWSER_TEST_SUITE_ERROR_CODES`,
856
+ `BROWSER_TEST_SUITE_EVENT_TYPES`, `BROWSER_TEST_SUITE_REASONS`,
857
+ `assertionError`, `default`, `skipError`.
585
858
 
586
859
  ### Availability and normalization
587
860
 
@@ -603,13 +876,40 @@ Evaluates bounded arithmetic, powers, constants, and common functions without `e
603
876
 
604
877
  ### Public surface
605
878
 
606
- default `CalculatorEngine`, `evaluateExpression()`; `calculate()` emits result/error events.
879
+ `new CalculatorEngine()` exposes synchronous
880
+ `calculate(expression): Calculation`,
881
+ `addEventListener(type,listener,options): void`,
882
+ `removeEventListener(type,listener,options): void`,
883
+ `on(type,listener,options): unsubscribe`,
884
+ `dispatchEvent(event): boolean`, and idempotent
885
+ `dispose(): boolean` / `destroy(): boolean`. `evaluateExpression(input): number`
886
+ remains the parser-only helper. `CALCULATOR_ENGINE_ERROR_CODES` is one frozen
887
+ record containing the stable `disposed`, `input`, `syntax`, `domain`, and
888
+ `evaluation` codes.
607
889
 
608
- Exact exports: `default`, `evaluateExpression`.
890
+ Exact exports: `CALCULATOR_ENGINE_ERROR_CODES`, `default`,
891
+ `evaluateExpression`.
609
892
 
610
893
  ### Availability and normalization
611
894
 
612
- **Cross-host.** Normalized `Calculation` result and parser errors. Transport: In-process only. [Deep protocol details](protocols.md).
895
+ **Cross-host.** Each engine owns one `calculator-engine` source on the realm's
896
+ branded `globalThis.arcaneEvents`. `calculator-result` publishes frozen public
897
+ detail `{result}`; the legacy instance listener receives the same `Calculation`
898
+ object returned by `calculate()`. `calculator-error` publishes frozen public
899
+ detail `{code}`; the legacy listener receives frozen
900
+ `{expression,error}` while `calculate()` rethrows that same `Error`. Both
901
+ occurrences carry one source-instance `operationId`. Listener callbacks are
902
+ synchronous observations; their failures are reported by the central event
903
+ authority and do not rewrite calculation settlement. Listener registration
904
+ supports `{once,signal}` and its returned unsubscribe also exposes `.dispose()`.
905
+ Disposal removes instance listeners and rejects later calculations with
906
+ `ARCANE_CALCULATOR_ENGINE_DISPOSED`. Invalid expression input, syntax, numeric
907
+ domain, and unexpected evaluation boundaries use
908
+ `ARCANE_CALCULATOR_EXPRESSION_INPUT_INVALID`,
909
+ `ARCANE_CALCULATOR_EXPRESSION_SYNTAX_INVALID`,
910
+ `ARCANE_CALCULATOR_EXPRESSION_DOMAIN_INVALID`, and
911
+ `ARCANE_CALCULATOR_EXPRESSION_EVALUATION_FAILED`. Transport: in-process only.
912
+ [Deep protocol details](protocols.md).
613
913
 
614
914
  ### Example
615
915
 
@@ -702,7 +1002,7 @@ Binds shared inbox, conversation, settings, theme, and provider workflows into o
702
1002
 
703
1003
  default controller with `start()`, `bind()`, `configure()`, `refresh()`, `select()`, `send()`, and settings actions.
704
1004
 
705
- Exact exports: `default`.
1005
+ Exact exports: `COMMUNICATION_APP_CONTROLLER_ERROR_CODES`, `default`.
706
1006
 
707
1007
  ### Availability and normalization
708
1008
 
@@ -726,7 +1026,9 @@ Fans out provider refresh/send operations and aggregates normalized threads/mess
726
1026
 
727
1027
  default `CommunicationHub`; provider enablement, `refresh()`, `messages()`, and `send()`.
728
1028
 
729
- Exact exports: `default`.
1029
+ Exact exports: `COMMUNICATION_HUB_ERROR_CODES`, `COMMUNICATION_HUB_EVENTS`,
1030
+ `COMMUNICATION_HUB_REFRESH_REASONS`, `COMMUNICATION_HUB_REFRESH_STATES`, and
1031
+ `default`.
730
1032
 
731
1033
  ### Availability and normalization
732
1034
 
@@ -792,17 +1094,48 @@ console.log(Object.keys(module));
792
1094
 
793
1095
  ### Overview
794
1096
 
795
- Owns normalized configuration/value contracts shared by chart, dashboard, Markdown, and voice components.
1097
+ Owns normalized configuration/value contracts and shared explicit STT activation
1098
+ behavior for chart, dashboard, Markdown, and voice components.
796
1099
 
797
1100
  ### Public surface
798
1101
 
799
- Six constant sets and twelve normalization/formatting helpers.
1102
+ Constant sets plus normalization, formatting, and explicit STT activation
1103
+ helpers. `createSTTActivationController({host,button,onChange,EventClass=CustomEvent})`
1104
+ consumes only normalized
1105
+ [`AIRuntimeState`](#airuntimestatejs) `stt` role records. Its frozen controller
1106
+ exposes `action`, `error`, `label`, `pending`, `selected`, `status`, `title`, and
1107
+ `visible` getters plus `request(action)`, `synchronize(role)`, and `destroy()`.
1108
+ `host` supplies `dispatchEvent(event)` and `requestSTTActivation(intent)`;
1109
+ `button` supplies `addEventListener()` and `removeEventListener()`; and
1110
+ `onChange()` is called whenever presentation should be rendered again. Browser
1111
+ callers use the default `CustomEvent`; non-DOM callers must inject a compatible
1112
+ `EventClass` constructor.
800
1113
 
801
- Exact exports: `CHART_LABELS`, `DASHBOARD_LABELS`, `MARKDOWN_FORMATS`, `MARKDOWN_LABELS`, `VOICE_LABELS`, `VOICE_MESSAGES`, `appendTranscription`, `applyMarkdownFormat`, `effectiveDashboardVisibility`, `normalizeChartOptions`, `normalizeChartRows`, `normalizeDashboardDefinitions`, `normalizeDashboardOptions`, `normalizeDashboardVisibility`, `normalizeMarkdownFormats`, `normalizeMarkdownOptions`, `normalizeVoiceOptions`.
1114
+ `request('load'|'unload')` emits the cancelable
1115
+ `speech-stt-activation-request` event with frozen `{intent,state}` before it
1116
+ invokes `host.requestSTTActivation(intent)`. Callback failure emits
1117
+ `speech-stt-activation-error` with frozen `{request,error,message}`. Syncing
1118
+ sticky state only changes the controller's observation and presentation; it
1119
+ never emits a lifecycle intent, chooses a provider, or starts a download.
1120
+ `destroy()` removes its button listener and suppresses late callback effects.
1121
+
1122
+ Exact exports: `CHART_LABELS`, `DASHBOARD_LABELS`, `MARKDOWN_FORMATS`,
1123
+ `MARKDOWN_LABELS`, `STT_ACTIVATION_ERROR_CODES`,
1124
+ `STT_ACTIVATION_EVENT_TYPES`, `STT_ACTIVATION_REASONS`, `VOICE_LABELS`,
1125
+ `VOICE_MESSAGES`, `appendTranscription`, `applyMarkdownFormat`,
1126
+ `createSTTActivationController`, `effectiveDashboardVisibility`,
1127
+ `normalizeChartOptions`, `normalizeChartRows`, `normalizeDashboardDefinitions`,
1128
+ `normalizeDashboardOptions`, `normalizeDashboardVisibility`,
1129
+ `normalizeMarkdownFormats`, `normalizeMarkdownOptions`, and
1130
+ `normalizeVoiceOptions`.
802
1131
 
803
1132
  ### Availability and normalization
804
1133
 
805
- **Cross-host.** Fully normalized labels, rows, definitions, visibility, formats, editor and voice options. Transport: In-process only. [Deep protocol details](protocols.md).
1134
+ **Cross-host with an injected event constructor outside DOM hosts.** Fully
1135
+ normalized labels, rows, definitions, visibility, formats, editor and voice
1136
+ options, plus capability-neutral STT activation intent and presentation state.
1137
+ Provider authority and lifecycle execution remain with the configured runtime
1138
+ owner. Transport: In-process only. [Deep protocol details](protocols.md).
806
1139
 
807
1140
  ### Example
808
1141
 
@@ -937,7 +1270,15 @@ Owns conversation limits, control messages, submission barriers, elapsed formatt
937
1270
 
938
1271
  default `ConversationTimebox`, `ConversationSubmissionBarrier`, constants and control helpers.
939
1272
 
940
- Exact exports: `CONVERSATION_TIMEBOX_LIMIT_MESSAGE`, `CONVERSATION_TIMEBOX_OPENING_INSTRUCTION`, `CONVERSATION_TIMEBOX_TOOL_NAME`, `ConversationSubmissionBarrier`, `appendConversationTimeboxOpeningInstruction`, `consumeConversationTimeboxCall`, `conversationTimeboxSubmissionKey`, `conversationTimeboxTool`, `createConversationTimeboxControlMessage`, `default`, `formatConversationElapsed`, `normalizeConversationTimeboxCommand`, `requireConversationTimeboxDelivery`.
1273
+ Exact exports: `CONVERSATION_TIMEBOX_ERROR_CODES`,
1274
+ `CONVERSATION_TIMEBOX_EVENT_TYPES`, `CONVERSATION_TIMEBOX_LIMIT_MESSAGE`,
1275
+ `CONVERSATION_TIMEBOX_OPENING_INSTRUCTION`, `CONVERSATION_TIMEBOX_REASONS`,
1276
+ `CONVERSATION_TIMEBOX_TOOL_NAME`, `ConversationSubmissionBarrier`,
1277
+ `appendConversationTimeboxOpeningInstruction`, `consumeConversationTimeboxCall`,
1278
+ `conversationTimeboxSubmissionKey`, `conversationTimeboxTool`,
1279
+ `createConversationTimeboxControlMessage`, `default`,
1280
+ `formatConversationElapsed`, `normalizeConversationTimeboxCommand`, and
1281
+ `requireConversationTimeboxDelivery`.
941
1282
 
942
1283
  ### Availability and normalization
943
1284
 
@@ -1009,7 +1350,7 @@ Provides app-scoped localStorage tables, batch reads/writes, filtering, deletion
1009
1350
 
1010
1351
  default `DBLS`; installs `window.dbls`, emits `dbls-ready`; CRUD/batch/key APIs.
1011
1352
 
1012
- Exact exports: `default`.
1353
+ Exact exports: `DBLS_EVENT_TYPES`, `DBLS_REASONS`, `default`.
1013
1354
 
1014
1355
  ### Availability and normalization
1015
1356
 
@@ -1033,7 +1374,7 @@ Provides app-scoped OPFS tables, worker I/O, backup/restore, compression, and CR
1033
1374
 
1034
1375
  default `DBOPFS`; installs `window.dbopfs`, emits `dbopfs-ready`; table/file/backup APIs.
1035
1376
 
1036
- Exact exports: `default`.
1377
+ Exact exports: `DBOPFS_EVENT_TYPES`, `DBOPFS_REASONS`, `default`.
1037
1378
 
1038
1379
  ### Availability and normalization
1039
1380
 
@@ -1058,8 +1399,8 @@ or search; applications call `bootstrap()` deliberately.
1058
1399
 
1059
1400
  ### Public surface
1060
1401
 
1061
- Exact exports: default and named `DBOPFSDocumentLibrary`,
1062
- `createDBOPFSDocumentLibrary()`, and `normalizeDBOPFSDocumentSchema()`.
1402
+ Exact exports: `DBOPFSDocumentLibrary`, `createDBOPFSDocumentLibrary`,
1403
+ `default`, and `normalizeDBOPFSDocumentSchema`.
1063
1404
 
1064
1405
  `new DBOPFSDocumentLibrary({concurrency,db,maxCorpusCharacters,
1065
1406
  maxDocumentCharacters,maxSearchCharacters,schema})` exposes `schema`,
@@ -1083,7 +1424,7 @@ source body as implicit authority, and never persists a caller-owned body.
1083
1424
  **Browser or compatible host with an injected DBOPFS adapter.** The adapter
1084
1425
  keeps the existing `get`, `set`, `getAllKeys`, and `delete` method names; Node
1085
1426
  can use the same class only through an explicitly imported runtime module and a
1086
- compatible storage adapter; SDK `0.2.1` publishes no Node package subpath or
1427
+ compatible storage adapter; SDK `0.3.0` publishes no Node package subpath or
1087
1428
  Node storage implementation for it. Bootstrap uses a bounded concurrent
1088
1429
  generation, commits its manifest last, cleans partial data on failure, and
1089
1430
  rejects case-colliding IDs. Search
@@ -1216,11 +1557,10 @@ context excerpts for caller-owned document records.
1216
1557
 
1217
1558
  ### Public surface
1218
1559
 
1219
- Exact exports: `DOCUMENT_SEARCH_FIELD_ORDER`, default and named
1220
- `DocumentLexicalSearch`, `createDocumentLexicalIndex()`,
1221
- `documentContextExcerpt()`, `documentSearchTokens()`,
1222
- `normalizedDocumentSearchText()`, `scoreDocumentBody()`, and
1223
- `scoreDocumentLexicalIndex()`.
1560
+ Exact exports: `DOCUMENT_SEARCH_FIELD_ORDER`, `DocumentLexicalSearch`,
1561
+ `createDocumentLexicalIndex`, `default`, `documentContextExcerpt`,
1562
+ `documentSearchTokens`, `normalizedDocumentSearchText`, `scoreDocumentBody`,
1563
+ and `scoreDocumentLexicalIndex`.
1224
1564
 
1225
1565
  `new DocumentLexicalSearch(records,{maxResults=20})` exposes
1226
1566
  `rank(query,{kinds,tags})` and `search(query,{kinds,limit,tags})`.
@@ -1283,7 +1623,9 @@ Normalizes global errors/rejections, fingerprints and deduplicates incidents, pe
1283
1623
 
1284
1624
  default `Errors`; event normalizers/fingerprint plus lifecycle, capture, delivery and teardown methods.
1285
1625
 
1286
- Exact exports: `default`, `fingerprintIncident`, `normalizeErrorEvent`, `normalizeRejectionEvent`.
1626
+ Exact exports: `GLOBAL_ERROR_EVENT_CODES`, `GLOBAL_ERROR_EVENT_TYPES`,
1627
+ `GLOBAL_ERROR_REASONS`, `default`, `fingerprintIncident`,
1628
+ `normalizeErrorEvent`, and `normalizeRejectionEvent`.
1287
1629
 
1288
1630
  ### Availability and normalization
1289
1631
 
@@ -1427,7 +1769,10 @@ Coordinates local-AI status component checks, ensured recovery, availability pro
1427
1769
 
1428
1770
  `createLocalAIReadinessController()`, `availabilityFromReport()`.
1429
1771
 
1430
- Exact exports: `availabilityFromReport`, `createLocalAIReadinessController`.
1772
+ Exact exports: `LOCAL_AI_READINESS_CONTROLLER_ERROR_CODES`,
1773
+ `LOCAL_AI_READINESS_CONTROLLER_EVENT_TYPES`,
1774
+ `LOCAL_AI_READINESS_CONTROLLER_REASONS`, `availabilityFromReport`, and
1775
+ `createLocalAIReadinessController`.
1431
1776
 
1432
1777
  ### Availability and normalization
1433
1778
 
@@ -1473,6 +1818,115 @@ import * as module from '/arcane/modules/Mail.js';
1473
1818
  console.log(Object.keys(module));
1474
1819
  ```
1475
1820
 
1821
+ ## MailOutbox.mjs
1822
+
1823
+ ### Overview
1824
+
1825
+ Persists each bounded provider-neutral mail report before delivery and owns its
1826
+ idempotent enqueue, FIFO drain, retry-window, terminal-state, reconciliation,
1827
+ and explicit invalid-record maintenance lifecycle. It selects no mail provider,
1828
+ recipient, retention policy, retry timer, or transport fallback.
1829
+
1830
+ ### Public surface
1831
+
1832
+ Exact exports: `MAIL_OUTBOX_ACCEPTANCE_AUTHORITIES`,
1833
+ `MAIL_OUTBOX_IDEMPOTENCY_WINDOW_MS`, `MAIL_OUTBOX_PROTOCOL`,
1834
+ `MAIL_OUTBOX_STATES`, `MAIL_OUTBOX_TABLE`, `MailOutbox`, `createMailOutbox`, and
1835
+ `default`.
1836
+
1837
+ ```text
1838
+ new MailOutbox({
1839
+ storage,
1840
+ deliver,
1841
+ clock=Date.now,
1842
+ isOnline=()=>globalThis.navigator?.onLine!==false,
1843
+ lockManager=undefined,
1844
+ onlineTarget=typeof globalThis.addEventListener==='function'?globalThis:null,
1845
+ onRecordCommitted=null,
1846
+ maxAttemptsPerDrain=16,
1847
+ maxInvalidRecords=128,
1848
+ maxRecords=512,
1849
+ maxReportBytes=786432,
1850
+ quarantineTable='mail_outbox_quarantine',
1851
+ table=MAIL_OUTBOX_TABLE
1852
+ }={})
1853
+ ```
1854
+
1855
+ `storage` must expose `get()`, `set()`, and `getAllKeys()`; explicit deletion or
1856
+ quarantine additionally requires `delete()`. `lockManager` must expose the Web
1857
+ Locks-compatible `request()` contract. The injected
1858
+ `deliver({report,reportKey,serializedReport,signal})` callback receives the
1859
+ frozen parsed report, its stable idempotency key, the exact stored JSON string,
1860
+ and the caller-owned signal. Omitted `lockManager` resolves first from storage
1861
+ and then from `navigator.locks`. A delivery result must identify a valid
1862
+ `requestId` and one of `accepted`, `delivery_uncertain`,
1863
+ `temporarily_rejected`, `permanently_rejected`, or `partially_accepted`;
1864
+ accepted results additionally require a provider ID or the admitted
1865
+ `arcane-core-mail-send-v1` acceptance authority.
1866
+
1867
+ Read-only getters are `started`, `invalidRecords`, and `lastBackgroundError`.
1868
+ Methods are `get(key)`, `list()`, `audit()`, `deleteInvalid(fileName)`,
1869
+ `repairInvalid(fileName,replacement)`,
1870
+ `quarantineInvalid({limit=64}={})`,
1871
+ `enqueue({report,reportKey}={}, {attempt=true,signal=null}={})`,
1872
+ `drain({reason='manual',signal=null}={})`, `start({signal=null}={})`, and
1873
+ `stop()`. `createMailOutbox(options)` returns `new MailOutbox(options)`.
1874
+
1875
+ Every returned durable record is deeply frozen and contains exactly
1876
+ `{protocol,reportKey,serializedReport,state,createdAt,updatedAt,firstAttemptAt,
1877
+ lastAttemptAt,nextAttemptAt,attempts,result,failure}`. Protocol is
1878
+ `arcane-mail-outbox/1`; the default table is `mail_outbox`; the idempotency
1879
+ window is 86,400,000 milliseconds. States are exactly `queued`, `sending`,
1880
+ `retry_wait`, `accepted`, `failed`, and `reconciliation_required`. Accepted
1881
+ means provider or admitted Core acceptance, not inbox delivery.
1882
+
1883
+ `enqueue()` serializes same-instance persistence and binds one report key to one
1884
+ exact serialized body. `drain()` runs or joins one bounded instance drain under
1885
+ an exclusive shared lock and attempts at most 16 records by default. Startup,
1886
+ an owned `online` listener, or an explicit call may trigger work; there is no
1887
+ polling or retry timer. Abort before the delivery call prevents that call, and a
1888
+ caller joining an existing drain may stop waiting without cancelling the shared
1889
+ drain. Once an accepted result is committed, it outranks a racing cancellation;
1890
+ cancellation never claims an admitted provider attempt stopped. An interrupted
1891
+ or ambiguous attempt remains a same-key retry inside the 24-hour window and
1892
+ becomes `reconciliation_required` when automatic retry would risk a duplicate.
1893
+ `stop()` aborts only the owned online drain, removes its listener, preserves
1894
+ durable records, and returns the instance.
1895
+
1896
+ `audit()` reports valid records plus bounded invalid-file metadata. Repair,
1897
+ deletion, and quarantine are explicit, revalidate the selected file under the
1898
+ table lock, and never infer destructive authority from a storage read failure.
1899
+ `onRecordCommitted(record)` is an observational callback after each durable
1900
+ write; callback failure cannot change the committed operation result.
1901
+
1902
+ ### Availability and normalization
1903
+
1904
+ **Browser/native WebView or compatible injected host.** The default application
1905
+ integration uses DBOPFS-compatible durable storage and `navigator.locks`; an
1906
+ alternate adapter owns its own durability claim and must provide equivalent
1907
+ storage and shared-lock semantics. Frozen records, bounds, state transitions,
1908
+ retry/reconciliation classification, invalid-record maintenance, and
1909
+ AbortSignal admission/join cancellation are normalized. Storage, lock,
1910
+ online-check, and injected-delivery failures remain visible through concrete
1911
+ `MAIL_OUTBOX_*` codes. Transport: injected durable storage, Web Locks,
1912
+ AbortSignal, optional online EventTarget, and an injected delivery callback.
1913
+ [Deep protocol details](mail.md#durable-send-semantics).
1914
+
1915
+ ### Example
1916
+
1917
+ ```javascript
1918
+ import {createMailOutbox} from '/arcane/modules/MailOutbox.mjs';
1919
+
1920
+ const outbox = createMailOutbox({storage, deliver});
1921
+ await outbox.start({signal});
1922
+ const record = await outbox.enqueue(
1923
+ {report, reportKey: 'report-20260827-001'},
1924
+ {attempt: true, signal}
1925
+ );
1926
+ console.log(record.state);
1927
+ outbox.stop();
1928
+ ```
1929
+
1476
1930
  ## MailTransport.mjs
1477
1931
 
1478
1932
  ### Overview
@@ -1481,9 +1935,12 @@ Sends one bounded mail report to a normalized HTTP(S) endpoint with timeout and
1481
1935
 
1482
1936
  ### Public surface
1483
1937
 
1484
- Timeout/size constants, `normalizeMailEndpoint()`, `sendMailReport()`.
1938
+ Timeout/size constants, `MailTransportError`, `normalizeMailEndpoint()`,
1939
+ `serializeMailReport()`, and `sendMailReport()`.
1485
1940
 
1486
- Exact exports: `DEFAULT_MAIL_REQUEST_TIMEOUT_MS`, `MAX_MAIL_RESPONSE_BYTES`, `normalizeMailEndpoint`, `sendMailReport`.
1941
+ Exact exports: `DEFAULT_MAIL_REQUEST_TIMEOUT_MS`, `MAX_MAIL_RESPONSE_BYTES`,
1942
+ `MailTransportError`, `normalizeMailEndpoint`, `serializeMailReport`,
1943
+ `sendMailReport`.
1487
1944
 
1488
1945
  ### Availability and normalization
1489
1946
 
@@ -1627,7 +2084,8 @@ Provides the first-class Arcane Ollama client without direct access to localhost
1627
2084
 
1628
2085
  `Ollama`, singleton/default `ollama`; 24 methods; installs `globalThis.arcaneOllama`, emits `arcane-ollama-ready`.
1629
2086
 
1630
- Exact exports: `Ollama`, `default`, `ollama`.
2087
+ Exact exports: `OLLAMA_EVENT_TYPES`, `OLLAMA_REASONS`, `Ollama`, `default`,
2088
+ and `ollama`.
1631
2089
 
1632
2090
  ### Availability and normalization
1633
2091
 
@@ -1699,7 +2157,8 @@ Searches and loads Open-Meteo data into frozen Arcane weather entities.
1699
2157
 
1700
2158
  Endpoint constants, default provider, `mapForecast()`; search/load methods and lifecycle events.
1701
2159
 
1702
- Exact exports: `OPEN_METEO_ENDPOINTS`, `default`, `mapForecast`.
2160
+ Exact exports: `OPEN_METEO_ENDPOINTS`, `OPEN_METEO_WEATHER_ERRORS`,
2161
+ `OPEN_METEO_WEATHER_EVENTS`, `default`, and `mapForecast`.
1703
2162
 
1704
2163
  ### Availability and normalization
1705
2164
 
@@ -1724,8 +2183,8 @@ semantics; it does not define a new storage protocol.
1724
2183
 
1725
2184
  ### Public surface
1726
2185
 
1727
- Exact exports: default and named `PersistentAIChatSession` plus
1728
- `createPersistentAIChatSession()`.
2186
+ Exact exports: `PersistentAIChatSession`, `createPersistentAIChatSession`, and
2187
+ `default`.
1729
2188
 
1730
2189
  Constructor and factory options are `{chat,chatEntity,chatFileName,
1731
2190
  contextBuilder,loadExisting,maxContextCharacters,maxMessageCharacters,
@@ -1781,7 +2240,9 @@ Loads and updates schema-defined app preferences through native storage with a n
1781
2240
 
1782
2241
  default `PreferenceStore`, re-exported `Preference`/schema; load/set/reset APIs and events.
1783
2242
 
1784
- Exact exports: `Preference`, `default`, `preferenceSchema`.
2243
+ Exact exports: `PREFERENCE_STORE_ERROR_CODES`,
2244
+ `PREFERENCE_STORE_EVENT_TYPES`, `Preference`, `default`, and
2245
+ `preferenceSchema`.
1785
2246
 
1786
2247
  ### Availability and normalization
1787
2248
 
@@ -1899,7 +2360,9 @@ Stores normalized record-review decisions through native storage or app-scoped l
1899
2360
 
1900
2361
  default store, record/review normalizers; `load()`, `get()`, `set()`, `snapshot()`, change event.
1901
2362
 
1902
- Exact exports: `default`, `normalizeRecordId`, `normalizeReview`.
2363
+ Exact exports: `RECORD_REVIEW_STORE_ERROR_CODES`,
2364
+ `RECORD_REVIEW_STORE_EVENT_TYPES`, `default`, `normalizeRecordId`, and
2365
+ `normalizeReview`.
1903
2366
 
1904
2367
  ### Availability and normalization
1905
2368
 
@@ -2019,7 +2482,9 @@ Captures a display surface as image, video, or GIF with explicit lifecycle event
2019
2482
 
2020
2483
  default `ScreenCapture`; acquire/capture/start/stop/reset methods.
2021
2484
 
2022
- Exact exports: `default`.
2485
+ Exact exports: `SCREEN_CAPTURE_ERROR_CODES`, `SCREEN_CAPTURE_ERRORS`,
2486
+ `SCREEN_CAPTURE_EVENT_TYPES`, `SCREEN_CAPTURE_IMAGE_TYPE_FALLBACK`,
2487
+ `SCREEN_CAPTURE_REASONS`, `SCREEN_CAPTURE_STATUSES`, and `default`.
2023
2488
 
2024
2489
  ### Availability and normalization
2025
2490
 
@@ -2041,13 +2506,75 @@ Segments bounded text, queues latest-request speech synthesis, and controls look
2041
2506
 
2042
2507
  ### Public surface
2043
2508
 
2044
- SpeechPlayback class/default, voice/limit constants, `splitSpeechText()`, playback lifecycle APIs.
2509
+ `SpeechPlayback` class/default, voice/limit compatibility constants,
2510
+ `SPEECH_PLAYBACK_STATE_EVENT`, `splitSpeechText()`, and playback lifecycle APIs.
2045
2511
 
2046
- Exact exports: `MAX_SPEECH_CHARACTERS`, `MAX_SPEECH_CHUNKS`, `MAX_SPEECH_INPUT`, `PREFERRED_STREAM_SEGMENT`, `SPEECH_VOICE_ALIASES`, `SPEECH_VOICE_OPTIONS`, `SpeechPlayback`, `default`, `splitSpeechText`.
2047
-
2048
- ### Availability and normalization
2512
+ Exact exports: `MAX_SPEECH_CHARACTERS`, `MAX_SPEECH_CHUNKS`,
2513
+ `MAX_SPEECH_INPUT`, `PREFERRED_STREAM_SEGMENT`, `SPEECH_PLAYBACK_STATE_EVENT`,
2514
+ `SPEECH_VOICE_ALIASES`, `SPEECH_VOICE_OPTIONS`, `SpeechPlayback`, `default`,
2515
+ and `splitSpeechText`.
2049
2516
 
2050
- **Browser + native bridge.** State/limits normalized; provider/media failures mixed. Transport: Arcane.speech.synthesize, Blob URLs, audio element. [Deep protocol details](protocols.md).
2517
+ ```text
2518
+ new SpeechPlayback({
2519
+ audio,
2520
+ speech=globalThis.Arcane?.speech,
2521
+ model=null,
2522
+ voice=null,
2523
+ responseFormat=null,
2524
+ speed=1,
2525
+ onState=()=>{},
2526
+ createObjectURL,
2527
+ revokeObjectURL,
2528
+ delay,
2529
+ messages={}
2530
+ })
2531
+ ```
2532
+
2533
+ `speech` must expose either `fetchTTS(payload, signal)` or
2534
+ `synthesize(payload, {signal})`. `prepare({key,parts,model,voice,responseFormat,
2535
+ speed,autoplay=true})` uses only caller-supplied model, voice, and response-format
2536
+ values; those three omitted values remain omitted so the selected AI/model
2537
+ catalog may admit its documented defaults. Speed defaults to `1`, is normalized
2538
+ as a positive number, and is always sent. The legacy voice constants remain
2539
+ exported for compatibility but are not selected by the class. There is no
2540
+ hard-coded model, response format, voice, or cloud/browser fallback.
2541
+
2542
+ Every preparation owns an operation ID and one AbortController for each active
2543
+ synthesis segment or playback delay. Replacement,
2544
+ `stop()`, `cancel()`, and `destroy()` abort their owned signals, suppress stale
2545
+ settlement, release Blob URLs, and publish synchronous
2546
+ `speech-playback-state` occurrences through `globalThis.arcaneEvents` before
2547
+ calling the compatibility `onState(frozenDetail)` callback. The detail contains
2548
+ `state`, `message`, `key`, `index`, `total`, `producing`, `buffered`, `hasAudio`,
2549
+ `operationId`, `code`, and `reason`; the canonical public occurrence omits
2550
+ provider response/error bodies. `destroy()` also removes every audio listener
2551
+ and disposes its per-instance canonical source handle; repeated destroy returns
2552
+ `false`. Signal abortion proves delivery suppression; whether provider work
2553
+ actually stops remains the selected provider's cancellation boundary.
2554
+
2555
+ Stable error codes are `ARCANE_SPEECH_PLAYBACK_DESTROYED`,
2556
+ `ARCANE_SPEECH_PLAYBACK_OPERATION_SEQUENCE_EXHAUSTED`,
2557
+ `ARCANE_SPEECH_PLAYBACK_SYNTHESIZER_UNAVAILABLE`,
2558
+ `ARCANE_SPEECH_PLAYBACK_SYNTHESIZED_AUDIO_CONTRACT_MISMATCH`,
2559
+ `ARCANE_SPEECH_PLAYBACK_AUDIO_PLAYBACK_REJECTED`,
2560
+ `ARCANE_SPEECH_PLAYBACK_REQUEST_CONTRACT_MISMATCH`, and
2561
+ `ARCANE_SPEECH_PLAYBACK_SYNTHESIS_REQUEST_REJECTED`, plus propagated
2562
+ `ARCANE_AI_OPERATION_SUPERSEDED` and `ARCANE_AI_REQUEST_ABORTED`.
2563
+ Exact lifecycle reasons are `playback-replaced`, `playback-stopped`,
2564
+ `playback-destroyed`, `speech-playback-cancelled`,
2565
+ `speech-synthesis-superseded`, `speech-synthesis-cancelled`,
2566
+ `speech-synthesizer-unavailable`, `synthesized-audio-contract-mismatch`,
2567
+ `audio-playback-rejected`, `audio-autoplay-rejected`,
2568
+ `speech-playback-request-contract-mismatch`, and
2569
+ `speech-synthesis-rejected`, as applicable to the emitted state.
2570
+
2571
+ ### Availability and normalization
2572
+
2573
+ **Browser + admitted AI/native bridge.** State, cancellation, lifecycle, and
2574
+ playable Blob normalization are shared. Provider/model/runtime/voice admission
2575
+ remains caller- and catalog-owned. Transport: `AI.fetchTTS`, compatible
2576
+ `Arcane.speech.synthesize`, Blob URLs, audio element, and the singleton event
2577
+ authority. [Deep protocol details](protocols.md).
2051
2578
 
2052
2579
  ### Example
2053
2580
 
@@ -2056,7 +2583,13 @@ import SpeechPlayback from '/arcane/modules/SpeechPlayback.js';
2056
2583
 
2057
2584
  const audio = document.body.appendChild(document.createElement('audio'));
2058
2585
  audio.controls = true;
2059
- const speech = new SpeechPlayback({audio});
2586
+ const speech = new SpeechPlayback({
2587
+ audio,
2588
+ speech: globalThis.ai,
2589
+ model: 'caller-selected-model',
2590
+ voice: 'caller-selected-voice',
2591
+ responseFormat: 'wav'
2592
+ });
2060
2593
  const speakButton = document.body.appendChild(document.createElement('button'));
2061
2594
  speakButton.type = 'button';
2062
2595
  speakButton.textContent = 'Speak';
@@ -2173,7 +2706,8 @@ Maps native terminal sessions and Arcane events into an EventTarget client.
2173
2706
 
2174
2707
  default `TerminalClient`; start/write/resize/signal/close/receive/destroy APIs and terminal events.
2175
2708
 
2176
- Exact exports: `default`.
2709
+ Exact exports: `TERMINAL_CLIENT_ERROR_CODES`, `TERMINAL_CLIENT_EVENT_TYPES`,
2710
+ `TERMINAL_CLIENT_REASONS`, and `default`.
2177
2711
 
2178
2712
  ### Availability and normalization
2179
2713
 
@@ -2221,7 +2755,8 @@ Performs import-time Arcane theme loading and subscribes to native appearance ch
2221
2755
 
2222
2756
  `bootstrapArcaneTheme()`, `arcaneThemeReady`, default ready promise.
2223
2757
 
2224
- Exact exports: `arcaneThemeReady`, `bootstrapArcaneTheme`, `default`.
2758
+ Exact exports: `arcaneThemeReady`, `bootstrapArcaneTheme`, `default`, and
2759
+ `disposeArcaneThemeBootstrap`.
2225
2760
 
2226
2761
  ### Availability and normalization
2227
2762
 
@@ -2379,7 +2914,8 @@ Waits for a component property, method, or readiness event with optional error e
2379
2914
 
2380
2915
  default `waitForComponent()`.
2381
2916
 
2382
- Exact exports: `default`.
2917
+ Exact exports: `COMPONENT_WAIT_ERROR_CODES`, `COMPONENT_WAIT_REASONS`, and
2918
+ `default`.
2383
2919
 
2384
2920
  ### Availability and normalization
2385
2921