@independo/inderun-web 0.1.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/LICENSE +21 -0
- package/README.md +50 -0
- package/dist/browser-host.d.ts +67 -0
- package/dist/browser-host.d.ts.map +1 -0
- package/dist/browser-host.js +125 -0
- package/dist/engine.d.ts +42 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +191 -0
- package/dist/errors.d.ts +93 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +155 -0
- package/dist/host.d.ts +2 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/openai-provider.d.ts +80 -0
- package/dist/openai-provider.d.ts.map +1 -0
- package/dist/openai-provider.js +345 -0
- package/dist/openai.d.ts +10 -0
- package/dist/openai.d.ts.map +1 -0
- package/dist/openai.js +9 -0
- package/dist/provider.d.ts +118 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +1 -0
- package/dist/registry.d.ts +29 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +42 -0
- package/dist/route-planner.d.ts +54 -0
- package/dist/route-planner.d.ts.map +1 -0
- package/dist/route-planner.js +110 -0
- package/dist/router.d.ts +54 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +164 -0
- package/dist/telemetry.d.ts +13 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +12 -0
- package/dist/web-sdk.d.ts +35 -0
- package/dist/web-sdk.d.ts.map +1 -0
- package/dist/web-sdk.js +38 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Independo GmbH
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# @independo/inderun-web
|
|
2
|
+
|
|
3
|
+
TypeScript/Web SDK for IndeRun.
|
|
4
|
+
|
|
5
|
+
This package provides the Web SDK entrypoint, the engine core, routing, telemetry, error normalization, and the OpenAI-compatible cloud provider.
|
|
6
|
+
|
|
7
|
+
## Basic Usage
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { createIndeRunWeb } from "@independo/inderun-web";
|
|
11
|
+
|
|
12
|
+
const inderun = createIndeRunWeb({
|
|
13
|
+
openAI: {
|
|
14
|
+
model: "gpt-5.2",
|
|
15
|
+
endpointUrl: "/api/inderun/openai-responses",
|
|
16
|
+
auth: "none"
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const result = await inderun.run({
|
|
21
|
+
schemaVersion: "1.0",
|
|
22
|
+
task: { kind: "text_to_text" },
|
|
23
|
+
prompt: "Write a one-sentence summary of IndeRun."
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Security Model
|
|
28
|
+
|
|
29
|
+
Browser apps should use a proxy endpoint and keep provider credentials server-side. `createIndeRunWeb` rejects direct calls to the public OpenAI Responses endpoint unless `allowDirectOpenAIEndpoint: true` is set for a controlled environment.
|
|
30
|
+
|
|
31
|
+
## Advanced: registering the OpenAI provider directly
|
|
32
|
+
|
|
33
|
+
`createIndeRunWeb` wires the OpenAI Responses provider for you. To register it
|
|
34
|
+
manually (e.g. alongside other providers), import it from the provider subpath:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { OpenAIResponsesProvider } from "@independo/inderun-web/openai";
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The provider normalizes OpenAI transport and API failures into the IndeRun error
|
|
41
|
+
taxonomy (`AuthError`, `RateLimited`, `Timeout`, `Unavailable`, `Internal`). The
|
|
42
|
+
exact status-to-class mapping is documented on the provider in code — see
|
|
43
|
+
`OpenAIResponsesProvider` — so it stays in sync with behavior.
|
|
44
|
+
|
|
45
|
+
## Commands
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
pnpm --filter @independo/inderun-web build
|
|
49
|
+
pnpm --filter @independo/inderun-web test
|
|
50
|
+
```
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ClockService, ConnectivityService, HostServices, HttpClientService, HttpRequest, HttpResponse } from "./host.js";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for the fetch-backed HTTP host service.
|
|
4
|
+
*/
|
|
5
|
+
export interface FetchHttpClientOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Optional fetch implementation. Useful for tests, SSR-like environments, or custom wrappers.
|
|
8
|
+
*/
|
|
9
|
+
fetchFn?: typeof fetch;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Browser connectivity service based on `navigator.onLine`.
|
|
13
|
+
*/
|
|
14
|
+
export declare class BrowserConnectivityService implements ConnectivityService {
|
|
15
|
+
/**
|
|
16
|
+
* Returns the browser's current online hint.
|
|
17
|
+
* Non-browser environments are treated as online so injected HTTP clients can still run in tests.
|
|
18
|
+
*/
|
|
19
|
+
isOnline(): Promise<boolean>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Clock service using wall-clock time and the browser performance timer when available.
|
|
23
|
+
*/
|
|
24
|
+
export declare class SystemClockService implements ClockService {
|
|
25
|
+
/**
|
|
26
|
+
* Returns current Unix epoch time in milliseconds.
|
|
27
|
+
*/
|
|
28
|
+
now(): number;
|
|
29
|
+
/**
|
|
30
|
+
* Returns monotonic milliseconds from `performance.now()` when available.
|
|
31
|
+
*/
|
|
32
|
+
monotonicNow(): number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* HTTP client service that adapts the platform `fetch` API to IndeRun's normalized HTTP contract.
|
|
36
|
+
*/
|
|
37
|
+
export declare class FetchHttpClient implements HttpClientService {
|
|
38
|
+
private readonly fetchFn;
|
|
39
|
+
/**
|
|
40
|
+
* Creates a fetch-backed HTTP client.
|
|
41
|
+
* @param options - Optional fetch implementation override.
|
|
42
|
+
* @throws Error when no fetch implementation is available.
|
|
43
|
+
*/
|
|
44
|
+
constructor(options?: FetchHttpClientOptions);
|
|
45
|
+
/**
|
|
46
|
+
* Sends a normalized HTTP request using `fetch`.
|
|
47
|
+
* @param request - Normalized HTTP request payload.
|
|
48
|
+
* @returns Normalized HTTP response payload with lower-cased response header names.
|
|
49
|
+
*/
|
|
50
|
+
send(request: HttpRequest): Promise<HttpResponse>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Options for constructing default browser host services.
|
|
54
|
+
*/
|
|
55
|
+
export interface CreateBrowserHostServicesOptions extends Partial<HostServices> {
|
|
56
|
+
/**
|
|
57
|
+
* Optional fetch implementation used when `httpClient` is not supplied.
|
|
58
|
+
*/
|
|
59
|
+
fetchFn?: typeof fetch;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Creates a browser-oriented HostServices bundle for the Web SDK.
|
|
63
|
+
* Supplied host services override the defaults; missing connectivity, clock, and HTTP services are created.
|
|
64
|
+
* @param options - Optional host service overrides and fetch implementation.
|
|
65
|
+
*/
|
|
66
|
+
export declare function createBrowserHostServices(options?: CreateBrowserHostServicesOptions): HostServices;
|
|
67
|
+
//# sourceMappingURL=browser-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-host.d.ts","sourceRoot":"","sources":["../src/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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser connectivity service based on `navigator.onLine`.
|
|
3
|
+
*/
|
|
4
|
+
export class BrowserConnectivityService {
|
|
5
|
+
/**
|
|
6
|
+
* Returns the browser's current online hint.
|
|
7
|
+
* Non-browser environments are treated as online so injected HTTP clients can still run in tests.
|
|
8
|
+
*/
|
|
9
|
+
async isOnline() {
|
|
10
|
+
if (typeof navigator === "undefined") {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
return navigator.onLine;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Clock service using wall-clock time and the browser performance timer when available.
|
|
18
|
+
*/
|
|
19
|
+
export class SystemClockService {
|
|
20
|
+
/**
|
|
21
|
+
* Returns current Unix epoch time in milliseconds.
|
|
22
|
+
*/
|
|
23
|
+
now() {
|
|
24
|
+
return Date.now();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Returns monotonic milliseconds from `performance.now()` when available.
|
|
28
|
+
*/
|
|
29
|
+
monotonicNow() {
|
|
30
|
+
if (typeof performance === "undefined") {
|
|
31
|
+
return Date.now();
|
|
32
|
+
}
|
|
33
|
+
return performance.now();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* HTTP client service that adapts the platform `fetch` API to IndeRun's normalized HTTP contract.
|
|
38
|
+
*/
|
|
39
|
+
export class FetchHttpClient {
|
|
40
|
+
fetchFn;
|
|
41
|
+
/**
|
|
42
|
+
* Creates a fetch-backed HTTP client.
|
|
43
|
+
* @param options - Optional fetch implementation override.
|
|
44
|
+
* @throws Error when no fetch implementation is available.
|
|
45
|
+
*/
|
|
46
|
+
constructor(options = {}) {
|
|
47
|
+
const fetchFn = options.fetchFn ?? globalThis.fetch?.bind(globalThis);
|
|
48
|
+
if (!fetchFn) {
|
|
49
|
+
throw new Error("FetchHttpClient requires a fetch implementation.");
|
|
50
|
+
}
|
|
51
|
+
this.fetchFn = fetchFn;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sends a normalized HTTP request using `fetch`.
|
|
55
|
+
* @param request - Normalized HTTP request payload.
|
|
56
|
+
* @returns Normalized HTTP response payload with lower-cased response header names.
|
|
57
|
+
*/
|
|
58
|
+
async send(request) {
|
|
59
|
+
const controller = typeof AbortController === "undefined" ? undefined : new AbortController();
|
|
60
|
+
let timeoutId;
|
|
61
|
+
if (controller && request.timeoutMs !== undefined) {
|
|
62
|
+
timeoutId = setTimeout(() => controller.abort(), request.timeoutMs);
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const init = {
|
|
66
|
+
method: request.method
|
|
67
|
+
};
|
|
68
|
+
if (request.headers) {
|
|
69
|
+
init.headers = request.headers;
|
|
70
|
+
}
|
|
71
|
+
if (request.body !== undefined) {
|
|
72
|
+
init.body = request.body;
|
|
73
|
+
}
|
|
74
|
+
if (controller) {
|
|
75
|
+
init.signal = controller.signal;
|
|
76
|
+
}
|
|
77
|
+
const response = await this.fetchFn(request.url, init);
|
|
78
|
+
const headers = {};
|
|
79
|
+
response.headers.forEach((value, key) => {
|
|
80
|
+
headers[key.toLowerCase()] = value;
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
status: response.status,
|
|
84
|
+
statusText: response.statusText,
|
|
85
|
+
headers,
|
|
86
|
+
body: await response.text()
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
if (timeoutId !== undefined) {
|
|
91
|
+
clearTimeout(timeoutId);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Creates a browser-oriented HostServices bundle for the Web SDK.
|
|
98
|
+
* Supplied host services override the defaults; missing connectivity, clock, and HTTP services are created.
|
|
99
|
+
* @param options - Optional host service overrides and fetch implementation.
|
|
100
|
+
*/
|
|
101
|
+
export function createBrowserHostServices(options = {}) {
|
|
102
|
+
const hostServices = {
|
|
103
|
+
connectivity: options.connectivity ?? new BrowserConnectivityService()
|
|
104
|
+
};
|
|
105
|
+
hostServices.clock = options.clock ?? new SystemClockService();
|
|
106
|
+
if (options.httpClient) {
|
|
107
|
+
hostServices.httpClient = options.httpClient;
|
|
108
|
+
}
|
|
109
|
+
else if (options.fetchFn) {
|
|
110
|
+
hostServices.httpClient = new FetchHttpClient({ fetchFn: options.fetchFn });
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
hostServices.httpClient = new FetchHttpClient();
|
|
114
|
+
}
|
|
115
|
+
if (options.deviceConstraints) {
|
|
116
|
+
hostServices.deviceConstraints = options.deviceConstraints;
|
|
117
|
+
}
|
|
118
|
+
if (options.secureStorage) {
|
|
119
|
+
hostServices.secureStorage = options.secureStorage;
|
|
120
|
+
}
|
|
121
|
+
if (options.telemetry) {
|
|
122
|
+
hostServices.telemetry = options.telemetry;
|
|
123
|
+
}
|
|
124
|
+
return hostServices;
|
|
125
|
+
}
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type TaskRequest, type TaskResult } from "@independo/inderun-contracts";
|
|
2
|
+
import type { HostServices } from "./host.js";
|
|
3
|
+
import { ProviderRegistry } from "./registry.js";
|
|
4
|
+
import { type TelemetryService } from "./telemetry.js";
|
|
5
|
+
/**
|
|
6
|
+
* Main orchestrator SDK entrypoint class.
|
|
7
|
+
* Validates tasks, executes routing rules based on request constraints and connectivity,
|
|
8
|
+
* triggers provider adapters, and logs timing telemetry.
|
|
9
|
+
*/
|
|
10
|
+
export declare class IndeRun {
|
|
11
|
+
private registry;
|
|
12
|
+
private hostServices;
|
|
13
|
+
private router;
|
|
14
|
+
private telemetryService;
|
|
15
|
+
/**
|
|
16
|
+
* Initializes the IndeRun instance.
|
|
17
|
+
* @param registry - Registry filled with active providers.
|
|
18
|
+
* @param hostServices - Services wrapping OS interfaces and indicators.
|
|
19
|
+
* @param telemetryService - Optional custom telemetry service listener.
|
|
20
|
+
*/
|
|
21
|
+
constructor(registry: ProviderRegistry, hostServices: HostServices, telemetryService?: TelemetryService);
|
|
22
|
+
/**
|
|
23
|
+
* Safely emits a telemetry event by swallowing any internal logging/telemetry system errors.
|
|
24
|
+
* @param event - The telemetry event to emit.
|
|
25
|
+
*/
|
|
26
|
+
private safeEmit;
|
|
27
|
+
/**
|
|
28
|
+
* Returns a stable, generic description of an error class for privacy-preserving telemetry.
|
|
29
|
+
* @param errorClass - The taxonomy classification of the exception.
|
|
30
|
+
*/
|
|
31
|
+
private getStableMessage;
|
|
32
|
+
/**
|
|
33
|
+
* Orchestrates the execution of a TaskRequest.
|
|
34
|
+
* Performs JSON Schema validation, selects a provider via routing rules,
|
|
35
|
+
* measures total execution time, and attaches telemetry metadata to the outcome.
|
|
36
|
+
* @param request - The canonical task request containing prompts, tasks, and constraints.
|
|
37
|
+
* @returns Canonical task output containing output details and telemetry metadata.
|
|
38
|
+
* @throws {IndeRunException} Standardized error indicating validation, connection, or provider failures.
|
|
39
|
+
*/
|
|
40
|
+
run(request: TaskRequest): Promise<TaskResult>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/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,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;CAoIrD"}
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { getTaskRequestValidationIssues } from "@independo/inderun-contracts";
|
|
2
|
+
import { ProviderRegistry } from "./registry.js";
|
|
3
|
+
import { Router } from "./router.js";
|
|
4
|
+
import { createInternal, toIndeRunException } from "./errors.js";
|
|
5
|
+
import { NoOpTelemetryService } from "./telemetry.js";
|
|
6
|
+
/**
|
|
7
|
+
* Main orchestrator SDK entrypoint class.
|
|
8
|
+
* Validates tasks, executes routing rules based on request constraints and connectivity,
|
|
9
|
+
* triggers provider adapters, and logs timing telemetry.
|
|
10
|
+
*/
|
|
11
|
+
export class IndeRun {
|
|
12
|
+
registry;
|
|
13
|
+
hostServices;
|
|
14
|
+
router;
|
|
15
|
+
telemetryService;
|
|
16
|
+
/**
|
|
17
|
+
* Initializes the IndeRun instance.
|
|
18
|
+
* @param registry - Registry filled with active providers.
|
|
19
|
+
* @param hostServices - Services wrapping OS interfaces and indicators.
|
|
20
|
+
* @param telemetryService - Optional custom telemetry service listener.
|
|
21
|
+
*/
|
|
22
|
+
constructor(registry, hostServices, telemetryService) {
|
|
23
|
+
this.registry = registry;
|
|
24
|
+
this.hostServices = hostServices;
|
|
25
|
+
this.router = new Router(this.registry);
|
|
26
|
+
this.telemetryService =
|
|
27
|
+
telemetryService || this.hostServices.telemetry || new NoOpTelemetryService();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Safely emits a telemetry event by swallowing any internal logging/telemetry system errors.
|
|
31
|
+
* @param event - The telemetry event to emit.
|
|
32
|
+
*/
|
|
33
|
+
safeEmit(event) {
|
|
34
|
+
try {
|
|
35
|
+
this.telemetryService.emit(event);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
// Telemetry failures must never disrupt primary execution flows.
|
|
39
|
+
console.warn("[IndeRun] Telemetry service emission failed:", err);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Returns a stable, generic description of an error class for privacy-preserving telemetry.
|
|
44
|
+
* @param errorClass - The taxonomy classification of the exception.
|
|
45
|
+
*/
|
|
46
|
+
getStableMessage(errorClass) {
|
|
47
|
+
switch (errorClass) {
|
|
48
|
+
case "CapabilityMismatch":
|
|
49
|
+
return "Provider capability mismatch.";
|
|
50
|
+
case "Offline":
|
|
51
|
+
return "Device is offline.";
|
|
52
|
+
case "AuthError":
|
|
53
|
+
return "Authentication failed.";
|
|
54
|
+
case "RateLimited":
|
|
55
|
+
return "Rate limit exceeded.";
|
|
56
|
+
case "Timeout":
|
|
57
|
+
return "Execution timed out.";
|
|
58
|
+
case "Unavailable":
|
|
59
|
+
return "Provider is unavailable.";
|
|
60
|
+
case "Internal":
|
|
61
|
+
default:
|
|
62
|
+
return "An internal engine error occurred.";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Orchestrates the execution of a TaskRequest.
|
|
67
|
+
* Performs JSON Schema validation, selects a provider via routing rules,
|
|
68
|
+
* measures total execution time, and attaches telemetry metadata to the outcome.
|
|
69
|
+
* @param request - The canonical task request containing prompts, tasks, and constraints.
|
|
70
|
+
* @returns Canonical task output containing output details and telemetry metadata.
|
|
71
|
+
* @throws {IndeRunException} Standardized error indicating validation, connection, or provider failures.
|
|
72
|
+
*/
|
|
73
|
+
async run(request) {
|
|
74
|
+
const startTime = this.hostServices.clock ? this.hostServices.clock.now() : Date.now();
|
|
75
|
+
const runId = request.requestId || `run_${Math.random().toString(36).substring(2, 11)}`;
|
|
76
|
+
try {
|
|
77
|
+
// 1. Validate request payload using schema contracts
|
|
78
|
+
const validationIssues = getTaskRequestValidationIssues(request);
|
|
79
|
+
if (validationIssues.length > 0) {
|
|
80
|
+
const message = `Validation failed for TaskRequest: ${validationIssues
|
|
81
|
+
.map((i) => `${i.path} - ${i.message}`)
|
|
82
|
+
.join("; ")}`;
|
|
83
|
+
throw createInternal(message, {
|
|
84
|
+
runId,
|
|
85
|
+
details: { validationIssues }
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// 2. Select the route based on constraints and host capabilities
|
|
89
|
+
const routeSelection = await this.router.selectRoute(request, this.hostServices);
|
|
90
|
+
const providers = [routeSelection.provider, ...routeSelection.fallbackProviders];
|
|
91
|
+
// Emit route_decided event
|
|
92
|
+
this.safeEmit({
|
|
93
|
+
type: "route_decided",
|
|
94
|
+
runId,
|
|
95
|
+
timestamp: this.hostServices.clock ? this.hostServices.clock.now() : Date.now(),
|
|
96
|
+
payload: {
|
|
97
|
+
selectedProviderId: routeSelection.routePlan.selectedProviderId,
|
|
98
|
+
fallbackProviderIds: routeSelection.routePlan.fallbackProviderIds,
|
|
99
|
+
rejectedProviders: routeSelection.routePlan.rejectedProviders,
|
|
100
|
+
fallbackAvailable: providers.length > 1,
|
|
101
|
+
taskKind: request.task.kind,
|
|
102
|
+
explanation: routeSelection.explanation,
|
|
103
|
+
constraints: request.constraints ?? null,
|
|
104
|
+
preferences: request.preferences ?? null
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
// 3. Execute the run task using the planned provider chain
|
|
108
|
+
const attemptedProviderIds = [];
|
|
109
|
+
let lastError;
|
|
110
|
+
for (const [index, provider] of providers.entries()) {
|
|
111
|
+
const providerId = provider.describe().id;
|
|
112
|
+
attemptedProviderIds.push(providerId);
|
|
113
|
+
try {
|
|
114
|
+
const result = await provider.run(request, {
|
|
115
|
+
runId,
|
|
116
|
+
hostServices: this.hostServices
|
|
117
|
+
});
|
|
118
|
+
const endTime = this.hostServices.clock ? this.hostServices.clock.now() : Date.now();
|
|
119
|
+
const totalMs = endTime - startTime;
|
|
120
|
+
result.runId = runId;
|
|
121
|
+
result.telemetry = {
|
|
122
|
+
...result.telemetry,
|
|
123
|
+
providerUsed: providerId,
|
|
124
|
+
totalMs
|
|
125
|
+
};
|
|
126
|
+
this.safeEmit({
|
|
127
|
+
type: "attempt_succeeded",
|
|
128
|
+
runId,
|
|
129
|
+
timestamp: endTime,
|
|
130
|
+
payload: {
|
|
131
|
+
providerId,
|
|
132
|
+
durationMs: totalMs,
|
|
133
|
+
fallbackOccurred: index > 0,
|
|
134
|
+
attemptedProviderIds
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
lastError = toIndeRunException(err, {
|
|
141
|
+
providerId,
|
|
142
|
+
runId,
|
|
143
|
+
details: {
|
|
144
|
+
attemptedProviderIds,
|
|
145
|
+
fallbackOccurred: index > 0,
|
|
146
|
+
routePlan: routeSelection.routePlan
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const endTime = this.hostServices.clock ? this.hostServices.clock.now() : Date.now();
|
|
152
|
+
const totalMs = endTime - startTime;
|
|
153
|
+
const exception = toIndeRunException(lastError ?? new Error("No providers were attempted."), {
|
|
154
|
+
runId,
|
|
155
|
+
details: {
|
|
156
|
+
totalMs,
|
|
157
|
+
attemptedProviderIds,
|
|
158
|
+
fallbackOccurred: providers.length > 1,
|
|
159
|
+
routePlan: routeSelection.routePlan
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
throw exception;
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
const exception = toIndeRunException(error, {
|
|
166
|
+
runId,
|
|
167
|
+
details: {
|
|
168
|
+
totalMs: typeof error.details?.totalMs === "number"
|
|
169
|
+
? error.details?.totalMs
|
|
170
|
+
: (this.hostServices.clock ? this.hostServices.clock.now() : Date.now()) - startTime
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
const endTime = this.hostServices.clock ? this.hostServices.clock.now() : Date.now();
|
|
174
|
+
const totalMs = typeof exception.details?.totalMs === "number"
|
|
175
|
+
? exception.details?.totalMs
|
|
176
|
+
: endTime - startTime;
|
|
177
|
+
this.safeEmit({
|
|
178
|
+
type: "attempt_failed",
|
|
179
|
+
runId,
|
|
180
|
+
timestamp: endTime,
|
|
181
|
+
payload: {
|
|
182
|
+
providerId: exception.providerId ?? null,
|
|
183
|
+
durationMs: totalMs,
|
|
184
|
+
errorClass: exception.errorClass,
|
|
185
|
+
message: this.getStableMessage(exception.errorClass)
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
throw exception;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { IndeRunError, IndeRunErrorClass } from "@independo/inderun-contracts";
|
|
2
|
+
/**
|
|
3
|
+
* Parameter structure required to initialize an IndeRunException.
|
|
4
|
+
*/
|
|
5
|
+
export interface IndeRunExceptionParams {
|
|
6
|
+
/**
|
|
7
|
+
* The standardized error class (e.g. 'CapabilityMismatch', 'Offline').
|
|
8
|
+
*/
|
|
9
|
+
errorClass: IndeRunErrorClass;
|
|
10
|
+
/**
|
|
11
|
+
* Explanatory human-readable message.
|
|
12
|
+
*/
|
|
13
|
+
message: string;
|
|
14
|
+
/**
|
|
15
|
+
* The unique run ID where this exception occurred.
|
|
16
|
+
*/
|
|
17
|
+
runId?: string;
|
|
18
|
+
/**
|
|
19
|
+
* The provider ID that triggered the exception, if execution reached a provider.
|
|
20
|
+
*/
|
|
21
|
+
providerId?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Whether the client should retry this request.
|
|
24
|
+
*/
|
|
25
|
+
retryable?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Backoff time suggestion in milliseconds before retrying.
|
|
28
|
+
*/
|
|
29
|
+
retryAfterMs?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Rich contextual metadata regarding the error.
|
|
32
|
+
*/
|
|
33
|
+
details?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Standardized framework exception thrown when route selection or provider execution fails.
|
|
37
|
+
* Extends the native JavaScript Error class and exposes normalized error schema fields.
|
|
38
|
+
*/
|
|
39
|
+
export declare class IndeRunException extends Error {
|
|
40
|
+
/** The schema version matching the API contracts. */
|
|
41
|
+
readonly schemaVersion = "1.0";
|
|
42
|
+
/** The categorized class of error. */
|
|
43
|
+
readonly errorClass: IndeRunErrorClass;
|
|
44
|
+
/** The unique execution run ID. */
|
|
45
|
+
readonly runId?: string;
|
|
46
|
+
/** The provider ID responsible for the error. */
|
|
47
|
+
readonly providerId?: string;
|
|
48
|
+
/** Whether the error is transient and retryable. */
|
|
49
|
+
readonly retryable?: boolean;
|
|
50
|
+
/** Suggested cooling-down time in milliseconds before retry. */
|
|
51
|
+
readonly retryAfterMs?: number;
|
|
52
|
+
/** Custom details and metadata context. */
|
|
53
|
+
readonly details?: Record<string, unknown>;
|
|
54
|
+
constructor(params: IndeRunExceptionParams);
|
|
55
|
+
/**
|
|
56
|
+
* Converts the exception into a JSON-compatible contract-compliant IndeRunError.
|
|
57
|
+
*/
|
|
58
|
+
toContractError(): IndeRunError;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Factory helper for CapabilityMismatch error class.
|
|
62
|
+
*/
|
|
63
|
+
export declare function createCapabilityMismatch(message: string, extra?: Omit<IndeRunExceptionParams, "errorClass" | "message">): IndeRunException;
|
|
64
|
+
/**
|
|
65
|
+
* Factory helper for Offline error class.
|
|
66
|
+
*/
|
|
67
|
+
export declare function createOffline(message: string, extra?: Omit<IndeRunExceptionParams, "errorClass" | "message">): IndeRunException;
|
|
68
|
+
/**
|
|
69
|
+
* Factory helper for AuthError error class.
|
|
70
|
+
*/
|
|
71
|
+
export declare function createAuthError(message: string, extra?: Omit<IndeRunExceptionParams, "errorClass" | "message">): IndeRunException;
|
|
72
|
+
/**
|
|
73
|
+
* Factory helper for RateLimited error class.
|
|
74
|
+
*/
|
|
75
|
+
export declare function createRateLimited(message: string, extra?: Omit<IndeRunExceptionParams, "errorClass" | "message">): IndeRunException;
|
|
76
|
+
/**
|
|
77
|
+
* Factory helper for Timeout error class.
|
|
78
|
+
*/
|
|
79
|
+
export declare function createTimeout(message: string, extra?: Omit<IndeRunExceptionParams, "errorClass" | "message">): IndeRunException;
|
|
80
|
+
/**
|
|
81
|
+
* Factory helper for Unavailable error class.
|
|
82
|
+
*/
|
|
83
|
+
export declare function createUnavailable(message: string, extra?: Omit<IndeRunExceptionParams, "errorClass" | "message">): IndeRunException;
|
|
84
|
+
/**
|
|
85
|
+
* Factory helper for Internal error class.
|
|
86
|
+
*/
|
|
87
|
+
export declare function createInternal(message: string, extra?: Omit<IndeRunExceptionParams, "errorClass" | "message">): IndeRunException;
|
|
88
|
+
/**
|
|
89
|
+
* Standardizes any caught error into an IndeRunException.
|
|
90
|
+
* If the input error is already an IndeRunException, merges additional fallback parameters (like totalMs).
|
|
91
|
+
*/
|
|
92
|
+
export declare function toIndeRunException(error: unknown, fallbackParams?: Partial<Omit<IndeRunExceptionParams, "message">>): IndeRunException;
|
|
93
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/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"}
|