@providerkit/core 0.21.1 → 0.23.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 +7 -7
- package/dist/attribution.d.ts +2 -2
- package/dist/auth/flows.d.ts.map +1 -1
- package/dist/auth/flows.js +5 -5
- package/dist/auth/flows.js.map +1 -1
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +1 -0
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/oauth.d.ts +12 -0
- package/dist/auth/oauth.d.ts.map +1 -1
- package/dist/auth/oauth.js +19 -1
- package/dist/auth/oauth.js.map +1 -1
- package/dist/auth/token-source.d.ts +9 -3
- package/dist/auth/token-source.d.ts.map +1 -1
- package/dist/auth/token-source.js +24 -9
- package/dist/auth/token-source.js.map +1 -1
- package/dist/auth/with-token.d.ts +29 -0
- package/dist/auth/with-token.d.ts.map +1 -0
- package/dist/auth/with-token.js +85 -0
- package/dist/auth/with-token.js.map +1 -0
- package/dist/capability.d.ts +9 -9
- package/dist/capability.js +9 -9
- package/dist/capability.js.map +1 -1
- package/dist/context.d.ts +43 -5
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +123 -4
- package/dist/context.js.map +1 -1
- package/dist/errors.d.ts +26 -17
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +57 -18
- package/dist/errors.js.map +1 -1
- package/dist/fallback.d.ts +45 -1
- package/dist/fallback.d.ts.map +1 -1
- package/dist/fallback.js +138 -75
- package/dist/fallback.js.map +1 -1
- package/dist/image.d.ts +1 -1
- package/dist/image.d.ts.map +1 -1
- package/dist/jev.d.ts +9 -9
- package/dist/jev.d.ts.map +1 -1
- package/dist/jev.js +1 -1
- package/dist/key-pool.d.ts +14 -8
- package/dist/key-pool.d.ts.map +1 -1
- package/dist/key-pool.js +35 -18
- package/dist/key-pool.js.map +1 -1
- package/dist/presets.d.ts +33 -24
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +25 -14
- package/dist/presets.js.map +1 -1
- package/dist/providers/anthropic.d.ts +5 -5
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +89 -34
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/factory.d.ts +2 -2
- package/dist/providers/factory.d.ts.map +1 -1
- package/dist/providers/factory.js +2 -1
- package/dist/providers/factory.js.map +1 -1
- package/dist/providers/gemini.d.ts +8 -2
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +117 -41
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/openai.d.ts +12 -9
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +72 -21
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/responses.d.ts +3 -3
- package/dist/providers/responses.d.ts.map +1 -1
- package/dist/providers/responses.js +103 -57
- package/dist/providers/responses.js.map +1 -1
- package/dist/providers/zai.d.ts +2 -2
- package/dist/providers/zai.js +2 -2
- package/dist/rate-limit.d.ts +13 -3
- package/dist/rate-limit.d.ts.map +1 -1
- package/dist/rate-limit.js +10 -4
- package/dist/rate-limit.js.map +1 -1
- package/dist/retry.d.ts +16 -5
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +29 -16
- package/dist/retry.js.map +1 -1
- package/dist/schema.d.ts +6 -6
- package/dist/schema.js +8 -8
- package/dist/tool-args.d.ts +23 -1
- package/dist/tool-args.d.ts.map +1 -1
- package/dist/tool-args.js +30 -2
- package/dist/tool-args.js.map +1 -1
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +2 -2
- package/dist/tools.js.map +1 -1
- package/dist/transport.d.ts +40 -10
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +82 -21
- package/dist/transport.js.map +1 -1
- package/dist/types.d.ts +37 -23
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -11
- package/dist/types.js.map +1 -1
- package/dist/usage.d.ts +4 -4
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +3 -3
- package/dist/usage.js.map +1 -1
- package/dist/watchdog.d.ts +14 -12
- package/dist/watchdog.d.ts.map +1 -1
- package/dist/watchdog.js +35 -16
- package/dist/watchdog.js.map +1 -1
- package/dist/zod.d.ts +4 -4
- package/dist/zod.js +3 -3
- package/package.json +1 -1
- package/src/attribution.ts +2 -2
- package/src/auth/flows.ts +5 -4
- package/src/auth/index.ts +1 -0
- package/src/auth/oauth.ts +23 -1
- package/src/auth/token-source.ts +30 -11
- package/src/auth/with-token.ts +97 -0
- package/src/capability.ts +12 -12
- package/src/context.ts +141 -6
- package/src/errors.ts +63 -23
- package/src/fallback.ts +173 -75
- package/src/image.ts +1 -1
- package/src/jev.ts +11 -11
- package/src/key-pool.ts +37 -20
- package/src/presets.ts +38 -24
- package/src/providers/anthropic.ts +97 -38
- package/src/providers/factory.ts +4 -3
- package/src/providers/gemini.ts +121 -44
- package/src/providers/openai.ts +78 -25
- package/src/providers/responses.ts +113 -61
- package/src/providers/zai.ts +2 -2
- package/src/rate-limit.ts +35 -7
- package/src/retry.ts +46 -15
- package/src/schema.ts +8 -8
- package/src/tool-args.ts +46 -2
- package/src/tools.ts +4 -4
- package/src/transport.ts +103 -23
- package/src/types.ts +37 -23
- package/src/usage.ts +5 -5
- package/src/watchdog.ts +38 -19
- package/src/zod.ts +4 -4
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RateLimitReading } from "./rate-limit.ts";
|
|
1
2
|
/**
|
|
2
3
|
* How hard the model thinks before answering. Absent = the provider's own
|
|
3
4
|
* default (never sent). Passed through verbatim on OpenAI-shape
|
|
@@ -5,7 +6,7 @@
|
|
|
5
6
|
* `output_config.effort` for current Claude models, where `none` is the lowest
|
|
6
7
|
* effort on a model that cannot stop thinking; and to thinking budgets for
|
|
7
8
|
* Claude 4.5 and older and for every other vendor on that wire.
|
|
8
|
-
* Support varies per model
|
|
9
|
+
* Support varies per model. An unsupported level comes back as a clean 400.
|
|
9
10
|
*
|
|
10
11
|
* Ordered least → most; the type derives from the array so the runtime guard
|
|
11
12
|
* and the union can never drift apart.
|
|
@@ -19,7 +20,7 @@ export interface TextPart {
|
|
|
19
20
|
type: "text";
|
|
20
21
|
text: string;
|
|
21
22
|
}
|
|
22
|
-
/** An image the model looks at (vision)
|
|
23
|
+
/** An image the model looks at (vision), with bytes as base64, never a URL the
|
|
23
24
|
* provider would have to fetch on our behalf. */
|
|
24
25
|
export interface ImagePart {
|
|
25
26
|
type: "image";
|
|
@@ -30,7 +31,7 @@ export interface ImagePart {
|
|
|
30
31
|
* `ImagePart`, which every adapter can send. */
|
|
31
32
|
export type FileMimeType = `application/${string}` | `audio/${string}` | `video/${string}` | `text/${string}`;
|
|
32
33
|
/**
|
|
33
|
-
* A file the model reads
|
|
34
|
+
* A file the model reads (a PDF, a recording, a video) as base64 bytes,
|
|
34
35
|
* never a URL. Only the Gemini adapter sends one, as `inlineData`, the way it
|
|
35
36
|
* sends an image. Every other adapter refuses it with an `invalid`
|
|
36
37
|
* ProviderError before any request goes out, rather than drop it: a dropped
|
|
@@ -76,7 +77,7 @@ export type ChatMessage = {
|
|
|
76
77
|
* OpenAI-shape serializes it as `reasoning_content`; Anthropic-shape
|
|
77
78
|
* drops it, since its thinking blocks carry signatures we never capture.
|
|
78
79
|
*
|
|
79
|
-
* A turn that
|
|
80
|
+
* A turn that disables thinking must not carry it. Mixing the two is
|
|
80
81
|
* unsupported. `stripReasoning` below is that rule, once.
|
|
81
82
|
*/
|
|
82
83
|
reasoning?: string;
|
|
@@ -84,7 +85,7 @@ export type ChatMessage = {
|
|
|
84
85
|
* OpenRouter's normalized reasoning payload, arriving on the stream and
|
|
85
86
|
* riding back UNMODIFIED on the next turn's assistant message.
|
|
86
87
|
*
|
|
87
|
-
* Opaque on purpose
|
|
88
|
+
* Opaque on purpose, with the same contract as Gemini's `thoughtSignature`,
|
|
88
89
|
* and for the same reason: it is the provider's own record of how it got
|
|
89
90
|
* here, and reading, reshaping or dropping it costs the model its
|
|
90
91
|
* continuity across a tool round. Absent on every other dialect.
|
|
@@ -112,7 +113,7 @@ export interface ReasoningItems {
|
|
|
112
113
|
provider: string;
|
|
113
114
|
items: unknown[];
|
|
114
115
|
}
|
|
115
|
-
/** JSON Schema for an object
|
|
116
|
+
/** JSON Schema for an object, as every provider's tool contract requires. */
|
|
116
117
|
export interface JsonObjectSchema {
|
|
117
118
|
type: "object";
|
|
118
119
|
properties?: Record<string, unknown>;
|
|
@@ -136,19 +137,19 @@ export interface ToolCallDelta {
|
|
|
136
137
|
}
|
|
137
138
|
export interface TokenUsage {
|
|
138
139
|
inputTokens: number;
|
|
139
|
-
/** Cache-
|
|
140
|
+
/** Cache-hit subset of `inputTokens`. Providers auto-cache repeated
|
|
140
141
|
* prefixes and bill the hit portion far cheaper, so it must be tracked
|
|
141
142
|
* separately to cost a turn correctly. 0 when the provider reports none. */
|
|
142
143
|
cachedInputTokens: number;
|
|
143
|
-
/** Tokens
|
|
144
|
+
/** Tokens written to cache, also a subset of `inputTokens`, so the total
|
|
144
145
|
* stays the whole prompt the window has to hold. Anthropic bills these
|
|
145
146
|
* above the input rate; the OpenAI-shape auto-cachers bill them at it.
|
|
146
147
|
* 0 when not reported. */
|
|
147
148
|
cacheWriteTokens?: number;
|
|
148
149
|
outputTokens: number;
|
|
149
150
|
/**
|
|
150
|
-
* The part of `outputTokens` spent thinking, when the provider reports it
|
|
151
|
-
*
|
|
151
|
+
* The part of `outputTokens` spent thinking, when the provider reports it.
|
|
152
|
+
* Already inside `outputTokens`, so never add it again. It is the number
|
|
152
153
|
* that explains a turn that came back empty with a length finish: the
|
|
153
154
|
* reasoning ate the budget. Anthropic does not report it; absent there.
|
|
154
155
|
*/
|
|
@@ -164,7 +165,7 @@ export interface TokenUsage {
|
|
|
164
165
|
reportedCostUsd?: number;
|
|
165
166
|
}
|
|
166
167
|
export declare const EMPTY_USAGE: TokenUsage;
|
|
167
|
-
/** Normalized streaming chunk
|
|
168
|
+
/** Normalized streaming chunk. Every provider's shape maps to this. */
|
|
168
169
|
export interface ProviderChunk {
|
|
169
170
|
type: "delta" | "usage" | "finish";
|
|
170
171
|
/** The selected endpoint and model when a fallback provider emits this chunk.
|
|
@@ -175,7 +176,7 @@ export interface ProviderChunk {
|
|
|
175
176
|
};
|
|
176
177
|
content?: string;
|
|
177
178
|
reasoning?: string;
|
|
178
|
-
/** OpenRouter's normalized reasoning payload
|
|
179
|
+
/** OpenRouter's normalized reasoning payload. Hand it back on the next
|
|
179
180
|
* turn's assistant message verbatim. See ChatMessage.reasoningDetails. */
|
|
180
181
|
reasoningDetails?: unknown[];
|
|
181
182
|
/** Once per turn, where a provider replays its reasoning. See ChatMessage.reasoningItems. */
|
|
@@ -184,7 +185,7 @@ export interface ProviderChunk {
|
|
|
184
185
|
usage?: TokenUsage;
|
|
185
186
|
finishReason?: FinishReason;
|
|
186
187
|
}
|
|
187
|
-
/** Pin or deny tool use. `{ name }` forces one specific tool
|
|
188
|
+
/** Pin or deny tool use. `{ name }` forces one specific tool, so a run is
|
|
188
189
|
* made to commit an answer at its step budget's edge. */
|
|
189
190
|
export type ToolChoice = "auto" | "none" | "required" | {
|
|
190
191
|
name: string;
|
|
@@ -192,15 +193,15 @@ export type ToolChoice = "auto" | "none" | "required" | {
|
|
|
192
193
|
/**
|
|
193
194
|
* Ask for a JSON object matching `schema`. Providers that enforce schemas get
|
|
194
195
|
* it verbatim; the rest get JSON mode plus the schema in the prompt. Either
|
|
195
|
-
* way the
|
|
196
|
+
* way the caller validates: a provider's "guaranteed" JSON is not one.
|
|
196
197
|
*/
|
|
197
198
|
export interface JsonOutput {
|
|
198
199
|
name: string;
|
|
199
200
|
schema: JsonObjectSchema;
|
|
200
201
|
/**
|
|
201
202
|
* Force OpenAI's strict schema mode on or off. Left unset, the adapters ask
|
|
202
|
-
* `isStrictSchema` and enforce whenever the schema actually qualifies
|
|
203
|
-
*
|
|
203
|
+
* `isStrictSchema` and enforce whenever the schema actually qualifies.
|
|
204
|
+
* This keeps an optional field from turning a working call into a
|
|
204
205
|
* 400. Set it only to overrule that reading.
|
|
205
206
|
*/
|
|
206
207
|
strict?: boolean;
|
|
@@ -230,13 +231,13 @@ export declare class JsonAnswerError extends Error {
|
|
|
230
231
|
/**
|
|
231
232
|
* How the schema rides on a call that ALSO carries tools.
|
|
232
233
|
*
|
|
233
|
-
* `"response_format"` sends both
|
|
234
|
+
* `"response_format"` sends both, as the shapes document and most models
|
|
234
235
|
* honour. `"prompt"` leaves the format off that call and sends the schema as
|
|
235
236
|
* prompt instead, which is what the Anthropic shape has always done.
|
|
236
237
|
*
|
|
237
238
|
* It is a setting because a model that cannot serve both never says so: its
|
|
238
239
|
* decoder is pinned to the schema, the tool call has nowhere to go, and it
|
|
239
|
-
* writes the announcement instead
|
|
240
|
+
* writes the announcement instead ("let me look that up") and stops. Nothing
|
|
240
241
|
* is logged, because nothing failed. `probeJsonWithTools` answers it in one
|
|
241
242
|
* call; there is no default that is right for every model.
|
|
242
243
|
*/
|
|
@@ -249,9 +250,10 @@ export interface StreamOptions {
|
|
|
249
250
|
* task emitting a large artifact must raise it or the tool-call JSON is
|
|
250
251
|
* silently truncated mid-argument. */
|
|
251
252
|
maxTokens?: number;
|
|
253
|
+
/** Not sent to Gemini, which fixes its own sampling. Same for `topP`. */
|
|
252
254
|
temperature?: number;
|
|
253
255
|
/**
|
|
254
|
-
* Nucleus sampling. Set this
|
|
256
|
+
* Nucleus sampling. Set this or `temperature`, not both. The vendors all
|
|
255
257
|
* document them as alternatives and some reject the pair outright.
|
|
256
258
|
*/
|
|
257
259
|
topP?: number;
|
|
@@ -268,7 +270,7 @@ export interface StreamOptions {
|
|
|
268
270
|
toolChoice?: ToolChoice;
|
|
269
271
|
json?: JsonOutput;
|
|
270
272
|
/**
|
|
271
|
-
* Overrides the provider's own setting for this call
|
|
273
|
+
* Overrides the provider's own setting for this call, so `probeJsonWithTools`
|
|
272
274
|
* asks the same model both ways. See {@link JsonWithTools}.
|
|
273
275
|
*/
|
|
274
276
|
jsonWithTools?: JsonWithTools;
|
|
@@ -287,7 +289,19 @@ export interface StreamOptions {
|
|
|
287
289
|
*/
|
|
288
290
|
onActivity?: () => void;
|
|
289
291
|
/**
|
|
290
|
-
*
|
|
292
|
+
* Called once per response whose headers report how full a subscription
|
|
293
|
+
* window is, whatever its status: `utilization` (1 is full), `resetAtMs`,
|
|
294
|
+
* and `window` when the headers name it. A caller sees the window fill
|
|
295
|
+
* turn by turn, instead of learning about it from the 429 that ends a run.
|
|
296
|
+
*
|
|
297
|
+
* Every adapter forwards it. Two backends send the headers today: Claude
|
|
298
|
+
* subscriptions (Anthropic's unified 5h/7d headers) and the ChatGPT backend
|
|
299
|
+
* (`x-codex-*`). A response that reports no window never calls it, which
|
|
300
|
+
* covers API-key accounts on every vendor and all of Gemini.
|
|
301
|
+
*/
|
|
302
|
+
onRateLimit?: (reading: RateLimitReading) => void;
|
|
303
|
+
/**
|
|
304
|
+
* `false` asks for at most one tool call per turn, for tools that must run
|
|
291
305
|
* in order, or a backend lane that refuses parallel calls. Absent or `true`
|
|
292
306
|
* is every vendor's default and sends nothing. Gemini has no such switch,
|
|
293
307
|
* so it refuses `false` rather than silently ignore it.
|
|
@@ -330,13 +344,13 @@ export declare function drainStream(stream: AsyncIterable<ProviderChunk>, model:
|
|
|
330
344
|
*
|
|
331
345
|
* The chain-of-thought belongs only to thinking turns. A provider that
|
|
332
346
|
* requires it replayed while thinking is ON (DeepSeek) rejects it when
|
|
333
|
-
* thinking is
|
|
347
|
+
* thinking is off. This is exactly the shape of a forced-submit salvage
|
|
334
348
|
* turn, where a run reasons through its whole investigation and then drops
|
|
335
349
|
* thinking to serialize what it already found.
|
|
336
350
|
*
|
|
337
351
|
* Returns a shallow-cleaned copy; the caller's array is left untouched.
|
|
338
352
|
*/
|
|
339
353
|
export declare function stripReasoning(messages: readonly ChatMessage[]): ChatMessage[];
|
|
340
|
-
/** `data:` URI for an image part
|
|
354
|
+
/** `data:` URI for an image part, as the OpenAI dialect requires inline. */
|
|
341
355
|
export declare function toDataUri(part: ImagePart): string;
|
|
342
356
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
// The seam — provider-neutral messages, tools and chunks. Every adapter
|
|
2
|
-
// (OpenAI-compatible, Anthropic, Responses, Gemini) translates to and from
|
|
3
|
-
// exactly these shapes, so a caller never sees a vendor's dialect.
|
|
4
|
-
//
|
|
5
|
-
// Deliberately NOT OpenAI's parameter types. Using one vendor's wire shape as
|
|
6
|
-
// the lingua franca forces the other adapters to round-trip through a dialect
|
|
7
|
-
// that isn't theirs, and every quirk of that dialect then leaks into callers
|
|
8
|
-
// who never asked for it.
|
|
9
1
|
/**
|
|
10
2
|
* How hard the model thinks before answering. Absent = the provider's own
|
|
11
3
|
* default (never sent). Passed through verbatim on OpenAI-shape
|
|
@@ -13,7 +5,7 @@
|
|
|
13
5
|
* `output_config.effort` for current Claude models, where `none` is the lowest
|
|
14
6
|
* effort on a model that cannot stop thinking; and to thinking budgets for
|
|
15
7
|
* Claude 4.5 and older and for every other vendor on that wire.
|
|
16
|
-
* Support varies per model
|
|
8
|
+
* Support varies per model. An unsupported level comes back as a clean 400.
|
|
17
9
|
*
|
|
18
10
|
* Ordered least → most; the type derives from the array so the runtime guard
|
|
19
11
|
* and the union can never drift apart.
|
|
@@ -187,7 +179,7 @@ export async function drainStream(stream, model) {
|
|
|
187
179
|
*
|
|
188
180
|
* The chain-of-thought belongs only to thinking turns. A provider that
|
|
189
181
|
* requires it replayed while thinking is ON (DeepSeek) rejects it when
|
|
190
|
-
* thinking is
|
|
182
|
+
* thinking is off. This is exactly the shape of a forced-submit salvage
|
|
191
183
|
* turn, where a run reasons through its whole investigation and then drops
|
|
192
184
|
* thinking to serialize what it already found.
|
|
193
185
|
*
|
|
@@ -210,7 +202,7 @@ export function stripReasoning(messages) {
|
|
|
210
202
|
return rest;
|
|
211
203
|
});
|
|
212
204
|
}
|
|
213
|
-
/** `data:` URI for an image part
|
|
205
|
+
/** `data:` URI for an image part, as the OpenAI dialect requires inline. */
|
|
214
206
|
export function toDataUri(part) {
|
|
215
207
|
return `data:${part.mimeType};base64,${part.data}`;
|
|
216
208
|
}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/usage.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { TokenUsage } from "./types.ts";
|
|
2
|
-
/** USD per
|
|
2
|
+
/** USD per million tokens, as every vendor prints its price sheet, so a row
|
|
3
3
|
* can be checked against one without arithmetic. */
|
|
4
4
|
export interface ModelRate {
|
|
5
5
|
/** Cache-MISS input: fresh tokens the provider had to read. */
|
|
6
6
|
input: number;
|
|
7
7
|
output: number;
|
|
8
8
|
/** Cache-HIT input. Providers auto-cache repeated prefixes and bill the hit
|
|
9
|
-
* portion far cheaper
|
|
9
|
+
* portion far cheaper: 0.1× on Anthropic, ~0.1× on Gemini, 0.5× on some
|
|
10
10
|
* OpenAI models. In an agent loop the re-sent context is overwhelmingly
|
|
11
11
|
* hits, so billing it at the miss rate overcounts by up to 10×. */
|
|
12
12
|
cacheRead: number;
|
|
@@ -40,7 +40,7 @@ export declare function subtractUsage(a: TokenUsage, b: TokenUsage): TokenUsage;
|
|
|
40
40
|
export declare function costUsd(usage: TokenUsage, rate: ModelRate): number;
|
|
41
41
|
/**
|
|
42
42
|
* Accumulates usage and cost across the calls of one run, pricing each with
|
|
43
|
-
* the rate in effect for the model that served it
|
|
43
|
+
* the rate in effect for the model that served it, so a run that switches to
|
|
44
44
|
* a backup model, or spans a time-of-day price boundary, still bills correctly.
|
|
45
45
|
* A call that carries a reported cost is billed that, with or without a rate.
|
|
46
46
|
*/
|
|
@@ -48,7 +48,7 @@ export declare class UsageTracker {
|
|
|
48
48
|
private usage;
|
|
49
49
|
private cost;
|
|
50
50
|
/** USD the cache hits saved, versus billing them all as misses.
|
|
51
|
-
* Observability only
|
|
51
|
+
* Observability only. Never billed. */
|
|
52
52
|
private saved;
|
|
53
53
|
add(usage: TokenUsage, rate?: ModelRate): void;
|
|
54
54
|
subtract(usage: TokenUsage, rate?: ModelRate): void;
|
package/dist/usage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C;qDACqD;AACrD,MAAM,WAAW,SAAS;IACxB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf;;;wEAGoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB;;0EAEsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;8DAG8D;AAC9D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,UAAU,CAUjE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,UAAU,CAUtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAgBlE;AAQD;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAuD;IACpE,OAAO,CAAC,IAAI,CAAK;IACjB;
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C;qDACqD;AACrD,MAAM,WAAW,SAAS;IACxB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf;;;wEAGoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB;;0EAEsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;8DAG8D;AAC9D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,UAAU,CAUjE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,UAAU,CAUtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAgBlE;AAQD;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAuD;IACpE,OAAO,CAAC,IAAI,CAAK;IACjB;4CACwC;IACxC,OAAO,CAAC,KAAK,CAAK;IAElB,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI;IAQ9C,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI;IAQnD,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED;;yDAEqD;IACrD,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIrC,KAAK,IAAI,IAAI;CAKd"}
|
package/dist/usage.js
CHANGED
|
@@ -58,13 +58,13 @@ export function costUsd(usage, rate) {
|
|
|
58
58
|
1_000_000);
|
|
59
59
|
}
|
|
60
60
|
/** What one call adds to a run: its reported cost, else its rate, else
|
|
61
|
-
* nothing
|
|
61
|
+
* nothing. An unpriced call still counts its tokens. */
|
|
62
62
|
function callCost(usage, rate) {
|
|
63
63
|
return rate ? costUsd(usage, rate) : (usage.reportedCostUsd ?? 0);
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
66
|
* Accumulates usage and cost across the calls of one run, pricing each with
|
|
67
|
-
* the rate in effect for the model that served it
|
|
67
|
+
* the rate in effect for the model that served it, so a run that switches to
|
|
68
68
|
* a backup model, or spans a time-of-day price boundary, still bills correctly.
|
|
69
69
|
* A call that carries a reported cost is billed that, with or without a rate.
|
|
70
70
|
*/
|
|
@@ -72,7 +72,7 @@ export class UsageTracker {
|
|
|
72
72
|
usage = { ...EMPTY_USAGE, cacheWriteTokens: 0 };
|
|
73
73
|
cost = 0;
|
|
74
74
|
/** USD the cache hits saved, versus billing them all as misses.
|
|
75
|
-
* Observability only
|
|
75
|
+
* Observability only. Never billed. */
|
|
76
76
|
saved = 0;
|
|
77
77
|
add(usage, rate) {
|
|
78
78
|
this.usage = addUsage(this.usage, usage);
|
package/dist/usage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"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"}
|
package/dist/watchdog.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Provider, ProviderChunk } from "./types.ts";
|
|
|
2
2
|
/** No byte at all for this long, once the response has started, and the
|
|
3
3
|
* stream is dead. */
|
|
4
4
|
export declare const STREAM_IDLE_MS = 60000;
|
|
5
|
-
/** No chunk for this long
|
|
5
|
+
/** No chunk for this long, including the wait for the response to start,
|
|
6
6
|
* and the stream is going nowhere, keep-alives or not. */
|
|
7
7
|
export declare const STREAM_PROGRESS_MS = 300000;
|
|
8
8
|
export interface StreamWatch {
|
|
@@ -10,17 +10,17 @@ export interface StreamWatch {
|
|
|
10
10
|
readonly signal: AbortSignal;
|
|
11
11
|
/** A chunk arrived: re-arm both deadlines, and mark TTFT if it was the first. */
|
|
12
12
|
sawByte(): void;
|
|
13
|
-
/** The response showed life without a chunk
|
|
13
|
+
/** The response showed life without a chunk: its headers, a keep-alive, a
|
|
14
14
|
* partial frame. Starts or re-arms the idle deadline only. */
|
|
15
15
|
sawActivity(): void;
|
|
16
16
|
/**
|
|
17
|
-
* Milliseconds from the call opening to its first chunk of any kind
|
|
17
|
+
* Milliseconds from the call opening to its first chunk of any kind. The
|
|
18
18
|
* wait a person actually experiences, and the number a prompt-cache pin
|
|
19
19
|
* exists to shrink. Null until something arrives.
|
|
20
20
|
*/
|
|
21
21
|
firstChunkMs(): number | null;
|
|
22
22
|
/**
|
|
23
|
-
* Re-issue a provider failure as the timeout
|
|
23
|
+
* Re-issue a provider failure as the timeout only when it was
|
|
24
24
|
* one of our deadlines that aborted. A caller's Stop passes through untouched.
|
|
25
25
|
*/
|
|
26
26
|
classify(err: unknown): unknown;
|
|
@@ -36,7 +36,7 @@ export interface StreamWatchOptions {
|
|
|
36
36
|
export declare function streamWatch(opts?: StreamWatchOptions): StreamWatch;
|
|
37
37
|
/**
|
|
38
38
|
* Wrap a stream so every chunk re-arms `watch`, and a failure is re-classified
|
|
39
|
-
* through it. Disposes on any exit
|
|
39
|
+
* through it. Disposes on any exit: completion, throw, or the consumer
|
|
40
40
|
* breaking out of the loop.
|
|
41
41
|
*/
|
|
42
42
|
export declare function watchChunks<T>(watch: StreamWatch, chunks: AsyncIterable<T>): AsyncGenerator<T>;
|
|
@@ -46,7 +46,7 @@ export declare function watchChunks<T>(watch: StreamWatch, chunks: AsyncIterable
|
|
|
46
46
|
* A stream that ends with no text and no tool call is a failure wearing a
|
|
47
47
|
* success's clothes: `stop_reason: end_turn` with zero content blocks, which
|
|
48
48
|
* the vendors emit under load, or a thinking block that ate the whole
|
|
49
|
-
* `max_tokens`. Nothing throws, so nothing retries
|
|
49
|
+
* `max_tokens`. Nothing throws, so nothing retries. The caller simply shows a
|
|
50
50
|
* person an empty answer, and the only trace is a bill.
|
|
51
51
|
*
|
|
52
52
|
* Reasoning is not an answer. It still streams the moment it arrives, so a
|
|
@@ -58,12 +58,12 @@ export declare function watchChunks<T>(watch: StreamWatch, chunks: AsyncIterable
|
|
|
58
58
|
*
|
|
59
59
|
* Classified by what fixes it. A `length` finish is the caller's own cap:
|
|
60
60
|
* `invalid`, so nothing retries it into the same cap and no backup model is
|
|
61
|
-
* cooled down for it
|
|
61
|
+
* cooled down for it. The fix is a larger `maxTokens` or a lower effort. Any
|
|
62
62
|
* other empty turn is `overload`, because that is both true and useful: it is
|
|
63
63
|
* theirs and temporary, so it is transient (the same model, retried, usually
|
|
64
64
|
* answers) and backup-eligible (a model that keeps doing it should be walked
|
|
65
65
|
* away from). Until something streams, the empty frames are held back, so the
|
|
66
|
-
* retry rule
|
|
66
|
+
* retry rule still holds: retry only while nothing was emitted.
|
|
67
67
|
*/
|
|
68
68
|
export declare function requireContent<T extends ProviderChunk>(provider: string, chunks: AsyncIterable<T>, opts?: {
|
|
69
69
|
afterToolResult?: boolean;
|
|
@@ -88,8 +88,8 @@ export interface WatchdogOptions {
|
|
|
88
88
|
* A provider with both silent failures already handled.
|
|
89
89
|
*
|
|
90
90
|
* Every consumer of this package wrote the same three lines around every
|
|
91
|
-
* `createStream
|
|
92
|
-
* the chunks
|
|
91
|
+
* `createStream`: build a watch, hand the provider the watch's signal, wrap
|
|
92
|
+
* the chunks. The middle one is the trap. Pass the caller's signal
|
|
93
93
|
* instead and everything still compiles, still streams, still passes the
|
|
94
94
|
* tests: the watchdog simply never aborts anything, because the request it was
|
|
95
95
|
* meant to cancel was never told about it. The failure has no symptom until
|
|
@@ -97,8 +97,10 @@ export interface WatchdogOptions {
|
|
|
97
97
|
*
|
|
98
98
|
* So the composition belongs here rather than in a docs snippet each app
|
|
99
99
|
* copies. The result is still a `Provider`, so it composes unchanged with
|
|
100
|
-
* `withStreamRetry` and `streamWithBackupModels
|
|
101
|
-
*
|
|
100
|
+
* `withStreamRetry` and `streamWithBackupModels`. Timeouts and empty turns
|
|
101
|
+
* without a `length` finish are transient, so wrapping it in a retry is safe.
|
|
102
|
+
* The one timeout a replay would make worse, no response at all within the
|
|
103
|
+
* progress window, says so itself with `shouldRetry: false`.
|
|
102
104
|
*/
|
|
103
105
|
export declare function withWatchdog(provider: Provider, opts?: WatchdogOptions): Provider;
|
|
104
106
|
//# sourceMappingURL=watchdog.d.ts.map
|
package/dist/watchdog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watchdog.d.ts","sourceRoot":"","sources":["../src/watchdog.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"watchdog.d.ts","sourceRoot":"","sources":["../src/watchdog.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAEV,QAAQ,EACR,aAAa,EAId,MAAM,YAAY,CAAC;AAEpB;sBACsB;AACtB,eAAO,MAAM,cAAc,QAAS,CAAC;AAErC;2DAC2D;AAC3D,eAAO,MAAM,kBAAkB,SAAU,CAAC;AAE1C,MAAM,WAAW,WAAW;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,iFAAiF;IACjF,OAAO,IAAI,IAAI,CAAC;IAChB;mEAC+D;IAC/D,WAAW,IAAI,IAAI,CAAC;IACpB;;;;OAIG;IACH,YAAY,IAAI,MAAM,GAAG,IAAI,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC;IAChC,8DAA8D;IAC9D,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wBAAgB,WAAW,CAAC,IAAI,GAAE,kBAAuB,GAAG,WAAW,CAiFtE;AAED;;;;GAIG;AACH,wBAAuB,WAAW,CAAC,CAAC,EAClC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GACvB,cAAc,CAAC,CAAC,CAAC,CAWnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAuB,cAAc,CAAC,CAAC,SAAS,aAAa,EAC3D,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EACxB,IAAI,GAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAO,GACvC,cAAc,CAAC,CAAC,CAAC,CAgDnB;AAED,MAAM,WAAW,eAAe;IAC9B;wCACoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;gFAC4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wEAAwE;IACxE,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,GAAE,eAAoB,GAAG,QAAQ,CA8CrF"}
|
package/dist/watchdog.js
CHANGED
|
@@ -24,15 +24,19 @@
|
|
|
24
24
|
// scratch, which re-ran the reasoning into the same deadline.
|
|
25
25
|
//
|
|
26
26
|
// When either fires, the watchdog aborts ITS OWN controller and the caller's
|
|
27
|
-
// signal is only bridged in
|
|
28
|
-
// distinguishable from our timeout. One is their cancel and is never retried
|
|
29
|
-
//
|
|
30
|
-
//
|
|
27
|
+
// signal is only bridged in, which is what keeps a person's Stop
|
|
28
|
+
// distinguishable from our timeout. One is their cancel and is never retried.
|
|
29
|
+
// The other is ours and transient, with one exception: a progress timeout
|
|
30
|
+
// before the response started carries `shouldRetry: false`. That wait was a
|
|
31
|
+
// backend thinking with its headers held back, and a replay sends the same
|
|
32
|
+
// prompt into the same 300s and pays for the reasoning again, up to three
|
|
33
|
+
// times (cc-proxy never replays slow headers). Its kind stays `timeout`, so a
|
|
34
|
+
// fallback pool still moves on to its next candidate.
|
|
31
35
|
import { ProviderError } from "./errors.js";
|
|
32
36
|
/** No byte at all for this long, once the response has started, and the
|
|
33
37
|
* stream is dead. */
|
|
34
38
|
export const STREAM_IDLE_MS = 60_000;
|
|
35
|
-
/** No chunk for this long
|
|
39
|
+
/** No chunk for this long, including the wait for the response to start,
|
|
36
40
|
* and the stream is going nowhere, keep-alives or not. */
|
|
37
41
|
export const STREAM_PROGRESS_MS = 300_000;
|
|
38
42
|
export function streamWatch(opts = {}) {
|
|
@@ -49,6 +53,9 @@ export function streamWatch(opts = {}) {
|
|
|
49
53
|
let firstChunk = null;
|
|
50
54
|
let fired = null;
|
|
51
55
|
let disposed = false;
|
|
56
|
+
// The first sign of life (the headers, a keep-alive, a chunk). The idle
|
|
57
|
+
// clock waits for it, and a timeout that fires before it is not replayed.
|
|
58
|
+
let responded = false;
|
|
52
59
|
// The bridge is structural rather than an event listener: AbortSignal.any
|
|
53
60
|
// aborts synchronously when an input is ALREADY aborted, which is the race
|
|
54
61
|
// no listener can catch (the event fired before we subscribed). It is also
|
|
@@ -57,7 +64,13 @@ export function streamWatch(opts = {}) {
|
|
|
57
64
|
const signal = callerSignal ? AbortSignal.any([callerSignal, timeout.signal]) : timeout.signal;
|
|
58
65
|
function deadline(ms, what) {
|
|
59
66
|
const timer = setTimeout(() => {
|
|
60
|
-
|
|
67
|
+
// Only the progress clock runs before the response starts, so this is
|
|
68
|
+
// the backend that thinks with its headers held back (see the header).
|
|
69
|
+
fired = responded
|
|
70
|
+
? new ProviderError(provider, "timeout", `stream went ${ms / 1000}s without ${what}`)
|
|
71
|
+
: new ProviderError(provider, "timeout", `no response in ${ms / 1000}s`, {
|
|
72
|
+
shouldRetry: false,
|
|
73
|
+
});
|
|
61
74
|
timeout.abort(fired);
|
|
62
75
|
}, ms);
|
|
63
76
|
// An orphaned watch — its consumer gone, dispose never called — must not
|
|
@@ -71,6 +84,7 @@ export function streamWatch(opts = {}) {
|
|
|
71
84
|
let progress = deadline(progressMs, "a chunk");
|
|
72
85
|
const live = () => !disposed && !signal.aborted;
|
|
73
86
|
function sawActivity() {
|
|
87
|
+
responded = true;
|
|
74
88
|
clearTimeout(idle);
|
|
75
89
|
if (live())
|
|
76
90
|
idle = deadline(idleMs, "a byte");
|
|
@@ -89,7 +103,10 @@ export function streamWatch(opts = {}) {
|
|
|
89
103
|
classify(err) {
|
|
90
104
|
// Our deadline, not theirs — and not the caller's Stop.
|
|
91
105
|
if (fired && !(callerSignal?.aborted ?? false)) {
|
|
92
|
-
return new ProviderError(fired.provider, "timeout", fired.message, {
|
|
106
|
+
return new ProviderError(fired.provider, "timeout", fired.message, {
|
|
107
|
+
shouldRetry: fired.shouldRetry,
|
|
108
|
+
cause: err,
|
|
109
|
+
});
|
|
93
110
|
}
|
|
94
111
|
return err;
|
|
95
112
|
},
|
|
@@ -102,7 +119,7 @@ export function streamWatch(opts = {}) {
|
|
|
102
119
|
}
|
|
103
120
|
/**
|
|
104
121
|
* Wrap a stream so every chunk re-arms `watch`, and a failure is re-classified
|
|
105
|
-
* through it. Disposes on any exit
|
|
122
|
+
* through it. Disposes on any exit: completion, throw, or the consumer
|
|
106
123
|
* breaking out of the loop.
|
|
107
124
|
*/
|
|
108
125
|
export async function* watchChunks(watch, chunks) {
|
|
@@ -125,7 +142,7 @@ export async function* watchChunks(watch, chunks) {
|
|
|
125
142
|
* A stream that ends with no text and no tool call is a failure wearing a
|
|
126
143
|
* success's clothes: `stop_reason: end_turn` with zero content blocks, which
|
|
127
144
|
* the vendors emit under load, or a thinking block that ate the whole
|
|
128
|
-
* `max_tokens`. Nothing throws, so nothing retries
|
|
145
|
+
* `max_tokens`. Nothing throws, so nothing retries. The caller simply shows a
|
|
129
146
|
* person an empty answer, and the only trace is a bill.
|
|
130
147
|
*
|
|
131
148
|
* Reasoning is not an answer. It still streams the moment it arrives, so a
|
|
@@ -137,12 +154,12 @@ export async function* watchChunks(watch, chunks) {
|
|
|
137
154
|
*
|
|
138
155
|
* Classified by what fixes it. A `length` finish is the caller's own cap:
|
|
139
156
|
* `invalid`, so nothing retries it into the same cap and no backup model is
|
|
140
|
-
* cooled down for it
|
|
157
|
+
* cooled down for it. The fix is a larger `maxTokens` or a lower effort. Any
|
|
141
158
|
* other empty turn is `overload`, because that is both true and useful: it is
|
|
142
159
|
* theirs and temporary, so it is transient (the same model, retried, usually
|
|
143
160
|
* answers) and backup-eligible (a model that keeps doing it should be walked
|
|
144
161
|
* away from). Until something streams, the empty frames are held back, so the
|
|
145
|
-
* retry rule
|
|
162
|
+
* retry rule still holds: retry only while nothing was emitted.
|
|
146
163
|
*/
|
|
147
164
|
export async function* requireContent(provider, chunks, opts = {}) {
|
|
148
165
|
const held = [];
|
|
@@ -186,7 +203,7 @@ export async function* requireContent(provider, chunks, opts = {}) {
|
|
|
186
203
|
const spent = usage?.reasoningTokens
|
|
187
204
|
? ` (${usage.reasoningTokens} of ${usage.outputTokens} output tokens went to reasoning)`
|
|
188
205
|
: "";
|
|
189
|
-
throw new ProviderError(provider, "invalid", `${provider}: the output cap ran out before any answer${spent}
|
|
206
|
+
throw new ProviderError(provider, "invalid", `${provider}: the output cap ran out before any answer${spent}. Raise maxTokens or lower effort.`);
|
|
190
207
|
}
|
|
191
208
|
throw new ProviderError(provider, "overload", `${provider}: completed with no content`);
|
|
192
209
|
}
|
|
@@ -194,8 +211,8 @@ export async function* requireContent(provider, chunks, opts = {}) {
|
|
|
194
211
|
* A provider with both silent failures already handled.
|
|
195
212
|
*
|
|
196
213
|
* Every consumer of this package wrote the same three lines around every
|
|
197
|
-
* `createStream
|
|
198
|
-
* the chunks
|
|
214
|
+
* `createStream`: build a watch, hand the provider the watch's signal, wrap
|
|
215
|
+
* the chunks. The middle one is the trap. Pass the caller's signal
|
|
199
216
|
* instead and everything still compiles, still streams, still passes the
|
|
200
217
|
* tests: the watchdog simply never aborts anything, because the request it was
|
|
201
218
|
* meant to cancel was never told about it. The failure has no symptom until
|
|
@@ -203,8 +220,10 @@ export async function* requireContent(provider, chunks, opts = {}) {
|
|
|
203
220
|
*
|
|
204
221
|
* So the composition belongs here rather than in a docs snippet each app
|
|
205
222
|
* copies. The result is still a `Provider`, so it composes unchanged with
|
|
206
|
-
* `withStreamRetry` and `streamWithBackupModels
|
|
207
|
-
*
|
|
223
|
+
* `withStreamRetry` and `streamWithBackupModels`. Timeouts and empty turns
|
|
224
|
+
* without a `length` finish are transient, so wrapping it in a retry is safe.
|
|
225
|
+
* The one timeout a replay would make worse, no response at all within the
|
|
226
|
+
* progress window, says so itself with `shouldRetry: false`.
|
|
208
227
|
*/
|
|
209
228
|
export function withWatchdog(provider, opts = {}) {
|
|
210
229
|
return {
|