@independo/inderun-web 0.4.0-rc.1 → 0.4.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.
@@ -174,7 +174,15 @@ export class OpenAIResponsesProvider {
174
174
  throw this.mapHttpError(response.status, response.statusText, response.headers, response.body, context);
175
175
  }
176
176
  const responseBody = parseJson(response.body);
177
+ // A lenient server (OpenRouter among them) can answer 2xx for a run that
178
+ // failed upstream; that is a failure to classify, not an empty answer.
179
+ if (responseBody.status === "failed" || responseBody.status === "cancelled") {
180
+ throw this.mapReportedError(responseBody.error, `OpenAI Responses run ended with status '${responseBody.status}'.`, context, responseBody.error_type);
181
+ }
177
182
  const outputText = extractOutputText(responseBody);
183
+ if (outputText === undefined && isRecord(responseBody.error)) {
184
+ throw this.mapReportedError(responseBody.error, "OpenAI Responses payload reported an error.", context, responseBody.error_type);
185
+ }
178
186
  if (outputText === undefined) {
179
187
  throw createInternal("OpenAI Responses payload did not contain text output.", {
180
188
  providerId: this.id,
@@ -221,7 +229,9 @@ export class OpenAIResponsesProvider {
221
229
  * - `response.completed` and `response.incomplete` become the terminal done,
222
230
  * with `finalText`, `usage`, and `finishReason` read off the embedded
223
231
  * response object by the same helpers Mode 1 uses — it has the same shape;
224
- * - `response.failed` and `error` become a terminal error;
232
+ * - `response.failed`, `response.error` and `error` become a terminal error,
233
+ * as does an untyped event carrying an `error` object (OpenRouter's
234
+ * documented mid-stream failure shape);
225
235
  * - every other event type is ignored, since the set is open and additive.
226
236
  *
227
237
  * @param request - Canonical IndeRun task request.
@@ -298,7 +308,10 @@ export class OpenAIResponsesProvider {
298
308
  yield done;
299
309
  return;
300
310
  }
301
- if (type === "response.failed" || type === "error") {
311
+ if (type === "response.failed" ||
312
+ type === "response.error" ||
313
+ type === "error" ||
314
+ (type === undefined && isRecord(parsed.error))) {
302
315
  yield { kind: "error", error: this.mapStreamError(parsed, context) };
303
316
  return;
304
317
  }
@@ -308,28 +321,64 @@ export class OpenAIResponsesProvider {
308
321
  // whatever deltas happened to arrive would hide a truncated response.
309
322
  }
310
323
  /**
311
- * Maps a `response.failed` / `error` stream event onto the error taxonomy.
312
- * These arrive over an HTTP 200 body, so there is no status code to classify
313
- * from; OpenAI reports rate limiting and auth failures here with the same
314
- * `code` values it uses in unary error bodies.
324
+ * Maps a `response.failed` / `response.error` / `error` stream event onto the
325
+ * error taxonomy. These arrive over an HTTP 200 body, so there is no status
326
+ * code to classify from; the event's own `code` is classified instead.
315
327
  *
316
328
  * Two payload shapes exist and both are accepted: the standalone `error`
317
329
  * event carries `code`/`message` at its root, while `response.failed` nests
318
- * them under `response.error`. The root `type` is the event name rather than
319
- * an error type, so it is never read as one.
330
+ * them under `response.error` and some servers nest them under `error`. The
331
+ * root `type` is the event name rather than an error type, so it is never
332
+ * read as one. OpenRouter's typed classification comes from the embedded
333
+ * response (`response.failed`) or the error's metadata (untyped events).
320
334
  */
321
335
  mapStreamError(event, context) {
322
336
  const nested = event.error ?? event.response?.error;
323
- const message = nested?.message ?? event.message ?? "OpenAI Responses stream reported a failure.";
324
- const code = nested?.code ?? event.code;
325
- const details = { errorType: nested?.type, errorCode: code };
337
+ return this.mapReportedError({
338
+ message: nested?.message ?? event.message,
339
+ type: nested?.type,
340
+ code: nested?.code ?? event.code
341
+ }, "OpenAI Responses stream reported a failure.", context, event.response?.error_type ?? nested?.metadata?.error_type);
342
+ }
343
+ /**
344
+ * Classifies a failure reported in a body rather than by the HTTP status: a
345
+ * failed stream event or a 2xx run body whose status is `failed`. The most
346
+ * specific signal wins:
347
+ * 1. OpenRouter's typed `error_type`, classified by the HTTP status it
348
+ * documents for that type (see `openRouterErrorTypeStatus`);
349
+ * 2. an integer `code`, which is an HTTP status (OpenRouter's convention) and
350
+ * is classified exactly as `mapHttpError` classifies that status;
351
+ * 3. a string code, by OpenAI's names.
352
+ * Anything unrecognized is a transient `Unavailable`, since the server did
353
+ * accept the request.
354
+ */
355
+ mapReportedError(reported, fallbackMessage, context, errorType) {
356
+ const message = typeof reported?.message === "string" && reported.message.length > 0
357
+ ? reported.message
358
+ : fallbackMessage;
359
+ const typedStatus = openRouterErrorTypeStatus(errorType);
360
+ const details = {
361
+ errorType: typedStatus !== undefined ? errorType : reported?.type,
362
+ errorCode: getErrorCode(reported?.code)
363
+ };
326
364
  const params = { providerId: this.id, runId: context.runId, details };
365
+ if (typedStatus !== undefined) {
366
+ return this.errorForStatus(typedStatus, message, params);
367
+ }
368
+ const code = reported?.code;
369
+ if (typeof code === "number" && Number.isInteger(code)) {
370
+ return this.errorForStatus(code, message, params);
371
+ }
327
372
  switch (code) {
328
373
  case "rate_limit_exceeded":
329
374
  return createRateLimited(message, { ...params, retryable: true });
330
375
  case "invalid_api_key":
331
376
  case "authentication_error":
332
377
  return createAuthError(message, params);
378
+ // The request itself was rejected; repeating it cannot succeed.
379
+ case "invalid_prompt":
380
+ case "image_content_policy_violation":
381
+ return createInternal(message, params);
333
382
  default:
334
383
  return createUnavailable(message, { ...params, retryable: true });
335
384
  }
@@ -395,66 +444,64 @@ export class OpenAIResponsesProvider {
395
444
  return body;
396
445
  }
397
446
  /**
398
- * Maps an OpenAI HTTP error response onto the IndeRun error taxonomy:
399
- * - `401` / `403` → `AuthError`
400
- * - `429` → `RateLimited` (honors `Retry-After` when present)
401
- * - `408` / `504` → `Timeout`
402
- * - `409` / `5xx` → `Unavailable`
403
- * - any other non-2xx status → `Internal`
447
+ * Maps an OpenAI HTTP error response onto the IndeRun error taxonomy by its
448
+ * status (see `errorForStatus`), honoring `Retry-After` on whichever status
449
+ * carries it.
404
450
  */
405
451
  mapHttpError(status, statusText, headers, body, context) {
406
452
  const error = parseJson(body);
407
453
  const message = getOpenAIErrorMessage(error, status, statusText);
408
- const details = {
409
- status,
410
- statusText,
411
- errorType: getString(error.error?.type),
412
- errorCode: getString(error.error?.code)
454
+ const params = {
455
+ providerId: this.id,
456
+ runId: context.runId,
457
+ details: {
458
+ status,
459
+ statusText,
460
+ errorType: getString(error.error?.type),
461
+ errorCode: getErrorCode(error.error?.code)
462
+ }
413
463
  };
464
+ return this.errorForStatus(status, message, params, parseRetryAfterMs(headers));
465
+ }
466
+ /**
467
+ * The status classification shared by HTTP errors and numeric in-body codes:
468
+ * - `401` / `403` → `AuthError`
469
+ * - `402` → `Unavailable`, not retryable: the account is out of credits, so
470
+ * this target cannot serve until someone tops it up. A 402 that carries
471
+ * `Retry-After` is the exception — OpenRouter documents it for its
472
+ * in-flight budget limit, a wait-and-retry case — and is `RateLimited`. Fallback is unaffected
473
+ * either way: the engine moves on to the next target whatever the class.
474
+ * - `429` → `RateLimited`
475
+ * - `408` / `504` → `Timeout`
476
+ * - `409` / `5xx` → `Unavailable`
477
+ * - any other status → `Internal`
478
+ *
479
+ * `retryAfterMs` travels on every retryable class; it is absent for numeric
480
+ * in-body codes, which have no header to read it from.
481
+ */
482
+ errorForStatus(status, message, params, retryAfterMs) {
483
+ const retry = { ...params, retryable: true };
484
+ if (retryAfterMs !== undefined) {
485
+ retry.retryAfterMs = retryAfterMs;
486
+ }
414
487
  if (status === 401 || status === 403) {
415
- return createAuthError(message, {
416
- providerId: this.id,
417
- runId: context.runId,
418
- details
419
- });
488
+ return createAuthError(message, params);
489
+ }
490
+ if (status === 402) {
491
+ return retryAfterMs === undefined
492
+ ? createUnavailable(message, { ...params, retryable: false })
493
+ : createRateLimited(message, retry);
420
494
  }
421
495
  if (status === 429) {
422
- const retryAfterMs = parseRetryAfterMs(headers);
423
- const params = {
424
- providerId: this.id,
425
- runId: context.runId,
426
- retryable: true,
427
- details
428
- };
429
- if (retryAfterMs !== undefined) {
430
- return createRateLimited(message, {
431
- ...params,
432
- retryAfterMs
433
- });
434
- }
435
- return createRateLimited(message, params);
496
+ return createRateLimited(message, retry);
436
497
  }
437
498
  if (status === 408 || status === 504) {
438
- return createTimeout(message, {
439
- providerId: this.id,
440
- runId: context.runId,
441
- retryable: true,
442
- details
443
- });
499
+ return createTimeout(message, retry);
444
500
  }
445
501
  if (status === 409 || status >= 500) {
446
- return createUnavailable(message, {
447
- providerId: this.id,
448
- runId: context.runId,
449
- retryable: true,
450
- details
451
- });
502
+ return createUnavailable(message, retry);
452
503
  }
453
- return createInternal(message, {
454
- providerId: this.id,
455
- runId: context.runId,
456
- details
457
- });
504
+ return createInternal(message, params);
458
505
  }
459
506
  }
460
507
  function createInput(request) {
@@ -563,3 +610,48 @@ function isRecord(value) {
563
610
  function getString(value) {
564
611
  return typeof value === "string" ? value : undefined;
565
612
  }
613
+ /**
614
+ * The HTTP status OpenRouter documents for each typed `error_type`, so a typed
615
+ * failure is classified exactly like the equivalent HTTP error. Refusals and
616
+ * content-policy violations are documented as 403 but are not credential
617
+ * failures, so they classify as a rejected request (400). Unknown types return
618
+ * `undefined` and the native `code` decides instead.
619
+ */
620
+ function openRouterErrorTypeStatus(errorType) {
621
+ return typeof errorType === "string" && Object.hasOwn(OPENROUTER_ERROR_TYPE_STATUS, errorType)
622
+ ? OPENROUTER_ERROR_TYPE_STATUS[errorType]
623
+ : undefined;
624
+ }
625
+ const OPENROUTER_ERROR_TYPE_STATUS = {
626
+ authentication: 401,
627
+ payment_required: 402,
628
+ permission_denied: 403,
629
+ rate_limit_exceeded: 429,
630
+ timeout: 504,
631
+ provider_unavailable: 502,
632
+ provider_overloaded: 503,
633
+ server: 500,
634
+ unmapped: 500,
635
+ not_found: 404,
636
+ image_not_found: 404,
637
+ precondition_failed: 412,
638
+ payload_too_large: 413,
639
+ unprocessable: 422,
640
+ content_policy_violation: 400,
641
+ refusal: 400,
642
+ context_length_exceeded: 400,
643
+ max_tokens_exceeded: 400,
644
+ token_limit_exceeded: 400,
645
+ string_too_long: 400,
646
+ invalid_request: 400,
647
+ invalid_prompt: 400,
648
+ invalid_image: 400,
649
+ image_too_large: 400,
650
+ image_too_small: 400,
651
+ unsupported_image_format: 400,
652
+ image_download_failed: 400
653
+ };
654
+ /** An error `code` as a detail string, whether the server sent a name or a numeric status. */
655
+ function getErrorCode(value) {
656
+ return typeof value === "number" ? String(value) : getString(value);
657
+ }
package/dist/web-sdk.d.ts CHANGED
@@ -30,7 +30,8 @@ export interface CreateIndeRunWebOptions {
30
30
  */
31
31
  hostServices?: CreateBrowserHostServicesOptions;
32
32
  /**
33
- * Explicit opt-in for calling the public OpenAI endpoint directly from this Web SDK factory.
33
+ * Explicit opt-in for calling a public Responses endpoint directly from this Web SDK factory —
34
+ * OpenAI's or OpenRouter's — with browser-held credentials.
34
35
  *
35
36
  * Browser apps should leave this unset and use a proxy endpoint with `openAI.auth = "none"` instead.
36
37
  * Direct calls can expose credentials to client-side code and are appropriate only for controlled
@@ -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,wBAAwB,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAChG,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,sCAAsC,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B;;;OAGG;IACH,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,0BAA0B,CAAC;IACzC;;OAEG;IACH,YAAY,CAAC,EAAE,gCAAgC,CAAC;IAChD;;;;;;OAMG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,qBAAqB,EAAE,OAAO,CAAC,GAAG;IACxE,qDAAqD;IACrD,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CA+B1E"}
1
+ {"version":3,"file":"web-sdk.d.ts","sourceRoot":"","sources":["../src/web-sdk.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gCAAgC,EACtC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAChG,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,sCAAsC,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B;;;OAGG;IACH,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,0BAA0B,CAAC;IACzC;;OAEG;IACH,YAAY,CAAC,EAAE,gCAAgC,CAAC;IAChD;;;;;;;OAOG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,qBAAqB,EAAE,OAAO,CAAC,GAAG;IACxE,qDAAqD;IACrD,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CA+B1E"}
package/dist/web-sdk.js CHANGED
@@ -45,12 +45,12 @@ export function createIndeRunWeb(options) {
45
45
  function assertSafeOpenAIEndpoint(openAI, allowDirectOpenAIEndpoint) {
46
46
  const endpointUrl = openAI.endpointUrl ?? DEFAULT_OPENAI_RESPONSES_ENDPOINT;
47
47
  const auth = openAI.auth ?? "authContextRef";
48
- const isDirectOpenAIEndpoint = isOpenAIResponsesEndpoint(endpointUrl);
49
- if (isDirectOpenAIEndpoint && auth !== "none" && !allowDirectOpenAIEndpoint) {
48
+ const isDirectPublicEndpoint = isPublicResponsesEndpoint(endpointUrl);
49
+ if (isDirectPublicEndpoint && auth !== "none" && !allowDirectOpenAIEndpoint) {
50
50
  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.');
51
51
  }
52
52
  }
53
- function isOpenAIResponsesEndpoint(endpointUrl) {
53
+ function isPublicResponsesEndpoint(endpointUrl) {
54
54
  let parsed;
55
55
  try {
56
56
  parsed = new URL(endpointUrl);
@@ -59,5 +59,14 @@ function isOpenAIResponsesEndpoint(endpointUrl) {
59
59
  return false;
60
60
  }
61
61
  const pathname = parsed.pathname.replace(/\/+$/u, "");
62
- return parsed.hostname.toLowerCase() === "api.openai.com" && pathname === "/v1/responses";
62
+ const endpoint = `${parsed.hostname.toLowerCase()}${pathname}`;
63
+ return PUBLIC_RESPONSES_ENDPOINTS.includes(endpoint);
63
64
  }
65
+ /**
66
+ * Hosted Responses endpoints whose credentials are developer-owned API keys, which the
67
+ * factory keeps out of browser code unless `allowDirectOpenAIEndpoint` says otherwise.
68
+ */
69
+ const PUBLIC_RESPONSES_ENDPOINTS = [
70
+ "api.openai.com/v1/responses",
71
+ "openrouter.ai/api/v1/responses"
72
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@independo/inderun-web",
3
- "version": "0.4.0-rc.1",
3
+ "version": "0.4.0",
4
4
  "description": "On-device AI with automatic cloud fallback for web apps. Runs ONNX Runtime or the Chrome Prompt API in the browser and falls back to an OpenAI-compatible endpoint, with streaming and cancellation behind one API.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -47,6 +47,10 @@
47
47
  "types": "./dist/index.d.ts",
48
48
  "default": "./dist/index.js"
49
49
  },
50
+ "./provider": {
51
+ "types": "./dist/provider.d.ts",
52
+ "default": "./dist/provider.js"
53
+ },
50
54
  "./openai": {
51
55
  "types": "./dist/openai.d.ts",
52
56
  "default": "./dist/openai.js"
@@ -68,8 +72,8 @@
68
72
  "README.md"
69
73
  ],
70
74
  "dependencies": {
71
- "@independo/inderun-contracts": "^0.4.0-rc.1",
72
- "@independo/inderun-route-core-wasm": "^0.4.0-rc.1"
75
+ "@independo/inderun-contracts": "^0.4.0",
76
+ "@independo/inderun-route-core-wasm": "^0.4.0"
73
77
  },
74
78
  "peerDependencies": {
75
79
  "@huggingface/transformers": "^4.0.0"
package/src/index.ts CHANGED
@@ -1,100 +1,60 @@
1
1
  /**
2
- * Unified entry point for the IndeRun Web SDK (`@independo/inderun-web`).
2
+ * Application entry point for the IndeRun Web SDK (`@independo/inderun-web`).
3
3
  *
4
- * Everything a browser app needs to run and stream tasks is exported from here:
5
- * the engine, the routing and provider seams, host services, error and telemetry
6
- * types, and the contract types the SDK's own signatures use. Provider adapters
7
- * are the deliberate exception — each ships from its own subpath
8
- * (`/openai`, `/onnx`, `/system-model`) so this surface stays provider-agnostic.
4
+ * It leads with the primary text API (`generateText` / `streamText`) and the
5
+ * factory that builds a ready engine, then carries the advanced task API
6
+ * (`run()` / `stream()` / `checkCapabilities()`) and the contract, error and
7
+ * telemetry types those signatures use. See `docs/architecture/api-layering.md`.
8
+ *
9
+ * Two kinds of export live elsewhere on purpose:
10
+ * - provider-authoring and host-integration APIs ship from
11
+ * `@independo/inderun-web/provider`;
12
+ * - provider adapters ship from their own subpaths (`/openai`, `/onnx`,
13
+ * `/system-model`), so this surface stays provider-agnostic.
14
+ *
15
+ * The engine's internals (router, route planner bindings, Event Gate) are not
16
+ * exported at all.
9
17
  */
10
18
 
11
19
  /**
12
- * Host services: the platform capabilities the engine reads and calls through,
13
- * and the seams an embedder overrides to supply its own (custom transport,
14
- * credential storage, clock).
20
+ * The primary text API: one canonical request per call, over any `IndeRunApi`.
15
21
  */
16
22
  export {
17
- type AbortSignalLike,
18
- type ConnectivityService,
19
- type DeviceConstraintsService,
20
- type SecureStorageService,
21
- type ClockService,
22
- type HttpClientService,
23
- type HttpRequest,
24
- type HttpResponse,
25
- type HttpStreamResponse,
26
- type HttpStreamingClientService,
27
- type HostServices,
28
- type ThermalState
29
- } from "./core/host.js";
23
+ generateText,
24
+ streamText,
25
+ toTaskRequest,
26
+ TextStreamRetractedError,
27
+ type GeneratedText,
28
+ type StreamedText,
29
+ type TextExecutionOptions,
30
+ type TextGenerationOptions,
31
+ type TextStream
32
+ } from "./facade/text.js";
30
33
 
31
34
  /**
32
- * The provider contract. Implement `ProviderAdapter` for a Mode 1 backend and add
33
- * a `stream` for Mode 2; the descriptor and dynamic capability check are what the
34
- * router plans against.
35
+ * The recommended way in: builds host services, registers the providers named in
36
+ * the options, and returns a ready engine.
35
37
  */
36
38
  export {
37
- type ProviderDescriptor,
38
- type ProviderDynamicCapabilities,
39
- type ProviderCapabilitySnapshot,
40
- type RunContext,
41
- type ProviderAdapter,
42
- type ProviderStreamContext,
43
- type ProviderStreamEvent,
44
- type StreamRun
45
- } from "./core/provider.js";
46
-
47
- /**
48
- * Per-run gatekeeper for a Mode 2 stream: assigns the sequence numbers callers
49
- * order by, and enforces that exactly one terminal outcome is produced with
50
- * nothing admitted after it. Exported for embedders driving a stream themselves.
51
- */
52
- export { EventGate } from "./core/event-gate.js";
53
-
54
- /** Holds the provider adapters a given engine instance can route to. */
55
- export { ProviderRegistry } from "./core/registry.js";
39
+ createIndeRunWeb,
40
+ type CreateIndeRunWebOptions,
41
+ type OpenAIFactoryOptions
42
+ } from "./web-sdk.js";
56
43
 
57
44
  /**
58
- * Route selection. `Router` turns a request plus a host capability snapshot into
59
- * a provider chain; `WasmRoutePlanner` is the shared Rust planner behind it, and
60
- * the only planner the Web SDK has — there is no JavaScript fallback.
45
+ * Model profiles: application-defined names for ordered sets of targets that a
46
+ * request can route within. `"auto"` is built in.
61
47
  */
62
- export { type RouteSelection, Router } from "./core/router.js";
63
- export {
64
- type RoutePlanner,
65
- type PlannerOutcome,
66
- type WasmUnavailableReason,
67
- type SharedPlannerInput,
68
- type SharedPlannerRoutePlan,
69
- WasmRoutePlanner
70
- } from "./core/route-planner.js";
48
+ export { AUTO_MODEL_PROFILE, type ModelProfiles } from "./core/model-profiles.js";
71
49
 
72
50
  /**
73
- * The normalized error taxonomy. Every failure the SDK surfaces is an
74
- * `IndeRunException` in one of these classes, whatever the provider raised.
51
+ * The advanced task API. `IndeRun` implements `IndeRunApi`; constructing one by
52
+ * hand takes a `ProviderRegistry` and `HostServices` from
53
+ * `@independo/inderun-web/provider`.
75
54
  */
76
- export {
77
- type IndeRunExceptionParams,
78
- IndeRunException,
79
- createCapabilityMismatch,
80
- createOffline,
81
- createAuthError,
82
- createRateLimited,
83
- createTimeout,
84
- createUnavailable,
85
- createInternal,
86
- toIndeRunException
87
- } from "./core/errors.js";
88
-
89
- /** The engine itself, and the app-facing API surface it implements. */
90
55
  export { IndeRun, type IndeRunOptions, type StreamHandleResult } from "./core/engine.js";
91
-
92
- /**
93
- * Model profiles: application-defined names for ordered sets of targets that a
94
- * request can route within. `"auto"` is built in.
95
- */
96
- export { AUTO_MODEL_PROFILE, type ModelProfiles } from "./core/model-profiles.js";
97
56
  export type { IndeRunApi } from "./core/generated/inderun-api.js";
57
+ export type { ProviderCapabilitySnapshot, StreamRun } from "./core/provider.js";
98
58
 
99
59
  /**
100
60
  * The contract types this SDK's own signatures take and return.
@@ -105,13 +65,14 @@ export type { IndeRunApi } from "./core/generated/inderun-api.js";
105
65
  * This is the npm counterpart of Gradle `api(...)` on Android and `@_exported
106
66
  * import` on Swift — see
107
67
  * {@link https://github.com/independo-gmbh/inderun/issues/189 | #189}. The
108
- * host-service and telemetry blocks in this file re-export their halves of the
109
- * same contract surface for the same reason.
68
+ * telemetry block below and the host-service block of the `/provider` entry
69
+ * point re-export their halves of the same contract surface for the same reason.
110
70
  *
111
71
  * Depend on `@independo/inderun-contracts` directly only for what is not
112
72
  * re-exported here: the JSON Schemas and the `get*ValidationIssues` validators.
113
73
  */
114
74
  export type {
75
+ ExecutionProvenance,
115
76
  IndeRunError,
116
77
  IndeRunErrorClass,
117
78
  StreamEvent,
@@ -121,6 +82,13 @@ export type {
121
82
  TaskResult
122
83
  } from "@independo/inderun-contracts";
123
84
 
85
+ /**
86
+ * The normalized error taxonomy. Every failure the SDK surfaces is an
87
+ * `IndeRunException` in one of these classes, whatever the provider raised.
88
+ * Provider authors create them with the `create*` helpers from `/provider`.
89
+ */
90
+ export { IndeRunException, toIndeRunException } from "./core/errors.js";
91
+
124
92
  /**
125
93
  * Telemetry. Pass a `TelemetryService` to observe routing decisions and attempt
126
94
  * outcomes; the engine defaults to `NoOpTelemetryService`.
@@ -131,43 +99,3 @@ export {
131
99
  type TelemetryService,
132
100
  NoOpTelemetryService
133
101
  } from "./core/telemetry.js";
134
-
135
- /**
136
- * The browser implementations of the host services above, and the factory that
137
- * assembles them. Use these directly only when constructing `IndeRun` by hand.
138
- */
139
- export {
140
- BrowserConnectivityService,
141
- FetchHttpClient,
142
- FetchStreamingHttpClient,
143
- SystemClockService,
144
- createBrowserHostServices,
145
- type CreateBrowserHostServicesOptions,
146
- type FetchHttpClientOptions
147
- } from "./core/browser-host.js";
148
-
149
- /**
150
- * The primary text API: one canonical request per call, over any `IndeRunApi`.
151
- * See `docs/architecture/api-layering.md`.
152
- */
153
- export {
154
- generateText,
155
- streamText,
156
- toTaskRequest,
157
- TextStreamRetractedError,
158
- type GeneratedText,
159
- type StreamedText,
160
- type TextExecutionOptions,
161
- type TextGenerationOptions,
162
- type TextStream
163
- } from "./facade/text.js";
164
-
165
- /**
166
- * The recommended way in: builds host services, registers the providers named in
167
- * the options, and returns a ready engine.
168
- */
169
- export {
170
- createIndeRunWeb,
171
- type CreateIndeRunWebOptions,
172
- type OpenAIFactoryOptions
173
- } from "./web-sdk.js";
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Provider-authoring and host-integration entry point
3
+ * (`@independo/inderun-web/provider`).
4
+ *
5
+ * For code that extends the engine rather than calls it: custom provider
6
+ * adapters, custom host services (transport, credential storage, clock), and
7
+ * assembling an `IndeRun` by hand from a `ProviderRegistry`. Applications that
8
+ * only call `generateText` / `streamText` or `run()` / `stream()` need nothing
9
+ * from here. Changes to this surface are called out in release notes.
10
+ */
11
+
12
+ /**
13
+ * Host services: the platform capabilities the engine reads and calls through,
14
+ * and the seams an embedder overrides to supply its own.
15
+ */
16
+ export {
17
+ type AbortSignalLike,
18
+ type ConnectivityService,
19
+ type DeviceConstraintsService,
20
+ type SecureStorageService,
21
+ type ClockService,
22
+ type HttpClientService,
23
+ type HttpRequest,
24
+ type HttpResponse,
25
+ type HttpStreamResponse,
26
+ type HttpStreamingClientService,
27
+ type HostServices,
28
+ type ThermalState
29
+ } from "./core/host.js";
30
+
31
+ /**
32
+ * The browser implementations of the host services above, and the factory that
33
+ * assembles them. Use these directly only when constructing `IndeRun` by hand.
34
+ */
35
+ export {
36
+ BrowserConnectivityService,
37
+ FetchHttpClient,
38
+ FetchStreamingHttpClient,
39
+ SystemClockService,
40
+ createBrowserHostServices,
41
+ type CreateBrowserHostServicesOptions,
42
+ type FetchHttpClientOptions
43
+ } from "./core/browser-host.js";
44
+
45
+ /**
46
+ * The provider contract. Implement `ProviderAdapter` for a Mode 1 backend and add
47
+ * a `stream` for Mode 2; the descriptor and dynamic capability check are what the
48
+ * router plans against.
49
+ */
50
+ export {
51
+ type ProviderDescriptor,
52
+ type ProviderDynamicCapabilities,
53
+ type ProviderCapabilitySnapshot,
54
+ type RunContext,
55
+ type ProviderAdapter,
56
+ type ProviderStreamContext,
57
+ type ProviderStreamEvent,
58
+ type StreamRun
59
+ } from "./core/provider.js";
60
+
61
+ /** Holds the provider adapters a given engine instance can route to. */
62
+ export { ProviderRegistry } from "./core/registry.js";
63
+
64
+ /**
65
+ * Constructors for the normalized error taxonomy. A provider maps every failure
66
+ * onto one of these classes; the engine does the rest.
67
+ */
68
+ export {
69
+ type IndeRunExceptionParams,
70
+ createCapabilityMismatch,
71
+ createOffline,
72
+ createAuthError,
73
+ createRateLimited,
74
+ createTimeout,
75
+ createUnavailable,
76
+ createInternal
77
+ } from "./core/errors.js";