arcane-os 0.66.0 → 0.67.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 +23 -0
- package/README.md +1 -1
- package/browser-runtime/ai/core-image.mjs +84 -34
- package/browser-runtime/ai/core-local.mjs +195 -43
- package/browser-runtime/ai/core-onnx.mjs +71 -12
- package/docs/reference/README.md +1 -0
- package/docs/reference/core-native-packaging.md +11 -4
- package/docs/reference/core-repositories.md +93 -9
- package/docs/reference/core-runtime.md +32 -5
- package/docs/reference/inventory/package-api.json +9 -9
- package/docs/reference/local-ai.md +112 -2
- package/docs/reference/local-image-generation.md +15 -4
- package/docs/reference/model-assets.md +50 -3
- package/docs/reference/native-decisions.md +181 -0
- package/docs/reference/sdk-api.md +55 -12
- package/package.json +5 -2
- package/src/core/repositories.mjs +27 -8
- package/src/core/runtime.mjs +11 -0
- package/src/core/services/decisions.mjs +144 -0
- package/src/core/services/local-ai.mjs +31 -9
- package/src/core/services/model-assets.mjs +98 -13
- package/src/git-identity.mjs +22 -58
- package/src/local-ai/decision-tokenizer-worker.mjs +31 -0
- package/src/local-ai/decision-tokenizer.mjs +109 -0
- package/src/local-ai/decisions.mjs +273 -0
- package/src/local-ai/dev.mjs +8 -2
- package/src/local-ai/onnx-worker.mjs +67 -7
- package/src/local-ai/onnx.mjs +23 -12
- package/src/native/portable-layout.mjs +8 -3
- package/src/repository.mjs +144 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {subscribeCoreClient} from '../core/client.mjs';
|
|
2
2
|
import {createArcaneEventSource} from '../event-manager.mjs';
|
|
3
3
|
import {encodeTensorMap, decodeTensorMap, encodeTensorFetches} from './onnx-tensors.mjs';
|
|
4
4
|
|
|
@@ -9,16 +9,26 @@ function unavailable(message) {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/** Optional system ONNX access. Construction neither connects nor installs. */
|
|
12
|
-
export function createCoreONNXRuntime({client
|
|
12
|
+
export function createCoreONNXRuntime({client: suppliedClient} = {}) {
|
|
13
13
|
const owner = {};
|
|
14
14
|
const events = createArcaneEventSource(owner, {source: 'core-onnx', eventTypes: ['onnx.state']});
|
|
15
15
|
const lifetime = new AbortController();
|
|
16
16
|
const pending = new Set();
|
|
17
|
+
let client = null;
|
|
18
|
+
let connection = null;
|
|
19
|
+
let stopInstallation;
|
|
17
20
|
let state = {id: 'onnx', installed: false, available: false, state: 'unknown', models: []};
|
|
18
21
|
let revision = 0;
|
|
19
22
|
let closed = false;
|
|
20
23
|
|
|
21
|
-
function current() {
|
|
24
|
+
function current() {
|
|
25
|
+
const busy = [...pending].some(
|
|
26
|
+
function currentRequest(request) {
|
|
27
|
+
return request.connection === connection && !request.signal.aborted;
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
return {...state, busy, closed};
|
|
31
|
+
}
|
|
22
32
|
function publish() { events.dispatch('onnx.state', current()); }
|
|
23
33
|
function accept(value) {
|
|
24
34
|
state = value ?? {id: 'onnx', installed: false, available: false, state: 'unavailable', models: []};
|
|
@@ -26,30 +36,66 @@ export function createCoreONNXRuntime({client = getInstalledCoreClient()} = {})
|
|
|
26
36
|
publish();
|
|
27
37
|
}
|
|
28
38
|
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
|
|
39
|
+
function bindClient({client: nextClient, error = null}) {
|
|
40
|
+
if (closed || (connection && nextClient === client)) return;
|
|
41
|
+
const previous = connection;
|
|
42
|
+
client = nextClient;
|
|
43
|
+
const currentConnection = {client, controller: new AbortController(), unsubscribe: null};
|
|
44
|
+
connection = currentConnection;
|
|
45
|
+
revision += 1;
|
|
46
|
+
state = {id: 'onnx', installed: false, available: false, state: client ? 'unknown' : 'unavailable', models: [], error};
|
|
47
|
+
previous?.unsubscribe?.();
|
|
48
|
+
previous?.controller.abort();
|
|
49
|
+
if (client) {
|
|
50
|
+
currentConnection.unsubscribe = client.events.on(
|
|
51
|
+
'localai.state',
|
|
52
|
+
function localStateChanged(snapshot) {
|
|
53
|
+
if (!closed && connection === currentConnection) {
|
|
54
|
+
accept(snapshot?.runtimes?.find(function onnxRuntime(runtime) { return runtime.id === 'onnx'; }));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
publish();
|
|
60
|
+
if (!closed && connection === currentConnection && client && suppliedClient === undefined) {
|
|
61
|
+
inspect().catch(
|
|
62
|
+
function initialONNXStateUnavailable(error) {
|
|
63
|
+
if (!closed && connection === currentConnection && !currentConnection.controller.signal.aborted) {
|
|
64
|
+
globalThis.console?.error('Core ONNX initial state unavailable.', error);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
32
70
|
|
|
33
71
|
async function invoke(method, parameters, {signal, timeoutMs = 0} = {}) {
|
|
34
72
|
if (closed) throw unavailable('The Core ONNX accessor is closed.');
|
|
35
73
|
if (!client) throw unavailable('Local ONNX requires an available Core connection.');
|
|
36
|
-
const
|
|
37
|
-
const operationSignal =
|
|
74
|
+
const currentConnection = connection;
|
|
75
|
+
const operationSignal = AbortSignal.any(
|
|
76
|
+
[lifetime.signal, currentConnection.controller.signal, ...(signal ? [signal] : [])]
|
|
77
|
+
);
|
|
78
|
+
const request = {connection: currentConnection, signal: operationSignal};
|
|
38
79
|
operationSignal.throwIfAborted();
|
|
39
80
|
pending.add(request);
|
|
40
81
|
publish();
|
|
41
82
|
try {
|
|
42
|
-
|
|
83
|
+
operationSignal.throwIfAborted();
|
|
84
|
+
const result = await currentConnection.client.invoke(method, parameters, {signal: operationSignal, timeoutMs});
|
|
85
|
+
operationSignal.throwIfAborted();
|
|
86
|
+
return result;
|
|
43
87
|
} finally {
|
|
44
88
|
pending.delete(request);
|
|
45
|
-
if (!closed) publish();
|
|
89
|
+
if (!closed && connection === currentConnection) publish();
|
|
46
90
|
}
|
|
47
91
|
}
|
|
48
92
|
|
|
49
93
|
async function inspect(options) {
|
|
50
94
|
const before = revision;
|
|
95
|
+
const currentConnection = connection;
|
|
51
96
|
try {
|
|
52
97
|
const result = await invoke('onnx.status', {}, options);
|
|
98
|
+
currentConnection.controller.signal.throwIfAborted();
|
|
53
99
|
if (!closed && revision === before) accept(result);
|
|
54
100
|
return current();
|
|
55
101
|
} catch (error) {
|
|
@@ -61,14 +107,19 @@ export function createCoreONNXRuntime({client = getInstalledCoreClient()} = {})
|
|
|
61
107
|
}
|
|
62
108
|
|
|
63
109
|
async function load({id, model, sessionOptions, signal, timeoutMs} = {}) {
|
|
64
|
-
|
|
110
|
+
const currentConnection = connection;
|
|
111
|
+
const result = await invoke('onnx.load', {id, model, sessionOptions}, {signal, timeoutMs});
|
|
112
|
+
currentConnection.controller.signal.throwIfAborted();
|
|
113
|
+
return result;
|
|
65
114
|
}
|
|
66
115
|
|
|
67
116
|
async function run({id, feeds, fetches, runOptions, signal, timeoutMs} = {}) {
|
|
117
|
+
const currentConnection = connection;
|
|
68
118
|
const result = await invoke('onnx.run', {
|
|
69
119
|
id, feeds: encodeTensorMap(feeds),
|
|
70
120
|
fetches: encodeTensorFetches(fetches), runOptions
|
|
71
121
|
}, {signal, timeoutMs});
|
|
122
|
+
currentConnection.controller.signal.throwIfAborted();
|
|
72
123
|
return decodeTensorMap(result);
|
|
73
124
|
}
|
|
74
125
|
|
|
@@ -86,11 +137,19 @@ export function createCoreONNXRuntime({client = getInstalledCoreClient()} = {})
|
|
|
86
137
|
if (closed) return;
|
|
87
138
|
closed = true;
|
|
88
139
|
lifetime.abort();
|
|
89
|
-
|
|
140
|
+
stopInstallation?.();
|
|
141
|
+
connection?.unsubscribe?.();
|
|
142
|
+
connection?.controller.abort();
|
|
90
143
|
state = {...state, available: false, state: 'closed'};
|
|
91
144
|
publish();
|
|
92
145
|
events.dispose();
|
|
93
146
|
}
|
|
94
147
|
|
|
148
|
+
if (suppliedClient === undefined) {
|
|
149
|
+
stopInstallation = subscribeCoreClient(bindClient, {signal: lifetime.signal});
|
|
150
|
+
} else {
|
|
151
|
+
bindClient({client: suppliedClient});
|
|
152
|
+
}
|
|
153
|
+
|
|
95
154
|
return {load, run, unload, inspect, current, subscribe, close};
|
|
96
155
|
}
|
package/docs/reference/README.md
CHANGED
|
@@ -70,6 +70,7 @@ alone does not make bare module names resolve in a browser.
|
|
|
70
70
|
| Persist application-selected preferences through Core | [Core preferences service](core-preferences.md) |
|
|
71
71
|
| Read complete selected Git text without changing a checkout | [Git text snapshots](git-text-snapshot.md) |
|
|
72
72
|
| Own a native working checkout under per-user ArcaneData/Repos | [Native repository workspaces](core-repositories.md) |
|
|
73
|
+
| Read Git identity defaults or select child-only author and credential hints | [Git identity configuration](core-repositories.md#git-identity-configuration) |
|
|
73
74
|
| Write, commit and push complete selected repository text | [Selected-text repository writing](core-repositories.md#write-commit-and-push-selected-text) |
|
|
74
75
|
| Build an installed-SDK portable Core payload | [Portable Core packaging](core-native-packaging.md) |
|
|
75
76
|
| Pass host-selected state defaults and unchanged explicit launch values to services | [Launch-time locations](core-native-packaging.md#launch-time-locations) |
|
|
@@ -261,10 +261,17 @@ service exposes retained worker sessions through `onnx.load/run/unload/status`;
|
|
|
261
261
|
model files remain caller-selected application resources. See
|
|
262
262
|
[native ONNX sessions](local-ai.md#native-onnx-sessions).
|
|
263
263
|
|
|
264
|
-
|
|
265
|
-
`
|
|
266
|
-
|
|
267
|
-
|
|
264
|
+
Selecting ONNX, image generation, or both composes one shared
|
|
265
|
+
`createModelAssetService` from `arcane-os/core/model-assets`. Native application
|
|
266
|
+
services obtain that same definition with `await context.getService('model-assets')`.
|
|
267
|
+
They obtain the selected local-AI owner with `await context.getService('local-ai')`
|
|
268
|
+
and its current native ONNX handle with `getONNXRuntime()`. These lookups await
|
|
269
|
+
only their selected service startup, independently of renderer readiness. See
|
|
270
|
+
[native service ownership and cleanup](local-ai.md#native-service-owners).
|
|
271
|
+
|
|
272
|
+
Selected `stable-diffusion.cpp` additionally composes `createLocalImageService`
|
|
273
|
+
from `arcane-os/core/image`. The image factory receives the full authored
|
|
274
|
+
selection plus that same model-assets instance.
|
|
268
275
|
Library, Koffi binding and variant paths resolve from the artifact root;
|
|
269
276
|
ordinary browser imports use `arcane-os/ai/core-image` and
|
|
270
277
|
`arcane-os/ai/core-model-assets` through the managed import map.
|
|
@@ -24,7 +24,8 @@ The Android host also supplies Git/process execution through the existing
|
|
|
24
24
|
process-adapter contract; this module does not install Git or choose shared
|
|
25
25
|
Android storage.
|
|
26
26
|
|
|
27
|
-
The factory's first
|
|
27
|
+
The factory's first operation that prepares a checkout creates necessary parent
|
|
28
|
+
directories. The read-only `configuration` operation never prepares one.
|
|
28
29
|
No existing data is moved, copied, deleted, renamed or migrated. `appRoot`,
|
|
29
30
|
`stateRoot`, preferences, OPFS and the existing CLI/workspace defaults remain
|
|
30
31
|
independent and unchanged.
|
|
@@ -47,7 +48,7 @@ await repository.close();
|
|
|
47
48
|
```
|
|
48
49
|
|
|
49
50
|
`createRepositoryWorkspace({name,directory,dataRoot,remote,branch,gitIdentity,onEvent,run}={})`
|
|
50
|
-
returns `{directory,open,status,pull,push,write,close,drain,dispose}`. The `directory`
|
|
51
|
+
returns `{directory,open,status,configuration,pull,push,write,close,drain,dispose}`. The `directory`
|
|
51
52
|
property is the absolute selected working path.
|
|
52
53
|
|
|
53
54
|
- Omit `directory` to select `<repositoriesRoot>/<name>`. The application supplies
|
|
@@ -67,15 +68,17 @@ property is the absolute selected working path.
|
|
|
67
68
|
authentication remain with Git and the native host. The SDK adds no download,
|
|
68
69
|
credential store, polling, network retry or process supervisor.
|
|
69
70
|
|
|
70
|
-
The open/status/
|
|
71
|
+
The open/status/configuration methods accept `{signal}={}` and return promises;
|
|
72
|
+
pull/push accept `{target,signal}={}` with an optional captured destination.
|
|
71
73
|
`write` accepts the complete file/message request described below:
|
|
72
74
|
|
|
73
75
|
| Method | Result and side effect |
|
|
74
76
|
|---|---|
|
|
75
77
|
| `open` | For a missing/empty destination, runs one clone and returns `{directory,cloned:true,stdout,stderr}` with complete process output. For an existing working repository root, returns `{directory,cloned:false}` after read-only inspection. Later opens on that owner reuse preparation. |
|
|
76
78
|
| `status` | Prepares the checkout if needed, then returns the existing `repositoryStatus` result unchanged. |
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
79
|
+
| `configuration` | Observes the existing working root, symbolic HEAD, origin and configured upstream. It never clones, initializes or fetches. |
|
|
80
|
+
| `pull` | Prepares the checkout if needed, then runs clean-checkout, fast-forward-only `repositoryPull`, optionally using the operation's selected target. |
|
|
81
|
+
| `push` | Prepares the checkout if needed, then runs `repositoryPush`, optionally using the operation's selected target, preserving support for unrelated uncommitted working files. |
|
|
79
82
|
| `write` | Writes exact caller-selected text files, stages and commits only their literal paths, then performs one ordinary non-force push. Returns confirmed operation outcomes; see below. |
|
|
80
83
|
| `close`, `drain`, `dispose` | The same idempotent operation: stop accepting new calls and await accepted work and its process/event cleanup. They retain the repository on disk. |
|
|
81
84
|
|
|
@@ -87,6 +90,83 @@ A failed or cancelled clone reports the actual failure; any remaining directory
|
|
|
87
90
|
is retained for application-owned inspection. There is no automatic deletion or
|
|
88
91
|
destructive retry. Filesystem failures and complete Git diagnostics propagate.
|
|
89
92
|
|
|
93
|
+
## Existing checkout configuration and selected targets
|
|
94
|
+
|
|
95
|
+
`configuration({signal}={})` observes an existing checkout without invoking
|
|
96
|
+
`open`, creating directories, cloning, initializing, fetching or changing Git
|
|
97
|
+
configuration. A missing repository reports the actual Git failure. A bare
|
|
98
|
+
cache or nested checkout directory reports `ARCANE_REPOSITORY_DIRECTORY_INVALID`.
|
|
99
|
+
Its result is:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
{
|
|
103
|
+
repositoryRoot,
|
|
104
|
+
headRef: fullSymbolicRef | null,
|
|
105
|
+
origin: {urls: [...], pushUrls: [...]},
|
|
106
|
+
upstream: {remoteNames: [...], mergeRefs: [...], urls: [...], pushUrls: [...]} | null
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`repositoryRoot` is this owner's absolute selected working root. `headRef` is
|
|
111
|
+
the complete symbolic HEAD, including an unborn branch, or `null` for detached
|
|
112
|
+
HEAD. `upstream` is `null` when HEAD does not name a local branch. Otherwise its
|
|
113
|
+
arrays contain that branch's configured `remote` and `merge` values; `urls` and
|
|
114
|
+
`pushUrls` observe the effective last configured remote name. A `.` remote
|
|
115
|
+
means the local repository and has no remote URL arrays. Origin is observed
|
|
116
|
+
independently, even when it is not the upstream.
|
|
117
|
+
|
|
118
|
+
Arrays retain configured order, repeated values, complete UTF-8 strings and
|
|
119
|
+
empty strings. `[]` means unset; `['']` means an explicit empty value. The
|
|
120
|
+
reader honors configured includes and ordinary Git configuration precedence.
|
|
121
|
+
Unset push URLs do not imply that Git cannot push: Git retains its normal URL
|
|
122
|
+
fallback and rewrite behavior. These are configuration observations, not
|
|
123
|
+
resolved endpoints, authentication, account identity or ownership proof.
|
|
124
|
+
The SDK neither queries a credential helper nor changes configuration here.
|
|
125
|
+
|
|
126
|
+
Metadata uses the shared raw-Git-text reader. Lifecycle/stderr events remain
|
|
127
|
+
with the process owner, raw stdout remains parser-owned, and undecodable text
|
|
128
|
+
reports `ARCANE_GIT_CONFIGURATION_NOT_TEXT`. Failures retain complete raw
|
|
129
|
+
stdout, process diagnostics and causal errors using the identity reader's
|
|
130
|
+
documented attachment behavior. One observation uses four read-only Git
|
|
131
|
+
commands for an attached local branch, or three otherwise. Results are not a
|
|
132
|
+
transaction with later work or external Git activity. The app owns any decision
|
|
133
|
+
that the current checkout corresponds to its selected repository and branch.
|
|
134
|
+
|
|
135
|
+
The optional `target:{remote,ref}` on `pull`, `push` and `write` selects that
|
|
136
|
+
operation's Git destination. Both fields are nonempty strings representable by
|
|
137
|
+
the native process transport. The SDK captures their exact strings when the
|
|
138
|
+
call is accepted; later edits to the target object or UI selection cannot
|
|
139
|
+
redirect queued or active work. Git owns ref parsing, URL interpretation,
|
|
140
|
+
credentials, hooks and remote outcomes. This target is independent of the
|
|
141
|
+
factory's `remote`/`branch`, which remain initial-clone inputs only.
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
const observed = await repository.configuration({signal});
|
|
145
|
+
// The app decides whether observed.headRef and configured URLs match its choice.
|
|
146
|
+
const target = {remote: connection.locator, ref: connection.ref};
|
|
147
|
+
await repository.pull({target, signal});
|
|
148
|
+
const result = await repository.write({files: selectedFiles, message, target, signal});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
A targeted pull uses `git pull --ff-only -- <remote> <ref>:`. The trailing colon
|
|
152
|
+
is Git's source-only fetch framing; the fetched history is integrated into the
|
|
153
|
+
current branch. It does not switch branches or reset files/history. The existing
|
|
154
|
+
clean-checkout requirement remains. A targeted push uses
|
|
155
|
+
`git push --no-follow-tags -- <remote> HEAD:<ref>`: current HEAD is published to
|
|
156
|
+
the selected ref, without force or implicit configured tag following. Existing
|
|
157
|
+
history is still sent when Git needs it. Ordinary conflicting Git settings or
|
|
158
|
+
remote rejection remain actual failures; no settings are rewritten.
|
|
159
|
+
|
|
160
|
+
Omitting `target` preserves ordinary configured pull/push behavior and its
|
|
161
|
+
existing result shape. Targeted pull/push results add the captured `target` and
|
|
162
|
+
complete `stdout`/`stderr` alongside the existing `action`, `repositoryRoot`,
|
|
163
|
+
`branch` and compatibility `output` field. Writer results and failure outcomes
|
|
164
|
+
add that same captured `target`. There is no hidden pre-write pull, branch
|
|
165
|
+
selection, retry, reset, force, reversal or recommit. The app decides when to
|
|
166
|
+
observe, refresh, write and publish. See Git's [pull](https://git-scm.com/docs/git-pull),
|
|
167
|
+
[push](https://git-scm.com/docs/git-push) and [configuration](https://git-scm.com/docs/git-config)
|
|
168
|
+
contracts.
|
|
169
|
+
|
|
90
170
|
## Git identity configuration
|
|
91
171
|
|
|
92
172
|
```javascript
|
|
@@ -215,7 +295,7 @@ const result = await repository.write({
|
|
|
215
295
|
});
|
|
216
296
|
```
|
|
217
297
|
|
|
218
|
-
`write({files:[{path,content}],message,signal}={})` requires at least one explicit
|
|
298
|
+
`write({files:[{path,content}],message,target,signal}={})` requires at least one explicit
|
|
219
299
|
file, a nonempty commit message and string content (including an empty string).
|
|
220
300
|
Paths name working files relative to this repository, not its root, outside
|
|
221
301
|
paths or Git-owned `.git` metadata. Strings must be representable as UTF-8;
|
|
@@ -239,9 +319,10 @@ native host.
|
|
|
239
319
|
One `git --literal-pathspecs add -- <paths>` stages only those exact names.
|
|
240
320
|
One `git --literal-pathspecs commit --only --cleanup=verbatim --file - -- <paths>`
|
|
241
321
|
commits only those paths, leaving unrelated staged paths staged. The original
|
|
242
|
-
message is streamed unchanged through standard input.
|
|
243
|
-
then uses that repository's existing remote/ref configuration, the optional
|
|
322
|
+
message is streamed unchanged through standard input. Without `target`, one
|
|
323
|
+
ordinary `git push` then uses that repository's existing remote/ref configuration, the optional
|
|
244
324
|
process-local identity selection above, existing credentials and hooks.
|
|
325
|
+
With `target`, the final push uses the selected current-HEAD mapping above.
|
|
245
326
|
There is no implicit pull, branch switch, forced push,
|
|
246
327
|
hook bypass, automatic retry, rollback or reset. If Git reports no changes to
|
|
247
328
|
commit, that actual failure is returned; the SDK creates no empty commit.
|
|
@@ -252,7 +333,8 @@ Existing Git attributes, clean filters, EOL settings and hooks continue to apply
|
|
|
252
333
|
when Git stages/commits content. The filesystem write preserves the original
|
|
253
334
|
text; this API does not claim that repository-configured filters leave Git blob
|
|
254
335
|
text identical. It preserves those settings. A push may also send existing history or other
|
|
255
|
-
refs selected by the repository's ordinary push configuration
|
|
336
|
+
refs selected by the repository's ordinary push configuration when no explicit
|
|
337
|
+
target is supplied.
|
|
256
338
|
|
|
257
339
|
### Result and failure outcomes
|
|
258
340
|
|
|
@@ -275,6 +357,8 @@ Successful completion returns:
|
|
|
275
357
|
|
|
276
358
|
Each output record retains complete stdout/stderr. `code` and the process
|
|
277
359
|
termination `signal` are included when a completed process result is available.
|
|
360
|
+
When supplied, `target:{remote,ref}` is included in the result or failure outcome
|
|
361
|
+
with the original accepted strings.
|
|
278
362
|
An in-progress write also records its current `path` on a failure outcome.
|
|
279
363
|
`writtenPaths` records successful filesystem writes in input order; `written`
|
|
280
364
|
becomes true only after every requested write succeeds. The other booleans
|
|
@@ -66,11 +66,34 @@ service's startup before invoking its handler. State errors use the shared
|
|
|
66
66
|
complete diagnostic serialization; the startup promise retains its original
|
|
67
67
|
rejection value.
|
|
68
68
|
|
|
69
|
-
Each lifecycle hook receives `{application, service, emit}`. Each request handler
|
|
70
|
-
receives `(parameters, {application, service, emit, requestId, signal})`, with
|
|
69
|
+
Each lifecycle hook receives `{application, service, emit, getService}`. Each request handler
|
|
70
|
+
receives `(parameters, {application, service, emit, getService, requestId, signal})`, with
|
|
71
71
|
`this` bound to its service definition. A hook or handler may publish a complete
|
|
72
72
|
service-owned event through `emit(event, data)`.
|
|
73
73
|
|
|
74
|
+
### Native service composition
|
|
75
|
+
|
|
76
|
+
`await runtime.getService(name)` and `await context.getService(name)` return the
|
|
77
|
+
actual registered service definition after that service's shared startup
|
|
78
|
+
promise. A lookup can start its selected dependency before `runtime.start()`;
|
|
79
|
+
it waits for that dependency alone, with no renderer, transport request or
|
|
80
|
+
all-service readiness barrier. Concurrent lookups reuse the same startup and
|
|
81
|
+
return the same object. Applications keep their service dependencies acyclic.
|
|
82
|
+
|
|
83
|
+
Use the returned service's documented native members, such as
|
|
84
|
+
[`getONNXRuntime()`](local-ai.md#native-service-owners), for same-process
|
|
85
|
+
composition. RPC handlers remain owned by the dispatcher; calling entries in
|
|
86
|
+
`service.methods` directly does not supply request tracking or cancellation.
|
|
87
|
+
No service lookup is exposed over the browser protocol.
|
|
88
|
+
|
|
89
|
+
An unregistered name rejects with `CORE_SERVICE_UNAVAILABLE`. Startup failure
|
|
90
|
+
rejects with the original error. New lookups reject with `CORE_CLOSING` once
|
|
91
|
+
shutdown begins; an already accepted lookup still settles with its startup.
|
|
92
|
+
Lookup provides readiness, not a lifetime lease or ownership transfer. Retain
|
|
93
|
+
each acquired native owner according to its own documented cleanup contract,
|
|
94
|
+
and use that retained handle during disposal rather than requesting a new one.
|
|
95
|
+
Independent services still dispose concurrently.
|
|
96
|
+
|
|
74
97
|
## State and frames
|
|
75
98
|
|
|
76
99
|
`runtime.current()` returns dispatcher state, application, version, per-service
|
|
@@ -133,9 +156,13 @@ the handler runs. A service that does not finish or respond to cancellation is
|
|
|
133
156
|
still unfinished; the SDK does not report a forced timeout as successful cleanup.
|
|
134
157
|
|
|
135
158
|
Use `lifetime:'service'` for accepted work, such as a save, that must survive a
|
|
136
|
-
renderer cancellation or disconnect.
|
|
137
|
-
request cancellation controls or
|
|
138
|
-
owns its persistence, queueing and failure semantics.
|
|
159
|
+
renderer cancellation or disconnect. The dispatcher does not abort these
|
|
160
|
+
operations through request cancellation controls or its own shutdown. The
|
|
161
|
+
service still owns its persistence, queueing and failure semantics. A composing
|
|
162
|
+
host or native service can abort its own lifetime signal during shutdown;
|
|
163
|
+
in-flight native inference can therefore be cancelled even when the dispatcher
|
|
164
|
+
retains a service-lifetime response. Service lifetime does not promise survival
|
|
165
|
+
of native host shutdown.
|
|
139
166
|
|
|
140
167
|
`runtime.close()` is idempotent and retains the same completion promise. It stops
|
|
141
168
|
accepting new requests, cancels request-lifetime operations, waits for accepted
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"sdkVersion": "0.
|
|
3
|
+
"sdkVersion": "0.66.0",
|
|
4
4
|
"environment": {
|
|
5
5
|
"runtime": "Node.js for Node entrypoints; browser for browser-only entrypoints",
|
|
6
6
|
"minimumVersion": "22.23.2 for Node entrypoints",
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
"summary": "Owns one selected native working checkout with ArcaneData/Repos defaults and existing Git/process lifecycle.",
|
|
165
165
|
"availability": "Node with Git on Windows, Linux and macOS; Android requires host process adaptation",
|
|
166
166
|
"protocol": "Git working repository and SDK process adapter",
|
|
167
|
-
"normalization": "Returns directory, open, status, pull, push, write and identical close/drain/dispose hooks. Only missing or empty destinations clone; existing roots are
|
|
167
|
+
"normalization": "Returns directory, open, status, configuration, pull, push, write and identical close/drain/dispose hooks. Only missing or empty destinations clone; existing roots are preserved. configuration observes the existing root, symbolic HEAD, origin URL/pushURL arrays and branch remote/merge/upstream URL arrays without clone/init/fetch, preserving unset, empty and repeated values. Explicit paths remain selected. Same-directory operations serialize within the process; cancellation and shutdown join accepted process work. pull/push/write accept a captured target {remote,ref} for current-branch fast-forward pull or non-force current-HEAD selected-ref push; omission retains ordinary configured behavior. write snapshots exact text and paths, stages/commits only literal owned paths and preserves unrelated staged files and Git filters. Complete outputs and causal failures retain confirmed local/committed/pushed and uncertain outcomes plus the supplied target. Optional gitIdentity captures name/email/username for child Git operations only; omitted fields remain inherited and no config file is written."
|
|
168
168
|
},
|
|
169
169
|
{
|
|
170
170
|
"id": "core-repositories:readGitIdentity",
|
|
@@ -493,14 +493,14 @@
|
|
|
493
493
|
"name": "createBrowserDecisionModel",
|
|
494
494
|
"displayName": "createBrowserDecisionModel()",
|
|
495
495
|
"kind": "function",
|
|
496
|
-
"signature": "createBrowserDecisionModel({family,model,revision,device,runtime})",
|
|
496
|
+
"signature": "createBrowserDecisionModel({family,model,revision,device,dtype,runtime}={})",
|
|
497
497
|
"entrypoints": ["arcane-os/ai/browser-decisions"],
|
|
498
498
|
"primaryImport": "arcane-os/ai/browser-decisions",
|
|
499
499
|
"group": "Browser typed decisions",
|
|
500
|
-
"summary": "Explicit-load Laya
|
|
500
|
+
"summary": "Explicit-load Laya and Julia-1 decisions with caller-selected precision, complete inputs and graph results.",
|
|
501
501
|
"availability": "Browser module Workers and the selected Transformers.js backend; import/construction starts no model load",
|
|
502
502
|
"protocol": "Caller-owned state/question/options rows; five-input decision graph; native Worker request/result lifecycle",
|
|
503
|
-
"normalization": "Full field tokenization, raw logits and unrounded softmax; no policy thresholds, storage or precision fallback"
|
|
503
|
+
"normalization": "Full field tokenization, raw logits and unrounded softmax; dtype defaults to fp16 for Laya and fp32 for Julia, with explicit values forwarded unchanged to the upstream loader; no policy thresholds, storage or precision fallback"
|
|
504
504
|
},
|
|
505
505
|
{
|
|
506
506
|
"id": "root:acceptWebSocket",
|
|
@@ -2106,13 +2106,13 @@
|
|
|
2106
2106
|
"name": "repositoryPull",
|
|
2107
2107
|
"displayName": "repositoryPull()",
|
|
2108
2108
|
"kind": "function",
|
|
2109
|
-
"signature": "async repositoryPull({ workspaceRoot=process.cwd(), signal, onEvent, run=runProcess }={})",
|
|
2109
|
+
"signature": "async repositoryPull({ workspaceRoot=process.cwd(), target, signal, onEvent, run=runProcess }={})",
|
|
2110
2110
|
"entrypoints": [
|
|
2111
2111
|
"arcane-os"
|
|
2112
2112
|
],
|
|
2113
2113
|
"primaryImport": "arcane-os",
|
|
2114
2114
|
"group": "Workspace, doctor, repository, and server",
|
|
2115
|
-
"summary": "Runs one fast-forward-only pull
|
|
2115
|
+
"summary": "Runs one fast-forward-only pull into the selected clean worktree, optionally from a captured remote/ref target.",
|
|
2116
2116
|
"availability": "Node; network-assisted Git",
|
|
2117
2117
|
"protocol": "Node ESM",
|
|
2118
2118
|
"normalization": "SDK-normalized inputs, errors, events, and documented result"
|
|
@@ -2122,13 +2122,13 @@
|
|
|
2122
2122
|
"name": "repositoryPush",
|
|
2123
2123
|
"displayName": "repositoryPush()",
|
|
2124
2124
|
"kind": "function",
|
|
2125
|
-
"signature": "async repositoryPush({ workspaceRoot=process.cwd(), signal, onEvent, run=runProcess }={})",
|
|
2125
|
+
"signature": "async repositoryPush({ workspaceRoot=process.cwd(), target, signal, onEvent, run=runProcess }={})",
|
|
2126
2126
|
"entrypoints": [
|
|
2127
2127
|
"arcane-os"
|
|
2128
2128
|
],
|
|
2129
2129
|
"primaryImport": "arcane-os",
|
|
2130
2130
|
"group": "Workspace, doctor, repository, and server",
|
|
2131
|
-
"summary": "Pushes the
|
|
2131
|
+
"summary": "Pushes the attached branch through ordinary configured Git or an explicit captured current-HEAD destination without force.",
|
|
2132
2132
|
"availability": "Node; network-assisted Git",
|
|
2133
2133
|
"protocol": "Node ESM",
|
|
2134
2134
|
"normalization": "SDK-normalized inputs, errors, events, and documented result"
|
|
@@ -174,6 +174,34 @@ This factory accepts chat/ONNX requirements; the separate
|
|
|
174
174
|
owns image requirements. The development and generated native composition
|
|
175
175
|
split the shared application record accordingly.
|
|
176
176
|
|
|
177
|
+
### Native service owners
|
|
178
|
+
|
|
179
|
+
A native application service uses its Core lifecycle or request context to
|
|
180
|
+
obtain the existing selected owner:
|
|
181
|
+
|
|
182
|
+
```js
|
|
183
|
+
const localAI = await context.getService('local-ai');
|
|
184
|
+
const onnx = localAI.getONNXRuntime();
|
|
185
|
+
const modelAssets = await context.getService('model-assets');
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`getService()` awaits only that service's existing startup. The synchronous
|
|
189
|
+
`getONNXRuntime()` returns its actual `load/run/unload/current/subscribe/close`
|
|
190
|
+
owner; it neither prepares another runtime nor loads a model. An unselected
|
|
191
|
+
engine reports `LOCAL_AI_RUNTIME_NOT_SELECTED`; an unavailable or recovering
|
|
192
|
+
owner reports `LOCAL_AI_RUNTIME_UNAVAILABLE`, and an aborted service lifetime
|
|
193
|
+
retains its abort reason. Development and generated native compositions register
|
|
194
|
+
one shared model-assets service when ONNX or image generation is selected.
|
|
195
|
+
|
|
196
|
+
Reacquire `getONNXRuntime()` on each explicit model load because runtime recovery
|
|
197
|
+
replaces that owner. Retain the acquired handle for that session's cleanup and
|
|
198
|
+
await its `unload({id})` without an already-aborted request signal before releasing
|
|
199
|
+
the corresponding model-assets retain handle. The native ONNX owner joins actual
|
|
200
|
+
worker exit; a cancelled request's rejection alone does not establish that exit.
|
|
201
|
+
Core closes services concurrently, and the host can cancel in-flight native work
|
|
202
|
+
at shutdown. These native members require no renderer readiness and introduce no
|
|
203
|
+
second inference engine. See [native Core composition](core-runtime.md#native-service-composition).
|
|
204
|
+
|
|
177
205
|
`localai.status` returns `{runtimes}` and, when Ollama is selected, the existing
|
|
178
206
|
`ollama` and `models.ollama` catalog fields. Runtime records distinguish
|
|
179
207
|
`installed`, `available`, `state`, `models`, ownership and errors. A listening
|
|
@@ -198,6 +226,14 @@ background health polling.
|
|
|
198
226
|
| `llama.unload` | `{model}` | Current state after release |
|
|
199
227
|
| `llama.chat` | `{model,payload,stream?,streamId?}` | Complete OpenAI-shaped completion |
|
|
200
228
|
|
|
229
|
+
`llama.status` and `llama.models` observe the selected service without loading,
|
|
230
|
+
restarting or waiting for it. Starting, loading, stopped and failed services
|
|
231
|
+
return their retained state/catalog; an available service supplies a fresh
|
|
232
|
+
catalog observation. The llama.cpp runtime record includes `released: true`
|
|
233
|
+
only after Core successfully closes its owned single-model server. Explicit
|
|
234
|
+
load, inference or recovery can resume that engine; observation cannot.
|
|
235
|
+
Status observation adds no background polling.
|
|
236
|
+
|
|
201
237
|
The `payload` is the complete request. SDK option names are translated only at
|
|
202
238
|
the upstream protocol boundary; messages, tool definitions and documents remain
|
|
203
239
|
unchanged. An explicit `payload.model` selects that request's model. Core waits
|
|
@@ -213,7 +249,8 @@ observe load, sleep and unload changes. Direct servers expose readiness at
|
|
|
213
249
|
request boundaries; they do not offer the router's passive model event stream.
|
|
214
250
|
|
|
215
251
|
Unloading a model from an owned single-model server closes that owned process;
|
|
216
|
-
a subsequent load can start it again.
|
|
252
|
+
a subsequent load can start it again. Repeating that unload returns the released
|
|
253
|
+
state without restarting the process. Releasing an externally owned direct
|
|
217
254
|
server returns `released: true, unloaded: false`, retaining the real catalog
|
|
218
255
|
and leaving that server running.
|
|
219
256
|
|
|
@@ -289,6 +326,38 @@ does not install software or select a model. A missing Core connection reports
|
|
|
289
326
|
unavailability, leaving browser Wllama/ONNX routes available for the application
|
|
290
327
|
to select.
|
|
291
328
|
|
|
329
|
+
Omit `client` to follow the installed Core client through
|
|
330
|
+
[`subscribeCoreClient`](core-client.md): construction may precede installation.
|
|
331
|
+
Each installation reads `llama.status` without selecting, downloading or loading
|
|
332
|
+
a model. Retirement or replacement synchronously revokes this provider's
|
|
333
|
+
`status().loaded`, cancels its owned operations and detaches the old lifecycle
|
|
334
|
+
listener. Late results cannot restore the retired selection. Explicitly load
|
|
335
|
+
the selection against the replacement client before inference. Passing a
|
|
336
|
+
`client`, including `null`, keeps that caller-supplied connection fixed.
|
|
337
|
+
|
|
338
|
+
`status()` is this provider's current state. The `arcane-ai-provider/2` contract
|
|
339
|
+
does not provide a provider-state subscription, so this installation handling
|
|
340
|
+
alone does not update an idle AI runtime's retained role state. The provider
|
|
341
|
+
runtime still reconciles the provider at its existing operation boundaries.
|
|
342
|
+
`inspect()` reports whether an explicit load can proceed, separately from
|
|
343
|
+
`status().loaded`. A genuine `starting` or `loading` service without an error
|
|
344
|
+
permits that load preflight even before its catalog arrives; Core's `llama.load`
|
|
345
|
+
waits for startup and verifies the exact requested model. An owned, successfully
|
|
346
|
+
released service permits loading only a model retained in its actual catalog.
|
|
347
|
+
An available service still requires that catalog membership. These observations
|
|
348
|
+
do not fabricate model records or readiness, and unavailable external services,
|
|
349
|
+
closed services and actual errors remain unavailable.
|
|
350
|
+
|
|
351
|
+
`dispose()` removes installation and service subscriptions and cancels owned
|
|
352
|
+
operations synchronously, then attempts its actually retained model's release
|
|
353
|
+
through its captured client. A configured selection alone does not own a native
|
|
354
|
+
model: disposing before load or after successful unload sends no native release,
|
|
355
|
+
including when the caller explicitly supplied `client: null`. A failed release
|
|
356
|
+
rejects with the actual error even though the provider is disposed; disposal
|
|
357
|
+
does not establish successful native unload.
|
|
358
|
+
It never unloads a retired selection through a replacement client or closes the
|
|
359
|
+
shared Core client.
|
|
360
|
+
|
|
292
361
|
If a router evicts the primary model while serving a request-specific model,
|
|
293
362
|
reload the primary selection before its next request. The provider does not
|
|
294
363
|
silently change the application's saved model choice. Release registration
|
|
@@ -316,13 +385,45 @@ try {
|
|
|
316
385
|
```
|
|
317
386
|
|
|
318
387
|
The factory accepts `{modulePath,signal?,onEvent?}` and starts no worker until
|
|
319
|
-
`load({id,model,sessionOptions?,signal?})`. The model path is absolute for this
|
|
388
|
+
`load({id,model,sessionOptions?,executionPreference?,signal?})`. The model path is absolute for this
|
|
320
389
|
direct Node API. Session creation defaults to the CPU execution provider;
|
|
321
390
|
explicit native session options remain caller-owned. The returned session
|
|
322
391
|
record contains `id`, `model`, `state`, `loaded`, `error`, input/output names and
|
|
323
392
|
metadata. A live ID requires explicit unload before replacement. An ID may be
|
|
324
393
|
loaded again once its previous worker exits after a failed load or unload.
|
|
325
394
|
A run error retains the loaded session so a corrected request can use it.
|
|
395
|
+
`current().sessions[].stopping` becomes `true` when terminal shutdown begins,
|
|
396
|
+
including worker failure or explicit cancellation/unload. The session is then
|
|
397
|
+
unavailable for new runs even while `loaded` remains `true` until actual exit.
|
|
398
|
+
A recoverable run error keeps `stopping:false` and the loaded session usable.
|
|
399
|
+
`current().sessions[].exited` reports actual worker exit, independently of a
|
|
400
|
+
rejected load or inference. Unload joins worker exit and output delivery even
|
|
401
|
+
when requesting termination fails; complete cleanup errors remain observable.
|
|
402
|
+
|
|
403
|
+
Select `executionPreference: 'gpu'` to try the installed runtime's advertised
|
|
404
|
+
CUDA, TensorRT, DirectML, CoreML and WebGPU providers in that order, followed by
|
|
405
|
+
CPU when no accelerator session can be created. Discovery runs once per load;
|
|
406
|
+
each advertised candidate receives one actual session-creation attempt with CPU
|
|
407
|
+
available for graph nodes that the accelerator cannot handle. No provider is
|
|
408
|
+
downloaded by selection. The upstream `bundled` flag describes packaging and
|
|
409
|
+
does not exclude separately installed CUDA or TensorRT libraries. An explicit
|
|
410
|
+
`sessionOptions.executionProviders`, including an empty array, takes precedence
|
|
411
|
+
and is passed unchanged without automatic discovery or retries. Automatic
|
|
412
|
+
DirectML attempts default `enableMemPattern` to `false` and `executionMode` to
|
|
413
|
+
`'sequential'` as required by that provider; explicit caller values remain
|
|
414
|
+
unchanged, including on the final CPU attempt.
|
|
415
|
+
|
|
416
|
+
Automatic GPU selection adds an `execution` record to the loaded session and
|
|
417
|
+
its ordinary state events: `preference`, complete `supportedBackends`,
|
|
418
|
+
`selectedProviders`, ordered `attempts` with their full errors, `fallback`, and
|
|
419
|
+
`discoveryError`. Each attempt records `executionProviders`, `status`
|
|
420
|
+
(`configured` or `failed`), and `error`. `fallback: true` means the SDK created
|
|
421
|
+
the final CPU session after GPU preference, including when no GPU candidate was
|
|
422
|
+
advertised. Successful creation establishes an accepted provider configuration;
|
|
423
|
+
it does not establish that a GPU executed any graph nodes. If every attempt
|
|
424
|
+
fails, the load error retains the complete attempt errors and `execution`
|
|
425
|
+
record. Inference failures retain their existing behavior and do not replay
|
|
426
|
+
inference on another provider.
|
|
326
427
|
|
|
327
428
|
`run({id,feeds,fetches?,runOptions?,signal?})` returns the complete output-name
|
|
328
429
|
map of `{type,dims,data}` tensors. Input records use that same shape with native
|
|
@@ -383,6 +484,15 @@ Closing the accessor cancels its requests and subscriptions; model unloading
|
|
|
383
484
|
is explicit because other accessors may share the Core session. It never
|
|
384
485
|
closes the shared Core client.
|
|
385
486
|
|
|
487
|
+
Omitting `client` follows Core installation events with current-client replay,
|
|
488
|
+
including installation after construction. Each new connection reads
|
|
489
|
+
`onnx.status`; it does not install a runtime or load a model. Retirement or
|
|
490
|
+
replacement immediately clears retained session readiness and cancels this
|
|
491
|
+
accessor's operations. Late old-client state and results are ignored. Passing
|
|
492
|
+
an explicit `client`, including `null`, retains caller ownership and does not
|
|
493
|
+
follow global installation changes. `close()` also removes the installation
|
|
494
|
+
subscription.
|
|
495
|
+
|
|
386
496
|
Construction neither opens a connection nor installs a runtime. A browser needs
|
|
387
497
|
an already available native Core service or the explicit development bridge.
|
|
388
498
|
Unavailable native ONNX leaves browser ONNX/Wllama under the application's
|