arcane-os 0.5.16 → 0.5.18

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 (190) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +42 -19
  3. package/bin/arcane-test.mjs +16 -13
  4. package/browser-runtime/ai/browser-speech-artifacts.mjs +41 -38
  5. package/browser-runtime/ai/browser-speech-providers.mjs +53 -46
  6. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +127 -124
  7. package/browser-runtime/ai/browser-wasm.mjs +6 -3
  8. package/browser-runtime/ai/browser-wllama-runtime.mjs +26 -23
  9. package/browser-runtime/ai/model-controller.mjs +94 -91
  10. package/browser-runtime/ai/speech-worker-client.mjs +12 -9
  11. package/browser-runtime/ai/speech-worker-runtime.mjs +56 -53
  12. package/browser-runtime/dependencies/strong-type/index.js +207 -82
  13. package/browser-runtime/dependencies/strong-type/package.json +15 -6
  14. package/browser-runtime/dom-event-instrumentation.mjs +24 -20
  15. package/browser-runtime/event-manager.mjs +111 -108
  16. package/browser-runtime/speech-text.mjs +35 -0
  17. package/docs/architecture.md +1 -1
  18. package/docs/reference/README.md +8 -8
  19. package/docs/reference/ai/browser-speech.md +230 -16
  20. package/docs/reference/ai/twin-cloud.md +1 -1
  21. package/docs/reference/availability-and-normalization.md +42 -1
  22. package/docs/reference/cli.md +1 -1
  23. package/docs/reference/core/arcane-ai-contracts.md +1 -1
  24. package/docs/reference/inventory/package-api.json +60 -4
  25. package/docs/reference/inventory/runtime-components.json +2 -2
  26. package/docs/reference/inventory/runtime-modules.json +29 -31
  27. package/docs/reference/protocols.md +17 -13
  28. package/docs/reference/runtime-components.md +6 -5
  29. package/docs/reference/runtime-modules.md +212 -70
  30. package/docs/reference/sdk-api.md +197 -11
  31. package/examples/wasm-ai-demo/index.html +1 -0
  32. package/node_modules/event-pubsub/node_modules/strong-type/README.md +408 -0
  33. package/node_modules/event-pubsub/node_modules/strong-type/assets/strong-type-header.png +0 -0
  34. package/node_modules/event-pubsub/node_modules/strong-type/index.js +1151 -0
  35. package/node_modules/event-pubsub/node_modules/strong-type/licence +21 -0
  36. package/node_modules/event-pubsub/node_modules/strong-type/node.js +125 -0
  37. package/node_modules/event-pubsub/node_modules/strong-type/package.json +61 -0
  38. package/node_modules/strong-type/README.md +42 -24
  39. package/node_modules/strong-type/benchmark/core.js +324 -0
  40. package/node_modules/strong-type/index.js +207 -82
  41. package/node_modules/strong-type/package.json +14 -6
  42. package/package.json +4 -3
  43. package/runtime/arcane/components/app-bar.html +5 -2
  44. package/runtime/arcane/components/assistant-panel.html +5 -2
  45. package/runtime/arcane/components/chart.html +15 -12
  46. package/runtime/arcane/components/chat.html +118 -141
  47. package/runtime/arcane/components/dashboard-config.html +6 -3
  48. package/runtime/arcane/components/data-view.html +4 -1
  49. package/runtime/arcane/components/directory-picker.html +5 -2
  50. package/runtime/arcane/components/document-inspector.html +6 -3
  51. package/runtime/arcane/components/file-drop.html +5 -2
  52. package/runtime/arcane/components/file-inspector.html +9 -6
  53. package/runtime/arcane/components/file-manager.html +16 -13
  54. package/runtime/arcane/components/local-ai-status.html +5 -2
  55. package/runtime/arcane/components/markdown-document.html +14 -11
  56. package/runtime/arcane/components/markdown-editor.html +4 -1
  57. package/runtime/arcane/components/modal.html +4 -1
  58. package/runtime/arcane/components/output-panel.html +6 -3
  59. package/runtime/arcane/components/preferences-form.html +4 -1
  60. package/runtime/arcane/components/record-timeline.html +8 -5
  61. package/runtime/arcane/components/relationship-board.html +9 -6
  62. package/runtime/arcane/components/source-code-viewer.html +12 -9
  63. package/runtime/arcane/components/source-explanation.html +8 -5
  64. package/runtime/arcane/components/speech.html +24 -21
  65. package/runtime/arcane/components/summary-strip.html +4 -1
  66. package/runtime/arcane/components/task-progress.html +6 -3
  67. package/runtime/arcane/components/terminal-workspace.html +4 -1
  68. package/runtime/arcane/components/voice-transcription.html +11 -8
  69. package/runtime/arcane/components/web-navigator.html +5 -2
  70. package/runtime/arcane/entities/ApiModelRecord.js +5 -2
  71. package/runtime/arcane/entities/Calculation.js +5 -2
  72. package/runtime/arcane/entities/Chat.js +33 -33
  73. package/runtime/arcane/entities/CommunicationMessage.js +4 -1
  74. package/runtime/arcane/entities/CommunicationThread.js +4 -1
  75. package/runtime/arcane/entities/File.js +1 -1
  76. package/runtime/arcane/entities/Image.js +8 -5
  77. package/runtime/arcane/entities/IntentEnvelope.js +20 -17
  78. package/runtime/arcane/entities/Preference.js +9 -6
  79. package/runtime/arcane/entities/Theme.js +5 -2
  80. package/runtime/arcane/entities/User.js +11 -11
  81. package/runtime/arcane/entities/Weather.js +5 -2
  82. package/runtime/arcane/modules/AI.js +503 -187
  83. package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
  84. package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
  85. package/runtime/arcane/modules/AIProviderRuntime.js +117 -92
  86. package/runtime/arcane/modules/AIResponseURLPolicy.js +148 -62
  87. package/runtime/arcane/modules/AIRuntimeState.js +29 -26
  88. package/runtime/arcane/modules/AnsiText.js +4 -1
  89. package/runtime/arcane/modules/ApiModelDatabase.js +22 -19
  90. package/runtime/arcane/modules/AppDataScope.js +8 -5
  91. package/runtime/arcane/modules/ArcaneCommunicationBridge.js +4 -1
  92. package/runtime/arcane/modules/ArcaneNavigationPolicy.js +8 -5
  93. package/runtime/arcane/modules/ArcaneNetworkPolicy.js +18 -15
  94. package/runtime/arcane/modules/AsyncBoundary.js +13 -10
  95. package/runtime/arcane/modules/BrowserTestSuite.js +19 -16
  96. package/runtime/arcane/modules/CalculatorEngine.js +5 -2
  97. package/runtime/arcane/modules/ChatRecords.js +18 -15
  98. package/runtime/arcane/modules/CommunicationAppController.js +9 -6
  99. package/runtime/arcane/modules/CommunicationHub.js +9 -6
  100. package/runtime/arcane/modules/CommunicationPreferences.js +4 -1
  101. package/runtime/arcane/modules/CommunicationProviderRegistry.js +4 -1
  102. package/runtime/arcane/modules/ComponentContracts.js +56 -53
  103. package/runtime/arcane/modules/ConfiguredAIChatSession.js +30 -27
  104. package/runtime/arcane/modules/ConversationActionItems.js +15 -12
  105. package/runtime/arcane/modules/ConversationClosingReport.js +11 -8
  106. package/runtime/arcane/modules/ConversationTimebox.js +28 -25
  107. package/runtime/arcane/modules/CoreLocalModelCatalog.js +17 -14
  108. package/runtime/arcane/modules/DBLS.js +7 -4
  109. package/runtime/arcane/modules/DBOPFS.js +7 -7
  110. package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +34 -31
  111. package/runtime/arcane/modules/DevelopmentWorkspace.js +4 -1
  112. package/runtime/arcane/modules/DirectoryPicker.js +8 -5
  113. package/runtime/arcane/modules/DocumentLexicalSearch.js +11 -8
  114. package/runtime/arcane/modules/DocumentNavigation.js +7 -4
  115. package/runtime/arcane/modules/Errors.js +28 -25
  116. package/runtime/arcane/modules/HTMLImport.js +7 -4
  117. package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +15 -12
  118. package/runtime/arcane/modules/LocalAIReadiness.js +21 -18
  119. package/runtime/arcane/modules/LocalAIReadinessController.js +6 -3
  120. package/runtime/arcane/modules/MD.js +1 -1
  121. package/runtime/arcane/modules/Mail.js +46 -43
  122. package/runtime/arcane/modules/MailOutbox.mjs +48 -45
  123. package/runtime/arcane/modules/MailTransport.mjs +29 -26
  124. package/runtime/arcane/modules/MarkdownSpeech.js +1 -50
  125. package/runtime/arcane/modules/MemoryRecords.js +7 -4
  126. package/runtime/arcane/modules/MessageAdvisory.js +6 -3
  127. package/runtime/arcane/modules/ModelDefinition.js +7 -4
  128. package/runtime/arcane/modules/Ollama.js +6 -3
  129. package/runtime/arcane/modules/OllamaModelIdentifier.js +4 -1
  130. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +18 -15
  131. package/runtime/arcane/modules/PersistentAIChatSession.js +33 -30
  132. package/runtime/arcane/modules/PreferenceStore.js +20 -17
  133. package/runtime/arcane/modules/PreparedSpeech.js +485 -0
  134. package/runtime/arcane/modules/Questionnaire.js +6 -3
  135. package/runtime/arcane/modules/RecordLinkIndex.js +4 -1
  136. package/runtime/arcane/modules/RecordPassageIndex.js +9 -6
  137. package/runtime/arcane/modules/RecordReviewStore.js +12 -9
  138. package/runtime/arcane/modules/RiskSignalAnalyzer.js +4 -1
  139. package/runtime/arcane/modules/ScopedOPFSCache.js +6 -3
  140. package/runtime/arcane/modules/ScreenCapture.js +20 -17
  141. package/runtime/arcane/modules/SpeechPlayback.js +61 -28
  142. package/runtime/arcane/modules/StaticDocumentCatalog.js +33 -30
  143. package/runtime/arcane/modules/SystemAppearance.js +5 -2
  144. package/runtime/arcane/modules/SystemToolRegistry.js +6 -3
  145. package/runtime/arcane/modules/TerminalClient.js +14 -11
  146. package/runtime/arcane/modules/TerminalCommandRegistry.js +4 -1
  147. package/runtime/arcane/modules/ThemeBootstrap.js +9 -6
  148. package/runtime/arcane/modules/ThemeManager.js +5 -2
  149. package/runtime/arcane/modules/TimeGuard.js +1 -1
  150. package/runtime/arcane/modules/ToolCallRouter.js +11 -8
  151. package/runtime/arcane/modules/WaitForComponent.js +19 -16
  152. package/runtime/arcane/modules/YouTubeMedia.js +4 -1
  153. package/runtime/strong-type/index.js +1276 -352
  154. package/runtime/strong-type/package.json +69 -45
  155. package/src/app-descriptor.mjs +17 -14
  156. package/src/application-tests.mjs +4 -1
  157. package/src/cli/main.mjs +8 -5
  158. package/src/constants.mjs +4 -1
  159. package/src/dev-server.mjs +8 -5
  160. package/src/doctor.mjs +5 -2
  161. package/src/dom-event-instrumentation.mjs +24 -20
  162. package/src/errors.mjs +7 -3
  163. package/src/event-manager.mjs +111 -108
  164. package/src/event-queue.mjs +8 -5
  165. package/src/events.mjs +12 -9
  166. package/src/import-map.mjs +36 -27
  167. package/src/installed-sdk-runtime.mjs +4 -1
  168. package/src/integrated-provider-loader.mjs +9 -6
  169. package/src/mail-credentials.mjs +16 -13
  170. package/src/mail-server.mjs +53 -50
  171. package/src/mail.mjs +18 -15
  172. package/src/native-plan.mjs +12 -9
  173. package/src/native-provider-loader.mjs +7 -4
  174. package/src/packager/core.mjs +18 -15
  175. package/src/process.mjs +6 -3
  176. package/src/release-bundle.mjs +14 -11
  177. package/src/runtime.mjs +4 -1
  178. package/src/scaffold.mjs +9 -6
  179. package/src/sdk-browser-runtime.mjs +4 -1
  180. package/src/source-server.mjs +17 -14
  181. package/src/targets/index.mjs +5 -2
  182. package/src/templates/workspace-template.mjs +13 -6
  183. package/src/testing-loader.mjs +7 -4
  184. package/src/testing.mjs +10 -7
  185. package/src/toolchain.mjs +13 -10
  186. package/src/update-check.mjs +9 -6
  187. package/src/workspace-operation-lock.mjs +14 -11
  188. package/src/workspace-runtime.mjs +4 -1
  189. package/src/workspace.mjs +17 -14
  190. package/runtime/arcane/modules/AIResponseLength.js +0 -32
@@ -0,0 +1,35 @@
1
+ import Is from './dependencies/strong-type/index.js';
2
+
3
+ const is=new Is(false);
4
+
5
+ function stripSpeechFormatting(text=''){
6
+ return text.replace(/([*#_`~])\1+/g,'');
7
+ }
8
+
9
+ // Speech-only filtering; single markers and all other text remain literal.
10
+ class MarkdownSpeech {
11
+ #pending='';
12
+
13
+ append(text='',end=false){
14
+ if(!is.string(text)){
15
+ throw new TypeError('Markdown speech input must be text.');
16
+ }
17
+
18
+ const source=this.#pending+text;
19
+ const trailing=end?null:/([*#_`~])\1*$/u.exec(source);
20
+ // Two copies retain the fact that a run repeats without retaining it all.
21
+ this.#pending=trailing
22
+ ?trailing[1].repeat(trailing[0].length===1?1:2)
23
+ :'';
24
+
25
+ return stripSpeechFormatting(
26
+ trailing?source.slice(0,trailing.index):source
27
+ );
28
+ }
29
+
30
+ reset(){
31
+ this.#pending='';
32
+ }
33
+ }
34
+
35
+ export {MarkdownSpeech,stripSpeechFormatting};
@@ -279,7 +279,7 @@ paths are withheld from the native provider. The provider copies the complete
279
279
  selected release rather than accepting an unrelated source path. Verification
280
280
  is a separate explicit operation for a selected release artifact.
281
281
 
282
- The SDK `0.5.16` runtime requires Arcane `0.8.12` or newer. Compatibility
282
+ The SDK `0.5.17` runtime requires Arcane `0.8.12` or newer. Compatibility
283
283
  is contractual rather than exact-version pinning: the prepared Core must meet
284
284
  the highest minimum declared by the runtime, selected app, and bundled app
285
285
  dependencies; keep each app's Arcane protocol generation; and provide every
@@ -17,7 +17,7 @@ high-level page links to the relevant deep section instead of repeating it.
17
17
  Install the SDK in your application:
18
18
 
19
19
  ```sh
20
- npm install --save-exact arcane-os@0.5.16
20
+ npm install --save-exact arcane-os@0.5.17
21
21
  ```
22
22
 
23
23
  For your first AI call, follow the [TWiN Cloud quick start](ai/twin-cloud.md).
@@ -58,9 +58,9 @@ This repository contains explicitly versioned surfaces with different owners:
58
58
 
59
59
  | Surface | Source identity | Meaning |
60
60
  | --- | --- | --- |
61
- | SDK and CLI | `arcane-os` `0.5.16` | The Node.js toolchain, portable `arcane-os/event-manager`, `arcane-os/logging`, `arcane-os/mail`, `arcane-os/preference-store`, and `arcane-os/speech-playback` entrypoints, plus the browser-only `arcane-os/ai/browser-wasm` and `arcane-os/ai/browser-speech` entrypoints in this checkout. |
62
- | Browser runtime | SDK `0.5.16`, protocol `arcane/1`, `runtime/` | The SDK-canonical runtime tree. `listRuntimeFiles()`, `readRuntimeFile()`, and `loadRuntimeRelease()` derive its current inventory directly from the selected directory. |
63
- | Browser SDK runtime | SDK `0.5.16`, `browser-runtime/` | The browser closure for events, shared logging, Wllama, and Browser Speech mechanisms. `listSdkBrowserRuntimeFiles()`, `readSdkBrowserRuntimeFile()`, and `loadSdkBrowserRuntimeRelease()` derive its current inventory directly from the selected directory. |
61
+ | SDK and CLI | `arcane-os` `0.5.17` | The Node.js toolchain, portable `arcane-os/event-manager`, `arcane-os/logging`, `arcane-os/mail`, `arcane-os/preference-store`, `arcane-os/speech-playback`, and `arcane-os/speech-text` entrypoints, plus the browser-only `arcane-os/ai/browser-wasm` and `arcane-os/ai/browser-speech` entrypoints in this checkout. |
62
+ | Browser runtime | SDK `0.5.17`, protocol `arcane/1`, `runtime/` | The SDK-canonical runtime tree. `listRuntimeFiles()`, `readRuntimeFile()`, and `loadRuntimeRelease()` derive its current inventory directly from the selected directory. |
63
+ | Browser SDK runtime | SDK `0.5.17`, `browser-runtime/` | The browser closure for events, shared logging, speech-text cleanup, Wllama, and Browser Speech mechanisms. `listSdkBrowserRuntimeFiles()`, `readSdkBrowserRuntimeFile()`, and `loadSdkBrowserRuntimeRelease()` derive its current inventory directly from the selected directory. |
64
64
  | Core reference snapshot | Arcane OS commit `567ad110bf57a1c2d4a3daa22ae93716cc5f4d7e`, protocol `arcane/1` | The application-facing Core contract imported into `docs/reference/core/`, with SDK-local links and package-boundary notes added explicitly. |
65
65
 
66
66
  The SDK runtime source and Core reference have different owners. A browser
@@ -75,7 +75,7 @@ and the distinction between a documentation snapshot and the selected runtime.
75
75
 
76
76
  ## Installed documentation and release identity
77
77
 
78
- This reference accompanies `arcane-os@0.5.16`. The installed package includes
78
+ This reference accompanies `arcane-os@0.5.17`. The installed package includes
79
79
  the maintained `docs/` tree and `examples/wasm-ai-demo/` source alongside
80
80
  README and CHANGELOG. Open `node_modules/arcane-os/docs/reference/README.md`
81
81
  for the matching local reference. The generated website and test suites remain
@@ -124,11 +124,11 @@ Public reference entries follow the established Arcane documentation model:
124
124
 
125
125
  ## Public runtime inventory
126
126
 
127
- The package exposes 198 semantic JavaScript records across 17 JavaScript
127
+ The package exposes 202 semantic JavaScript records across 18 JavaScript
128
128
  entrypoints, plus eight JSON Schemas and package metadata. Ten entrypoints are
129
129
  Node.js control-plane surfaces,
130
130
  `arcane-os/event-manager`, `arcane-os/logging`, `arcane-os/mail`, `arcane-os/preference-store`, and
131
- `arcane-os/speech-playback` run in Node and browsers, and
131
+ `arcane-os/speech-playback` plus `arcane-os/speech-text` run in Node and browsers, and
132
132
  `arcane-os/ai/browser-wasm` plus `arcane-os/ai/browser-speech` are browser-only.
133
133
  The [machine-readable package
134
134
  inventory](inventory/package-api.json) and [SDK member reference](sdk-api.md)
@@ -139,7 +139,7 @@ download, install, or self-update.
139
139
 
140
140
  The synchronized browser payload exposes:
141
141
 
142
- - 82 JavaScript module artifacts under `runtime/arcane/modules/`, including
142
+ - 83 JavaScript module artifacts under `runtime/arcane/modules/`, including
143
143
  ESM modules, classic vendor globals, one worker protocol, and one Node-oriented
144
144
  mail transport;
145
145
  - 14 shared entity modules under `runtime/arcane/entities/`;
@@ -13,7 +13,7 @@ import map resolves `arcane/AI` and `arcane/DBOPFS`. These browser modules are
13
13
  not Node inference APIs. To create an application:
14
14
 
15
15
  ```bash
16
- npx arcane-os@0.5.16 new hello-speech --path ./hello-speech --target browser
16
+ npx arcane-os@0.5.18 new hello-speech --path ./hello-speech --target browser
17
17
  cd hello-speech
18
18
  npm install
19
19
  npm run dev
@@ -280,15 +280,17 @@ passage synchronously before `Promise.all` waits, so synthesis can use the
280
280
  provider's available capacity. The returned array has one boolean per passage
281
281
  in input order: `true` after all its extracted audio buffers naturally end,
282
282
  or `false` after terminal cancellation or failure. `ai.stopAudio()` cancels
283
- all speech owned by that AI instance and settles pending playback results
284
- `false`.
283
+ streamed speech and prepared playback owned by that AI instance and settles
284
+ pending playback results `false`. Detached preparation described below keeps
285
+ its independent lifetime.
285
286
 
286
287
  The selected voice and speed are captured for segments extracted by that call.
287
288
  That includes any text left in the same AI instance's partial-stream buffer;
288
289
  finish the previous producer before starting a separate complete passage.
289
290
  Voice, speed, pause, and playback options are not retained with an unfinished
290
291
  `end:false` remainder. A later call supplies its own options, and `finishTTS()`
291
- uses their defaults. The optional text format below lasts through that flush.
292
+ uses their defaults while flushing any pending single formatting mark through
293
+ the same automatic speech-input cleanup.
292
294
  A call extracting no segments returns `true` without waiting for earlier jobs.
293
295
  An already muted call returns `false`.
294
296
 
@@ -300,6 +302,198 @@ pause delays the next queued audio on the existing `AudioContext` clock; it
300
302
  does not delay the preceding promise after that passage's last buffer ends.
301
303
  The promise is a playback result, not a listener acknowledgement.
302
304
 
305
+ ## Prepare narration once and replay stored audio
306
+
307
+ Use `ai.prepareTTS()` when preparation must continue independently of playback,
308
+ or when a later visit should reuse generated audio. It returns a handle
309
+ synchronously and starts preparing the supplied complete parts without speaking
310
+ them. Attach `ai.playPreparedTTS()` immediately to play those parts as their
311
+ audio becomes available, or omit playback to prepare them silently.
312
+
313
+ Use the configured `ai` and ready, application-owned `dbopfs` from the quick
314
+ start. Configuration itself does not load Kokoro. This path reads stored audio
315
+ first: a complete match can replay while the AI starts muted, with no model
316
+ load. Only missing audio requests the selected provider's shared load/unmute
317
+ path. Do not eagerly call `setSpeechMuted(false)` before this path if fully
318
+ cached playback should avoid loading the model.
319
+
320
+ ```javascript
321
+ ai.configureTTSSegmentation(
322
+ {
323
+ punctuation: 'any',
324
+ wordCadence: null
325
+ }
326
+ );
327
+
328
+ function prepareNarration(text, key) {
329
+ return ai.prepareTTS(
330
+ {
331
+ parts: [
332
+ {
333
+ input: text,
334
+ voice: speechSelection.model.defaultVoice,
335
+ speed: 1,
336
+ pauseAfterMs: 0
337
+ }
338
+ ],
339
+ storage: {
340
+ db: dbopfs,
341
+ table: 'saved_narration',
342
+ key
343
+ },
344
+ identity: {
345
+ model: speechSelection.model,
346
+ runtime: speechSelection.runtime
347
+ },
348
+ onState: reportNarrationPreparation
349
+ }
350
+ );
351
+ }
352
+
353
+ function reportNarrationPreparation(state) {
354
+ console.log('Narration preparation:', state);
355
+ }
356
+
357
+ function reportNarrationPlayback(state) {
358
+ console.log('Narration playback:', state);
359
+ }
360
+
361
+ async function readNarration(text, key) {
362
+ const prepared = prepareNarration(text, key);
363
+ const playback = ai.playPreparedTTS(
364
+ prepared,
365
+ {onState: reportNarrationPlayback}
366
+ );
367
+ const [record, ended] = await Promise.all(
368
+ [prepared.ready, playback.finished]
369
+ );
370
+ return {record, ended};
371
+ }
372
+ ```
373
+
374
+ Call `readNarration('**Hello**. Welcome back.', 'welcome')` from an owned user
375
+ action and handle its rejection. Calling only `prepareNarration(...)` prepares
376
+ silently; observe that handle's `ready` promise to receive its complete record
377
+ or error. A storage key groups application content. The application owns its
378
+ keys, preparation priority, semantic identity, and retention policy; the SDK
379
+ does not select another page or speak background work.
380
+
381
+ ### Preparation inputs and reuse
382
+
383
+ `ai.prepareTTS({parts,storage,identity,signal,onState})` accepts an ordered array
384
+ of strings or `{input,voice?,speed?,pauseAfterMs?}` records. An omitted voice
385
+ uses the selected model default; omitted speed uses `ai.voiceSpeed`; omitted
386
+ pause is zero. The SDK snapshots the selected speech configuration and current
387
+ punctuation/word-cadence options for that preparation. A part's pause applies
388
+ after its final extracted segment. Complete original input remains available
389
+ for semantic comparison; automatic Markdown cleanup affects only the speech
390
+ copy and occurs once before segmentation.
391
+
392
+ `storage` is optional. When supplied, `{db,table,key}` names the caller's ready
393
+ DBOPFS instance and its application-owned table/key. The SDK stores complete
394
+ generated audio as raw files and retains MIME metadata separately so subsequent
395
+ `Blob` playback preserves its content type. Reuse compares complete semantic
396
+ inputs, including parts, selection, segmentation, and separate application
397
+ `identity`. A changed voice, speed, source text, or other semantic selection
398
+ prepares the changed request. An SDK patch version alone does not invalidate
399
+ stored speech.
400
+
401
+ The storage key is encoded as `encodeURIComponent(key) + '.json'` for its
402
+ manifest. That version-1 manifest keeps an `entries` array of semantic variants
403
+ under the key. Each entry records
404
+ `{id,parts,originalParts,selection,segmentation,identity,segments}`; the ordered
405
+ stored segment entries name `{audioFile,contentType}`. `originalParts` retains
406
+ the complete source text, including whitespace. These persistent semantic
407
+ inputs and `identity` must be JSON-compatible. Raw audio filenames contain the
408
+ generated record ID and segment index. Storage writes preserve existing
409
+ variants; the application chooses when its records should be removed.
410
+
411
+ Matching pending requests on the same AI instance and the same storage
412
+ `db`/`table`/`key` share synthesis. Each caller receives its own handle and
413
+ cancellation signal. Cancelling one handle detaches that caller; the shared
414
+ preparation is aborted only when its last pending caller cancels. Different AI
415
+ instances do not share an in-flight synthesis operation. Complete stored
416
+ results remain reusable through the same application storage.
417
+ After a durable preparation completes, a later preparation call rereads its
418
+ manifest and saved-file presence, regenerating only missing segments. A
419
+ completed preparation without storage reuses its retained Blobs.
420
+
421
+ Preparation requests retain call order for synthesis admission. Within each
422
+ request, punctuation segments use the existing bounded provider queue: the
423
+ default Kokoro capacity admits up to four at once, with later segments waiting
424
+ in FIFO order. Completion may be out of order; segment metadata and playback
425
+ remain in input order. Preparing another request does not attach it to playback.
426
+
427
+ ### Preparation handle and progress
428
+
429
+ | Member | Contract |
430
+ | --- | --- |
431
+ | `state` | Current string: `queued`, `preparing`, `ready`, `error`, or `cancelled`. |
432
+ | `segments` | Ordered segment metadata with `input`, `voice`, `speed`, `pauseAfterMs`, `index`, `state`, `audioFile`, `contentType`, and `error`. |
433
+ | `ready` | Promise resolving the complete ordered record when every segment is generated or reused and, when storage is supplied, durably saved. Rejects with the complete error or `AbortError` if cancelled while pending. |
434
+ | `getAudio(index)` | Promise waiting for that ordered segment and returning its complete `Blob` with the recorded MIME type. |
435
+ | `cancel()` | Cancels this preparation handle without erasing successful stored segments. |
436
+
437
+ The optional synchronous `onState` callback receives
438
+ `{state,completed,total,segments,error}`. It observes preparation only; it is
439
+ not a playback-state callback. `completed` counts settled segments, including
440
+ failed segments; inspect `state`, segment errors, and `ready` for the outcome.
441
+ `total` is the number of ordered segments.
442
+ Without `storage`, the handle retains generated Blobs for its lifetime; the
443
+ same result shape has `audioFile:null` and the actual `contentType`.
444
+ The supplied signal observes preparation until `ready` settles. Manual
445
+ `cancel()` remains available afterward to stop further reads through that
446
+ handle. If a raw audio write has already begun when cancellation arrives,
447
+ its metadata transaction finishes so that successful audio can be reused;
448
+ no later queued write starts for that cancelled preparation.
449
+ Cancelling preparation prevents later synthesis, but the existing shared
450
+ provider load/unmute operation has no per-preparation signal and may finish.
451
+ Cancellation does not claim to stop an already-started shared model load.
452
+
453
+ ### Playback controls and independent lifetimes
454
+
455
+ `ai.playPreparedTTS(prepared,{signal,onState})` returns
456
+ `{state,error,finished,pause(),resume(),stop()}` immediately. It uses the
457
+ existing AI audio-clock scheduler and waits for each earlier segment before scheduling
458
+ later audio. Ready adjacent buffers retain contiguous scheduling. Requested
459
+ pauses separate adjacent parts; a final trailing pause does not delay
460
+ `finished`, which resolves after the final audio buffer ends.
461
+
462
+ `state` and `error` are current-state getters. The optional synchronous
463
+ `onState` callback receives `{state,error}` and is observational. Playback
464
+ states are `waiting`, `waiting-for-gesture`, `scheduled`, `paused`, `complete`,
465
+ `stopped`, and `error`. Use `waiting-for-gesture` to present an audio-unlock
466
+ control. A `false` result from `resume()` is not a first-segment-ready signal;
467
+ inspect `state` and `error` to distinguish a stopped or unavailable context
468
+ from browser gesture waiting. The ordinary playback path creates its audio
469
+ context immediately, before the first audio segment is ready.
470
+
471
+ `finished` resolves `true` after natural playback completion and `false` after
472
+ stop, playback cancellation, or failure. Real failures also reach the existing
473
+ `ai-tts-failure` event and complete SDK diagnostics. `pause()`
474
+ and `resume()` control only this handle's audio context, and `stop()` stops
475
+ that playback handle. The controls return booleans; pause and resume are
476
+ asynchronous. Each AI has one playback lane: a new `playPreparedTTS()` call
477
+ stops its preceding streamed or prepared playback, and `streamTTS()` interrupts
478
+ active prepared playback. This replacement preserves detached preparation.
479
+ None of these playback controls cancels preparation or deletes saved audio.
480
+ Use the preparation handle's `cancel()` or its separate `signal` when the
481
+ application also wants to stop preparation. Successful saved segments survive
482
+ cancellation or failure for later reuse.
483
+
484
+ `ai.stopAudio()` stops streamed speech and all prepared playback on that AI,
485
+ while detached preparation continues. `ai.setSpeechMuted(true)` additionally
486
+ cancels provider TTS work and unloads the provider. Replacing the speech
487
+ configuration cancels missing generation tied to the earlier selection.
488
+ Neither action deletes completed stored audio. Apply those broader lifecycle
489
+ controls deliberately when the application intends to stop provider work.
490
+
491
+ Preparation `ready` and playback `finished` are separate promises. Natural
492
+ playback completion must not be used as a signal to cancel other background
493
+ preparations. A page that starts several preparations owns and observes every
494
+ `ready` promise, even when it plays only one handle. Browser autoplay permission
495
+ still applies; neither promise proves that a person heard the audio.
496
+
303
497
  ## Stream chunks as they arrive
304
498
 
305
499
  Use the configured `ai` created above. Run this snippet from an owned user
@@ -343,18 +537,19 @@ if (finalPrepared === false) {
343
537
  ```
344
538
 
345
539
  The segmentation default uses sentence punctuation. To submit smaller complete
346
- segments, call `ai.configureTTSSegmentation({punctuation:'any',wordCadence:4})`
540
+ segments, call `ai.configureTTSSegmentation({punctuation:'any',wordCadence:null})`
347
541
  before feeding the stream. Chunk boundaries themselves do not force a sentence
348
542
  boundary; `finishTTS()` flushes any remaining text. It is not a playback-ended
349
543
  notification. Do not mute or dispose immediately after it if playback should
350
544
  continue.
351
545
 
352
- ## Omit Markdown formatting marks from narration
546
+ ## Automatic speech-input formatting cleanup
353
547
 
354
- Select `textFormat:'markdown'` for raw model text that contains formatting:
548
+ Every TTS entrypoint removes repeated same formatting marks from the outbound
549
+ speech-input copy automatically. No application option is required:
355
550
 
356
551
  ```javascript
357
- ai.streamTTS('## Heading\n**Hello', false, {textFormat:'markdown'});
552
+ ai.streamTTS('## Heading\n**Hello');
358
553
  ai.streamTTS('**. Next sentence.');
359
554
  await ai.finishTTS();
360
555
  ```
@@ -366,12 +561,30 @@ preserved. This is a small narration filter, not a full Markdown parser.
366
561
  Ordinary prose is forwarded immediately; only a trailing formatting candidate
367
562
  waits for its next character or the final flush.
368
563
 
369
- The format stays active until `end:true`, `finishTTS()`, or cancellation. New
370
- streams default to `plain`, which preserves exact submitted text. The shared
371
- chat component selects Markdown mode automatically. Applications already
372
- speaking visible DOM text can keep plain mode. Displayed messages, saved
373
- history, model input, language, voice, synthesis capacity, and playback timing
374
- are not changed by the filter.
564
+ `end:true`, `finishTTS()`, or cancellation clears pending streaming formatting
565
+ state. `fetchTTS()`, provider-runtime TTS requests, direct Kokoro provider
566
+ requests, and `SpeechPlayback` apply the same cleanup to complete input. An
567
+ existing `textFormat` extra is ignored and cannot disable or select cleanup.
568
+ SDK-internal delegation carries `{speechInputPrepared:true}` outside the speech
569
+ payload only after one cleanup pass, preventing a second non-idempotent pass.
570
+ Applications omit that internal metadata. Displayed messages, saved history,
571
+ model input, caller payload objects, language, voice, synthesis capacity, and
572
+ playback timing are not changed by the filter.
573
+
574
+ The shared helper is public for code that needs the speech-only
575
+ transformation directly:
576
+
577
+ ```javascript
578
+ import {
579
+ MarkdownSpeech,
580
+ stripSpeechFormatting
581
+ } from 'arcane-os/speech-text';
582
+
583
+ console.log(stripSpeechFormatting('**Hello**')); // Hello
584
+ const speechText = new MarkdownSpeech();
585
+ console.log(speechText.append('## Head', false)); // ' Head'
586
+ console.log(speechText.append('ing', true)); // ing
587
+ ```
375
588
 
376
589
  ## Choose a device or reduce memory use
377
590
 
@@ -446,7 +659,7 @@ These are actions for your own controls, using the same `ai` instance:
446
659
 
447
660
  ```javascript
448
661
  function stopSpeech() {
449
- ai.stopAudio(); // Cancels queued speech and stops scheduled/playing audio.
662
+ ai.stopAudio(); // Stops streamed speech and all prepared playback.
450
663
  }
451
664
 
452
665
  async function muteSpeech() {
@@ -476,7 +689,8 @@ in place; it does not erase the application's data.
476
689
  For a cancellable individual synthesis, unmute first. A fresh browser speech
477
690
  configuration is muted, so calling `providerRuntime.load('tts')` directly at
478
691
  that point rejects with `ARCANE_AI_TTS_MUTED`. `fetchTTS()` accepts an
479
- `AbortSignal` as its second argument and returns a WAV `Blob` without playing it:
692
+ `AbortSignal` as its second argument, cleans repeated formatting marks from the
693
+ outbound input copy, and returns a WAV `Blob` without playing it:
480
694
 
481
695
  ```javascript
482
696
  const synthesisController = new AbortController();
@@ -9,7 +9,7 @@ same managed browser imports as the [browser speech quick start](browser-speech.
9
9
  Create an application and start its source server:
10
10
 
11
11
  ```bash
12
- npx arcane-os@0.5.16 new hello-twin --path ./hello-twin --target browser
12
+ npx arcane-os@0.5.17 new hello-twin --path ./hello-twin --target browser
13
13
  cd hello-twin
14
14
  npm install
15
15
  npm run dev
@@ -3,6 +3,46 @@
3
3
  Use this page to choose an API by capability. The compact labels tell you where
4
4
  it runs; the [protocol guide](protocols.md) contains the implementation detail.
5
5
 
6
+ ## Shared type predicates
7
+
8
+ SDK-owned JavaScript uses the declared `strong-type` dependency for type
9
+ predicates. Node and managed renderer modules import `Is` from `strong-type`;
10
+ browser providers and workers use their shipped relative dependency path.
11
+ Component scripts import it within their own asynchronous component scope.
12
+ Publication bootstrap tools import the shipped runtime dependency by relative
13
+ path so they remain available before npm dependency installation.
14
+ The dependency pin and both shipped projections use 2.0.1. Update them together
15
+ through the published dependency workflow when another version is needed.
16
+
17
+ Reuse one non-throwing instance per module or component:
18
+
19
+ ```javascript
20
+ import Is from 'strong-type';
21
+
22
+ const is=new Is(false);
23
+
24
+ function requireText(value){
25
+ if(!is.string(value))throw new TypeError('Text is required.');
26
+ return value;
27
+ }
28
+ ```
29
+
30
+ The predicates classify values without coercing them. Existing API owners keep
31
+ their defaults, domain constraints, complete payloads, and public error behavior.
32
+ Use `number` for primitive numbers, `finite` for finite numbers, and `integer`
33
+ or `safeInteger` for the corresponding integer contract. `object` includes null;
34
+ retain a contract's separate null and array handling. `plainObject` is narrower
35
+ than a general non-array object check and must not silently reject previously
36
+ accepted class instances.
37
+
38
+ Constructor identity checks, diagnostic type labels, foreign-language source,
39
+ and isolated generated script bodies retain native operators where a replacement
40
+ would change their contract or execution scope. `DBOPFSWorker.js` and
41
+ `SystemPlatformPresentation.js` retain their few native predicates to preserve
42
+ classic-script loading and synchronous availability. Upstream dependency source is
43
+ consumed unchanged. Non-throwing strong-type array and constructor probes return
44
+ false when a probe throws; SDK branching continues through its owning error path.
45
+
6
46
  ## Availability labels
7
47
 
8
48
  | Label | Meaning |
@@ -32,12 +72,13 @@ version; WebKitGTK availability must not be generalized to macOS.
32
72
  | Select and observe independent LLM/STT/TTS roles | `/arcane/modules/AIProviderRuntime.js` and `AIRuntimeState.js` | **Cross-host** controller/state; registered providers retain their own host requirements | Required/projected provider members, route/configuration records, and status fields; per-role lifecycle, cancellation, stream cleanup, sticky state, and startup barriers are normalized. `localOnly` creates no fallback. |
33
73
  | Run a caller-selected local LLM entirely in a browser renderer | `arcane-os/ai/browser-wasm` through `createArcaneAI()` | **Browser** only; secure context, WebAssembly, OPFS/DBOPFS, WebGPU, and requested full offload are required; no CPU fallback | The public AI API module normalizes multi-model lifecycle, status, complete all-choice streaming, cancellation, exact ordered structural tool-call visibility, and session persistence. Model sources are canonical ordered file descriptors; licenses and model choice remain application policy. |
34
74
  | Run caller-selected Whisper or Kokoro in a browser renderer | `arcane-os/ai/browser-speech` registered with `AIProviderRuntime` | **Browser** only; DBOPFS, Web Locks, Workers, Fetch/object URLs, and a caller-supplied self-contained runtime/model closure are required | STT/TTS use independent provider/2 lifecycle and status. Kokoro adds bounded Worker/session concurrency and explicit `auto`, `webgpu`, or `wasm` execution. Complete model/runtime selection, offline behavior, cancellation, Worker teardown, and request/result shapes are normalized. No runtime/model content or cloud fallback is supplied. |
75
+ | Prepare ordered speech playback or reuse the speech-input formatting filter | `arcane-os/speech-playback` and `arcane-os/speech-text` | **Node** with injected media adapters, or **Browser / Native WebView** media; the text filter itself is **Cross-host** | Stored and caller-owned text stays exact. Only the outbound synthesis copy automatically loses repeated same formatting marks. A capacity-advertising provider receives complete segments immediately while retaining indexed playback; native/custom synthesis stays serialized. |
35
76
  | Preserve complete chat history and memory | `/arcane/modules/PersistentAIChatSession.js` | **Browser / native WebView** with ChatEntity/DBOPFS and a configured chat function | Existing DBOPFS names and memory semantics are preserved. Live-context commit is atomic; durable persistence is explicit and coherent across user/assistant turns and atomic all-ID tool-result batches. |
36
77
  | Search an app-owned document corpus for explicit chat context | `/arcane/modules/DBOPFSDocumentLibrary.js` | **Browser** or compatible injected DBOPFS adapter | Generation/manifest completion, complete lexical search, partial read failures, and untrusted context labels are normalized. Construction does not search; an explicitly wired context builder performs retrieval for each prepared chat send. |
37
78
  | Read host identity, capabilities, storage, preferences, appearance, or platform state | `globalThis.Arcane` | **Cross-host** where the method is implemented and admitted | Promise behavior and `Arcane.Error` are normalized. Result fields are normalized unless the method explicitly documents a platform-dependent snapshot. |
38
79
  | Use local AI without coupling app code to Ollama HTTP | `Arcane.localAI`, `Arcane.ai`, or `/arcane/modules/Ollama.js` | Primarily **Native**; Android exposes a narrower admitted inference projection | Admission, errors, and managed-operation events are normalized. Direct Ollama response envelopes remain **Provider-native**. |
39
80
  | Use TWiN Cloud from the renderer profile | `/arcane/modules/AI.js` | **Cloud** from an allowed browser/native renderer | High-level chat behavior is normalized by the module. The TWiN access key authenticates remote LLM chat; raw provider diagnostics remain provider-specific. No automatic cloud fallback is inferred from local failure. |
40
- | Use speech through one application helper | `/arcane/modules/AI.js` and `Arcane.speech` | **Browser** or **Native** | The helper keeps audio on device: Whisper owns STT and Kokoro owns TTS. It normalizes application-facing audio/text behavior while browser and native request/response plumbing differs below that boundary. |
81
+ | Use speech through one application helper | `/arcane/modules/AI.js` and `Arcane.speech` | **Browser** or **Native** | The helper keeps audio on device: Whisper owns STT and Kokoro owns TTS. It automatically cleans only the outbound speech-input copy and normalizes application-facing audio/text behavior while browser and native request/response plumbing differs below that boundary. |
41
82
  | Inspect or manage raw Ollama models | `Arcane.ollama` or `/arcane/modules/Ollama.js` | **Native** desktop Core for management; narrower Android inference only | Wrapper method names, errors, streaming correlation, and admission are Arcane-controlled. Direct Ollama success envelopes are intentionally provider-native. |
42
83
  | Use native terminal, installation, user, provisioning, or machine controls | matching `Arcane.*` namespace | **Native** and app/capability restricted | Calls and errors use the common bridge contract. Platform results can be host-specific and are marked in the method guide. |
43
84
 
@@ -214,7 +214,7 @@ portable runtime subpaths such as `arcane-os/preference-store` and
214
214
  modules. The result reports the complete map written to the selected
215
215
  application; no fixed entry count is a release contract.
216
216
 
217
- SDK `0.5.16` preserves the physical workspace route count and ordered include
217
+ SDK `0.5.17` preserves the physical workspace route count and ordered include
218
218
  list. External and modern integrated routes require `components`, `css`,
219
219
  `dependencies`, `entities`, `img`, `modules`, and `sdk`; a physical workspace
220
220
  may omit only an optional trailing `security` include. The external license
@@ -9,7 +9,7 @@ They are not TypeScript declarations.
9
9
 
10
10
  ## Portable SDK AI and Core AI
11
11
 
12
- The SDK `0.5.16` has two related but separate normalized boundaries:
12
+ The SDK `0.5.17` has two related but separate normalized boundaries:
13
13
 
14
14
  | Boundary | Use | Host |
15
15
  |---|---|---|
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "sdkVersion": "0.5.16",
3
+ "sdkVersion": "0.5.18",
4
4
  "environment": {
5
5
  "runtime": "Node.js for Node entrypoints; browser for browser-only entrypoints",
6
6
  "minimumVersion": "22.23.2 for Node entrypoints",
7
7
  "moduleSystem": "ESM"
8
8
  },
9
- "memberCount": 198,
9
+ "memberCount": 202,
10
10
  "members": [
11
11
  {
12
12
  "id": "root:APP_BUNDLE_DESCRIPTOR_NAME",
@@ -1395,7 +1395,7 @@
1395
1395
  "summary": "Default binding for the canonical SpeechPlayback runtime class, with capability-gated eager provider submission and exact-order playback.",
1396
1396
  "availability": "Node with injected media adapters, or browser/native WebView media",
1397
1397
  "protocol": "SpeechPlayback runtime contract",
1398
- "normalization": "Binding identity and namespace come directly from the canonical runtime module; a fetchTTS client with positive advertised TTS execution capacity receives all complete segments immediately while its provider owns bounded admission and SpeechPlayback retains indexed order; other clients remain serialized"
1398
+ "normalization": "Binding identity and namespace come directly from the canonical runtime module; stored part input remains exact while only each outbound synthesis copy receives automatic repeated-formatting-mark cleanup and SDK-internal preparation metadata; a fetchTTS client with positive advertised TTS execution capacity receives all complete segments immediately while its provider owns bounded admission and SpeechPlayback retains indexed order; other clients remain serialized; canonical state dispatch precedes the optional synchronous onState callback"
1399
1399
  },
1400
1400
  {
1401
1401
  "id": "speech-playback:SPEECH_PLAYBACK_STATE_EVENT",
@@ -1411,6 +1411,34 @@
1411
1411
  "protocol": "SpeechPlayback runtime contract",
1412
1412
  "normalization": "Exact immutable speech-playback-state event name"
1413
1413
  },
1414
+ {
1415
+ "id": "speech-playback:SPEECH_VOICE_ALIASES",
1416
+ "name": "SPEECH_VOICE_ALIASES",
1417
+ "displayName": "SPEECH_VOICE_ALIASES",
1418
+ "kind": "constant",
1419
+ "signature": "const SPEECH_VOICE_ALIASES",
1420
+ "entrypoints": ["arcane-os/speech-playback"],
1421
+ "primaryImport": "arcane-os/speech-playback",
1422
+ "group": "Portable runtime modules",
1423
+ "summary": "Mutable compatibility membership set for the ten shared speech voice identifiers.",
1424
+ "availability": "Node and browser",
1425
+ "protocol": "SpeechPlayback runtime contract",
1426
+ "normalization": "Derived once from SPEECH_VOICE_OPTIONS in published order; ordinary mutable Set containing alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, and shimmer; SpeechPlayback does not select it automatically"
1427
+ },
1428
+ {
1429
+ "id": "speech-playback:SPEECH_VOICE_OPTIONS",
1430
+ "name": "SPEECH_VOICE_OPTIONS",
1431
+ "displayName": "SPEECH_VOICE_OPTIONS",
1432
+ "kind": "constant",
1433
+ "signature": "const SPEECH_VOICE_OPTIONS",
1434
+ "entrypoints": ["arcane-os/speech-playback"],
1435
+ "primaryImport": "arcane-os/speech-playback",
1436
+ "group": "Portable runtime modules",
1437
+ "summary": "Mutable ordered compatibility value/label records for existing speech controls.",
1438
+ "availability": "Node and browser",
1439
+ "protocol": "SpeechPlayback runtime contract",
1440
+ "normalization": "Ordinary mutable array and mutable records ordered as Alloy, Ash, Ballad, Coral, Echo, Fable, Nova, Onyx, Sage, and Shimmer; provider support and selection remain caller-owned"
1441
+ },
1414
1442
  {
1415
1443
  "id": "speech-playback:SpeechPlayback",
1416
1444
  "name": "SpeechPlayback",
@@ -1423,7 +1451,7 @@
1423
1451
  "summary": "Named binding for the same capability-aware, exact-order canonical class exposed as the subpath default.",
1424
1452
  "availability": "Node with injected media adapters, or browser/native WebView media",
1425
1453
  "protocol": "SpeechPlayback runtime contract",
1426
- "normalization": "Binding identity equals the default export; prepare preserves each nonblank part input exactly without trimming, splitting, or freezing it; provider-advertised capacity enables eager submission while the provider owns its bound, native and custom clients remain serialized, and media availability remains host-owned"
1454
+ "normalization": "Binding identity equals the default export; prepare preserves each nonblank part input exactly without trimming, splitting, or freezing it; requestSpeech changes only the cloned outbound input through automatic repeated-formatting-mark cleanup and carries SDK-internal preparation metadata; provider-advertised capacity enables eager submission while the provider owns its bound, native and custom clients remain serialized, canonical state dispatch precedes optional synchronous onState delivery, and media availability remains host-owned"
1427
1455
  },
1428
1456
  {
1429
1457
  "id": "speech-playback:splitSpeechText",
@@ -1439,6 +1467,34 @@
1439
1467
  "protocol": "SpeechPlayback runtime contract",
1440
1468
  "normalization": "Uses trimming only to detect blank input; nonblank text is returned unchanged in one mutable array without trimming, splitting, or freezing"
1441
1469
  },
1470
+ {
1471
+ "id": "speech-text:MarkdownSpeech",
1472
+ "name": "MarkdownSpeech",
1473
+ "displayName": "MarkdownSpeech",
1474
+ "kind": "class",
1475
+ "signature": "new MarkdownSpeech()",
1476
+ "entrypoints": ["arcane-os/speech-text"],
1477
+ "primaryImport": "arcane-os/speech-text",
1478
+ "group": "Portable runtime modules",
1479
+ "summary": "Streams speech-only repeated-formatting-mark removal across input chunk boundaries.",
1480
+ "availability": "Node and browser",
1481
+ "protocol": "Speech text normalization",
1482
+ "normalization": "append(text='',end=false) emits newly available narration, retains only a trailing candidate formatting mark across chunks, and resets after a terminal append; reset() discards that pending state; caller text remains unchanged"
1483
+ },
1484
+ {
1485
+ "id": "speech-text:stripSpeechFormatting",
1486
+ "name": "stripSpeechFormatting",
1487
+ "displayName": "stripSpeechFormatting()",
1488
+ "kind": "function",
1489
+ "signature": "stripSpeechFormatting(text='')",
1490
+ "entrypoints": ["arcane-os/speech-text"],
1491
+ "primaryImport": "arcane-os/speech-text",
1492
+ "group": "Portable runtime modules",
1493
+ "summary": "Removes repeated runs of speech formatting marks from one complete text value.",
1494
+ "availability": "Node and browser",
1495
+ "protocol": "Speech text normalization",
1496
+ "normalization": "Calls the supplied value's replace method and returns its result with runs of two or more identical *, #, _, backtick, or ~ marks removed; single marks and every other character remain literal; it does not parse Markdown or modify the supplied value; values without callable replace fail with the native TypeError"
1497
+ },
1442
1498
  {
1443
1499
  "id": "root:readRuntimeFile",
1444
1500
  "name": "readRuntimeFile",
@@ -5,7 +5,7 @@
5
5
  "repository": "https://github.com/TheWizardNexus/arcane-os-sdk.git",
6
6
  "branch": "main",
7
7
  "path": "runtime/arcane/components",
8
- "sdkVersion": "0.5.16"
8
+ "sdkVersion": "0.5.18"
9
9
  },
10
10
  "componentCount": 39,
11
11
  "loader": "/arcane/modules/HTMLImport.js",
@@ -171,7 +171,7 @@
171
171
  ],
172
172
  "availability": "Browser and supported native WebViews",
173
173
  "transport": "HTMLImport + DOM; injected Arcane/provider modules where listed",
174
- "normalization": "UI/runtime state, honest model progress, complete timestamped transcript including ui_hidden stored records, user-facing structural arguments.message, nonblank all-ID tool-result restoration, collapsed complete raw inspection, ordered parallel-call replay validation, per-choice streamed/terminal complete-envelope correlation, complete nonstructural stream rendering, generic visible failure outcomes with complete console diagnostics, atomic executed/declined/cancelled/not-executed result batches with one continuation, plural pending-call reload recovery, reentrant terminal-event ownership, and BFCache-preserving page lifecycle are normalized; destroy aborts observation and returns true once/false thereafter; AI/storage/media behavior remains mixed"
174
+ "normalization": "UI/runtime state, honest model progress, complete timestamped transcript including ui_hidden stored records, user-facing structural arguments.message, nonblank all-ID tool-result restoration, collapsed complete raw inspection, ordered parallel-call replay validation, per-choice streamed/terminal complete-envelope correlation, complete nonstructural stream rendering, automatic repeated-formatting-mark removal from only the outbound speech-input copy while displayed and stored Markdown stays exact, generic visible failure outcomes with complete console diagnostics, atomic executed/declined/cancelled/not-executed result batches with one continuation, plural pending-call reload recovery, reentrant terminal-event ownership, and BFCache-preserving page lifecycle are normalized; destroy aborts observation and returns true once/false thereafter; AI/storage/media behavior remains mixed"
175
175
  },
176
176
  {
177
177
  "file": "runtime/arcane/components/conversation-view.html",