arcane-os 0.88.1 → 0.90.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 +34 -0
- package/browser-runtime/ai/browser-decisions.mjs +31 -4
- package/browser-runtime/ai/core-local.mjs +105 -25
- package/browser-runtime/ai/decision-runtime.mjs +7 -0
- package/browser-runtime/ai/decision-worker.mjs +9 -1
- package/browser-runtime/core/client.mjs +6 -0
- package/browser-runtime/core/contracts.mjs +10 -0
- package/docs/reference/ai/browser-decisions.md +89 -7
- package/docs/reference/core-client.md +59 -0
- package/docs/reference/core-native-packaging.md +62 -10
- package/docs/reference/core-repositories.md +104 -8
- package/docs/reference/git-text-snapshot.md +16 -1
- package/docs/reference/inventory/package-api.json +25 -25
- package/docs/reference/inventory/runtime-components.json +1 -1
- package/docs/reference/inventory/runtime-modules.json +4 -4
- package/docs/reference/local-ai.md +108 -9
- package/docs/reference/mcp-stdio.md +76 -1
- package/docs/reference/native-app-control.md +17 -5
- package/docs/reference/protocols.md +14 -0
- package/docs/reference/runtime-modules.md +9 -3
- package/docs/reference/sdk-api.md +202 -35
- package/package.json +2 -2
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +1 -5
- package/schemas/arcane-app.schema.json +13 -3
- package/schemas/arcane-package.schema.json +10 -1
- package/src/app-descriptor.mjs +6 -2
- package/src/cli/app-control.mjs +1 -1
- package/src/core/hosts/windows/ArcaneHost.cs +273 -5
- package/src/core/hosts/windows/ArcaneLauncher.cs +9 -0
- package/src/core/hosts/windows/ArcaneWindowControl.cs +7 -7
- package/src/core/repositories.mjs +17 -6
- package/src/core/services/local-ai.mjs +183 -22
- package/src/git-text-snapshot.mjs +4 -2
- package/src/installed-sdk-runtime.mjs +2 -0
- package/src/local-ai/config.mjs +16 -0
- package/src/local-ai/dev.mjs +2 -2
- package/src/local-ai/discover.mjs +3 -0
- package/src/local-ai/install.mjs +130 -20
- package/src/local-ai/llama-execution-windows.ps1 +158 -0
- package/src/local-ai/llama-execution.mjs +169 -0
- package/src/local-ai/server.mjs +38 -8
- package/src/native/portable-layout.mjs +13 -3
- package/src/repository.mjs +33 -8
- package/src/workspace-runtime.mjs +97 -1
|
@@ -981,7 +981,7 @@
|
|
|
981
981
|
],
|
|
982
982
|
"availability": "Browser and supported native WebViews",
|
|
983
983
|
"transport": "HTMLImport + DOM; injected Arcane/provider modules where listed",
|
|
984
|
-
"normalization": "Preference/native appearance behavior mixed; selected button background, text and outline remain visible during hover while the hover fill applies only to unselected enabled buttons; no component-ready contract"
|
|
984
|
+
"normalization": "Preference/native appearance behavior mixed; selected button background, text and outline remain visible during hover while the hover fill applies only to unselected enabled buttons; no component-ready contract; pending choices expose aria-disabled and ignore repeated activation while staying in the keyboard focus flow; completion and failure do not move focus, and an unavailable Skin choice retains native disabling"
|
|
985
985
|
},
|
|
986
986
|
{
|
|
987
987
|
"file": "runtime/arcane/components/unified-inbox.html",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"summary": "Owns provider-selectable chat and the one-time caller-authority browser STT/TTS configuration, lifecycle, synthesis, transcription, and playback boundary.",
|
|
31
31
|
"availability": "Browser + native bridge + TWiN Cloud",
|
|
32
32
|
"protocol": "arcane-ai-browser-speech-configuration/1, AIProviderRuntime arcane-ai-provider/2 routes, globalThis.arcaneEvents, TWiN Cloud HTTPS, Arcane.ollama, Arcane.speech, Android WebView bridge",
|
|
33
|
-
"normalization": "Complete mutable caller-owned browser speech authority, SDK-owned provider registration/replacement/disposal, explicit STT/TTS activation, normalized Whisper STT and Kokoro TTS execution with default capacities 1 and 4 respectively, explicit provider-neutral execution snapshots through status(role,{execution:true}), sticky readiness, canonical window.user readiness without compatibility-event object-identity admission or polling, exact ordered structural calls with required arguments.message, atomic nonblank all-ID tool-result sequencing, complete all-choice streaming/data validation, native Ollama structural adaptation, complete-response then all validated tool callbacks then completion ordering, observed async callbacks, Blob/File transcription, default repeated-formatting-mark removal from cloned outbound TTS input, explicit textFormat:'plain' preservation for complete synthesis/preparation while streaming cleanup remains automatic and caller/visible content stays exact, immediate exact-segment synthesis, per-call voice/speed capture, optional final-segment pause on the existing audio clock, optional per-call terminal playback completion, detached preparation with complete semantic DBOPFS audio reuse and same-owner pending request sharing; each preparation owns its pending activation interest, final-interest cancellation aborts that activation while other interests preserve it, complete cache hits start no model, and cancellation after readiness leaves the ready model loaded; independent prepared playback without a model load for cached audio, ordered audio-clock scheduling, playable audio, active-generation TTS operation-failure routing, mute, and cancellation are normalized; provider/model/runtime/voice policy remains caller-owned. Both speech roles default execution.device to auto: webnn-npu when navigator.ml.createContext is exposed, then webgpu when navigator.gpu is exposed, then wasm for CPU execution. Failed backend loads clean up the pool before trying fresh Workers with the same prepared model and dtype; explicit devices never fall back. STT capacity only accepts 1; TTS accepts 1 through 4. Execution snapshots expose requestedDevice, selectedDevice, maxConcurrentRequests, and activeRequestCount for both roles; selectedDevice is null while unloaded and names the successful upstream session backend request when loaded. It does not prove every operation used the physical NPU: WebNN unsupported operations may use WASM, and compatibility depends on the browser, driver, hardware, and graph.",
|
|
34
|
-
"surface": "Native fetchTTS(payload,signal) and fetchSTT(audio,signal) forward caller cancellation separately from their complete Core speech payloads, normalize aborts to AbortError and suppress late results; actual engine interruption remains service-owned. prepareTTSPlayback(payload,signal) silently returns a real Blob or native-speech descriptor; native controls expose finished/released/state/error/pause/resume/stop, and actual release owns the playback lane. fetchTTS and durable prepareTTS report ARCANE_AI_TTS_AUDIO_EXPORT_UNAVAILABLE for native voices. Request-local model overrides remain exact and never mutate the configured model. Browser-speech protocol/event/error/reason constants; default `AI`; read-only `providerRuntime`, `browserSpeechConfiguration`, and `browserSpeechDescriptor`; explicit `providerRuntime.status(role,{execution:true})` snapshots; `streamTTS(text,end,options={})` with optional voice, speed, pauseAfterMs, and waitForPlayback; default speech-input cleanup with SDK-internal preparation metadata and explicit complete-call textFormat:'plain' consumed before engine dispatch; `prepareTTS({parts,storage,identity,textFormat,signal,onState})` returning ordered segments, state, ready, getAudio(index), and cancel(); async `readPreparedTTS({parts,textFormat,storage,identity,signal,onState})` returning a complete ready handle or null through the same semantic matcher, with no activation, unmute, synthesis, playback, storage writes, or partial repair; manifest, audio availability, and returned-handle reads use DBOPFS createTable:false so absent tables remain absent; supplied adapters own that read-existing behavior; missing matches/audio return null, malformed metadata and storage failures reject, and omitted storage sees only completed matching same-AI in-memory audio; hits replay ready state, misses emit nothing, and the lookup signal detaches on settlement while returned-handle cancellation stays independent; `prepareAudioOutput()` returning the persistent WebAudio handle {kind,state,contextState,error,subscribe,resume,dispose} without resume, unmute, model load, sources, sound, or gesture listeners; current-state replay and output-specific canonical `AI_AUDIO_OUTPUT_STATE_EVENT` (`ai-audio-output-state`), with ready only for an actually running context; explicit owner disposal observes context-bound cleanup and close; `playPreparedTTS(prepared,{signal,onState,audioOutput})` returning state, error, finished, pause(), resume(), and stop() with one playback lane per AI and observational state/error callbacks; explicit live same-AI audioOutput borrows its context until owner disposal, while omission or null preserves per-playback terminal close; configure/dispose speech, route lifecycle, declaration-validated chat/stream requests with exact ordered calls; optional streamRequest toolText:{name,field} and onToolText(text,call,displayId) for decoded selected argument text with actual call identity, distinct from ordinary prose and terminal tool execution; synthesis/transcription and playback controls; initializes from current canonical user readiness, installs `window.ai`, and projects `ai-ready` plus active-generation `ai-tts-failure`."
|
|
33
|
+
"normalization": "Complete mutable caller-owned browser speech authority, SDK-owned provider registration/replacement/disposal, explicit STT/TTS activation, normalized Whisper STT and Kokoro TTS execution with default capacities 1 and 4 respectively, explicit provider-neutral execution snapshots through status(role,{execution:true}), sticky readiness, canonical window.user readiness without compatibility-event object-identity admission or polling, exact ordered structural calls with required arguments.message, atomic nonblank all-ID tool-result sequencing, complete all-choice streaming/data validation, native Ollama structural adaptation, complete-response then all validated tool callbacks then completion ordering, observed async callbacks, Blob/File transcription, default repeated-formatting-mark removal from cloned outbound TTS input, explicit textFormat:'plain' preservation for complete synthesis/preparation while streaming cleanup remains automatic and caller/visible content stays exact, immediate exact-segment synthesis, per-call voice/speed capture, optional final-segment pause on the existing audio clock, optional per-call terminal playback completion, detached preparation with complete semantic DBOPFS audio reuse and same-owner pending request sharing; each preparation owns its pending activation interest, final-interest cancellation aborts that activation while other interests preserve it, complete cache hits start no model, and cancellation after readiness leaves the ready model loaded; independent prepared playback without a model load for cached audio, ordered audio-clock scheduling, playable audio, active-generation TTS operation-failure routing, mute, and cancellation are normalized; provider/model/runtime/voice policy remains caller-owned. Both speech roles default execution.device to auto: webnn-npu when navigator.ml.createContext is exposed, then webgpu when navigator.gpu is exposed, then wasm for CPU execution. Failed backend loads clean up the pool before trying fresh Workers with the same prepared model and dtype; explicit devices never fall back. STT capacity only accepts 1; TTS accepts 1 through 4. Execution snapshots expose requestedDevice, selectedDevice, maxConcurrentRequests, and activeRequestCount for both roles; selectedDevice is null while unloaded and names the successful upstream session backend request when loaded. It does not prove every operation used the physical NPU: WebNN unsupported operations may use WASM, and compatibility depends on the browser, driver, hardware, and graph. High-level LLM selection defaults to eager activation; startLanguageModel:false preserves the selected tuple and registered adapters without preloading through later readiness callbacks. Caller cancellation waits for accepted old-role cleanup and prevents later configuration/preload, or reaches the first owned load after selection commits. Newer accepted selections supersede older continuations; deferred or cancelled activation stays inactive until explicit load/startup, and a caller abort after successful settlement never unloads the ready model. Separate callers joining an existing runtime load retain their current cancellation ownership.",
|
|
34
|
+
"surface": "Native fetchTTS(payload,signal) and fetchSTT(audio,signal) forward caller cancellation separately from their complete Core speech payloads, normalize aborts to AbortError and suppress late results; actual engine interruption remains service-owned. prepareTTSPlayback(payload,signal) silently returns a real Blob or native-speech descriptor; native controls expose finished/released/state/error/pause/resume/stop, and actual release owns the playback lane. fetchTTS and durable prepareTTS report ARCANE_AI_TTS_AUDIO_EXPORT_UNAVAILABLE for native voices. Request-local model overrides remain exact and never mutate the configured model. Browser-speech protocol/event/error/reason constants; default `AI`; read-only `providerRuntime`, `browserSpeechConfiguration`, and `browserSpeechDescriptor`; explicit `providerRuntime.status(role,{execution:true})` snapshots; `streamTTS(text,end,options={})` with optional voice, speed, pauseAfterMs, and waitForPlayback; default speech-input cleanup with SDK-internal preparation metadata and explicit complete-call textFormat:'plain' consumed before engine dispatch; `prepareTTS({parts,storage,identity,textFormat,signal,onState})` returning ordered segments, state, ready, getAudio(index), and cancel(); async `readPreparedTTS({parts,textFormat,storage,identity,signal,onState})` returning a complete ready handle or null through the same semantic matcher, with no activation, unmute, synthesis, playback, storage writes, or partial repair; manifest, audio availability, and returned-handle reads use DBOPFS createTable:false so absent tables remain absent; supplied adapters own that read-existing behavior; missing matches/audio return null, malformed metadata and storage failures reject, and omitted storage sees only completed matching same-AI in-memory audio; hits replay ready state, misses emit nothing, and the lookup signal detaches on settlement while returned-handle cancellation stays independent; `prepareAudioOutput()` returning the persistent WebAudio handle {kind,state,contextState,error,subscribe,resume,dispose} without resume, unmute, model load, sources, sound, or gesture listeners; current-state replay and output-specific canonical `AI_AUDIO_OUTPUT_STATE_EVENT` (`ai-audio-output-state`), with ready only for an actually running context; explicit owner disposal observes context-bound cleanup and close; `playPreparedTTS(prepared,{signal,onState,audioOutput})` returning state, error, finished, pause(), resume(), and stop() with one playback lane per AI and observational state/error callbacks; explicit live same-AI audioOutput borrows its context until owner disposal, while omission or null preserves per-playback terminal close; configure/dispose speech, route lifecycle, declaration-validated chat/stream requests with exact ordered calls; optional streamRequest toolText:{name,field} and onToolText(text,call,displayId) for decoded selected argument text with actual call identity, distinct from ordinary prose and terminal tool execution; synthesis/transcription and playback controls; initializes from current canonical user readiness, installs `window.ai`, and projects `ai-ready` plus active-generation `ai-tts-failure`. `setAI(llmService,sttService,ttsService,model,modelTTS,modelSTT,options)` and `transitionAI(llmService,sttService,ttsService,model,modelTTS,modelSTT,options)` preserve six positional preferences; `configureProviders(selections,options)` and `transitionProviders(selections,options)` accept the same optional {signal:null,startLanguageModel:true} defaults. setAI retains its synchronous boolean and configureProviders its synchronous route result. Explicit `providerRuntime.load('llm',{signal})` or `startProviders({startLanguageModel:true,signal})` activates a deferred selected route."
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
"file": "runtime/arcane/modules/AIModelSelectionController.js",
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"summary": "Sticky mutable LLM, speech-to-text, and text-to-speech lifecycle snapshots, intents, subscriptions, and startup-settlement barriers.",
|
|
134
134
|
"availability": "Cross-host in-process state contract; actual role readiness remains provider specific",
|
|
135
135
|
"protocol": "arcane-ai-runtime-state/1 over the per-realm globalThis.arcaneEvents authority",
|
|
136
|
-
"normalization": "Closed monotonic sticky role snapshots, transient lifecycle intents, synchronous current-state replay, AbortSignal cleanup, and startup settlement are normalized; unloaded recovery/error may retain the exact busy operation until settlement, without readiness for new inference.",
|
|
136
|
+
"normalization": "Closed monotonic sticky role snapshots, transient lifecycle intents, synchronous current-state replay, AbortSignal cleanup, and startup settlement are normalized; unloaded recovery/error may retain the exact busy operation until settlement, without readiness for new inference. During unloading, an already loaded role may retain busy:true with its actual operationId while captured requests settle; this grants no readiness or new-request permission and is not a continuesAIRuntimeOperation recovery state.",
|
|
137
137
|
"surface": "Protocol/event/role/state constants; snapshot, state subscribe/publish, intent request/subscribe, continuesAIRuntimeOperation(previous,current,operationId) for the real continuing runtime operation, and `startAIRuntime({startMuted,startTranscription,signal})` returning `{barrier,settled,cancel}`."
|
|
138
138
|
},
|
|
139
139
|
{
|
|
@@ -1201,7 +1201,7 @@
|
|
|
1201
1201
|
"summary": "Matches configured risk signals and levels against complete text.",
|
|
1202
1202
|
"availability": "Cross-host",
|
|
1203
1203
|
"protocol": "In-process only",
|
|
1204
|
-
"normalization": "
|
|
1204
|
+
"normalization": "Complete literal text; existing non-string conversion only.",
|
|
1205
1205
|
"surface": "`DEFAULT_LEVELS`, `analyzeRiskSignals()`."
|
|
1206
1206
|
},
|
|
1207
1207
|
{
|
|
@@ -86,7 +86,8 @@ transport loss retain their owning cancellation behavior. A terminal engine
|
|
|
86
86
|
failure reaches the original request as its actual error rather than a
|
|
87
87
|
fabricated readiness success. See [native speech reconciliation](native-speech.md).
|
|
88
88
|
|
|
89
|
-
`llamaCpp` accepts `url`, `model`, `modelsDirectory`,
|
|
89
|
+
`llamaCpp` accepts `url`, `model`, `alias`, `modelsDirectory`, `executionTarget`,
|
|
90
|
+
and an `args` string array.
|
|
90
91
|
`model` selects a single GGUF file; `modelsDirectory` selects llama.cpp router
|
|
91
92
|
mode. Paths resolve from the application root. Ollama accepts `url`,
|
|
92
93
|
`modelsDirectory`, and `args`. The default endpoints are
|
|
@@ -94,6 +95,24 @@ mode. Paths resolve from the application root. Ollama accepts `url`,
|
|
|
94
95
|
directories are `.arcane/models/llama.cpp` and `.arcane/models/ollama` inside the
|
|
95
96
|
application. Applications choose and provision their models explicitly.
|
|
96
97
|
|
|
98
|
+
A llama runtime requirement accepts `backend: 'auto' | 'cpu' | 'cuda'`, with
|
|
99
|
+
`auto` preserving the ordinary platform distribution. Explicit `cpu` also
|
|
100
|
+
configures CPU execution, including on a Metal-capable macOS distribution.
|
|
101
|
+
`cuda` currently selects the official Windows x64 CUDA 13.4 engine and its
|
|
102
|
+
matching same-release CUDA companion archive. For example:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{"runtimes": [{"id": "llama.cpp", "backend": "cuda"}]}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Development prepares this explicit distribution instead of treating an unknown
|
|
109
|
+
PATH executable or external listener as proof of its backend. Native packaging
|
|
110
|
+
bundles the selected runtime tree and companion libraries through the existing
|
|
111
|
+
runtime workflow. A custom CUDA `url` also needs its explicit `companionUrl`;
|
|
112
|
+
the SDK does not guess a companion location. Installation records distinguish
|
|
113
|
+
the distribution's `backend` from its `requestedBackend` execution mode.
|
|
114
|
+
Selecting an unavailable distribution reports its actual error.
|
|
115
|
+
|
|
97
116
|
## Development
|
|
98
117
|
|
|
99
118
|
```sh
|
|
@@ -119,10 +138,23 @@ Zstandard archives use the supported Node runtime's decompressor.
|
|
|
119
138
|
|
|
120
139
|
Selected ONNX preparation installs `onnxruntime-node@1.30.0` by default into a
|
|
121
140
|
managed npm prefix, retaining its complete published runtime dependency tree.
|
|
122
|
-
|
|
141
|
+
The npm installation skips supplementary upstream GPU downloads. On Windows
|
|
142
|
+
x64, an omitted version or explicit `1.30.0`, with no explicit `url`, also
|
|
143
|
+
selects the SDK's corrected native distribution, revision
|
|
144
|
+
`1.30.0-directml-reshape-1`. The installer downloads
|
|
145
|
+
`arcane-onnx-runtime-windows-x64.tar.gz` from the installed `arcane-os` package's
|
|
146
|
+
numeric GitHub release and extracts its native libraries into the new
|
|
147
|
+
installation. Its URL is
|
|
148
|
+
`https://github.com/TheWizardNexus/arcane-os-sdk/releases/download/<sdk-version>/arcane-onnx-runtime-windows-x64.tar.gz`.
|
|
149
|
+
The same-version npm JavaScript and binding remain in place. Explicit URLs,
|
|
150
|
+
other ONNX versions and other platform/architecture selections retain their
|
|
151
|
+
upstream package path. For the corrected selection, an existing installation
|
|
152
|
+
without the matching `nativeDistributionRevision` is left intact and a fresh
|
|
153
|
+
installation is prepared; running installations keep their original trees.
|
|
123
154
|
Node/npm must be available while preparing that runtime; a native app consumes
|
|
124
155
|
the bundled tree without installing it again. Applications that omit ONNX do
|
|
125
|
-
not install its package.
|
|
156
|
+
not install its package. Runtime preparation alone establishes no model or
|
|
157
|
+
device execution result.
|
|
126
158
|
|
|
127
159
|
For the optional development browser connection, load the bootstrap after the
|
|
128
160
|
managed import map and before creating a Core-backed provider:
|
|
@@ -226,7 +258,7 @@ background health polling.
|
|
|
226
258
|
| --- | --- | --- |
|
|
227
259
|
| `llama.status` | `{}` | Runtime state and model catalog |
|
|
228
260
|
| `llama.models` | `{}` | `{models}` |
|
|
229
|
-
| `llama.load` | `{model}` | State after the exact model reports loaded |
|
|
261
|
+
| `llama.load` | `{model,assetProjectionId?,resourcePaths?,executionTarget?}` | State after the exact model reports loaded |
|
|
230
262
|
| `llama.unload` | `{model}` | Current state after release |
|
|
231
263
|
| `llama.chat` | `{model,payload,stream?,streamId?}` | Complete OpenAI-shaped completion |
|
|
232
264
|
|
|
@@ -238,6 +270,36 @@ only after Core successfully closes its owned single-model server. Explicit
|
|
|
238
270
|
load, inference or recovery can resume that engine; observation cannot.
|
|
239
271
|
Status observation adds no background polling.
|
|
240
272
|
|
|
273
|
+
For a saved browser GGUF, prepare its complete file through the existing
|
|
274
|
+
[`model-assets` owner](model-assets.md), then call `llama.load` with its
|
|
275
|
+
`assetProjectionId` and `resourcePaths: {model: 'selected.gguf'}`. Core retains
|
|
276
|
+
that member before replacing its owned server, uses the exact `model` value as
|
|
277
|
+
the server alias, and releases the retained use only after actual process exit.
|
|
278
|
+
The preparation owner can release its use when loading settles. Replacement,
|
|
279
|
+
cancelled loading, unload and shutdown all preserve this lifetime. A cancelled
|
|
280
|
+
projected load joins process shutdown before returning. Ordinary router loads
|
|
281
|
+
retain their existing shared-load behavior.
|
|
282
|
+
|
|
283
|
+
`executionTarget: {deviceId}` uses the identifier from this computer's execution
|
|
284
|
+
device catalog. Windows CPU selection disables GPU offload; Windows NVIDIA GPU
|
|
285
|
+
selection requires the CUDA distribution and resolves the current adapter LUID
|
|
286
|
+
to its CUDA UUID. The new server sees that one physical GPU as `CUDA0`.
|
|
287
|
+
No machine-specific device ID is embedded in configuration examples. Each host
|
|
288
|
+
resolves its own saved selection; an absent or unsupported device reports an
|
|
289
|
+
error. Other host adapters remain subject to their declared catalog support.
|
|
290
|
+
`executionTarget: null` uses the configured runtime default. Omission preserves
|
|
291
|
+
an active selection's target. Runtime `execution` separates `requestedTarget`,
|
|
292
|
+
`resolvedDevice` and `configuredTarget`; `observedTarget: null` means actual
|
|
293
|
+
inference placement has not been observed. Configuration is not placement proof.
|
|
294
|
+
|
|
295
|
+
An external server keeps ownership of its model and device. Projected loading
|
|
296
|
+
or explicit target changes report `LOCAL_AI_EXTERNAL_SELECTION_UNSUPPORTED`
|
|
297
|
+
without stopping it or changing a working Core observation. `managed` describes
|
|
298
|
+
whether an installed executable can be managed at this listener; `owned` reports
|
|
299
|
+
an actual SDK-owned process. Recovery retains a live projection across process
|
|
300
|
+
replacement. If the projection was already released after exit, prepare it again;
|
|
301
|
+
resuming never substitutes another model or target.
|
|
302
|
+
|
|
241
303
|
The `payload` is the complete request. SDK option names are translated only at
|
|
242
304
|
the upstream protocol boundary; messages, tool definitions and documents remain
|
|
243
305
|
unchanged. An explicit `payload.model` selects that request's model. Core waits
|
|
@@ -365,10 +427,44 @@ runtime still reconciles the provider at its existing operation boundaries.
|
|
|
365
427
|
permits that load preflight even before its catalog arrives; Core's `llama.load`
|
|
366
428
|
waits for startup and verifies the exact requested model. An owned, successfully
|
|
367
429
|
released service permits loading only a model retained in its actual catalog.
|
|
368
|
-
|
|
430
|
+
With `prepareModel`, an installed `managed` service also admits an explicit
|
|
431
|
+
load before the requested model exists in its catalog. An available external
|
|
432
|
+
service still requires catalog membership. These observations
|
|
369
433
|
do not fabricate model records or readiness, and unavailable external services,
|
|
370
434
|
closed services and actual errors remain unavailable.
|
|
371
435
|
|
|
436
|
+
The optional `prepareModel({selection,signal,progress})` callback runs only at
|
|
437
|
+
an actual provider load. Return `{assetProjectionId,resourcePaths,executionTarget,release?}`;
|
|
438
|
+
direct `provider.load` fields override the corresponding callback
|
|
439
|
+
fields, including an explicit null target. The provider awaits `release()`
|
|
440
|
+
after Core loading settles and before reporting readiness. Preparation must
|
|
441
|
+
observe cancellation and settle so even a late returned projection is released.
|
|
442
|
+
Only a dispatched Core selection owns a native unload; cancelled preparation
|
|
443
|
+
alone does not unload another model.
|
|
444
|
+
|
|
445
|
+
```js
|
|
446
|
+
import {prepareCoreModelAssets} from 'arcane-os/ai/core-model-assets';
|
|
447
|
+
|
|
448
|
+
// modelFile is the complete GGUF Blob/File read from the application's store.
|
|
449
|
+
// selectedDeviceId came from this host's execution-device catalog.
|
|
450
|
+
const provider = createCoreLocalAIProvider({
|
|
451
|
+
client,
|
|
452
|
+
async prepareModel({signal, progress}) {
|
|
453
|
+
const projection = await prepareCoreModelAssets({
|
|
454
|
+
client, workingDirectory: '.arcane/model-work', signal,
|
|
455
|
+
members: [{path: 'moon-raccoon.gguf', file: modelFile}],
|
|
456
|
+
onProgress: progress
|
|
457
|
+
});
|
|
458
|
+
return {
|
|
459
|
+
assetProjectionId: projection.id,
|
|
460
|
+
resourcePaths: {model: 'moon-raccoon.gguf'},
|
|
461
|
+
executionTarget: {deviceId: selectedDeviceId},
|
|
462
|
+
release: projection.release
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
```
|
|
467
|
+
|
|
372
468
|
`dispose()` removes installation and service subscriptions and cancels owned
|
|
373
469
|
operations synchronously, then attempts its actually retained model's release
|
|
374
470
|
through its captured client. A configured selection alone does not own a native
|
|
@@ -639,7 +735,7 @@ not execution evidence on each platform.
|
|
|
639
735
|
|
|
640
736
|
## Native bundling
|
|
641
737
|
|
|
642
|
-
The SDK portable native build includes selected
|
|
738
|
+
The SDK portable native build includes complete selected runtime trees under
|
|
643
739
|
`runtime/local-ai/<runtime-id>`. Runtime records in the artifact are relative
|
|
644
740
|
to the artifact root and resolve on the destination machine. The generated
|
|
645
741
|
Core entry composes the local AI service only when the application selects it.
|
|
@@ -649,13 +745,16 @@ Model files remain application-selected native resources.
|
|
|
649
745
|
`arcane-os/local-ai`. Both accept `{runtimes,directory,platform,architecture,
|
|
650
746
|
signal,onEvent}`; bundling also requires `outputRoot`. Platform names follow
|
|
651
747
|
Node: `win32`, `linux`, `darwin`, and supported Android distributions.
|
|
652
|
-
Architectures are `x64` or `arm64`. Availability depends on the
|
|
653
|
-
|
|
748
|
+
Architectures are `x64` or `arm64`. Availability depends on the selected
|
|
749
|
+
distribution's published platform assets; Ollama has no official Android runtime
|
|
654
750
|
archive in this installer.
|
|
655
751
|
|
|
656
752
|
Ensure returns absolute `{id,version,platform,architecture,root}` records.
|
|
657
753
|
Server runtimes also include `executable`; ONNX includes `modulePath` pointing
|
|
658
|
-
to its public package entry.
|
|
754
|
+
to its public package entry. The corrected Windows x64 ONNX selection also
|
|
755
|
+
includes `nativeDistributionRevision: '1.30.0-directml-reshape-1'`; bundling
|
|
756
|
+
retains that metadata with the complete native libraries. Image records include
|
|
757
|
+
`libraryPath`,
|
|
659
758
|
`bindingModulePath`, requested `backend`, installed `variants` and selected
|
|
660
759
|
`models` metadata. Variant records carry backend, runtime root and library path.
|
|
661
760
|
Bundle returns `{runtimes,files}`,
|
|
@@ -75,7 +75,8 @@ Save this in the consuming application and configure the MCP client's subprocess
|
|
|
75
75
|
command as `node` with that application's script path. Client configuration
|
|
76
76
|
file formats and process launch policy remain client-owned. Change `menu` to
|
|
77
77
|
change the complete result; no model, repository, or native host is needed for
|
|
78
|
-
this example.
|
|
78
|
+
this example. A native package can instead use its
|
|
79
|
+
[existing bundled runtime](#launch-from-a-native-package).
|
|
79
80
|
|
|
80
81
|
The application explicitly converts its domain record into an MCP result.
|
|
81
82
|
The SDK does not guess from `content`, `message`, or other domain field names.
|
|
@@ -255,6 +256,80 @@ The adapter uses `-32700` for malformed JSON, `-32600` for invalid requests,
|
|
|
255
256
|
`-32603` for internal failures, and `-32002` for a missing resource. Its
|
|
256
257
|
`-32000` lifecycle error requests initialization before ordinary operations.
|
|
257
258
|
|
|
259
|
+
## Launch from a native package
|
|
260
|
+
|
|
261
|
+
The generated `runtime/arcane-core.mjs` accepts
|
|
262
|
+
`--arcane-app-entry <app-relative-module>` to import an application-owned entry
|
|
263
|
+
instead of starting ordinary Core. Include the entry and its complete local
|
|
264
|
+
source closure in the application's `package.nativeResources`, for example:
|
|
265
|
+
|
|
266
|
+
```json
|
|
267
|
+
{
|
|
268
|
+
"package": {
|
|
269
|
+
"nativeResources": {
|
|
270
|
+
"include": ["native", "src", "package.json"]
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Save the complete example above as `native/moon-mcp.mjs`. Native packaging copies
|
|
277
|
+
the selected files beneath the artifact's `app/` directory. It does not discover
|
|
278
|
+
entry dependencies from this runtime argument or execute the entry during
|
|
279
|
+
packaging. Public imports such as `arcane-os/mcp/stdio` use the artifact's
|
|
280
|
+
existing SDK package and Node's ordinary package resolution.
|
|
281
|
+
|
|
282
|
+
Configure the MCP client's command and argument array for the selected artifact:
|
|
283
|
+
|
|
284
|
+
| Artifact | Command | Arguments |
|
|
285
|
+
| --- | --- | --- |
|
|
286
|
+
| Windows | `<artifact-root>/runtime/ArcaneCore.exe` | `["--arcane-app-entry", "native/moon-mcp.mjs"]` |
|
|
287
|
+
| macOS | `<artifact-root>/runtime/node` | `["<artifact-root>/runtime/arcane-core.mjs", "--arcane-app-entry", "native/moon-mcp.mjs"]` |
|
|
288
|
+
| Portable | The host's supported Node executable | `["<artifact-root>/runtime/arcane-core.mjs", "--arcane-app-entry", "native/moon-mcp.mjs"]` |
|
|
289
|
+
|
|
290
|
+
These are placeholders for the actual native paths. For macOS, `artifact-root`
|
|
291
|
+
is `<app-id>.app/Contents/Resources`. The portable provider supplies no Node
|
|
292
|
+
executable. Windows uses its existing SEA executable and filesystem loader;
|
|
293
|
+
do not pass `arcane-core.mjs` as a script argument to that executable. These
|
|
294
|
+
commands select the runtime directly, not the GUI launcher, and create no
|
|
295
|
+
window or second Core host.
|
|
296
|
+
|
|
297
|
+
The module path resolves from the artifact's `app/`, independently of the
|
|
298
|
+
client's working directory. Native path separators, spaces, Unicode, `#` and
|
|
299
|
+
`%` retain their filesystem meaning through file-URL conversion. The original
|
|
300
|
+
`process.argv` remains complete and unchanged, including this flag, its path,
|
|
301
|
+
and every app argument. The flag is read from user arguments starting at index
|
|
302
|
+
2 for both normal Node and SEA. A missing or empty value throws `TypeError`;
|
|
303
|
+
module-loading failures remain actual errors and never start ordinary Core.
|
|
304
|
+
|
|
305
|
+
This is a dynamic import: the entry runs its top-level code and observes its
|
|
306
|
+
own session lifetime, as the example's `server.start()` and `await server.closed`
|
|
307
|
+
do. Do not put its only startup behind `if (import.meta.main)`; the imported
|
|
308
|
+
module is not Node's main entry. The SDK calls no default export or factory.
|
|
309
|
+
|
|
310
|
+
App-entry mode skips ordinary Core launch-context loading, manifest service
|
|
311
|
+
composition, state-directory creation, local-AI startup, shared-host startup,
|
|
312
|
+
and Core signal handlers. If the application wants the existing explicit launch
|
|
313
|
+
JSON or host state-root arguments, append them to the same argument array and
|
|
314
|
+
read them deliberately in its entry:
|
|
315
|
+
|
|
316
|
+
```javascript
|
|
317
|
+
import {readCoreLaunchContext} from 'arcane-os/core/host';
|
|
318
|
+
|
|
319
|
+
const context = await readCoreLaunchContext();
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
For example, append `"--arcane-launch-config", "<selected-launch.json>"`.
|
|
323
|
+
Relative launch JSON paths retain their caller-working-directory meaning. The
|
|
324
|
+
application chooses defaults, services and any connection to an existing Core;
|
|
325
|
+
the entry selector neither reads nor applies the manifest's launch defaults.
|
|
326
|
+
|
|
327
|
+
The application owns process signals, graceful MCP drain, and its underlying
|
|
328
|
+
service shutdown. Keep stdout exclusively for MCP JSON-RPC and diagnostics on
|
|
329
|
+
stderr; the ordinary Core `arcane/1` transport must not share those MCP pipes.
|
|
330
|
+
When the flag is absent, ordinary Core startup and service lifecycle are
|
|
331
|
+
unchanged. See [native entry composition](core-native-packaging.md#app-owned-runtime-entry).
|
|
332
|
+
|
|
258
333
|
## Evidence boundary
|
|
259
334
|
|
|
260
335
|
`test/mcp-stdio-server.test.mjs` contains focused in-memory stream fixtures for
|
|
@@ -73,11 +73,11 @@ connection or other business result.
|
|
|
73
73
|
| Member | Contract |
|
|
74
74
|
| --- | --- |
|
|
75
75
|
| `connectAppControl({endpoint, signal?, onError?})` | Connect once to the explicit running host. It never launches an app, creates Core, changes a profile or reconnects automatically. |
|
|
76
|
-
| `status(options?)` | Returns app identity, platform/host, current URL, document generation, readiness, window title/state/client dimensions and available operations. Readiness describes the document, not models or application services. |
|
|
76
|
+
| `status(options?)` | Returns app identity, platform/host, current URL, document generation, readiness, window title/state/client dimensions and available operations. Window state is `Normal`, `Maximized`, `Minimized`, or `Fullscreen`. Readiness describes the document, not models or application services. |
|
|
77
77
|
| `inspect(parameters={}, options?)` | Optional `shadowPath` selects an open shadow root. Optional CSS `selector` selects zero or more elements within the selected root; omission selects the whole root. Optional `documentGeneration` selects the expected document. Returns complete HTML/text, live control state and DOM-derived role/name hints. |
|
|
78
78
|
| `capture(parameters={}, options?)` | Returns `{mimeType:'image/png', data, documentGeneration, url}`. `data` contains the complete base64 PNG. Optional `documentGeneration` selects the expected document. |
|
|
79
79
|
| `act(parameters, options?)` | Requires `documentGeneration`, one unambiguous CSS `selector` within the root selected by optional `shadowPath`, and the action fields below. |
|
|
80
|
-
| `key(parameters, options?)` | Requires `documentGeneration` and `key:'Tab'`, `'Enter'`, or `'
|
|
80
|
+
| `key(parameters, options?)` | Requires `documentGeneration` and `key:'Tab'`, `'Enter'`, `'Space'`, or `'Escape'`. Optional `shiftKey:true` is supported only for Tab. Sends one ordered press/release pair to the selected WebView's current focus. |
|
|
81
81
|
| `resize(parameters, options?)` | Requires positive integral native client `width` and `height` supported by WinForms. Optional `documentGeneration` selects the expected document. Resizes only a Normal window and returns immediate previous/actual client dimensions plus the subsequently observed CSS viewport. |
|
|
82
82
|
| `close()` | Closes this caller's connection and cancels its pending requests. It never closes the app or Core. Returns the connection's completion promise. |
|
|
83
83
|
| `closed` | Connection lifetime promise; actual transport failures remain observable. |
|
|
@@ -207,6 +207,8 @@ const moved = await app.key({documentGeneration: page.documentGeneration, key: '
|
|
|
207
207
|
console.log(moved.previous.focusPath, moved.actual.focusPath);
|
|
208
208
|
await app.key({documentGeneration: moved.documentGeneration, key: 'Tab', shiftKey: true});
|
|
209
209
|
await app.key({documentGeneration: moved.documentGeneration, key: 'Enter'});
|
|
210
|
+
const current = await app.inspect();
|
|
211
|
+
await app.key({documentGeneration: current.documentGeneration, key: 'Escape'});
|
|
210
212
|
```
|
|
211
213
|
|
|
212
214
|
Keys use the selected WebView's current focus. No selector, shadow path, frame
|
|
@@ -214,7 +216,10 @@ selection, focus assignment or desktop activation is performed. Tab and
|
|
|
214
216
|
Shift+Tab use a fixed Tab `rawKeyDown`/`keyUp` pair, with the Shift modifier on
|
|
215
217
|
both events for Shift+Tab. Enter and Space use `keyDown` with their corresponding
|
|
216
218
|
text, followed by `keyUp`, preserving browser default actions and application
|
|
217
|
-
`preventDefault` handling.
|
|
219
|
+
`preventDefault` handling. Escape uses `key:'Escape'`, `code:'Escape'` and native
|
|
220
|
+
virtual key 27 in a `rawKeyDown`/`keyUp` pair, without text fields. It follows the
|
|
221
|
+
selected WebView's normal Escape handling; it does not promise that a particular
|
|
222
|
+
dialog closes. Shift+Tab does not send a separate Shift key pair.
|
|
218
223
|
The API exposes these fixed keys, not an arbitrary protocol method or script.
|
|
219
224
|
|
|
220
225
|
The result contains `key`, `shiftKey`, `previous` and `actual` document views,
|
|
@@ -264,7 +269,7 @@ origin. Read `viewport` for the resulting CSS dimensions instead of assuming a
|
|
|
264
269
|
particular DPI or zoom conversion.
|
|
265
270
|
|
|
266
271
|
Immediately before the UI-thread mutation, the host checks the actual
|
|
267
|
-
|
|
272
|
+
window state and records `previous:{title,state,width,height}`. It records
|
|
268
273
|
`actual` in the same shape immediately after the native setter, then observes
|
|
269
274
|
the CSS `viewport` asynchronously. The result also contains `requested`,
|
|
270
275
|
`resizeAttempted`, `resizeCompleted`, `documentGeneration` and `url`.
|
|
@@ -274,13 +279,20 @@ native snapshot and the document observation; these records are not an atomic
|
|
|
274
279
|
native/CSS snapshot. Completion does not establish that asynchronous application
|
|
275
280
|
resize handlers have settled.
|
|
276
281
|
|
|
277
|
-
Maximized or
|
|
282
|
+
Maximized, minimized or fullscreen windows return `ARCANE_APP_CONTROL_FAILED` before any
|
|
278
283
|
size mutation, with `reason:'unsupported-window-state'`,
|
|
279
284
|
`supportedWindowState:'Normal'` and the complete current `window` in the error's
|
|
280
285
|
`data` entries. The host never automatically restores, maximizes or minimizes a
|
|
281
286
|
window to satisfy this request. Invalid dimensions return `INVALID_ARGUMENT`.
|
|
282
287
|
The same state rule applies to explicit restoration.
|
|
283
288
|
|
|
289
|
+
Native fullscreen reports `Fullscreen`, including while its underlying WinForms
|
|
290
|
+
state is Normal. A minimized fullscreen window reports `Minimized`. The
|
|
291
|
+
requesting document can select its state through
|
|
292
|
+
[`Arcane.window.setState({state})`](core-client.md#current-window-state); app-control
|
|
293
|
+
does not add a separate state-setting operation. That facade uses lowercase
|
|
294
|
+
state values, while app-control preserves its existing capitalized values.
|
|
295
|
+
|
|
284
296
|
Restore using the actual `previous.width` and `previous.height` from the
|
|
285
297
|
operation being reversed, never a historical status snapshot or CSS viewport
|
|
286
298
|
dimensions. Restoration is an explicit second request; cancellation does not
|
|
@@ -475,6 +475,20 @@ the selected runtime content. The lock document describes the selected
|
|
|
475
475
|
installation and projected roots; it is not a content-identity or admission
|
|
476
476
|
record.
|
|
477
477
|
|
|
478
|
+
Both runtime materializers accept explicit `browserDecisions: true` to acquire
|
|
479
|
+
the upstream bundled Transformers.js 4.3.0 entry, matching ONNX Runtime
|
|
480
|
+
1.31.0-dev.20260914-8d85527a0 asyncify module/WASM, and license files into
|
|
481
|
+
`arcane/sdk/ai/decisions-runtime/` before replacement. Default `false` performs
|
|
482
|
+
no optional acquisition. The complete selected files remain unchanged;
|
|
483
|
+
`workspace.decisions.started`/`workspace.decisions.progress` count completed
|
|
484
|
+
files. Cancellation, HTTP failures and observer failures join acquisition
|
|
485
|
+
cleanup and preserve the previous projection. Retain the option on each refresh
|
|
486
|
+
that needs the closure. The optional `browserDecisions` result describes its
|
|
487
|
+
directory, versions and filenames; installed materialization nests it under
|
|
488
|
+
`workspaceRuntime`. Model/tokenizer data remain upstream and cache-owned.
|
|
489
|
+
See [extension-local decisions](ai/browser-decisions.md#extension-local-executables-manifest-v3)
|
|
490
|
+
for the separate `runtime.local: true` browser selection.
|
|
491
|
+
|
|
478
492
|
`upgradeApplication()` and `arcane upgrade` run the application's ordinary
|
|
479
493
|
`npm upgrade` command. They do not independently reconcile the installed SDK
|
|
480
494
|
projection, semantic Arcane lock, or managed import map.
|
|
@@ -128,7 +128,7 @@ own asynchronous work, cancellation, and backpressure.
|
|
|
128
128
|
| [`RecordLinkIndex.js`](#recordlinkindexjs) | esm | Parses record links and builds their normalized index. | Cross-host | Fully normalized. |
|
|
129
129
|
| [`RecordPassageIndex.js`](#recordpassageindexjs) | esm | Indexes text lines, page markers, dates, rules, and excerpts for record review. | Cross-host | Fully normalized. |
|
|
130
130
|
| [`RecordReviewStore.js`](#recordreviewstorejs) | esm | Stores normalized record-review decisions through native storage or app-scoped local fallback. | Browser/native hybrid | Complete records preserved; unreadable stored content fails observably. |
|
|
131
|
-
| [`RiskSignalAnalyzer.js`](#risksignalanalyzerjs) | esm | Matches configured risk signals and levels against complete text. | Cross-host |
|
|
131
|
+
| [`RiskSignalAnalyzer.js`](#risksignalanalyzerjs) | esm | Matches configured risk signals and levels against complete text. | Cross-host | Complete literal text; existing non-string conversion only. |
|
|
132
132
|
| [`ScamRiskPolicy.js`](#scamriskpolicyjs) | esm | Combines deterministic scam signals with optional Arcane blocked-domain evidence and safety guidance. | Cross-host | Complete mutable results; blocked-domain policy requires `secure:true`. |
|
|
133
133
|
| [`ScopedOPFSCache.js`](#scopedopfscachejs) | esm | Provides a narrow exact-key JSON cache inside one app-owned OPFS namespace. | Browser / native WebView | Filename-safe keys, complete JSON values, and malformed-cache cleanup normalized; storage errors mixed. |
|
|
134
134
|
| [`ScreenCapture.js`](#screencapturejs) | esm | Captures a display surface as image, video, or GIF with explicit lifecycle events. | Browser / native WebView | State/events normalized; permission and codec errors mixed. |
|
|
@@ -1386,7 +1386,11 @@ transcription-model load.
|
|
|
1386
1386
|
**Cross-host state contract.** States are `unavailable`, `unloaded`, `loading`,
|
|
1387
1387
|
`recovering`, `ready`, `unloading`, `error`, and `disposed`. Recovery remains
|
|
1388
1388
|
`loaded: false`; `recovering` and `error` may retain `busy: true` with an actual
|
|
1389
|
-
`operationId` until the pending request settles.
|
|
1389
|
+
`operationId` until the pending request settles. During `unloading`, an already
|
|
1390
|
+
loaded role may retain `busy: true` with its actual `operationId` while captured
|
|
1391
|
+
requests settle. That observation grants no readiness or permission for a new
|
|
1392
|
+
request and is not a `continuesAIRuntimeOperation` recovery state.
|
|
1393
|
+
Revisions increase monotonically.
|
|
1390
1394
|
The events `arcane-ai-runtime-state`, `arcane-ai-runtime-intent`, and
|
|
1391
1395
|
`arcane-ai-runtime-startup-settled` normalize observation only: receiving one
|
|
1392
1396
|
does not grant a native capability, prove browser support, or load a provider.
|
|
@@ -4010,9 +4014,11 @@ Matches configured risk signals and levels against complete text.
|
|
|
4010
4014
|
|
|
4011
4015
|
Exact exports: `DEFAULT_LEVELS`, `analyzeRiskSignals`.
|
|
4012
4016
|
|
|
4017
|
+
`analyzeRiskSignals(input, {signals, levels})` scans the complete `String(input ?? '')` without Unicode normalization or whitespace changes. Fullwidth characters and decomposed characters remain as supplied. Each signal's `RegExp.lastIndex` resets before testing; signal order, weights and selected levels determine the mutable `{level, matches, score, textLength}` result. `textLength` is the JavaScript string length after the existing non-string conversion; `null` and `undefined` become an empty string. Ordinary `ScamRiskPolicy.assessScamRisk()` uses this same literal-text path.
|
|
4018
|
+
|
|
4013
4019
|
### Availability and normalization
|
|
4014
4020
|
|
|
4015
|
-
**Cross-host.**
|
|
4021
|
+
**Cross-host.** Complete literal text; existing non-string conversion only. Transport: In-process only. [Deep protocol details](protocols.md).
|
|
4016
4022
|
|
|
4017
4023
|
### Example
|
|
4018
4024
|
|