@providerkit/core 0.1.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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +245 -0
  3. package/dist/context.d.ts +69 -0
  4. package/dist/context.d.ts.map +1 -0
  5. package/dist/context.js +132 -0
  6. package/dist/context.js.map +1 -0
  7. package/dist/errors.d.ts +86 -0
  8. package/dist/errors.d.ts.map +1 -0
  9. package/dist/errors.js +356 -0
  10. package/dist/errors.js.map +1 -0
  11. package/dist/index.d.ts +13 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +13 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/providers/anthropic.d.ts +26 -0
  16. package/dist/providers/anthropic.d.ts.map +1 -0
  17. package/dist/providers/anthropic.js +245 -0
  18. package/dist/providers/anthropic.js.map +1 -0
  19. package/dist/providers/openai.d.ts +30 -0
  20. package/dist/providers/openai.d.ts.map +1 -0
  21. package/dist/providers/openai.js +185 -0
  22. package/dist/providers/openai.js.map +1 -0
  23. package/dist/retry.d.ts +79 -0
  24. package/dist/retry.d.ts.map +1 -0
  25. package/dist/retry.js +200 -0
  26. package/dist/retry.js.map +1 -0
  27. package/dist/schema.d.ts +2 -0
  28. package/dist/schema.d.ts.map +1 -0
  29. package/dist/schema.js +48 -0
  30. package/dist/schema.js.map +1 -0
  31. package/dist/tool-args.d.ts +12 -0
  32. package/dist/tool-args.d.ts.map +1 -0
  33. package/dist/tool-args.js +113 -0
  34. package/dist/tool-args.js.map +1 -0
  35. package/dist/tools.d.ts +82 -0
  36. package/dist/tools.d.ts.map +1 -0
  37. package/dist/tools.js +155 -0
  38. package/dist/tools.js.map +1 -0
  39. package/dist/transport.d.ts +31 -0
  40. package/dist/transport.d.ts.map +1 -0
  41. package/dist/transport.js +157 -0
  42. package/dist/transport.js.map +1 -0
  43. package/dist/types.d.ts +168 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +75 -0
  46. package/dist/types.js.map +1 -0
  47. package/dist/usage.d.ts +50 -0
  48. package/dist/usage.d.ts.map +1 -0
  49. package/dist/usage.js +71 -0
  50. package/dist/usage.js.map +1 -0
  51. package/dist/watchdog.d.ts +34 -0
  52. package/dist/watchdog.d.ts.map +1 -0
  53. package/dist/watchdog.js +85 -0
  54. package/dist/watchdog.js.map +1 -0
  55. package/dist/zod.d.ts +32 -0
  56. package/dist/zod.d.ts.map +1 -0
  57. package/dist/zod.js +49 -0
  58. package/dist/zod.js.map +1 -0
  59. package/package.json +76 -0
  60. package/src/context.ts +150 -0
  61. package/src/errors.ts +398 -0
  62. package/src/index.ts +12 -0
  63. package/src/providers/anthropic.ts +315 -0
  64. package/src/providers/openai.ts +246 -0
  65. package/src/retry.ts +246 -0
  66. package/src/schema.ts +67 -0
  67. package/src/tool-args.ts +117 -0
  68. package/src/tools.ts +237 -0
  69. package/src/transport.ts +162 -0
  70. package/src/types.ts +231 -0
  71. package/src/usage.ts +106 -0
  72. package/src/watchdog.ts +119 -0
  73. package/src/zod.ts +74 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export interface RequestInit_ {
2
+ url: string;
3
+ headers?: Record<string, string>;
4
+ body: unknown;
5
+ /** Names the provider in the error envelope. */
6
+ provider: string;
7
+ signal?: AbortSignal;
8
+ /** Swapped in tests, or to route through a proxy. Defaults to global fetch. */
9
+ fetchImpl?: typeof fetch;
10
+ }
11
+ /** Join a base URL and a path without doubling or dropping the slash. */
12
+ export declare function apiUrl(baseUrl: string, path: string): string;
13
+ /**
14
+ * How long the provider says to wait, read from the RESPONSE rather than from
15
+ * a thrown error. Headers are authoritative — `Retry-After` first, then the
16
+ * vendor reset headers that name a subscription window rather than a
17
+ * per-minute throttle, because "try again in a moment" is a lie for those.
18
+ */
19
+ export declare function retryAfterFromHeaders(headers: Headers, now?: number): number | undefined;
20
+ /** POST and parse one JSON response. For the endpoints that do not stream. */
21
+ export declare function postJson<T = unknown>(opts: RequestInit_): Promise<T>;
22
+ /**
23
+ * POST an SSE request and yield each `data:` payload, trimmed.
24
+ *
25
+ * Frames are split on the blank line the spec requires, so a payload
26
+ * containing a bare newline survives; `[DONE]` is swallowed here rather than in
27
+ * every adapter. CRLF is normalized — some gateways send it, and a `\r` left on
28
+ * the end of a JSON payload is a parse error nobody enjoys debugging.
29
+ */
30
+ export declare function streamSse(opts: RequestInit_): AsyncGenerator<string>;
31
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,yEAAyE;AACzE,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,SAAa,GAAG,MAAM,GAAG,SAAS,CA6B5F;AAoCD,8EAA8E;AAC9E,wBAAsB,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAI1E;AAED;;;;;;;GAOG;AACH,wBAAuB,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,CAAC,MAAM,CAAC,CAmD3E"}
@@ -0,0 +1,157 @@
1
+ // The wire. One `fetch`, one SSE reader, one error envelope — no vendor SDK,
2
+ // no Node built-ins, so the same build runs in Bun, Node, Workers, Deno and an
3
+ // MV3 service worker.
4
+ //
5
+ // Adapters keep only their per-event mapping; everything about being an HTTP
6
+ // client lives here once.
7
+ import { classify, isTransportFailure, ProviderError } from "./errors.js";
8
+ /** Join a base URL and a path without doubling or dropping the slash. */
9
+ export function apiUrl(baseUrl, path) {
10
+ return `${baseUrl.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
11
+ }
12
+ /**
13
+ * How long the provider says to wait, read from the RESPONSE rather than from
14
+ * a thrown error. Headers are authoritative — `Retry-After` first, then the
15
+ * vendor reset headers that name a subscription window rather than a
16
+ * per-minute throttle, because "try again in a moment" is a lie for those.
17
+ */
18
+ export function retryAfterFromHeaders(headers, now = Date.now()) {
19
+ const retryAfter = headers.get("retry-after");
20
+ if (retryAfter) {
21
+ if (/^\d+$/.test(retryAfter))
22
+ return Number(retryAfter) * 1000;
23
+ const date = Date.parse(retryAfter);
24
+ if (!Number.isNaN(date))
25
+ return Math.max(0, date - now);
26
+ }
27
+ // Anthropic and several gateways publish an epoch-seconds reset instead.
28
+ for (const name of [
29
+ "anthropic-ratelimit-unified-reset",
30
+ "anthropic-ratelimit-requests-reset",
31
+ "anthropic-ratelimit-tokens-reset",
32
+ "x-ratelimit-reset-requests",
33
+ "x-ratelimit-reset-tokens",
34
+ "x-ratelimit-reset",
35
+ ]) {
36
+ const value = headers.get(name);
37
+ if (!value)
38
+ continue;
39
+ if (/^\d+$/.test(value)) {
40
+ const seconds = Number(value);
41
+ // Epoch seconds (a big number) or a relative count — tell them apart by
42
+ // magnitude rather than by trusting one vendor's convention.
43
+ const ms = seconds > 1_000_000_000 ? seconds * 1000 - now : seconds * 1000;
44
+ if (ms > 0)
45
+ return ms;
46
+ }
47
+ const date = Date.parse(value);
48
+ if (!Number.isNaN(date))
49
+ return Math.max(0, date - now);
50
+ }
51
+ return undefined;
52
+ }
53
+ /** Turn a non-2xx response into the classified error every caller branches on. */
54
+ async function errorFor(provider, res) {
55
+ const text = await res.text().catch(() => "");
56
+ const kind = classify({ status: res.status, error: text }, res.status, text);
57
+ const message = text
58
+ ? `${provider} ${res.status}: ${text.slice(0, 500)}`
59
+ : `${provider} ${res.status} ${res.statusText}`;
60
+ return new ProviderError(provider, kind, message, {
61
+ status: res.status,
62
+ retryAfterMs: retryAfterFromHeaders(res.headers),
63
+ body: text.slice(0, 2_000) || undefined,
64
+ });
65
+ }
66
+ async function send(opts) {
67
+ const doFetch = opts.fetchImpl ?? globalThis.fetch;
68
+ try {
69
+ return await doFetch(opts.url, {
70
+ method: "POST",
71
+ headers: { "content-type": "application/json", ...opts.headers },
72
+ body: typeof opts.body === "string" ? opts.body : JSON.stringify(opts.body),
73
+ signal: opts.signal,
74
+ });
75
+ }
76
+ catch (err) {
77
+ // A stopped run rejects here too, and that is not a failure — let it pass
78
+ // through untouched. Anything that is not a recognizable transport
79
+ // rejection is a bug of ours and keeps its own loud shape.
80
+ if (opts.signal?.aborted || !isTransportFailure(err))
81
+ throw err;
82
+ throw new ProviderError(opts.provider, "network", `no response from ${opts.url}`, {
83
+ cause: err,
84
+ });
85
+ }
86
+ }
87
+ /** POST and parse one JSON response. For the endpoints that do not stream. */
88
+ export async function postJson(opts) {
89
+ const res = await send(opts);
90
+ if (!res.ok)
91
+ throw await errorFor(opts.provider, res);
92
+ return (await res.json());
93
+ }
94
+ /**
95
+ * POST an SSE request and yield each `data:` payload, trimmed.
96
+ *
97
+ * Frames are split on the blank line the spec requires, so a payload
98
+ * containing a bare newline survives; `[DONE]` is swallowed here rather than in
99
+ * every adapter. CRLF is normalized — some gateways send it, and a `\r` left on
100
+ * the end of a JSON payload is a parse error nobody enjoys debugging.
101
+ */
102
+ export async function* streamSse(opts) {
103
+ const res = await send(opts);
104
+ if (!res.ok)
105
+ throw await errorFor(opts.provider, res);
106
+ // A 2xx with no body at all is an upstream anomaly, not a request we got
107
+ // wrong — worth the same retry a 5xx gets.
108
+ if (!res.body) {
109
+ throw new ProviderError(opts.provider, "overload", `${opts.provider}: empty response body`, {
110
+ status: res.status,
111
+ });
112
+ }
113
+ const reader = res.body.getReader();
114
+ const decoder = new TextDecoder();
115
+ let buffer = "";
116
+ /** Pull the `data:` payload out of one SSE frame, joining continuation
117
+ * lines the way the spec says to. Returns null for a comment or a frame
118
+ * carrying only an `event:` name. */
119
+ function payloadOf(frame) {
120
+ const parts = [];
121
+ for (const line of frame.split("\n")) {
122
+ if (!line.startsWith("data:"))
123
+ continue;
124
+ parts.push(line.slice(5).replace(/^ /, ""));
125
+ }
126
+ if (parts.length === 0)
127
+ return null;
128
+ const payload = parts.join("\n").trim();
129
+ return payload.length > 0 ? payload : null;
130
+ }
131
+ try {
132
+ for (;;) {
133
+ const { done, value } = await reader.read();
134
+ if (done)
135
+ break;
136
+ buffer += decoder.decode(value, { stream: true }).replace(/\r\n/g, "\n");
137
+ let boundary = buffer.indexOf("\n\n");
138
+ while (boundary !== -1) {
139
+ const frame = buffer.slice(0, boundary);
140
+ buffer = buffer.slice(boundary + 2);
141
+ const payload = payloadOf(frame);
142
+ if (payload !== null && payload !== "[DONE]")
143
+ yield payload;
144
+ boundary = buffer.indexOf("\n\n");
145
+ }
146
+ }
147
+ // A stream that ends without its final blank line still has an event in
148
+ // hand — dropping it loses the last delta, or the usage record.
149
+ const tail = payloadOf(buffer);
150
+ if (tail !== null && tail !== "[DONE]")
151
+ yield tail;
152
+ }
153
+ finally {
154
+ reader.releaseLock();
155
+ }
156
+ }
157
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * How hard the model thinks before answering. Absent = the provider's own
3
+ * default (never sent). Passed through verbatim on OpenAI-shape
4
+ * (`reasoning_effort`); mapped to thinking budgets on Anthropic-shape.
5
+ * Support varies per model — an unsupported level comes back as a clean 400.
6
+ *
7
+ * Ordered least → most; the type derives from the array so the runtime guard
8
+ * and the union can never drift apart.
9
+ */
10
+ export declare const EFFORTS: readonly ["none", "low", "medium", "high", "max"];
11
+ export type Effort = (typeof EFFORTS)[number];
12
+ /** The one place the effort union meets raw input (pickers, CLI flags). */
13
+ export declare function isEffort(value: string): value is Effort;
14
+ export type ImageMimeType = "image/jpeg" | "image/png" | "image/webp" | "image/gif";
15
+ export interface TextPart {
16
+ type: "text";
17
+ text: string;
18
+ }
19
+ /** An image the model looks at (vision) — bytes as base64, never a URL the
20
+ * provider would have to fetch on our behalf. */
21
+ export interface ImagePart {
22
+ type: "image";
23
+ mimeType: ImageMimeType;
24
+ data: string;
25
+ }
26
+ export type ContentPart = TextPart | ImagePart;
27
+ /**
28
+ * A tool the model asked to run. `arguments` is the RAW JSON string, not a
29
+ * parsed object: it arrives in fragments and can be truncated mid-stream, so
30
+ * assembly and validation are the consumer's job (see tools/define).
31
+ */
32
+ export interface ToolCall {
33
+ id: string;
34
+ name: string;
35
+ arguments: string;
36
+ /** Gemini's opaque reasoning token. It must ride back on the next turn
37
+ * verbatim or the model loses its own chain of thought. */
38
+ thoughtSignature?: string;
39
+ }
40
+ export type ChatMessage = {
41
+ role: "system";
42
+ content: string;
43
+ } | {
44
+ role: "user";
45
+ content: string | ContentPart[];
46
+ } | {
47
+ role: "assistant";
48
+ content: string;
49
+ /**
50
+ * The model's chain-of-thought. Thinking-mode providers require it
51
+ * replayed on a turn that made a tool call (DeepSeek 400s without it).
52
+ * OpenAI-shape serializes it as `reasoning_content`; Anthropic-shape
53
+ * drops it, since its thinking blocks carry signatures we never capture.
54
+ *
55
+ * A turn that DISABLES thinking must not carry it — mixing the two is
56
+ * unsupported. `stripReasoning` below is that rule, once.
57
+ */
58
+ reasoning?: string;
59
+ toolCalls?: ToolCall[];
60
+ } | {
61
+ role: "tool";
62
+ toolCallId: string;
63
+ name: string;
64
+ content: string;
65
+ /** Images a tool hands back (a screenshot, a rendered chart). */
66
+ images?: ImagePart[];
67
+ };
68
+ /** JSON Schema for an object — what every provider's tool contract wants. */
69
+ export interface JsonObjectSchema {
70
+ type: "object";
71
+ properties?: Record<string, unknown>;
72
+ required?: string[];
73
+ additionalProperties?: boolean;
74
+ [key: string]: unknown;
75
+ }
76
+ export interface ToolDefinition {
77
+ name: string;
78
+ description: string;
79
+ inputSchema: JsonObjectSchema;
80
+ }
81
+ export type FinishReason = "stop" | "length" | "tool_calls" | "content_filter";
82
+ /** Incremental tool-call fragment, assembled by `index` by the consumer. */
83
+ export interface ToolCallDelta {
84
+ index: number;
85
+ id?: string;
86
+ name?: string;
87
+ arguments?: string;
88
+ thoughtSignature?: string;
89
+ }
90
+ export interface TokenUsage {
91
+ inputTokens: number;
92
+ /** Cache-HIT subset of `inputTokens` — providers auto-cache repeated
93
+ * prefixes and bill the hit portion far cheaper, so it must be tracked
94
+ * separately to cost a turn correctly. 0 when the provider reports none. */
95
+ cachedInputTokens: number;
96
+ /** Tokens WRITTEN to cache. Anthropic bills these above the input rate;
97
+ * the OpenAI-shape auto-cachers bill them at it. 0 when not reported. */
98
+ cacheWriteTokens?: number;
99
+ outputTokens: number;
100
+ }
101
+ export declare const EMPTY_USAGE: TokenUsage;
102
+ /** Normalized streaming chunk — every provider's shape collapses into this. */
103
+ export interface ProviderChunk {
104
+ type: "delta" | "usage" | "finish";
105
+ content?: string;
106
+ reasoning?: string;
107
+ toolCalls?: ToolCallDelta[];
108
+ usage?: TokenUsage;
109
+ finishReason?: FinishReason;
110
+ }
111
+ /** Pin or deny tool use. `{ name }` forces one specific tool — how a run is
112
+ * made to commit an answer at its step budget's edge. */
113
+ export type ToolChoice = "auto" | "none" | "required" | {
114
+ name: string;
115
+ };
116
+ /**
117
+ * Ask for a JSON object matching `schema`. Providers that enforce schemas get
118
+ * it verbatim; the rest get JSON mode plus the schema in the prompt. Either
119
+ * way the CALLER validates — a provider's "guaranteed" JSON is not one.
120
+ */
121
+ export interface JsonOutput {
122
+ name: string;
123
+ schema: JsonObjectSchema;
124
+ }
125
+ export interface StreamOptions {
126
+ /** Override the provider's bound model for this call. */
127
+ model?: string;
128
+ effort?: Effort;
129
+ /** Output ceiling. On most providers thinking and answer SHARE it, so a
130
+ * task emitting a large artifact must raise it or the tool-call JSON is
131
+ * silently truncated mid-argument. */
132
+ maxTokens?: number;
133
+ temperature?: number;
134
+ signal?: AbortSignal;
135
+ toolChoice?: ToolChoice;
136
+ json?: JsonOutput;
137
+ }
138
+ export interface Provider {
139
+ readonly id: string;
140
+ readonly model: string;
141
+ createStream(messages: ChatMessage[], tools: ToolDefinition[], opts?: StreamOptions): AsyncIterable<ProviderChunk>;
142
+ }
143
+ export interface Completion {
144
+ text: string;
145
+ reasoning: string;
146
+ usage: TokenUsage;
147
+ finishReason: FinishReason | null;
148
+ model: string;
149
+ }
150
+ /** Drain a no-tools stream into a Completion. Usage chunks are cumulative on
151
+ * some providers and final-only on others: the LAST one wins. */
152
+ export declare function drainStream(stream: AsyncIterable<ProviderChunk>, model: string): Promise<Completion>;
153
+ /**
154
+ * Prepare a history for a thinking-DISABLED turn: strip `reasoning` from every
155
+ * assistant message.
156
+ *
157
+ * The chain-of-thought belongs only to thinking turns. A provider that
158
+ * requires it replayed while thinking is ON (DeepSeek) rejects it when
159
+ * thinking is OFF — which is exactly the shape of a forced-submit salvage
160
+ * turn, where a run reasons through its whole investigation and then drops
161
+ * thinking to serialize what it already found.
162
+ *
163
+ * Returns a shallow-cleaned copy; the caller's array is left untouched.
164
+ */
165
+ export declare function stripReasoning(messages: readonly ChatMessage[]): ChatMessage[];
166
+ /** `data:` URI for an image part — what the OpenAI dialect wants inline. */
167
+ export declare function toDataUri(part: ImagePart): string;
168
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AASA;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,mDAAoD,CAAC;AACzE,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9C,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,MAAM,CAEvD;AAED,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,CAAC;AAEpF,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED;kDACkD;AAClD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE/C;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB;gEAC4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAAA;CAAE,GACjD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;CACxB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;CACtB,CAAC;AAEN,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,gBAAgB,CAAC;CAC/B;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,gBAAgB,CAAC;AAE/E,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB;;iFAE6E;IAC7E,iBAAiB,EAAE,MAAM,CAAC;IAC1B;8EAC0E;IAC1E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,EAAE,UAIzB,CAAC;AAEF,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;IAC5B,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED;0DAC0D;AAC1D,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;2CAEuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,YAAY,CACV,QAAQ,EAAE,WAAW,EAAE,EACvB,KAAK,EAAE,cAAc,EAAE,EACvB,IAAI,CAAC,EAAE,aAAa,GACnB,aAAa,CAAC,aAAa,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,UAAU,CAAC;IAClB,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;kEACkE;AAClE,wBAAsB,WAAW,CAC/B,MAAM,EAAE,aAAa,CAAC,aAAa,CAAC,EACpC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,UAAU,CAAC,CAgBrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,EAAE,CAM9E;AAED,4EAA4E;AAC5E,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAEjD"}
package/dist/types.js ADDED
@@ -0,0 +1,75 @@
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
+ /**
10
+ * How hard the model thinks before answering. Absent = the provider's own
11
+ * default (never sent). Passed through verbatim on OpenAI-shape
12
+ * (`reasoning_effort`); mapped to thinking budgets on Anthropic-shape.
13
+ * Support varies per model — an unsupported level comes back as a clean 400.
14
+ *
15
+ * Ordered least → most; the type derives from the array so the runtime guard
16
+ * and the union can never drift apart.
17
+ */
18
+ export const EFFORTS = ["none", "low", "medium", "high", "max"];
19
+ /** The one place the effort union meets raw input (pickers, CLI flags). */
20
+ export function isEffort(value) {
21
+ return EFFORTS.some((effort) => effort === value);
22
+ }
23
+ export const EMPTY_USAGE = {
24
+ inputTokens: 0,
25
+ cachedInputTokens: 0,
26
+ outputTokens: 0,
27
+ };
28
+ /** Drain a no-tools stream into a Completion. Usage chunks are cumulative on
29
+ * some providers and final-only on others: the LAST one wins. */
30
+ export async function drainStream(stream, model) {
31
+ let text = "";
32
+ let reasoning = "";
33
+ let usage = EMPTY_USAGE;
34
+ let finishReason = null;
35
+ for await (const chunk of stream) {
36
+ if (chunk.type === "delta") {
37
+ if (chunk.content)
38
+ text += chunk.content;
39
+ if (chunk.reasoning)
40
+ reasoning += chunk.reasoning;
41
+ }
42
+ else if (chunk.type === "usage" && chunk.usage) {
43
+ usage = chunk.usage;
44
+ }
45
+ else if (chunk.type === "finish" && chunk.finishReason) {
46
+ finishReason = chunk.finishReason;
47
+ }
48
+ }
49
+ return { text, reasoning, usage, finishReason, model };
50
+ }
51
+ /**
52
+ * Prepare a history for a thinking-DISABLED turn: strip `reasoning` from every
53
+ * assistant message.
54
+ *
55
+ * The chain-of-thought belongs only to thinking turns. A provider that
56
+ * requires it replayed while thinking is ON (DeepSeek) rejects it when
57
+ * thinking is OFF — which is exactly the shape of a forced-submit salvage
58
+ * turn, where a run reasons through its whole investigation and then drops
59
+ * thinking to serialize what it already found.
60
+ *
61
+ * Returns a shallow-cleaned copy; the caller's array is left untouched.
62
+ */
63
+ export function stripReasoning(messages) {
64
+ return messages.map((message) => {
65
+ if (message.role !== "assistant" || message.reasoning === undefined)
66
+ return message;
67
+ const { reasoning: _dropped, ...rest } = message;
68
+ return rest;
69
+ });
70
+ }
71
+ /** `data:` URI for an image part — what the OpenAI dialect wants inline. */
72
+ export function toDataUri(part) {
73
+ return `data:${part.mimeType};base64,${part.data}`;
74
+ }
75
+ //# sourceMappingURL=types.js.map
@@ -0,0 +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;;;;;;;;GAQG;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;AAkGD,MAAM,CAAC,MAAM,WAAW,GAAe;IACrC,WAAW,EAAE,CAAC;IACd,iBAAiB,EAAE,CAAC;IACpB,YAAY,EAAE,CAAC;CAChB,CAAC;AA0DF;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,IAAI,KAAK,GAAe,WAAW,CAAC;IACpC,IAAI,YAAY,GAAwB,IAAI,CAAC;IAC7C,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACjC,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;QACpD,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,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AACzD,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,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC;QACpF,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;QACjD,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"}
@@ -0,0 +1,50 @@
1
+ import type { TokenUsage } from "./types.ts";
2
+ /** USD per MILLION tokens — how every vendor prints its price sheet, so a row
3
+ * can be checked against one without arithmetic. */
4
+ export interface ModelRate {
5
+ /** Cache-MISS input: fresh tokens the provider had to read. */
6
+ input: number;
7
+ output: number;
8
+ /** Cache-HIT input. Providers auto-cache repeated prefixes and bill the hit
9
+ * portion far cheaper — 0.1× on Anthropic, ~0.1× on Gemini, 0.5× on some
10
+ * OpenAI models. In an agent loop the re-sent context is overwhelmingly
11
+ * hits, so billing it at the miss rate overcounts by up to 10×. */
12
+ cacheRead: number;
13
+ /** Input WRITTEN to cache. Anthropic bills this ABOVE the input rate
14
+ * (1.25×); the OpenAI-shape auto-cachers bill it at the input rate.
15
+ * Defaults to `input` when a vendor does not price it separately. */
16
+ cacheWrite?: number;
17
+ }
18
+ /** Add two usage records. */
19
+ export declare function addUsage(a: TokenUsage, b: TokenUsage): TokenUsage;
20
+ /**
21
+ * USD for one call.
22
+ *
23
+ * Cached tokens are a SUBSET of input, not an addition to it: the miss part
24
+ * bills at the full rate and the hit part at the cache rate. `cached` is
25
+ * clamped to `input` so an over-reporting provider can neither drive the miss
26
+ * count negative nor bill for more prompt than it was sent.
27
+ */
28
+ export declare function costUsd(usage: TokenUsage, rate: ModelRate): number;
29
+ /**
30
+ * Accumulates usage and cost across the calls of one run, pricing each with
31
+ * the rate in effect for the model that served it — so a run that switches to
32
+ * a backup model, or spans a time-of-day price boundary, still bills correctly.
33
+ */
34
+ export declare class UsageTracker {
35
+ private usage;
36
+ private cost;
37
+ /** USD the cache hits saved, versus billing them all as misses.
38
+ * Observability only — never billed. */
39
+ private saved;
40
+ add(usage: TokenUsage, rate?: ModelRate): void;
41
+ get totals(): TokenUsage;
42
+ get costUsd(): number;
43
+ get cacheSavingsUsd(): number;
44
+ /** A generous runaway guard, not a quality cap: the loop's step budget is
45
+ * the real bound, and a run that trips this should finalize rather than
46
+ * fail, so set it well above any legitimate run. */
47
+ isOverBudget(maxUsd: number): boolean;
48
+ reset(): void;
49
+ }
50
+ //# sourceMappingURL=usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAQA,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,6BAA6B;AAC7B,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,UAAU,CAOjE;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAalE;AAED;;;;GAIG;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,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 ADDED
@@ -0,0 +1,71 @@
1
+ import { EMPTY_USAGE } from "./types.js";
2
+ /** Add two usage records. */
3
+ export function addUsage(a, b) {
4
+ return {
5
+ inputTokens: a.inputTokens + b.inputTokens,
6
+ cachedInputTokens: a.cachedInputTokens + b.cachedInputTokens,
7
+ cacheWriteTokens: (a.cacheWriteTokens ?? 0) + (b.cacheWriteTokens ?? 0),
8
+ outputTokens: a.outputTokens + b.outputTokens,
9
+ };
10
+ }
11
+ /**
12
+ * USD for one call.
13
+ *
14
+ * Cached tokens are a SUBSET of input, not an addition to it: the miss part
15
+ * bills at the full rate and the hit part at the cache rate. `cached` is
16
+ * clamped to `input` so an over-reporting provider can neither drive the miss
17
+ * count negative nor bill for more prompt than it was sent.
18
+ */
19
+ export function costUsd(usage, rate) {
20
+ const input = Math.max(0, usage.inputTokens);
21
+ const cached = Math.min(Math.max(0, usage.cachedInputTokens), input);
22
+ const written = Math.max(0, usage.cacheWriteTokens ?? 0);
23
+ const miss = input - cached;
24
+ const writeRate = rate.cacheWrite ?? rate.input;
25
+ return ((miss * rate.input +
26
+ cached * rate.cacheRead +
27
+ written * writeRate +
28
+ Math.max(0, usage.outputTokens) * rate.output) /
29
+ 1_000_000);
30
+ }
31
+ /**
32
+ * Accumulates usage and cost across the calls of one run, pricing each with
33
+ * the rate in effect for the model that served it — so a run that switches to
34
+ * a backup model, or spans a time-of-day price boundary, still bills correctly.
35
+ */
36
+ export class UsageTracker {
37
+ usage = { ...EMPTY_USAGE, cacheWriteTokens: 0 };
38
+ cost = 0;
39
+ /** USD the cache hits saved, versus billing them all as misses.
40
+ * Observability only — never billed. */
41
+ saved = 0;
42
+ add(usage, rate) {
43
+ this.usage = addUsage(this.usage, usage);
44
+ if (!rate)
45
+ return;
46
+ this.cost += costUsd(usage, rate);
47
+ const cached = Math.min(Math.max(0, usage.cachedInputTokens), Math.max(0, usage.inputTokens));
48
+ this.saved += (cached * (rate.input - rate.cacheRead)) / 1_000_000;
49
+ }
50
+ get totals() {
51
+ return { ...this.usage };
52
+ }
53
+ get costUsd() {
54
+ return this.cost;
55
+ }
56
+ get cacheSavingsUsd() {
57
+ return this.saved;
58
+ }
59
+ /** A generous runaway guard, not a quality cap: the loop's step budget is
60
+ * the real bound, and a run that trips this should finalize rather than
61
+ * fail, so set it well above any legitimate run. */
62
+ isOverBudget(maxUsd) {
63
+ return this.cost >= maxUsd;
64
+ }
65
+ reset() {
66
+ this.usage = { ...EMPTY_USAGE, cacheWriteTokens: 0 };
67
+ this.cost = 0;
68
+ this.saved = 0;
69
+ }
70
+ }
71
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /** No byte at all for this long and the stream is considered wedged. */
2
+ export declare const STREAM_IDLE_MS = 60000;
3
+ export interface StreamWatch {
4
+ /** Hand this to the provider in place of the caller's signal. */
5
+ readonly signal: AbortSignal;
6
+ /** A byte arrived: re-arm the deadline, and mark TTFT if it was the first. */
7
+ sawByte(): void;
8
+ /**
9
+ * Milliseconds from the call opening to its first byte of any kind — the
10
+ * wait a person actually experiences, and the number a prompt-cache pin
11
+ * exists to shrink. Null until something arrives.
12
+ */
13
+ firstChunkMs(): number | null;
14
+ /**
15
+ * Re-issue a provider failure as the idle timeout when — and only when — it
16
+ * was our deadline that aborted. A caller's Stop passes through untouched.
17
+ */
18
+ classify(err: unknown): unknown;
19
+ /** Clear the deadline timer. Safe to call more than once. */
20
+ dispose(): void;
21
+ }
22
+ export interface StreamWatchOptions {
23
+ provider?: string;
24
+ idleMs?: number;
25
+ signal?: AbortSignal;
26
+ }
27
+ export declare function streamWatch(opts?: StreamWatchOptions): StreamWatch;
28
+ /**
29
+ * Wrap a stream so every chunk re-arms `watch`, and a failure is re-classified
30
+ * through it. Disposes on any exit — completion, throw, or the consumer
31
+ * breaking out of the loop.
32
+ */
33
+ export declare function watchChunks<T>(watch: StreamWatch, chunks: AsyncIterable<T>): AsyncGenerator<T>;
34
+ //# sourceMappingURL=watchdog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watchdog.d.ts","sourceRoot":"","sources":["../src/watchdog.ts"],"names":[],"mappings":"AAgBA,wEAAwE;AACxE,eAAO,MAAM,cAAc,QAAS,CAAC;AAErC,MAAM,WAAW,WAAW;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,8EAA8E;IAC9E,OAAO,IAAI,IAAI,CAAC;IAChB;;;;OAIG;IACH,YAAY,IAAI,MAAM,GAAG,IAAI,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC;IAChC,6DAA6D;IAC7D,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wBAAgB,WAAW,CAAC,IAAI,GAAE,kBAAuB,GAAG,WAAW,CAoDtE;AAED;;;;GAIG;AACH,wBAAuB,WAAW,CAAC,CAAC,EAClC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,GACvB,cAAc,CAAC,CAAC,CAAC,CAWnB"}