@independo/inderun-web 0.3.3 → 0.4.0-rc.1
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 +16 -7
- package/dist/core/engine.d.ts +26 -2
- package/dist/core/engine.d.ts.map +1 -1
- package/dist/core/engine.js +78 -34
- package/dist/core/errors.d.ts +13 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +32 -0
- package/dist/core/model-profiles.d.ts +34 -0
- package/dist/core/model-profiles.d.ts.map +1 -0
- package/dist/core/model-profiles.js +49 -0
- package/dist/core/provenance.d.ts +32 -0
- package/dist/core/provenance.d.ts.map +1 -0
- package/dist/core/provenance.js +71 -0
- package/dist/core/provider.d.ts +13 -0
- package/dist/core/provider.d.ts.map +1 -1
- package/dist/core/route-planner.d.ts +1 -1
- package/dist/core/route-planner.d.ts.map +1 -1
- package/dist/core/route-planner.js +2 -1
- package/dist/core/router.d.ts +4 -3
- package/dist/core/router.d.ts.map +1 -1
- package/dist/core/router.js +4 -3
- package/dist/facade/text.d.ts +123 -0
- package/dist/facade/text.d.ts.map +1 -0
- package/dist/facade/text.js +234 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/providers/onnx/provider.d.ts.map +1 -1
- package/dist/providers/onnx/provider.js +1 -0
- package/dist/providers/openai/provider.d.ts.map +1 -1
- package/dist/providers/openai/provider.js +18 -0
- package/dist/web-sdk.d.ts +19 -2
- package/dist/web-sdk.d.ts.map +1 -1
- package/dist/web-sdk.js +10 -2
- package/package.json +3 -3
- package/src/core/engine.ts +114 -35
- package/src/core/errors.ts +35 -1
- package/src/core/model-profiles.ts +70 -0
- package/src/core/provenance.ts +90 -0
- package/src/core/provider.ts +13 -0
- package/src/core/route-planner.ts +3 -1
- package/src/core/router.ts +12 -3
- package/src/facade/text.ts +349 -0
- package/src/index.ts +28 -2
- package/src/providers/onnx/provider.ts +1 -0
- package/src/providers/openai/provider.ts +21 -0
- package/src/web-sdk.ts +31 -5
package/README.md
CHANGED
|
@@ -15,26 +15,35 @@ The contract types this SDK's own signatures take and return — `TaskRequest`,
|
|
|
15
15
|
## Basic Usage
|
|
16
16
|
|
|
17
17
|
```ts
|
|
18
|
-
import { createIndeRunWeb } from "@independo/inderun-web";
|
|
18
|
+
import { createIndeRunWeb, generateText, streamText } from "@independo/inderun-web";
|
|
19
19
|
|
|
20
20
|
const inderun = createIndeRunWeb({
|
|
21
21
|
openAI: {
|
|
22
|
-
|
|
22
|
+
models: ["gpt-5.2"],
|
|
23
23
|
endpointUrl: "/api/inderun/openai-responses",
|
|
24
24
|
auth: "none"
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
prompt: "Write a one-sentence summary of IndeRun."
|
|
28
|
+
const { text, provenance } = await generateText(inderun, {
|
|
29
|
+
prompt: "Write a one-sentence summary of IndeRun.",
|
|
30
|
+
execution: { privacy: "local_preferred" }
|
|
32
31
|
});
|
|
32
|
+
|
|
33
|
+
const stream = await streamText(inderun, { system: "Use plain language.", prompt: "Explain routing." });
|
|
34
|
+
for await (const delta of stream.textStream) process.stdout.write(delta);
|
|
35
|
+
const { finishReason } = await stream.result;
|
|
33
36
|
```
|
|
34
37
|
|
|
38
|
+
`generateText` and `streamText` take `prompt` or `messages`, an optional `system`, `model` (a
|
|
39
|
+
[model profile](https://github.com/independo-gmbh/inderun/blob/main/docs/architecture/api-layering.md#model-profiles),
|
|
40
|
+
default `"auto"`), the usual sampling options, and an `execution` policy that reuses the canonical
|
|
41
|
+
constraint values. Each call compiles to one `TaskRequest` — `toTaskRequest(options)` shows which —
|
|
42
|
+
and runs through the engine below, so errors, fallback, and cancellation match the advanced API.
|
|
43
|
+
|
|
35
44
|
## Streaming
|
|
36
45
|
|
|
37
|
-
`stream()` returns the run handle, its canonical `StreamEvent` sequence, and a `cancel()` hook:
|
|
46
|
+
For the full event sequence, use the advanced API. `stream()` returns the run handle, its canonical `StreamEvent` sequence, and a `cancel()` hook:
|
|
38
47
|
|
|
39
48
|
```ts
|
|
40
49
|
const { handle, events, cancel } = await inderun.stream({
|
package/dist/core/engine.d.ts
CHANGED
|
@@ -4,12 +4,28 @@ import type { ProviderCapabilitySnapshot, StreamRun } from "./provider.js";
|
|
|
4
4
|
import type { IndeRunApi } from "./generated/inderun-api.js";
|
|
5
5
|
import { ProviderRegistry } from "./registry.js";
|
|
6
6
|
import { type TelemetryService } from "./telemetry.js";
|
|
7
|
+
import { type ModelProfiles } from "./model-profiles.js";
|
|
7
8
|
/**
|
|
8
9
|
* @deprecated Renamed to `StreamRun`, which is the name the generated
|
|
9
10
|
* `IndeRunApi` surface and the Swift/Kotlin SDKs use. Kept as an alias so the
|
|
10
11
|
* rename is not a breaking change.
|
|
11
12
|
*/
|
|
12
13
|
export type StreamHandleResult = StreamRun;
|
|
14
|
+
/**
|
|
15
|
+
* Optional engine configuration.
|
|
16
|
+
*/
|
|
17
|
+
export interface IndeRunOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Telemetry listener. Defaults to the host's telemetry service, then to a no-op.
|
|
20
|
+
*/
|
|
21
|
+
telemetryService?: TelemetryService;
|
|
22
|
+
/**
|
|
23
|
+
* Named model profiles requests can route within (`TaskRequest.modelProfile`).
|
|
24
|
+
* Each maps a profile name to an ordered list of target (provider instance) ids.
|
|
25
|
+
* `"auto"` is built in and cannot be redefined. See `docs/architecture/api-layering.md`.
|
|
26
|
+
*/
|
|
27
|
+
modelProfiles?: ModelProfiles;
|
|
28
|
+
}
|
|
13
29
|
/**
|
|
14
30
|
* Main orchestrator SDK entrypoint class.
|
|
15
31
|
* Validates tasks, executes routing rules based on request constraints and connectivity,
|
|
@@ -20,13 +36,21 @@ export declare class IndeRun implements IndeRunApi {
|
|
|
20
36
|
private hostServices;
|
|
21
37
|
private router;
|
|
22
38
|
private telemetryService;
|
|
39
|
+
private modelProfiles;
|
|
23
40
|
/**
|
|
24
41
|
* Initializes the IndeRun instance.
|
|
25
42
|
* @param registry - Registry filled with active providers.
|
|
26
43
|
* @param hostServices - Services wrapping OS interfaces and indicators.
|
|
27
|
-
* @param
|
|
44
|
+
* @param options - Optional telemetry listener and model profiles.
|
|
45
|
+
* @throws {Error} If a model profile is malformed (see {@link validateModelProfiles}).
|
|
46
|
+
*/
|
|
47
|
+
constructor(registry: ProviderRegistry, hostServices: HostServices, options?: IndeRunOptions);
|
|
48
|
+
/**
|
|
49
|
+
* Validates the request against the schema and resolves its model profile.
|
|
50
|
+
* Both failures are request validation errors: they are reported before any
|
|
51
|
+
* provider is probed, with the offending fields in `details.validationIssues`.
|
|
28
52
|
*/
|
|
29
|
-
|
|
53
|
+
private validateRequest;
|
|
30
54
|
/**
|
|
31
55
|
* Current time from the host clock, falling back to wall-clock time when the
|
|
32
56
|
* host does not supply one.
|
|
@@ -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;
|
|
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;AAElG,OAAO,EAEL,KAAK,aAAa,EAInB,MAAM,qBAAqB,CAAC;AAG7B;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED;;;;GAIG;AACH,qBAAa,OAAQ,YAAW,UAAU;IAatC,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,YAAY;IAbtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,aAAa,CAAgB;IAErC;;;;;;OAMG;gBAEO,QAAQ,EAAE,gBAAgB,EAC1B,YAAY,EAAE,YAAY,EAClC,OAAO,GAAE,cAAmB;IAS9B;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAkBvB;;;OAGG;IACH,OAAO,CAAC,GAAG;IAIX;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAwBxB;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAShB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;;;;;;OAOG;IACG,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IA4HpD;;;;;;;;;;;;;;;;;OAiBG;IACG,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC;IAoRtD;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC;CASjE"}
|
package/dist/core/engine.js
CHANGED
|
@@ -4,6 +4,8 @@ import { Router } from "./router.js";
|
|
|
4
4
|
import { createCapabilityMismatch, createInternal, createUnavailable, toIndeRunException } from "./errors.js";
|
|
5
5
|
import { NoOpTelemetryService } from "./telemetry.js";
|
|
6
6
|
import { EventGate } from "./event-gate.js";
|
|
7
|
+
import { AUTO_MODEL_PROFILE, resolveModelProfile, validateModelProfiles } from "./model-profiles.js";
|
|
8
|
+
import { ProvenanceRecorder } from "./provenance.js";
|
|
7
9
|
/**
|
|
8
10
|
* Main orchestrator SDK entrypoint class.
|
|
9
11
|
* Validates tasks, executes routing rules based on request constraints and connectivity,
|
|
@@ -14,18 +16,44 @@ export class IndeRun {
|
|
|
14
16
|
hostServices;
|
|
15
17
|
router;
|
|
16
18
|
telemetryService;
|
|
19
|
+
modelProfiles;
|
|
17
20
|
/**
|
|
18
21
|
* Initializes the IndeRun instance.
|
|
19
22
|
* @param registry - Registry filled with active providers.
|
|
20
23
|
* @param hostServices - Services wrapping OS interfaces and indicators.
|
|
21
|
-
* @param
|
|
24
|
+
* @param options - Optional telemetry listener and model profiles.
|
|
25
|
+
* @throws {Error} If a model profile is malformed (see {@link validateModelProfiles}).
|
|
22
26
|
*/
|
|
23
|
-
constructor(registry, hostServices,
|
|
27
|
+
constructor(registry, hostServices, options = {}) {
|
|
24
28
|
this.registry = registry;
|
|
25
29
|
this.hostServices = hostServices;
|
|
26
30
|
this.router = new Router(this.registry);
|
|
27
31
|
this.telemetryService =
|
|
28
|
-
telemetryService || this.hostServices.telemetry || new NoOpTelemetryService();
|
|
32
|
+
options.telemetryService || this.hostServices.telemetry || new NoOpTelemetryService();
|
|
33
|
+
this.modelProfiles = options.modelProfiles ?? {};
|
|
34
|
+
validateModelProfiles(this.modelProfiles);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Validates the request against the schema and resolves its model profile.
|
|
38
|
+
* Both failures are request validation errors: they are reported before any
|
|
39
|
+
* provider is probed, with the offending fields in `details.validationIssues`.
|
|
40
|
+
*/
|
|
41
|
+
validateRequest(request, runId) {
|
|
42
|
+
const validationIssues = getTaskRequestValidationIssues(request);
|
|
43
|
+
if (validationIssues.length === 0) {
|
|
44
|
+
const resolved = resolveModelProfile(this.modelProfiles, request.modelProfile);
|
|
45
|
+
if (resolved.known) {
|
|
46
|
+
return resolved.profile;
|
|
47
|
+
}
|
|
48
|
+
validationIssues.push({
|
|
49
|
+
path: "/modelProfile",
|
|
50
|
+
message: `unknown model profile "${request.modelProfile}"; configure it in the engine's modelProfiles`
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
const message = `Validation failed for TaskRequest: ${validationIssues
|
|
54
|
+
.map((i) => `${i.path} - ${i.message}`)
|
|
55
|
+
.join("; ")}`;
|
|
56
|
+
throw createInternal(message, { runId, details: { validationIssues } });
|
|
29
57
|
}
|
|
30
58
|
/**
|
|
31
59
|
* Current time from the host clock, falling back to wall-clock time when the
|
|
@@ -50,6 +78,7 @@ export class IndeRun {
|
|
|
50
78
|
rejectedProviders: routeSelection.routePlan.rejectedProviders,
|
|
51
79
|
fallbackAvailable: providerCount > 1,
|
|
52
80
|
taskKind: request.task.kind,
|
|
81
|
+
modelProfile: request.modelProfile ?? "auto",
|
|
53
82
|
constraints: request.constraints ?? null,
|
|
54
83
|
preferences: request.preferences ?? null,
|
|
55
84
|
explanation: routeSelection.explanation
|
|
@@ -103,21 +132,14 @@ export class IndeRun {
|
|
|
103
132
|
async run(request) {
|
|
104
133
|
const startTime = this.now();
|
|
105
134
|
const runId = request.requestId || `run_${Math.random().toString(36).substring(2, 11)}`;
|
|
135
|
+
const provenance = new ProvenanceRecorder(request.modelProfile ?? AUTO_MODEL_PROFILE);
|
|
106
136
|
try {
|
|
107
|
-
// 1. Validate request payload using schema contracts
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
.map((i) => `${i.path} - ${i.message}`)
|
|
112
|
-
.join("; ")}`;
|
|
113
|
-
throw createInternal(message, {
|
|
114
|
-
runId,
|
|
115
|
-
details: { validationIssues }
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
// 2. Select the route based on constraints and host capabilities
|
|
119
|
-
const routeSelection = await this.router.selectRoute(request, this.hostServices, "run");
|
|
137
|
+
// 1. Validate request payload using schema contracts and resolve its model profile
|
|
138
|
+
const modelProfile = this.validateRequest(request, runId);
|
|
139
|
+
// 2. Select the route based on constraints, model profile, and host capabilities
|
|
140
|
+
const routeSelection = await this.router.selectRoute(request, this.hostServices, "run", modelProfile);
|
|
120
141
|
const providers = [routeSelection.provider, ...routeSelection.fallbackProviders];
|
|
142
|
+
provenance.routed(routeSelection.routePlan);
|
|
121
143
|
this.emitRouteDecided(runId, request, routeSelection, providers.length);
|
|
122
144
|
// 3. Execute the run task using the planned provider chain
|
|
123
145
|
const attemptedProviderIds = [];
|
|
@@ -138,6 +160,8 @@ export class IndeRun {
|
|
|
138
160
|
providerUsed: providerId,
|
|
139
161
|
totalMs
|
|
140
162
|
};
|
|
163
|
+
provenance.attempted(providerId, "succeeded");
|
|
164
|
+
result.provenance = provenance.build(provider.describe(), result.telemetry.reportedModel);
|
|
141
165
|
this.safeEmit({
|
|
142
166
|
type: "attempt_succeeded",
|
|
143
167
|
runId,
|
|
@@ -152,7 +176,7 @@ export class IndeRun {
|
|
|
152
176
|
return result;
|
|
153
177
|
}
|
|
154
178
|
catch (err) {
|
|
155
|
-
|
|
179
|
+
const attemptError = toIndeRunException(err, {
|
|
156
180
|
providerId,
|
|
157
181
|
runId,
|
|
158
182
|
details: {
|
|
@@ -161,6 +185,8 @@ export class IndeRun {
|
|
|
161
185
|
routePlan: routeSelection.routePlan
|
|
162
186
|
}
|
|
163
187
|
});
|
|
188
|
+
provenance.attempted(providerId, "failed", attemptError.errorClass);
|
|
189
|
+
lastError = attemptError;
|
|
164
190
|
}
|
|
165
191
|
}
|
|
166
192
|
const endTime = this.now();
|
|
@@ -170,14 +196,14 @@ export class IndeRun {
|
|
|
170
196
|
details: {
|
|
171
197
|
totalMs,
|
|
172
198
|
attemptedProviderIds,
|
|
173
|
-
fallbackOccurred:
|
|
199
|
+
fallbackOccurred: attemptedProviderIds.length > 1,
|
|
174
200
|
routePlan: routeSelection.routePlan
|
|
175
201
|
}
|
|
176
202
|
});
|
|
177
203
|
throw exception;
|
|
178
204
|
}
|
|
179
205
|
catch (error) {
|
|
180
|
-
const
|
|
206
|
+
const normalized = toIndeRunException(error, {
|
|
181
207
|
runId,
|
|
182
208
|
details: {
|
|
183
209
|
totalMs: typeof error.details?.totalMs === "number"
|
|
@@ -185,6 +211,10 @@ export class IndeRun {
|
|
|
185
211
|
: this.now() - startTime
|
|
186
212
|
}
|
|
187
213
|
});
|
|
214
|
+
// A routing refusal throws before any attempt; its rejections travel on the details.
|
|
215
|
+
provenance.routingFailed(normalized.details);
|
|
216
|
+
// No attempt produced the result, so the outcome is attributed to no provider.
|
|
217
|
+
const exception = normalized.withProvenance(provenance.build());
|
|
188
218
|
const endTime = this.now();
|
|
189
219
|
const totalMs = typeof exception.details?.totalMs === "number"
|
|
190
220
|
? exception.details?.totalMs
|
|
@@ -225,24 +255,28 @@ export class IndeRun {
|
|
|
225
255
|
const startTime = this.now();
|
|
226
256
|
const now = () => this.now();
|
|
227
257
|
const runId = request.requestId || `run_${Math.random().toString(36).substring(2, 11)}`;
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
258
|
+
const provenance = new ProvenanceRecorder(request.modelProfile ?? AUTO_MODEL_PROFILE);
|
|
259
|
+
let modelProfile;
|
|
260
|
+
try {
|
|
261
|
+
modelProfile = this.validateRequest(request, runId);
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
throw toIndeRunException(error, { runId }).withProvenance(provenance.build());
|
|
234
265
|
}
|
|
235
266
|
// Route selection failures are the one class of stream error that surfaces as a
|
|
236
267
|
// rejected promise instead of a terminal event, so they must still carry the
|
|
237
268
|
// runId — there is no handle for the caller to correlate them with otherwise.
|
|
238
269
|
let routeSelection;
|
|
239
270
|
try {
|
|
240
|
-
routeSelection = await this.router.selectRoute(request, this.hostServices, "stream");
|
|
271
|
+
routeSelection = await this.router.selectRoute(request, this.hostServices, "stream", modelProfile);
|
|
241
272
|
}
|
|
242
273
|
catch (error) {
|
|
243
|
-
|
|
274
|
+
const exception = toIndeRunException(error, { runId });
|
|
275
|
+
provenance.routingFailed(exception.details);
|
|
276
|
+
throw exception.withProvenance(provenance.build());
|
|
244
277
|
}
|
|
245
278
|
const providers = [routeSelection.provider, ...routeSelection.fallbackProviders];
|
|
279
|
+
provenance.routed(routeSelection.routePlan);
|
|
246
280
|
this.emitRouteDecided(runId, request, routeSelection, providers.length);
|
|
247
281
|
// Defensive only: streaming eligibility is decided by the route planner, which
|
|
248
282
|
// throws with its own rejection reasons when nothing can stream. Reaching here
|
|
@@ -267,14 +301,18 @@ export class IndeRun {
|
|
|
267
301
|
async function* run() {
|
|
268
302
|
const attemptedProviderIds = [];
|
|
269
303
|
let committed = false;
|
|
270
|
-
const cancelledOutcome = (partialText) => {
|
|
304
|
+
const cancelledOutcome = (partialText, cancelledProvider) => {
|
|
271
305
|
const reason = typeof controller.signal.reason === "string" ? controller.signal.reason : undefined;
|
|
306
|
+
if (cancelledProvider !== undefined) {
|
|
307
|
+
provenance.attempted(cancelledProvider.describe().id, "cancelled");
|
|
308
|
+
}
|
|
272
309
|
return {
|
|
273
310
|
outcome: "cancelled",
|
|
274
311
|
runId,
|
|
275
312
|
schemaVersion: "1.0",
|
|
276
313
|
partialText,
|
|
277
|
-
...(reason !== undefined ? { reason } : {})
|
|
314
|
+
...(reason !== undefined ? { reason } : {}),
|
|
315
|
+
provenance: provenance.build(cancelledProvider?.describe())
|
|
278
316
|
};
|
|
279
317
|
};
|
|
280
318
|
for (const [index, provider] of providers.entries()) {
|
|
@@ -325,6 +363,7 @@ export class IndeRun {
|
|
|
325
363
|
continue;
|
|
326
364
|
}
|
|
327
365
|
// ev.kind === "done"
|
|
366
|
+
provenance.attempted(providerId, "succeeded");
|
|
328
367
|
const outcome = {
|
|
329
368
|
outcome: "completed",
|
|
330
369
|
runId,
|
|
@@ -332,7 +371,8 @@ export class IndeRun {
|
|
|
332
371
|
finalText: ev.finalText,
|
|
333
372
|
telemetry: { providerUsed: providerId, totalMs: now() - startTime },
|
|
334
373
|
...(ev.finishReason !== undefined ? { finishReason: ev.finishReason } : {}),
|
|
335
|
-
...(ev.usage !== undefined ? { usage: ev.usage } : {})
|
|
374
|
+
...(ev.usage !== undefined ? { usage: ev.usage } : {}),
|
|
375
|
+
provenance: provenance.build(provider.describe(), ev.reportedModel)
|
|
336
376
|
};
|
|
337
377
|
const terminal = gate.terminate(outcome, now());
|
|
338
378
|
safeEmit({
|
|
@@ -350,7 +390,7 @@ export class IndeRun {
|
|
|
350
390
|
return;
|
|
351
391
|
}
|
|
352
392
|
if (controller.signal.aborted) {
|
|
353
|
-
const terminal = gate.terminate(cancelledOutcome(partialText), now());
|
|
393
|
+
const terminal = gate.terminate(cancelledOutcome(partialText, provider), now());
|
|
354
394
|
safeEmit({
|
|
355
395
|
type: "stream_cancelled",
|
|
356
396
|
runId,
|
|
@@ -366,7 +406,7 @@ export class IndeRun {
|
|
|
366
406
|
}
|
|
367
407
|
catch (err) {
|
|
368
408
|
if (controller.signal.aborted) {
|
|
369
|
-
const terminal = gate.terminate(cancelledOutcome(partialText), now());
|
|
409
|
+
const terminal = gate.terminate(cancelledOutcome(partialText, provider), now());
|
|
370
410
|
safeEmit({
|
|
371
411
|
type: "stream_cancelled",
|
|
372
412
|
runId,
|
|
@@ -382,6 +422,7 @@ export class IndeRun {
|
|
|
382
422
|
runId,
|
|
383
423
|
details: { attemptedProviderIds }
|
|
384
424
|
});
|
|
425
|
+
provenance.attempted(providerId, "failed", exception.errorClass);
|
|
385
426
|
if (!committed) {
|
|
386
427
|
safeEmit({
|
|
387
428
|
type: "stream_attempt_failed",
|
|
@@ -395,12 +436,14 @@ export class IndeRun {
|
|
|
395
436
|
});
|
|
396
437
|
continue;
|
|
397
438
|
}
|
|
439
|
+
// Committed: the failure belongs to this provider, not to the chain.
|
|
398
440
|
const outcome = {
|
|
399
441
|
outcome: "error",
|
|
400
442
|
runId,
|
|
401
443
|
schemaVersion: "1.0",
|
|
402
444
|
error: exception.toContractError(),
|
|
403
|
-
partialText
|
|
445
|
+
partialText,
|
|
446
|
+
provenance: provenance.build(provider.describe())
|
|
404
447
|
};
|
|
405
448
|
const terminal = gate.terminate(outcome, now());
|
|
406
449
|
safeEmit({
|
|
@@ -441,7 +484,8 @@ export class IndeRun {
|
|
|
441
484
|
runId,
|
|
442
485
|
schemaVersion: "1.0",
|
|
443
486
|
error: exception.toContractError(),
|
|
444
|
-
partialText: ""
|
|
487
|
+
partialText: "",
|
|
488
|
+
provenance: provenance.build()
|
|
445
489
|
};
|
|
446
490
|
const terminal = gate.terminate(outcome, now());
|
|
447
491
|
safeEmit({
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IndeRunError, IndeRunErrorClass } from "@independo/inderun-contracts";
|
|
1
|
+
import type { ExecutionProvenance, IndeRunError, IndeRunErrorClass } from "@independo/inderun-contracts";
|
|
2
2
|
/**
|
|
3
3
|
* Parameter structure required to initialize an IndeRunException.
|
|
4
4
|
*/
|
|
@@ -31,6 +31,10 @@ export interface IndeRunExceptionParams {
|
|
|
31
31
|
* Rich contextual metadata regarding the error.
|
|
32
32
|
*/
|
|
33
33
|
details?: Record<string, unknown>;
|
|
34
|
+
/**
|
|
35
|
+
* How the failed execution played out, attached by the engine.
|
|
36
|
+
*/
|
|
37
|
+
provenance?: ExecutionProvenance;
|
|
34
38
|
}
|
|
35
39
|
/**
|
|
36
40
|
* Standardized framework exception thrown when route selection or provider execution fails.
|
|
@@ -51,11 +55,19 @@ export declare class IndeRunException extends Error {
|
|
|
51
55
|
readonly retryAfterMs?: number;
|
|
52
56
|
/** Custom details and metadata context. */
|
|
53
57
|
readonly details?: Record<string, unknown>;
|
|
58
|
+
/** How the failed execution played out: attempts, rejections, the provider committed to. */
|
|
59
|
+
readonly provenance?: ExecutionProvenance;
|
|
54
60
|
constructor(params: IndeRunExceptionParams);
|
|
55
61
|
/**
|
|
56
62
|
* Converts the exception into a JSON-compatible contract-compliant IndeRunError.
|
|
57
63
|
*/
|
|
58
64
|
toContractError(): IndeRunError;
|
|
65
|
+
/**
|
|
66
|
+
* A copy of this exception carrying `provenance`. The engine attaches provenance once it
|
|
67
|
+
* knows how the whole execution ended, replacing anything set earlier.
|
|
68
|
+
*/
|
|
69
|
+
withProvenance(provenance: ExecutionProvenance): IndeRunException;
|
|
70
|
+
private params;
|
|
59
71
|
}
|
|
60
72
|
/**
|
|
61
73
|
* Factory helper for CapabilityMismatch error class.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/core/errors.js
CHANGED
|
@@ -17,6 +17,8 @@ export class IndeRunException extends Error {
|
|
|
17
17
|
retryAfterMs;
|
|
18
18
|
/** Custom details and metadata context. */
|
|
19
19
|
details;
|
|
20
|
+
/** How the failed execution played out: attempts, rejections, the provider committed to. */
|
|
21
|
+
provenance;
|
|
20
22
|
constructor(params) {
|
|
21
23
|
super(params.message);
|
|
22
24
|
this.name = "IndeRunException";
|
|
@@ -31,6 +33,8 @@ export class IndeRunException extends Error {
|
|
|
31
33
|
this.retryAfterMs = params.retryAfterMs;
|
|
32
34
|
if (params.details !== undefined)
|
|
33
35
|
this.details = params.details;
|
|
36
|
+
if (params.provenance !== undefined)
|
|
37
|
+
this.provenance = params.provenance;
|
|
34
38
|
Object.setPrototypeOf(this, IndeRunException.prototype);
|
|
35
39
|
}
|
|
36
40
|
/**
|
|
@@ -52,8 +56,33 @@ export class IndeRunException extends Error {
|
|
|
52
56
|
err.retryAfterMs = this.retryAfterMs;
|
|
53
57
|
if (this.details !== undefined)
|
|
54
58
|
err.details = this.details;
|
|
59
|
+
if (this.provenance !== undefined)
|
|
60
|
+
err.provenance = this.provenance;
|
|
55
61
|
return err;
|
|
56
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* A copy of this exception carrying `provenance`. The engine attaches provenance once it
|
|
65
|
+
* knows how the whole execution ended, replacing anything set earlier.
|
|
66
|
+
*/
|
|
67
|
+
withProvenance(provenance) {
|
|
68
|
+
return new IndeRunException({ ...this.params(), provenance });
|
|
69
|
+
}
|
|
70
|
+
params() {
|
|
71
|
+
const params = { errorClass: this.errorClass, message: this.message };
|
|
72
|
+
if (this.runId !== undefined)
|
|
73
|
+
params.runId = this.runId;
|
|
74
|
+
if (this.providerId !== undefined)
|
|
75
|
+
params.providerId = this.providerId;
|
|
76
|
+
if (this.retryable !== undefined)
|
|
77
|
+
params.retryable = this.retryable;
|
|
78
|
+
if (this.retryAfterMs !== undefined)
|
|
79
|
+
params.retryAfterMs = this.retryAfterMs;
|
|
80
|
+
if (this.details !== undefined)
|
|
81
|
+
params.details = this.details;
|
|
82
|
+
if (this.provenance !== undefined)
|
|
83
|
+
params.provenance = this.provenance;
|
|
84
|
+
return params;
|
|
85
|
+
}
|
|
57
86
|
}
|
|
58
87
|
/**
|
|
59
88
|
* Factory helper for CapabilityMismatch error class.
|
|
@@ -126,6 +155,9 @@ export function toIndeRunException(error, fallbackParams) {
|
|
|
126
155
|
...(fallbackParams.details || {})
|
|
127
156
|
};
|
|
128
157
|
}
|
|
158
|
+
const provenance = error.provenance ?? fallbackParams.provenance;
|
|
159
|
+
if (provenance !== undefined)
|
|
160
|
+
mergedParams.provenance = provenance;
|
|
129
161
|
return new IndeRunException(mergedParams);
|
|
130
162
|
}
|
|
131
163
|
return error;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { SharedPlannerInput } from "./route-planner.js";
|
|
2
|
+
/**
|
|
3
|
+
* The built-in profile: every registered target, ranked by constraints and
|
|
4
|
+
* preferences alone. Requests that name no profile route within it.
|
|
5
|
+
*/
|
|
6
|
+
export declare const AUTO_MODEL_PROFILE = "auto";
|
|
7
|
+
/**
|
|
8
|
+
* Application-defined model profiles: a profile name mapped to an ordered list of
|
|
9
|
+
* target ids (provider instance ids, each bound to one model). Requests name a
|
|
10
|
+
* profile through `TaskRequest.modelProfile`; the route planner treats the list as
|
|
11
|
+
* an allow-list and ranks its entries after placement and before preferences.
|
|
12
|
+
* Ids that name no registered provider are ignored by the planner.
|
|
13
|
+
*/
|
|
14
|
+
export type ModelProfiles = Readonly<Record<string, readonly string[]>>;
|
|
15
|
+
/** A resolved profile as the shared planner consumes it; absent means `auto`. */
|
|
16
|
+
export type ResolvedModelProfile = SharedPlannerInput["modelProfile"];
|
|
17
|
+
/**
|
|
18
|
+
* Checks profile configuration once, when the engine is constructed, so a
|
|
19
|
+
* malformed profile is a setup error rather than a per-request surprise.
|
|
20
|
+
* @throws {Error} When a profile is named `auto`, is empty, or lists a target twice.
|
|
21
|
+
*/
|
|
22
|
+
export declare function validateModelProfiles(profiles: ModelProfiles): void;
|
|
23
|
+
/**
|
|
24
|
+
* Resolves a request's profile name against the configured profiles.
|
|
25
|
+
* @returns `{ known: true }` with the planner input (undefined for `auto`), or
|
|
26
|
+
* `{ known: false }` when the name matches no configured profile.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveModelProfile(profiles: ModelProfiles, name: string | undefined): {
|
|
29
|
+
known: true;
|
|
30
|
+
profile: ResolvedModelProfile;
|
|
31
|
+
} | {
|
|
32
|
+
known: false;
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=model-profiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-profiles.d.ts","sourceRoot":"","sources":["../../src/core/model-profiles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D;;;GAGG;AACH,eAAO,MAAM,kBAAkB,SAAS,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;AAExE,iFAAiF;AACjF,MAAM,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;AAEtE;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAwBnE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,aAAa,EACvB,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,CAUnE"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The built-in profile: every registered target, ranked by constraints and
|
|
3
|
+
* preferences alone. Requests that name no profile route within it.
|
|
4
|
+
*/
|
|
5
|
+
export const AUTO_MODEL_PROFILE = "auto";
|
|
6
|
+
/**
|
|
7
|
+
* Checks profile configuration once, when the engine is constructed, so a
|
|
8
|
+
* malformed profile is a setup error rather than a per-request surprise.
|
|
9
|
+
* @throws {Error} When a profile is named `auto`, is empty, or lists a target twice.
|
|
10
|
+
*/
|
|
11
|
+
export function validateModelProfiles(profiles) {
|
|
12
|
+
for (const [name, targetIds] of Object.entries(profiles)) {
|
|
13
|
+
if (name.length === 0) {
|
|
14
|
+
throw new Error("Model profile names must be non-empty.");
|
|
15
|
+
}
|
|
16
|
+
if (name === AUTO_MODEL_PROFILE) {
|
|
17
|
+
throw new Error(`"${AUTO_MODEL_PROFILE}" is the built-in model profile and cannot be redefined.`);
|
|
18
|
+
}
|
|
19
|
+
if (targetIds.length === 0) {
|
|
20
|
+
throw new Error(`Model profile "${name}" must list at least one target id.`);
|
|
21
|
+
}
|
|
22
|
+
const seen = new Set();
|
|
23
|
+
for (const id of targetIds) {
|
|
24
|
+
if (id.length === 0) {
|
|
25
|
+
throw new Error(`Model profile "${name}" lists an empty target id.`);
|
|
26
|
+
}
|
|
27
|
+
if (seen.has(id)) {
|
|
28
|
+
throw new Error(`Model profile "${name}" lists target "${id}" more than once.`);
|
|
29
|
+
}
|
|
30
|
+
seen.add(id);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolves a request's profile name against the configured profiles.
|
|
36
|
+
* @returns `{ known: true }` with the planner input (undefined for `auto`), or
|
|
37
|
+
* `{ known: false }` when the name matches no configured profile.
|
|
38
|
+
*/
|
|
39
|
+
export function resolveModelProfile(profiles, name) {
|
|
40
|
+
if (name === undefined || name === AUTO_MODEL_PROFILE) {
|
|
41
|
+
return { known: true, profile: undefined };
|
|
42
|
+
}
|
|
43
|
+
if (!Object.hasOwn(profiles, name)) {
|
|
44
|
+
return { known: false };
|
|
45
|
+
}
|
|
46
|
+
// validateModelProfiles guarantees every configured profile is non-empty.
|
|
47
|
+
const [first, ...rest] = profiles[name];
|
|
48
|
+
return { known: true, profile: { name, targetIds: [first, ...rest] } };
|
|
49
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ExecutionProvenance, IndeRunErrorClass } from "@independo/inderun-contracts";
|
|
2
|
+
import type { ProviderDescriptor } from "./provider.js";
|
|
3
|
+
import type { SharedPlannerRoutePlan } from "./route-planner.js";
|
|
4
|
+
type ExecutionProvenanceAttempt = ExecutionProvenance["attempts"][number];
|
|
5
|
+
/**
|
|
6
|
+
* Accumulates what one execution did -- each attempt and how it ended -- and renders it as the
|
|
7
|
+
* normalized {@link ExecutionProvenance} carried on results, terminal outcomes, and errors.
|
|
8
|
+
*
|
|
9
|
+
* Everything recorded is either observed by the engine (attempts, their outcomes) or declared or
|
|
10
|
+
* reported by a provider (descriptor type and model, the model a response names). Nothing is
|
|
11
|
+
* inferred: an unknown is left absent or reported as `unknown`.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ProvenanceRecorder {
|
|
14
|
+
private readonly modelProfile;
|
|
15
|
+
private readonly attempts;
|
|
16
|
+
private routeRejections;
|
|
17
|
+
constructor(modelProfile?: string);
|
|
18
|
+
/** Records the planner's rejections; codes only, never the provider-supplied messages. */
|
|
19
|
+
routed(routePlan: SharedPlannerRoutePlan): void;
|
|
20
|
+
/** Records the rejections a routing failure carried out on its exception's details. */
|
|
21
|
+
routingFailed(details: Record<string, unknown> | undefined): void;
|
|
22
|
+
/** Records how one provider attempt ended. */
|
|
23
|
+
attempted(providerId: string, outcome: ExecutionProvenanceAttempt["outcome"], errorClass?: IndeRunErrorClass): void;
|
|
24
|
+
/**
|
|
25
|
+
* Renders the record. `attributedTo` is the provider the outcome belongs to -- the one that
|
|
26
|
+
* produced the result, the one a stream was committed to, or the one running at cancellation --
|
|
27
|
+
* and is absent when no provider was reached or every attempt failed before a commit.
|
|
28
|
+
*/
|
|
29
|
+
build(attributedTo?: ProviderDescriptor, reportedModel?: string): ExecutionProvenance;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=provenance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../../src/core/provenance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAC3F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGjE,KAAK,0BAA0B,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAG1E;;;;;;;GAOG;AACH,qBAAa,kBAAkB;IAIjB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAHzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;IAC7D,OAAO,CAAC,eAAe,CAAwB;gBAElB,YAAY,GAAE,MAA2B;IAEtE,0FAA0F;IAC1F,MAAM,CAAC,SAAS,EAAE,sBAAsB,GAAG,IAAI;IAI/C,uFAAuF;IACvF,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI;IASjE,8CAA8C;IAC9C,SAAS,CACP,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,0BAA0B,CAAC,SAAS,CAAC,EAC9C,UAAU,CAAC,EAAE,iBAAiB,GAC7B,IAAI;IAQP;;;;OAIG;IACH,KAAK,CAAC,YAAY,CAAC,EAAE,kBAAkB,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,mBAAmB;CActF"}
|