@independo/inderun-web 0.2.0-dev.1 → 0.2.0-dev.2
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/README.md +117 -1
- package/dist/onnx-provider.d.ts +78 -0
- package/dist/onnx-provider.d.ts.map +1 -0
- package/dist/onnx-provider.js +217 -0
- package/dist/onnx-runtime.d.ts +110 -0
- package/dist/onnx-runtime.d.ts.map +1 -0
- package/dist/onnx-runtime.js +76 -0
- package/dist/onnx-transformers-runtime.d.ts +72 -0
- package/dist/onnx-transformers-runtime.d.ts.map +1 -0
- package/dist/onnx-transformers-runtime.js +210 -0
- package/dist/onnx.d.ts +13 -0
- package/dist/onnx.d.ts.map +1 -0
- package/dist/onnx.js +12 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +15 -11
- package/dist/web-sdk.d.ts +12 -3
- package/dist/web-sdk.d.ts.map +1 -1
- package/dist/web-sdk.js +20 -8
- package/package.json +15 -3
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
TypeScript/Web SDK for IndeRun.
|
|
10
10
|
|
|
11
|
-
This package provides the Web SDK entrypoint, the engine core, routing, telemetry, error normalization,
|
|
11
|
+
This package provides the Web SDK entrypoint, the engine core, routing, telemetry, error normalization, the OpenAI-compatible cloud provider, and the Web ONNX Runtime provider for developer-supplied local models.
|
|
12
12
|
|
|
13
13
|
## Basic Usage
|
|
14
14
|
|
|
@@ -48,6 +48,122 @@ taxonomy (`AuthError`, `RateLimited`, `Timeout`, `Unavailable`, `Internal`). The
|
|
|
48
48
|
exact status-to-class mapping is documented on the provider in code — see
|
|
49
49
|
`OpenAIResponsesProvider` — so it stays in sync with behavior.
|
|
50
50
|
|
|
51
|
+
## On-Device Models: ONNX Runtime (Web)
|
|
52
|
+
|
|
53
|
+
`local.onnx.genai.web` runs developer-supplied ONNX models in the browser. Registering it is what
|
|
54
|
+
makes `constraints.privacy = "local_required"` routable. Pass `onnx` to the factory (`openAI` and
|
|
55
|
+
`onnx` are both optional, but at least one is required):
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { createIndeRunWeb } from "@independo/inderun-web";
|
|
59
|
+
|
|
60
|
+
const inderun = createIndeRunWeb({
|
|
61
|
+
onnx: {
|
|
62
|
+
modelPackage: {
|
|
63
|
+
id: "phi-3-mini-web",
|
|
64
|
+
format: "onnx",
|
|
65
|
+
tasks: ["text_to_text"],
|
|
66
|
+
runtime: { platforms: ["web"] },
|
|
67
|
+
source: { sourceType: "registry", ref: "onnx-community/Phi-3-mini-4k-instruct" }
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`modelPackage` is the provider-neutral `ModelPackage` contract from
|
|
74
|
+
`@independo/inderun-contracts`; only `id` and `format` are required, and the package is validated
|
|
75
|
+
(including the inline-secret and URL-userinfo rules) before every attempt. Model files must never
|
|
76
|
+
carry credentials — use `authContextRef` and secure storage instead.
|
|
77
|
+
|
|
78
|
+
Options: `id` (defaults to `local.onnx.genai.web`), `modelPackage` (required), `runtime`, and
|
|
79
|
+
`timeoutMs` (a request's `constraints.timeoutMs` wins).
|
|
80
|
+
|
|
81
|
+
The default runtime loads **quantized** weights (`q4f16` on WebGPU, `q4` otherwise). Transformers.js
|
|
82
|
+
would otherwise pick `fp32`, which makes ONNX Runtime fail session creation with an allocation error
|
|
83
|
+
(`std::bad_alloc`) for anything but tiny models. Override with `dtype` when your model does not
|
|
84
|
+
publish that variant:
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { OnnxRuntimeWebProvider, createTransformersJsRuntime } from "@independo/inderun-web/onnx";
|
|
88
|
+
|
|
89
|
+
const provider = new OnnxRuntimeWebProvider({
|
|
90
|
+
modelPackage,
|
|
91
|
+
runtime: createTransformersJsRuntime({ dtype: "q8", device: "wasm" })
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The default runtime targets models that load through the Transformers.js `text-generation` pipeline
|
|
96
|
+
— for example `onnx-community/gemma-3-1b-it-ONNX`. Multimodal exports split across separate
|
|
97
|
+
encoder/decoder graphs need `AutoProcessor` plus a model-specific class and should implement the
|
|
98
|
+
runtime seam instead — see [Custom runtimes](#custom-runtimes).
|
|
99
|
+
|
|
100
|
+
### Runtime dependency
|
|
101
|
+
|
|
102
|
+
The default runtime uses [Transformers.js](https://www.npmjs.com/package/@huggingface/transformers),
|
|
103
|
+
which runs ONNX models on `onnxruntime-web` and owns the generation loop (ONNX Runtime GenAI has no
|
|
104
|
+
browser build). It is an optional dependency that IndeRun does not bundle — install it yourself:
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
pnpm add @huggingface/transformers
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
If the package is present but fails to initialize, the provider reports itself unavailable and
|
|
111
|
+
routing produces an explainable `capability_unavailable` rejection instead of throwing. Bundlers do
|
|
112
|
+
need to resolve the specifier, so an app that imports `@independo/inderun-web/onnx` without
|
|
113
|
+
installing Transformers.js should pass its own runtime (or a `load` override) — see
|
|
114
|
+
[Custom runtimes](#custom-runtimes). WASM threads additionally require
|
|
115
|
+
cross-origin isolation (`Cross-Origin-Opener-Policy: same-origin`,
|
|
116
|
+
`Cross-Origin-Embedder-Policy: require-corp`) on whatever serves your app.
|
|
117
|
+
|
|
118
|
+
### Supported model sources
|
|
119
|
+
|
|
120
|
+
| `source.sourceType` | Web |
|
|
121
|
+
| ------------------- | ----------- |
|
|
122
|
+
| `registry` | Supported (hub model id in `source.ref`) |
|
|
123
|
+
| `bundled` | Supported (assets served by your app) |
|
|
124
|
+
| `app_managed` | Supported (assets served by your app) |
|
|
125
|
+
| `programmatic` | Supported (requires `createGenerator`) |
|
|
126
|
+
| `remote` | Deferred — download yourself, then declare the files |
|
|
127
|
+
| `filesystem` | Unsupported — browsers cannot read arbitrary local paths |
|
|
128
|
+
|
|
129
|
+
### Errors
|
|
130
|
+
|
|
131
|
+
| Condition | `errorClass` |
|
|
132
|
+
| ----------------------------------------------------------- | -------------------- |
|
|
133
|
+
| Capability gate fails pre-attempt, model missing/incompatible | `CapabilityMismatch` |
|
|
134
|
+
| Runtime initialization failure, resource exhaustion | `Unavailable` |
|
|
135
|
+
| Generation exceeded its timeout budget | `Timeout` |
|
|
136
|
+
| Malformed/empty model output, unexpected runtime failure | `Internal` |
|
|
137
|
+
|
|
138
|
+
A purely local runtime never produces `AuthError`, `RateLimited`, or `Offline`.
|
|
139
|
+
|
|
140
|
+
### Custom runtimes
|
|
141
|
+
|
|
142
|
+
Swap the execution backend without touching provider semantics by implementing
|
|
143
|
+
`OnnxTextGenerationRuntime`:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import {
|
|
147
|
+
OnnxRuntimeWebProvider,
|
|
148
|
+
OnnxRuntimeError,
|
|
149
|
+
createFixtureOnnxRuntime,
|
|
150
|
+
type OnnxTextGenerationRuntime
|
|
151
|
+
} from "@independo/inderun-web/onnx";
|
|
152
|
+
|
|
153
|
+
const runtime: OnnxTextGenerationRuntime = {
|
|
154
|
+
async prepare(modelPackage) {
|
|
155
|
+
return { available: true };
|
|
156
|
+
},
|
|
157
|
+
async generate({ messages, generation }, signal) {
|
|
158
|
+
// Throw OnnxRuntimeError("capability" | "unavailable" | "timeout" | "internal", …)
|
|
159
|
+
// to steer IndeRun error normalization.
|
|
160
|
+
return { text: "…" };
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`createFixtureOnnxRuntime()` provides a deterministic in-memory runtime for tests and offline demos.
|
|
166
|
+
|
|
51
167
|
## Commands
|
|
52
168
|
|
|
53
169
|
```sh
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type ModelPackage, type ModelSourceType, type TaskRequest, type TaskResult } from "@independo/inderun-contracts";
|
|
2
|
+
import type { HostServices } from "./host.js";
|
|
3
|
+
import { type OnnxTextGenerationRuntime } from "./onnx-runtime.js";
|
|
4
|
+
import type { ProviderAdapter, ProviderDescriptor, ProviderDynamicCapabilities, RunContext } from "./provider.js";
|
|
5
|
+
/** Default provider id of the Web member of the ONNX Runtime provider family. */
|
|
6
|
+
export declare const DEFAULT_ONNX_WEB_PROVIDER_ID = "local.onnx.genai.web";
|
|
7
|
+
/**
|
|
8
|
+
* Model source types the Web member of the ONNX Runtime provider family can honor.
|
|
9
|
+
*
|
|
10
|
+
* `filesystem` is unsupported because browsers do not expose arbitrary local paths, and `remote`
|
|
11
|
+
* is deferred: hosts download model files themselves and then supply them as `bundled`,
|
|
12
|
+
* `app_managed`, or `programmatic`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const SUPPORTED_WEB_MODEL_SOURCE_TYPES: readonly ModelSourceType[];
|
|
15
|
+
/**
|
|
16
|
+
* Configuration for the Web ONNX Runtime provider.
|
|
17
|
+
*/
|
|
18
|
+
export interface OnnxProviderOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Provider id exposed in telemetry and routing explanations.
|
|
21
|
+
*/
|
|
22
|
+
id?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Provider-neutral bootstrap metadata describing the developer-supplied model.
|
|
25
|
+
*/
|
|
26
|
+
modelPackage: ModelPackage;
|
|
27
|
+
/**
|
|
28
|
+
* Runtime implementation used to execute generation. Defaults to the Transformers.js-backed
|
|
29
|
+
* runtime; applications can inject their own implementation of the seam.
|
|
30
|
+
*/
|
|
31
|
+
runtime?: OnnxTextGenerationRuntime;
|
|
32
|
+
/**
|
|
33
|
+
* Optional generation timeout in milliseconds. A request-level `constraints.timeoutMs` wins.
|
|
34
|
+
*/
|
|
35
|
+
timeoutMs?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Local provider adapter that executes Mode-1 text-to-text requests with a developer-supplied ONNX
|
|
39
|
+
* model in the browser.
|
|
40
|
+
*
|
|
41
|
+
* The adapter owns the IndeRun-facing contract (descriptor, capability checks, error taxonomy) and
|
|
42
|
+
* delegates execution to an injectable {@link OnnxTextGenerationRuntime}. ONNX Runtime execution
|
|
43
|
+
* backends (WASM, WebGPU, WebNN) stay behind that seam and are never public routing concepts.
|
|
44
|
+
*/
|
|
45
|
+
export declare class OnnxRuntimeWebProvider implements ProviderAdapter {
|
|
46
|
+
private readonly options;
|
|
47
|
+
private readonly id;
|
|
48
|
+
private readonly modelPackage;
|
|
49
|
+
private readonly runtime;
|
|
50
|
+
/**
|
|
51
|
+
* Creates a Web ONNX Runtime provider.
|
|
52
|
+
* @param options - Model package plus optional id, runtime, and timeout overrides.
|
|
53
|
+
*/
|
|
54
|
+
constructor(options: OnnxProviderOptions);
|
|
55
|
+
/**
|
|
56
|
+
* Returns static metadata used by the router for deterministic provider selection.
|
|
57
|
+
*/
|
|
58
|
+
describe(): ProviderDescriptor;
|
|
59
|
+
/**
|
|
60
|
+
* Reports dynamic provider availability for the current host.
|
|
61
|
+
*
|
|
62
|
+
* Every failure below is provider-internal detail: the shared route planner flattens it into a
|
|
63
|
+
* single `capability_unavailable` rejection carrying the returned reason.
|
|
64
|
+
*
|
|
65
|
+
* @param _host - Host services available to the engine (unused; ONNX runs in-process).
|
|
66
|
+
*/
|
|
67
|
+
capabilities(_host: HostServices): Promise<ProviderDynamicCapabilities>;
|
|
68
|
+
/**
|
|
69
|
+
* Executes a normalized text-to-text task on the developer-supplied local ONNX model.
|
|
70
|
+
* @param request - Canonical IndeRun task request.
|
|
71
|
+
* @param context - Engine execution context containing run id and host services.
|
|
72
|
+
* @returns Normalized IndeRun task result.
|
|
73
|
+
* @throws IndeRunException mapped to the standard error taxonomy.
|
|
74
|
+
*/
|
|
75
|
+
run(request: TaskRequest, context: RunContext): Promise<TaskResult>;
|
|
76
|
+
private mapRuntimeError;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=onnx-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onnx-provider.d.ts","sourceRoot":"","sources":["../src/onnx-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,8BAA8B,CAAC;AAStC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAIL,KAAK,yBAAyB,EAC/B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,2BAA2B,EAC3B,UAAU,EACX,MAAM,eAAe,CAAC;AAEvB,iFAAiF;AACjF,eAAO,MAAM,4BAA4B,yBAAyB,CAAC;AAKnE;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,EAAE,SAAS,eAAe,EAKtE,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,YAAY,EAAE,YAAY,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,yBAAyB,CAAC;IACpC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,qBAAa,sBAAuB,YAAW,eAAe;IAShD,OAAO,CAAC,QAAQ,CAAC,OAAO;IARpC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IAEpD;;;OAGG;gBAC0B,OAAO,EAAE,mBAAmB;IAMzD;;OAEG;IACH,QAAQ,IAAI,kBAAkB;IAsB9B;;;;;;;OAOG;IACG,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAoC7E;;;;;;OAMG;IACG,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAoEzE,OAAO,CAAC,eAAe;CA2BxB"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { getModelPackageValidationIssues } from "@independo/inderun-contracts";
|
|
2
|
+
import { createCapabilityMismatch, createInternal, createTimeout, createUnavailable, toIndeRunException } from "./errors.js";
|
|
3
|
+
import { OnnxRuntimeError } from "./onnx-runtime.js";
|
|
4
|
+
import { createTransformersJsRuntime } from "./onnx-transformers-runtime.js";
|
|
5
|
+
/** Default provider id of the Web member of the ONNX Runtime provider family. */
|
|
6
|
+
export const DEFAULT_ONNX_WEB_PROVIDER_ID = "local.onnx.genai.web";
|
|
7
|
+
/** Task kind this provider implements in Milestone 2 (Mode 1 only). */
|
|
8
|
+
const TEXT_TO_TEXT = "text_to_text";
|
|
9
|
+
/**
|
|
10
|
+
* Model source types the Web member of the ONNX Runtime provider family can honor.
|
|
11
|
+
*
|
|
12
|
+
* `filesystem` is unsupported because browsers do not expose arbitrary local paths, and `remote`
|
|
13
|
+
* is deferred: hosts download model files themselves and then supply them as `bundled`,
|
|
14
|
+
* `app_managed`, or `programmatic`.
|
|
15
|
+
*/
|
|
16
|
+
export const SUPPORTED_WEB_MODEL_SOURCE_TYPES = [
|
|
17
|
+
"registry",
|
|
18
|
+
"bundled",
|
|
19
|
+
"programmatic",
|
|
20
|
+
"app_managed"
|
|
21
|
+
];
|
|
22
|
+
/**
|
|
23
|
+
* Local provider adapter that executes Mode-1 text-to-text requests with a developer-supplied ONNX
|
|
24
|
+
* model in the browser.
|
|
25
|
+
*
|
|
26
|
+
* The adapter owns the IndeRun-facing contract (descriptor, capability checks, error taxonomy) and
|
|
27
|
+
* delegates execution to an injectable {@link OnnxTextGenerationRuntime}. ONNX Runtime execution
|
|
28
|
+
* backends (WASM, WebGPU, WebNN) stay behind that seam and are never public routing concepts.
|
|
29
|
+
*/
|
|
30
|
+
export class OnnxRuntimeWebProvider {
|
|
31
|
+
options;
|
|
32
|
+
id;
|
|
33
|
+
modelPackage;
|
|
34
|
+
runtime;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a Web ONNX Runtime provider.
|
|
37
|
+
* @param options - Model package plus optional id, runtime, and timeout overrides.
|
|
38
|
+
*/
|
|
39
|
+
constructor(options) {
|
|
40
|
+
this.options = options;
|
|
41
|
+
this.id = options.id ?? DEFAULT_ONNX_WEB_PROVIDER_ID;
|
|
42
|
+
this.modelPackage = options.modelPackage;
|
|
43
|
+
this.runtime = options.runtime ?? createTransformersJsRuntime();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Returns static metadata used by the router for deterministic provider selection.
|
|
47
|
+
*/
|
|
48
|
+
describe() {
|
|
49
|
+
return {
|
|
50
|
+
id: this.id,
|
|
51
|
+
type: "local",
|
|
52
|
+
transport: "in_process",
|
|
53
|
+
supports: {
|
|
54
|
+
run: true,
|
|
55
|
+
streaming: false,
|
|
56
|
+
realtime: false,
|
|
57
|
+
tools: false,
|
|
58
|
+
reasoningEvents: false,
|
|
59
|
+
structuredOutput: false,
|
|
60
|
+
multimodal: false
|
|
61
|
+
},
|
|
62
|
+
cancel: "soft",
|
|
63
|
+
tasks: getDeclaredTasks(this.modelPackage),
|
|
64
|
+
privacy: {
|
|
65
|
+
dataLeavesDevice: false
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Reports dynamic provider availability for the current host.
|
|
71
|
+
*
|
|
72
|
+
* Every failure below is provider-internal detail: the shared route planner flattens it into a
|
|
73
|
+
* single `capability_unavailable` rejection carrying the returned reason.
|
|
74
|
+
*
|
|
75
|
+
* @param _host - Host services available to the engine (unused; ONNX runs in-process).
|
|
76
|
+
*/
|
|
77
|
+
async capabilities(_host) {
|
|
78
|
+
const issues = getModelPackageValidationIssues(this.modelPackage);
|
|
79
|
+
if (issues.length > 0) {
|
|
80
|
+
const summary = issues.map((issue) => `${issue.path} ${issue.message}`).join("; ");
|
|
81
|
+
return { available: false, reason: `model package malformed: ${summary}` };
|
|
82
|
+
}
|
|
83
|
+
const sourceType = this.modelPackage.source?.sourceType;
|
|
84
|
+
if (sourceType !== undefined && !SUPPORTED_WEB_MODEL_SOURCE_TYPES.includes(sourceType)) {
|
|
85
|
+
return {
|
|
86
|
+
available: false,
|
|
87
|
+
reason: sourceType === "filesystem"
|
|
88
|
+
? "model source unavailable: 'filesystem' model sources are unsupported on Web because browsers cannot read arbitrary local paths."
|
|
89
|
+
: `model source unavailable: '${sourceType}' model sources are deferred on Web; supply model files as ${SUPPORTED_WEB_MODEL_SOURCE_TYPES.join(", ")}.`
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const platforms = this.modelPackage.runtime?.platforms;
|
|
93
|
+
if (Array.isArray(platforms) && platforms.length > 0 && !platforms.includes("web")) {
|
|
94
|
+
return {
|
|
95
|
+
available: false,
|
|
96
|
+
reason: `platform unsupported: the model package targets ${platforms.join(", ")} and does not list 'web'.`
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (!getDeclaredTasks(this.modelPackage).includes(TEXT_TO_TEXT)) {
|
|
100
|
+
return {
|
|
101
|
+
available: false,
|
|
102
|
+
reason: `unsupported task: the model package declares ${getDeclaredTasks(this.modelPackage).join(", ")} and does not support '${TEXT_TO_TEXT}'.`
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return this.runtime.prepare(this.modelPackage);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Executes a normalized text-to-text task on the developer-supplied local ONNX model.
|
|
109
|
+
* @param request - Canonical IndeRun task request.
|
|
110
|
+
* @param context - Engine execution context containing run id and host services.
|
|
111
|
+
* @returns Normalized IndeRun task result.
|
|
112
|
+
* @throws IndeRunException mapped to the standard error taxonomy.
|
|
113
|
+
*/
|
|
114
|
+
async run(request, context) {
|
|
115
|
+
const availability = await this.capabilities(context.hostServices);
|
|
116
|
+
if (!availability.available) {
|
|
117
|
+
throw createCapabilityMismatch(availability.reason ?? "ONNX Runtime Web provider is unavailable on this host.", { providerId: this.id, runId: context.runId });
|
|
118
|
+
}
|
|
119
|
+
const messages = createMessages(request);
|
|
120
|
+
if (messages.length === 0) {
|
|
121
|
+
throw createInternal("ONNX Runtime Web provider requires a prompt or messages.", {
|
|
122
|
+
providerId: this.id,
|
|
123
|
+
runId: context.runId
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const timeoutMs = request.constraints?.timeoutMs ?? this.options.timeoutMs;
|
|
127
|
+
const controller = new AbortController();
|
|
128
|
+
const timer = timeoutMs !== undefined && timeoutMs > 0
|
|
129
|
+
? setTimeout(() => controller.abort(), timeoutMs)
|
|
130
|
+
: undefined;
|
|
131
|
+
let output;
|
|
132
|
+
try {
|
|
133
|
+
output = await this.runtime.generate({
|
|
134
|
+
modelPackage: this.modelPackage,
|
|
135
|
+
messages,
|
|
136
|
+
...(request.generation !== undefined ? { generation: request.generation } : {})
|
|
137
|
+
}, controller.signal);
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
throw this.mapRuntimeError(err, context);
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
if (timer !== undefined)
|
|
144
|
+
clearTimeout(timer);
|
|
145
|
+
}
|
|
146
|
+
if (typeof output.text !== "string" || output.text.length === 0) {
|
|
147
|
+
throw createInternal("ONNX Runtime Web provider returned no text output.", {
|
|
148
|
+
providerId: this.id,
|
|
149
|
+
runId: context.runId
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const result = {
|
|
153
|
+
schemaVersion: "1.0",
|
|
154
|
+
runId: context.runId,
|
|
155
|
+
output: {
|
|
156
|
+
type: "text",
|
|
157
|
+
text: output.text
|
|
158
|
+
},
|
|
159
|
+
finishReason: output.finishReason ?? "stop",
|
|
160
|
+
telemetry: {
|
|
161
|
+
providerUsed: this.id,
|
|
162
|
+
totalMs: 0
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
if (output.usage) {
|
|
166
|
+
result.usage = output.usage;
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
mapRuntimeError(error, context) {
|
|
171
|
+
const extra = { providerId: this.id, runId: context.runId };
|
|
172
|
+
if (error instanceof OnnxRuntimeError) {
|
|
173
|
+
const details = error.originalError !== undefined
|
|
174
|
+
? { details: { originalError: getErrorSummary(error.originalError) } }
|
|
175
|
+
: {};
|
|
176
|
+
switch (error.kind) {
|
|
177
|
+
case "capability":
|
|
178
|
+
return createCapabilityMismatch(error.message, { ...extra, ...details });
|
|
179
|
+
case "unavailable":
|
|
180
|
+
return createUnavailable(error.message, { ...extra, ...details });
|
|
181
|
+
case "timeout":
|
|
182
|
+
return createTimeout(error.message, { ...extra, ...details });
|
|
183
|
+
default:
|
|
184
|
+
return createInternal(error.message, { ...extra, ...details });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (isAbortError(error)) {
|
|
188
|
+
return createTimeout("ONNX Runtime Web generation timed out.", extra);
|
|
189
|
+
}
|
|
190
|
+
return toIndeRunException(error, extra);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function getDeclaredTasks(modelPackage) {
|
|
194
|
+
const tasks = modelPackage.tasks;
|
|
195
|
+
return Array.isArray(tasks) && tasks.length > 0 ? tasks : [TEXT_TO_TEXT];
|
|
196
|
+
}
|
|
197
|
+
function createMessages(request) {
|
|
198
|
+
if (request.messages && request.messages.length > 0) {
|
|
199
|
+
return request.messages.map((message) => ({
|
|
200
|
+
role: message.role,
|
|
201
|
+
content: message.content
|
|
202
|
+
}));
|
|
203
|
+
}
|
|
204
|
+
const prompt = request.prompt;
|
|
205
|
+
return prompt !== undefined && prompt.length > 0 ? [{ role: "user", content: prompt }] : [];
|
|
206
|
+
}
|
|
207
|
+
function isAbortError(error) {
|
|
208
|
+
return (typeof error === "object" &&
|
|
209
|
+
error !== null &&
|
|
210
|
+
error.name === "AbortError");
|
|
211
|
+
}
|
|
212
|
+
function getErrorSummary(error) {
|
|
213
|
+
if (error instanceof Error) {
|
|
214
|
+
return { name: error.name, message: error.message, stack: error.stack };
|
|
215
|
+
}
|
|
216
|
+
return { message: String(error) };
|
|
217
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { ModelPackage, TaskRequest, TaskResult } from "@independo/inderun-contracts";
|
|
2
|
+
/**
|
|
3
|
+
* Availability snapshot reported by an ONNX text generation runtime.
|
|
4
|
+
*
|
|
5
|
+
* The `reason` string uses the provider-internal capability vocabulary documented in
|
|
6
|
+
* `docs/architecture/onnx-runtime-provider-family.md`. It is not a public enum: the provider
|
|
7
|
+
* flattens every failure into a single `capability_unavailable` route rejection and carries the
|
|
8
|
+
* reason as human-readable text.
|
|
9
|
+
*/
|
|
10
|
+
export interface OnnxRuntimeAvailability {
|
|
11
|
+
/** Whether the runtime can execute the given model package on this host right now. */
|
|
12
|
+
available: boolean;
|
|
13
|
+
/** Human-readable detail describing why the runtime is unavailable. */
|
|
14
|
+
reason?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Normalized conversation turn handed to an ONNX text generation runtime.
|
|
18
|
+
*/
|
|
19
|
+
export interface OnnxGenerationMessage {
|
|
20
|
+
/** The role of the author of this turn. */
|
|
21
|
+
role: "system" | "user" | "assistant";
|
|
22
|
+
/** Plain-text content of this turn. */
|
|
23
|
+
content: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Normalized generation request handed to an ONNX text generation runtime.
|
|
27
|
+
*/
|
|
28
|
+
export interface OnnxGenerationInput {
|
|
29
|
+
/** The model package the provider was configured with. */
|
|
30
|
+
modelPackage: ModelPackage;
|
|
31
|
+
/** Conversation turns, normalized from `prompt` or `messages` by the provider. */
|
|
32
|
+
messages: OnnxGenerationMessage[];
|
|
33
|
+
/** Optional generation controls copied from the task request. */
|
|
34
|
+
generation?: NonNullable<TaskRequest["generation"]>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Normalized generation result returned by an ONNX text generation runtime.
|
|
38
|
+
*/
|
|
39
|
+
export interface OnnxGenerationOutput {
|
|
40
|
+
/** The generated text. */
|
|
41
|
+
text: string;
|
|
42
|
+
/** Optional normalized finish reason; the provider defaults to `stop`. */
|
|
43
|
+
finishReason?: TaskResult["finishReason"];
|
|
44
|
+
/** Optional token accounting, when the runtime reports it. */
|
|
45
|
+
usage?: TaskResult["usage"];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Failure category a runtime can signal so the provider maps it onto the IndeRun error taxonomy.
|
|
49
|
+
*
|
|
50
|
+
* - `capability`: model or runtime cannot serve this request (`CapabilityMismatch`).
|
|
51
|
+
* - `unavailable`: runtime initialization failure or resource exhaustion (`Unavailable`).
|
|
52
|
+
* - `timeout`: generation exceeded its budget or was aborted (`Timeout`).
|
|
53
|
+
* - `internal`: unexpected runtime failure (`Internal`).
|
|
54
|
+
*/
|
|
55
|
+
export type OnnxRuntimeErrorKind = "capability" | "unavailable" | "timeout" | "internal";
|
|
56
|
+
/**
|
|
57
|
+
* Error type ONNX runtime implementations throw to steer IndeRun error normalization.
|
|
58
|
+
*
|
|
59
|
+
* Anything else thrown by a runtime is normalized to `Internal`.
|
|
60
|
+
*/
|
|
61
|
+
export declare class OnnxRuntimeError extends Error {
|
|
62
|
+
/** Failure category used by the provider to select an IndeRun error class. */
|
|
63
|
+
readonly kind: OnnxRuntimeErrorKind;
|
|
64
|
+
/** Optional underlying error captured for telemetry details. */
|
|
65
|
+
readonly originalError?: unknown;
|
|
66
|
+
constructor(kind: OnnxRuntimeErrorKind, message: string, originalError?: unknown);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Injectable seam between the IndeRun ONNX Web provider and the actual on-device runtime.
|
|
70
|
+
*
|
|
71
|
+
* IndeRun ships a Transformers.js-backed implementation as the default and a deterministic
|
|
72
|
+
* fixture for tests, but applications can supply their own implementation (for example a
|
|
73
|
+
* hand-rolled `onnxruntime-web` pipeline) without touching the provider.
|
|
74
|
+
*/
|
|
75
|
+
export interface OnnxTextGenerationRuntime {
|
|
76
|
+
/**
|
|
77
|
+
* Checks runtime package availability, execution backend availability, and model readiness.
|
|
78
|
+
* Implementations must resolve with an availability snapshot rather than throwing.
|
|
79
|
+
*/
|
|
80
|
+
prepare(modelPackage: ModelPackage): Promise<OnnxRuntimeAvailability>;
|
|
81
|
+
/**
|
|
82
|
+
* Runs one Mode-1 generation. Implementations should honor `signal` where the underlying
|
|
83
|
+
* runtime allows it; ONNX inference is not hard-interruptible, so cancellation is best effort.
|
|
84
|
+
*/
|
|
85
|
+
generate(input: OnnxGenerationInput, signal?: AbortSignal): Promise<OnnxGenerationOutput>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Configuration for the deterministic fixture runtime.
|
|
89
|
+
*/
|
|
90
|
+
export interface FixtureOnnxRuntimeOptions {
|
|
91
|
+
/** Availability snapshot returned by `prepare`. Defaults to `{ available: true }`. */
|
|
92
|
+
availability?: OnnxRuntimeAvailability;
|
|
93
|
+
/** Text or full output produced by `generate`. Defaults to a deterministic echo. */
|
|
94
|
+
respond?: (input: OnnxGenerationInput) => string | OnnxGenerationOutput;
|
|
95
|
+
/** Error thrown by `generate` instead of producing output. */
|
|
96
|
+
failWith?: unknown;
|
|
97
|
+
/** Artificial generation delay in milliseconds, used to exercise timeouts. */
|
|
98
|
+
delayMs?: number;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Creates a deterministic in-memory ONNX runtime.
|
|
102
|
+
*
|
|
103
|
+
* This is the test seam mandated by the ONNX Runtime provider family specification: it proves the
|
|
104
|
+
* model package contract, capability checks, routing, and error normalization without depending on
|
|
105
|
+
* a real ONNX runtime, and it lets demos exercise the on-device route offline.
|
|
106
|
+
*
|
|
107
|
+
* @param options - Scripted availability, response, failure, and delay behavior.
|
|
108
|
+
*/
|
|
109
|
+
export declare function createFixtureOnnxRuntime(options?: FixtureOnnxRuntimeOptions): OnnxTextGenerationRuntime;
|
|
110
|
+
//# sourceMappingURL=onnx-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onnx-runtime.d.ts","sourceRoot":"","sources":["../src/onnx-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE1F;;;;;;;GAOG;AACH,MAAM,WAAW,uBAAuB;IACtC,sFAAsF;IACtF,SAAS,EAAE,OAAO,CAAC;IACnB,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,2CAA2C;IAC3C,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACtC,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,0DAA0D;IAC1D,YAAY,EAAE,YAAY,CAAC;IAC3B,kFAAkF;IAClF,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC,iEAAiE;IACjE,UAAU,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,YAAY,CAAC,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC;IAC1C,8DAA8D;IAC9D,KAAK,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;AAEzF;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,gEAAgE;IAChE,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;gBAErB,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,OAAO;CAQjF;AAED;;;;;;GAMG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,OAAO,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACtE;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,mBAAmB,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC3F;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,sFAAsF;IACtF,YAAY,CAAC,EAAE,uBAAuB,CAAC;IACvC,oFAAoF;IACpF,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,MAAM,GAAG,oBAAoB,CAAC;IACxE,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,GAAE,yBAA8B,GACtC,yBAAyB,CA4B3B"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error type ONNX runtime implementations throw to steer IndeRun error normalization.
|
|
3
|
+
*
|
|
4
|
+
* Anything else thrown by a runtime is normalized to `Internal`.
|
|
5
|
+
*/
|
|
6
|
+
export class OnnxRuntimeError extends Error {
|
|
7
|
+
/** Failure category used by the provider to select an IndeRun error class. */
|
|
8
|
+
kind;
|
|
9
|
+
/** Optional underlying error captured for telemetry details. */
|
|
10
|
+
originalError;
|
|
11
|
+
constructor(kind, message, originalError) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "OnnxRuntimeError";
|
|
14
|
+
this.kind = kind;
|
|
15
|
+
if (originalError !== undefined)
|
|
16
|
+
this.originalError = originalError;
|
|
17
|
+
Object.setPrototypeOf(this, OnnxRuntimeError.prototype);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates a deterministic in-memory ONNX runtime.
|
|
22
|
+
*
|
|
23
|
+
* This is the test seam mandated by the ONNX Runtime provider family specification: it proves the
|
|
24
|
+
* model package contract, capability checks, routing, and error normalization without depending on
|
|
25
|
+
* a real ONNX runtime, and it lets demos exercise the on-device route offline.
|
|
26
|
+
*
|
|
27
|
+
* @param options - Scripted availability, response, failure, and delay behavior.
|
|
28
|
+
*/
|
|
29
|
+
export function createFixtureOnnxRuntime(options = {}) {
|
|
30
|
+
const availability = options.availability ?? { available: true };
|
|
31
|
+
return {
|
|
32
|
+
async prepare() {
|
|
33
|
+
return availability;
|
|
34
|
+
},
|
|
35
|
+
async generate(input, signal) {
|
|
36
|
+
if (options.delayMs !== undefined && options.delayMs > 0) {
|
|
37
|
+
await delay(options.delayMs, signal);
|
|
38
|
+
}
|
|
39
|
+
throwIfAborted(signal);
|
|
40
|
+
if (options.failWith !== undefined) {
|
|
41
|
+
throw options.failWith;
|
|
42
|
+
}
|
|
43
|
+
const response = options.respond
|
|
44
|
+
? options.respond(input)
|
|
45
|
+
: createFixtureText(input.modelPackage, input.messages);
|
|
46
|
+
return typeof response === "string" ? { text: response } : response;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function createFixtureText(modelPackage, messages) {
|
|
51
|
+
const lastUserMessage = [...messages].reverse().find((message) => message.role === "user");
|
|
52
|
+
const prompt = lastUserMessage?.content ?? "";
|
|
53
|
+
return `[fixture:${modelPackage.id}] ${prompt}`;
|
|
54
|
+
}
|
|
55
|
+
function delay(ms, signal) {
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
const timer = setTimeout(() => {
|
|
58
|
+
signal?.removeEventListener("abort", onAbort);
|
|
59
|
+
resolve();
|
|
60
|
+
}, ms);
|
|
61
|
+
function onAbort() {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
reject(new OnnxRuntimeError("timeout", "Fixture ONNX generation was aborted."));
|
|
64
|
+
}
|
|
65
|
+
if (signal?.aborted) {
|
|
66
|
+
onAbort();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function throwIfAborted(signal) {
|
|
73
|
+
if (signal?.aborted) {
|
|
74
|
+
throw new OnnxRuntimeError("timeout", "Fixture ONNX generation was aborted.");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { ModelPackage } from "@independo/inderun-contracts";
|
|
2
|
+
import { type OnnxTextGenerationRuntime } from "./onnx-runtime.js";
|
|
3
|
+
/**
|
|
4
|
+
* Structural view of the `@huggingface/transformers` entry points this runtime uses.
|
|
5
|
+
*
|
|
6
|
+
* The dependency is optional, so the module is typed structurally instead of imported for types.
|
|
7
|
+
*/
|
|
8
|
+
export interface TransformersModule {
|
|
9
|
+
/** Builds a task pipeline, downloading or loading model assets as needed. */
|
|
10
|
+
pipeline: (task: string, model?: string, options?: Record<string, unknown>) => Promise<TransformersTextGenerator>;
|
|
11
|
+
/** Global Transformers.js environment used to point the loader at local model assets. */
|
|
12
|
+
env?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Structural view of a Transformers.js `text-generation` pipeline.
|
|
16
|
+
*/
|
|
17
|
+
export type TransformersTextGenerator = (input: unknown, options?: Record<string, unknown>) => Promise<unknown>;
|
|
18
|
+
/**
|
|
19
|
+
* Configuration for the Transformers.js-backed ONNX runtime.
|
|
20
|
+
*/
|
|
21
|
+
export interface TransformersJsRuntimeOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Overrides how the `@huggingface/transformers` module is loaded. Tests inject a fake module;
|
|
24
|
+
* production uses a lazy dynamic import so the dependency stays optional.
|
|
25
|
+
*/
|
|
26
|
+
load?: () => Promise<TransformersModule>;
|
|
27
|
+
/**
|
|
28
|
+
* Execution backend passed to Transformers.js. Defaults to `webgpu` when `navigator.gpu`
|
|
29
|
+
* exists and `wasm` otherwise. This is an ONNX Runtime execution backend, not an IndeRun
|
|
30
|
+
* routing concept.
|
|
31
|
+
*/
|
|
32
|
+
device?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Weight quantization passed to Transformers.js (for example `q4`, `q4f16`, `q8`, `fp16`,
|
|
35
|
+
* `fp32`).
|
|
36
|
+
*
|
|
37
|
+
* Defaults to a quantized variant (`q4f16` on WebGPU, `q4` otherwise) because Transformers.js
|
|
38
|
+
* would otherwise load full `fp32` weights, which exhausts browser memory for all but the
|
|
39
|
+
* smallest models. Set explicitly when the model does not publish the default variant.
|
|
40
|
+
*/
|
|
41
|
+
dtype?: string;
|
|
42
|
+
/** Base path or URL for locally served model assets (`bundled` / `app_managed` sources). */
|
|
43
|
+
localModelPath?: string;
|
|
44
|
+
/** Extra options merged into the Transformers.js `pipeline()` call. */
|
|
45
|
+
pipelineOptions?: Record<string, unknown>;
|
|
46
|
+
/**
|
|
47
|
+
* Supplies a pre-built generator instead of letting this runtime construct one. Required for
|
|
48
|
+
* `programmatic` model sources, where the application owns model resolution.
|
|
49
|
+
*/
|
|
50
|
+
createGenerator?: (context: {
|
|
51
|
+
modelPackage: ModelPackage;
|
|
52
|
+
module: TransformersModule;
|
|
53
|
+
device: string;
|
|
54
|
+
}) => Promise<TransformersTextGenerator>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Creates the default Web ONNX runtime, backed by Transformers.js (which runs ONNX models through
|
|
58
|
+
* `onnxruntime-web`).
|
|
59
|
+
*
|
|
60
|
+
* ONNX Runtime GenAI has no browser build, so Transformers.js fills the generative-loop role
|
|
61
|
+
* (tokenization, sampling, KV cache) behind the `OnnxTextGenerationRuntime` seam. Applications that
|
|
62
|
+
* need a different runtime implement the seam themselves and pass it to the provider.
|
|
63
|
+
*
|
|
64
|
+
* `@huggingface/transformers` is an optional dependency the application installs: when it is absent
|
|
65
|
+
* the runtime
|
|
66
|
+
* reports itself unavailable instead of throwing, so routing degrades to an explainable
|
|
67
|
+
* `capability_unavailable` rejection.
|
|
68
|
+
*
|
|
69
|
+
* @param options - Loader, backend, and model-resolution overrides.
|
|
70
|
+
*/
|
|
71
|
+
export declare function createTransformersJsRuntime(options?: TransformersJsRuntimeOptions): OnnxTextGenerationRuntime;
|
|
72
|
+
//# sourceMappingURL=onnx-transformers-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onnx-transformers-runtime.d.ts","sourceRoot":"","sources":["../src/onnx-transformers-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAKL,KAAK,yBAAyB,EAC/B,MAAM,mBAAmB,CAAC;AAE3B;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,QAAQ,EAAE,CACR,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC9B,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACxC,yFAAyF;IACzF,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,CACtC,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC9B,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACzC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4FAA4F;IAC5F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE;QAC1B,YAAY,EAAE,YAAY,CAAC;QAC3B,MAAM,EAAE,kBAAkB,CAAC;QAC3B,MAAM,EAAE,MAAM,CAAC;KAChB,KAAK,OAAO,CAAC,yBAAyB,CAAC,CAAC;CAC1C;AAID;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,4BAAiC,GACzC,yBAAyB,CAyI3B"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { OnnxRuntimeError } from "./onnx-runtime.js";
|
|
2
|
+
const TEXT_GENERATION_TASK = "text-generation";
|
|
3
|
+
/**
|
|
4
|
+
* Creates the default Web ONNX runtime, backed by Transformers.js (which runs ONNX models through
|
|
5
|
+
* `onnxruntime-web`).
|
|
6
|
+
*
|
|
7
|
+
* ONNX Runtime GenAI has no browser build, so Transformers.js fills the generative-loop role
|
|
8
|
+
* (tokenization, sampling, KV cache) behind the `OnnxTextGenerationRuntime` seam. Applications that
|
|
9
|
+
* need a different runtime implement the seam themselves and pass it to the provider.
|
|
10
|
+
*
|
|
11
|
+
* `@huggingface/transformers` is an optional dependency the application installs: when it is absent
|
|
12
|
+
* the runtime
|
|
13
|
+
* reports itself unavailable instead of throwing, so routing degrades to an explainable
|
|
14
|
+
* `capability_unavailable` rejection.
|
|
15
|
+
*
|
|
16
|
+
* @param options - Loader, backend, and model-resolution overrides.
|
|
17
|
+
*/
|
|
18
|
+
export function createTransformersJsRuntime(options = {}) {
|
|
19
|
+
let modulePromise;
|
|
20
|
+
let generatorPromise;
|
|
21
|
+
async function loadModule() {
|
|
22
|
+
modulePromise ??= (options.load ?? loadTransformersModule)();
|
|
23
|
+
return modulePromise;
|
|
24
|
+
}
|
|
25
|
+
async function loadGenerator(modelPackage) {
|
|
26
|
+
generatorPromise ??= (async () => {
|
|
27
|
+
const module = await loadModule();
|
|
28
|
+
const device = resolveDevice(options.device);
|
|
29
|
+
if (options.createGenerator) {
|
|
30
|
+
return options.createGenerator({ modelPackage, module, device });
|
|
31
|
+
}
|
|
32
|
+
const modelRef = getModelRef(modelPackage);
|
|
33
|
+
if (!modelRef) {
|
|
34
|
+
throw new OnnxRuntimeError("capability", "model source unavailable: the model package does not declare source.ref.");
|
|
35
|
+
}
|
|
36
|
+
applyEnvironment(module, modelPackage, options.localModelPath);
|
|
37
|
+
const pipelineOptions = {
|
|
38
|
+
device,
|
|
39
|
+
dtype: options.dtype ?? defaultDtype(device),
|
|
40
|
+
...(options.pipelineOptions ?? {})
|
|
41
|
+
};
|
|
42
|
+
return module.pipeline(TEXT_GENERATION_TASK, modelRef, pipelineOptions);
|
|
43
|
+
})();
|
|
44
|
+
return generatorPromise;
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
async prepare(modelPackage) {
|
|
48
|
+
let module;
|
|
49
|
+
try {
|
|
50
|
+
module = await loadModule();
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
modulePromise = undefined;
|
|
54
|
+
return {
|
|
55
|
+
available: false,
|
|
56
|
+
reason: `runtime package unavailable: install the optional dependency @huggingface/transformers (${getErrorMessage(err)}).`
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (typeof module.pipeline !== "function") {
|
|
60
|
+
return {
|
|
61
|
+
available: false,
|
|
62
|
+
reason: "runtime initialization failed: @huggingface/transformers did not expose pipeline()."
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (modelPackage.format !== "onnx") {
|
|
66
|
+
return {
|
|
67
|
+
available: false,
|
|
68
|
+
reason: `unsupported model format: the Transformers.js runtime consumes ONNX weights, received '${modelPackage.format}'.`
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const sourceType = modelPackage.source?.sourceType;
|
|
72
|
+
if (sourceType === "programmatic" && !options.createGenerator) {
|
|
73
|
+
return {
|
|
74
|
+
available: false,
|
|
75
|
+
reason: "model source unavailable: programmatic model packages require a createGenerator option."
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (!options.createGenerator && !getModelRef(modelPackage)) {
|
|
79
|
+
return {
|
|
80
|
+
available: false,
|
|
81
|
+
reason: "model source unavailable: the model package does not declare source.ref."
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return { available: true };
|
|
85
|
+
},
|
|
86
|
+
async generate(input, signal) {
|
|
87
|
+
let generator;
|
|
88
|
+
try {
|
|
89
|
+
generator = await loadGenerator(input.modelPackage);
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
generatorPromise = undefined;
|
|
93
|
+
if (err instanceof OnnxRuntimeError)
|
|
94
|
+
throw err;
|
|
95
|
+
if (isResourceExhaustion(err)) {
|
|
96
|
+
throw new OnnxRuntimeError("unavailable", `insufficient memory to load the model: ${getErrorMessage(err)}. Try a smaller model or a more aggressive dtype (for example 'q4').`, err);
|
|
97
|
+
}
|
|
98
|
+
throw new OnnxRuntimeError("capability", `model files missing or unreadable: ${getErrorMessage(err)}`, err);
|
|
99
|
+
}
|
|
100
|
+
if (signal?.aborted) {
|
|
101
|
+
throw new OnnxRuntimeError("timeout", "ONNX generation was aborted before it started.");
|
|
102
|
+
}
|
|
103
|
+
let raw;
|
|
104
|
+
try {
|
|
105
|
+
raw = await generator(input.messages, createGenerationOptions(input, signal));
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
throw new OnnxRuntimeError("internal", `ONNX generation failed: ${getErrorMessage(err)}`, err);
|
|
109
|
+
}
|
|
110
|
+
const text = extractGeneratedText(raw);
|
|
111
|
+
if (text === undefined) {
|
|
112
|
+
throw new OnnxRuntimeError("internal", "model output malformed: the Transformers.js pipeline returned no text.");
|
|
113
|
+
}
|
|
114
|
+
return { text };
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
async function loadTransformersModule() {
|
|
119
|
+
// The specifier stays a literal so bundlers and dev servers resolve the bare package name; the
|
|
120
|
+
// `as string` cast keeps TypeScript from requiring the optional dependency's types here. Apps that
|
|
121
|
+
// do not install Transformers.js should pass their own `load` (or a different runtime) rather than
|
|
122
|
+
// relying on this default, which their bundler will fail to resolve.
|
|
123
|
+
return (await import("@huggingface/transformers"));
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Browser-viable weight variant. Transformers.js defaults to `fp32`, which makes ONNX Runtime
|
|
127
|
+
* allocate the full-precision model and fail session creation with an allocation error for
|
|
128
|
+
* anything but tiny models.
|
|
129
|
+
*/
|
|
130
|
+
function defaultDtype(device) {
|
|
131
|
+
return device === "webgpu" ? "q4f16" : "q4";
|
|
132
|
+
}
|
|
133
|
+
function resolveDevice(configured) {
|
|
134
|
+
if (configured !== undefined)
|
|
135
|
+
return configured;
|
|
136
|
+
const gpu = globalThis.navigator?.gpu;
|
|
137
|
+
return gpu ? "webgpu" : "wasm";
|
|
138
|
+
}
|
|
139
|
+
function getModelRef(modelPackage) {
|
|
140
|
+
const ref = modelPackage.source?.ref;
|
|
141
|
+
return typeof ref === "string" && ref.length > 0 ? ref : undefined;
|
|
142
|
+
}
|
|
143
|
+
function applyEnvironment(module, modelPackage, localModelPath) {
|
|
144
|
+
const env = module.env;
|
|
145
|
+
if (!env)
|
|
146
|
+
return;
|
|
147
|
+
const sourceType = modelPackage.source?.sourceType;
|
|
148
|
+
if (sourceType === "bundled" || sourceType === "app_managed") {
|
|
149
|
+
env.allowLocalModels = true;
|
|
150
|
+
env.allowRemoteModels = false;
|
|
151
|
+
if (localModelPath !== undefined) {
|
|
152
|
+
env.localModelPath = localModelPath;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function createGenerationOptions(input, signal) {
|
|
157
|
+
const generation = input.generation;
|
|
158
|
+
const generationOptions = {};
|
|
159
|
+
if (generation?.maxOutputTokens !== undefined) {
|
|
160
|
+
generationOptions.max_new_tokens = generation.maxOutputTokens;
|
|
161
|
+
}
|
|
162
|
+
if (generation?.temperature !== undefined) {
|
|
163
|
+
generationOptions.temperature = generation.temperature;
|
|
164
|
+
generationOptions.do_sample = generation.temperature > 0;
|
|
165
|
+
}
|
|
166
|
+
if (generation?.topP !== undefined) {
|
|
167
|
+
generationOptions.top_p = generation.topP;
|
|
168
|
+
}
|
|
169
|
+
if (generation?.stop !== undefined && generation.stop.length > 0) {
|
|
170
|
+
generationOptions.stop_strings = generation.stop;
|
|
171
|
+
}
|
|
172
|
+
if (signal !== undefined) {
|
|
173
|
+
generationOptions.signal = signal;
|
|
174
|
+
}
|
|
175
|
+
return generationOptions;
|
|
176
|
+
}
|
|
177
|
+
function extractGeneratedText(raw) {
|
|
178
|
+
const first = Array.isArray(raw) ? raw[0] : raw;
|
|
179
|
+
if (!isRecord(first)) {
|
|
180
|
+
return typeof first === "string" ? first : undefined;
|
|
181
|
+
}
|
|
182
|
+
const generated = first.generated_text;
|
|
183
|
+
if (typeof generated === "string") {
|
|
184
|
+
return generated;
|
|
185
|
+
}
|
|
186
|
+
if (Array.isArray(generated)) {
|
|
187
|
+
const last = generated[generated.length - 1];
|
|
188
|
+
if (isRecord(last) && typeof last.content === "string") {
|
|
189
|
+
return last.content;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Detects out-of-memory failures surfaced by ONNX Runtime session creation, which arrive as
|
|
196
|
+
* allocation errors from the WASM/native layer rather than as typed errors.
|
|
197
|
+
*/
|
|
198
|
+
function isResourceExhaustion(error) {
|
|
199
|
+
const message = getErrorMessage(error).toLowerCase();
|
|
200
|
+
return (message.includes("bad_alloc") ||
|
|
201
|
+
message.includes("out of memory") ||
|
|
202
|
+
message.includes("failed to allocate") ||
|
|
203
|
+
message.includes("allocation failed"));
|
|
204
|
+
}
|
|
205
|
+
function isRecord(value) {
|
|
206
|
+
return typeof value === "object" && value !== null;
|
|
207
|
+
}
|
|
208
|
+
function getErrorMessage(error) {
|
|
209
|
+
return error instanceof Error ? error.message : String(error);
|
|
210
|
+
}
|
package/dist/onnx.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-specific entry point for the Web member of the ONNX Runtime provider family.
|
|
3
|
+
*
|
|
4
|
+
* Kept out of the unified SDK index (`@independo/inderun-web`) so the top-level
|
|
5
|
+
* surface stays provider-agnostic. Import from `@independo/inderun-web/onnx`
|
|
6
|
+
* when registering the adapter manually or when implementing a custom
|
|
7
|
+
* `OnnxTextGenerationRuntime`; most browser apps should pass `onnx` to
|
|
8
|
+
* `createIndeRunWeb` from the main entry point instead.
|
|
9
|
+
*/
|
|
10
|
+
export { OnnxRuntimeWebProvider, DEFAULT_ONNX_WEB_PROVIDER_ID, SUPPORTED_WEB_MODEL_SOURCE_TYPES, type OnnxProviderOptions } from "./onnx-provider.js";
|
|
11
|
+
export { OnnxRuntimeError, createFixtureOnnxRuntime, type FixtureOnnxRuntimeOptions, type OnnxGenerationInput, type OnnxGenerationMessage, type OnnxGenerationOutput, type OnnxRuntimeAvailability, type OnnxRuntimeErrorKind, type OnnxTextGenerationRuntime } from "./onnx-runtime.js";
|
|
12
|
+
export { createTransformersJsRuntime, type TransformersJsRuntimeOptions, type TransformersModule, type TransformersTextGenerator } from "./onnx-transformers-runtime.js";
|
|
13
|
+
//# sourceMappingURL=onnx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onnx.d.ts","sourceRoot":"","sources":["../src/onnx.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAC5B,gCAAgC,EAChC,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,yBAAyB,EAC/B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,2BAA2B,EAC3B,KAAK,4BAA4B,EACjC,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC/B,MAAM,gCAAgC,CAAC"}
|
package/dist/onnx.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-specific entry point for the Web member of the ONNX Runtime provider family.
|
|
3
|
+
*
|
|
4
|
+
* Kept out of the unified SDK index (`@independo/inderun-web`) so the top-level
|
|
5
|
+
* surface stays provider-agnostic. Import from `@independo/inderun-web/onnx`
|
|
6
|
+
* when registering the adapter manually or when implementing a custom
|
|
7
|
+
* `OnnxTextGenerationRuntime`; most browser apps should pass `onnx` to
|
|
8
|
+
* `createIndeRunWeb` from the main entry point instead.
|
|
9
|
+
*/
|
|
10
|
+
export { OnnxRuntimeWebProvider, DEFAULT_ONNX_WEB_PROVIDER_ID, SUPPORTED_WEB_MODEL_SOURCE_TYPES } from "./onnx-provider.js";
|
|
11
|
+
export { OnnxRuntimeError, createFixtureOnnxRuntime } from "./onnx-runtime.js";
|
|
12
|
+
export { createTransformersJsRuntime } from "./onnx-transformers-runtime.js";
|
package/dist/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAOtD,OAAO,EAIL,KAAK,YAAY,EAEjB,KAAK,sBAAsB,EAE5B,MAAM,oBAAoB,CAAC;AAE5B;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,QAAQ,EAAE,eAAe,CAAC;IAC1B;;OAEG;IACH,iBAAiB,EAAE,eAAe,EAAE,CAAC;IACrC;;OAEG;IACH,SAAS,EAAE,sBAAsB,CAAC;IAClC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,qBAAa,MAAM;IAEf,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,OAAO;gBADP,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,GAAE,YAAqC;IAGxD;;;;;;;;;OASG;IACG,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC;IAc5F,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,2BAA2B;IAuBnC,OAAO,CAAC,kBAAkB;
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAOtD,OAAO,EAIL,KAAK,YAAY,EAEjB,KAAK,sBAAsB,EAE5B,MAAM,oBAAoB,CAAC;AAE5B;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,QAAQ,EAAE,eAAe,CAAC;IAC1B;;OAEG;IACH,iBAAiB,EAAE,eAAe,EAAE,CAAC;IACrC;;OAEG;IACH,SAAS,EAAE,sBAAsB,CAAC;IAClC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,qBAAa,MAAM;IAEf,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,OAAO;gBADP,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,GAAE,YAAqC;IAGxD;;;;;;;;;OASG;IACG,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC;IAc5F,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,2BAA2B;IAuBnC,OAAO,CAAC,kBAAkB;IA0F1B,OAAO,CAAC,2BAA2B;IAiCnC,OAAO,CAAC,gBAAgB;CAYzB"}
|
package/dist/router.js
CHANGED
|
@@ -67,17 +67,24 @@ export class Router {
|
|
|
67
67
|
.filter((candidate) => candidate.descriptor.supports.run);
|
|
68
68
|
const localCandidates = eligible.filter((candidate) => candidate.descriptor.type !== "cloud");
|
|
69
69
|
const cloudCandidates = eligible.filter((candidate) => candidate.descriptor.type === "cloud");
|
|
70
|
-
|
|
70
|
+
// Constraint filtering must apply to the whole candidate list, not just the selected provider:
|
|
71
|
+
// the remainder becomes the engine's fallback chain, and a fallback that violates the request
|
|
72
|
+
// constraints would let a `local_required` run be retried against a cloud provider.
|
|
73
|
+
const admissible = eligible.filter((candidate) => {
|
|
71
74
|
const descriptor = candidate.descriptor;
|
|
72
75
|
const constraints = planInput.constraints;
|
|
73
|
-
|
|
76
|
+
// Mirrors `is_data_private` in the shared Rust planner: a provider is private when it
|
|
77
|
+
// declares that data does not leave the device, defaulting to non-cloud providers.
|
|
78
|
+
const isDataPrivate = descriptor.privacy
|
|
79
|
+
? !descriptor.privacy.dataLeavesDevice
|
|
80
|
+
: descriptor.type !== "cloud";
|
|
74
81
|
if (constraints.cloud === "forbidden" && descriptor.type === "cloud") {
|
|
75
82
|
return false;
|
|
76
83
|
}
|
|
77
84
|
if (constraints.cloud === "required" && descriptor.type !== "cloud") {
|
|
78
85
|
return false;
|
|
79
86
|
}
|
|
80
|
-
if (constraints.privacy === "local_required" && !
|
|
87
|
+
if (constraints.privacy === "local_required" && !isDataPrivate) {
|
|
81
88
|
return false;
|
|
82
89
|
}
|
|
83
90
|
if (constraints.privacy === "cloud_required" && descriptor.type !== "cloud") {
|
|
@@ -88,10 +95,7 @@ export class Router {
|
|
|
88
95
|
}
|
|
89
96
|
return candidate.capabilities.available;
|
|
90
97
|
});
|
|
91
|
-
|
|
92
|
-
? [selected, ...eligible.filter((candidate) => candidate !== selected)]
|
|
93
|
-
: [];
|
|
94
|
-
if (ordered.length === 0) {
|
|
98
|
+
if (admissible.length === 0) {
|
|
95
99
|
const failureSummary = this.buildFallbackFailureSummary({
|
|
96
100
|
online,
|
|
97
101
|
constraints: planInput.constraints,
|
|
@@ -114,17 +118,17 @@ export class Router {
|
|
|
114
118
|
}
|
|
115
119
|
};
|
|
116
120
|
}
|
|
117
|
-
const selectedProviderId =
|
|
121
|
+
const selectedProviderId = admissible[0]?.descriptor.id;
|
|
118
122
|
return {
|
|
119
123
|
selectedProviderId,
|
|
120
|
-
fallbackProviderIds:
|
|
121
|
-
candidates:
|
|
124
|
+
fallbackProviderIds: admissible.slice(1).map((candidate) => candidate.descriptor.id),
|
|
125
|
+
candidates: admissible.map((candidate, index) => ({
|
|
122
126
|
providerId: candidate.descriptor.id,
|
|
123
127
|
order: index
|
|
124
128
|
})),
|
|
125
129
|
rejectedProviders: [],
|
|
126
130
|
explanation: {
|
|
127
|
-
summary: `Selected provider '${selectedProviderId}' deterministically from ${
|
|
131
|
+
summary: `Selected provider '${selectedProviderId}' deterministically from ${admissible.length} eligible candidate(s).`,
|
|
128
132
|
selectedProviderId
|
|
129
133
|
}
|
|
130
134
|
};
|
package/dist/web-sdk.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type CreateBrowserHostServicesOptions } from "./browser-host.js";
|
|
2
2
|
import { IndeRun } from "./engine.js";
|
|
3
|
+
import { type OnnxProviderOptions } from "./onnx-provider.js";
|
|
3
4
|
import { type OpenAIProviderOptions } from "./openai-provider.js";
|
|
4
5
|
/**
|
|
5
6
|
* Configuration for the default Web SDK factory.
|
|
@@ -8,7 +9,12 @@ export interface CreateIndeRunWebOptions {
|
|
|
8
9
|
/**
|
|
9
10
|
* OpenAI Responses provider configuration registered by the factory.
|
|
10
11
|
*/
|
|
11
|
-
openAI
|
|
12
|
+
openAI?: OpenAIProviderOptions;
|
|
13
|
+
/**
|
|
14
|
+
* Web ONNX Runtime provider configuration registered by the factory, for developer-supplied
|
|
15
|
+
* local models. Registering it is what makes `constraints.privacy = "local_required"` routable.
|
|
16
|
+
*/
|
|
17
|
+
onnx?: OnnxProviderOptions;
|
|
12
18
|
/**
|
|
13
19
|
* Optional browser host service overrides.
|
|
14
20
|
*/
|
|
@@ -23,13 +29,16 @@ export interface CreateIndeRunWebOptions {
|
|
|
23
29
|
allowDirectOpenAIEndpoint?: boolean;
|
|
24
30
|
}
|
|
25
31
|
/**
|
|
26
|
-
* Creates a Web SDK instance with the
|
|
32
|
+
* Creates a Web SDK instance with the configured providers registered.
|
|
33
|
+
*
|
|
34
|
+
* Pass `openAI` for cloud execution, `onnx` for developer-supplied local models, or both to let
|
|
35
|
+
* routing choose between them; at least one is required.
|
|
27
36
|
*
|
|
28
37
|
* Use `openAI.auth = "none"` with a proxy endpoint for production browser apps so the OpenAI API key never ships
|
|
29
38
|
* to the client. Direct OpenAI calls require `allowDirectOpenAIEndpoint` and should resolve credentials through
|
|
30
39
|
* `authContextRef` and `SecureStorageService`.
|
|
31
40
|
*
|
|
32
|
-
* @param options -
|
|
41
|
+
* @param options - Provider configuration and optional host service overrides.
|
|
33
42
|
*/
|
|
34
43
|
export declare function createIndeRunWeb(options: CreateIndeRunWebOptions): IndeRun;
|
|
35
44
|
//# sourceMappingURL=web-sdk.d.ts.map
|
package/dist/web-sdk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-sdk.d.ts","sourceRoot":"","sources":["../src/web-sdk.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gCAAgC,EACtC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAG9B;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,MAAM,EAAE,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"web-sdk.d.ts","sourceRoot":"","sources":["../src/web-sdk.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gCAAgC,EACtC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAG9B;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B;;;OAGG;IACH,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B;;OAEG;IACH,YAAY,CAAC,EAAE,gCAAgC,CAAC;IAChD;;;;;;OAMG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAmB1E"}
|
package/dist/web-sdk.js
CHANGED
|
@@ -1,27 +1,39 @@
|
|
|
1
1
|
import { createBrowserHostServices } from "./browser-host.js";
|
|
2
2
|
import { IndeRun } from "./engine.js";
|
|
3
|
+
import { OnnxRuntimeWebProvider } from "./onnx-provider.js";
|
|
3
4
|
import { DEFAULT_OPENAI_RESPONSES_ENDPOINT, OpenAIResponsesProvider } from "./openai-provider.js";
|
|
4
5
|
import { ProviderRegistry } from "./registry.js";
|
|
5
6
|
/**
|
|
6
|
-
* Creates a Web SDK instance with the
|
|
7
|
+
* Creates a Web SDK instance with the configured providers registered.
|
|
8
|
+
*
|
|
9
|
+
* Pass `openAI` for cloud execution, `onnx` for developer-supplied local models, or both to let
|
|
10
|
+
* routing choose between them; at least one is required.
|
|
7
11
|
*
|
|
8
12
|
* Use `openAI.auth = "none"` with a proxy endpoint for production browser apps so the OpenAI API key never ships
|
|
9
13
|
* to the client. Direct OpenAI calls require `allowDirectOpenAIEndpoint` and should resolve credentials through
|
|
10
14
|
* `authContextRef` and `SecureStorageService`.
|
|
11
15
|
*
|
|
12
|
-
* @param options -
|
|
16
|
+
* @param options - Provider configuration and optional host service overrides.
|
|
13
17
|
*/
|
|
14
18
|
export function createIndeRunWeb(options) {
|
|
15
|
-
|
|
19
|
+
if (!options.openAI && !options.onnx) {
|
|
20
|
+
throw new Error("createIndeRunWeb requires at least one provider configuration (openAI and/or onnx).");
|
|
21
|
+
}
|
|
16
22
|
const registry = new ProviderRegistry();
|
|
17
|
-
|
|
23
|
+
if (options.openAI) {
|
|
24
|
+
assertSafeOpenAIEndpoint(options.openAI, options.allowDirectOpenAIEndpoint);
|
|
25
|
+
registry.register(new OpenAIResponsesProvider(options.openAI));
|
|
26
|
+
}
|
|
27
|
+
if (options.onnx) {
|
|
28
|
+
registry.register(new OnnxRuntimeWebProvider(options.onnx));
|
|
29
|
+
}
|
|
18
30
|
return new IndeRun(registry, createBrowserHostServices(options.hostServices));
|
|
19
31
|
}
|
|
20
|
-
function assertSafeOpenAIEndpoint(
|
|
21
|
-
const endpointUrl =
|
|
22
|
-
const auth =
|
|
32
|
+
function assertSafeOpenAIEndpoint(openAI, allowDirectOpenAIEndpoint) {
|
|
33
|
+
const endpointUrl = openAI.endpointUrl ?? DEFAULT_OPENAI_RESPONSES_ENDPOINT;
|
|
34
|
+
const auth = openAI.auth ?? "authContextRef";
|
|
23
35
|
const isDirectOpenAIEndpoint = isOpenAIResponsesEndpoint(endpointUrl);
|
|
24
|
-
if (isDirectOpenAIEndpoint && auth !== "none" && !
|
|
36
|
+
if (isDirectOpenAIEndpoint && auth !== "none" && !allowDirectOpenAIEndpoint) {
|
|
25
37
|
throw new Error('createIndeRunWeb is proxy-first for browser safety. Configure openAI.endpointUrl to a server-side proxy with auth: "none", or set allowDirectOpenAIEndpoint: true for controlled direct OpenAI calls.');
|
|
26
38
|
}
|
|
27
39
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@independo/inderun-web",
|
|
3
|
-
"version": "0.2.0-dev.
|
|
3
|
+
"version": "0.2.0-dev.2",
|
|
4
4
|
"description": "TypeScript/Web SDK for IndeRun.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -40,6 +40,10 @@
|
|
|
40
40
|
"./openai": {
|
|
41
41
|
"types": "./dist/openai.d.ts",
|
|
42
42
|
"default": "./dist/openai.js"
|
|
43
|
+
},
|
|
44
|
+
"./onnx": {
|
|
45
|
+
"types": "./dist/onnx.d.ts",
|
|
46
|
+
"default": "./dist/onnx.js"
|
|
43
47
|
}
|
|
44
48
|
},
|
|
45
49
|
"files": [
|
|
@@ -47,8 +51,16 @@
|
|
|
47
51
|
"README.md"
|
|
48
52
|
],
|
|
49
53
|
"dependencies": {
|
|
50
|
-
"@independo/inderun-contracts": "^0.2.0-dev.
|
|
51
|
-
"@independo/inderun-route-core-wasm": "^0.2.0-dev.
|
|
54
|
+
"@independo/inderun-contracts": "^0.2.0-dev.2",
|
|
55
|
+
"@independo/inderun-route-core-wasm": "^0.2.0-dev.2"
|
|
56
|
+
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"@huggingface/transformers": "^4.0.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependenciesMeta": {
|
|
61
|
+
"@huggingface/transformers": {
|
|
62
|
+
"optional": true
|
|
63
|
+
}
|
|
52
64
|
},
|
|
53
65
|
"devDependencies": {
|
|
54
66
|
"@types/node": "^26.1.1",
|