arcane-os 0.68.0 → 0.70.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 +36 -0
- package/README.md +9 -4
- package/browser-runtime/ai/browser-decisions.mjs +46 -2
- package/browser-runtime/ai/browser-speech-artifacts.mjs +58 -62
- package/browser-runtime/ai/browser-speech-providers.mjs +8 -3
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +76 -164
- package/browser-runtime/ai/dbopfs-model-parts.mjs +344 -0
- package/browser-runtime/ai/dbopfs-model-resources.mjs +190 -0
- package/browser-runtime/ai/decision-runtime.mjs +17 -1
- package/browser-runtime/ai/decision-worker.mjs +21 -1
- package/browser-runtime/ai/model-resource-bridge.mjs +231 -0
- package/browser-runtime/ai/speech-worker-client.mjs +68 -28
- package/browser-runtime/ai/speech-worker-runtime.mjs +212 -97
- package/browser-runtime/core/contracts.mjs +1 -1
- package/docs/reference/README.md +2 -0
- package/docs/reference/ai/browser-decisions.md +57 -3
- package/docs/reference/ai/browser-speech.md +94 -26
- package/docs/reference/ai/browser-wasm.md +28 -20
- package/docs/reference/core-native-packaging.md +54 -0
- package/docs/reference/core-runtime.md +9 -0
- package/docs/reference/core-shared-host.md +190 -0
- package/docs/reference/inventory/package-api.json +3 -3
- package/docs/reference/inventory/runtime-modules.json +3 -3
- package/docs/reference/runtime-components.md +4 -2
- package/docs/reference/runtime-modules.md +120 -20
- package/docs/reference/sdk-api.md +64 -30
- package/package.json +2 -2
- package/runtime/arcane/components/theme-switcher.html +1 -1
- package/runtime/arcane/modules/AI.js +7 -22
- package/runtime/arcane/modules/AIProviderRuntime.js +84 -6
- package/runtime/arcane/modules/DBOPFS.js +180 -26
- package/schemas/arcane-app.schema.json +10 -0
- package/src/app-descriptor.mjs +23 -1
- package/src/core/host.mjs +2 -0
- package/src/core/hosts/windows/ArcaneHost.cs +46 -0
- package/src/core/hosts/windows/ArcaneLauncher.cs +21 -0
- package/src/core/runtime.mjs +9 -4
- package/src/core/services/packaged-web.mjs +8 -1
- package/src/core/shared-host.mjs +500 -0
- package/src/native/portable-layout.mjs +66 -34
- package/src/native/portable-provider.mjs +1 -0
|
@@ -170,7 +170,7 @@ default `AI`; read-only `providerRuntime`, `speechActivationPending`, `browserSp
|
|
|
170
170
|
`streamRequest()`, `streamMessage()`, `fetchRequest()`, `fetch()`,
|
|
171
171
|
read-only `ttsSegmentation`, `configureTTSSegmentation()`,
|
|
172
172
|
`streamTTS(text='',end=false,options={})`,
|
|
173
|
-
`prepareTTS({parts,storage,identity,signal,onState})`,
|
|
173
|
+
`prepareTTS({parts,textFormat,storage,identity,signal,onState})`,
|
|
174
174
|
`playPreparedTTS(prepared,{signal,onState})`,
|
|
175
175
|
`finishTTS()`, `prepareTTSPlayback()`, `fetchTTS()`, `fetchSTT()`, `stopAudio()`, `resumeAudio()`,
|
|
176
176
|
`playAudio()`; consumes `user-entity-loaded` and `arcane-ollama-ready`,
|
|
@@ -393,14 +393,17 @@ synthesis payload to `Arcane.speech.synthesize(request, {signal})`; Core aborts
|
|
|
393
393
|
are normalized to `AbortError` with `ARCANE_AI_REQUEST_ABORTED`. Actual engine
|
|
394
394
|
interruption belongs to the registered service. It does not independently
|
|
395
395
|
choose a provider, cloud fallback, model, runtime, or
|
|
396
|
-
voice policy for the application.
|
|
397
|
-
marks from a cloned outbound input before delegation; the caller's
|
|
398
|
-
unchanged.
|
|
396
|
+
voice policy for the application. By default, calls remove repeated same
|
|
397
|
+
formatting marks from a cloned outbound input before delegation; the caller's
|
|
398
|
+
payload stays unchanged. Public payload field `textFormat:'plain'` preserves
|
|
399
|
+
the complete input, including whitespace and repeated marks. The SDK consumes
|
|
400
|
+
that field before provider/host dispatch. Omission and other values retain the
|
|
401
|
+
default cleanup. The third `preparation` argument is reserved for SDK-internal
|
|
399
402
|
delegation, where `{speechInputPrepared:true}` prevents a second cleanup pass;
|
|
400
403
|
applications omit it. `streamTTS(text='',end=false,options={})` and
|
|
401
404
|
`finishTTS()` use the selected playback boundary. The third-argument options below
|
|
402
|
-
are available in SDK `0.5.12`.
|
|
403
|
-
SDK `0.5.16`
|
|
405
|
+
are available in SDK `0.5.12`. In these streaming options, the `textFormat`
|
|
406
|
+
compatibility extra added in SDK `0.5.16` remains ignored:
|
|
404
407
|
|
|
405
408
|
| Field | Default | Meaning |
|
|
406
409
|
| --- | --- | --- |
|
|
@@ -408,7 +411,7 @@ SDK `0.5.16` is ignored beginning in `0.5.17`:
|
|
|
408
411
|
| `speed` | Current `ai.voiceSpeed` | A supplied positive speed is captured for those segments and forwarded to `fetchTTS()`. It does not change `ai.voiceSpeed`. |
|
|
409
412
|
| `pauseAfterMs` | `0` | Finite, nonnegative milliseconds placed after the final extracted segment on the existing audio clock. Invalid values throw `RangeError`; no pause is inserted between this call's other segments. |
|
|
410
413
|
| `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. |
|
|
411
|
-
| `textFormat` | Ignored compatibility extra |
|
|
414
|
+
| `textFormat` | Ignored streaming compatibility extra | Streaming narration retains automatic cleanup. The public plain selection belongs to complete synthesis payloads or `prepareTTS` options. |
|
|
412
415
|
|
|
413
416
|
Audio-file voice and speed use the existing `fetchTTS()` validation and error path.
|
|
414
417
|
The automatic cleanup changes only the outbound speech-input copy; displayed,
|
|
@@ -418,7 +421,7 @@ text, single marks, ordinary punctuation, and other characters remain literal.
|
|
|
418
421
|
A trailing candidate mark waits for the next character so a repeated run split
|
|
419
422
|
across chunks is still omitted. Ordinary prose streams immediately.
|
|
420
423
|
`end:true`, `finishTTS()`, muted terminal calls, and `stopAudio()` clear pending
|
|
421
|
-
formatting state. `textFormat` is not an opt-out.
|
|
424
|
+
formatting state. Streaming `textFormat` is not an opt-out.
|
|
422
425
|
|
|
423
426
|
Voice, speed, pause, and playback overrides belong to the segments
|
|
424
427
|
extracted in that invocation, including any text buffered by an earlier call.
|
|
@@ -458,18 +461,29 @@ last audio buffer ends, without waiting out that pause. Completion describes
|
|
|
458
461
|
the playback lifecycle, not proof that a listener heard the sound. See the
|
|
459
462
|
[complete-passage example](ai/browser-speech.md#queue-complete-passages-and-wait-for-playback).
|
|
460
463
|
|
|
461
|
-
`prepareTTS({parts,storage,identity,signal,onState})` returns an immediate
|
|
464
|
+
`prepareTTS({parts,textFormat,storage,identity,signal,onState})` returns an immediate
|
|
462
465
|
`{segments,state,ready,getAudio(index),cancel()}` handle for detached complete
|
|
463
466
|
speech preparation. Parts are strings or `{input,voice?,speed?,pauseAfterMs?}`
|
|
464
467
|
records. It retains the full source for semantic matching, snapshots the
|
|
465
468
|
selected speech configuration and segmentation, and applies automatic
|
|
466
|
-
formatting cleanup once to the speech copy
|
|
469
|
+
formatting cleanup once to the speech copy by default. `textFormat:'plain'`
|
|
470
|
+
preserves each complete input before the same ordered segmentation. Prepared
|
|
471
|
+
segment text participates in reuse, keeping cleaned and exact synthesis inputs
|
|
472
|
+
distinct when they differ. This SDK text-treatment choice does not change the
|
|
473
|
+
selected engine's own input capacity. Generation uses the existing
|
|
467
474
|
bounded provider queue without adding playback. Optional
|
|
468
475
|
`storage:{db,table,key}` saves complete audio files and their MIME metadata in
|
|
469
476
|
the caller's ready DBOPFS instance; the separate JSON-compatible `identity`
|
|
470
477
|
adds application-owned semantic context. Reuse compares complete inputs rather
|
|
471
478
|
than an SDK version alone.
|
|
472
479
|
|
|
480
|
+
Only missing audio joins TTS activation. Each preparation supplies its own
|
|
481
|
+
cancellation lifetime to the existing provider runtime. The last pending
|
|
482
|
+
activation interest cancels the owned load; other preparation/playback or
|
|
483
|
+
joining direct-load interests preserve it. Cache-only preparation never loads
|
|
484
|
+
the model, and cancelling after activation does not unload an already-ready
|
|
485
|
+
model. Provider work owns actual cancellation and cleanup completion.
|
|
486
|
+
|
|
473
487
|
`state` is `queued`, `preparing`, `ready`, `error`, or `cancelled`.
|
|
474
488
|
`onState({state,completed,total,segments,error})` synchronously observes
|
|
475
489
|
preparation progress. `ready` resolves the complete record after every segment
|
|
@@ -479,8 +493,8 @@ the retained MIME type. Preparation failure rejects; cancellation rejects as
|
|
|
479
493
|
`AbortError` and preserves successfully stored segments. Matching pending
|
|
480
494
|
requests share synthesis only on the same AI instance and storage group;
|
|
481
495
|
cancelling one handle does not cancel another active matching caller.
|
|
482
|
-
Preparation cancellation prevents later synthesis
|
|
483
|
-
|
|
496
|
+
Preparation cancellation prevents later synthesis and releases its activation
|
|
497
|
+
interest. The provider's operation remains responsible for actual cleanup.
|
|
484
498
|
|
|
485
499
|
`playPreparedTTS(prepared,{signal,onState})` can attach immediately. Its returned
|
|
486
500
|
`{state,error,finished,pause(),resume(),stop()}` handle schedules segments in
|
|
@@ -1017,9 +1031,20 @@ The singleton exposes read-only `protocol`, `configured`, and `speechMuted`;
|
|
|
1017
1031
|
`supportsTranscriptionCapture(providerId=null)`;
|
|
1018
1032
|
`createTranscriptionCapture(options={})`;
|
|
1019
1033
|
`synthesize(payload,options={},preparation={})`; and
|
|
1020
|
-
`setSpeechMuted(muted)`. Provider payloads must be data-only; callbacks,
|
|
1034
|
+
`setSpeechMuted(muted,{signal}={})`. Provider payloads must be data-only; callbacks,
|
|
1021
1035
|
accessors, symbols, and cycles are rejected at the provider boundary.
|
|
1022
1036
|
|
|
1037
|
+
`setSpeechMuted(false,{signal})` shares pending activation while retaining an
|
|
1038
|
+
independent interest for each caller. Aborting one signal rejects only that
|
|
1039
|
+
caller's wait. When no pending interests remain, abort reaches the owned load.
|
|
1040
|
+
No-signal callers and direct `load('tts',...)` calls joining that activation
|
|
1041
|
+
also retain it. A rejected load preserves its complete error for the remaining
|
|
1042
|
+
callers. An already-aborted signal rejects before changing mute intent.
|
|
1043
|
+
Explicit `setSpeechMuted(true)` still cancels shared activation and unloads TTS;
|
|
1044
|
+
once accepted, that mute cleanup runs to completion rather than being undone
|
|
1045
|
+
by cancellation of its caller's signal. Completed activation is not unloaded
|
|
1046
|
+
merely because a former observer later aborts.
|
|
1047
|
+
|
|
1023
1048
|
Selection options admit `localOnly=false`; inspection admits
|
|
1024
1049
|
`{localOnly=false,signal=null}`; startup admits
|
|
1025
1050
|
`{startLanguageModel=true,startMuted=true,startTranscription=false,signal=null}` (including an omitted
|
|
@@ -1032,9 +1057,12 @@ records are the closed `{llm,stt,tts}`, `{stt,tts}`, or
|
|
|
1032
1057
|
`{providers,routes,expectedProviders}` shapes described below.
|
|
1033
1058
|
`configureFromTuple()` accepts exactly six provider/model preference entries.
|
|
1034
1059
|
|
|
1035
|
-
|
|
1036
|
-
formatting marks from a cloned outbound payload's `input` or `text` field.
|
|
1037
|
-
|
|
1060
|
+
By default, direct TTS `request()` and `synthesize()` remove repeated same
|
|
1061
|
+
formatting marks from a cloned outbound payload's `input` or `text` field.
|
|
1062
|
+
Public payload field `textFormat:'plain'` preserves that input exactly. The SDK
|
|
1063
|
+
consumes this field before queuing/dispatch; queued requests retain their
|
|
1064
|
+
selected text treatment. Omission and other values keep the default cleanup.
|
|
1065
|
+
The caller's payload and request records remain unchanged. The optional
|
|
1038
1066
|
`preparation` argument is reserved for SDK-owned delegation;
|
|
1039
1067
|
`{speechInputPrepared:true}` prevents a second pass after another SDK speech
|
|
1040
1068
|
boundary has already cleaned the copy. Applications omit that argument. LLM
|
|
@@ -2193,6 +2221,59 @@ default `DBOPFS`; installs `window.dbopfs`, emits `dbopfs-ready`; table/file/bac
|
|
|
2193
2221
|
|
|
2194
2222
|
Exact exports: `DBOPFS_EVENT_TYPES`, `DBOPFS_REASONS`, `default`.
|
|
2195
2223
|
|
|
2224
|
+
`subscribeChanges(listener, {signal, once})` observes
|
|
2225
|
+
`DBOPFS_EVENT_TYPES.change` (`dbopfs-change`) through the existing canonical
|
|
2226
|
+
`arcane-os/event-manager` source. It returns an idempotent unsubscribe function
|
|
2227
|
+
with `.dispose()`; aborting the supplied signal also removes the subscription.
|
|
2228
|
+
Each listener receives an event whose `detail` contains:
|
|
2229
|
+
|
|
2230
|
+
| Field | Meaning |
|
|
2231
|
+
| --- | --- |
|
|
2232
|
+
| `applicationId`, `storagePath` | Existing application identity and `apps/<application-id>` OPFS scope. |
|
|
2233
|
+
| `tableName`, `directoryName` | Logical table and physical directory; `memories` / `memory` retain their existing alias. |
|
|
2234
|
+
| `fileName` | Complete record filename, or `null` for a removed table. |
|
|
2235
|
+
| `action` | `write`, `append`, `delete`, or `table-delete`. A write does not claim whether a record was newly created. |
|
|
2236
|
+
| `originId`, `sequence`, `changeId` | Per-document origin and incrementing committed occurrence, shared by local and remote notifications for that occurrence. These are correlation fields, separate from realm-local canonical event-source IDs. |
|
|
2237
|
+
| `remote` | `false` at the writing DBOPFS source, `true` when received from another live document. |
|
|
2238
|
+
|
|
2239
|
+
A write is published after writable-stream `close()` succeeds, or after the
|
|
2240
|
+
existing OPFS worker acknowledges its completed write/flush/close. A removal
|
|
2241
|
+
is published after OPFS removes the record or table. The affected cached record
|
|
2242
|
+
or table, including alias keys and removed-table handles, is invalidated before
|
|
2243
|
+
listeners run. A read already in progress may still resolve its earlier
|
|
2244
|
+
snapshot; it cannot repopulate the cache after an intervening delivered change.
|
|
2245
|
+
Notification metadata does not contain, rewrite, or reread record bodies.
|
|
2246
|
+
|
|
2247
|
+
`set()` and raw `writeFile()` publish one occurrence per completed write;
|
|
2248
|
+
`setMany()`, `deleteMany()`, clear operations, and restore retain their existing
|
|
2249
|
+
per-record results and publish only their actual successful mutations. A
|
|
2250
|
+
partial batch is not a transaction: successful records are announced even when
|
|
2251
|
+
siblings fail. Missing records, absent/non-empty empty-table removal, failed
|
|
2252
|
+
writes/removals, and reads emit no committed-change event. `deleteTable()` keeps
|
|
2253
|
+
its existing return/error-reporting behavior; its returned `true` alone does
|
|
2254
|
+
not imply that a committed-change event was emitted.
|
|
2255
|
+
|
|
2256
|
+
Within one document, subscribe through this source or the canonical event
|
|
2257
|
+
manager, rather than consuming both as separate changes. Across documents,
|
|
2258
|
+
DBOPFS owns one native `BroadcastChannel` named from the application storage
|
|
2259
|
+
path. Native storage-partition matching plus that path selects the receiving
|
|
2260
|
+
documents. A remote receiver invalidates its affected cache before publishing
|
|
2261
|
+
locally and never rebroadcasts the occurrence. There is no echo back to the
|
|
2262
|
+
writing DBOPFS source. Ordinary storage success remains success if a transport
|
|
2263
|
+
notification fails; the notification error is reported separately.
|
|
2264
|
+
|
|
2265
|
+
Subscriptions are live-only: subscribe before the application's initial read,
|
|
2266
|
+
then let the application map the table/file/action to its own records and UI.
|
|
2267
|
+
DBOPFS performs no polling, initial full-table read, automatic picker refresh,
|
|
2268
|
+
or event-history replay. The channel lasts for the owning page, independent of
|
|
2269
|
+
individual listener lifetimes, so a document that only writes still announces
|
|
2270
|
+
its commits. `pagehide` closes the channel; `pageshow` after suspension reopens
|
|
2271
|
+
it and clears only that document's in-memory caches. Resuming a page does not
|
|
2272
|
+
fabricate a storage mutation. Applications own any resume-time view refresh.
|
|
2273
|
+
Missed events during suspension, process termination, or realm loss are not
|
|
2274
|
+
replayed; the stored records remain the authority. Direct OPFS writes made
|
|
2275
|
+
outside DBOPFS are not observed by this contract.
|
|
2276
|
+
|
|
2196
2277
|
`createCompressedPNG({tableNames, additionalTables, signal})` returns an
|
|
2197
2278
|
`image/png` Blob without downloading or writing records. Omitted `tableNames`
|
|
2198
2279
|
selects all discovered saved tables; `[]` selects none. Named absent tables
|
|
@@ -2234,16 +2315,35 @@ unreadable row remains in its original string form so the owning application
|
|
|
2234
2315
|
can display, diagnose, or recover it without silent data loss. DOM and storage
|
|
2235
2316
|
errors remain observable. The logical `memories` table continues to map to the
|
|
2236
2317
|
physical `memory` directory, and successful or already-absent empty-table
|
|
2237
|
-
removal invalidates both alias and cached-handle state.
|
|
2238
|
-
|
|
2318
|
+
removal invalidates both alias and cached-handle state. Cross-document change
|
|
2319
|
+
delivery requires native `BroadcastChannel` in the same origin and storage
|
|
2320
|
+
partition, with the same application scope; separate WebView profiles do not
|
|
2321
|
+
share this transport. If it is unavailable, local change subscriptions and
|
|
2322
|
+
ordinary DBOPFS storage continue, without cross-document notification or a
|
|
2323
|
+
polling replacement. Transport: OPFS, DBOPFSWorker, Compression Streams, native
|
|
2324
|
+
BroadcastChannel, and the existing event-pubsub-backed canonical event owner.
|
|
2239
2325
|
[Deep protocol details](protocols.md).
|
|
2240
2326
|
|
|
2241
2327
|
### Example
|
|
2242
2328
|
|
|
2243
2329
|
```javascript
|
|
2244
|
-
import
|
|
2330
|
+
import '/arcane/modules/DBOPFS.js';
|
|
2331
|
+
|
|
2332
|
+
await dbopfs.readyPromise;
|
|
2333
|
+
const lifetime = new AbortController();
|
|
2334
|
+
const stop = dbopfs.subscribeChanges(function showCommittedParade(event) {
|
|
2335
|
+
const change = event.detail;
|
|
2336
|
+
if (change.tableName === 'moon_bus') {
|
|
2337
|
+
console.log(change.action, change.fileName, change.remote);
|
|
2338
|
+
}
|
|
2339
|
+
}, {signal: lifetime.signal});
|
|
2245
2340
|
|
|
2246
|
-
|
|
2341
|
+
await dbopfs.set('moon_bus', 'squid-parade.json', {
|
|
2342
|
+
destination: 'The moon', passengers: ['Captain Squid', 'One confused lobster']
|
|
2343
|
+
});
|
|
2344
|
+
// Another live page using this app/storage scope receives the same occurrence.
|
|
2345
|
+
// The application can read that one record when its view needs the body.
|
|
2346
|
+
stop(); // lifetime.abort() is the equivalent subscription cleanup.
|
|
2247
2347
|
```
|
|
2248
2348
|
|
|
2249
2349
|
## DBOPFSDocumentLibrary.js
|
|
@@ -1906,6 +1906,20 @@ default class PreferenceStore extends EventTarget
|
|
|
1906
1906
|
subpath and managed browser key both resolve directly to the canonical runtime
|
|
1907
1907
|
module. Deep protocol: [Browser runtime delivery](protocols.md#browser-runtime-delivery).
|
|
1908
1908
|
|
|
1909
|
+
The default adapter recognizes an absent optional preferences namespace only
|
|
1910
|
+
from the exact Core lookup tuple `code:'METHOD_NOT_ALLOWED'`,
|
|
1911
|
+
`reason:'core-namespace-unavailable'`, `namespace:'preferences'`, and the
|
|
1912
|
+
matching `method:'preferences.<operation>'`. Single `get`, `set`, and `delete`
|
|
1913
|
+
operations then retry once through the existing app-scoped local adapter after
|
|
1914
|
+
checking disposal and cancellation, preserving complete values and operation
|
|
1915
|
+
context. The existing Android unsupported-capability route is unchanged.
|
|
1916
|
+
An advertised `setMany` batch rejected for that exact absence retains its
|
|
1917
|
+
original rejection and performs no serial retry; subsequent operations use the
|
|
1918
|
+
selected local adapter.
|
|
1919
|
+
Partial-service, permission, persistence, transport and cancellation failures
|
|
1920
|
+
remain errors. Explicit adapters retain their own behavior. See the
|
|
1921
|
+
[complete PreferenceStore contract](runtime-modules.md#preferencestorejs).
|
|
1922
|
+
|
|
1909
1923
|
### Example
|
|
1910
1924
|
|
|
1911
1925
|
```javascript
|
|
@@ -7325,6 +7339,15 @@ without restarting services. Its snapshot preserves complete service errors
|
|
|
7325
7339
|
and active request state; see [runtime replay](core-runtime.md#state-and-frames)
|
|
7326
7340
|
for authoritative readiness and reentrant lifecycle ordering.
|
|
7327
7341
|
|
|
7342
|
+
An unregistered method returns `METHOD_NOT_ALLOWED` with its exact `method`,
|
|
7343
|
+
first dotted `namespace`, and `reason:'core-namespace-unavailable'` when that
|
|
7344
|
+
namespace has neither a named service nor any registered method. Otherwise
|
|
7345
|
+
the reason is `core-method-unavailable`; built-in `system`, `app` and `version`
|
|
7346
|
+
namespaces count as present. This is a lookup result before handler or
|
|
7347
|
+
permission decisions. Handler/startup errors and older unmarked errors do not
|
|
7348
|
+
establish namespace absence. The dispatcher does not choose a replacement
|
|
7349
|
+
service; optional browser adapters own their documented response to absence.
|
|
7350
|
+
|
|
7328
7351
|
### Availability and normalization
|
|
7329
7352
|
|
|
7330
7353
|
**Node on Windows, Linux and macOS native hosts; Android requires its native host
|
|
@@ -8821,13 +8844,14 @@ occurrences use source `ai-model-controller`; every load or unload owns one
|
|
|
8821
8844
|
non-null operation ID shared by its state and progress occurrences. Public
|
|
8822
8845
|
progress retains the exact selected `modelId`, `phase`, state, and nested
|
|
8823
8846
|
file-progress field names. Browser-WASM download progress preserves
|
|
8824
|
-
`completed`, `total`, and `unit:'files'
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
8847
|
+
`completed`, `total`, and `unit:'files'`, with complete per-file `members`
|
|
8848
|
+
reporting stored shards. A member's `total` remains `null` until its complete
|
|
8849
|
+
response is stored, unless the HTTP range plan already establishes its shard
|
|
8850
|
+
total. `activeTransfers`, `transferLimit`, and `transferMode` describe the
|
|
8851
|
+
active download work. Closed shards, active-worker changes, and completion
|
|
8852
|
+
boundaries publish semantic progress; the existing heartbeat repeats the latest
|
|
8853
|
+
record. These fields describe files and shards, without byte-based display
|
|
8854
|
+
requirements or estimated transfer rates.
|
|
8831
8855
|
Accessor-bearing provider status
|
|
8832
8856
|
and malformed progress reject with `ARCANE_AI_PROVIDER_STATUS_INVALID` and
|
|
8833
8857
|
`ARCANE_AI_PROVIDER_PROGRESS_INVALID`. After disposal, lifecycle operations fail with
|
|
@@ -9420,8 +9444,8 @@ console.log(provider.status().state); // unloaded
|
|
|
9420
9444
|
### Overview
|
|
9421
9445
|
|
|
9422
9446
|
Adapts an existing DBOPFS instance into a complete multi-model, ordered
|
|
9423
|
-
multi-file cache without renaming its public methods.
|
|
9424
|
-
|
|
9447
|
+
multi-file cache without renaming its public methods. Every new full response
|
|
9448
|
+
or Range transfer is committed in ordered parts. An interrupted set
|
|
9425
9449
|
is not a cache hit, but its completed members remain available to the next
|
|
9426
9450
|
install so only missing work is fetched.
|
|
9427
9451
|
|
|
@@ -9439,25 +9463,26 @@ workers
|
|
|
9439
9463
|
when the probe returns a usable total from exposed `Content-Range` or optional
|
|
9440
9464
|
descriptor `bytes`. The mutable
|
|
9441
9465
|
result contains `kind`, `tableName`, `downloadConcurrency`, the original
|
|
9442
|
-
`adapter`, and `ready`, `install`, `ensure`, and `
|
|
9466
|
+
`adapter`, and `ready`, `install`, `ensure`, `remove`, and `fetchResource`. `ensure()` returns
|
|
9443
9467
|
`files` and `cache:'cached'|'installed'`. It preserves the complete model content.
|
|
9444
9468
|
`offline:true` never downloads and rejects a miss with
|
|
9445
9469
|
`ARCANE_AI_MODEL_OFFLINE_MISS`.
|
|
9446
9470
|
|
|
9447
|
-
When supplied, `onProgress` receives
|
|
9448
|
-
|
|
9449
|
-
`
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9471
|
+
When supplied, `onProgress` receives ordered file progress and `members`
|
|
9472
|
+
records with each file's `name`, committed `completed` parts, `total`, and
|
|
9473
|
+
`unit:'shards'`. Streaming totals remain `null` until the response finishes;
|
|
9474
|
+
previously complete files identify `state:'cached'`. `activeTransfers` is the
|
|
9475
|
+
current transfer-worker count, `transferLimit` is selected concurrency, and
|
|
9476
|
+
`transferMode` is `probing`, `files`, `ranges`, or `single`. Closed-part and
|
|
9477
|
+
lifecycle changes publish promptly, with an existing 250 ms heartbeat. No
|
|
9478
|
+
byte progress, transfer rate, or estimated completion time is produced.
|
|
9479
|
+
|
|
9480
|
+
`fetchResource(input,{signal,onProgress,...requestOptions})` returns
|
|
9481
|
+
`{file,status,statusText,headers,url,redirected}` for a complete stored Fetch
|
|
9482
|
+
response. SDK browser model loaders use this shared owner for configuration,
|
|
9483
|
+
tokenizer, graph, external-data, and other fetched resources. Successful
|
|
9484
|
+
complete GET resources may be reused; supported HTTP ranges resume closed
|
|
9485
|
+
parts after interruption. Request framing stays at the transport boundary.
|
|
9461
9486
|
|
|
9462
9487
|
### Availability and normalization
|
|
9463
9488
|
|
|
@@ -9468,9 +9493,9 @@ resumable Range parts. For any source member, a followed redirect that
|
|
|
9468
9493
|
turns the first `bytes=0-0` probe into `200` triggers one direct probe of the
|
|
9469
9494
|
final URL. Confirmed support cancels the original body and starts the Range
|
|
9470
9495
|
pool; refusal keeps the original response as the ordinary single-fetch path,
|
|
9471
|
-
|
|
9496
|
+
without requiring a readable `Content-Length`. A missing `Content-Range` can
|
|
9472
9497
|
use optional descriptor `bytes` for Range planning; without either total, the
|
|
9473
|
-
store
|
|
9498
|
+
store uses one full fetch streamed into ordered persistent parts. A confirmed source member is divided into
|
|
9474
9499
|
deterministic OPFS Range parts of roughly 4 MB each, up to 4,096 parts. A
|
|
9475
9500
|
monolithic source may use at most
|
|
9476
9501
|
`downloadConcurrency` Range workers; split sources keep one Range worker per
|
|
@@ -9479,7 +9504,7 @@ in order as one logical Blob. A later non-206, contradictory exposed Range
|
|
|
9479
9504
|
response, or incorrectly framed body fails rather than assembling partial
|
|
9480
9505
|
content. On failure or cancellation, peers settle while completed shards and
|
|
9481
9506
|
Range parts remain available for retry; an unfinished active part restarts after
|
|
9482
|
-
refresh. A persisted Range part whose length does not match its requested HTTP
|
|
9507
|
+
refresh. Existing whole-file caches remain readable without migration. A persisted Range part whose length does not match its requested HTTP
|
|
9483
9508
|
frame is discarded and fetched again. A complete whole member supersedes its
|
|
9484
9509
|
redundant current Range fragments. Cleanup failure is warned without
|
|
9485
9510
|
hiding the usable model. Wllama requires every selected model Blob or File to
|
|
@@ -9761,7 +9786,7 @@ retains the complete list of deletions already completed.
|
|
|
9761
9786
|
|
|
9762
9787
|
Adapts an existing DBOPFS instance into a complete caller-selected speech
|
|
9763
9788
|
runtime/model store. It serializes each selected model with an exclusive Web
|
|
9764
|
-
Lock,
|
|
9789
|
+
Lock, preserves complete peer files and closed parts after failure, stores ordinary mutable selection
|
|
9765
9790
|
metadata before content, and treats a changed file inventory or source mapping
|
|
9766
9791
|
as a cache miss that is downloaded again.
|
|
9767
9792
|
|
|
@@ -9771,7 +9796,7 @@ as a cache miss that is downloaded again.
|
|
|
9771
9796
|
createDbopfsSpeechArtifactStore({ dbopfs, tableName='arcane_ai_browser_speech', fetchImpl=null, objectUrlFactory=null }={})
|
|
9772
9797
|
```
|
|
9773
9798
|
|
|
9774
|
-
The mutable result is `{protocol,tableName,prepare,remove}`.
|
|
9799
|
+
The mutable result is `{protocol,tableName,prepare,remove,fetchResource}`.
|
|
9775
9800
|
`prepare(authority,{signal,onProgress,offline=false,security})` uses a complete
|
|
9776
9801
|
compatible cache or downloads every declared file, preserves complete content
|
|
9777
9802
|
and materializes object URLs, then returns
|
|
@@ -9781,9 +9806,18 @@ needs those URLs. `offline:true` never fetches and rejects a miss with
|
|
|
9781
9806
|
authority's files and selection metadata. Optional `onProgress` receives
|
|
9782
9807
|
preparation and download records with `phase`, `stage`, `message`, and the
|
|
9783
9808
|
current `file` when available. File operations report actual `completed` and
|
|
9784
|
-
`total` inventory counts with `unit:'files'
|
|
9809
|
+
`total` inventory counts with `unit:'files'`, and `resource` carries the current
|
|
9810
|
+
closed-part progress with `unit:'shards'`; module preparation uses
|
|
9785
9811
|
`total:null`. Cancellation stops progress along with the owning operation.
|
|
9786
9812
|
|
|
9813
|
+
New files stream into ordered DBOPFS parts with no required response length.
|
|
9814
|
+
Existing complete whole files stay readable without migration.
|
|
9815
|
+
`fetchResource(input,{signal,onProgress,...requestOptions})` returns
|
|
9816
|
+
`{file,status,statusText,headers,url,redirected}` and gives the dedicated
|
|
9817
|
+
speech Worker the same complete resource storage owner for runtime fetches.
|
|
9818
|
+
Native ESM imports and unmapped classic Worker internals retain their platform
|
|
9819
|
+
loader; they are not claimed as intercepted HTTP fetches.
|
|
9820
|
+
|
|
9787
9821
|
### Availability and normalization
|
|
9788
9822
|
|
|
9789
9823
|
**Browser with a ready DBOPFS instance, OPFS, Web Locks, Fetch or an injected
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arcane-os",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.70.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",
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
"test": "npm run test:unit && npm run test:functional && npm run test:integration && npm run test:regression",
|
|
124
124
|
"test:release": "node ./bin/arcane-test.mjs test/npm-release.test.mjs",
|
|
125
125
|
"test:unit": "node ./bin/arcane-test.mjs test/app-descriptor.test.mjs test/app-schema.test.mjs test/app-selection.test.mjs test/contracts.test.mjs test/conversation-closing-report.test.mjs test/doctor.test.mjs test/mail-credentials.test.mjs test/mail-outbox.test.mjs test/mail-public-api.test.mjs test/mail-send.test.mjs test/mail-transport.test.mjs test/native-windows-icon.test.mjs test/targets.test.mjs test/workspace-operation-lock.test.mjs",
|
|
126
|
-
"test:functional": "node ./bin/arcane-test.mjs test/ai-ollama-readiness.test.mjs test/core-ollama-lifecycle.test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-decisions.test.mjs test/browser-speech-providers.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-input.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/chat-transient-retention.test.mjs test/cli.test.mjs test/continuous-voice-capture.test.mjs test/codex-app-server.test.mjs test/mcp-stdio-server.test.mjs test/core-classic-source.test.mjs test/core-client.test.mjs test/core-client-installation.test.mjs test/core-ai-installation.test.mjs test/core-llama-lifecycle.test.mjs test/core-development.test.mjs test/core-host.test.mjs test/core-model-assets.test.mjs test/core-native-services.test.mjs test/core-packaged-web.test.mjs test/core-runtime.test.mjs test/core-stdio.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs-png.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/file-preview.test.mjs test/import-map.test.mjs test/local-image-editing.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/markdown-editor.test.mjs test/markdown-media.test.mjs test/markdown-source-map.test.mjs test/modal.test.mjs test/native-decisions.test.mjs test/native-onnx.test.mjs test/native-module-packaging.test.mjs test/native-module-resource-references.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/rendered-print.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/theme-manager.test.mjs test/twin-cloud-images.test.mjs test/twin-cloud.test.mjs test/websocket-client-import-map.test.mjs test/websocket.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
|
|
126
|
+
"test:functional": "node ./bin/arcane-test.mjs test/ai-ollama-readiness.test.mjs test/core-ollama-lifecycle.test.mjs test/ai-request-model.test.mjs test/ai-request-retry.test.mjs test/ai-stream-cancellation.test.mjs test/browser-decisions.test.mjs test/browser-speech-providers.test.mjs test/browser-speech-artifacts.test.mjs test/browser-speech-resource-bridge.test.mjs test/browser-wasm-gpu-notice.test.mjs test/browser-wasm-download-resume.test.mjs test/chat-input.test.mjs test/chat-stream-speech.test.mjs test/chat-transcript-scroll.test.mjs test/chat-transient-retention.test.mjs test/cli.test.mjs test/continuous-voice-capture.test.mjs test/codex-app-server.test.mjs test/mcp-stdio-server.test.mjs test/core-classic-source.test.mjs test/core-client.test.mjs test/core-client-installation.test.mjs test/core-ai-installation.test.mjs test/core-llama-lifecycle.test.mjs test/core-development.test.mjs test/core-host.test.mjs test/core-shared-host.test.mjs test/core-model-assets.test.mjs test/core-native-services.test.mjs test/core-packaged-web.test.mjs test/core-runtime.test.mjs test/core-stdio.test.mjs test/dbopfs-committed-events.test.mjs test/dbopfs-document-library.test.mjs test/dbopfs-model-resources.test.mjs test/dbopfs-png.test.mjs test/dbopfs.test.mjs test/dev-server.test.mjs test/dev-pwa.test.mjs test/dom-event-instrumentation.test.mjs test/event-manager.test.mjs test/events.test.mjs test/file-preview.test.mjs test/import-map.test.mjs test/local-image-editing.test.mjs test/mail-cli.test.mjs test/mail-runtime.test.mjs test/mail-server.test.mjs test/markdown-editor.test.mjs test/markdown-media.test.mjs test/markdown-source-map.test.mjs test/modal.test.mjs test/model-resource-bridge.test.mjs test/native-decisions.test.mjs test/native-onnx.test.mjs test/native-module-packaging.test.mjs test/native-module-resource-references.test.mjs test/packaging.test.mjs test/pwa-packaging.test.mjs test/pwa-client.test.mjs test/pwa-install.test.mjs test/pwa-worker.test.mjs test/persistent-ai-chat-session.test.mjs test/reference-completeness.test.mjs test/rendered-print.test.mjs test/runtime-api-behavior.test.mjs test/runtime.test.mjs test/scaffold.test.mjs test/speech-playback.test.mjs test/site.test.mjs test/theme-manager.test.mjs test/twin-cloud-images.test.mjs test/twin-cloud.test.mjs test/websocket-client-import-map.test.mjs test/websocket.test.mjs test/update-check.test.mjs test/user-explicit-updates.test.mjs",
|
|
127
127
|
"test:integration": "node ./bin/arcane-test.mjs test/installed-package-runtime.test.mjs test/root-app-layout.test.mjs test/integrated-shared.test.mjs test/integrated-workspace.test.mjs test/mail-browser.test.mjs test/native-macos-provider.test.mjs test/native-plan.test.mjs test/native-portable-provider.test.mjs test/native-provider-loader.test.mjs test/npm-release.test.mjs test/release-bundle.test.mjs test/release-capability-smoke.test.mjs test/shared-payload-batch.test.mjs test/tarball.test.mjs test/browser-wasm-cpu.test.mjs test/wllama-webgpu-runtime.test.mjs",
|
|
128
128
|
"test:regression": "node ./bin/arcane-test.mjs test/channel-workflows.test.mjs test/html-import-registration.test.mjs test/html-import-packaged-script.test.mjs test/logging-regression.test.mjs test/markdown-speech.test.mjs test/prepared-speech.test.mjs test/native-provider-generation.test.mjs test/speech-queue-regression.test.mjs test/testing.test.mjs test/test-sets.test.mjs",
|
|
129
129
|
"check": "node tools/check-source.mjs && npm test",
|
|
@@ -1182,7 +1182,6 @@ class AI {
|
|
|
1182
1182
|
#speechJobSequence=0;
|
|
1183
1183
|
#stopOllamaReady=null;
|
|
1184
1184
|
#ttsSegmentation={...DEFAULT_TTS_SEGMENTATION};
|
|
1185
|
-
#preparedSpeechReadiness = null;
|
|
1186
1185
|
#preparedSpeechPlaybacks = new Set();
|
|
1187
1186
|
#nativeSpeechPlaybacks = new Set();
|
|
1188
1187
|
#speechUnlockContext = null;
|
|
@@ -4394,7 +4393,7 @@ class AI {
|
|
|
4394
4393
|
runtime.#browserSpeechTransition,activation.controller.signal
|
|
4395
4394
|
);
|
|
4396
4395
|
activation.controller.signal.throwIfAborted();
|
|
4397
|
-
await runtime.#providerRuntime.setSpeechMuted(false);
|
|
4396
|
+
await runtime.#providerRuntime.setSpeechMuted(false, {signal: activation.controller.signal});
|
|
4398
4397
|
if(runtime.#speechActivation!==activation)return false;
|
|
4399
4398
|
const status=runtime.#providerRuntime.status('tts');
|
|
4400
4399
|
runtime.muted=status.state!=='ready'||status.loaded!==true;
|
|
@@ -6336,7 +6335,7 @@ class AI {
|
|
|
6336
6335
|
return result;
|
|
6337
6336
|
}
|
|
6338
6337
|
|
|
6339
|
-
prepareTTS({parts, storage = null, identity = null, signal = null, onState = null} = {}) {
|
|
6338
|
+
prepareTTS({parts, textFormat, storage = null, identity = null, signal = null, onState = null} = {}) {
|
|
6340
6339
|
if(this.#providerSpeechModel()?.speech?.playback==='native'){
|
|
6341
6340
|
const error=new Error('Native browser speech has no audio file to prepare or store; use prepareTTSPlayback.');
|
|
6342
6341
|
error.code='ARCANE_AI_TTS_AUDIO_EXPORT_UNAVAILABLE';
|
|
@@ -6384,7 +6383,7 @@ class AI {
|
|
|
6384
6383
|
if(!is.finite(pauseAfterMs) || pauseAfterMs < 0) {
|
|
6385
6384
|
throw new RangeError('Prepared speech pauses must be nonnegative milliseconds.');
|
|
6386
6385
|
}
|
|
6387
|
-
const cleaned = stripSpeechFormatting(source.input);
|
|
6386
|
+
const cleaned = textFormat === 'plain' ? source.input : stripSpeechFormatting(source.input);
|
|
6388
6387
|
const {segments: outputs} = this.#segmentSpeechText(cleaned, true, segmentation);
|
|
6389
6388
|
for(const [index, input] of outputs.entries()) {
|
|
6390
6389
|
if(!input.trim()) continue;
|
|
@@ -6409,22 +6408,7 @@ class AI {
|
|
|
6409
6408
|
if(selected) {
|
|
6410
6409
|
const status = runtime.#providerRuntime.status('tts');
|
|
6411
6410
|
if(status.state !== 'ready' || status.loaded !== true) {
|
|
6412
|
-
|
|
6413
|
-
const readiness = runtime.#providerRuntime.setSpeechMuted(false);
|
|
6414
|
-
runtime.#preparedSpeechReadiness = readiness;
|
|
6415
|
-
readiness.finally(
|
|
6416
|
-
function releasePreparedSpeechReadiness() {
|
|
6417
|
-
if(runtime.#preparedSpeechReadiness === readiness) {
|
|
6418
|
-
runtime.#preparedSpeechReadiness = null;
|
|
6419
|
-
}
|
|
6420
|
-
}
|
|
6421
|
-
).catch(
|
|
6422
|
-
function reportPreparedSpeechReadinessFailure(error) {
|
|
6423
|
-
runtime.#traceSpeech('prepareTTS.readiness.error', {error});
|
|
6424
|
-
}
|
|
6425
|
-
);
|
|
6426
|
-
}
|
|
6427
|
-
await runtime.#preparedSpeechReadiness;
|
|
6411
|
+
await runtime.#providerRuntime.setSpeechMuted(false, {signal: requestSignal});
|
|
6428
6412
|
assertPreparedSpeechSelection();
|
|
6429
6413
|
}
|
|
6430
6414
|
}
|
|
@@ -7175,6 +7159,7 @@ class AI {
|
|
|
7175
7159
|
'model',
|
|
7176
7160
|
'voice',
|
|
7177
7161
|
'input',
|
|
7162
|
+
'textFormat',
|
|
7178
7163
|
'responseFormat',
|
|
7179
7164
|
'speed'
|
|
7180
7165
|
]);
|
|
@@ -7183,7 +7168,7 @@ class AI {
|
|
|
7183
7168
|
||!acceptedKeys.has(key)
|
|
7184
7169
|
||!Object.hasOwn(descriptors[key],'value')){
|
|
7185
7170
|
const error=new TypeError(
|
|
7186
|
-
'AI.fetchTTS accepts only model, voice, input, responseFormat, and speed data properties.'
|
|
7171
|
+
'AI.fetchTTS accepts only model, voice, input, textFormat, responseFormat, and speed data properties.'
|
|
7187
7172
|
);
|
|
7188
7173
|
error.code='ARCANE_AI_TTS_REQUEST_INVALID';
|
|
7189
7174
|
throw error;
|
|
@@ -7208,7 +7193,7 @@ class AI {
|
|
|
7208
7193
|
error.code='ARCANE_AI_TTS_INPUT_INVALID';
|
|
7209
7194
|
throw error;
|
|
7210
7195
|
}
|
|
7211
|
-
const input=speechInputPrepared===true
|
|
7196
|
+
const input=speechInputPrepared===true||descriptors.textFormat?.value==='plain'
|
|
7212
7197
|
?suppliedInput
|
|
7213
7198
|
:stripSpeechFormatting(suppliedInput);
|
|
7214
7199
|
const selection=this.#providerRuntime.selection('tts');
|