arcane-os 0.49.0 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ import {arcaneLogging} from '../logging.mjs';
3
3
 
4
4
  const is = new Is(false);
5
5
  const twinChatURL = 'https://inference.do-ai.run/v1/chat/completions';
6
+ const twinSystemOneURL = 'https://inference.do-ai.run/v1/systemone';
6
7
 
7
8
  /** A stateless TWiN request; browser AI shares the HTTP and format owners below. */
8
9
  export async function fetchRequest({
@@ -87,6 +88,72 @@ export async function fetchRequest({
87
88
  }
88
89
  }
89
90
 
91
+ /** Submit caller-owned state and questions without interpreting the provider's answers. */
92
+ export async function fetchSystemOneRequest({
93
+ twinKey,
94
+ model,
95
+ state,
96
+ questions,
97
+ signal = null,
98
+ id = Date.now(),
99
+ onRequest = function observeSystemOneRequest(){},
100
+ onResponse = function observeSystemOneResponse(){},
101
+ onRetry = null
102
+ } = {}){
103
+ if(signal?.aborted){
104
+ throw normalizeAIRequestAbort(signal.reason);
105
+ }
106
+ if(!is.string(twinKey) || !twinKey){
107
+ const error = new Error('AI provider is not configured.');
108
+ error.code = 'AI_PROVIDER_NOT_CONFIGURED';
109
+ throw error;
110
+ }
111
+ if(!is.string(model) || !model){
112
+ throw new TypeError('TWiN fetchSystemOneRequest requires an explicit model.');
113
+ }
114
+
115
+ const request = {model, state, questions};
116
+ // Capture the caller's complete payload before a diagnostic observer runs.
117
+ const body = JSON.stringify(request);
118
+ try{
119
+ await onRequest(
120
+ request,
121
+ id,
122
+ {operation:'systemone', transport:'http', destination:twinSystemOneURL}
123
+ );
124
+ if(signal?.aborted){
125
+ throw normalizeAIRequestAbort(signal.reason);
126
+ }
127
+ const response = await fetchJSONResponse(
128
+ twinSystemOneURL,
129
+ {
130
+ method:'POST',
131
+ credentials:'omit',
132
+ headers:{
133
+ 'Content-Type':'application/json',
134
+ Authorization:`Bearer ${twinKey}`
135
+ },
136
+ body,
137
+ ...(signal ? {signal} : {})
138
+ },
139
+ {onRetry}
140
+ );
141
+ if(signal?.aborted){
142
+ throw normalizeAIRequestAbort(signal.reason);
143
+ }
144
+ await onResponse(response, id, false);
145
+ if(signal?.aborted){
146
+ throw normalizeAIRequestAbort(signal.reason);
147
+ }
148
+ return response;
149
+ }catch(error){
150
+ if(isAIRequestAbort(error, signal)){
151
+ throw normalizeAIRequestAbort(error);
152
+ }
153
+ throw error;
154
+ }
155
+ }
156
+
90
157
  export function isAIRequestAbort(error, signal){
91
158
  return signal?.aborted
92
159
  || error?.name === 'AbortError'
@@ -1,7 +1,7 @@
1
1
  # Browser speech providers
2
2
 
3
3
  `arcane-os/ai/browser-speech` supplies caller-selected Whisper or native Web
4
- Speech recognition, Kokoro text-to-speech, and TWiN Cloud text-to-speech providers. Its local path
4
+ Speech recognition and synthesis, Kokoro text-to-speech, and TWiN Cloud text-to-speech providers. Its local path
5
5
  provides artifact storage, live module routing, role Workers, provider/2
6
6
  adapters, bounded parallel TTS synthesis, audio normalization, cancellation,
7
7
  and cleanup.
@@ -82,6 +82,97 @@ honestly rather than recording again or silently switching providers. See the
82
82
  [Web Speech specification](https://webaudio.github.io/web-speech-api/#speechreco-methods)
83
83
  for native stop/abort behavior.
84
84
 
85
+ ## Native browser text-to-speech and voice previews
86
+
87
+ `createBrowserSpeechSynthesisProvider({id,model:{id,name?,defaultVoice?},language?})`
88
+ uses the host browser's `speechSynthesis` and `SpeechSynthesisUtterance`.
89
+ The application selects this provider as its default when desired; constructing
90
+ it does not change global preferences, activate Chat speech, or play audio.
91
+ The provider declares `localOnly:false` because a browser voice may use a remote
92
+ service. Individual catalog records expose the browser's `localService` value.
93
+
94
+ ```javascript
95
+ import {createBrowserSpeechSynthesisProvider} from 'arcane-os/ai/browser-speech';
96
+
97
+ const voicePreview = createBrowserSpeechSynthesisProvider({
98
+ id: 'browser-preview',
99
+ model: {id: 'browser-voices', name: 'Browser voices'}
100
+ });
101
+ const unsubscribe = voicePreview.subscribeCatalog(function showVoices(models) {
102
+ // Pass these real records to the application's language/voice selector.
103
+ console.log(models[0].voices);
104
+ });
105
+
106
+ // Call only from the application's explicit Play action.
107
+ function playIntroduction(input, voice) {
108
+ return voicePreview.play({input, voice});
109
+ }
110
+ // The owning view unsubscribes and disposes voicePreview when it closes.
111
+ ```
112
+
113
+ `catalog()` synchronously returns an array of model records. Each model has
114
+ `speech:{playback:'native'}` and `voices:[{id,name,lang,default,localService}]`;
115
+ `id` is the exact native `voiceURI`. `subscribeCatalog(callback)` immediately
116
+ replays that same shape and updates it on `voiceschanged` or a changed default,
117
+ returning an unsubscribe function. An initially empty inventory is ordinary pending browser
118
+ state. There is no polling, discovery utterance, model download, or page-load
119
+ barrier. Language selectors derive their choices from this actual inventory.
120
+
121
+ `provider.setDefaultVoice(voiceURI)` updates the provider's current
122
+ `catalog()[0].defaultVoice` synchronously and returns that current value.
123
+ The application may call it from its catalog subscription after asynchronous
124
+ voice discovery or when its saved selection changes. The SDK supplies no
125
+ voice-name preference: preserve an explicit saved choice in the application
126
+ and pass the exact native `voiceURI`. Repeating the current value is a no-op,
127
+ so a catalog subscription can apply the same choice without notification loops.
128
+ `null`, an empty string, or an omitted argument clears the configured default
129
+ and restores the existing browser-default behavior. A non-string, non-null
130
+ value throws `TypeError`; an unloading or disposed provider retains its
131
+ existing lifecycle error. A voice need not be present when setting the default:
132
+ the existing preparation/playback availability behavior below still applies.
133
+
134
+ Only future preparations use the new default. Explicit request voices and
135
+ already-prepared, queued, or active speech keep their selected voice. Updating
136
+ the default does not load, unload, replace, cancel, pause, resume, or speak.
137
+ AI's ordinary speech path reads this current catalog for new requests, so no
138
+ provider reconfiguration is necessary.
139
+
140
+ `prepare({input,voice?,language?,speed?},{signal?})` returns an inert
141
+ `{kind:'native-speech',input,voice,language,speed,play(options)}` descriptor.
142
+ `play(payload,{signal,onState})` is the explicit-preview convenience. Both
143
+ preserve complete input. Omitted voice uses the current default, initially
144
+ `model.defaultVoice`, or the actual browser default; a supplied voice is never replaced with a named
145
+ SDK alias. Language comes from that voice unless explicitly provided. Neither
146
+ API reads the conversation's language preference. A saved voice waits for
147
+ `voiceschanged` if the inventory is empty; a nonempty inventory missing it
148
+ reports `ARCANE_AI_SPEECH_VOICE_UNAVAILABLE`.
149
+
150
+ Playback returns `{finished,released,state,error,pause(),resume(),stop()}`.
151
+ `finished` resolves `true` on actual native end, `false` on stop/abort, and
152
+ rejects genuine native failures. `released` resolves when native resource
153
+ ownership actually ends: a failed pause/resume/cancel can report an error before
154
+ the utterance terminates. `onState({state,error})` observes queued,
155
+ waiting-for-voices, playing, paused, complete, stopped, or error. Keep complete
156
+ errors in diagnostics and ordinary status in the interface.
157
+
158
+ Preview does not depend on AI mute or model activation. Use a separate provider
159
+ instance when the preview should have a lifetime independent of Chat's selected
160
+ provider. Provider unload/dispose stop their own playback, invalidate prepared
161
+ descriptors, and disposal removes catalog listeners. Web Speech pause/resume/cancel
162
+ operate on the native synthesis object globally; the SDK serializes its own
163
+ utterances and does not claim control isolation from unrelated direct native
164
+ callers. See the [native synthesis contract](https://webaudio.github.io/web-speech-api/#tts-section).
165
+
166
+ For Chat, configure this provider with `ai.configureSpeechProvider('tts',provider)`
167
+ and retain the existing explicit mute/unmute lifecycle. `AI.streamTTS()` and
168
+ `SpeechPlayback` use actual utterance completion and cancellation in original
169
+ order. `AI.prepareTTSPlayback(payload,signal)` returns either real Blob audio or
170
+ the native descriptor without speaking; its signal remains attached by default
171
+ when the returned descriptor is played. `AI.fetchTTS()` and durable
172
+ `AI.prepareTTS()` remain audio-file APIs and report
173
+ `ARCANE_AI_TTS_AUDIO_EXPORT_UNAVAILABLE` for native synthesis, which exposes no
174
+ downloadable audio file.
175
+
85
176
  <a id="digitalocean-fal-text-to-speech"></a>
86
177
 
87
178
  ## TWiN Cloud text-to-speech
@@ -116,11 +116,72 @@ managed import map. Browser Fetch and CORS behavior still apply. Importing it
116
116
  does not instantiate `AI`, read saved preferences, configure speech, or change
117
117
  the existing `arcane-os/ai` browser entry.
118
118
 
119
+ ## Evaluate caller-owned state with System One
120
+
121
+ Use the named `fetchSystemOneRequest` export for the provider's native
122
+ state-and-questions operation. The application supplies the model and complete
123
+ provider-compatible `state` and `questions`; the SDK selects no model or scoring
124
+ policy and assigns no meaning to questions, answer keys, or scales.
125
+
126
+ ```javascript
127
+ import {fetchSystemOneRequest} from 'arcane-os/ai/twin-cloud';
128
+
129
+ const response = await fetchSystemOneRequest({
130
+ twinKey: applicationRuntime.twinKey,
131
+ model: 'typesafe-jev-1.13.0',
132
+ state: applicationState,
133
+ questions: applicationQuestions,
134
+ signal: controller.signal
135
+ });
136
+ ```
137
+
138
+ `applicationRuntime`, `applicationState`, `applicationQuestions`, and
139
+ `controller` are supplied by the application. The example's JEV identifier is
140
+ an explicit caller selection, not an SDK default. For OSS chat-completion models
141
+ such as `openai-gpt-oss-120b` and `openai-gpt-oss-20b`, use `fetchRequest` with
142
+ caller-owned messages and structured-output settings instead. The application
143
+ chooses the operation matching its model's provider contract.
144
+
145
+ ```javascript
146
+ fetchSystemOneRequest({
147
+ twinKey,
148
+ model,
149
+ state,
150
+ questions,
151
+ signal,
152
+ id,
153
+ onRequest,
154
+ onResponse,
155
+ onRetry
156
+ })
157
+ // Promise<complete parsed provider JSON>
158
+ ```
159
+
160
+ The SDK posts exactly `{model,state,questions}` as JSON to
161
+ `https://inference.do-ai.run/v1/systemone`, using `twinKey` only as bearer
162
+ authentication. It adds no prompt, chat envelope, tool call, output limit, or
163
+ answer conversion. Caller content stays unchanged within ordinary JSON
164
+ transport encoding. The request is serialized before `onRequest`, so that
165
+ diagnostic callback cannot rewrite the dispatched payload. The entire parsed
166
+ provider JSON reaches `onResponse` and the returned promise without selecting
167
+ or transforming answers.
168
+
169
+ The explicit key/model requirements, optional `signal`, `id`, callbacks,
170
+ retry observer, complete errors, and lack of retained history follow the shared
171
+ request behavior above. `onRequest(request,id,metadata)` receives
172
+ `{operation:'systemone',transport:'http',destination:'https://inference.do-ai.run/v1/systemone'}`
173
+ as metadata. `onResponse(response,id,false)` receives the complete parsed
174
+ response. Both callbacks are awaited; failures propagate and cancellation is
175
+ checked again after they settle. The existing `fetchJSONResponse` owner
176
+ provides the same HTTP retries and cancellation for this operation; no separate
177
+ transport or retry loop is created.
178
+
119
179
  ### Shared low-level integration helpers
120
180
 
121
181
  The same module also exports the helpers used by browser `AI.js`. Ordinary
122
- callers use `fetchRequest`; these exports let SDK transport integration share
123
- the existing implementation rather than maintain another retry or body reader.
182
+ callers use `fetchRequest` or `fetchSystemOneRequest`; these exports let SDK
183
+ transport integration share the existing implementation rather than maintain
184
+ another retry or body reader.
124
185
 
125
186
  | Export | Contract |
126
187
  | --- | --- |
@@ -80,6 +80,7 @@ version; WebKitGTK availability must not be generalized to macOS.
80
80
  | 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**. |
81
81
  | 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. |
82
82
  | Send one TWiN Cloud request with an explicit key and model | `fetchRequest` from `arcane-os/ai/twin-cloud` | **Node** and **Browser**, using standard Fetch and a remote HTTPS provider | Keeps complete messages and returns the full parsed provider JSON. Rejected Fetch and HTTP 529 share three retries after 3000 ms; HTTP 429 overload retains unlimited three-second retries. Optional `onRetry` reports waiting/requesting phases without blocking recovery. Shared structured-output mapping and cancellation match browser TWiN transport. No browser profile, AI/user singleton, DBOPFS, or retained request history is created. |
83
+ | Evaluate caller-owned state and questions with TWiN System One | `fetchSystemOneRequest` from `arcane-os/ai/twin-cloud` | **Node** and **Browser**, using standard Fetch and a remote HTTPS provider | Posts the explicit model and complete state/questions through the existing JSON transport. Returns the entire parsed provider result and shares its retry, diagnostic, and cancellation behavior. Model choice, question definitions, answer interpretation, and scoring policy stay with the caller; no conversation state is retained. |
83
84
  | Use speech through one application helper | `/arcane/modules/AI.js` and `Arcane.speech` | **Browser** or **Native** | Whisper and Kokoro keep their on-device paths; explicitly selected Web Speech STT and TWiN Cloud TTS declare their non-local behavior. The helper automatically cleans only the outbound synthesis-input copy and normalizes application-facing audio/text behavior while request/response plumbing differs below that boundary. |
84
85
  | 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. |
85
86
  | 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. |
@@ -6,7 +6,7 @@
6
6
  "minimumVersion": "22.23.2 for Node entrypoints",
7
7
  "moduleSystem": "ESM"
8
8
  },
9
- "memberCount": 219,
9
+ "memberCount": 220,
10
10
  "runtimeSubpathPatterns": {
11
11
  "arcane-os/modules/*": "./runtime/arcane/modules/*",
12
12
  "arcane-os/entities/*": "./runtime/arcane/entities/*"
@@ -3452,6 +3452,20 @@
3452
3452
  "protocol": "TWiN Cloud complete-response chat",
3453
3453
  "normalization": "Preserves complete messages and parsed provider JSON; maps explicit structured-output, tool, and reasoning options; shares overload-only HTTP 429 retry after 3000 ms and cancellation; retains no browser profile, storage, or request history"
3454
3454
  },
3455
+ {
3456
+ "id": "twin-cloud:fetchSystemOneRequest",
3457
+ "name": "fetchSystemOneRequest",
3458
+ "displayName": "fetchSystemOneRequest()",
3459
+ "kind": "function",
3460
+ "signature": "async fetchSystemOneRequest({twinKey,model,state,questions,signal=null,id=Date.now(),onRequest,onResponse,onRetry=null}={})",
3461
+ "entrypoints": ["arcane-os/ai/twin-cloud"],
3462
+ "primaryImport": "arcane-os/ai/twin-cloud",
3463
+ "group": "TWiN Cloud state-and-questions requests",
3464
+ "summary": "Sends caller-owned model, state, and questions to the native System One endpoint with explicit credentials.",
3465
+ "availability": "Node and Browser; remote HTTPS provider",
3466
+ "protocol": "TWiN Cloud native System One request",
3467
+ "normalization": "Preserves complete state and questions within JSON transport and returns the full parsed provider result; shares existing JSON transport retry, diagnostics, and cancellation; leaves model choice, scales, and answer interpretation with the caller and retains no history"
3468
+ },
3455
3469
  {
3456
3470
  "id": "twin-cloud:fetchHTTPResponse",
3457
3471
  "name": "fetchHTTPResponse",
@@ -1682,8 +1682,19 @@ On desktop native capture, an accessible editable BCP47 language control occupie
1682
1682
  the feedback area instead of idle transcription/voice readiness boilerplate.
1683
1683
  `recognitionLanguage` defaults to `navigator.language`, accepts an explicit
1684
1684
  language tag without restricting it to the suggested choices, and is passed to
1685
- the capture owner at start. The control is disabled during active capture so
1686
- changes affect the next capture. Native voice loading, errors, and speaking
1685
+ the capture owner at start. Opening or reopening the editable picker shows all
1686
+ suggestions regardless of its saved/current value. Filtering begins only after
1687
+ the user changes the input text; initialization, programmatic configuration,
1688
+ and choosing a suggestion leave the full list available on the next opening.
1689
+ Suggestions display their native language and region names alongside the exact
1690
+ BCP47 tags; they are suggestions, not an exhaustive provider support inventory.
1691
+ The selected or freely typed tag remains unchanged. Arrow keys navigate the
1692
+ suggestions, Enter chooses the active suggestion, and Escape or Tab closes the
1693
+ list. The picker is visible and enabled only for desktop live-transcription
1694
+ mode, including before recording begins. It is disabled during active capture
1695
+ so changes affect the next capture; leaving live-transcription mode closes and
1696
+ disables it. File/model transcription and conversation-language configuration
1697
+ remain separate. Native voice loading, errors, and speaking
1687
1698
  remain visible. Model-based transcription retains its existing status, and
1688
1699
  mobile speech retains its existing voice-output-only presentation.
1689
1700
 
@@ -160,7 +160,7 @@ read-only `ttsSegmentation`, `configureTTSSegmentation()`,
160
160
  `streamTTS(text='',end=false,options={})`,
161
161
  `prepareTTS({parts,storage,identity,signal,onState})`,
162
162
  `playPreparedTTS(prepared,{signal,onState})`,
163
- `finishTTS()`, `fetchTTS()`, `fetchSTT()`, `stopAudio()`, `resumeAudio()`,
163
+ `finishTTS()`, `prepareTTSPlayback()`, `fetchTTS()`, `fetchSTT()`, `stopAudio()`, `resumeAudio()`,
164
164
  `playAudio()`; consumes `user-entity-loaded` and `arcane-ollama-ready`,
165
165
  installs `window.ai`, and emits `ai-ready` and `ai-tts-failure`.
166
166
 
@@ -374,7 +374,7 @@ marks from a cloned outbound input before delegation; the caller's payload stays
374
374
  unchanged. The third `preparation` argument is reserved for SDK-internal
375
375
  delegation, where `{speechInputPrepared:true}` prevents a second cleanup pass;
376
376
  applications omit it. `streamTTS(text='',end=false,options={})` and
377
- `finishTTS()` use this same request boundary. The third-argument options below
377
+ `finishTTS()` use the selected playback boundary. The third-argument options below
378
378
  are available in SDK `0.5.12`. The `textFormat` compatibility extra added in
379
379
  SDK `0.5.16` is ignored beginning in `0.5.17`:
380
380
 
@@ -386,7 +386,7 @@ SDK `0.5.16` is ignored beginning in `0.5.17`:
386
386
  | `waitForPlayback` | `false` | Omission retains the preparation promise. With `true`, the promise resolves after every extracted segment reaches a terminal playback state: `true` when all naturally end, or `false` after terminal cancellation or failure. |
387
387
  | `textFormat` | Ignored compatibility extra | Repeated same formatting marks are removed automatically from every TTS call. This value no longer selects or disables cleanup. |
388
388
 
389
- The voice and speed use the existing `fetchTTS()` validation and error path.
389
+ Audio-file voice and speed use the existing `fetchTTS()` validation and error path.
390
390
  The automatic cleanup changes only the outbound speech-input copy; displayed,
391
391
  stored, model, and caller-owned content remains exact. It is a narrow
392
392
  formatting-mark filter, not a full Markdown parser: links, code contents, list
@@ -405,6 +405,24 @@ for a complete passage. A call extracting no segments resolves
405
405
  `true` without waiting for earlier jobs; `finishTTS()` remains a preparation
406
406
  flush, not a queue-wide playback barrier. A muted call resolves `false`.
407
407
 
408
+ `prepareTTSPlayback(payload,signal,preparation={})` is the silent playback-oriented
409
+ request. Audio-file providers retain the `fetchTTS()` Blob contract; a selected
410
+ model with `speech.playback:'native'` returns an inert `native-speech` descriptor.
411
+ Its `play({signal,onState})` returns native completion and lifecycle controls.
412
+ The preparation signal remains its default playback signal. Native input stays
413
+ complete; per-request voice/language/speed and the configured model default own
414
+ selection, without reading global user voice or conversation-language fields.
415
+ Native streaming jobs wait for actual end in order and allocate no AudioContext.
416
+ When native speech follows recorded audio, the preceding audio clock still owns
417
+ its requested inter-part pause. Native trailing silence delays the next part,
418
+ not the completed playback promise; cancellation retires either pending gap.
419
+ Failed native control remains owned through its `released` promise, so Stop can
420
+ still reach it and subsequent buffered audio cannot overlap it. Explicit saved
421
+ Blob playback continues to use its own AudioContext even when native speech is
422
+ the currently selected provider. `fetchTTS()` and durable `prepareTTS()` report
423
+ `ARCANE_AI_TTS_AUDIO_EXPORT_UNAVAILABLE` for native selection; no audio file is
424
+ fabricated. See [native voice catalogs and previews](ai/browser-speech.md#native-browser-text-to-speech-and-voice-previews).
425
+
408
426
  Playback completion stays pending while the browser waits for an audio-unlock
409
427
  gesture or a recoverable resume attempt. If resuming a closed `AudioContext`
410
428
  fails, the affected jobs terminate and their playback results settle `false`.
@@ -3731,8 +3749,10 @@ new SpeechPlayback({
3731
3749
  })
3732
3750
  ```
3733
3751
 
3734
- `speech` must expose either `fetchTTS(payload, signal)` or
3735
- `synthesize(payload, {signal})`. `SpeechPlayback` also supplies a third
3752
+ `speech` may expose `prepareTTSPlayback(payload,signal)` returning a Blob or
3753
+ native descriptor, a native provider's silent `prepare(payload,{signal})`,
3754
+ `fetchTTS(payload, signal)`, or `synthesize(payload, {signal})`.
3755
+ The playback-oriented method is preferred. `SpeechPlayback` also supplies a third
3736
3756
  SDK-internal preparation object; existing two-argument clients may ignore it.
3737
3757
  `prepare({key,parts,model,voice,responseFormat,
3738
3758
  speed,autoplay=true})` uses only caller-supplied model, voice, and response-format
@@ -3775,6 +3795,15 @@ releases prepared URLs. Replay keeps completed URLs and still-pending provider
3775
3795
  work, then re-submits only failed missing provider segments before starting
3776
3796
  again from index zero.
3777
3797
 
3798
+ Native descriptors are retained separately from Blob URLs and never assigned to
3799
+ an audio element. `autoplay:false` remains silent. Play, Pause, Resume, Stop and
3800
+ Replay use the native control; only a successful current native `finished`
3801
+ advances the next part. Native errors remain observable, and a failed native
3802
+ control stays owned until its optional `released` promise confirms cleanup.
3803
+ Stale completion after stop/restart/disposal cannot advance replacement content.
3804
+ Selecting a native part hides and clears the HTML audio source while preserving
3805
+ the same shared playback state events and complete original parts.
3806
+
3778
3807
  Every preparation owns an operation ID and one AbortController for each active
3779
3808
  synthesis segment or playback delay. Replacement,
3780
3809
  `stop()`, `cancel()`, and `destroy()` abort their owned signals, suppress stale
@@ -123,6 +123,7 @@ browser map are cataloged separately in [Runtime modules](runtime-modules.md).
123
123
  | Member | Kind | Import | Group | Availability |
124
124
  | --- | --- | --- | --- | --- |
125
125
  | `fetchRequest()` | function | `arcane-os/ai/twin-cloud` | TWiN Cloud requests | Node and Browser; remote HTTPS provider |
126
+ | `fetchSystemOneRequest()` | function | `arcane-os/ai/twin-cloud` | TWiN Cloud state-and-questions requests | Node and Browser; remote HTTPS provider |
126
127
  | `fetchHTTPResponse()` | function | `arcane-os/ai/twin-cloud` | Shared AI transport integration | Node and Browser |
127
128
  | `fetchJSONResponse()` | function | `arcane-os/ai/twin-cloud` | Shared AI transport integration | Node and Browser |
128
129
  | `structuredOutputFormat()` | function | `arcane-os/ai/twin-cloud` | Shared AI transport integration | Node and Browser |
@@ -7953,6 +7954,59 @@ console.log(response);
7953
7954
  `server-config.json` is an application-owned, ignored configuration file;
7954
7955
  never commit its key or print it in diagnostics. The SDK does not read it.
7955
7956
 
7957
+ ## fetchSystemOneRequest()
7958
+
7959
+ ### Overview
7960
+
7961
+ Sends one native TWiN System One request with caller-owned credentials, model,
7962
+ state, and questions. Question definitions, scales, model selection, and answer
7963
+ interpretation remain application responsibilities.
7964
+
7965
+ ### Signature and result
7966
+
7967
+ ```text
7968
+ async fetchSystemOneRequest({twinKey,model,state,questions,signal=null,id=Date.now(),onRequest,onResponse,onRetry=null}={})
7969
+ ```
7970
+
7971
+ Import the named function from `arcane-os/ai/twin-cloud`. It posts
7972
+ `{model,state,questions}` to `https://inference.do-ai.run/v1/systemone` and
7973
+ returns the entire parsed provider JSON. It adds no chat messages, tools,
7974
+ scoring rules, or output limit. Payload content is preserved within ordinary
7975
+ JSON transport encoding; serialization occurs before the diagnostic callback.
7976
+
7977
+ `onRequest(request,id,metadata)` receives the complete payload before dispatch,
7978
+ with `{operation:'systemone',transport:'http',destination:'https://inference.do-ai.run/v1/systemone'}`
7979
+ as metadata. `onResponse(response,id,false)` receives the entire parsed result
7980
+ before return. Both callbacks are awaited and failures propagate. The key is
7981
+ used only for transport authentication, outside the diagnostic payloads.
7982
+
7983
+ ### Availability and normalization
7984
+
7985
+ **Node and Browser; Cloud transport.** Uses the existing `fetchJSONResponse`
7986
+ owner for complete errors, retries, `onRetry`, and `signal` cancellation, with
7987
+ no browser singleton, profile, storage, or retained history. A missing key uses
7988
+ `AI_PROVIDER_NOT_CONFIGURED`; a missing explicit model throws `TypeError`.
7989
+ Cancellation prevents successful return and uses `ARCANE_AI_REQUEST_ABORTED`,
7990
+ including checks after callback settlement. Import starts no request.
7991
+
7992
+ ### Example
7993
+
7994
+ ```javascript
7995
+ import {fetchSystemOneRequest} from 'arcane-os/ai/twin-cloud';
7996
+
7997
+ const response = await fetchSystemOneRequest({
7998
+ twinKey: applicationRuntime.twinKey,
7999
+ model: 'typesafe-jev-1.13.0',
8000
+ state: applicationState,
8001
+ questions: applicationQuestions
8002
+ });
8003
+ ```
8004
+
8005
+ The runtime configuration, state, and questions in this example belong to the
8006
+ application. The JEV identifier is an explicit caller choice, not a default.
8007
+ See [TWiN Cloud](ai/twin-cloud.md#evaluate-caller-owned-state-with-system-one)
8008
+ for the complete transport and callback contract.
8009
+
7956
8010
  ## fetchHTTPResponse()
7957
8011
 
7958
8012
  ### Overview
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arcane-os",
3
- "version": "0.49.0",
3
+ "version": "0.51.0",
4
4
  "description": "Arcane OS JavaScript SDK, project-local CLI, browser runtime, and repository-portable application packager.",
5
5
  "type": "module",
6
6
  "main": "./src/index.mjs",