arcane-os 0.5.17 → 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 (183) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +9 -9
  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 +46 -43
  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 +5 -1
  17. package/docs/reference/ai/browser-speech.md +198 -5
  18. package/docs/reference/availability-and-normalization.md +40 -0
  19. package/docs/reference/inventory/package-api.json +1 -1
  20. package/docs/reference/inventory/runtime-components.json +1 -1
  21. package/docs/reference/inventory/runtime-modules.json +20 -24
  22. package/docs/reference/protocols.md +1 -1
  23. package/docs/reference/runtime-modules.md +125 -35
  24. package/docs/reference/sdk-api.md +23 -7
  25. package/examples/wasm-ai-demo/index.html +1 -0
  26. package/node_modules/event-pubsub/node_modules/strong-type/README.md +408 -0
  27. package/node_modules/event-pubsub/node_modules/strong-type/assets/strong-type-header.png +0 -0
  28. package/node_modules/event-pubsub/node_modules/strong-type/index.js +1151 -0
  29. package/node_modules/event-pubsub/node_modules/strong-type/licence +21 -0
  30. package/node_modules/event-pubsub/node_modules/strong-type/node.js +125 -0
  31. package/node_modules/event-pubsub/node_modules/strong-type/package.json +61 -0
  32. package/node_modules/strong-type/README.md +42 -24
  33. package/node_modules/strong-type/benchmark/core.js +324 -0
  34. package/node_modules/strong-type/index.js +207 -82
  35. package/node_modules/strong-type/package.json +14 -6
  36. package/package.json +3 -3
  37. package/runtime/arcane/components/app-bar.html +5 -2
  38. package/runtime/arcane/components/assistant-panel.html +5 -2
  39. package/runtime/arcane/components/chart.html +15 -12
  40. package/runtime/arcane/components/chat.html +117 -138
  41. package/runtime/arcane/components/dashboard-config.html +6 -3
  42. package/runtime/arcane/components/data-view.html +4 -1
  43. package/runtime/arcane/components/directory-picker.html +5 -2
  44. package/runtime/arcane/components/document-inspector.html +6 -3
  45. package/runtime/arcane/components/file-drop.html +5 -2
  46. package/runtime/arcane/components/file-inspector.html +9 -6
  47. package/runtime/arcane/components/file-manager.html +16 -13
  48. package/runtime/arcane/components/local-ai-status.html +5 -2
  49. package/runtime/arcane/components/markdown-document.html +14 -11
  50. package/runtime/arcane/components/markdown-editor.html +4 -1
  51. package/runtime/arcane/components/modal.html +4 -1
  52. package/runtime/arcane/components/output-panel.html +6 -3
  53. package/runtime/arcane/components/preferences-form.html +4 -1
  54. package/runtime/arcane/components/record-timeline.html +8 -5
  55. package/runtime/arcane/components/relationship-board.html +9 -6
  56. package/runtime/arcane/components/source-code-viewer.html +12 -9
  57. package/runtime/arcane/components/source-explanation.html +8 -5
  58. package/runtime/arcane/components/speech.html +24 -21
  59. package/runtime/arcane/components/summary-strip.html +4 -1
  60. package/runtime/arcane/components/task-progress.html +6 -3
  61. package/runtime/arcane/components/terminal-workspace.html +4 -1
  62. package/runtime/arcane/components/voice-transcription.html +11 -8
  63. package/runtime/arcane/components/web-navigator.html +5 -2
  64. package/runtime/arcane/entities/ApiModelRecord.js +5 -2
  65. package/runtime/arcane/entities/Calculation.js +5 -2
  66. package/runtime/arcane/entities/Chat.js +33 -33
  67. package/runtime/arcane/entities/CommunicationMessage.js +4 -1
  68. package/runtime/arcane/entities/CommunicationThread.js +4 -1
  69. package/runtime/arcane/entities/File.js +1 -1
  70. package/runtime/arcane/entities/Image.js +8 -5
  71. package/runtime/arcane/entities/IntentEnvelope.js +20 -17
  72. package/runtime/arcane/entities/Preference.js +9 -6
  73. package/runtime/arcane/entities/Theme.js +5 -2
  74. package/runtime/arcane/entities/User.js +11 -11
  75. package/runtime/arcane/entities/Weather.js +5 -2
  76. package/runtime/arcane/modules/AI.js +491 -165
  77. package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
  78. package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
  79. package/runtime/arcane/modules/AIProviderRuntime.js +88 -85
  80. package/runtime/arcane/modules/AIResponseURLPolicy.js +148 -62
  81. package/runtime/arcane/modules/AIRuntimeState.js +29 -26
  82. package/runtime/arcane/modules/AnsiText.js +4 -1
  83. package/runtime/arcane/modules/ApiModelDatabase.js +22 -19
  84. package/runtime/arcane/modules/AppDataScope.js +8 -5
  85. package/runtime/arcane/modules/ArcaneCommunicationBridge.js +4 -1
  86. package/runtime/arcane/modules/ArcaneNavigationPolicy.js +8 -5
  87. package/runtime/arcane/modules/ArcaneNetworkPolicy.js +18 -15
  88. package/runtime/arcane/modules/AsyncBoundary.js +13 -10
  89. package/runtime/arcane/modules/BrowserTestSuite.js +19 -16
  90. package/runtime/arcane/modules/CalculatorEngine.js +5 -2
  91. package/runtime/arcane/modules/ChatRecords.js +18 -15
  92. package/runtime/arcane/modules/CommunicationAppController.js +9 -6
  93. package/runtime/arcane/modules/CommunicationHub.js +9 -6
  94. package/runtime/arcane/modules/CommunicationPreferences.js +4 -1
  95. package/runtime/arcane/modules/CommunicationProviderRegistry.js +4 -1
  96. package/runtime/arcane/modules/ComponentContracts.js +56 -53
  97. package/runtime/arcane/modules/ConfiguredAIChatSession.js +30 -27
  98. package/runtime/arcane/modules/ConversationActionItems.js +15 -12
  99. package/runtime/arcane/modules/ConversationClosingReport.js +11 -8
  100. package/runtime/arcane/modules/ConversationTimebox.js +28 -25
  101. package/runtime/arcane/modules/CoreLocalModelCatalog.js +17 -14
  102. package/runtime/arcane/modules/DBLS.js +7 -4
  103. package/runtime/arcane/modules/DBOPFS.js +7 -7
  104. package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +34 -31
  105. package/runtime/arcane/modules/DevelopmentWorkspace.js +4 -1
  106. package/runtime/arcane/modules/DirectoryPicker.js +8 -5
  107. package/runtime/arcane/modules/DocumentLexicalSearch.js +11 -8
  108. package/runtime/arcane/modules/DocumentNavigation.js +7 -4
  109. package/runtime/arcane/modules/Errors.js +28 -25
  110. package/runtime/arcane/modules/HTMLImport.js +7 -4
  111. package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +15 -12
  112. package/runtime/arcane/modules/LocalAIReadiness.js +21 -18
  113. package/runtime/arcane/modules/LocalAIReadinessController.js +6 -3
  114. package/runtime/arcane/modules/MD.js +1 -1
  115. package/runtime/arcane/modules/Mail.js +46 -43
  116. package/runtime/arcane/modules/MailOutbox.mjs +48 -45
  117. package/runtime/arcane/modules/MailTransport.mjs +29 -26
  118. package/runtime/arcane/modules/MemoryRecords.js +7 -4
  119. package/runtime/arcane/modules/MessageAdvisory.js +6 -3
  120. package/runtime/arcane/modules/ModelDefinition.js +7 -4
  121. package/runtime/arcane/modules/Ollama.js +6 -3
  122. package/runtime/arcane/modules/OllamaModelIdentifier.js +4 -1
  123. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +18 -15
  124. package/runtime/arcane/modules/PersistentAIChatSession.js +33 -30
  125. package/runtime/arcane/modules/PreferenceStore.js +20 -17
  126. package/runtime/arcane/modules/PreparedSpeech.js +485 -0
  127. package/runtime/arcane/modules/Questionnaire.js +6 -3
  128. package/runtime/arcane/modules/RecordLinkIndex.js +4 -1
  129. package/runtime/arcane/modules/RecordPassageIndex.js +9 -6
  130. package/runtime/arcane/modules/RecordReviewStore.js +12 -9
  131. package/runtime/arcane/modules/RiskSignalAnalyzer.js +4 -1
  132. package/runtime/arcane/modules/ScopedOPFSCache.js +6 -3
  133. package/runtime/arcane/modules/ScreenCapture.js +20 -17
  134. package/runtime/arcane/modules/SpeechPlayback.js +29 -26
  135. package/runtime/arcane/modules/StaticDocumentCatalog.js +33 -30
  136. package/runtime/arcane/modules/SystemAppearance.js +5 -2
  137. package/runtime/arcane/modules/SystemToolRegistry.js +6 -3
  138. package/runtime/arcane/modules/TerminalClient.js +14 -11
  139. package/runtime/arcane/modules/TerminalCommandRegistry.js +4 -1
  140. package/runtime/arcane/modules/ThemeBootstrap.js +9 -6
  141. package/runtime/arcane/modules/ThemeManager.js +5 -2
  142. package/runtime/arcane/modules/TimeGuard.js +1 -1
  143. package/runtime/arcane/modules/ToolCallRouter.js +11 -8
  144. package/runtime/arcane/modules/WaitForComponent.js +19 -16
  145. package/runtime/arcane/modules/YouTubeMedia.js +4 -1
  146. package/runtime/strong-type/index.js +1276 -352
  147. package/runtime/strong-type/package.json +69 -45
  148. package/src/app-descriptor.mjs +17 -14
  149. package/src/application-tests.mjs +4 -1
  150. package/src/cli/main.mjs +8 -5
  151. package/src/constants.mjs +4 -1
  152. package/src/dev-server.mjs +8 -5
  153. package/src/doctor.mjs +5 -2
  154. package/src/dom-event-instrumentation.mjs +24 -20
  155. package/src/errors.mjs +7 -3
  156. package/src/event-manager.mjs +111 -108
  157. package/src/event-queue.mjs +8 -5
  158. package/src/events.mjs +12 -9
  159. package/src/import-map.mjs +35 -27
  160. package/src/installed-sdk-runtime.mjs +4 -1
  161. package/src/integrated-provider-loader.mjs +9 -6
  162. package/src/mail-credentials.mjs +16 -13
  163. package/src/mail-server.mjs +53 -50
  164. package/src/mail.mjs +18 -15
  165. package/src/native-plan.mjs +12 -9
  166. package/src/native-provider-loader.mjs +7 -4
  167. package/src/packager/core.mjs +18 -15
  168. package/src/process.mjs +6 -3
  169. package/src/release-bundle.mjs +14 -11
  170. package/src/runtime.mjs +4 -1
  171. package/src/scaffold.mjs +9 -6
  172. package/src/sdk-browser-runtime.mjs +4 -1
  173. package/src/source-server.mjs +17 -14
  174. package/src/targets/index.mjs +5 -2
  175. package/src/templates/workspace-template.mjs +13 -6
  176. package/src/testing-loader.mjs +7 -4
  177. package/src/testing.mjs +10 -7
  178. package/src/toolchain.mjs +13 -10
  179. package/src/update-check.mjs +9 -6
  180. package/src/workspace-operation-lock.mjs +14 -11
  181. package/src/workspace-runtime.mjs +4 -1
  182. package/src/workspace.mjs +17 -14
  183. package/runtime/arcane/modules/AIResponseLength.js +0 -32
@@ -1,3 +1,7 @@
1
+ import Is from './dependencies/strong-type/index.js';
2
+
3
+ const is=new Is(false);
4
+
1
5
  function stripSpeechFormatting(text=''){
2
6
  return text.replace(/([*#_`~])\1+/g,'');
3
7
  }
@@ -7,7 +11,7 @@ class MarkdownSpeech {
7
11
  #pending='';
8
12
 
9
13
  append(text='',end=false){
10
- if(typeof text!=='string'){
14
+ if(!is.string(text)){
11
15
  throw new TypeError('Markdown speech input must be text.');
12
16
  }
13
17
 
@@ -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.17 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,8 +280,9 @@ 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;
@@ -301,6 +302,198 @@ pause delays the next queued audio on the existing `AudioContext` clock; it
301
302
  does not delay the preceding promise after that passage's last buffer ends.
302
303
  The promise is a playback result, not a listener acknowledgement.
303
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
+
304
497
  ## Stream chunks as they arrive
305
498
 
306
499
  Use the configured `ai` created above. Run this snippet from an owned user
@@ -378,7 +571,7 @@ Applications omit that internal metadata. Displayed messages, saved history,
378
571
  model input, caller payload objects, language, voice, synthesis capacity, and
379
572
  playback timing are not changed by the filter.
380
573
 
381
- The dependency-free helper is public for code that needs the speech-only
574
+ The shared helper is public for code that needs the speech-only
382
575
  transformation directly:
383
576
 
384
577
  ```javascript
@@ -466,7 +659,7 @@ These are actions for your own controls, using the same `ai` instance:
466
659
 
467
660
  ```javascript
468
661
  function stopSpeech() {
469
- ai.stopAudio(); // Cancels queued speech and stops scheduled/playing audio.
662
+ ai.stopAudio(); // Stops streamed speech and all prepared playback.
470
663
  }
471
664
 
472
665
  async function muteSpeech() {
@@ -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 |
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "sdkVersion": "0.5.17",
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",
@@ -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.17"
8
+ "sdkVersion": "0.5.18"
9
9
  },
10
10
  "componentCount": 39,
11
11
  "loader": "/arcane/modules/HTMLImport.js",
@@ -5,12 +5,12 @@
5
5
  "repository": "https://github.com/TheWizardNexus/arcane-os-sdk.git",
6
6
  "branch": "main",
7
7
  "path": "runtime/arcane",
8
- "sdkVersion": "0.5.17",
8
+ "sdkVersion": "0.5.18",
9
9
  "protocol": "arcane/1"
10
10
  },
11
11
  "artifactCount": 85,
12
12
  "javascriptArtifactCount": 83,
13
- "esmExportCount": 356,
13
+ "esmExportCount": 352,
14
14
  "artifacts": [
15
15
  {
16
16
  "file": "runtime/arcane/modules/AI.js",
@@ -29,8 +29,8 @@
29
29
  "summary": "Owns provider-selectable chat and the one-time caller-authority browser STT/TTS configuration, lifecycle, synthesis, transcription, and playback boundary.",
30
30
  "availability": "Browser + native bridge + TWiN Cloud",
31
31
  "protocol": "arcane-ai-browser-speech-configuration/1, AIProviderRuntime arcane-ai-provider/2 routes, globalThis.arcaneEvents, TWiN Cloud HTTPS, Arcane.ollama, Arcane.speech, Android WebView bridge",
32
- "normalization": "Complete mutable caller-owned browser speech authority, SDK-owned provider registration/replacement/disposal, explicit STT/TTS activation, normalized Kokoro TTS execution with default capacity 4, explicit provider-neutral execution snapshots through status(role,{execution:true}), sticky readiness, canonical window.user readiness without compatibility-event object-identity admission or polling, exact ordered structural calls with required arguments.message, atomic nonblank all-ID tool-result sequencing, complete all-choice streaming/data validation, native Ollama structural adaptation, complete-response then all validated tool callbacks then completion ordering, observed async callbacks, Blob/File transcription, automatic repeated-formatting-mark removal from cloned outbound TTS input while caller and visible content stays exact, immediate exact-segment synthesis, per-call voice/speed capture, optional final-segment pause on the existing audio clock, optional per-call terminal playback completion, ordered audio-clock scheduling, playable audio, active-generation TTS operation-failure routing, mute, and cancellation are normalized; provider/model/runtime/voice policy remains caller-owned.",
33
- "surface": "Browser-speech protocol/event/error/reason constants; default `AI`; read-only `providerRuntime`, `browserSpeechConfiguration`, and `browserSpeechDescriptor`; explicit `providerRuntime.status(role,{execution:true})` snapshots; `streamTTS(text,end,options={})` with optional voice, speed, pauseAfterMs, and waitForPlayback; automatic speech-input cleanup with SDK-internal preparation metadata; configure/dispose speech, route lifecycle, declaration-validated chat/stream requests with exact ordered calls, synthesis/transcription, and playback controls; initializes from current canonical user readiness, installs `window.ai`, and projects `ai-ready` plus active-generation `ai-tts-failure`."
32
+ "normalization": "Complete mutable caller-owned browser speech authority, SDK-owned provider registration/replacement/disposal, explicit STT/TTS activation, normalized Kokoro TTS execution with default capacity 4, explicit provider-neutral execution snapshots through status(role,{execution:true}), sticky readiness, canonical window.user readiness without compatibility-event object-identity admission or polling, exact ordered structural calls with required arguments.message, atomic nonblank all-ID tool-result sequencing, complete all-choice streaming/data validation, native Ollama structural adaptation, complete-response then all validated tool callbacks then completion ordering, observed async callbacks, Blob/File transcription, automatic repeated-formatting-mark removal from cloned outbound TTS input while caller and visible content stays exact, immediate exact-segment synthesis, per-call voice/speed capture, optional final-segment pause on the existing audio clock, optional per-call terminal playback completion, detached preparation with complete semantic DBOPFS audio reuse and same-owner pending request sharing, independent prepared playback without a model load for cached audio, ordered audio-clock scheduling, playable audio, active-generation TTS operation-failure routing, mute, and cancellation are normalized; provider/model/runtime/voice policy remains caller-owned.",
33
+ "surface": "Browser-speech protocol/event/error/reason constants; default `AI`; read-only `providerRuntime`, `browserSpeechConfiguration`, and `browserSpeechDescriptor`; explicit `providerRuntime.status(role,{execution:true})` snapshots; `streamTTS(text,end,options={})` with optional voice, speed, pauseAfterMs, and waitForPlayback; automatic speech-input cleanup with SDK-internal preparation metadata; `prepareTTS({parts,storage,identity,signal,onState})` returning ordered segments, state, ready, getAudio(index), and cancel(); `playPreparedTTS(prepared,{signal,onState})` returning state, error, finished, pause(), resume(), and stop() with one playback lane per AI and observational state/error callbacks; configure/dispose speech, route lifecycle, declaration-validated chat/stream requests with exact ordered calls, synthesis/transcription, and playback controls; initializes from current canonical user readiness, installs `window.ai`, and projects `ai-ready` plus active-generation `ai-tts-failure`."
34
34
  },
35
35
  {
36
36
  "file": "runtime/arcane/modules/AIPreferenceRuntime.js",
@@ -79,23 +79,6 @@
79
79
  "normalization": "Normalizes mutable complete per-role routes, lifecycle/status, cancellation, streaming cleanup, capacity-1 FIFO LLM/STT lanes, bounded provider-declared parallel TTS requests with FIFO overflow, automatic repeated-formatting-mark removal from cloned direct TTS payloads, local-only selection, direct LLM history/declaration/terminal structural contracts, complete all-choice content/reasoning FIFO iteration, private automatic provider draining with result-first buffering, terminal-only structural calls, exact per-choice observed/terminal correlation, and a separate complete validated terminal result without creating a fallback.",
80
80
  "surface": "Protocol constants; singleton-only `AIProviderRuntime`; `aiProviderRuntime`; `getAIProviderRuntime()`; provider registration/identity/selection, closed three-role and STT/TTS-only validation/configuration/replacement, status/catalog/inspection, startup, per-role load/unload/dispose/cancel, dispose-all, request/stream/speech aliases, SDK-internal speech-input preparation metadata, and mute controls."
81
81
  },
82
- {
83
- "file": "runtime/arcane/modules/AIResponseLength.js",
84
- "name": "AIResponseLength.js",
85
- "kind": "esm",
86
- "exports": [
87
- "AI_RESPONSE_LENGTH_DEFAULT",
88
- "AI_RESPONSE_LENGTH_OPTIONS",
89
- "aiResponseLengthInstruction",
90
- "applyAIResponseLength",
91
- "normalizeAIResponseLength"
92
- ],
93
- "summary": "Normalizes low/medium/high response-preference selectors while leaving complete prompts unchanged.",
94
- "availability": "Cross-host",
95
- "protocol": "In-process only",
96
- "normalization": "Selectors normalize to low, medium, or high; every label is Complete, the instruction is empty, and prompt content remains unchanged.",
97
- "surface": "Response-preference constants plus `normalizeAIResponseLength()`, `aiResponseLengthInstruction()`, and `applyAIResponseLength()`."
98
- },
99
82
  {
100
83
  "file": "runtime/arcane/modules/AIResponseURLPolicy.js",
101
84
  "name": "AIResponseURLPolicy.js",
@@ -108,8 +91,8 @@
108
91
  ],
109
92
  "summary": "Extracts and audits links from AI Markdown, rendered HTML, CSS, srcset, bare URLs, and email text.",
110
93
  "availability": "Cross-host",
111
- "protocol": "In-process; bundled Marked parser",
112
- "normalization": "Normalized frozen allowlist audit.",
94
+ "protocol": "In-process; bundled Marked parser and native HTML parsing when a document is available",
95
+ "normalization": "Mutable audit with exact link comparison after entity and Markdown escape decoding, without URI canonicalization or response mutation. Browsers use native HTML parsing; hosts without a document retain lexical extraction and the existing limited entity decoder. Already decoded rendered values are not decoded again. Authored links retain source offsets; DOM-only attribute links use document order after authored links.",
113
96
  "surface": "`auditAIResponseLinks()`, `extractAIResponseLinks()`, `normalizeAIResponseLink()`, `decodeHTMLCharacterReferences()`."
114
97
  },
115
98
  {
@@ -834,7 +817,7 @@
834
817
  "summary": "Re-exports the shared MarkdownSpeech class that removes repeated same formatting marks from streamed narration before speech segmentation.",
835
818
  "availability": "Cross-host",
836
819
  "protocol": "Shared arcane-os/speech-text package entrypoint",
837
- "normalization": "The runtime projection and public package subpath share dependency-free speech-only filtering of repeated *, #, _, backtick, and ~ runs across chunks; single marks and all other characters remain literal; terminal flush and reset clear pending formatting state.",
820
+ "normalization": "The runtime projection and public package subpath share speech-only filtering of repeated *, #, _, backtick, and ~ runs across chunks; single marks and all other characters remain literal; terminal flush and reset clear pending formatting state.",
838
821
  "surface": "`MarkdownSpeech`; `append(text='',end=false)`, `reset()`."
839
822
  },
840
823
  {
@@ -1018,6 +1001,19 @@
1018
1001
  "normalization": "Complete ordinary values remain mutable; setAll uses one optional atomic adapter batch for every selected value when advertised, otherwise retains complete serial per-key compatibility, never retries a rejected dispatched batch serially, and only exact unsupported native capability changes future operations to the browser fallback.",
1019
1002
  "surface": "Event/error constants, default `PreferenceStore`, re-exported `Preference`/schema; load/set/setAll/reset APIs, required adapter get/set/delete plus optional setMany, state-free EventTarget/on compatibility, and `dispose()`."
1020
1003
  },
1004
+ {
1005
+ "file": "runtime/arcane/modules/PreparedSpeech.js",
1006
+ "name": "PreparedSpeech.js",
1007
+ "kind": "esm",
1008
+ "exports": [
1009
+ "prepareSpeech"
1010
+ ],
1011
+ "summary": "Owns detached ordered speech preparation, complete semantic audio reuse, and per-caller cancellation behind AI.prepareTTS.",
1012
+ "availability": "Browser or native WebView with Blob, AbortController, an injected synthesis callback, and optional ready DBOPFS",
1013
+ "protocol": "In-process preparation handle plus caller-owned DBOPFS raw audio and version-1 semantic manifest",
1014
+ "normalization": "Preserves complete original parts and JSON-compatible semantic context, shares pending matching work on the same owner/storage group, admits segments in order, stores complete Blobs and MIME metadata, retains successful audio after failure or cancellation, and separates generation readiness from playback.",
1015
+ "surface": "Named prepareSpeech({owner,parts,originalParts,selection,segmentation,storage,identity,signal,onState,synthesize}) returns {segments,state,ready,getAudio(index),cancel()}; applications use AI.prepareTTS and AI.playPreparedTTS so the shared AI owner retains segmentation, provider readiness, capacity, and playback."
1016
+ },
1021
1017
  {
1022
1018
  "file": "runtime/arcane/modules/QRCode.min.js",
1023
1019
  "name": "QRCode.min.js",
@@ -66,7 +66,7 @@ portable subpaths that resolve directly to canonical runtime-module namespaces
66
66
  from both Node package exports and managed browser keys;
67
67
  `arcane/PreferenceStore` and `arcane/SpeechPlayback` remain their established
68
68
  browser import-map names. The additional portable `arcane-os/speech-text`
69
- subpath owns shared dependency-free speech-input cleanup and has the same
69
+ subpath owns shared speech-input cleanup and has the same
70
70
  managed browser key. There is
71
71
  no exported `importMapApplication()` function, `generateImportMap()` function, or
72
72
  `arcane-os/import-map` package subpath.