@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.
- package/README.md +30 -2
- package/dist/index.d.ts +35 -54
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -48
- package/dist/provider.d.ts +34 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +33 -0
- package/dist/providers/openai/provider.d.ts +41 -11
- package/dist/providers/openai/provider.d.ts.map +1 -1
- package/dist/providers/openai/provider.js +150 -58
- package/dist/web-sdk.d.ts +2 -1
- package/dist/web-sdk.d.ts.map +1 -1
- package/dist/web-sdk.js +13 -4
- package/package.json +7 -3
- package/src/index.ts +48 -120
- package/src/provider.ts +77 -0
- package/src/providers/openai/provider.ts +211 -68
- package/src/web-sdk.ts +16 -5
|
@@ -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" ||
|
|
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
|
|
312
|
-
* These arrive over an HTTP 200 body, so there is no status
|
|
313
|
-
*
|
|
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
|
|
319
|
-
* an error type, so it is never
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
*
|
|
400
|
-
*
|
|
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
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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
|
-
|
|
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
|
|
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
|
package/dist/web-sdk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-sdk.d.ts","sourceRoot":"","sources":["../src/web-sdk.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gCAAgC,EACtC,MAAM,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
|
|
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
|
|
49
|
-
if (
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
72
|
-
"@independo/inderun-route-core-wasm": "^0.4.0
|
|
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
|
-
*
|
|
2
|
+
* Application entry point for the IndeRun Web SDK (`@independo/inderun-web`).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
type
|
|
22
|
-
type
|
|
23
|
-
type
|
|
24
|
-
type
|
|
25
|
-
type
|
|
26
|
-
|
|
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
|
|
33
|
-
*
|
|
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
|
-
|
|
38
|
-
type
|
|
39
|
-
type
|
|
40
|
-
|
|
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
|
-
*
|
|
59
|
-
*
|
|
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
|
|
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
|
|
74
|
-
*
|
|
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
|
-
*
|
|
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";
|
package/src/provider.ts
ADDED
|
@@ -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";
|