arcane-os 0.93.0 → 0.94.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 +15 -0
- package/README.md +1 -1
- package/browser-runtime/ai/twin-cloud.mjs +109 -46
- package/browser-runtime/core/client.mjs +2 -0
- package/docs/reference/ai/twin-cloud.md +35 -14
- package/docs/reference/availability-and-normalization.md +1 -1
- package/docs/reference/inventory/package-api.json +95 -11
- package/docs/reference/local-ai.md +81 -5
- package/docs/reference/native-speech.md +220 -11
- package/docs/reference/runtime-modules.md +21 -18
- package/docs/reference/sdk-api.md +152 -11
- package/package.json +2 -1
- package/schemas/arcane-app.schema.json +2 -2
- package/schemas/arcane-package.schema.json +2 -2
- package/src/core/services/speech.mjs +85 -23
- package/src/local-ai/config.mjs +12 -1
- package/src/local-ai/dev.mjs +71 -4
- package/src/local-ai/install.mjs +113 -5
- package/src/local-ai/kokoro/frontend.mjs +219 -0
- package/src/local-ai/kokoro/helper.mjs +168 -0
- package/src/local-ai/kokoro/index.mjs +645 -0
- package/src/local-ai/kokoro/native/CMakeLists.txt +45 -0
- package/src/local-ai/kokoro/native/main.cpp +249 -0
- package/src/native/portable-layout.mjs +67 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.94.0
|
|
4
|
+
|
|
5
|
+
- Recover all TWiN HTTP 429 quota responses through the shared chat/System One
|
|
6
|
+
transport. Honor Retry-After or exponential backoff, share a transient
|
|
7
|
+
same-endpoint/credential cooldown, and pace concurrent recovery dispatches.
|
|
8
|
+
Fetch rejection, 429 and 529 share three retries; cancellation stops waits.
|
|
9
|
+
Preserve exact requests and complete terminal errors, including provider
|
|
10
|
+
status_code and nested error records. Do not replay 400/413 errors, consumed
|
|
11
|
+
streams, callbacks, or image submissions.
|
|
12
|
+
- Include the completed native Kokoro synthesis capability: retained voices,
|
|
13
|
+
explicit model preparation, owned cancellation and audio output through the
|
|
14
|
+
shared native speech contract. Reuse its retained compatible runtime and
|
|
15
|
+
source archives alongside the existing native host, Whisper and ONNX assets.
|
|
16
|
+
Package inclusion is distinct from application or native-runtime acceptance.
|
|
17
|
+
|
|
3
18
|
## 0.93.0
|
|
4
19
|
|
|
5
20
|
- Add native desktop notification status, submission, state and removal through
|
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ selected SDK projection or an explicit live SDK source mount. Both profiles
|
|
|
25
25
|
share the theme, packaging, event, cancellation,
|
|
26
26
|
and browser run contracts while retaining their selected application layout.
|
|
27
27
|
|
|
28
|
-
This checkout defines the `0.
|
|
28
|
+
This checkout defines the `0.94.0` SDK contract. Development applications declare
|
|
29
29
|
`arcane-os` as `latest` and retain their lockfile. Exact SDK pins begin when Roshi
|
|
30
30
|
designates a production build. Follow [Consumer updates](docs/consumer-updates.md)
|
|
31
31
|
to refresh and compare the installed SDK and lockfile with the published channel;
|
|
@@ -4,6 +4,8 @@ import {arcaneLogging} from '../logging.mjs';
|
|
|
4
4
|
const is = new Is(false);
|
|
5
5
|
const twinChatURL = 'https://inference.do-ai.run/v1/chat/completions';
|
|
6
6
|
const twinSystemOneURL = 'https://inference.do-ai.run/v1/systemone';
|
|
7
|
+
const activeHTTPRequests = new Map();
|
|
8
|
+
const httpRetryDelayMs = 3000;
|
|
7
9
|
|
|
8
10
|
/** A stateless TWiN request; browser AI shares the HTTP and format owners below. */
|
|
9
11
|
export async function fetchRequest({
|
|
@@ -450,10 +452,24 @@ export function openAIResponseFormat(format){
|
|
|
450
452
|
/** Shared with browser streaming; consume no successful body at this boundary. */
|
|
451
453
|
export async function fetchHTTPResponse(url, options, {onRetry = null} = {}) {
|
|
452
454
|
const {signal} = options;
|
|
453
|
-
const retryDelayMs = 3000;
|
|
454
455
|
const maxRecoveryRetries = 3;
|
|
455
|
-
let recoveryRetries = 0;
|
|
456
456
|
let attempt = 0;
|
|
457
|
+
let retry = null;
|
|
458
|
+
const destination = url?.url ?? String(url);
|
|
459
|
+
const headers = new Headers(options.headers ?? url?.headers);
|
|
460
|
+
const requestOptions = {...options, headers};
|
|
461
|
+
const authorization = headers.get('authorization') ?? '';
|
|
462
|
+
let accounts = activeHTTPRequests.get(destination);
|
|
463
|
+
if (!accounts) {
|
|
464
|
+
accounts = new Map();
|
|
465
|
+
activeHTTPRequests.set(destination, accounts);
|
|
466
|
+
}
|
|
467
|
+
let pacing = accounts.get(authorization);
|
|
468
|
+
if (!pacing) {
|
|
469
|
+
pacing = {active: 0, rateLimited: false, resumeAt: 0, nextDispatchAt: 0, error: null};
|
|
470
|
+
accounts.set(authorization, pacing);
|
|
471
|
+
}
|
|
472
|
+
pacing.active += 1;
|
|
457
473
|
try {
|
|
458
474
|
while (true) {
|
|
459
475
|
if (signal?.aborted) {
|
|
@@ -462,7 +478,7 @@ export async function fetchHTTPResponse(url, options, {onRetry = null} = {}) {
|
|
|
462
478
|
let response;
|
|
463
479
|
let error;
|
|
464
480
|
try {
|
|
465
|
-
response = await
|
|
481
|
+
response = await dispatchHTTPRequest(url, requestOptions, pacing, onRetry, retry, attempt);
|
|
466
482
|
} catch (fetchError) {
|
|
467
483
|
if (isAIRequestAbort(fetchError, signal)) {
|
|
468
484
|
throw normalizeAIRequestAbort(fetchError);
|
|
@@ -483,7 +499,7 @@ export async function fetchHTTPResponse(url, options, {onRetry = null} = {}) {
|
|
|
483
499
|
? await response.json()
|
|
484
500
|
: await response.text();
|
|
485
501
|
} catch (bodyError) {
|
|
486
|
-
if (status !== 529 || isAIRequestAbort(bodyError, signal)) {
|
|
502
|
+
if ((status !== 429 && status !== 529) || isAIRequestAbort(bodyError, signal)) {
|
|
487
503
|
throw bodyError;
|
|
488
504
|
}
|
|
489
505
|
error = bodyError;
|
|
@@ -495,61 +511,108 @@ export async function fetchHTTPResponse(url, options, {onRetry = null} = {}) {
|
|
|
495
511
|
const message = is.string(error)
|
|
496
512
|
? error
|
|
497
513
|
: error?.error?.message ?? error?.message;
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
if (
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
514
|
+
const retryDelayMs = status === 429
|
|
515
|
+
? httpRateLimitDelay(response, httpRetryDelayMs * (2 ** Math.min(attempt, maxRecoveryRetries - 1)))
|
|
516
|
+
: httpRetryDelayMs;
|
|
517
|
+
if (status === 429) {
|
|
518
|
+
pacing.rateLimited = true;
|
|
519
|
+
pacing.resumeAt = Math.max(pacing.resumeAt, Date.now() + retryDelayMs);
|
|
520
|
+
pacing.error = error;
|
|
521
|
+
}
|
|
522
|
+
if ((status !== null && status !== 429 && status !== 529)
|
|
523
|
+
|| attempt >= maxRecoveryRetries) {
|
|
524
|
+
throw error;
|
|
507
525
|
}
|
|
508
526
|
attempt += 1;
|
|
509
527
|
arcaneLogging.warn(
|
|
510
528
|
`${message ?? 'AI request transport failed.'}\nRetrying in ${retryDelayMs / 1000} seconds`,
|
|
511
529
|
error
|
|
512
530
|
);
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
);
|
|
517
|
-
await new Promise(
|
|
518
|
-
function waitForRequestRetry(resolve, reject) {
|
|
519
|
-
function finishRetryDelay() {
|
|
520
|
-
signal?.removeEventListener('abort', cancelRetryDelay);
|
|
521
|
-
resolve();
|
|
522
|
-
}
|
|
523
|
-
function cancelRetryDelay() {
|
|
524
|
-
clearTimeout(timer);
|
|
525
|
-
signal.removeEventListener('abort', cancelRetryDelay);
|
|
526
|
-
reject(normalizeAIRequestAbort(signal.reason));
|
|
527
|
-
}
|
|
528
|
-
const timer = setTimeout(finishRetryDelay, retryDelayMs);
|
|
529
|
-
signal?.addEventListener(
|
|
530
|
-
'abort',
|
|
531
|
-
cancelRetryDelay,
|
|
532
|
-
{once: true}
|
|
533
|
-
);
|
|
534
|
-
if (signal?.aborted) {
|
|
535
|
-
cancelRetryDelay();
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
);
|
|
539
|
-
if (signal?.aborted) {
|
|
540
|
-
throw normalizeAIRequestAbort(signal.reason);
|
|
541
|
-
}
|
|
542
|
-
observeRequestRetry(
|
|
543
|
-
onRetry,
|
|
544
|
-
{phase: 'requesting', attempt, delayMs: retryDelayMs, status, error}
|
|
545
|
-
);
|
|
531
|
+
retry = {phase: 'waiting', attempt, delayMs: retryDelayMs, status, error};
|
|
532
|
+
observeRequestRetry(onRetry, retry);
|
|
533
|
+
await waitForHTTPDelay(retryDelayMs, signal);
|
|
546
534
|
}
|
|
547
535
|
} catch (error) {
|
|
548
536
|
if (isAIRequestAbort(error, signal)) {
|
|
549
537
|
throw normalizeAIRequestAbort(error);
|
|
550
538
|
}
|
|
551
539
|
throw error;
|
|
540
|
+
} finally {
|
|
541
|
+
pacing.active -= 1;
|
|
542
|
+
if (pacing.active === 0) {
|
|
543
|
+
// Retain neither credentials nor quota state beyond the active request group.
|
|
544
|
+
accounts.delete(authorization);
|
|
545
|
+
if (accounts.size === 0) {
|
|
546
|
+
activeHTTPRequests.delete(destination);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function httpRateLimitDelay(response, fallback) {
|
|
553
|
+
const value = response.headers.get('retry-after')?.trim();
|
|
554
|
+
if (!value) return fallback;
|
|
555
|
+
const seconds = Number(value);
|
|
556
|
+
if (is.finite(seconds)) {
|
|
557
|
+
return seconds >= 0 && is.finite(seconds * 1000) ? seconds * 1000 : fallback;
|
|
552
558
|
}
|
|
559
|
+
// Accept HTTP weekday date forms, not an arbitrary numeric string interpreted as a date.
|
|
560
|
+
const date = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun)/i.test(value) ? Date.parse(value) : NaN;
|
|
561
|
+
return is.finite(date) ? Math.max(0, date - Date.now()) : fallback;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
async function dispatchHTTPRequest(url, options, pacing, onRetry, retry, attempt) {
|
|
565
|
+
const {signal} = options;
|
|
566
|
+
let observation = null;
|
|
567
|
+
// Only an observed quota response coordinates otherwise independent requests.
|
|
568
|
+
while (pacing.rateLimited) {
|
|
569
|
+
if (signal?.aborted) throw normalizeAIRequestAbort(signal.reason);
|
|
570
|
+
const delayMs = Math.max(pacing.resumeAt, pacing.nextDispatchAt) - Date.now();
|
|
571
|
+
if (delayMs <= 0) {
|
|
572
|
+
// Claim and initiate Fetch in this continuation, with no intervening asynchronous wait.
|
|
573
|
+
pacing.nextDispatchAt = Date.now() + httpRetryDelayMs;
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
if (!retry && !observation) {
|
|
577
|
+
observation = {phase: 'waiting', attempt, delayMs, status: 429, error: pacing.error};
|
|
578
|
+
observeRequestRetry(onRetry, observation);
|
|
579
|
+
}
|
|
580
|
+
await waitForHTTPDelay(delayMs, signal);
|
|
581
|
+
}
|
|
582
|
+
if (observation && !signal?.aborted) {
|
|
583
|
+
observeRequestRetry(onRetry, {...observation, phase: 'requesting'});
|
|
584
|
+
}
|
|
585
|
+
if (retry) {
|
|
586
|
+
observeRequestRetry(onRetry, {...retry, phase: 'requesting'});
|
|
587
|
+
}
|
|
588
|
+
if (signal?.aborted) throw normalizeAIRequestAbort(signal.reason);
|
|
589
|
+
return fetch(url, options);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
async function waitForHTTPDelay(delayMs, signal) {
|
|
593
|
+
let remaining = delayMs;
|
|
594
|
+
do {
|
|
595
|
+
if (signal?.aborted) throw normalizeAIRequestAbort(signal.reason);
|
|
596
|
+
// Only split at the host timer range; never shorten the provider's requested wait.
|
|
597
|
+
const milliseconds = Math.min(remaining, 2147483647);
|
|
598
|
+
await new Promise(
|
|
599
|
+
function waitForRequestRetry(resolve, reject) {
|
|
600
|
+
function finishRetryDelay() {
|
|
601
|
+
signal?.removeEventListener('abort', cancelRetryDelay);
|
|
602
|
+
resolve();
|
|
603
|
+
}
|
|
604
|
+
function cancelRetryDelay() {
|
|
605
|
+
clearTimeout(timer);
|
|
606
|
+
signal.removeEventListener('abort', cancelRetryDelay);
|
|
607
|
+
reject(normalizeAIRequestAbort(signal.reason));
|
|
608
|
+
}
|
|
609
|
+
const timer = setTimeout(finishRetryDelay, milliseconds);
|
|
610
|
+
signal?.addEventListener('abort', cancelRetryDelay, {once: true});
|
|
611
|
+
if (signal?.aborted) cancelRetryDelay();
|
|
612
|
+
}
|
|
613
|
+
);
|
|
614
|
+
remaining -= milliseconds;
|
|
615
|
+
} while (remaining > 0);
|
|
553
616
|
}
|
|
554
617
|
|
|
555
618
|
function observeRequestRetry(onRetry, state) {
|
|
@@ -598,6 +598,8 @@ export function createCoreFacade(client){
|
|
|
598
598
|
remove:name=>invoke('environment.delete',{name})},
|
|
599
599
|
mail:{send:request=>invoke('mail.send',request??{},{timeoutMs:450000})},
|
|
600
600
|
speech:{status:()=>invoke('speech.status',{},{timeoutMs:10000}),
|
|
601
|
+
load:function loadSpeech(request,options){return invoke('speech.load',request??{},{timeoutMs:0,signal:options?.signal,onRequest:options?.onRequest});},
|
|
602
|
+
unload:function unloadSpeech(request,options){return invoke('speech.unload',request??{},{timeoutMs:0,signal:options?.signal,onRequest:options?.onRequest});},
|
|
601
603
|
synthesize:(request,options)=>invoke('speech.synthesize',request??{},{timeoutMs:180000,signal:options?.signal}),
|
|
602
604
|
transcribe:(request,options)=>invoke('speech.transcribe',request??{},{timeoutMs:180000,signal:options?.signal,onRequest:options?.onRequest})},
|
|
603
605
|
localAI:{status:()=>invoke('localai.status',{},{timeoutMs:15000}),
|
|
@@ -94,17 +94,34 @@ The key is
|
|
|
94
94
|
transport authentication, not part of either callback's message payload. Keep
|
|
95
95
|
credentials out of application logging as well.
|
|
96
96
|
|
|
97
|
-
Before a successful response is consumed,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
97
|
+
Before a successful response is consumed, rejected Fetch calls and HTTP `429`
|
|
98
|
+
or `529` share a budget of three retries (four total attempts). Every `429`
|
|
99
|
+
qualifies, including request-per-minute and token-per-minute quota responses;
|
|
100
|
+
the error message does not select recovery. A readable `Retry-After` header
|
|
101
|
+
supplies the `429` delay as seconds or an HTTP date. Otherwise the upcoming
|
|
102
|
+
retry number selects a `3000`, `6000`, or `12000` millisecond delay. Rejected
|
|
103
|
+
Fetch and `529` retain their `3000` millisecond delay. A provider's longer wait
|
|
104
|
+
is preserved, split only at the host timer's range when necessary.
|
|
105
|
+
|
|
106
|
+
After an observed `429`, overlapping requests through this module with the
|
|
107
|
+
same exact endpoint and Authorization value share the latest cooldown and
|
|
108
|
+
dispatch at least three seconds apart. A later quota response extends that
|
|
109
|
+
cooldown, including a terminal quota response while sibling calls remain active;
|
|
110
|
+
its fallback remains at most `12000` milliseconds. Different endpoints and credentials remain independent, and requests
|
|
111
|
+
before any quota response remain concurrent. This is active-operation pacing,
|
|
112
|
+
not a persistent global rate limiter: the module releases the group, including
|
|
113
|
+
its credential key and error, when its last HTTP operation settles. It does not
|
|
114
|
+
coordinate separate tabs, processes, or independently loaded module instances.
|
|
115
|
+
|
|
116
|
+
Each attempt reuses the exact destination, Fetch option values, serialized request,
|
|
117
|
+
and signal. Headers are normalized once through standard Fetch `Headers` and
|
|
118
|
+
retained for retries, including when the caller supplied a one-shot iterable.
|
|
119
|
+
Other HTTP errors (including `400` and `413`), successful-response
|
|
120
|
+
decoding failures, and application callback failures do not retry. A known
|
|
121
|
+
`429` or `529` also retries when reading its diagnostic body fails;
|
|
122
|
+
`onRetry.error` retains that exact failure. The last complete error is thrown
|
|
123
|
+
unchanged on exhaustion, preserving provider fields such as `status_code` and
|
|
124
|
+
nested `error.type`/`error.message`. No error envelope is rebuilt or sanitized.
|
|
108
125
|
Pass a fresh
|
|
109
126
|
`AbortController`'s `signal` and call `abort()` to cancel. Cancellation during
|
|
110
127
|
the request, response-body read, retry wait, or callback settlement prevents
|
|
@@ -114,12 +131,16 @@ A missing key uses `AI_PROVIDER_NOT_CONFIGURED`, a missing explicit model
|
|
|
114
131
|
throws `TypeError`, and an unsupported `structuredOutput` input uses
|
|
115
132
|
`AI_STRUCTURED_OUTPUT_INVALID`.
|
|
116
133
|
|
|
117
|
-
Optional `onRetry({phase,attempt,delayMs,status,error})` observes
|
|
134
|
+
Optional `onRetry({phase,attempt,delayMs,status,error})` observes recovery.
|
|
118
135
|
`phase:'waiting'` arrives before the abortable delay; `phase:'requesting'`
|
|
119
136
|
arrives immediately before the next Fetch. `attempt` is the one-based upcoming
|
|
120
|
-
retry number across
|
|
137
|
+
retry number across the shared budget, `delayMs` is the selected wait, `status` is the
|
|
121
138
|
HTTP status or `null` for a rejected Fetch, and `error` is the complete original
|
|
122
|
-
failure value.
|
|
139
|
+
failure value. An initial request waiting behind an already observed quota
|
|
140
|
+
reports `attempt:0`, `status:429`, and that complete quota error. Shared pacing
|
|
141
|
+
can extend the actual wait beyond its initial observation; `requesting` is
|
|
142
|
+
emitted only after that wait, immediately before dispatch. This observer runs
|
|
143
|
+
synchronously without awaiting its returned
|
|
123
144
|
promise. Synchronous throws and rejected promises are reported through the
|
|
124
145
|
shared console logger and cannot change the request outcome or trigger another
|
|
125
146
|
retry. `onRequest` still runs once per logical request. Retry observations stay
|
|
@@ -99,7 +99,7 @@ where listed. See [native output and host requirements](core-native-packaging.md
|
|
|
99
99
|
| Label speakers in caller-fed mono audio | [`arcane-os/diarization`, `arcane-os/core/diarization`](diarization.md) | **Node** with built helper, selected official NeMo libraries and Nemotron model; official CPU archives cover Windows x64 and Linux/macOS x64/arm64 | Independent retained streams, complete timed segments and optional probability frames. Generic labels are not personal identities or speech transcripts; cancellation and close observe native cleanup. Android needs host adaptation. |
|
|
100
100
|
| 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**. |
|
|
101
101
|
| 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. |
|
|
102
|
-
| 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
|
|
102
|
+
| 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 all HTTP 429/529 share three retries. Quota recovery honors Retry-After or exponential delay; active same-endpoint/credential requests share cooldown and paced dispatch. Optional `onRetry` reports waiting/requesting without blocking recovery. Complete errors and cancellation match browser TWiN transport. No browser profile, AI/user singleton, DBOPFS, or retained request history is created. |
|
|
103
103
|
| 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. |
|
|
104
104
|
| Generate images from a complete caller-owned prompt | `generateImages` from `arcane-os/ai/twin-cloud` | **Node** and **Browser**, using standard Fetch, Blob, and a remote HTTPS provider | Caller selects `fal-ai/flux/schnell` or `stable-diffusion-3.5-large`, credentials, and provider parameters. Returns every image as a Blob with media metadata in provider order; owns progress, job polling, and cancellation. Submission is not automatically replayed after an ambiguous failure. Display and storage stay application-owned. |
|
|
105
105
|
| 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/TTS and TWiN Cloud TTS declare their non-local behavior. `prepareTTSPlayback` supports real audio and silent native descriptors; `fetchTTS` and durable `prepareTTS` require real audio. Provider choice, model, voice, and credentials stay application-owned. |
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"minimumVersion": "22.23.2 for Node entrypoints",
|
|
7
7
|
"moduleSystem": "ESM"
|
|
8
8
|
},
|
|
9
|
-
"memberCount":
|
|
9
|
+
"memberCount": 314,
|
|
10
10
|
"runtimeSubpathPatterns": {
|
|
11
11
|
"arcane-os/modules/*": "./runtime/arcane/modules/*",
|
|
12
12
|
"arcane-os/entities/*": "./runtime/arcane/entities/*"
|
|
@@ -166,6 +166,90 @@
|
|
|
166
166
|
"protocol": "arcane/1 service definition",
|
|
167
167
|
"normalization": "Binding identity equals the named createNativeDecisionService export"
|
|
168
168
|
},
|
|
169
|
+
{
|
|
170
|
+
"id": "local-ai-kokoro:createNativeKokoroRuntime",
|
|
171
|
+
"name": "createNativeKokoroRuntime",
|
|
172
|
+
"displayName": "createNativeKokoroRuntime()",
|
|
173
|
+
"kind": "function",
|
|
174
|
+
"signature": "createNativeKokoroRuntime({onnx,modelAssets,runtime,prepare,modelId='kokoro',model=KOKORO_MODEL,revision=KOKORO_REVISION,dtype='fp32',paths,assetProjectionId,resourcePaths,sessionOptions,executionPreference='gpu',executionTarget,signal,onEvent}={})",
|
|
175
|
+
"entrypoints": ["arcane-os/local-ai/kokoro"],
|
|
176
|
+
"primaryImport": "arcane-os/local-ai/kokoro",
|
|
177
|
+
"group": "Core native speech",
|
|
178
|
+
"summary": "Composes the selected Kokoro FP32 graph with the host's existing ONNX/model-resource owners and a persistent native phonemization/Opus helper.",
|
|
179
|
+
"availability": "Node with matching prepared helper/data and ONNX resources; SDK helper archive for Windows x64, other hosts require a matching custom helper distribution",
|
|
180
|
+
"protocol": "Replaying kokoro.state, retained ONNX activation and complete ordered native speech requests",
|
|
181
|
+
"normalization": "Returns current/subscribe/load/synthesize/unload/close; construction performs no preparation or inference. Explicit load selects a DBOPFS projection or complete native resource paths; synthesis retains complete ordered input, selected US/GB voice and 24kHz mono WAV or Ogg Opus output. Active cancellation joins owned helper/session retirement and preserves surviving queued work on the same configured provider; ONNX native interruption may wait for the current call. No alternate model, voice or provider retry is introduced. See native-speech.md for exact activation, selection and result contracts."
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"id": "local-ai-kokoro:default",
|
|
185
|
+
"name": "default",
|
|
186
|
+
"displayName": "createNativeKokoroRuntime default export",
|
|
187
|
+
"kind": "function",
|
|
188
|
+
"signature": "default as createNativeKokoroRuntime",
|
|
189
|
+
"entrypoints": ["arcane-os/local-ai/kokoro"],
|
|
190
|
+
"primaryImport": "arcane-os/local-ai/kokoro",
|
|
191
|
+
"group": "Core native speech",
|
|
192
|
+
"summary": "Default binding for the same native Kokoro engine factory.",
|
|
193
|
+
"availability": "Node with matching prepared native resources",
|
|
194
|
+
"protocol": "Native Kokoro engine lifecycle",
|
|
195
|
+
"normalization": "Binding identity equals the named createNativeKokoroRuntime export"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"id": "local-ai-kokoro:KOKORO_MODEL",
|
|
199
|
+
"name": "KOKORO_MODEL",
|
|
200
|
+
"displayName": "KOKORO_MODEL",
|
|
201
|
+
"kind": "constant",
|
|
202
|
+
"signature": "const KOKORO_MODEL",
|
|
203
|
+
"entrypoints": ["arcane-os/local-ai/kokoro"],
|
|
204
|
+
"primaryImport": "arcane-os/local-ai/kokoro",
|
|
205
|
+
"group": "Core native speech",
|
|
206
|
+
"summary": "Identifies the Kokoro model implemented by the native frontend.",
|
|
207
|
+
"availability": "Node",
|
|
208
|
+
"protocol": "Native model selection",
|
|
209
|
+
"normalization": "Value is onnx-community/Kokoro-82M-v1.0-ONNX; constructor selection preserves this model's FP32 graph and resource contract"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"id": "local-ai-kokoro:KOKORO_REVISION",
|
|
213
|
+
"name": "KOKORO_REVISION",
|
|
214
|
+
"displayName": "KOKORO_REVISION",
|
|
215
|
+
"kind": "constant",
|
|
216
|
+
"signature": "const KOKORO_REVISION",
|
|
217
|
+
"entrypoints": ["arcane-os/local-ai/kokoro"],
|
|
218
|
+
"primaryImport": "arcane-os/local-ai/kokoro",
|
|
219
|
+
"group": "Core native speech",
|
|
220
|
+
"summary": "Identifies the selected upstream Kokoro model revision.",
|
|
221
|
+
"availability": "Node",
|
|
222
|
+
"protocol": "Native model resource selection",
|
|
223
|
+
"normalization": "Value is 1939ad2a8e416c0acfeecc08a694d14ef25f2231; graph, tokenizer and voice resources use this same revision"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"id": "local-ai-kokoro:KOKORO_SAMPLE_RATE",
|
|
227
|
+
"name": "KOKORO_SAMPLE_RATE",
|
|
228
|
+
"displayName": "KOKORO_SAMPLE_RATE",
|
|
229
|
+
"kind": "constant",
|
|
230
|
+
"signature": "const KOKORO_SAMPLE_RATE",
|
|
231
|
+
"entrypoints": ["arcane-os/local-ai/kokoro"],
|
|
232
|
+
"primaryImport": "arcane-os/local-ai/kokoro",
|
|
233
|
+
"group": "Core native speech",
|
|
234
|
+
"summary": "Native Kokoro PCM synthesis rate in samples per second.",
|
|
235
|
+
"availability": "Node",
|
|
236
|
+
"protocol": "Audio format",
|
|
237
|
+
"normalization": "Value is 24000; the selected output is mono WAV or Ogg Opus with the complete synthesized sample sequence"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"id": "local-ai-kokoro:KOKORO_VOICES",
|
|
241
|
+
"name": "KOKORO_VOICES",
|
|
242
|
+
"displayName": "KOKORO_VOICES",
|
|
243
|
+
"kind": "constant",
|
|
244
|
+
"signature": "const KOKORO_VOICES",
|
|
245
|
+
"entrypoints": ["arcane-os/local-ai/kokoro"],
|
|
246
|
+
"primaryImport": "arcane-os/local-ai/kokoro",
|
|
247
|
+
"group": "Core native speech",
|
|
248
|
+
"summary": "The 28 supported US and British English voice identifiers for the selected native Kokoro resources.",
|
|
249
|
+
"availability": "Node",
|
|
250
|
+
"protocol": "Native speech voice selection",
|
|
251
|
+
"normalization": "Complete ordered voice array exported by the frontend; af_heart is the omitted voice default. An unsupported explicit voice reports its actual incompatibility without substitution."
|
|
252
|
+
},
|
|
169
253
|
{
|
|
170
254
|
"id": "local-ai-whisper:createWhisperRuntime",
|
|
171
255
|
"name": "createWhisperRuntime",
|
|
@@ -345,8 +429,8 @@
|
|
|
345
429
|
"group": "Core native speech",
|
|
346
430
|
"summary": "Composes host-supplied transcription and synthesis engines with independent loading and role readiness.",
|
|
347
431
|
"availability": "Node Core with explicitly supplied engines; engine platform, model and format support remain engine-owned",
|
|
348
|
-
"protocol": "arcane/1 speech.status/transcribe/synthesize with speech.state/progress",
|
|
349
|
-
"normalization": "Returns current/subscribe/close/start/methods/drain/dispose; forwards complete requests and results unchanged; replaying service state, synchronous accepted Thinking, combined request/lifetime cancellation and concurrent joined engine shutdown;
|
|
432
|
+
"protocol": "arcane/1 speech.status/load/unload/transcribe/synthesize with speech.state/progress",
|
|
433
|
+
"normalization": "Returns current/subscribe/close/start/methods/drain/dispose; forwards complete requests and results unchanged; replaying service state, synchronous accepted Thinking, combined request/lifetime cancellation and concurrent joined engine shutdown. Explicit load/unload require role stt or tts and forward the remaining activation fields and complete result through that role's configured engine; supported preparation remains with that engine. Startup waiting is independently owned from caller cancellation; no automatic provider selection is introduced."
|
|
350
434
|
},
|
|
351
435
|
{
|
|
352
436
|
"id": "core-speech:default",
|
|
@@ -609,10 +693,10 @@
|
|
|
609
693
|
"entrypoints": ["arcane-os/local-ai"],
|
|
610
694
|
"primaryImport": "arcane-os/local-ai",
|
|
611
695
|
"group": "Core local AI",
|
|
612
|
-
"summary": "Reuses selected managed native runtimes or installs complete llama.cpp/Ollama/image distributions, ONNX npm runtime trees with selected SDK native libraries, or
|
|
696
|
+
"summary": "Reuses selected managed native runtimes or installs complete llama.cpp/Ollama/image distributions, ONNX npm runtime trees with selected SDK native libraries, NeMo libraries, or Kokoro native helper/data trees.",
|
|
613
697
|
"availability": "Node; selected distribution platform and architecture assets determine runtime availability",
|
|
614
698
|
"protocol": "Upstream release archives and selected ONNX/Koffi npm installations; corrected Windows x64 ONNX native libraries from the installed SDK numeric release",
|
|
615
|
-
"normalization": "Returns absolute runtime records, including image library/binding/variant/model metadata; Windows x64 ONNX with no explicit URL and omitted version or 1.30.0 adds nativeDistributionRevision 1.30.0-directml-reshape-1, reuses that revision or prepares a fresh installation while preserving older trees; explicit URLs and other ONNX versions/platforms retain their upstream package path; shares matching installs, preserves libraries, reports failures without changing global PATH or services and prepares no model files"
|
|
699
|
+
"normalization": "Returns absolute runtime records, including image library/binding/variant/model metadata; Windows x64 ONNX with no explicit URL and omitted version or 1.30.0 adds nativeDistributionRevision 1.30.0-directml-reshape-1, reuses that revision or prepares a fresh installation while preserving older trees; explicit URLs and other ONNX versions/platforms retain their upstream package path; shares matching installs, preserves libraries, reports failures without changing global PATH or services and prepares no model files. Kokoro returns helperExecutable, espeakDataDirectory and libraryDirectory for the complete selected helper tree; Windows x64 defaults to the installed SDK numeric release, while explicit url/helperRoot supplies another prepared distribution and preserves model/ONNX ownership."
|
|
616
700
|
},
|
|
617
701
|
{
|
|
618
702
|
"id": "local-ai:bundleLocalAIRuntimes",
|
|
@@ -626,7 +710,7 @@
|
|
|
626
710
|
"summary": "Copies selected complete runtime distributions into a fresh native artifact staging root.",
|
|
627
711
|
"availability": "Node; supports bundling selected published platform assets independently of the build host",
|
|
628
712
|
"protocol": "Artifact-relative runtime/local-ai layout",
|
|
629
|
-
"normalization": "Returns {runtimes,files} with artifact-relative runtime/variant paths and complete inventory; corrected Windows x64 ONNX retains nativeDistributionRevision and complete native libraries while modulePath becomes artifact-relative; image URL descriptors remain for post-launch preparation and external model working paths report portability incompatibility"
|
|
713
|
+
"normalization": "Returns {runtimes,files} with artifact-relative runtime/variant paths and complete inventory; corrected Windows x64 ONNX retains nativeDistributionRevision and complete native libraries while modulePath becomes artifact-relative; image URL descriptors remain for post-launch preparation and external model working paths report portability incompatibility. Kokoro retains the complete helper/data tree and relocates helperExecutable, espeakDataDirectory and libraryDirectory; ONNX and model resources retain their separate owners."
|
|
630
714
|
},
|
|
631
715
|
{
|
|
632
716
|
"id": "root:WS",
|
|
@@ -4122,7 +4206,7 @@
|
|
|
4122
4206
|
"summary": "Sends one complete TWiN Cloud request with an explicit caller-owned key and model.",
|
|
4123
4207
|
"availability": "Node and Browser; remote HTTPS provider",
|
|
4124
4208
|
"protocol": "TWiN Cloud complete-response chat",
|
|
4125
|
-
"normalization": "Preserves complete messages and
|
|
4209
|
+
"normalization": "Preserves complete messages and provider JSON; Fetch rejection and all HTTP 429/529 share three retries; quota recovery honors Retry-After or exponential delay with transient same-endpoint/credential pacing, complete terminal errors and cancellation; retains no browser profile, storage, or history"
|
|
4126
4210
|
},
|
|
4127
4211
|
{
|
|
4128
4212
|
"id": "twin-cloud:fetchSystemOneRequest",
|
|
@@ -4171,21 +4255,21 @@
|
|
|
4171
4255
|
"name": "fetchHTTPResponse",
|
|
4172
4256
|
"displayName": "fetchHTTPResponse()",
|
|
4173
4257
|
"kind": "function",
|
|
4174
|
-
"signature": "async fetchHTTPResponse(url,options)",
|
|
4258
|
+
"signature": "async fetchHTTPResponse(url,options,{onRetry=null}={})",
|
|
4175
4259
|
"entrypoints": ["arcane-os/ai/twin-cloud"],
|
|
4176
4260
|
"primaryImport": "arcane-os/ai/twin-cloud",
|
|
4177
4261
|
"group": "Shared AI transport integration",
|
|
4178
4262
|
"summary": "Returns a successful unconsumed Fetch Response through the shared AI HTTP owner.",
|
|
4179
4263
|
"availability": "Node and Browser",
|
|
4180
4264
|
"protocol": "Shared AI HTTP transport",
|
|
4181
|
-
"normalization": "Preserves caller Fetch options and complete
|
|
4265
|
+
"normalization": "Preserves caller Fetch options and complete errors; Fetch rejection and all HTTP 429/529 share three retries; Retry-After or exponential quota delay and transient same-endpoint/credential pacing remain abortable; onRetry observes waiting/requesting; cancellation uses ARCANE_AI_REQUEST_ABORTED"
|
|
4182
4266
|
},
|
|
4183
4267
|
{
|
|
4184
4268
|
"id": "twin-cloud:fetchJSONResponse",
|
|
4185
4269
|
"name": "fetchJSONResponse",
|
|
4186
4270
|
"displayName": "fetchJSONResponse()",
|
|
4187
4271
|
"kind": "function",
|
|
4188
|
-
"signature": "async fetchJSONResponse(url,options)",
|
|
4272
|
+
"signature": "async fetchJSONResponse(url,options,{onRetry=null}={})",
|
|
4189
4273
|
"entrypoints": ["arcane-os/ai/twin-cloud"],
|
|
4190
4274
|
"primaryImport": "arcane-os/ai/twin-cloud",
|
|
4191
4275
|
"group": "Shared AI transport integration",
|
|
@@ -4360,7 +4444,7 @@
|
|
|
4360
4444
|
"summary": "Projects a Core client into the established application-facing Arcane namespace.",
|
|
4361
4445
|
"availability": "Browser and native WebView JavaScript hosts with a Core client",
|
|
4362
4446
|
"protocol": "arcane/1 compatibility facade",
|
|
4363
|
-
"normalization": "Routes namespace methods through client.invoke while retaining operation-specific parameters, correlation, streaming callbacks, timeouts and cancellation; window.state({signal}?) reads the requesting window and window.setState({state},{signal}?) selects normal, maximized or fullscreen. The matching Windows host returns {platform:'windows',supported:true,state}, including observed minimized state, restores normal bounds/frame controls on leaving fullscreen and prevents activation/focus assignment during visible state transitions without changing TopMost, Core, origin or profile. Saved Settings remain application-owned; cancellation does not undo an applied change and unavailable hosts retain their actual errors without fallback. window.setTheme(presentation,{signal}?) forwards the complete per-window backgroundColor/textColor record, with omitted fields unchanged and null reset, and returns the host's actual applied/unsupported result without changing system appearance. notifications.status/show/state/close forward complete caller requests and standard invoke options; status normalizes only METHOD_NOT_ALLOWED with core-namespace-unavailable while retaining the complete original error. Matching native window hosts retain complete notification records and ordered revisions across renderer navigation, with notifications.state events and subscribe-before-snapshot recovery. Submitted means native Show returned, not displayed or read; cancellation after submission does not remove an accepted notice, and explicit close retains its record. Recipient, text, trigger, deduplication and navigation policy remains application-owned"
|
|
4447
|
+
"normalization": "Routes namespace methods through client.invoke while retaining operation-specific parameters, correlation, streaming callbacks, timeouts and cancellation; window.state({signal}?) reads the requesting window and window.setState({state},{signal}?) selects normal, maximized or fullscreen. The matching Windows host returns {platform:'windows',supported:true,state}, including observed minimized state, restores normal bounds/frame controls on leaving fullscreen and prevents activation/focus assignment during visible state transitions without changing TopMost, Core, origin or profile. Saved Settings remain application-owned; cancellation does not undo an applied change and unavailable hosts retain their actual errors without fallback. window.setTheme(presentation,{signal}?) forwards the complete per-window backgroundColor/textColor record, with omitted fields unchanged and null reset, and returns the host's actual applied/unsupported result without changing system appearance. notifications.status/show/state/close forward complete caller requests and standard invoke options; status normalizes only METHOD_NOT_ALLOWED with core-namespace-unavailable while retaining the complete original error. Matching native window hosts retain complete notification records and ordered revisions across renderer navigation, with notifications.state events and subscribe-before-snapshot recovery. Submitted means native Show returned, not displayed or read; cancellation after submission does not remove an accepted notice, and explicit close retains its record. Recipient, text, trigger, deduplication and navigation policy remains application-owned. speech.load(request,options) and speech.unload(request,options) forward complete activation requests, cancellation and request observers with no elapsed-time cutoff; selected engines own preparation and native retirement."
|
|
4364
4448
|
},
|
|
4365
4449
|
{
|
|
4366
4450
|
"id": "core-client:installCoreClient",
|