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.
- package/CHANGELOG.md +41 -0
- package/README.md +1 -1
- package/browser-runtime/ai/browser-speech-synthesis.mjs +587 -0
- package/browser-runtime/ai/browser-speech.mjs +1 -0
- package/browser-runtime/ai/twin-cloud.mjs +67 -0
- package/docs/reference/ai/browser-speech.md +92 -1
- package/docs/reference/ai/twin-cloud.md +63 -2
- package/docs/reference/availability-and-normalization.md +1 -0
- package/docs/reference/inventory/package-api.json +15 -1
- package/docs/reference/runtime-components.md +13 -2
- package/docs/reference/runtime-modules.md +34 -5
- package/docs/reference/sdk-api.md +54 -0
- package/package.json +1 -1
- package/runtime/arcane/components/speech.html +223 -26
- package/runtime/arcane/modules/AI.js +179 -17
- package/runtime/arcane/modules/SpeechPlayback.js +242 -36
|
@@ -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
|
|
123
|
-
the existing implementation rather than maintain
|
|
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":
|
|
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.
|
|
1686
|
-
|
|
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
|
|
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
|
-
|
|
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`
|
|
3735
|
-
`
|
|
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