@providerkit/core 0.15.1 → 0.16.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/dist/errors.d.ts +17 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +55 -6
- package/dist/errors.js.map +1 -1
- package/dist/presets.d.ts +37 -2
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +37 -2
- package/dist/presets.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +46 -17
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +25 -1
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +44 -16
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/responses.d.ts.map +1 -1
- package/dist/providers/responses.js +131 -24
- package/dist/providers/responses.js.map +1 -1
- package/dist/rate-limit.d.ts.map +1 -1
- package/dist/rate-limit.js +53 -22
- package/dist/rate-limit.js.map +1 -1
- package/dist/schema.d.ts +10 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +49 -0
- package/dist/schema.js.map +1 -1
- package/dist/transport.d.ts +30 -3
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +67 -28
- package/dist/transport.js.map +1 -1
- package/dist/types.d.ts +26 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/usage.d.ts +5 -4
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +14 -5
- package/dist/usage.js.map +1 -1
- package/dist/watchdog.d.ts +22 -8
- package/dist/watchdog.d.ts.map +1 -1
- package/dist/watchdog.js +77 -27
- package/dist/watchdog.js.map +1 -1
- package/package.json +3 -2
- package/src/errors.ts +60 -5
- package/src/presets.ts +37 -2
- package/src/providers/anthropic.ts +50 -17
- package/src/providers/gemini.ts +30 -1
- package/src/providers/openai.ts +42 -16
- package/src/providers/responses.ts +158 -26
- package/src/rate-limit.ts +55 -24
- package/src/schema.ts +51 -0
- package/src/transport.ts +95 -24
- package/src/types.ts +26 -2
- package/src/usage.ts +14 -5
- package/src/watchdog.ts +89 -32
package/dist/types.d.ts
CHANGED
|
@@ -127,10 +127,19 @@ export interface TokenUsage {
|
|
|
127
127
|
* prefixes and bill the hit portion far cheaper, so it must be tracked
|
|
128
128
|
* separately to cost a turn correctly. 0 when the provider reports none. */
|
|
129
129
|
cachedInputTokens: number;
|
|
130
|
-
/** Tokens WRITTEN to cache
|
|
131
|
-
* the
|
|
130
|
+
/** Tokens WRITTEN to cache — also a subset of `inputTokens`, so the total
|
|
131
|
+
* stays the whole prompt the window has to hold. Anthropic bills these
|
|
132
|
+
* above the input rate; the OpenAI-shape auto-cachers bill them at it.
|
|
133
|
+
* 0 when not reported. */
|
|
132
134
|
cacheWriteTokens?: number;
|
|
133
135
|
outputTokens: number;
|
|
136
|
+
/**
|
|
137
|
+
* The part of `outputTokens` spent thinking, when the provider reports it —
|
|
138
|
+
* already INSIDE `outputTokens`, so never add it again. It is the number
|
|
139
|
+
* that explains a turn that came back empty with a length finish: the
|
|
140
|
+
* reasoning ate the budget. Anthropic does not report it; absent there.
|
|
141
|
+
*/
|
|
142
|
+
reasoningTokens?: number;
|
|
134
143
|
/**
|
|
135
144
|
* What the provider says this call cost, in USD: its bill, not our
|
|
136
145
|
* arithmetic. Only OpenRouter sends one today. It is the one number a rate
|
|
@@ -254,6 +263,21 @@ export interface StreamOptions {
|
|
|
254
263
|
* caches by it); every other endpoint ignores it.
|
|
255
264
|
*/
|
|
256
265
|
sessionId?: string;
|
|
266
|
+
/**
|
|
267
|
+
* Called when the response headers arrive and on every read of the body
|
|
268
|
+
* after, keep-alives included. `withWatchdog` sets it: a stream that is only
|
|
269
|
+
* sending keep-alives is alive, which no chunk an adapter yields can show.
|
|
270
|
+
* Every adapter here forwards it; a custom Provider that does not still
|
|
271
|
+
* works, on the watchdog's progress clock alone.
|
|
272
|
+
*/
|
|
273
|
+
onActivity?: () => void;
|
|
274
|
+
/**
|
|
275
|
+
* `false` asks for at most one tool call per turn — for tools that must run
|
|
276
|
+
* in order, or a backend lane that refuses parallel calls. Absent or `true`
|
|
277
|
+
* is every vendor's default and sends nothing. Gemini has no such switch,
|
|
278
|
+
* so it refuses `false` rather than silently ignore it.
|
|
279
|
+
*/
|
|
280
|
+
parallelToolCalls?: boolean;
|
|
257
281
|
}
|
|
258
282
|
export interface Provider {
|
|
259
283
|
readonly id: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,2EAA2E;AAC3E,mEAAmE;AACnE,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,6EAA6E;AAC7E,0BAA0B;AAE1B;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAU,CAAC;AAGzE,2EAA2E;AAC3E,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC;AACpD,CAAC;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,2EAA2E;AAC3E,mEAAmE;AACnE,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,6EAA6E;AAC7E,0BAA0B;AAE1B;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAU,CAAC;AAGzE,2EAA2E;AAC3E,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC;AACpD,CAAC;AAsJD,MAAM,CAAC,MAAM,WAAW,GAAe;IACrC,WAAW,EAAE,CAAC;IACd,iBAAiB,EAAE,CAAC;IACpB,YAAY,EAAE,CAAC;CAChB,CAAC;AAuCF;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IACnE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAC7B,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,WAAW,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,SAAS,EAAE,CAAC;YACnB,yEAAyE;YACzE,sEAAsE;YACtE,0EAA0E;YAC1E,4EAA4E;YAC5E,MAAM,IAAI,eAAe,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,IAAY,EAAE,SAAiB;IAClD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAED;iFACiF;AACjF,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,IAAI,CAAS;IAEtB,YAAY,IAAY,EAAE,KAAc;QACtC,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,KAAK,CAAC,mCAAmC,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC;CACF;AAED;;;;;;;;kEAQkE;AAClE,MAAM,YAAY,GAAG,iEAAiE,CAAC;AAEvF,SAAS,WAAW,CAAC,IAAY;IAC/B,KAAK,MAAM,CAAC,EAAE,IAAI,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9E,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACpC,IAAI,QAAQ,KAAK,EAAE,IAAI,QAAQ,KAAK,MAAM;YAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACpE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;uEAMuE;AACvE,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,IAAI,KAAK,IAAI;gBAAE,CAAC,EAAE,CAAC;iBAClB,IAAI,IAAI,KAAK,GAAG;gBAAE,QAAQ,GAAG,KAAK,CAAC;QAC1C,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG;YAAE,QAAQ,GAAG,IAAI,CAAC;aACpC,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG;YAAE,KAAK,EAAE,CAAC;aAC1C,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACtC,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AA6FD;kEACkE;AAClE,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAoC,EACpC,KAAa;IAEb,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,4EAA4E;IAC5E,4EAA4E;IAC5E,yEAAyE;IACzE,6DAA6D;IAC7D,IAAI,gBAAuC,CAAC;IAC5C,IAAI,KAAK,GAAe,WAAW,CAAC;IACpC,IAAI,YAAY,GAAwB,IAAI,CAAC;IAC7C,IAAI,MAA+B,CAAC;IACpC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,MAAM;YAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QACxC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC3B,IAAI,KAAK,CAAC,OAAO;gBAAE,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC;YACzC,IAAI,KAAK,CAAC,SAAS;gBAAE,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC;YAClD,IAAI,KAAK,CAAC,gBAAgB,EAAE,MAAM;gBAAE,gBAAgB,GAAG,KAAK,CAAC,gBAAgB,CAAC;QAChF,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACjD,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QACtB,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YACzD,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;QACpC,CAAC;IACH,CAAC;IACD,OAAO;QACL,IAAI;QACJ,SAAS;QACT,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,KAAK;QACL,YAAY;QACZ,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,KAAK;QAC7B,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgC;IAC7D,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC9B,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW;YAAE,OAAO,OAAO,CAAC;QACjD,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,OAAO,CAAC,gBAAgB,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC;QAC9F,yEAAyE;QACzE,yEAAyE;QACzE,iEAAiE;QACjE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;QAC1E,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,SAAS,CAAC,IAAe;IACvC,OAAO,QAAQ,IAAI,CAAC,QAAQ,WAAW,IAAI,CAAC,IAAI,EAAE,CAAC;AACrD,CAAC"}
|
package/dist/usage.d.ts
CHANGED
|
@@ -31,10 +31,11 @@ export declare function subtractUsage(a: TokenUsage, b: TokenUsage): TokenUsage;
|
|
|
31
31
|
* A cost the provider reported wins outright, including a reported 0: a free
|
|
32
32
|
* call priced at the rate would be billed for something nobody charged.
|
|
33
33
|
*
|
|
34
|
-
* Cached tokens are
|
|
35
|
-
* bills at the full rate
|
|
36
|
-
* clamped to `input` so an over-reporting
|
|
37
|
-
* count negative nor bill for more prompt
|
|
34
|
+
* Cached and written tokens are SUBSETS of input, not additions to it: the
|
|
35
|
+
* miss part bills at the full rate, the hit part at the cache rate, the write
|
|
36
|
+
* part at the write rate. `cached` is clamped to `input` so an over-reporting
|
|
37
|
+
* provider can neither drive the miss count negative nor bill for more prompt
|
|
38
|
+
* than it was sent.
|
|
38
39
|
*/
|
|
39
40
|
export declare function costUsd(usage: TokenUsage, rate: ModelRate): number;
|
|
40
41
|
/**
|
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,
|
|
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;6CACyC;IACzC,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
|
@@ -9,6 +9,9 @@ export function addUsage(a, b) {
|
|
|
9
9
|
cachedInputTokens: a.cachedInputTokens + b.cachedInputTokens,
|
|
10
10
|
cacheWriteTokens: (a.cacheWriteTokens ?? 0) + (b.cacheWriteTokens ?? 0),
|
|
11
11
|
outputTokens: a.outputTokens + b.outputTokens,
|
|
12
|
+
...(a.reasoningTokens !== undefined || b.reasoningTokens !== undefined
|
|
13
|
+
? { reasoningTokens: (a.reasoningTokens ?? 0) + (b.reasoningTokens ?? 0) }
|
|
14
|
+
: {}),
|
|
12
15
|
};
|
|
13
16
|
}
|
|
14
17
|
/**
|
|
@@ -21,6 +24,9 @@ export function subtractUsage(a, b) {
|
|
|
21
24
|
cachedInputTokens: Math.max(0, a.cachedInputTokens - b.cachedInputTokens),
|
|
22
25
|
cacheWriteTokens: Math.max(0, (a.cacheWriteTokens ?? 0) - (b.cacheWriteTokens ?? 0)),
|
|
23
26
|
outputTokens: Math.max(0, a.outputTokens - b.outputTokens),
|
|
27
|
+
...(a.reasoningTokens !== undefined
|
|
28
|
+
? { reasoningTokens: Math.max(0, a.reasoningTokens - (b.reasoningTokens ?? 0)) }
|
|
29
|
+
: {}),
|
|
24
30
|
};
|
|
25
31
|
}
|
|
26
32
|
/**
|
|
@@ -29,10 +35,11 @@ export function subtractUsage(a, b) {
|
|
|
29
35
|
* A cost the provider reported wins outright, including a reported 0: a free
|
|
30
36
|
* call priced at the rate would be billed for something nobody charged.
|
|
31
37
|
*
|
|
32
|
-
* Cached tokens are
|
|
33
|
-
* bills at the full rate
|
|
34
|
-
* clamped to `input` so an over-reporting
|
|
35
|
-
* count negative nor bill for more prompt
|
|
38
|
+
* Cached and written tokens are SUBSETS of input, not additions to it: the
|
|
39
|
+
* miss part bills at the full rate, the hit part at the cache rate, the write
|
|
40
|
+
* part at the write rate. `cached` is clamped to `input` so an over-reporting
|
|
41
|
+
* provider can neither drive the miss count negative nor bill for more prompt
|
|
42
|
+
* than it was sent.
|
|
36
43
|
*/
|
|
37
44
|
export function costUsd(usage, rate) {
|
|
38
45
|
if (usage.reportedCostUsd !== undefined)
|
|
@@ -40,7 +47,9 @@ export function costUsd(usage, rate) {
|
|
|
40
47
|
const input = Math.max(0, usage.inputTokens);
|
|
41
48
|
const cached = Math.min(Math.max(0, usage.cachedInputTokens), input);
|
|
42
49
|
const written = Math.max(0, usage.cacheWriteTokens ?? 0);
|
|
43
|
-
|
|
50
|
+
// Writes are inside `input` too. Left in the miss count they billed twice —
|
|
51
|
+
// once at the input rate, again at the write rate: 2.25× on Claude.
|
|
52
|
+
const miss = Math.max(0, input - cached - written);
|
|
44
53
|
const writeRate = rate.cacheWrite ?? rate.input;
|
|
45
54
|
return ((miss * rate.input +
|
|
46
55
|
cached * rate.cacheRead +
|
package/dist/usage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAmBzC;;;8DAG8D;AAC9D,MAAM,UAAU,QAAQ,CAAC,CAAa,EAAE,CAAa;IACnD,OAAO;QACL,WAAW,EAAE,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW;QAC1C,iBAAiB,EAAE,CAAC,CAAC,iBAAiB,GAAG,CAAC,CAAC,iBAAiB;QAC5D,gBAAgB,EAAE,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC;QACvE,YAAY,EAAE,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY;
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"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"}
|
package/dist/watchdog.d.ts
CHANGED
|
@@ -1,28 +1,36 @@
|
|
|
1
1
|
import type { Provider, ProviderChunk } from "./types.ts";
|
|
2
|
-
/** No byte at all for this long
|
|
2
|
+
/** No byte at all for this long, once the response has started, and the
|
|
3
|
+
* stream is dead. */
|
|
3
4
|
export declare const STREAM_IDLE_MS = 60000;
|
|
5
|
+
/** No chunk for this long — the wait for the response to start included —
|
|
6
|
+
* and the stream is going nowhere, keep-alives or not. */
|
|
7
|
+
export declare const STREAM_PROGRESS_MS = 300000;
|
|
4
8
|
export interface StreamWatch {
|
|
5
9
|
/** Hand this to the provider in place of the caller's signal. */
|
|
6
10
|
readonly signal: AbortSignal;
|
|
7
|
-
/** A
|
|
11
|
+
/** A chunk arrived: re-arm both deadlines, and mark TTFT if it was the first. */
|
|
8
12
|
sawByte(): void;
|
|
13
|
+
/** The response showed life without a chunk — its headers, a keep-alive, a
|
|
14
|
+
* partial frame. Starts or re-arms the idle deadline only. */
|
|
15
|
+
sawActivity(): void;
|
|
9
16
|
/**
|
|
10
|
-
* Milliseconds from the call opening to its first
|
|
17
|
+
* Milliseconds from the call opening to its first chunk of any kind — the
|
|
11
18
|
* wait a person actually experiences, and the number a prompt-cache pin
|
|
12
19
|
* exists to shrink. Null until something arrives.
|
|
13
20
|
*/
|
|
14
21
|
firstChunkMs(): number | null;
|
|
15
22
|
/**
|
|
16
|
-
* Re-issue a provider failure as the
|
|
17
|
-
*
|
|
23
|
+
* Re-issue a provider failure as the timeout when — and only when — it was
|
|
24
|
+
* one of our deadlines that aborted. A caller's Stop passes through untouched.
|
|
18
25
|
*/
|
|
19
26
|
classify(err: unknown): unknown;
|
|
20
|
-
/** Clear the deadline
|
|
27
|
+
/** Clear the deadline timers. Safe to call more than once. */
|
|
21
28
|
dispose(): void;
|
|
22
29
|
}
|
|
23
30
|
export interface StreamWatchOptions {
|
|
24
31
|
provider?: string;
|
|
25
32
|
idleMs?: number;
|
|
33
|
+
progressMs?: number;
|
|
26
34
|
signal?: AbortSignal;
|
|
27
35
|
}
|
|
28
36
|
export declare function streamWatch(opts?: StreamWatchOptions): StreamWatch;
|
|
@@ -47,10 +55,16 @@ export declare function watchChunks<T>(watch: StreamWatch, chunks: AsyncIterable
|
|
|
47
55
|
* The throw lands before any chunk is yielded downstream, so the retry rule
|
|
48
56
|
* that matters — retry only while nothing was emitted — still holds.
|
|
49
57
|
*/
|
|
50
|
-
export declare function requireContent<T extends ProviderChunk>(provider: string, chunks: AsyncIterable<T
|
|
58
|
+
export declare function requireContent<T extends ProviderChunk>(provider: string, chunks: AsyncIterable<T>, opts?: {
|
|
59
|
+
afterToolResult?: boolean;
|
|
60
|
+
}): AsyncGenerator<T>;
|
|
51
61
|
export interface WatchdogOptions {
|
|
52
|
-
/**
|
|
62
|
+
/** No byte this long after the response starts and the stream is dead.
|
|
63
|
+
* Defaults to `STREAM_IDLE_MS`. */
|
|
53
64
|
idleMs?: number;
|
|
65
|
+
/** No chunk this long, from the POST on, and the stream is going nowhere.
|
|
66
|
+
* Defaults to `STREAM_PROGRESS_MS`. */
|
|
67
|
+
progressMs?: number;
|
|
54
68
|
/**
|
|
55
69
|
* Reject a turn that ends having said nothing, as `requireContent` does. On
|
|
56
70
|
* by default: an empty completion is a failure in every loop, and the one
|
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":"AA+BA,OAAO,KAAK,EAEV,QAAQ,EACR,aAAa,EAGd,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,CAgEtE;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;;;;;;;;;;;;;;GAcG;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,CAkCnB;AAED,MAAM,WAAW,eAAe;IAC9B;wCACoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;4CACwC;IACxC,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;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,GAAE,eAAoB,GAAG,QAAQ,CA8CrF"}
|
package/dist/watchdog.js
CHANGED
|
@@ -1,31 +1,49 @@
|
|
|
1
1
|
// The two ways a stream fails without failing: it goes silent, or it ends
|
|
2
2
|
// having said nothing at all.
|
|
3
3
|
//
|
|
4
|
-
// The stream
|
|
4
|
+
// The stream watchdog.
|
|
5
5
|
//
|
|
6
6
|
// A provider that stops sending bytes is indistinguishable from a long prefill
|
|
7
7
|
// — except that it never ends, and every SDK's default is to wait forever. A
|
|
8
8
|
// queued route or a wedged prefill upstream hangs the caller indefinitely, and
|
|
9
9
|
// the symptom is the worst kind: nothing. No error, no log, no timeout.
|
|
10
10
|
//
|
|
11
|
-
// So the seam gives itself
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
11
|
+
// So the seam gives itself two deadlines, because "silent" means two things:
|
|
12
|
+
//
|
|
13
|
+
// - IDLE: no byte at all, keep-alives included, for a minute after the
|
|
14
|
+
// response started. A dead socket. Any read re-arms it — a keep-alive is
|
|
15
|
+
// proof of life no chunk can carry (cc-proxy pings every 15s while it
|
|
16
|
+
// buffers a long tool call, and the old chunk-only clock killed those turns).
|
|
17
|
+
// - PROGRESS: no chunk for five minutes, counted from the POST. A stream that
|
|
18
|
+
// is alive and going nowhere — a route parked behind keep-alives — and the
|
|
19
|
+
// wait for the response to START, which is the one some backends take
|
|
20
|
+
// minutes over: the ChatGPT backend withholds its headers until the model's
|
|
21
|
+
// first output, so a high-effort turn on a large prompt sends nothing at all
|
|
22
|
+
// for minutes and is healthy the whole time (cc-proxy defaults that wait to
|
|
23
|
+
// 300s, measured). On a one-minute clock it was aborted and retried from
|
|
24
|
+
// scratch, which re-ran the reasoning into the same deadline.
|
|
25
|
+
//
|
|
26
|
+
// When either fires, the watchdog aborts ITS OWN controller and the caller's
|
|
27
|
+
// signal is only bridged in — which is what keeps a person's Stop
|
|
15
28
|
// distinguishable from our timeout. One is their cancel and is never retried;
|
|
16
29
|
// the other is ours, is transient, and fires while nothing has streamed yet,
|
|
17
30
|
// so the retry is always safe.
|
|
18
31
|
import { ProviderError } from "./errors.js";
|
|
19
|
-
/** No byte at all for this long
|
|
32
|
+
/** No byte at all for this long, once the response has started, and the
|
|
33
|
+
* stream is dead. */
|
|
20
34
|
export const STREAM_IDLE_MS = 60_000;
|
|
35
|
+
/** No chunk for this long — the wait for the response to start included —
|
|
36
|
+
* and the stream is going nowhere, keep-alives or not. */
|
|
37
|
+
export const STREAM_PROGRESS_MS = 300_000;
|
|
21
38
|
export function streamWatch(opts = {}) {
|
|
22
39
|
const provider = opts.provider ?? "provider";
|
|
23
40
|
const idleMs = opts.idleMs ?? STREAM_IDLE_MS;
|
|
41
|
+
const progressMs = opts.progressMs ?? STREAM_PROGRESS_MS;
|
|
24
42
|
const callerSignal = opts.signal;
|
|
25
43
|
const started = Date.now();
|
|
26
44
|
const timeout = new AbortController();
|
|
27
45
|
let firstChunk = null;
|
|
28
|
-
let
|
|
46
|
+
let fired = null;
|
|
29
47
|
let disposed = false;
|
|
30
48
|
// The bridge is structural rather than an event listener: AbortSignal.any
|
|
31
49
|
// aborts synchronously when an input is ALREADY aborted, which is the race
|
|
@@ -33,38 +51,48 @@ export function streamWatch(opts = {}) {
|
|
|
33
51
|
// the package's runtime floor — see `engines` — rather than a polyfilled
|
|
34
52
|
// nicety: every runtime this package targets has had it for years.
|
|
35
53
|
const signal = callerSignal ? AbortSignal.any([callerSignal, timeout.signal]) : timeout.signal;
|
|
36
|
-
|
|
37
|
-
cause,
|
|
38
|
-
});
|
|
39
|
-
function arm() {
|
|
54
|
+
function deadline(ms, what) {
|
|
40
55
|
const timer = setTimeout(() => {
|
|
41
|
-
|
|
42
|
-
timeout.abort(
|
|
43
|
-
},
|
|
56
|
+
fired = new ProviderError(provider, "timeout", `stream went ${ms / 1000}s without ${what}`);
|
|
57
|
+
timeout.abort(fired);
|
|
58
|
+
}, ms);
|
|
44
59
|
// An orphaned watch — its consumer gone, dispose never called — must not
|
|
45
60
|
// hold a Node event loop open for a full deadline.
|
|
46
61
|
timer.unref?.();
|
|
47
62
|
return timer;
|
|
48
63
|
}
|
|
49
|
-
|
|
64
|
+
// The idle clock waits for the response to start; until then only the
|
|
65
|
+
// progress clock runs (see the header comment).
|
|
66
|
+
let idle;
|
|
67
|
+
let progress = deadline(progressMs, "a chunk");
|
|
68
|
+
const live = () => !disposed && !signal.aborted;
|
|
69
|
+
function sawActivity() {
|
|
70
|
+
clearTimeout(idle);
|
|
71
|
+
if (live())
|
|
72
|
+
idle = deadline(idleMs, "a byte");
|
|
73
|
+
}
|
|
50
74
|
return {
|
|
51
75
|
signal,
|
|
52
76
|
sawByte() {
|
|
53
77
|
firstChunk ??= Date.now() - started;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
78
|
+
sawActivity();
|
|
79
|
+
clearTimeout(progress);
|
|
80
|
+
if (live())
|
|
81
|
+
progress = deadline(progressMs, "a chunk");
|
|
57
82
|
},
|
|
83
|
+
sawActivity,
|
|
58
84
|
firstChunkMs: () => firstChunk,
|
|
59
85
|
classify(err) {
|
|
60
86
|
// Our deadline, not theirs — and not the caller's Stop.
|
|
61
|
-
if (
|
|
62
|
-
return
|
|
87
|
+
if (fired && !(callerSignal?.aborted ?? false)) {
|
|
88
|
+
return new ProviderError(fired.provider, "timeout", fired.message, { cause: err });
|
|
89
|
+
}
|
|
63
90
|
return err;
|
|
64
91
|
},
|
|
65
92
|
dispose() {
|
|
66
93
|
disposed = true;
|
|
67
|
-
clearTimeout(
|
|
94
|
+
clearTimeout(idle);
|
|
95
|
+
clearTimeout(progress);
|
|
68
96
|
},
|
|
69
97
|
};
|
|
70
98
|
}
|
|
@@ -102,10 +130,13 @@ export async function* watchChunks(watch, chunks) {
|
|
|
102
130
|
* The throw lands before any chunk is yielded downstream, so the retry rule
|
|
103
131
|
* that matters — retry only while nothing was emitted — still holds.
|
|
104
132
|
*/
|
|
105
|
-
export async function* requireContent(provider, chunks) {
|
|
133
|
+
export async function* requireContent(provider, chunks, opts = {}) {
|
|
106
134
|
const held = [];
|
|
107
135
|
let usable = false;
|
|
136
|
+
let finish;
|
|
108
137
|
for await (const chunk of chunks) {
|
|
138
|
+
if (chunk.type === "finish")
|
|
139
|
+
finish = chunk.finishReason;
|
|
109
140
|
if (!usable) {
|
|
110
141
|
usable = Boolean(chunk.content || chunk.reasoning || chunk.toolCalls?.length);
|
|
111
142
|
// Held rather than forwarded: once a chunk is out, the stream is
|
|
@@ -121,9 +152,18 @@ export async function* requireContent(provider, chunks) {
|
|
|
121
152
|
}
|
|
122
153
|
yield chunk;
|
|
123
154
|
}
|
|
124
|
-
if (
|
|
125
|
-
|
|
155
|
+
if (usable)
|
|
156
|
+
return;
|
|
157
|
+
// The one empty turn that is an answer: the model read a tool result and
|
|
158
|
+
// chose to stop. An agent whose reply IS a tool (a chat bot's send_message)
|
|
159
|
+
// ends every turn this way — retried, cc-proxy measured one such bot
|
|
160
|
+
// failing ~68% of real turns (11 retries, ~3 minutes, then an error). A
|
|
161
|
+
// `length` stop or no finish at all is still the failure this guard is for.
|
|
162
|
+
if (opts.afterToolResult && finish === "stop") {
|
|
163
|
+
yield* held;
|
|
164
|
+
return;
|
|
126
165
|
}
|
|
166
|
+
throw new ProviderError(provider, "overload", `${provider}: completed with no content`);
|
|
127
167
|
}
|
|
128
168
|
/**
|
|
129
169
|
* A provider with both silent failures already handled.
|
|
@@ -148,20 +188,26 @@ export function withWatchdog(provider, opts = {}) {
|
|
|
148
188
|
// Armed on first read, not here: a stream built now and iterated later
|
|
149
189
|
// must not spend its deadline sitting in a variable.
|
|
150
190
|
async function* watched() {
|
|
151
|
-
//
|
|
191
|
+
// The deadlines and signal all default inside streamWatch.
|
|
152
192
|
const watch = streamWatch({
|
|
153
193
|
provider: provider.id,
|
|
154
194
|
idleMs: opts.idleMs,
|
|
195
|
+
progressMs: opts.progressMs,
|
|
155
196
|
signal: streamOpts.signal,
|
|
156
197
|
});
|
|
198
|
+
const callerActivity = streamOpts.onActivity;
|
|
157
199
|
const source = provider.createStream(messages, tools, {
|
|
158
200
|
...streamOpts,
|
|
159
201
|
signal: watch.signal,
|
|
202
|
+
onActivity: () => {
|
|
203
|
+
watch.sawActivity();
|
|
204
|
+
callerActivity?.();
|
|
205
|
+
},
|
|
160
206
|
});
|
|
161
207
|
let reported = false;
|
|
162
208
|
for await (const chunk of watchChunks(watch, source)) {
|
|
163
209
|
// Before `requireContent` holds anything back — TTFT is the first
|
|
164
|
-
//
|
|
210
|
+
// chunk of any kind, not the first one worth showing.
|
|
165
211
|
if (!reported) {
|
|
166
212
|
reported = true;
|
|
167
213
|
opts.onFirstChunk?.(watch.firstChunkMs() ?? 0);
|
|
@@ -169,7 +215,11 @@ export function withWatchdog(provider, opts = {}) {
|
|
|
169
215
|
yield chunk;
|
|
170
216
|
}
|
|
171
217
|
}
|
|
172
|
-
return opts.requireContent === false
|
|
218
|
+
return opts.requireContent === false
|
|
219
|
+
? watched()
|
|
220
|
+
: requireContent(provider.id, watched(), {
|
|
221
|
+
afterToolResult: messages.at(-1)?.role === "tool",
|
|
222
|
+
});
|
|
173
223
|
},
|
|
174
224
|
};
|
|
175
225
|
}
|
package/dist/watchdog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watchdog.js","sourceRoot":"","sources":["../src/watchdog.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,8BAA8B;AAC9B,EAAE;AACF,
|
|
1
|
+
{"version":3,"file":"watchdog.js","sourceRoot":"","sources":["../src/watchdog.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@providerkit/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "The layer under your agent loop: one seam for every LLM provider, plus the failure handling you only learn in production.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
],
|
|
47
47
|
"scripts": {
|
|
48
48
|
"build": "tsc",
|
|
49
|
-
"typecheck": "tsc --noEmit && tsc -p test",
|
|
49
|
+
"typecheck": "tsc --noEmit && tsc -p test && tsc -p scripts",
|
|
50
50
|
"test": "vitest run",
|
|
51
51
|
"test:watch": "vitest",
|
|
52
52
|
"lint": "eslint src test",
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
|
+
"@types/node": "^24.13.3",
|
|
73
74
|
"typescript": "^5.9.3",
|
|
74
75
|
"vitest": "^4.1.2",
|
|
75
76
|
"zod": "^4.3.6"
|
package/src/errors.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// read before the status — status alone gives the wrong advice ("retry" for an
|
|
11
11
|
// empty balance, "check your key" for a plan that never included the API).
|
|
12
12
|
|
|
13
|
-
import { parseUsageLimitBody, type RateLimitWindow } from "./rate-limit.ts";
|
|
13
|
+
import { parseRateLimitResponse, parseUsageLimitBody, type RateLimitWindow } from "./rate-limit.ts";
|
|
14
14
|
import type { FilePart } from "./types.ts";
|
|
15
15
|
|
|
16
16
|
/** What kind of failure this is, named by what actually fixes it. */
|
|
@@ -379,6 +379,12 @@ const QUOTA_PATTERNS: readonly RegExp[] = [
|
|
|
379
379
|
/usage limits? (?:reached|exceeded|hit)/i,
|
|
380
380
|
/reached your (?:usage|weekly|monthly|daily) limit/i,
|
|
381
381
|
/(?:weekly|monthly|daily|plan) usage limit/i,
|
|
382
|
+
// The ChatGPT backend's spent-window error: `usage_limit_reached`, worded
|
|
383
|
+
// "The usage limit has been reached". As a 429 it read as a throttle and in
|
|
384
|
+
// a stream as an overload, so the backup walker spent every model on the
|
|
385
|
+
// same account-wide wall (cc-proxy: "a 502 retry storm").
|
|
386
|
+
/usage[_\s]limit[_\s]reached/i,
|
|
387
|
+
/usage limit has been reached/i,
|
|
382
388
|
/purchase extra usage/i,
|
|
383
389
|
/upgrade your plan/i,
|
|
384
390
|
/quota\b[^.]{0,40}\b(?:exhausted|exceeded|will be refreshed)/i,
|
|
@@ -429,6 +435,12 @@ const CONTENT_PATTERNS: readonly RegExp[] = [
|
|
|
429
435
|
/content policy/i,
|
|
430
436
|
/cyber[_\s]policy/i,
|
|
431
437
|
/safety|PROHIBITED_CONTENT|blocked|refusal|policy violation|misalignment/i,
|
|
438
|
+
// OpenAI's flagged-prompt codes. They arrive with no status inside a stream,
|
|
439
|
+
// where an unnamed failure is floored to overload and retried — three more
|
|
440
|
+
// copies of a prompt that will be flagged every time.
|
|
441
|
+
/\binvalid_prompt\b/,
|
|
442
|
+
/\bbio[_\s]policy\b/i,
|
|
443
|
+
/violat\w* (?:our |the )?usage polic/i,
|
|
432
444
|
// Document and media boundary violations
|
|
433
445
|
/maximum of \d+ PDF pages/i,
|
|
434
446
|
/PDF specified is password protected/i,
|
|
@@ -576,8 +588,10 @@ export function parseRetryAfterMs(err: unknown, body?: string): number | undefin
|
|
|
576
588
|
? (headers as Record<string, unknown>)["retry-after"]
|
|
577
589
|
: undefined;
|
|
578
590
|
if (typeof value !== "string") return undefined;
|
|
579
|
-
// Seconds, or an HTTP-date — both are legal per RFC 9110.
|
|
580
|
-
|
|
591
|
+
// Seconds, or an HTTP-date — both are legal per RFC 9110. Seconds are read
|
|
592
|
+
// as a NUMBER first: `Date.parse("1.5")` is a day in 2001, a wait of zero.
|
|
593
|
+
const seconds = Number(value.trim());
|
|
594
|
+
if (value.trim() !== "" && Number.isFinite(seconds) && seconds >= 0) return seconds * 1000;
|
|
581
595
|
const date = Date.parse(value);
|
|
582
596
|
return Number.isNaN(date) ? undefined : Math.max(0, date - Date.now());
|
|
583
597
|
}
|
|
@@ -660,7 +674,8 @@ export function parseContextOverflow(err: unknown, body?: string): ContextOverfl
|
|
|
660
674
|
*/
|
|
661
675
|
export function streamError(provider: string, error: unknown): ProviderError {
|
|
662
676
|
const body = JSON.stringify(error ?? {}) ?? "";
|
|
663
|
-
const status =
|
|
677
|
+
const status =
|
|
678
|
+
readNumber(error, "code") ?? readNumber(error, "status") ?? readNumber(error, "status_code");
|
|
664
679
|
const code =
|
|
665
680
|
readString(error, "code") ?? readString(error, "status") ?? readString(error, "type");
|
|
666
681
|
const kind = classifyHttp(status, body);
|
|
@@ -672,12 +687,52 @@ export function streamError(provider: string, error: unknown): ProviderError {
|
|
|
672
687
|
...(status !== undefined ? { status } : {}),
|
|
673
688
|
...(code ? { code } : {}),
|
|
674
689
|
retryAfterMs: parseRetryAfterMs(error, body),
|
|
675
|
-
...
|
|
690
|
+
...readReset(error, body),
|
|
676
691
|
body: body.slice(0, 2_000),
|
|
677
692
|
},
|
|
678
693
|
);
|
|
679
694
|
}
|
|
680
695
|
|
|
696
|
+
/** The reset a stream error carries: the body's clock, plus the rate-limit
|
|
697
|
+
* headers the ChatGPT backend mirrors INTO its error frame — the only place a
|
|
698
|
+
* failure after the 200 can say which window ran out. */
|
|
699
|
+
function readReset(error: unknown, body: string) {
|
|
700
|
+
const raw =
|
|
701
|
+
typeof error === "object" && error !== null
|
|
702
|
+
? (error as { headers?: unknown }).headers
|
|
703
|
+
: undefined;
|
|
704
|
+
if (typeof raw !== "object" || raw === null) return parseUsageLimitBody(body);
|
|
705
|
+
const headers = new Headers();
|
|
706
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
707
|
+
if (typeof value === "string" || typeof value === "number") headers.set(name, String(value));
|
|
708
|
+
}
|
|
709
|
+
return parseRateLimitResponse(headers, body);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* A stream that closed before its turn did: no finish stated, no terminal
|
|
714
|
+
* event, no `[DONE]`.
|
|
715
|
+
*
|
|
716
|
+
* It used to end quietly, with a null finish and no usage. Honest, and nobody
|
|
717
|
+
* read it: a caller that never checks the finish keeps half an answer as if it
|
|
718
|
+
* were the whole one, the ledger records a billed turn as free, and no pool
|
|
719
|
+
* learns the endpoint is dropping streams. cc-proxy shipped the same fix
|
|
720
|
+
* (0.1.39) for the same reason — "instead of marking affected streamed
|
|
721
|
+
* responses as successful".
|
|
722
|
+
*
|
|
723
|
+
* `network`, because that is what it is: the same failure as a socket that
|
|
724
|
+
* dies mid-read, seen from the other side of a clean close. Transient, so a
|
|
725
|
+
* cut that lands before anything was emitted is retried; one that lands after
|
|
726
|
+
* is not (invariant 1), and reaches the caller after everything it delivered.
|
|
727
|
+
*/
|
|
728
|
+
export function streamCut(provider: string): ProviderError {
|
|
729
|
+
return new ProviderError(
|
|
730
|
+
provider,
|
|
731
|
+
"network",
|
|
732
|
+
`${provider}: the stream ended before the turn did`,
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
|
|
681
736
|
/** The loggable surface of a failure — so a dead run never reads
|
|
682
737
|
* "400 status code (no body)". */
|
|
683
738
|
export function describeProviderError(err: unknown): Record<string, unknown> {
|