@independo/inderun-web 0.2.0-dev.1 → 0.2.0-dev.10

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.
Files changed (75) hide show
  1. package/README.md +187 -1
  2. package/dist/core/browser-host.d.ts.map +1 -0
  3. package/dist/{engine.d.ts → core/engine.d.ts} +6 -0
  4. package/dist/core/engine.d.ts.map +1 -0
  5. package/dist/{engine.js → core/engine.js} +14 -1
  6. package/dist/core/errors.d.ts.map +1 -0
  7. package/dist/core/host.d.ts.map +1 -0
  8. package/dist/{provider.d.ts → core/provider.d.ts} +9 -0
  9. package/dist/core/provider.d.ts.map +1 -0
  10. package/dist/core/registry.d.ts.map +1 -0
  11. package/dist/{route-planner.d.ts → core/route-planner.d.ts} +31 -8
  12. package/dist/core/route-planner.d.ts.map +1 -0
  13. package/dist/{route-planner.js → core/route-planner.js} +46 -17
  14. package/dist/{router.d.ts → core/router.d.ts} +11 -1
  15. package/dist/core/router.d.ts.map +1 -0
  16. package/dist/{router.js → core/router.js} +26 -20
  17. package/dist/core/telemetry.d.ts.map +1 -0
  18. package/dist/index.d.ts +9 -9
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +9 -9
  21. package/dist/onnx.d.ts +13 -0
  22. package/dist/onnx.d.ts.map +1 -0
  23. package/dist/onnx.js +12 -0
  24. package/dist/openai.d.ts +1 -1
  25. package/dist/openai.d.ts.map +1 -1
  26. package/dist/openai.js +1 -1
  27. package/dist/providers/onnx/provider.d.ts +78 -0
  28. package/dist/providers/onnx/provider.d.ts.map +1 -0
  29. package/dist/providers/onnx/provider.js +217 -0
  30. package/dist/providers/onnx/runtime.d.ts +110 -0
  31. package/dist/providers/onnx/runtime.d.ts.map +1 -0
  32. package/dist/providers/onnx/runtime.js +76 -0
  33. package/dist/providers/onnx/transformers-runtime.d.ts +72 -0
  34. package/dist/providers/onnx/transformers-runtime.d.ts.map +1 -0
  35. package/dist/providers/onnx/transformers-runtime.js +210 -0
  36. package/dist/{openai-provider.d.ts → providers/openai/provider.d.ts} +21 -3
  37. package/dist/providers/openai/provider.d.ts.map +1 -0
  38. package/dist/{openai-provider.js → providers/openai/provider.js} +42 -2
  39. package/dist/providers/system-model/chrome-runtime.d.ts +48 -0
  40. package/dist/providers/system-model/chrome-runtime.d.ts.map +1 -0
  41. package/dist/providers/system-model/chrome-runtime.js +137 -0
  42. package/dist/providers/system-model/provider.d.ts +67 -0
  43. package/dist/providers/system-model/provider.d.ts.map +1 -0
  44. package/dist/providers/system-model/provider.js +190 -0
  45. package/dist/providers/system-model/runtime.d.ts +110 -0
  46. package/dist/providers/system-model/runtime.d.ts.map +1 -0
  47. package/dist/providers/system-model/runtime.js +73 -0
  48. package/dist/system-model.d.ts +13 -0
  49. package/dist/system-model.d.ts.map +1 -0
  50. package/dist/system-model.js +12 -0
  51. package/dist/web-sdk.d.ts +23 -6
  52. package/dist/web-sdk.d.ts.map +1 -1
  53. package/dist/web-sdk.js +29 -12
  54. package/package.json +21 -5
  55. package/dist/browser-host.d.ts.map +0 -1
  56. package/dist/engine.d.ts.map +0 -1
  57. package/dist/errors.d.ts.map +0 -1
  58. package/dist/host.d.ts.map +0 -1
  59. package/dist/openai-provider.d.ts.map +0 -1
  60. package/dist/provider.d.ts.map +0 -1
  61. package/dist/registry.d.ts.map +0 -1
  62. package/dist/route-planner.d.ts.map +0 -1
  63. package/dist/router.d.ts.map +0 -1
  64. package/dist/telemetry.d.ts.map +0 -1
  65. /package/dist/{browser-host.d.ts → core/browser-host.d.ts} +0 -0
  66. /package/dist/{browser-host.js → core/browser-host.js} +0 -0
  67. /package/dist/{errors.d.ts → core/errors.d.ts} +0 -0
  68. /package/dist/{errors.js → core/errors.js} +0 -0
  69. /package/dist/{host.d.ts → core/host.d.ts} +0 -0
  70. /package/dist/{host.js → core/host.js} +0 -0
  71. /package/dist/{provider.js → core/provider.js} +0 -0
  72. /package/dist/{registry.d.ts → core/registry.d.ts} +0 -0
  73. /package/dist/{registry.js → core/registry.js} +0 -0
  74. /package/dist/{telemetry.d.ts → core/telemetry.d.ts} +0 -0
  75. /package/dist/{telemetry.js → core/telemetry.js} +0 -0
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, and the OpenAI-compatible cloud provider.
11
+ This package provides the Web SDK entrypoint, the engine core, routing, telemetry, error normalization, the OpenAI-compatible cloud provider, the Web ONNX Runtime provider for developer-supplied local models, and the Web system-model provider for browser-managed on-device models.
12
12
 
13
13
  ## Basic Usage
14
14
 
@@ -48,6 +48,192 @@ 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
+
167
+ ## On-Device Models: Web System-Model Provider
168
+
169
+ `local.system-model.web` runs a browser-managed on-device model — currently
170
+ [Chrome's Prompt API](https://developer.chrome.com/docs/ai/prompt-api) (`LanguageModel`, Gemini
171
+ Nano). Unlike the ONNX provider above, this provider takes no `modelPackage`: the browser owns
172
+ model availability, download, and execution. Registering it also makes
173
+ `constraints.privacy = "local_required"` routable. Pass `systemModel` to the factory:
174
+
175
+ ```ts
176
+ import { createIndeRunWeb } from "@independo/inderun-web";
177
+
178
+ const inderun = createIndeRunWeb({
179
+ systemModel: {}
180
+ });
181
+ ```
182
+
183
+ Options: `id` (defaults to `local.system-model.web`), `runtime` (defaults to
184
+ `createChromePromptApiRuntime()`), and `timeoutMs` (a request's `constraints.timeoutMs` wins).
185
+
186
+ ### Browser support
187
+
188
+ Desktop Chrome 138+ only (Windows 10/11, macOS 13+, Linux, ChromeOS), and requires roughly 22 GB
189
+ free storage plus either a >4 GB VRAM GPU or a 16 GB RAM / 4+ core CPU. These figures come from
190
+ Chrome and may change — see the [Prompt API docs](https://developer.chrome.com/docs/ai/prompt-api)
191
+ for the current requirements. Edge exposes an analogous API, but this package has not yet verified
192
+ whether it shares the exact `LanguageModel` global shape. Everywhere else, the provider reports
193
+ itself unavailable (`api_missing`) rather than throwing.
194
+
195
+ ### Errors
196
+
197
+ | Condition | `errorClass` |
198
+ | ------------------------------------------------------------- | --------------------- |
199
+ | Capability gate fails pre-attempt (any non-available state) | `CapabilityMismatch` |
200
+ | Hardware/browser-feature failure surfaced during generation | `CapabilityMismatch` |
201
+ | Storage/network constraints, transient failure | `Unavailable` |
202
+ | Generation aborted or exceeded its timeout budget | `Timeout` |
203
+ | Malformed/empty model output, unexpected runtime failure | `Internal` |
204
+
205
+ A purely local runtime never produces `AuthError`, `RateLimited`, or `Offline`. See
206
+ [`docs/architecture/web-system-model-provider-family.md`](https://github.com/independo-gmbh/inderun/blob/main/docs/architecture/web-system-model-provider-family.md)
207
+ in the monorepo for the full capability-state vocabulary.
208
+
209
+ ### Custom runtimes
210
+
211
+ Swap the execution backend without touching provider semantics by implementing
212
+ `SystemModelRuntime`:
213
+
214
+ ```ts
215
+ import {
216
+ SystemModelWebProvider,
217
+ SystemModelRuntimeError,
218
+ createFixtureSystemModelRuntime,
219
+ type SystemModelRuntime
220
+ } from "@independo/inderun-web/system-model";
221
+
222
+ const runtime: SystemModelRuntime = {
223
+ async availability() {
224
+ return { kind: "available" };
225
+ },
226
+ async generate({ messages, generation }, signal) {
227
+ // Throw SystemModelRuntimeError("capability" | "unavailable" | "timeout" | "internal", …)
228
+ // to steer IndeRun error normalization.
229
+ return { text: "…" };
230
+ }
231
+ };
232
+ ```
233
+
234
+ `createFixtureSystemModelRuntime()` provides a deterministic in-memory runtime for tests and
235
+ offline demos.
236
+
51
237
  ## Commands
52
238
 
53
239
  ```sh
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-host.d.ts","sourceRoot":"","sources":["../../src/core/browser-host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACX,YAAY,EACb,MAAM,WAAW,CAAC;AAEnB;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED;;GAEG;AACH,qBAAa,0BAA2B,YAAW,mBAAmB;IACpE;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;CAOnC;AAED;;GAEG;AACH,qBAAa,kBAAmB,YAAW,YAAY;IACrD;;OAEG;IACH,GAAG,IAAI,MAAM;IAIb;;OAEG;IACH,YAAY,IAAI,MAAM;CAOvB;AAED;;GAEG;AACH,qBAAa,eAAgB,YAAW,iBAAiB;IACvD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IAEvC;;;;OAIG;gBACS,OAAO,GAAE,sBAA2B;IAShD;;;;OAIG;IACG,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;CA0CxD;AAED;;GAEG;AACH,MAAM,WAAW,gCAAiC,SAAQ,OAAO,CAAC,YAAY,CAAC;IAC7E;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,gCAAqC,GAC7C,YAAY,CA2Bd"}
@@ -1,5 +1,6 @@
1
1
  import { type TaskRequest, type TaskResult } from "@independo/inderun-contracts";
2
2
  import type { HostServices } from "./host.js";
3
+ import type { ProviderCapabilitySnapshot } from "./provider.js";
3
4
  import { ProviderRegistry } from "./registry.js";
4
5
  import { type TelemetryService } from "./telemetry.js";
5
6
  /**
@@ -38,5 +39,10 @@ export declare class IndeRun {
38
39
  * @throws {IndeRunException} Standardized error indicating validation, connection, or provider failures.
39
40
  */
40
41
  run(request: TaskRequest): Promise<TaskResult>;
42
+ /**
43
+ * Reports each registered provider's static descriptor and current dynamic capability check,
44
+ * without executing a task. Useful for UI that shows live provider availability before a run.
45
+ */
46
+ checkCapabilities(): Promise<ProviderCapabilitySnapshot[]>;
41
47
  }
42
48
  //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/core/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGjD,OAAO,EAAuB,KAAK,gBAAgB,EAAwB,MAAM,gBAAgB,CAAC;AAElG;;;;GAIG;AACH,qBAAa,OAAO;IAWhB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,YAAY;IAXtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAmB;IAE3C;;;;;OAKG;gBAEO,QAAQ,EAAE,gBAAgB,EAC1B,YAAY,EAAE,YAAY,EAClC,gBAAgB,CAAC,EAAE,gBAAgB;IAOrC;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAShB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;;;;;;OAOG;IACG,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAuIpD;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC;CASjE"}
@@ -101,7 +101,9 @@ export class IndeRun {
101
101
  taskKind: request.task.kind,
102
102
  explanation: routeSelection.explanation,
103
103
  constraints: request.constraints ?? null,
104
- preferences: request.preferences ?? null
104
+ preferences: request.preferences ?? null,
105
+ plannerSource: routeSelection.plannerSource,
106
+ plannerUnavailableReason: routeSelection.plannerUnavailableReason ?? null
105
107
  }
106
108
  });
107
109
  // 3. Execute the run task using the planned provider chain
@@ -188,4 +190,15 @@ export class IndeRun {
188
190
  throw exception;
189
191
  }
190
192
  }
193
+ /**
194
+ * Reports each registered provider's static descriptor and current dynamic capability check,
195
+ * without executing a task. Useful for UI that shows live provider availability before a run.
196
+ */
197
+ async checkCapabilities() {
198
+ return Promise.all(this.registry.list().map(async (provider) => ({
199
+ providerId: provider.describe().id,
200
+ descriptor: provider.describe(),
201
+ capabilities: await provider.capabilities(this.hostServices)
202
+ })));
203
+ }
191
204
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEpF;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,UAAU,EAAE,iBAAiB,CAAC;IAC9B;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,qDAAqD;IACrD,QAAQ,CAAC,aAAa,SAAS;IAC/B,sCAAsC;IACtC,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,mCAAmC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,oDAAoD;IACpD,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,gEAAgE;IAChE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAE/B,MAAM,EAAE,sBAAsB;IAa1C;;OAEG;IACH,eAAe,IAAI,YAAY;CAahC;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,YAAY,GAAG,SAAS,CAAC,GAC7D,gBAAgB,CAElB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,YAAY,GAAG,SAAS,CAAC,GAC7D,gBAAgB,CAElB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,YAAY,GAAG,SAAS,CAAC,GAC7D,gBAAgB,CAElB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,YAAY,GAAG,SAAS,CAAC,GAC7D,gBAAgB,CAElB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,YAAY,GAAG,SAAS,CAAC,GAC7D,gBAAgB,CAElB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,YAAY,GAAG,SAAS,CAAC,GAC7D,gBAAgB,CAElB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,YAAY,GAAG,SAAS,CAAC,GAC7D,gBAAgB,CAElB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,EACd,cAAc,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAAE,SAAS,CAAC,CAAC,GAChE,gBAAgB,CAuDlB"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/core/host.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,YAAY,EACZ,mBAAmB,EACnB,wBAAwB,EACxB,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACb,MAAM,8BAA8B,CAAC"}
@@ -83,6 +83,15 @@ export interface ProviderDynamicCapabilities {
83
83
  */
84
84
  reason?: string;
85
85
  }
86
+ /**
87
+ * Snapshot of a registered provider's static descriptor and current dynamic
88
+ * capability check, without executing a task.
89
+ */
90
+ export interface ProviderCapabilitySnapshot {
91
+ providerId: string;
92
+ descriptor: ProviderDescriptor;
93
+ capabilities: ProviderDynamicCapabilities;
94
+ }
86
95
  /**
87
96
  * Execution context passed to provider run commands.
88
97
  */
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/core/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IACjC;;OAEG;IACH,SAAS,EAAE,YAAY,GAAG,gBAAgB,GAAG,MAAM,GAAG,KAAK,GAAG,UAAU,CAAC;IACzE;;OAEG;IACH,cAAc,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;IAEnD;;OAEG;IACH,QAAQ,EAAE;QACR,mEAAmE;QACnE,GAAG,EAAE,OAAO,CAAC;QACb,mDAAmD;QACnD,SAAS,EAAE,OAAO,CAAC;QACnB,6DAA6D;QAC7D,QAAQ,EAAE,OAAO,CAAC;QAClB,6DAA6D;QAC7D,KAAK,EAAE,OAAO,CAAC;QACf,wEAAwE;QACxE,eAAe,EAAE,OAAO,CAAC;QACzB,kFAAkF;QAClF,gBAAgB,EAAE,OAAO,CAAC;QAC1B,6EAA6E;QAC7E,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IAEF;;;;;OAKG;IACH,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAEjC;;OAEG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAEhB;;OAEG;IACH,MAAM,CAAC,EAAE;QACP,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IAEF;;OAEG;IACH,OAAO,CAAC,EAAE;QACR,6DAA6D;QAC7D,gBAAgB,EAAE,OAAO,CAAC;QAC1B,2DAA2D;QAC3D,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,YAAY,EAAE,2BAA2B,CAAC;CAC3C;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,QAAQ,IAAI,kBAAkB,CAAC;IAC/B;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;IACvE;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC7D"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAsC;IAEvD;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAWzC;;;OAGG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAI5C;;OAEG;IACH,IAAI,IAAI,eAAe,EAAE;IAIzB;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd"}
@@ -12,11 +12,28 @@ export interface SharedPlannerModule {
12
12
  planRouteJson: (inputJson: string) => string | Promise<string>;
13
13
  }
14
14
  /**
15
- * Strategy that turns planner input into a deterministic route plan, or `null`
16
- * when the planner is unavailable (callers then fall back to local selection).
15
+ * Coarse, privacy-safe reason the WASM planner produced no route plan. Used
16
+ * only for observability (telemetry/logging) — callers still fall back to
17
+ * local selection regardless of which reason fired.
18
+ */
19
+ export type WasmUnavailableReason = "import_failed" | "invalid_module_shape" | "init_failed" | "plan_failed";
20
+ /**
21
+ * Result of a {@link RoutePlanner} attempt. `routePlan` is `null` when the
22
+ * planner could not produce a plan, in which case `source` is `"unavailable"`
23
+ * and `unavailableReason` narrows down why, so callers can log/emit telemetry
24
+ * instead of silently swapping planners.
25
+ */
26
+ export interface PlannerOutcome {
27
+ routePlan: SharedPlannerRoutePlan | null;
28
+ source: "wasm" | "unavailable";
29
+ unavailableReason?: WasmUnavailableReason;
30
+ }
31
+ /**
32
+ * Strategy that turns planner input into a deterministic route plan, or an
33
+ * "unavailable" outcome (callers then fall back to local selection).
17
34
  */
18
35
  export interface RoutePlanner {
19
- planRoute(input: SharedPlannerInput): Promise<SharedPlannerRoutePlan | null>;
36
+ planRoute(input: SharedPlannerInput): Promise<PlannerOutcome>;
20
37
  }
21
38
  /**
22
39
  * A provider paired with the descriptor/capability projection the shared route
@@ -29,16 +46,22 @@ export interface ProviderRuntimeSnapshot {
29
46
  }
30
47
  /**
31
48
  * {@link RoutePlanner} backed by the Rust route core compiled to WASM. The
32
- * module is imported lazily and memoized; if it cannot be loaded, `planRoute`
33
- * resolves to `null` so the engine can fall back to local selection.
49
+ * module specifier is a static literal (not configurable) so bundlers such as
50
+ * Vite/webpack/Rollup can statically resolve and chunk it — a variable
51
+ * specifier defeats bundler analysis and silently never loads in the browser
52
+ * (see issue #109). The module is imported lazily and memoized; if it cannot
53
+ * be loaded, `planRoute` resolves an "unavailable" outcome so the engine can
54
+ * fall back to local selection, and logs once via `console.warn` so the
55
+ * degradation is never fully silent.
34
56
  */
35
57
  export declare class WasmRoutePlanner implements RoutePlanner {
36
- private readonly moduleSpecifier;
37
58
  private modulePromise?;
38
- constructor(moduleSpecifier?: string);
39
- planRoute(input: SharedPlannerInput): Promise<SharedPlannerRoutePlan | null>;
59
+ private loadFailureReason?;
60
+ private hasWarned;
61
+ planRoute(input: SharedPlannerInput): Promise<PlannerOutcome>;
40
62
  private loadModule;
41
63
  private importModule;
64
+ private warnOnce;
42
65
  }
43
66
  /**
44
67
  * Describes each provider and evaluates its dynamic capabilities against the
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-planner.d.ts","sourceRoot":"","sources":["../../src/core/route-planner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,IAAI,sBAAsB,EACnC,iBAAiB,IAAI,kBAAkB,EACvC,WAAW,EACZ,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,CAAC;AAE3D;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAChE;AAED;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAC/B,eAAe,GAAG,sBAAsB,GAAG,aAAa,GAAG,aAAa,CAAC;AAE3E;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACzC,MAAM,EAAE,MAAM,GAAG,aAAa,CAAC;IAC/B,iBAAiB,CAAC,EAAE,qBAAqB,CAAC;CAC3C;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC/D;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,eAAe,CAAC;IAC1B,UAAU,EAAE,kBAAkB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAClE,YAAY,EAAE,kBAAkB,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;CACvE;AAED;;;;;;;;;GASG;AACH,qBAAa,gBAAiB,YAAW,YAAY;IACnD,OAAO,CAAC,aAAa,CAAC,CAAsC;IAC5D,OAAO,CAAC,iBAAiB,CAAC,CAAwB;IAClD,OAAO,CAAC,SAAS,CAAS;IAEpB,SAAS,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC;YAkBrD,UAAU;YAOV,YAAY;IA6B1B,OAAO,CAAC,QAAQ;CAUjB;AAED;;;GAGG;AACH,wBAAsB,+BAA+B,CACnD,iBAAiB,EAAE,eAAe,EAAE,EACpC,YAAY,EAAE,YAAY,GACzB,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAepC;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,uBAAuB,EAAE,EACpC,aAAa,EAAE,OAAO,GACrB,kBAAkB,CAsBpB"}
@@ -1,23 +1,33 @@
1
- const DEFAULT_WASM_SPECIFIER = "@independo/inderun-route-core-wasm";
2
1
  /**
3
2
  * {@link RoutePlanner} backed by the Rust route core compiled to WASM. The
4
- * module is imported lazily and memoized; if it cannot be loaded, `planRoute`
5
- * resolves to `null` so the engine can fall back to local selection.
3
+ * module specifier is a static literal (not configurable) so bundlers such as
4
+ * Vite/webpack/Rollup can statically resolve and chunk it — a variable
5
+ * specifier defeats bundler analysis and silently never loads in the browser
6
+ * (see issue #109). The module is imported lazily and memoized; if it cannot
7
+ * be loaded, `planRoute` resolves an "unavailable" outcome so the engine can
8
+ * fall back to local selection, and logs once via `console.warn` so the
9
+ * degradation is never fully silent.
6
10
  */
7
11
  export class WasmRoutePlanner {
8
- moduleSpecifier;
9
12
  modulePromise;
10
- constructor(moduleSpecifier = DEFAULT_WASM_SPECIFIER) {
11
- this.moduleSpecifier = moduleSpecifier;
12
- }
13
+ loadFailureReason;
14
+ hasWarned = false;
13
15
  async planRoute(input) {
14
16
  const module = await this.loadModule();
15
17
  if (!module) {
16
- return null;
18
+ const unavailableReason = this.loadFailureReason ?? "import_failed";
19
+ this.warnOnce(unavailableReason);
20
+ return { routePlan: null, source: "unavailable", unavailableReason };
21
+ }
22
+ try {
23
+ const json = JSON.stringify(input);
24
+ const result = await module.planRouteJson(json);
25
+ return { routePlan: JSON.parse(result), source: "wasm" };
26
+ }
27
+ catch (error) {
28
+ this.warnOnce("plan_failed", error);
29
+ return { routePlan: null, source: "unavailable", unavailableReason: "plan_failed" };
17
30
  }
18
- const json = JSON.stringify(input);
19
- const result = await module.planRouteJson(json);
20
- return JSON.parse(result);
21
31
  }
22
32
  async loadModule() {
23
33
  if (!this.modulePromise) {
@@ -26,19 +36,38 @@ export class WasmRoutePlanner {
26
36
  return this.modulePromise;
27
37
  }
28
38
  async importModule() {
39
+ let mod;
29
40
  try {
30
- const mod = (await import(/* @vite-ignore */ this.moduleSpecifier));
31
- if (mod.initSharedCore) {
41
+ mod = (await import("@independo/inderun-route-core-wasm"));
42
+ }
43
+ catch (error) {
44
+ this.loadFailureReason = "import_failed";
45
+ this.warnOnce("import_failed", error);
46
+ return null;
47
+ }
48
+ if (typeof mod.planRouteJson !== "function") {
49
+ this.loadFailureReason = "invalid_module_shape";
50
+ this.warnOnce("invalid_module_shape");
51
+ return null;
52
+ }
53
+ if (mod.initSharedCore) {
54
+ try {
32
55
  await mod.initSharedCore();
33
56
  }
34
- if (typeof mod.planRouteJson !== "function") {
57
+ catch (error) {
58
+ this.loadFailureReason = "init_failed";
59
+ this.warnOnce("init_failed", error);
35
60
  return null;
36
61
  }
37
- return mod;
38
62
  }
39
- catch {
40
- return null;
63
+ return mod;
64
+ }
65
+ warnOnce(reason, error) {
66
+ if (this.hasWarned) {
67
+ return;
41
68
  }
69
+ this.hasWarned = true;
70
+ console.warn(`[IndeRun] WASM route planner unavailable (${reason}); falling back to local route selection.`, error);
42
71
  }
43
72
  }
44
73
  /**
@@ -2,7 +2,7 @@ import type { TaskRequest } from "@independo/inderun-contracts";
2
2
  import type { HostServices } from "./host.js";
3
3
  import type { ProviderAdapter } from "./provider.js";
4
4
  import type { ProviderRegistry } from "./registry.js";
5
- import { type RoutePlanner, type SharedPlannerRoutePlan } from "./route-planner.js";
5
+ import { type RoutePlanner, type SharedPlannerRoutePlan, type WasmUnavailableReason } from "./route-planner.js";
6
6
  /**
7
7
  * Output structure from the Router containing the chosen provider and a route selection description.
8
8
  */
@@ -23,6 +23,16 @@ export interface RouteSelection {
23
23
  * Explanation detailing the selection decision. Useful for debugging and telemetry.
24
24
  */
25
25
  explanation: string;
26
+ /**
27
+ * Which planner produced `routePlan`: the shared Rust/WASM core, or the
28
+ * local TypeScript fallback used when the WASM planner is unavailable.
29
+ */
30
+ plannerSource: "wasm" | "fallback";
31
+ /**
32
+ * Set when `plannerSource` is `"fallback"` because the WASM planner failed;
33
+ * `undefined` when the fallback was not caused by a planner failure.
34
+ */
35
+ plannerUnavailableReason?: WasmUnavailableReason;
26
36
  }
27
37
  /**
28
38
  * Routing engine module. Filters registered providers against task types, request constraints,
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/core/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,EAC3B,KAAK,qBAAqB,EAE3B,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;IACpB;;;OAGG;IACH,aAAa,EAAE,MAAM,GAAG,UAAU,CAAC;IACnC;;;OAGG;IACH,wBAAwB,CAAC,EAAE,qBAAqB,CAAC;CAClD;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;IAc3B,OAAO,CAAC,2BAA2B;IA2BnC,OAAO,CAAC,kBAAkB;IA0F1B,OAAO,CAAC,2BAA2B;IAiCnC,OAAO,CAAC,gBAAgB;CAYzB"}
@@ -26,26 +26,26 @@ export class Router {
26
26
  const online = await hostServices.connectivity.isOnline();
27
27
  const snapshots = await collectProviderRuntimeSnapshots(this.registry.list(), hostServices);
28
28
  const planInput = buildSharedPlannerInput(request, snapshots, online);
29
- const routePlan = await this.planner.planRoute(planInput);
30
- if (routePlan) {
31
- return this.selectFromSharedPlan(snapshots, routePlan);
29
+ const outcome = await this.planner.planRoute(planInput);
30
+ if (outcome.routePlan) {
31
+ return this.selectFromSharedPlan(snapshots, outcome.routePlan);
32
32
  }
33
- return this.selectFallbackRoute(request, snapshots, online);
33
+ return this.selectFallbackRoute(request, snapshots, online, outcome.unavailableReason);
34
34
  }
35
35
  selectFromSharedPlan(snapshots, routePlan) {
36
36
  if (!routePlan.selectedProviderId) {
37
37
  throw this.routePlanFailure(routePlan);
38
38
  }
39
- return this.buildSelectionFromRoutePlan(snapshots, routePlan);
39
+ return this.buildSelectionFromRoutePlan(snapshots, routePlan, "wasm");
40
40
  }
41
- selectFallbackRoute(request, snapshots, online) {
41
+ selectFallbackRoute(request, snapshots, online, plannerUnavailableReason) {
42
42
  const plan = this.createFallbackPlan(request, snapshots, online);
43
43
  if (!plan.selectedProviderId) {
44
44
  throw this.routePlanFailure(plan);
45
45
  }
46
- return this.buildSelectionFromRoutePlan(snapshots, plan);
46
+ return this.buildSelectionFromRoutePlan(snapshots, plan, "fallback", plannerUnavailableReason);
47
47
  }
48
- buildSelectionFromRoutePlan(snapshots, routePlan) {
48
+ buildSelectionFromRoutePlan(snapshots, routePlan, plannerSource, plannerUnavailableReason) {
49
49
  const orderedProviders = routePlan.candidates
50
50
  .map((candidate) => snapshots.find((snapshot) => snapshot.descriptor.id === candidate.providerId))
51
51
  .filter((snapshot) => snapshot !== undefined);
@@ -57,7 +57,9 @@ export class Router {
57
57
  provider: selected.provider,
58
58
  fallbackProviders: orderedProviders.slice(1).map((snapshot) => snapshot.provider),
59
59
  routePlan,
60
- explanation: routePlan.explanation.summary
60
+ explanation: routePlan.explanation.summary,
61
+ plannerSource,
62
+ ...(plannerUnavailableReason ? { plannerUnavailableReason } : {})
61
63
  };
62
64
  }
63
65
  createFallbackPlan(request, snapshots, online) {
@@ -67,17 +69,24 @@ export class Router {
67
69
  .filter((candidate) => candidate.descriptor.supports.run);
68
70
  const localCandidates = eligible.filter((candidate) => candidate.descriptor.type !== "cloud");
69
71
  const cloudCandidates = eligible.filter((candidate) => candidate.descriptor.type === "cloud");
70
- const selected = eligible.find((candidate) => {
72
+ // Constraint filtering must apply to the whole candidate list, not just the selected provider:
73
+ // the remainder becomes the engine's fallback chain, and a fallback that violates the request
74
+ // constraints would let a `local_required` run be retried against a cloud provider.
75
+ const admissible = eligible.filter((candidate) => {
71
76
  const descriptor = candidate.descriptor;
72
77
  const constraints = planInput.constraints;
73
- const privacy = descriptor.privacy?.dataLeavesDevice ?? descriptor.type !== "cloud";
78
+ // Mirrors `is_data_private` in the shared Rust planner: a provider is private when it
79
+ // declares that data does not leave the device, defaulting to non-cloud providers.
80
+ const isDataPrivate = descriptor.privacy
81
+ ? !descriptor.privacy.dataLeavesDevice
82
+ : descriptor.type !== "cloud";
74
83
  if (constraints.cloud === "forbidden" && descriptor.type === "cloud") {
75
84
  return false;
76
85
  }
77
86
  if (constraints.cloud === "required" && descriptor.type !== "cloud") {
78
87
  return false;
79
88
  }
80
- if (constraints.privacy === "local_required" && !privacy) {
89
+ if (constraints.privacy === "local_required" && !isDataPrivate) {
81
90
  return false;
82
91
  }
83
92
  if (constraints.privacy === "cloud_required" && descriptor.type !== "cloud") {
@@ -88,10 +97,7 @@ export class Router {
88
97
  }
89
98
  return candidate.capabilities.available;
90
99
  });
91
- const ordered = selected
92
- ? [selected, ...eligible.filter((candidate) => candidate !== selected)]
93
- : [];
94
- if (ordered.length === 0) {
100
+ if (admissible.length === 0) {
95
101
  const failureSummary = this.buildFallbackFailureSummary({
96
102
  online,
97
103
  constraints: planInput.constraints,
@@ -114,17 +120,17 @@ export class Router {
114
120
  }
115
121
  };
116
122
  }
117
- const selectedProviderId = ordered[0]?.descriptor.id;
123
+ const selectedProviderId = admissible[0]?.descriptor.id;
118
124
  return {
119
125
  selectedProviderId,
120
- fallbackProviderIds: ordered.slice(1).map((candidate) => candidate.descriptor.id),
121
- candidates: ordered.map((candidate, index) => ({
126
+ fallbackProviderIds: admissible.slice(1).map((candidate) => candidate.descriptor.id),
127
+ candidates: admissible.map((candidate, index) => ({
122
128
  providerId: candidate.descriptor.id,
123
129
  order: index
124
130
  })),
125
131
  rejectedProviders: [],
126
132
  explanation: {
127
- summary: `Selected provider '${selectedProviderId}' deterministically from ${ordered.length} eligible candidate(s).`,
133
+ summary: `Selected provider '${selectedProviderId}' deterministically from ${admissible.length} eligible candidate(s).`,
128
134
  selectedProviderId
129
135
  }
130
136
  };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../src/core/telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAErF,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AAEtC;;GAEG;AACH,qBAAa,oBAAqB,YAAW,gBAAgB;IAC3D;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;CAGnC"}
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- export { type ConnectivityService, type DeviceConstraintsService, type SecureStorageService, type ClockService, type HttpClientService, type HttpRequest, type HttpResponse, type HostServices, type ThermalState } from "./host.js";
2
- export { type ProviderDescriptor, type ProviderDynamicCapabilities, type RunContext, type ProviderAdapter } from "./provider.js";
3
- export { ProviderRegistry } from "./registry.js";
4
- export { type RouteSelection, Router } from "./router.js";
5
- export { type RoutePlanner, type SharedPlannerInput, type SharedPlannerRoutePlan, WasmRoutePlanner } from "./route-planner.js";
6
- export { type IndeRunExceptionParams, IndeRunException, createCapabilityMismatch, createOffline, createAuthError, createRateLimited, createTimeout, createUnavailable, createInternal, toIndeRunException } from "./errors.js";
7
- export { IndeRun } from "./engine.js";
8
- export { type TelemetryEventType, type TelemetryEvent, type TelemetryService, NoOpTelemetryService } from "./telemetry.js";
9
- export { BrowserConnectivityService, FetchHttpClient, SystemClockService, createBrowserHostServices, type CreateBrowserHostServicesOptions, type FetchHttpClientOptions } from "./browser-host.js";
1
+ export { type ConnectivityService, type DeviceConstraintsService, type SecureStorageService, type ClockService, type HttpClientService, type HttpRequest, type HttpResponse, type HostServices, type ThermalState } from "./core/host.js";
2
+ export { type ProviderDescriptor, type ProviderDynamicCapabilities, type ProviderCapabilitySnapshot, type RunContext, type ProviderAdapter } from "./core/provider.js";
3
+ export { ProviderRegistry } from "./core/registry.js";
4
+ export { type RouteSelection, Router } from "./core/router.js";
5
+ export { type RoutePlanner, type PlannerOutcome, type WasmUnavailableReason, type SharedPlannerInput, type SharedPlannerRoutePlan, WasmRoutePlanner } from "./core/route-planner.js";
6
+ export { type IndeRunExceptionParams, IndeRunException, createCapabilityMismatch, createOffline, createAuthError, createRateLimited, createTimeout, createUnavailable, createInternal, toIndeRunException } from "./core/errors.js";
7
+ export { IndeRun } from "./core/engine.js";
8
+ export { type TelemetryEventType, type TelemetryEvent, type TelemetryService, NoOpTelemetryService } from "./core/telemetry.js";
9
+ export { BrowserConnectivityService, FetchHttpClient, SystemClockService, createBrowserHostServices, type CreateBrowserHostServicesOptions, type FetchHttpClientOptions } from "./core/browser-host.js";
10
10
  export { createIndeRunWeb, type CreateIndeRunWebOptions } from "./web-sdk.js";
11
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,YAAY,EAClB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAChC,KAAK,UAAU,EACf,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,KAAK,sBAAsB,EAC3B,gBAAgB,EAChB,wBAAwB,EACxB,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,oBAAoB,EACrB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,0BAA0B,EAC1B,eAAe,EACf,kBAAkB,EAClB,yBAAyB,EACzB,KAAK,gCAAgC,EACrC,KAAK,sBAAsB,EAC5B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,UAAU,EACf,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,gBAAgB,EACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,KAAK,sBAAsB,EAC3B,gBAAgB,EAChB,wBAAwB,EACxB,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EACnB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,oBAAoB,EACrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,0BAA0B,EAC1B,eAAe,EACf,kBAAkB,EAClB,yBAAyB,EACzB,KAAK,gCAAgC,EACrC,KAAK,sBAAsB,EAC5B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,cAAc,CAAC"}