@independo/inderun-web 0.3.0-dev.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +12 -10
  2. package/dist/core/engine.d.ts +11 -0
  3. package/dist/core/engine.d.ts.map +1 -1
  4. package/dist/core/engine.js +38 -42
  5. package/dist/core/route-planner.d.ts +16 -13
  6. package/dist/core/route-planner.d.ts.map +1 -1
  7. package/dist/core/route-planner.js +22 -19
  8. package/dist/core/router.d.ts +1 -39
  9. package/dist/core/router.d.ts.map +1 -1
  10. package/dist/core/router.js +12 -206
  11. package/dist/index.d.ts +63 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +47 -2
  14. package/dist/onnx.d.ts +21 -0
  15. package/dist/onnx.d.ts.map +1 -1
  16. package/dist/onnx.js +15 -0
  17. package/dist/openai.d.ts +7 -0
  18. package/dist/openai.d.ts.map +1 -1
  19. package/dist/openai.js +7 -0
  20. package/dist/system-model.d.ts +13 -0
  21. package/dist/system-model.d.ts.map +1 -1
  22. package/dist/system-model.js +13 -0
  23. package/package.json +22 -8
  24. package/src/core/browser-host.ts +339 -0
  25. package/src/core/engine.ts +540 -0
  26. package/src/core/errors.ts +220 -0
  27. package/src/core/event-gate.ts +71 -0
  28. package/src/core/generated/inderun-api.ts +19 -0
  29. package/src/core/host.ts +15 -0
  30. package/src/core/provider.ts +231 -0
  31. package/src/core/registry.ts +48 -0
  32. package/src/core/route-planner.ts +261 -0
  33. package/src/core/router.ts +149 -0
  34. package/src/core/sse.ts +134 -0
  35. package/src/core/telemetry.ts +20 -0
  36. package/src/index.ts +147 -0
  37. package/src/onnx.ts +57 -0
  38. package/src/openai.ts +21 -0
  39. package/src/providers/onnx/provider.ts +300 -0
  40. package/src/providers/onnx/runtime.ts +188 -0
  41. package/src/providers/onnx/transformers-runtime.ts +345 -0
  42. package/src/providers/openai/provider.ts +765 -0
  43. package/src/providers/system-model/chrome-runtime.ts +221 -0
  44. package/src/providers/system-model/provider.ts +260 -0
  45. package/src/providers/system-model/runtime.ts +202 -0
  46. package/src/system-model.ts +49 -0
  47. package/src/web-sdk.ts +114 -0
package/README.md CHANGED
@@ -2,14 +2,16 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/@independo/inderun-web?logo=npm)](https://www.npmjs.com/package/@independo/inderun-web)
4
4
 
5
- > Part of **[IndeRun](https://github.com/independo-gmbh/inderun)** — an open-source AI execution
6
- > framework that gives applications one unified API for running tasks across on-device, edge, and
7
- > cloud providers. New here? Start with the [IndeRun README](https://github.com/independo-gmbh/inderun#readme).
5
+ > Part of **[IndeRun](https://github.com/independo-gmbh/inderun)** — on-device AI with automatic
6
+ > cloud fallback, for cross-platform apps. New here? Start with the
7
+ > [IndeRun README](https://github.com/independo-gmbh/inderun#readme).
8
8
 
9
9
  TypeScript/Web SDK for IndeRun.
10
10
 
11
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
+ The contract types this SDK's own signatures take and return — `TaskRequest`, `TaskResult`, `StreamEvent`, `StreamRunHandle`, `StreamTerminalOutcome`, `IndeRunError`, the host-service and telemetry interfaces, and (from the `/onnx` subpath) `ModelPackage` — are re-exported here, so a fully typed app does not need to depend on `@independo/inderun-contracts` separately. Import that package directly only if you want the JSON Schemas or the `get*ValidationIssues` validators.
14
+
13
15
  ## Basic Usage
14
16
 
15
17
  ```ts
@@ -47,14 +49,14 @@ for await (const event of events) {
47
49
  }
48
50
  ```
49
51
 
50
- Order by `event.sequence`, not by arrival: it is the ordering authority for a run. Treat an
51
- unrecognized `event.type` as ignore-or-pass-through — the set is open and additive. Exactly one
52
- `terminal` event is produced per run, and `cancel()` is idempotent.
52
+ Streaming over the network needs a host that can deliver a response body incrementally.
53
+ `createBrowserHostServices` provides one; a custom host without a `streamingHttpClient` still runs
54
+ Mode 1, and a stream request is refused at routing time with a `streaming_unavailable` reason rather
55
+ than failing later.
53
56
 
54
- Streaming needs a host that can deliver a response body incrementally.
55
- `createBrowserHostServices` provides one; a custom host without a
56
- `streamingHttpClient` still runs Mode 1, and a stream request is refused at routing
57
- time with a `streaming_unavailable` reason rather than failing later.
57
+ Event types, ordering, the terminal guarantees, cancellation, and fallback are identical on every
58
+ SDK and documented once, in
59
+ [Streaming (Mode 2)](https://github.com/independo-gmbh/inderun/blob/main/docs/streaming.md).
58
60
 
59
61
  ### Custom OpenAI-compatible endpoints
60
62
 
@@ -27,6 +27,17 @@ export declare class IndeRun implements IndeRunApi {
27
27
  * @param telemetryService - Optional custom telemetry service listener.
28
28
  */
29
29
  constructor(registry: ProviderRegistry, hostServices: HostServices, telemetryService?: TelemetryService);
30
+ /**
31
+ * Current time from the host clock, falling back to wall-clock time when the
32
+ * host does not supply one.
33
+ */
34
+ private now;
35
+ /**
36
+ * Emits `route_decided` for a completed route selection. Shared by `run()` and
37
+ * `stream()`: the payload is identical for both modes, and the interaction
38
+ * mode is already reflected in the plan the router returned.
39
+ */
40
+ private emitRouteDecided;
30
41
  /**
31
42
  * Safely emits a telemetry event by swallowing any internal logging/telemetry system errors.
32
43
  * @param event - The telemetry event to emit.
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/core/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EAAmB,0BAA0B,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC5F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAQjD,OAAO,EAAuB,KAAK,gBAAgB,EAAwB,MAAM,gBAAgB,CAAC;AAGlG;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAE3C;;;;GAIG;AACH,qBAAa,OAAQ,YAAW,UAAU;IAWtC,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;;;;;;;;;;;;;;;;;OAiBG;IACG,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC;IA+QtD;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC;CASjE"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/core/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,KAAK,EAAmB,0BAA0B,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC5F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAQjD,OAAO,EAAuB,KAAK,gBAAgB,EAAwB,MAAM,gBAAgB,CAAC;AAGlG;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAE3C;;;;GAIG;AACH,qBAAa,OAAQ,YAAW,UAAU;IAWtC,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,GAAG;IAIX;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAuBxB;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAShB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;;;;;;OAOG;IACG,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAsHpD;;;;;;;;;;;;;;;;;OAiBG;IACG,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC;IA+PtD;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC;CASjE"}
@@ -27,6 +27,35 @@ export class IndeRun {
27
27
  this.telemetryService =
28
28
  telemetryService || this.hostServices.telemetry || new NoOpTelemetryService();
29
29
  }
30
+ /**
31
+ * Current time from the host clock, falling back to wall-clock time when the
32
+ * host does not supply one.
33
+ */
34
+ now() {
35
+ return this.hostServices.clock ? this.hostServices.clock.now() : Date.now();
36
+ }
37
+ /**
38
+ * Emits `route_decided` for a completed route selection. Shared by `run()` and
39
+ * `stream()`: the payload is identical for both modes, and the interaction
40
+ * mode is already reflected in the plan the router returned.
41
+ */
42
+ emitRouteDecided(runId, request, routeSelection, providerCount) {
43
+ this.safeEmit({
44
+ type: "route_decided",
45
+ runId,
46
+ timestamp: this.now(),
47
+ payload: {
48
+ selectedProviderId: routeSelection.routePlan.selectedProviderId,
49
+ fallbackProviderIds: routeSelection.routePlan.fallbackProviderIds,
50
+ rejectedProviders: routeSelection.routePlan.rejectedProviders,
51
+ fallbackAvailable: providerCount > 1,
52
+ taskKind: request.task.kind,
53
+ constraints: request.constraints ?? null,
54
+ preferences: request.preferences ?? null,
55
+ explanation: routeSelection.explanation
56
+ }
57
+ });
58
+ }
30
59
  /**
31
60
  * Safely emits a telemetry event by swallowing any internal logging/telemetry system errors.
32
61
  * @param event - The telemetry event to emit.
@@ -72,7 +101,7 @@ export class IndeRun {
72
101
  * @throws {IndeRunException} Standardized error indicating validation, connection, or provider failures.
73
102
  */
74
103
  async run(request) {
75
- const startTime = this.hostServices.clock ? this.hostServices.clock.now() : Date.now();
104
+ const startTime = this.now();
76
105
  const runId = request.requestId || `run_${Math.random().toString(36).substring(2, 11)}`;
77
106
  try {
78
107
  // 1. Validate request payload using schema contracts
@@ -89,24 +118,7 @@ export class IndeRun {
89
118
  // 2. Select the route based on constraints and host capabilities
90
119
  const routeSelection = await this.router.selectRoute(request, this.hostServices, "run");
91
120
  const providers = [routeSelection.provider, ...routeSelection.fallbackProviders];
92
- // Emit route_decided event
93
- this.safeEmit({
94
- type: "route_decided",
95
- runId,
96
- timestamp: this.hostServices.clock ? this.hostServices.clock.now() : Date.now(),
97
- payload: {
98
- selectedProviderId: routeSelection.routePlan.selectedProviderId,
99
- fallbackProviderIds: routeSelection.routePlan.fallbackProviderIds,
100
- rejectedProviders: routeSelection.routePlan.rejectedProviders,
101
- fallbackAvailable: providers.length > 1,
102
- taskKind: request.task.kind,
103
- explanation: routeSelection.explanation,
104
- constraints: request.constraints ?? null,
105
- preferences: request.preferences ?? null,
106
- plannerSource: routeSelection.plannerSource,
107
- plannerUnavailableReason: routeSelection.plannerUnavailableReason ?? null
108
- }
109
- });
121
+ this.emitRouteDecided(runId, request, routeSelection, providers.length);
110
122
  // 3. Execute the run task using the planned provider chain
111
123
  const attemptedProviderIds = [];
112
124
  let lastError;
@@ -118,7 +130,7 @@ export class IndeRun {
118
130
  runId,
119
131
  hostServices: this.hostServices
120
132
  });
121
- const endTime = this.hostServices.clock ? this.hostServices.clock.now() : Date.now();
133
+ const endTime = this.now();
122
134
  const totalMs = endTime - startTime;
123
135
  result.runId = runId;
124
136
  result.telemetry = {
@@ -151,7 +163,7 @@ export class IndeRun {
151
163
  });
152
164
  }
153
165
  }
154
- const endTime = this.hostServices.clock ? this.hostServices.clock.now() : Date.now();
166
+ const endTime = this.now();
155
167
  const totalMs = endTime - startTime;
156
168
  const exception = toIndeRunException(lastError ?? new Error("No providers were attempted."), {
157
169
  runId,
@@ -170,10 +182,10 @@ export class IndeRun {
170
182
  details: {
171
183
  totalMs: typeof error.details?.totalMs === "number"
172
184
  ? error.details?.totalMs
173
- : (this.hostServices.clock ? this.hostServices.clock.now() : Date.now()) - startTime
185
+ : this.now() - startTime
174
186
  }
175
187
  });
176
- const endTime = this.hostServices.clock ? this.hostServices.clock.now() : Date.now();
188
+ const endTime = this.now();
177
189
  const totalMs = typeof exception.details?.totalMs === "number"
178
190
  ? exception.details?.totalMs
179
191
  : endTime - startTime;
@@ -210,8 +222,8 @@ export class IndeRun {
210
222
  * @throws {IndeRunException} If validation fails or no eligible streaming provider exists.
211
223
  */
212
224
  async stream(request) {
213
- const startTime = this.hostServices.clock ? this.hostServices.clock.now() : Date.now();
214
- const now = () => (this.hostServices.clock ? this.hostServices.clock.now() : Date.now());
225
+ const startTime = this.now();
226
+ const now = () => this.now();
215
227
  const runId = request.requestId || `run_${Math.random().toString(36).substring(2, 11)}`;
216
228
  const validationIssues = getTaskRequestValidationIssues(request);
217
229
  if (validationIssues.length > 0) {
@@ -231,23 +243,7 @@ export class IndeRun {
231
243
  throw toIndeRunException(error, { runId });
232
244
  }
233
245
  const providers = [routeSelection.provider, ...routeSelection.fallbackProviders];
234
- this.safeEmit({
235
- type: "route_decided",
236
- runId,
237
- timestamp: now(),
238
- payload: {
239
- selectedProviderId: routeSelection.routePlan.selectedProviderId,
240
- fallbackProviderIds: routeSelection.routePlan.fallbackProviderIds,
241
- rejectedProviders: routeSelection.routePlan.rejectedProviders,
242
- fallbackAvailable: providers.length > 1,
243
- taskKind: request.task.kind,
244
- explanation: routeSelection.explanation,
245
- constraints: request.constraints ?? null,
246
- preferences: request.preferences ?? null,
247
- plannerSource: routeSelection.plannerSource,
248
- plannerUnavailableReason: routeSelection.plannerUnavailableReason ?? null
249
- }
250
- });
246
+ this.emitRouteDecided(runId, request, routeSelection, providers.length);
251
247
  // Defensive only: streaming eligibility is decided by the route planner, which
252
248
  // throws with its own rejection reasons when nothing can stream. Reaching here
253
249
  // means a planned provider was unregistered between planning and selection.
@@ -17,25 +17,23 @@ export interface SharedPlannerModule {
17
17
  planRouteJson: (inputJson: string) => string | Promise<string>;
18
18
  }
19
19
  /**
20
- * Coarse, privacy-safe reason the WASM planner produced no route plan. Used
21
- * only for observability (telemetry/logging) — callers still fall back to
22
- * local selection regardless of which reason fired.
20
+ * Coarse, privacy-safe reason the WASM planner produced no route plan. Surfaced
21
+ * on the resulting `Internal` routing error and in the `console.warn`, so an
22
+ * operator can tell a missing bundle chunk from a blocked instantiation.
23
23
  */
24
24
  export type WasmUnavailableReason = "import_failed" | "invalid_module_shape" | "init_failed" | "plan_failed";
25
25
  /**
26
26
  * Result of a {@link RoutePlanner} attempt. `routePlan` is `null` when the
27
- * planner could not produce a plan, in which case `source` is `"unavailable"`
28
- * and `unavailableReason` narrows down why, so callers can log/emit telemetry
29
- * instead of silently swapping planners.
27
+ * planner could not produce a plan, and `unavailableReason` then narrows down
28
+ * why.
30
29
  */
31
30
  export interface PlannerOutcome {
32
31
  routePlan: SharedPlannerRoutePlan | null;
33
- source: "wasm" | "unavailable";
34
32
  unavailableReason?: WasmUnavailableReason;
35
33
  }
36
34
  /**
37
35
  * Strategy that turns planner input into a deterministic route plan, or an
38
- * "unavailable" outcome (callers then fall back to local selection).
36
+ * "unavailable" outcome (which the router reports as a routing failure).
39
37
  */
40
38
  export interface RoutePlanner {
41
39
  planRoute(input: SharedPlannerInput): Promise<PlannerOutcome>;
@@ -55,13 +53,14 @@ export interface ProviderRuntimeSnapshot {
55
53
  * Vite/webpack/Rollup can statically resolve and chunk it — a variable
56
54
  * specifier defeats bundler analysis and silently never loads in the browser
57
55
  * (see issue #109). The module is imported lazily and memoized; if it cannot
58
- * be loaded, `planRoute` resolves an "unavailable" outcome so the engine can
59
- * fall back to local selection, and logs once via `console.warn` so the
60
- * degradation is never fully silent.
56
+ * be loaded, `planRoute` resolves an "unavailable" outcome, which the engine
57
+ * turns into an `Internal` routing failure carrying the reason below. There is
58
+ * no second planner to degrade to — a failure here is a failure to route, not a
59
+ * quieter route — so this also logs once via `console.warn` to name the cause.
61
60
  */
62
61
  export declare class WasmRoutePlanner implements RoutePlanner {
63
62
  private modulePromise?;
64
- private loadFailureReason?;
63
+ private loadFailure?;
65
64
  private hasWarned;
66
65
  planRoute(input: SharedPlannerInput): Promise<PlannerOutcome>;
67
66
  private loadModule;
@@ -70,7 +69,11 @@ export declare class WasmRoutePlanner implements RoutePlanner {
70
69
  }
71
70
  /**
72
71
  * Describes each provider and evaluates its dynamic capabilities against the
73
- * host, returning snapshots sorted by provider id for deterministic planning.
72
+ * host.
73
+ *
74
+ * Registration order is passed through untouched: the shared planner ranks
75
+ * candidates itself and tie-breaks by provider id, so sorting here would only
76
+ * assert an ordering the planner is free to ignore.
74
77
  */
75
78
  export declare function collectProviderRuntimeSnapshots(registryProviders: ProviderAdapter[], hostServices: HostServices): Promise<ProviderRuntimeSnapshot[]>;
76
79
  /**
@@ -1 +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;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,kBAAkB,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAEjF;;;;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,EACtB,eAAe,GAAE,eAAuB,GACvC,kBAAkB,CAuBpB"}
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;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,kBAAkB,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAEjF;;;;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;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACzC,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;;;;;;;;;;GAUG;AACH,qBAAa,gBAAiB,YAAW,YAAY;IACnD,OAAO,CAAC,aAAa,CAAC,CAAsC;IAC5D,OAAO,CAAC,WAAW,CAAC,CAAqD;IACzE,OAAO,CAAC,SAAS,CAAS;IAEpB,SAAS,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC;YAoBrD,UAAU;YAOV,YAAY;IA0B1B,OAAO,CAAC,QAAQ;CAOjB;AAED;;;;;;;GAOG;AACH,wBAAsB,+BAA+B,CACnD,iBAAiB,EAAE,eAAe,EAAE,EACpC,YAAY,EAAE,YAAY,GACzB,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAapC;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,uBAAuB,EAAE,EACpC,aAAa,EAAE,OAAO,EACtB,eAAe,GAAE,eAAuB,GACvC,kBAAkB,CAuBpB"}
@@ -4,29 +4,32 @@
4
4
  * Vite/webpack/Rollup can statically resolve and chunk it — a variable
5
5
  * specifier defeats bundler analysis and silently never loads in the browser
6
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.
7
+ * be loaded, `planRoute` resolves an "unavailable" outcome, which the engine
8
+ * turns into an `Internal` routing failure carrying the reason below. There is
9
+ * no second planner to degrade to — a failure here is a failure to route, not a
10
+ * quieter route — so this also logs once via `console.warn` to name the cause.
10
11
  */
11
12
  export class WasmRoutePlanner {
12
13
  modulePromise;
13
- loadFailureReason;
14
+ loadFailure;
14
15
  hasWarned = false;
15
16
  async planRoute(input) {
16
17
  const module = await this.loadModule();
17
18
  if (!module) {
18
- const unavailableReason = this.loadFailureReason ?? "import_failed";
19
- this.warnOnce(unavailableReason);
20
- return { routePlan: null, source: "unavailable", unavailableReason };
19
+ // The load path only records why it failed; warning here covers both the
20
+ // first attempt and every later call served from the memoized promise.
21
+ const unavailableReason = this.loadFailure?.reason ?? "import_failed";
22
+ this.warnOnce(unavailableReason, this.loadFailure?.error);
23
+ return { routePlan: null, unavailableReason };
21
24
  }
22
25
  try {
23
26
  const json = JSON.stringify(input);
24
27
  const result = await module.planRouteJson(json);
25
- return { routePlan: JSON.parse(result), source: "wasm" };
28
+ return { routePlan: JSON.parse(result) };
26
29
  }
27
30
  catch (error) {
28
31
  this.warnOnce("plan_failed", error);
29
- return { routePlan: null, source: "unavailable", unavailableReason: "plan_failed" };
32
+ return { routePlan: null, unavailableReason: "plan_failed" };
30
33
  }
31
34
  }
32
35
  async loadModule() {
@@ -41,13 +44,11 @@ export class WasmRoutePlanner {
41
44
  mod = (await import("@independo/inderun-route-core-wasm"));
42
45
  }
43
46
  catch (error) {
44
- this.loadFailureReason = "import_failed";
45
- this.warnOnce("import_failed", error);
47
+ this.loadFailure = { reason: "import_failed", error };
46
48
  return null;
47
49
  }
48
50
  if (typeof mod.planRouteJson !== "function") {
49
- this.loadFailureReason = "invalid_module_shape";
50
- this.warnOnce("invalid_module_shape");
51
+ this.loadFailure = { reason: "invalid_module_shape" };
51
52
  return null;
52
53
  }
53
54
  if (mod.initSharedCore) {
@@ -55,8 +56,7 @@ export class WasmRoutePlanner {
55
56
  await mod.initSharedCore();
56
57
  }
57
58
  catch (error) {
58
- this.loadFailureReason = "init_failed";
59
- this.warnOnce("init_failed", error);
59
+ this.loadFailure = { reason: "init_failed", error };
60
60
  return null;
61
61
  }
62
62
  }
@@ -67,15 +67,19 @@ export class WasmRoutePlanner {
67
67
  return;
68
68
  }
69
69
  this.hasWarned = true;
70
- console.warn(`[IndeRun] WASM route planner unavailable (${reason}); falling back to local route selection.`, error);
70
+ console.warn(`[IndeRun] WASM route planner unavailable (${reason}); routing will fail.`, error);
71
71
  }
72
72
  }
73
73
  /**
74
74
  * Describes each provider and evaluates its dynamic capabilities against the
75
- * host, returning snapshots sorted by provider id for deterministic planning.
75
+ * host.
76
+ *
77
+ * Registration order is passed through untouched: the shared planner ranks
78
+ * candidates itself and tie-breaks by provider id, so sorting here would only
79
+ * assert an ordering the planner is free to ignore.
76
80
  */
77
81
  export async function collectProviderRuntimeSnapshots(registryProviders, hostServices) {
78
- const snapshots = await Promise.all(registryProviders.map(async (provider) => {
82
+ return Promise.all(registryProviders.map(async (provider) => {
79
83
  const descriptor = provider.describe();
80
84
  const capabilities = await provider.capabilities(hostServices);
81
85
  return {
@@ -84,7 +88,6 @@ export async function collectProviderRuntimeSnapshots(registryProviders, hostSer
84
88
  capabilities: toSharedPlannerCapabilities(capabilities, descriptor, provider)
85
89
  };
86
90
  }));
87
- return snapshots.sort((left, right) => left.descriptor.id.localeCompare(right.descriptor.id));
88
91
  }
89
92
  /**
90
93
  * Assembles the normalized {@link SharedPlannerInput} the shared route core
@@ -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 InteractionMode, type RoutePlanner, type SharedPlannerRoutePlan, type WasmUnavailableReason } from "./route-planner.js";
5
+ import { type InteractionMode, type RoutePlanner, type SharedPlannerRoutePlan } 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,16 +23,6 @@ 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;
36
26
  }
37
27
  /**
38
28
  * Routing engine module. Filters registered providers against task types, request constraints,
@@ -59,35 +49,7 @@ export declare class Router {
59
49
  */
60
50
  selectRoute(request: TaskRequest, hostServices: HostServices, interactionMode?: InteractionMode): Promise<RouteSelection>;
61
51
  private selectFromSharedPlan;
62
- private selectFallbackRoute;
63
52
  private buildSelectionFromRoutePlan;
64
- /**
65
- * Hand-written mirror of the shared Rust planner (`rust/inderun-route-core/src/planner.rs`),
66
- * used when the WASM core cannot be loaded. It reproduces the same rejection
67
- * codes and messages so route explanations stay comparable across both paths.
68
- *
69
- * Known, deliberate divergence: this mirror keeps the id-sorted snapshot order
70
- * instead of reproducing the Rust placement/preference ranks, so `optimizeFor`
71
- * does not influence ordering here.
72
- */
73
- private createFallbackPlan;
74
- /**
75
- * Mirrors `infer_failure_code` in the shared Rust planner. The offline class is
76
- * derived from the rejection reasons rather than from the connectivity flag
77
- * alone: an offline host whose only provider is local and non-streaming failed
78
- * on capability, not on connectivity, and reporting `Offline` there would
79
- * contradict the explanation shipped alongside it.
80
- */
81
- private inferFallbackFailureCode;
82
- /**
83
- * Mirrors `evaluate_provider` in the shared Rust planner: it accumulates every
84
- * violated rule rather than short-circuiting, so a rejected provider carries a
85
- * complete explanation. The streaming checks are ordered static-before-dynamic
86
- * for the same reason as in Rust — a provider that never declared streaming
87
- * must not also be reported as dynamically unavailable.
88
- */
89
- private evaluateFallbackCandidate;
90
- private buildFallbackFailureSummary;
91
53
  /**
92
54
  * Routing failure throws before any `route_decided` telemetry is emitted, so the
93
55
  * plan's diagnostics are attached to the exception — that is the only channel
@@ -1 +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,EAGL,KAAK,eAAe,EAEpB,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;;;;;;;;;;;;;OAaG;IACG,WAAW,CACf,OAAO,EAAE,WAAW,EACpB,YAAY,EAAE,YAAY,EAC1B,eAAe,GAAE,eAAuB,GACvC,OAAO,CAAC,cAAc,CAAC;IAoB1B,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,mBAAmB;IAe3B,OAAO,CAAC,2BAA2B;IA2BnC;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAwE1B;;;;;;OAMG;IACH,OAAO,CAAC,wBAAwB;IAsBhC;;;;;;OAMG;IACH,OAAO,CAAC,yBAAyB;IA4FjC,OAAO,CAAC,2BAA2B;IAyCnC;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;CAkBzB"}
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,EAGL,KAAK,eAAe,EAEpB,KAAK,YAAY,EACjB,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;;;;;;;;;;;;;OAaG;IACG,WAAW,CACf,OAAO,EAAE,WAAW,EACpB,YAAY,EAAE,YAAY,EAC1B,eAAe,GAAE,eAAuB,GACvC,OAAO,CAAC,cAAc,CAAC;IAoB1B,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,2BAA2B;IAuBnC;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;CAkBzB"}