@rarebit-one/harness-kernel 0.18.0 → 0.19.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 +256 -16
- package/dist/agent.d.ts +29 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +145 -31
- package/dist/agent.js.map +1 -1
- package/dist/connectors/auth.d.ts +32 -0
- package/dist/connectors/auth.d.ts.map +1 -0
- package/dist/connectors/auth.js +85 -0
- package/dist/connectors/auth.js.map +1 -0
- package/dist/connectors/mcpClient.d.ts +14 -4
- package/dist/connectors/mcpClient.d.ts.map +1 -1
- package/dist/connectors/mcpClient.js +32 -11
- package/dist/connectors/mcpClient.js.map +1 -1
- package/dist/engines/acp.d.ts.map +1 -1
- package/dist/engines/acp.js +2 -1
- package/dist/engines/acp.js.map +1 -1
- package/dist/engines/capability.d.ts +1 -1
- package/dist/engines/capability.js +1 -1
- package/dist/engines/claudeCode.d.ts.map +1 -1
- package/dist/engines/claudeCode.js +2 -1
- package/dist/engines/claudeCode.js.map +1 -1
- package/dist/engines/claudeCodeDriver.d.ts.map +1 -1
- package/dist/engines/claudeCodeDriver.js +4 -3
- package/dist/engines/claudeCodeDriver.js.map +1 -1
- package/dist/engines/codex.d.ts +6 -5
- package/dist/engines/codex.d.ts.map +1 -1
- package/dist/engines/codex.js +6 -5
- package/dist/engines/codex.js.map +1 -1
- package/dist/engines/codexDriver.d.ts +1 -1
- package/dist/engines/codexDriver.js +1 -1
- package/dist/engines/connectorMcp.d.ts +13 -0
- package/dist/engines/connectorMcp.d.ts.map +1 -1
- package/dist/engines/connectorMcp.js +23 -0
- package/dist/engines/connectorMcp.js.map +1 -1
- package/dist/engines/gateway.d.ts +5 -2
- package/dist/engines/gateway.d.ts.map +1 -1
- package/dist/engines/gateway.js +7 -2
- package/dist/engines/gateway.js.map +1 -1
- package/dist/engines/native.d.ts.map +1 -1
- package/dist/engines/native.js +10 -3
- package/dist/engines/native.js.map +1 -1
- package/dist/engines/types.d.ts +10 -1
- package/dist/engines/types.d.ts.map +1 -1
- package/dist/events.d.ts +22 -8
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/loop.d.ts +28 -1
- package/dist/loop.d.ts.map +1 -1
- package/dist/loop.js +1 -0
- package/dist/loop.js.map +1 -1
- package/dist/models/chat.d.ts +12 -6
- package/dist/models/chat.d.ts.map +1 -1
- package/dist/models/chat.js +11 -6
- package/dist/models/chat.js.map +1 -1
- package/dist/models/retry.d.ts +259 -0
- package/dist/models/retry.d.ts.map +1 -0
- package/dist/models/retry.js +409 -0
- package/dist/models/retry.js.map +1 -0
- package/dist/models/types.d.ts +7 -0
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js.map +1 -1
- package/dist/private.d.ts.map +1 -1
- package/dist/private.js +12 -2
- package/dist/private.js.map +1 -1
- package/dist/processGroup.d.ts +10 -2
- package/dist/processGroup.d.ts.map +1 -1
- package/dist/processGroup.js +29 -2
- package/dist/processGroup.js.map +1 -1
- package/dist/secrets.d.ts +17 -7
- package/dist/secrets.d.ts.map +1 -1
- package/dist/secrets.js +38 -24
- package/dist/secrets.js.map +1 -1
- package/dist/tools/concurrency.d.ts +48 -0
- package/dist/tools/concurrency.d.ts.map +1 -0
- package/dist/tools/concurrency.js +64 -0
- package/dist/tools/concurrency.js.map +1 -0
- package/dist/tools/metadata.d.ts +18 -3
- package/dist/tools/metadata.d.ts.map +1 -1
- package/dist/tools/metadata.js +7 -0
- package/dist/tools/metadata.js.map +1 -1
- package/dist/tools/registry.d.ts +6 -4
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +5 -3
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/terminal.d.ts +8 -6
- package/dist/tools/terminal.d.ts.map +1 -1
- package/dist/tools/terminal.js +8 -6
- package/dist/tools/terminal.js.map +1 -1
- package/dist/tools/validate.d.ts +49 -0
- package/dist/tools/validate.d.ts.map +1 -0
- package/dist/tools/validate.js +346 -0
- package/dist/tools/validate.js.map +1 -0
- package/dist/transcript.d.ts +53 -0
- package/dist/transcript.d.ts.map +1 -0
- package/dist/transcript.js +104 -0
- package/dist/transcript.js.map +1 -0
- package/dist/types.d.ts +44 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/models/chat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAC9D,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,QAAQ,EACR,QAAQ,EACT,MAAM,uBAAuB,CAAA;AAC9B,OAAO,
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/models/chat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAC9D,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,QAAQ,EACR,QAAQ,EACT,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,eAAe,EAErB,MAAM,YAAY,CAAA;AAEnB;;;GAGG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpD;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAAA;AAEzC;;;;GAIG;AACH,MAAM,WAAW,WAAY,SAAQ,eAAe;IAClD;;;;OAIG;IACH,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAA;CACnB;AAED,+EAA+E;AAC/E,MAAM,MAAM,YAAY,GAAG,cAAc,CAAA;AAEzC,yCAAyC;AACzC,MAAM,MAAM,SAAS,GAAG,eAAe,CAAC,WAAW,EAAE,YAAY,CAAC,CAAA;AAElE,wDAAwD;AACxD,eAAO,MAAM,SAAS,SAAS,CAAA;AAE/B;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,GAAE,OAAO,CAAC,SAAS,CAAM,GAAG,SAAS,CAoEtF;AAED,qFAAqF;AACrF,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,KAAK,IAAI,SAAS,CAE3E;AAED,kFAAkF;AAClF,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAElE;AAED,4DAA4D;AAC5D,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,YAAY,EAAE,EACxB,KAAK,EAAE,QAAQ,EAAE,EACjB,KAAK,CAAC,EAAE,QAAQ,EAAE,EAClB,eAAe,CAAC,EAAE,eAAe,GAChC,WAAW,CAQb"}
|
package/dist/models/chat.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { requireCapability, } from "./types.js";
|
|
1
|
+
import { CapabilityError, requireCapability, } from "./types.js";
|
|
2
2
|
/** The kind string every chat model registers under. */
|
|
3
3
|
export const CHAT_KIND = "chat";
|
|
4
4
|
/**
|
|
@@ -11,11 +11,13 @@ export const CHAT_KIND = "chat";
|
|
|
11
11
|
*
|
|
12
12
|
* Capabilities are reported conservatively, from what the `Provider` interface
|
|
13
13
|
* can actually express: it has no streaming method and no attachment channel,
|
|
14
|
-
* so those stay false. `
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* so those stay false. A request carrying `parts` is refused with a
|
|
15
|
+
* `CapabilityError` even when `multimodalInput` is passed in `caps`, because
|
|
16
|
+
* there is no channel to forward them on. `usage` follows the provider's own
|
|
17
|
+
* `reportsUsage` declaration: the SDK-backed adapters set it (their
|
|
18
|
+
* `ConverseResult.usage` becomes `ModelResult.usage`), while a provider that
|
|
19
|
+
* declares nothing — the mock, a custom provider — reports `usage: false`
|
|
20
|
+
* rather than promising accounting it does not deliver.
|
|
19
21
|
*/
|
|
20
22
|
export function chatModel(provider, caps = {}) {
|
|
21
23
|
const resolved = {
|
|
@@ -32,6 +34,9 @@ export function chatModel(provider, caps = {}) {
|
|
|
32
34
|
async invoke(req, ctx) {
|
|
33
35
|
if (req.parts?.length) {
|
|
34
36
|
requireCapability({ id: provider.name, kind: CHAT_KIND, caps: resolved }, "multimodalInput", "request carries parts");
|
|
37
|
+
// A declared capability is not a channel: `ConverseRequest` has nowhere
|
|
38
|
+
// to put an attachment, so forwarding would drop it. Refuse instead.
|
|
39
|
+
throw new CapabilityError({ id: provider.name, kind: CHAT_KIND, caps: resolved }, "multimodalInput", "declared, but not deliverable: the Provider interface has no attachment channel, so parts would be dropped");
|
|
35
40
|
}
|
|
36
41
|
if (req.tools.length > 0) {
|
|
37
42
|
requireCapability({ id: provider.name, kind: CHAT_KIND, caps: resolved }, "tools", "request carries tool definitions");
|
package/dist/models/chat.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/models/chat.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,iBAAiB,GAMlB,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/models/chat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { type ModelInvocation } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Retry and fallback around a model invocation, as an opt-in decorator.
|
|
4
|
+
*
|
|
5
|
+
* The kernel leaves transient failures to the vendor SDKs by default. A caller
|
|
6
|
+
* that needs a policy those SDKs cannot express — a wait that knows the run's
|
|
7
|
+
* deadline, an honoured `Retry-After`, a named chain of other models to try
|
|
8
|
+
* once the primary is exhausted — wraps its model in {@link withRetry} and
|
|
9
|
+
* turns the SDK's own retries off (`providerOptions.maxRetries: 0`), so the two
|
|
10
|
+
* do not multiply.
|
|
11
|
+
*
|
|
12
|
+
* This is infrastructure, not a quality loop: an attempt is repeated only when
|
|
13
|
+
* the call FAILED (threw), never because its answer was judged poor. And it is
|
|
14
|
+
* explicit: there is no default fallback chain, so a call that ends up on
|
|
15
|
+
* another model does so because the caller listed that model.
|
|
16
|
+
*
|
|
17
|
+
* It wraps a {@link ModelInvocation} rather than being a `Middleware`
|
|
18
|
+
* because a fallback chain needs several invocations, and middleware is handed
|
|
19
|
+
* exactly one `next`. Being payload-generic, it covers every kind the same way
|
|
20
|
+
* middleware does: a chat model, a detector, a forecaster.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* What to do after a failed attempt.
|
|
24
|
+
*
|
|
25
|
+
* - `retry` — a transient fault: try the same model again after a backoff, and
|
|
26
|
+
* move to the next model in the chain once its attempts run out.
|
|
27
|
+
* - `fallback` — this model will not answer soon: skip its remaining attempts
|
|
28
|
+
* and move to the next model at once.
|
|
29
|
+
* - `fatal` — a fault no other attempt can fix (a bad credential, an invalid
|
|
30
|
+
* request): rethrow it unchanged, trying nothing else.
|
|
31
|
+
*/
|
|
32
|
+
export type RetryDecision = "retry" | "fallback" | "fatal";
|
|
33
|
+
/** One model in the chain giving up, or one wait before trying it again. */
|
|
34
|
+
export type RetryEvent = {
|
|
35
|
+
type: "retry";
|
|
36
|
+
/** The invocation id that failed and will be tried again. */
|
|
37
|
+
model: string;
|
|
38
|
+
/** The attempt on this model that just failed, from 1. */
|
|
39
|
+
attempt: number;
|
|
40
|
+
/** How long the wrapper waits before the next attempt. */
|
|
41
|
+
delayMs: number;
|
|
42
|
+
/** True when `delayMs` came from the server's `Retry-After`. */
|
|
43
|
+
retryAfter: boolean;
|
|
44
|
+
/** The failure. Absent when the wrapper was built with `private: true`. */
|
|
45
|
+
error?: unknown;
|
|
46
|
+
} | {
|
|
47
|
+
type: "fallback";
|
|
48
|
+
/** The invocation id given up on. */
|
|
49
|
+
from: string;
|
|
50
|
+
/** The next invocation id in the chain. */
|
|
51
|
+
to: string;
|
|
52
|
+
/**
|
|
53
|
+
* Why `from` was given up on: its retries or wait budget ran out
|
|
54
|
+
* (`exhausted`), the classifier said `fallback`, or it was skipped
|
|
55
|
+
* because an earlier call of this wrapper exhausted it (`sticky`).
|
|
56
|
+
*/
|
|
57
|
+
reason: "exhausted" | "fallback" | "sticky";
|
|
58
|
+
error?: unknown;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* What the wrapper did on a call that succeeded, reported as `meta.retry` on
|
|
62
|
+
* the result. Consumers audit which model actually served a call from it.
|
|
63
|
+
*/
|
|
64
|
+
export interface RetryReport {
|
|
65
|
+
/**
|
|
66
|
+
* The id of the invocation that answered. When the chain entry that
|
|
67
|
+
* answered is itself a `withRetry` wrapper, this is the model inside it that
|
|
68
|
+
* answered, and `attempts`, `fellBackFrom` and `waitedMs` include its calls.
|
|
69
|
+
*/
|
|
70
|
+
served: string;
|
|
71
|
+
/** The answering entry's position in this chain: 0 is the primary, n the n-th fallback. */
|
|
72
|
+
position: number;
|
|
73
|
+
/** Every call made for this invocation, including the one that answered. */
|
|
74
|
+
attempts: number;
|
|
75
|
+
/** Ids of the models tried and given up on, in order; empty when the primary served. */
|
|
76
|
+
fellBackFrom: string[];
|
|
77
|
+
/** Total time this invocation spent waiting between attempts. */
|
|
78
|
+
waitedMs: number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Internal: the id of the model that served a call, when a `withRetry` wrapper
|
|
82
|
+
* reported one on its result. The native loop reads it so a run's `provider`
|
|
83
|
+
* names the fallback that answered rather than the primary. Not exported from
|
|
84
|
+
* `index.ts`.
|
|
85
|
+
*/
|
|
86
|
+
export declare function servedBy(meta: Record<string, unknown> | undefined): string | undefined;
|
|
87
|
+
/** Exponential backoff: `baseMs × 2^(retry−1)`, capped at `maxMs`. */
|
|
88
|
+
export interface BackoffOptions {
|
|
89
|
+
/** The first wait. Default 500. */
|
|
90
|
+
baseMs?: number;
|
|
91
|
+
/** The longest single wait. Default 8000. */
|
|
92
|
+
maxMs?: number;
|
|
93
|
+
/**
|
|
94
|
+
* Randomise each wait between half and all of its computed value, so many
|
|
95
|
+
* callers refused at once do not retry in step. Default true.
|
|
96
|
+
*/
|
|
97
|
+
jitter?: boolean;
|
|
98
|
+
}
|
|
99
|
+
export interface RetryOptions<Req, Res> {
|
|
100
|
+
/**
|
|
101
|
+
* Calls per model, including the first. Default 3 (the SDK default this
|
|
102
|
+
* replaces: one call plus two retries). 1 means never retry, only fall back.
|
|
103
|
+
*/
|
|
104
|
+
maxAttempts?: number;
|
|
105
|
+
/**
|
|
106
|
+
* The wait before retry `n` (from 1): exponential options, or a function for
|
|
107
|
+
* a fixed schedule (`(n) => [1000, 2000, 3000][n - 1] ?? 3000`).
|
|
108
|
+
*/
|
|
109
|
+
backoff?: BackoffOptions | ((retry: number) => number);
|
|
110
|
+
/**
|
|
111
|
+
* Wait what the server's `Retry-After` (or `retry-after-ms`) header asks
|
|
112
|
+
* instead of the computed backoff. Default true. A server wait longer than
|
|
113
|
+
* the remaining budget is not shortened, since a shortened wait would only
|
|
114
|
+
* be refused again: that model is given up on and the chain moves on.
|
|
115
|
+
*/
|
|
116
|
+
respectRetryAfter?: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* The longest server-asked wait honoured. Default 60000, as the vendor SDKs
|
|
119
|
+
* do. A `Retry-After` above it is treated as a wait that does not fit: that
|
|
120
|
+
* model is given up on and the chain moves on, rather than sleeping for an
|
|
121
|
+
* implausible hour or day.
|
|
122
|
+
*/
|
|
123
|
+
maxRetryAfterMs?: number;
|
|
124
|
+
/** Decide each failure. Default {@link defaultRetryClassifier}. */
|
|
125
|
+
classify?: (err: unknown) => RetryDecision;
|
|
126
|
+
/**
|
|
127
|
+
* The ordered models to try once the primary is given up on. Empty (the
|
|
128
|
+
* default) means retry only: the kernel never picks a fallback by itself.
|
|
129
|
+
*/
|
|
130
|
+
fallbacks?: ModelInvocation<Req, Res>[];
|
|
131
|
+
/**
|
|
132
|
+
* The absolute deadline (epoch ms) every attempt must finish by, or a
|
|
133
|
+
* function returning it. The wrapper never starts a wait that would run past
|
|
134
|
+
* it. The call's context bounds it too: `InvokeContext.budget.deadlineAt`
|
|
135
|
+
* (which the native loop sets to the run's deadline, so a wrapped model in
|
|
136
|
+
* `runConversation` or `runAgent` knows how much of the run is left) and
|
|
137
|
+
* `budget.maxDurationMs` counted from the call's start. The earliest wins.
|
|
138
|
+
* Set this when the model is called outside the native loop, or when the
|
|
139
|
+
* caller's own deadline is earlier than the run's.
|
|
140
|
+
*/
|
|
141
|
+
deadlineAt?: number | (() => number);
|
|
142
|
+
/**
|
|
143
|
+
* Time to leave for the call itself: a wait that would leave less than this
|
|
144
|
+
* before the deadline is not started. Default 0.
|
|
145
|
+
*/
|
|
146
|
+
minCallMs?: number;
|
|
147
|
+
/**
|
|
148
|
+
* The most this wrapper waits in total, summed across every call made
|
|
149
|
+
* through it. Default unlimited.
|
|
150
|
+
*
|
|
151
|
+
* This budget belongs to the INSTANCE and never refills, so build one
|
|
152
|
+
* wrapper per run or turn when you set it. A wrapper registered once at
|
|
153
|
+
* startup and shared by every run would spend it on the first rate limit
|
|
154
|
+
* and never retry again.
|
|
155
|
+
*/
|
|
156
|
+
waitBudgetMs?: number;
|
|
157
|
+
/**
|
|
158
|
+
* Once a model has been given up on because its retries or wait budget ran
|
|
159
|
+
* out, start every later call of this wrapper at the next model rather than
|
|
160
|
+
* asking it again (asking a rate-limited model again only adds a refusal
|
|
161
|
+
* under the same limit). A `fallback` decision does not make it sticky.
|
|
162
|
+
* Default false.
|
|
163
|
+
*
|
|
164
|
+
* Like `waitBudgetMs`, this is instance state that never resets: build one
|
|
165
|
+
* wrapper per run or turn when you set it. A wrapper with neither option
|
|
166
|
+
* keeps no state between calls and is safe to share.
|
|
167
|
+
*/
|
|
168
|
+
stickyFallback?: boolean;
|
|
169
|
+
/**
|
|
170
|
+
* The run is private (`RunSpec.private`): its material must stay on the one
|
|
171
|
+
* model it was given. Retrying that model is allowed; a fallback chain is
|
|
172
|
+
* refused when the wrapper is built, because a fallback is exactly a way for
|
|
173
|
+
* the material to reach another model. That includes a primary that is
|
|
174
|
+
* itself a `withRetry` wrapper with fallbacks; a nested `withRetry` must also
|
|
175
|
+
* be built `private: true`, or it is refused, since it logs and reports on
|
|
176
|
+
* its own.
|
|
177
|
+
*
|
|
178
|
+
* An upstream error can quote the material, so none of its text leaves the
|
|
179
|
+
* wrapper by its own hand: `onEvent` receives no `error`, `ctx.log` lines
|
|
180
|
+
* name the HTTP status at most, and `RetryExhaustedError`'s `failures` and
|
|
181
|
+
* `cause` hold a narrowed error carrying only that status. A fatal error or
|
|
182
|
+
* an abort is still rethrown unchanged, exactly as the model threw it; that
|
|
183
|
+
* error is the caller's to keep off its own channels.
|
|
184
|
+
*
|
|
185
|
+
* Caller-declared today: the native engine selects its own provider and
|
|
186
|
+
* takes no injected model, so a private run cannot reach this wrapper. A
|
|
187
|
+
* hook that ever lets an engine wrap its model must pass `RunSpec.private`
|
|
188
|
+
* through here, or this refusal becomes a hope.
|
|
189
|
+
*/
|
|
190
|
+
private?: boolean;
|
|
191
|
+
/** Told about each retry and fallback as it happens. A throwing observer is logged and skipped. */
|
|
192
|
+
onEvent?: (event: RetryEvent) => void;
|
|
193
|
+
/** Injectable for tests. Must reject with `signal.reason` when it aborts. */
|
|
194
|
+
sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
195
|
+
/** Injectable for tests. Default `Date.now`. */
|
|
196
|
+
now?: () => number;
|
|
197
|
+
/** Injectable for tests (jitter). Default `Math.random`. */
|
|
198
|
+
random?: () => number;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Thrown when every model in the chain failed without a fatal error: the last
|
|
202
|
+
* failure is its `cause`, every failure is in `failures`. A `fatal` error is
|
|
203
|
+
* never wrapped, and neither is an abort.
|
|
204
|
+
*/
|
|
205
|
+
export declare class RetryExhaustedError extends Error {
|
|
206
|
+
/** Each failed call, in order. */
|
|
207
|
+
readonly failures: {
|
|
208
|
+
model: string;
|
|
209
|
+
error: unknown;
|
|
210
|
+
}[];
|
|
211
|
+
/** Why the chain stopped: every model was tried, or the deadline left no room for another attempt. */
|
|
212
|
+
readonly reason: "exhausted" | "deadline";
|
|
213
|
+
/** Total time spent waiting between those calls. */
|
|
214
|
+
readonly waitedMs: number;
|
|
215
|
+
constructor(failures: {
|
|
216
|
+
model: string;
|
|
217
|
+
error: unknown;
|
|
218
|
+
}[], reason: "exhausted" | "deadline", cause: unknown, waitedMs?: number);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* The HTTP status a failed call carries: the SDK error's `status` (or
|
|
222
|
+
* `statusCode`), else a leading status in its message ("429 Rate limit
|
|
223
|
+
* exceeded"), which is how some gateways' errors arrive.
|
|
224
|
+
*/
|
|
225
|
+
export declare function errorStatus(err: unknown): number | undefined;
|
|
226
|
+
/**
|
|
227
|
+
* The wait a failed call's server asked for, in ms: `retry-after-ms`, else
|
|
228
|
+
* `retry-after` as seconds or an HTTP date. Read from the error's `headers`,
|
|
229
|
+
* a `Headers` or a plain record, the way the SDKs attach them.
|
|
230
|
+
*/
|
|
231
|
+
export declare function retryAfterMs(err: unknown, now?: number): number | undefined;
|
|
232
|
+
/**
|
|
233
|
+
* The default classification: rate limits, timeouts, server faults (but not
|
|
234
|
+
* 501/505) and dropped connections are retried; a nested `withRetry` that ran
|
|
235
|
+
* out moves this chain to its next model; everything else — auth (401/403), payment
|
|
236
|
+
* (402), an invalid request (400/404/422), a credential or option the kernel
|
|
237
|
+
* refused, and any error it cannot recognise — is fatal. Unknown errors are
|
|
238
|
+
* fatal on purpose: retrying what nobody classified hides it.
|
|
239
|
+
*/
|
|
240
|
+
export declare function defaultRetryClassifier(err: unknown): RetryDecision;
|
|
241
|
+
/**
|
|
242
|
+
* Wrap a model in retry-and-fallback.
|
|
243
|
+
*
|
|
244
|
+
* The returned invocation keeps the primary's `id` and `kind`; its `caps` are
|
|
245
|
+
* what every model in the chain can do (a capability one fallback lacks is not
|
|
246
|
+
* advertised), and it streams only when all of them stream. `probe` asks the
|
|
247
|
+
* primary.
|
|
248
|
+
*
|
|
249
|
+
* On success the result is the serving model's, with `meta.retry` set to a
|
|
250
|
+
* {@link RetryReport}. A streaming call is never retried or sent to a fallback
|
|
251
|
+
* once its sink has received anything: the caller has already shown that
|
|
252
|
+
* output, and a second answer spliced after it would be a different reply.
|
|
253
|
+
*
|
|
254
|
+
* An abort (the call's `signal`) stops a wait at once and is rethrown as the
|
|
255
|
+
* signal's reason, the same as an abort mid-request, so the loop still reads
|
|
256
|
+
* it as a clean stop.
|
|
257
|
+
*/
|
|
258
|
+
export declare function withRetry<Req, Res>(primary: ModelInvocation<Req, Res>, options?: RetryOptions<Req, Res>): ModelInvocation<Req, Res>;
|
|
259
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/models/retry.ts"],"names":[],"mappings":"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"}
|