@providerkit/core 0.21.0 → 0.22.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/capability.d.ts +9 -9
- package/dist/capability.js +9 -9
- package/dist/capability.js.map +1 -1
- package/dist/context.d.ts +4 -4
- package/dist/context.js +4 -4
- package/dist/errors.d.ts +15 -15
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +14 -14
- 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 +4 -4
- package/dist/key-pool.js +6 -6
- package/dist/key-pool.js.map +1 -1
- package/dist/presets.d.ts +26 -22
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +13 -12
- 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 +9 -9
- 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 +2 -2
- package/dist/providers/gemini.d.ts.map +1 -1
- package/dist/providers/gemini.js +15 -14
- 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 +14 -13
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/responses.d.ts +3 -3
- package/dist/providers/responses.js +5 -5
- 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 +3 -3
- package/dist/rate-limit.js +3 -3
- package/dist/retry.d.ts +5 -5
- package/dist/retry.js +4 -4
- package/dist/schema.d.ts +6 -6
- package/dist/schema.js +8 -8
- package/dist/tool-args.d.ts +1 -1
- package/dist/tool-args.js +2 -2
- 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 +7 -7
- package/dist/transport.js +6 -6
- package/dist/types.d.ts +24 -23
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -3
- 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 +12 -12
- package/dist/watchdog.js +10 -10
- 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/capability.ts +12 -12
- package/src/context.ts +4 -4
- package/src/errors.ts +18 -18
- package/src/image.ts +1 -1
- package/src/jev.ts +11 -11
- package/src/key-pool.ts +7 -7
- package/src/presets.ts +26 -22
- package/src/providers/anthropic.ts +14 -14
- package/src/providers/factory.ts +4 -3
- package/src/providers/gemini.ts +19 -16
- package/src/providers/openai.ts +22 -17
- package/src/providers/responses.ts +11 -11
- package/src/providers/zai.ts +2 -2
- package/src/rate-limit.ts +4 -4
- package/src/retry.ts +5 -5
- package/src/schema.ts +8 -8
- package/src/tool-args.ts +2 -2
- package/src/tools.ts +4 -4
- package/src/transport.ts +7 -7
- package/src/types.ts +24 -23
- package/src/usage.ts +5 -5
- package/src/watchdog.ts +13 -13
- package/src/zod.ts +4 -4
package/src/usage.ts
CHANGED
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
import type { TokenUsage } from "./types.ts";
|
|
16
16
|
import { EMPTY_USAGE } from "./types.ts";
|
|
17
17
|
|
|
18
|
-
/** USD per
|
|
18
|
+
/** USD per million tokens, as every vendor prints its price sheet, so a row
|
|
19
19
|
* can be checked against one without arithmetic. */
|
|
20
20
|
export interface ModelRate {
|
|
21
21
|
/** Cache-MISS input: fresh tokens the provider had to read. */
|
|
22
22
|
input: number;
|
|
23
23
|
output: number;
|
|
24
24
|
/** Cache-HIT input. Providers auto-cache repeated prefixes and bill the hit
|
|
25
|
-
* portion far cheaper
|
|
25
|
+
* portion far cheaper: 0.1× on Anthropic, ~0.1× on Gemini, 0.5× on some
|
|
26
26
|
* OpenAI models. In an agent loop the re-sent context is overwhelmingly
|
|
27
27
|
* hits, so billing it at the miss rate overcounts by up to 10×. */
|
|
28
28
|
cacheRead: number;
|
|
@@ -95,14 +95,14 @@ export function costUsd(usage: TokenUsage, rate: ModelRate): number {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
/** What one call adds to a run: its reported cost, else its rate, else
|
|
98
|
-
* nothing
|
|
98
|
+
* nothing. An unpriced call still counts its tokens. */
|
|
99
99
|
function callCost(usage: TokenUsage, rate: ModelRate | undefined): number {
|
|
100
100
|
return rate ? costUsd(usage, rate) : (usage.reportedCostUsd ?? 0);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
/**
|
|
104
104
|
* Accumulates usage and cost across the calls of one run, pricing each with
|
|
105
|
-
* the rate in effect for the model that served it
|
|
105
|
+
* the rate in effect for the model that served it, so a run that switches to
|
|
106
106
|
* a backup model, or spans a time-of-day price boundary, still bills correctly.
|
|
107
107
|
* A call that carries a reported cost is billed that, with or without a rate.
|
|
108
108
|
*/
|
|
@@ -110,7 +110,7 @@ export class UsageTracker {
|
|
|
110
110
|
private usage: TokenUsage = { ...EMPTY_USAGE, cacheWriteTokens: 0 };
|
|
111
111
|
private cost = 0;
|
|
112
112
|
/** USD the cache hits saved, versus billing them all as misses.
|
|
113
|
-
* Observability only
|
|
113
|
+
* Observability only. Never billed. */
|
|
114
114
|
private saved = 0;
|
|
115
115
|
|
|
116
116
|
add(usage: TokenUsage, rate?: ModelRate): void {
|
package/src/watchdog.ts
CHANGED
|
@@ -42,7 +42,7 @@ import type {
|
|
|
42
42
|
* stream is dead. */
|
|
43
43
|
export const STREAM_IDLE_MS = 60_000;
|
|
44
44
|
|
|
45
|
-
/** No chunk for this long
|
|
45
|
+
/** No chunk for this long, including the wait for the response to start,
|
|
46
46
|
* and the stream is going nowhere, keep-alives or not. */
|
|
47
47
|
export const STREAM_PROGRESS_MS = 300_000;
|
|
48
48
|
|
|
@@ -51,17 +51,17 @@ export interface StreamWatch {
|
|
|
51
51
|
readonly signal: AbortSignal;
|
|
52
52
|
/** A chunk arrived: re-arm both deadlines, and mark TTFT if it was the first. */
|
|
53
53
|
sawByte(): void;
|
|
54
|
-
/** The response showed life without a chunk
|
|
54
|
+
/** The response showed life without a chunk: its headers, a keep-alive, a
|
|
55
55
|
* partial frame. Starts or re-arms the idle deadline only. */
|
|
56
56
|
sawActivity(): void;
|
|
57
57
|
/**
|
|
58
|
-
* Milliseconds from the call opening to its first chunk of any kind
|
|
58
|
+
* Milliseconds from the call opening to its first chunk of any kind. The
|
|
59
59
|
* wait a person actually experiences, and the number a prompt-cache pin
|
|
60
60
|
* exists to shrink. Null until something arrives.
|
|
61
61
|
*/
|
|
62
62
|
firstChunkMs(): number | null;
|
|
63
63
|
/**
|
|
64
|
-
* Re-issue a provider failure as the timeout
|
|
64
|
+
* Re-issue a provider failure as the timeout only when it was
|
|
65
65
|
* one of our deadlines that aborted. A caller's Stop passes through untouched.
|
|
66
66
|
*/
|
|
67
67
|
classify(err: unknown): unknown;
|
|
@@ -148,7 +148,7 @@ export function streamWatch(opts: StreamWatchOptions = {}): StreamWatch {
|
|
|
148
148
|
|
|
149
149
|
/**
|
|
150
150
|
* Wrap a stream so every chunk re-arms `watch`, and a failure is re-classified
|
|
151
|
-
* through it. Disposes on any exit
|
|
151
|
+
* through it. Disposes on any exit: completion, throw, or the consumer
|
|
152
152
|
* breaking out of the loop.
|
|
153
153
|
*/
|
|
154
154
|
export async function* watchChunks<T>(
|
|
@@ -173,7 +173,7 @@ export async function* watchChunks<T>(
|
|
|
173
173
|
* A stream that ends with no text and no tool call is a failure wearing a
|
|
174
174
|
* success's clothes: `stop_reason: end_turn` with zero content blocks, which
|
|
175
175
|
* the vendors emit under load, or a thinking block that ate the whole
|
|
176
|
-
* `max_tokens`. Nothing throws, so nothing retries
|
|
176
|
+
* `max_tokens`. Nothing throws, so nothing retries. The caller simply shows a
|
|
177
177
|
* person an empty answer, and the only trace is a bill.
|
|
178
178
|
*
|
|
179
179
|
* Reasoning is not an answer. It still streams the moment it arrives, so a
|
|
@@ -185,12 +185,12 @@ export async function* watchChunks<T>(
|
|
|
185
185
|
*
|
|
186
186
|
* Classified by what fixes it. A `length` finish is the caller's own cap:
|
|
187
187
|
* `invalid`, so nothing retries it into the same cap and no backup model is
|
|
188
|
-
* cooled down for it
|
|
188
|
+
* cooled down for it. The fix is a larger `maxTokens` or a lower effort. Any
|
|
189
189
|
* other empty turn is `overload`, because that is both true and useful: it is
|
|
190
190
|
* theirs and temporary, so it is transient (the same model, retried, usually
|
|
191
191
|
* answers) and backup-eligible (a model that keeps doing it should be walked
|
|
192
192
|
* away from). Until something streams, the empty frames are held back, so the
|
|
193
|
-
* retry rule
|
|
193
|
+
* retry rule still holds: retry only while nothing was emitted.
|
|
194
194
|
*/
|
|
195
195
|
export async function* requireContent<T extends ProviderChunk>(
|
|
196
196
|
provider: string,
|
|
@@ -240,7 +240,7 @@ export async function* requireContent<T extends ProviderChunk>(
|
|
|
240
240
|
throw new ProviderError(
|
|
241
241
|
provider,
|
|
242
242
|
"invalid",
|
|
243
|
-
`${provider}: the output cap ran out before any answer${spent}
|
|
243
|
+
`${provider}: the output cap ran out before any answer${spent}. Raise maxTokens or lower effort.`,
|
|
244
244
|
);
|
|
245
245
|
}
|
|
246
246
|
throw new ProviderError(provider, "overload", `${provider}: completed with no content`);
|
|
@@ -267,8 +267,8 @@ export interface WatchdogOptions {
|
|
|
267
267
|
* A provider with both silent failures already handled.
|
|
268
268
|
*
|
|
269
269
|
* Every consumer of this package wrote the same three lines around every
|
|
270
|
-
* `createStream
|
|
271
|
-
* the chunks
|
|
270
|
+
* `createStream`: build a watch, hand the provider the watch's signal, wrap
|
|
271
|
+
* the chunks. The middle one is the trap. Pass the caller's signal
|
|
272
272
|
* instead and everything still compiles, still streams, still passes the
|
|
273
273
|
* tests: the watchdog simply never aborts anything, because the request it was
|
|
274
274
|
* meant to cancel was never told about it. The failure has no symptom until
|
|
@@ -276,8 +276,8 @@ export interface WatchdogOptions {
|
|
|
276
276
|
*
|
|
277
277
|
* So the composition belongs here rather than in a docs snippet each app
|
|
278
278
|
* copies. The result is still a `Provider`, so it composes unchanged with
|
|
279
|
-
* `withStreamRetry` and `streamWithBackupModels
|
|
280
|
-
*
|
|
279
|
+
* `withStreamRetry` and `streamWithBackupModels`. Timeouts and empty turns
|
|
280
|
+
* without a `length` finish are transient, so wrapping it in a retry is safe.
|
|
281
281
|
*/
|
|
282
282
|
export function withWatchdog(provider: Provider, opts: WatchdogOptions = {}): Provider {
|
|
283
283
|
return {
|
package/src/zod.ts
CHANGED
|
@@ -12,8 +12,8 @@ import type { JsonObjectSchema } from "./types.ts";
|
|
|
12
12
|
* A zod schema as the JSON Schema every provider's tool contract wants.
|
|
13
13
|
*
|
|
14
14
|
* `$schema` is dropped. zod emits the dialect URI at the root, and a provider
|
|
15
|
-
* validating a tool's `parameters` against its own supported subset
|
|
16
|
-
* under `strict: true`, Gemini's `parametersJsonSchema`
|
|
15
|
+
* validating a tool's `parameters` against its own supported subset (OpenAI
|
|
16
|
+
* under `strict: true`, Gemini's `parametersJsonSchema`) rejects the whole
|
|
17
17
|
* tool over that one key, with a message that names neither zod nor the field.
|
|
18
18
|
*/
|
|
19
19
|
export function toJsonObjectSchema(schema: z.ZodType, label = "schema"): JsonObjectSchema {
|
|
@@ -46,14 +46,14 @@ export interface ZodToolSpec<I, O> {
|
|
|
46
46
|
* rejecting the call. Worth it for a TERMINAL tool, which gets no second
|
|
47
47
|
* chance: a forced-submit salvage turn runs exactly once, and discarding an
|
|
48
48
|
* otherwise-valid answer over a few extra characters loses the whole run.
|
|
49
|
-
* Off by default
|
|
49
|
+
* Off by default: an ordinary tool can simply be called again.
|
|
50
50
|
*/
|
|
51
51
|
clampOverflow?: boolean;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* A tool whose arguments are validated by zod, with the failure reported to
|
|
56
|
-
* the
|
|
56
|
+
* the model in words it can act on. `topic: expected string, received number`
|
|
57
57
|
* beats a stack trace it cannot read.
|
|
58
58
|
*/
|
|
59
59
|
export function zodTool<I, O>(spec: ZodToolSpec<I, O>): Tool<I, O> {
|