arcane-os 0.83.0 → 0.83.1
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 +13 -0
- package/README.md +1 -1
- package/docs/reference/local-ai.md +24 -3
- package/docs/reference/native-decisions.md +13 -0
- package/package.json +1 -1
- package/src/local-ai/onnx-worker.mjs +39 -5
- package/src/local-ai/onnx.mjs +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.83.1
|
|
4
|
+
|
|
5
|
+
- Preserve complete failure-only native ONNX diagnostics in `error.onnxRun`,
|
|
6
|
+
including session and request identity, failure stage, graph metadata,
|
|
7
|
+
provider execution, run options and encoded feed/fetch tensors. Existing
|
|
8
|
+
rejected evaluations and retained decision error state carry the record.
|
|
9
|
+
- Retain the device inventory already consumed by automatic physical selection
|
|
10
|
+
without another hardware query. Successful inference performs no diagnostic
|
|
11
|
+
tensor encoding; original errors and diagnostic-construction failures remain
|
|
12
|
+
observable without changing model inputs, device selection or cancellation.
|
|
13
|
+
- These diagnostics expose evidence for a failed operation; they do not claim
|
|
14
|
+
to correct an application inference failure. No dependency changes.
|
|
15
|
+
|
|
3
16
|
## 0.83.0
|
|
4
17
|
|
|
5
18
|
- Add optional `shadowPath` to native app-control inspection and actions. Follow
|
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ selected SDK projection or an explicit live SDK source mount. Both profiles
|
|
|
25
25
|
share the theme, packaging, event, cancellation,
|
|
26
26
|
and browser run contracts while retaining their selected application layout.
|
|
27
27
|
|
|
28
|
-
This checkout defines the `0.83.
|
|
28
|
+
This checkout defines the `0.83.1` SDK contract. Development applications declare
|
|
29
29
|
`arcane-os` as `latest` and retain their lockfile. Exact SDK pins begin when Roshi
|
|
30
30
|
designates a production build. Follow [Consumer updates](docs/consumer-updates.md)
|
|
31
31
|
to refresh and compare the installed SDK and lockfile with the published channel;
|
|
@@ -420,9 +420,13 @@ unchanged, including on the final CPU attempt.
|
|
|
420
420
|
Every loaded session includes an `execution` record in its ordinary state
|
|
421
421
|
events: `preference`, `requestedTarget`, `resolvedDevice`, `resolution`,
|
|
422
422
|
`reason`, `configuredTarget`, `observedTarget`, complete `supportedBackends`,
|
|
423
|
-
`selectedProviders`, ordered `attempts` with their full errors, `fallback`,
|
|
424
|
-
`discoveryError
|
|
425
|
-
|
|
423
|
+
`selectedProviders`, ordered `attempts` with their full errors, `fallback`,
|
|
424
|
+
`discoveryError`, and `deviceInventory`. The inventory retains the complete
|
|
425
|
+
`{platform,state,devices,issues}` already obtained for that load's automatic
|
|
426
|
+
physical selection. It is `null` when that load did not gather an inventory;
|
|
427
|
+
retaining it performs no additional discovery. Each attempt records provider
|
|
428
|
+
names in `executionProviders`, its requested `configuredTarget`, `status`
|
|
429
|
+
(`configured` or `failed`), and
|
|
426
430
|
`error`. The accepted top-level `configuredTarget` is
|
|
427
431
|
`{source,executionProviders}`; it retains the complete provider options,
|
|
428
432
|
including native numeric `deviceId` values. Its `source` is `cpu-default`,
|
|
@@ -531,6 +535,23 @@ String input containing U+0000 reports an incompatibility at the native tensor
|
|
|
531
535
|
boundary: the Node binding uses null-terminated strings and cannot preserve
|
|
532
536
|
that input completely. The SDK does not alter the supplied string.
|
|
533
537
|
|
|
538
|
+
A failed run preserves the original error, stack, cause and additional fields,
|
|
539
|
+
and adds the developer diagnostic `error.onnxRun`. It contains `sessionId`,
|
|
540
|
+
`requestId`, `stage`, the original `model` path and `runtimeModulePath`, the
|
|
541
|
+
session's complete `execution` record, `runOptions`, and input/output names and
|
|
542
|
+
metadata. `stage` distinguishes `feed-conversion`, `fetch-conversion`,
|
|
543
|
+
`session.run`, `output-conversion`, and `result-delivery`. `feeds` and `fetches`
|
|
544
|
+
retain complete tensor types, dimensions and data through the existing Core tensor encoding;
|
|
545
|
+
omitted options remain omitted at the JSON boundary. `feedsSource` and
|
|
546
|
+
`fetchesSource` identify `request` records when conversion did not complete,
|
|
547
|
+
or `converted` values prepared for `session.run`. No partial converted map is
|
|
548
|
+
presented as the complete input. The actual input tensors are preserved without changes
|
|
549
|
+
to inference, and successful runs create no diagnostic tensor copy. If building
|
|
550
|
+
this diagnostic fails, its complete `diagnosticError` accompanies the fields
|
|
551
|
+
obtained before that failure; the original run error remains the failure.
|
|
552
|
+
Session metadata and feeds describe graph inputs, not internal node tensors
|
|
553
|
+
that the native runtime has not reported.
|
|
554
|
+
|
|
534
555
|
`current()` returns `{sessions,closed}`. `subscribe(listener)` replays current
|
|
535
556
|
state synchronously and returns an unsubscribe function. Load, readiness,
|
|
536
557
|
unload and failures remain observable. `unload({id,signal?})` releases that
|
|
@@ -336,6 +336,19 @@ progress includes model preparation, tokenization and evaluation; downloaded
|
|
|
336
336
|
members report files, not byte progress. Complete technical errors belong in
|
|
337
337
|
developer diagnostics, while the application owns its user-facing status.
|
|
338
338
|
|
|
339
|
+
An ONNX run failure reaches the rejected evaluation and retained `error` in
|
|
340
|
+
`current()`, `decisions.status`, and `decisions.state`, including the complete
|
|
341
|
+
[`error.onnxRun` diagnostic](local-ai.md#native-onnx-sessions). This identifies
|
|
342
|
+
the actual session, request, failure stage, model path, provider execution
|
|
343
|
+
record, graph metadata and complete encoded feed tensors with their dimensions.
|
|
344
|
+
The activation's `execution.execution.deviceInventory` retains the complete
|
|
345
|
+
inventory consumed by automatic physical selection during its load, or `null`
|
|
346
|
+
when that selection path did not gather one.
|
|
347
|
+
Neither observation starts another hardware query or changes model execution.
|
|
348
|
+
Retain these complete records in the selected developer inspection surface;
|
|
349
|
+
ordinary user status remains application-owned. A retained error identifies
|
|
350
|
+
that failed request and does not by itself establish that a later request failed.
|
|
351
|
+
|
|
339
352
|
Concurrent callers selecting the same family, model, revision, dtype, source,
|
|
340
353
|
mapping and target share one explicit activation.
|
|
341
354
|
Cancelling a load or evaluation cancels that activation and its outstanding operations, because the
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {parentPort,workerData} from 'node:worker_threads';
|
|
2
2
|
import {pathToFileURL} from 'node:url';
|
|
3
3
|
import Is from 'strong-type';
|
|
4
|
+
import {encodeTensorMap,encodeTensorFetches} from '../../browser-runtime/ai/onnx-tensors.mjs';
|
|
4
5
|
|
|
5
6
|
const is=new Is(false);
|
|
6
7
|
const imported=await import(pathToFileURL(workerData.modulePath).href);
|
|
7
8
|
const ort=imported.default??imported;
|
|
8
9
|
let session;
|
|
10
|
+
let sessionExecution;
|
|
9
11
|
|
|
10
12
|
function describeError(error){
|
|
11
13
|
if(!(error instanceof Error))return {name:'Error',message:String(error),cause:error};
|
|
@@ -27,6 +29,7 @@ async function createSession(request) {
|
|
|
27
29
|
resolution: 'automatic',
|
|
28
30
|
reason: selectProviders ? 'engine-default-required' : 'caller-session-options',
|
|
29
31
|
...request.targetResolution,
|
|
32
|
+
deviceInventory: request.deviceInventory ?? null,
|
|
30
33
|
configuredTarget: null,
|
|
31
34
|
observedTarget: null,
|
|
32
35
|
supportedBackends: [],
|
|
@@ -225,28 +228,35 @@ function tensorMap(records,inputs=false){
|
|
|
225
228
|
}
|
|
226
229
|
|
|
227
230
|
async function handleRequest(request){
|
|
231
|
+
let runStage;
|
|
232
|
+
let feeds;
|
|
233
|
+
let fetches;
|
|
228
234
|
try{
|
|
229
235
|
let result;
|
|
230
236
|
if(request.operation==='load'){
|
|
231
|
-
|
|
237
|
+
sessionExecution = await createSession(request);
|
|
232
238
|
result={
|
|
233
239
|
inputNames:session.inputNames,
|
|
234
240
|
outputNames:session.outputNames,
|
|
235
241
|
inputMetadata:session.inputMetadata,
|
|
236
242
|
outputMetadata:session.outputMetadata
|
|
237
243
|
};
|
|
238
|
-
if (
|
|
244
|
+
if (sessionExecution) result.execution = sessionExecution;
|
|
239
245
|
}else if(request.operation==='run'){
|
|
240
|
-
|
|
241
|
-
|
|
246
|
+
runStage='feed-conversion';
|
|
247
|
+
feeds=tensorMap(request.feeds,true);
|
|
248
|
+
runStage='fetch-conversion';
|
|
249
|
+
fetches=request.fetches===undefined||request.fetches===null||is.array(request.fetches)
|
|
242
250
|
?request.fetches:tensorMap(request.fetches);
|
|
243
251
|
// ORT treats an empty fetch map as its options overload and would
|
|
244
252
|
// ignore the third argument. Both forms select every output.
|
|
245
253
|
const allOutputs=fetches===undefined
|
|
246
254
|
||(fetches!==null&&!is.array(fetches)&&Object.keys(fetches).length===0);
|
|
255
|
+
runStage='session.run';
|
|
247
256
|
const outputs=allOutputs
|
|
248
257
|
?await session.run(feeds,request.runOptions)
|
|
249
258
|
:await session.run(feeds,fetches,request.runOptions);
|
|
259
|
+
runStage='output-conversion';
|
|
250
260
|
result=Object.fromEntries(Object.entries(outputs).map(function tensorRecord([name,tensor]){
|
|
251
261
|
return [name,{type:tensor.type,data:tensor.data,dims:tensor.dims}];
|
|
252
262
|
}));
|
|
@@ -258,9 +268,33 @@ async function handleRequest(request){
|
|
|
258
268
|
}
|
|
259
269
|
// Structured cloning retains typed tensors and BigInt without taking
|
|
260
270
|
// ownership of the caller's buffers or converting their contents.
|
|
271
|
+
if(request.operation==='run')runStage='result-delivery';
|
|
261
272
|
parentPort.postMessage({requestId:request.requestId,operation:request.operation,result});
|
|
262
273
|
}catch(error){
|
|
263
|
-
|
|
274
|
+
const record=describeError(error);
|
|
275
|
+
if(request.operation==='run'){
|
|
276
|
+
const diagnostic={
|
|
277
|
+
sessionId:workerData.sessionId,requestId:request.requestId,stage:runStage,
|
|
278
|
+
model:workerData.model,runtimeModulePath:workerData.modulePath,
|
|
279
|
+
execution:sessionExecution??null,runOptions:request.runOptions,
|
|
280
|
+
feedsSource:feeds===undefined?'request':'converted',
|
|
281
|
+
fetchesSource:runStage==='feed-conversion'||runStage==='fetch-conversion'?'request':'converted'
|
|
282
|
+
};
|
|
283
|
+
record.onnxRun=diagnostic;
|
|
284
|
+
try{
|
|
285
|
+
diagnostic.inputNames=session?.inputNames??null;
|
|
286
|
+
diagnostic.inputMetadata=session?.inputMetadata??null;
|
|
287
|
+
diagnostic.outputNames=session?.outputNames??null;
|
|
288
|
+
diagnostic.outputMetadata=session?.outputMetadata??null;
|
|
289
|
+
// Copy complete tensors only after failure. The same codec used
|
|
290
|
+
// by Core tensor transport preserves BigInt and typed values.
|
|
291
|
+
diagnostic.feeds=encodeTensorMap(feeds===undefined?request.feeds:feeds);
|
|
292
|
+
diagnostic.fetches=encodeTensorFetches(diagnostic.fetchesSource==='request'?request.fetches:fetches);
|
|
293
|
+
}catch(diagnosticError){
|
|
294
|
+
diagnostic.diagnosticError=describeError(diagnosticError);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
parentPort.postMessage({requestId:request.requestId,operation:request.operation,error:record});
|
|
264
298
|
}finally{
|
|
265
299
|
if(request.operation==='unload')parentPort.close();
|
|
266
300
|
}
|
package/src/local-ai/onnx.mjs
CHANGED
|
@@ -216,7 +216,7 @@ export function createONNXRuntime({modulePath,onEvent,signal,executionDevices:su
|
|
|
216
216
|
operationSignal.throwIfAborted();
|
|
217
217
|
if (entry.stopping || entry.exited || entry.active !== operation) return;
|
|
218
218
|
operation.payload = {...operation.payload, targetResolution, deviceInventory};
|
|
219
|
-
entry.state.execution = {...entry.state.execution, ...targetResolution};
|
|
219
|
+
entry.state.execution = {...entry.state.execution, ...targetResolution, deviceInventory: deviceInventory ?? null};
|
|
220
220
|
publish(entry);
|
|
221
221
|
postOperation(entry, operation);
|
|
222
222
|
}
|
|
@@ -348,7 +348,7 @@ export function createONNXRuntime({modulePath,onEvent,signal,executionDevices:su
|
|
|
348
348
|
state:{id,model,state:'loading',loaded:false,error:null,inputNames:[],outputNames:[],inputMetadata:[],outputMetadata:[],
|
|
349
349
|
execution: {requestedTarget: executionTarget ?? null, resolvedDevice: null,
|
|
350
350
|
resolution: executionTarget === undefined || executionTarget === null ? 'automatic' : null,
|
|
351
|
-
reason: 'session-loading', configuredTarget: null, observedTarget: null}},
|
|
351
|
+
reason: 'session-loading', configuredTarget: null, observedTarget: null, deviceInventory: null}},
|
|
352
352
|
controller: new AbortController(), preparation: null,
|
|
353
353
|
worker:null,active:null,queue:[],stopping:false,exited:false,stopTask:null,terminalError:null,releaseError:null,terminationRequested:false,outputTasks:[]
|
|
354
354
|
};
|
|
@@ -356,7 +356,7 @@ export function createONNXRuntime({modulePath,onEvent,signal,executionDevices:su
|
|
|
356
356
|
sessions.set(id,entry);
|
|
357
357
|
try{
|
|
358
358
|
entry.worker=new Worker(new URL('./onnx-worker.mjs',import.meta.url),{
|
|
359
|
-
workerData:{modulePath},stdout:true,stderr:true
|
|
359
|
+
workerData:{modulePath,sessionId:id,model},stdout:true,stderr:true
|
|
360
360
|
});
|
|
361
361
|
entry.outputTasks.push(
|
|
362
362
|
captureOutput(entry,entry.worker.stdout,'local-ai.onnx.stdout'),
|