@jaypie/llm 1.3.14 → 1.3.16
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/cjs/constants.d.ts +56 -1
- package/dist/cjs/index.cjs +369 -19
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +80 -4
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/operate/adapters/BedrockAdapter.d.ts +8 -0
- package/dist/cjs/operate/adapters/OpenAiAdapter.d.ts +5 -0
- package/dist/cjs/operate/adapters/OpenRouterAdapter.d.ts +11 -0
- package/dist/cjs/operate/types.d.ts +6 -1
- package/dist/cjs/providers/anthropic/types.d.ts +14 -1
- package/dist/cjs/types/LlmProvider.interface.d.ts +19 -0
- package/dist/cjs/util/cacheControl.d.ts +21 -0
- package/dist/cjs/util/index.d.ts +1 -0
- package/dist/esm/constants.d.ts +56 -1
- package/dist/esm/index.d.ts +80 -4
- package/dist/esm/index.js +369 -19
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/operate/adapters/BedrockAdapter.d.ts +8 -0
- package/dist/esm/operate/adapters/OpenAiAdapter.d.ts +5 -0
- package/dist/esm/operate/adapters/OpenRouterAdapter.d.ts +11 -0
- package/dist/esm/operate/types.d.ts +6 -1
- package/dist/esm/providers/anthropic/types.d.ts +14 -1
- package/dist/esm/types/LlmProvider.interface.d.ts +19 -0
- package/dist/esm/util/cacheControl.d.ts +21 -0
- package/dist/esm/util/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/cjs/constants.d.ts
CHANGED
|
@@ -47,6 +47,61 @@ export declare const MODEL: {
|
|
|
47
47
|
SONNET: string;
|
|
48
48
|
};
|
|
49
49
|
};
|
|
50
|
+
/** Price of one million tokens, in US dollars. */
|
|
51
|
+
export interface LlmModelCost {
|
|
52
|
+
/**
|
|
53
|
+
* Cache-read (cached input) tokens. Omitted when the provider does not price
|
|
54
|
+
* cache reads separately from uncached input.
|
|
55
|
+
*/
|
|
56
|
+
cachedInputRead?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Cache-write tokens. A scalar when the rate does not vary by TTL; keyed by
|
|
59
|
+
* the same `"5m"` / `"1h"` literals as `LlmCache` when it does, so a cost
|
|
60
|
+
* calculation reads the TTL straight off `OperateRequest.cache`. Omitted
|
|
61
|
+
* means cache writes bill at the `input` rate.
|
|
62
|
+
*/
|
|
63
|
+
cachedInputWrite?: number | {
|
|
64
|
+
"1h": number;
|
|
65
|
+
"5m": number;
|
|
66
|
+
};
|
|
67
|
+
/** Uncached input tokens. */
|
|
68
|
+
input: number;
|
|
69
|
+
/** Output tokens. */
|
|
70
|
+
output: number;
|
|
71
|
+
/**
|
|
72
|
+
* Reasoning tokens, when billed at a rate other than `output`. Omitted means
|
|
73
|
+
* reasoning bills as output, which is true of every provider listed here.
|
|
74
|
+
*/
|
|
75
|
+
reasoning?: number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Standard list price per million tokens, keyed by literal model id (verified
|
|
79
|
+
* 2026-07-21). Keys are string literals rather than `MODEL.*` references so a
|
|
80
|
+
* model retired from the catalog keeps its price here: historic ids stay
|
|
81
|
+
* priceable after they leave `MODEL.*`, which is what makes replaying old
|
|
82
|
+
* usage records possible.
|
|
83
|
+
*
|
|
84
|
+
* Caveats the numbers cannot carry:
|
|
85
|
+
* - **Standard rate only.** Introductory, batch, flex, priority, fast-mode, and
|
|
86
|
+
* data-residency rates are excluded. Sonnet 5 is listed at its standard
|
|
87
|
+
* $3/$15, not the introductory rate.
|
|
88
|
+
* - **Cache writes are Anthropic-only.** Fireworks writes bill at the input
|
|
89
|
+
* rate. OpenAI and xAI discount reads automatically and publish no write
|
|
90
|
+
* premium. Google charges nothing to write an implicit cache; explicit
|
|
91
|
+
* caching bills storage per hour, a unit this table does not carry (and one
|
|
92
|
+
* `@jaypie/llm` does not wire).
|
|
93
|
+
* - **Short-context tier.** Long-prompt surcharges are not modeled: Gemini 3.1
|
|
94
|
+
* Pro doubles above 200K, Grok doubles at 200K, GPT-5.5 is 2x in / 1.5x out
|
|
95
|
+
* above 272K.
|
|
96
|
+
* - **Text rates.** Gemini prices audio input higher than text/image/video.
|
|
97
|
+
* - **Proxies are deliberately absent.** Bedrock (`PROVIDER.BEDROCK.*`) and
|
|
98
|
+
* OpenRouter (`MODEL.OPENROUTER.*`) resell many vendors and price per backend
|
|
99
|
+
* route, so no single rate is correct for a proxy id. Price those against the
|
|
100
|
+
* backend model, or against the proxy's own published rate.
|
|
101
|
+
*
|
|
102
|
+
* Unlisted ids return `undefined` — callers must handle a miss.
|
|
103
|
+
*/
|
|
104
|
+
export declare const COST: Record<string, LlmModelCost>;
|
|
50
105
|
export declare const PROVIDER: {
|
|
51
106
|
readonly BEDROCK: {
|
|
52
107
|
readonly DEFAULT: "amazon.nova-pro-v1:0";
|
|
@@ -201,7 +256,7 @@ export declare const DEFAULT: {
|
|
|
201
256
|
*/
|
|
202
257
|
export declare const ALL: {
|
|
203
258
|
readonly BASE: readonly ["claude-sonnet-4-6", "gemini-3.1-pro-preview", "gpt-5.4", "grok-latest"];
|
|
204
|
-
readonly COMBINED: readonly ("claude-opus-4-8" | "claude-haiku-4-5" | "gemini-3.
|
|
259
|
+
readonly COMBINED: readonly ("claude-opus-4-8" | "claude-haiku-4-5" | "gemini-3.1-pro-preview" | "gpt-5.5" | "gpt-5.4-mini" | "gpt-5.4-nano" | "grok-latest" | "claude-sonnet-4-6" | "gemini-3.1-flash-lite" | "gemini-3.5-flash" | "gpt-5.4" | "grok-4-1-fast-non-reasoning" | "grok-4-1-fast-reasoning")[];
|
|
205
260
|
readonly LARGE: readonly ["claude-opus-4-8", "gemini-3.1-pro-preview", "gpt-5.5", "grok-latest"];
|
|
206
261
|
readonly SMALL: readonly ["claude-sonnet-4-6", "gemini-3.5-flash", "gpt-5.4-mini", "grok-4-1-fast-reasoning"];
|
|
207
262
|
readonly TINY: readonly ["claude-haiku-4-5", "gemini-3.1-flash-lite", "gpt-5.4-nano", "grok-4-1-fast-non-reasoning"];
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -46,8 +46,8 @@ const MODEL = {
|
|
|
46
46
|
QWEN: "accounts/fireworks/models/qwen3p7-plus",
|
|
47
47
|
},
|
|
48
48
|
// Google
|
|
49
|
-
GEMINI_FLASH: "gemini-3.
|
|
50
|
-
GEMINI_FLASH_LITE: "gemini-3.
|
|
49
|
+
GEMINI_FLASH: "gemini-3.6-flash",
|
|
50
|
+
GEMINI_FLASH_LITE: "gemini-3.5-flash-lite",
|
|
51
51
|
GEMINI_PRO: "gemini-3.1-pro-preview",
|
|
52
52
|
// OpenAI
|
|
53
53
|
SOL: "gpt-5.6-sol",
|
|
@@ -68,6 +68,177 @@ const MODEL = {
|
|
|
68
68
|
SONNET: "anthropic/claude-sonnet-5",
|
|
69
69
|
},
|
|
70
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* Standard list price per million tokens, keyed by literal model id (verified
|
|
73
|
+
* 2026-07-21). Keys are string literals rather than `MODEL.*` references so a
|
|
74
|
+
* model retired from the catalog keeps its price here: historic ids stay
|
|
75
|
+
* priceable after they leave `MODEL.*`, which is what makes replaying old
|
|
76
|
+
* usage records possible.
|
|
77
|
+
*
|
|
78
|
+
* Caveats the numbers cannot carry:
|
|
79
|
+
* - **Standard rate only.** Introductory, batch, flex, priority, fast-mode, and
|
|
80
|
+
* data-residency rates are excluded. Sonnet 5 is listed at its standard
|
|
81
|
+
* $3/$15, not the introductory rate.
|
|
82
|
+
* - **Cache writes are Anthropic-only.** Fireworks writes bill at the input
|
|
83
|
+
* rate. OpenAI and xAI discount reads automatically and publish no write
|
|
84
|
+
* premium. Google charges nothing to write an implicit cache; explicit
|
|
85
|
+
* caching bills storage per hour, a unit this table does not carry (and one
|
|
86
|
+
* `@jaypie/llm` does not wire).
|
|
87
|
+
* - **Short-context tier.** Long-prompt surcharges are not modeled: Gemini 3.1
|
|
88
|
+
* Pro doubles above 200K, Grok doubles at 200K, GPT-5.5 is 2x in / 1.5x out
|
|
89
|
+
* above 272K.
|
|
90
|
+
* - **Text rates.** Gemini prices audio input higher than text/image/video.
|
|
91
|
+
* - **Proxies are deliberately absent.** Bedrock (`PROVIDER.BEDROCK.*`) and
|
|
92
|
+
* OpenRouter (`MODEL.OPENROUTER.*`) resell many vendors and price per backend
|
|
93
|
+
* route, so no single rate is correct for a proxy id. Price those against the
|
|
94
|
+
* backend model, or against the proxy's own published rate.
|
|
95
|
+
*
|
|
96
|
+
* Unlisted ids return `undefined` — callers must handle a miss.
|
|
97
|
+
*/
|
|
98
|
+
const COST = {
|
|
99
|
+
// Anthropic — https://platform.claude.com/docs/en/about-claude/pricing
|
|
100
|
+
"claude-3-5-haiku-20241022": {
|
|
101
|
+
cachedInputRead: 0.08,
|
|
102
|
+
cachedInputWrite: { "1h": 1.6, "5m": 1.0 },
|
|
103
|
+
input: 0.8,
|
|
104
|
+
output: 4.0,
|
|
105
|
+
},
|
|
106
|
+
"claude-fable-5": {
|
|
107
|
+
cachedInputRead: 1.0,
|
|
108
|
+
cachedInputWrite: { "1h": 20.0, "5m": 12.5 },
|
|
109
|
+
input: 10.0,
|
|
110
|
+
output: 50.0,
|
|
111
|
+
},
|
|
112
|
+
"claude-haiku-4-5": {
|
|
113
|
+
cachedInputRead: 0.1,
|
|
114
|
+
cachedInputWrite: { "1h": 2.0, "5m": 1.25 },
|
|
115
|
+
input: 1.0,
|
|
116
|
+
output: 5.0,
|
|
117
|
+
},
|
|
118
|
+
"claude-mythos-5": {
|
|
119
|
+
cachedInputRead: 1.0,
|
|
120
|
+
cachedInputWrite: { "1h": 20.0, "5m": 12.5 },
|
|
121
|
+
input: 10.0,
|
|
122
|
+
output: 50.0,
|
|
123
|
+
},
|
|
124
|
+
"claude-opus-4-1": {
|
|
125
|
+
cachedInputRead: 1.5,
|
|
126
|
+
cachedInputWrite: { "1h": 30.0, "5m": 18.75 },
|
|
127
|
+
input: 15.0,
|
|
128
|
+
output: 75.0,
|
|
129
|
+
},
|
|
130
|
+
"claude-opus-4-5": {
|
|
131
|
+
cachedInputRead: 0.5,
|
|
132
|
+
cachedInputWrite: { "1h": 10.0, "5m": 6.25 },
|
|
133
|
+
input: 5.0,
|
|
134
|
+
output: 25.0,
|
|
135
|
+
},
|
|
136
|
+
"claude-opus-4-6": {
|
|
137
|
+
cachedInputRead: 0.5,
|
|
138
|
+
cachedInputWrite: { "1h": 10.0, "5m": 6.25 },
|
|
139
|
+
input: 5.0,
|
|
140
|
+
output: 25.0,
|
|
141
|
+
},
|
|
142
|
+
"claude-opus-4-7": {
|
|
143
|
+
cachedInputRead: 0.5,
|
|
144
|
+
cachedInputWrite: { "1h": 10.0, "5m": 6.25 },
|
|
145
|
+
input: 5.0,
|
|
146
|
+
output: 25.0,
|
|
147
|
+
},
|
|
148
|
+
"claude-opus-4-8": {
|
|
149
|
+
cachedInputRead: 0.5,
|
|
150
|
+
cachedInputWrite: { "1h": 10.0, "5m": 6.25 },
|
|
151
|
+
input: 5.0,
|
|
152
|
+
output: 25.0,
|
|
153
|
+
},
|
|
154
|
+
"claude-sonnet-4-20250514": {
|
|
155
|
+
cachedInputRead: 0.3,
|
|
156
|
+
cachedInputWrite: { "1h": 6.0, "5m": 3.75 },
|
|
157
|
+
input: 3.0,
|
|
158
|
+
output: 15.0,
|
|
159
|
+
},
|
|
160
|
+
"claude-sonnet-4-5": {
|
|
161
|
+
cachedInputRead: 0.3,
|
|
162
|
+
cachedInputWrite: { "1h": 6.0, "5m": 3.75 },
|
|
163
|
+
input: 3.0,
|
|
164
|
+
output: 15.0,
|
|
165
|
+
},
|
|
166
|
+
"claude-sonnet-4-6": {
|
|
167
|
+
cachedInputRead: 0.3,
|
|
168
|
+
cachedInputWrite: { "1h": 6.0, "5m": 3.75 },
|
|
169
|
+
input: 3.0,
|
|
170
|
+
output: 15.0,
|
|
171
|
+
},
|
|
172
|
+
"claude-sonnet-5": {
|
|
173
|
+
cachedInputRead: 0.3,
|
|
174
|
+
cachedInputWrite: { "1h": 6.0, "5m": 3.75 },
|
|
175
|
+
input: 3.0,
|
|
176
|
+
output: 15.0,
|
|
177
|
+
},
|
|
178
|
+
// Fireworks — https://docs.fireworks.ai/serverless/pricing
|
|
179
|
+
"accounts/fireworks/models/deepseek-v4-pro": {
|
|
180
|
+
cachedInputRead: 0.145,
|
|
181
|
+
input: 1.74,
|
|
182
|
+
output: 3.48,
|
|
183
|
+
},
|
|
184
|
+
"accounts/fireworks/models/glm-5p2": {
|
|
185
|
+
cachedInputRead: 0.14,
|
|
186
|
+
input: 1.4,
|
|
187
|
+
output: 4.4,
|
|
188
|
+
},
|
|
189
|
+
"accounts/fireworks/models/kimi-k2p7-code": {
|
|
190
|
+
cachedInputRead: 0.19,
|
|
191
|
+
input: 0.95,
|
|
192
|
+
output: 4.0,
|
|
193
|
+
},
|
|
194
|
+
"accounts/fireworks/models/minimax-m2p7": {
|
|
195
|
+
cachedInputRead: 0.06,
|
|
196
|
+
input: 0.3,
|
|
197
|
+
output: 1.2,
|
|
198
|
+
},
|
|
199
|
+
"accounts/fireworks/models/qwen3p7-plus": {
|
|
200
|
+
cachedInputRead: 0.08,
|
|
201
|
+
input: 0.4,
|
|
202
|
+
output: 1.6,
|
|
203
|
+
},
|
|
204
|
+
// Google — https://ai.google.dev/gemini-api/docs/pricing
|
|
205
|
+
"gemini-2.5-flash": { cachedInputRead: 0.03, input: 0.3, output: 2.5 },
|
|
206
|
+
"gemini-3.1-flash-lite": {
|
|
207
|
+
cachedInputRead: 0.025,
|
|
208
|
+
input: 0.25,
|
|
209
|
+
output: 1.5,
|
|
210
|
+
},
|
|
211
|
+
"gemini-3.1-flash-lite-preview": {
|
|
212
|
+
cachedInputRead: 0.025,
|
|
213
|
+
input: 0.25,
|
|
214
|
+
output: 1.5,
|
|
215
|
+
},
|
|
216
|
+
"gemini-3.1-pro-preview": { cachedInputRead: 0.2, input: 2.0, output: 12.0 },
|
|
217
|
+
"gemini-3.5-flash": { cachedInputRead: 0.15, input: 1.5, output: 9.0 },
|
|
218
|
+
// Flash-Lite 3.5 has no separate cache-read rate on the standard tier
|
|
219
|
+
"gemini-3.5-flash-lite": { input: 0.3, output: 2.5 },
|
|
220
|
+
"gemini-3.6-flash": { cachedInputRead: 0.15, input: 1.5, output: 7.5 },
|
|
221
|
+
// OpenAI — https://developers.openai.com/api/docs/pricing
|
|
222
|
+
"gpt-5.4": { cachedInputRead: 0.25, input: 2.5, output: 15.0 },
|
|
223
|
+
"gpt-5.4-mini": { cachedInputRead: 0.075, input: 0.75, output: 4.5 },
|
|
224
|
+
"gpt-5.4-nano": { cachedInputRead: 0.02, input: 0.2, output: 1.25 },
|
|
225
|
+
"gpt-5.5": { cachedInputRead: 0.5, input: 5.0, output: 30.0 },
|
|
226
|
+
"gpt-5.6-luna": { cachedInputRead: 0.1, input: 1.0, output: 6.0 },
|
|
227
|
+
"gpt-5.6-sol": { cachedInputRead: 0.5, input: 5.0, output: 30.0 },
|
|
228
|
+
"gpt-5.6-terra": { cachedInputRead: 0.25, input: 2.5, output: 15.0 },
|
|
229
|
+
// xAI — https://docs.x.ai/docs/models ("grok-latest" aliases grok-4.3-latest)
|
|
230
|
+
"grok-4-1-fast-non-reasoning": {
|
|
231
|
+
cachedInputRead: 0.05,
|
|
232
|
+
input: 0.2,
|
|
233
|
+
output: 0.5,
|
|
234
|
+
},
|
|
235
|
+
"grok-4-1-fast-reasoning": {
|
|
236
|
+
cachedInputRead: 0.05,
|
|
237
|
+
input: 0.2,
|
|
238
|
+
output: 0.5,
|
|
239
|
+
},
|
|
240
|
+
"grok-latest": { cachedInputRead: 0.2, input: 1.25, output: 2.5 },
|
|
241
|
+
};
|
|
71
242
|
const GOOGLE_PROVIDER = {
|
|
72
243
|
// https://ai.google.dev/gemini-api/docs/models
|
|
73
244
|
DEFAULT: MODEL.GEMINI_FLASH,
|
|
@@ -273,6 +444,7 @@ const ALL = {
|
|
|
273
444
|
var constants = /*#__PURE__*/Object.freeze({
|
|
274
445
|
__proto__: null,
|
|
275
446
|
ALL: ALL,
|
|
447
|
+
COST: COST,
|
|
276
448
|
DEFAULT: DEFAULT,
|
|
277
449
|
EFFORT: EFFORT,
|
|
278
450
|
MODEL: MODEL,
|
|
@@ -501,6 +673,12 @@ function sumUsageByProviderModel(usage) {
|
|
|
501
673
|
totals[key].output += item.output;
|
|
502
674
|
totals[key].reasoning += item.reasoning;
|
|
503
675
|
totals[key].total += item.total;
|
|
676
|
+
if (item.cacheRead !== undefined) {
|
|
677
|
+
totals[key].cacheRead = (totals[key].cacheRead ?? 0) + item.cacheRead;
|
|
678
|
+
}
|
|
679
|
+
if (item.cacheWrite !== undefined) {
|
|
680
|
+
totals[key].cacheWrite = (totals[key].cacheWrite ?? 0) + item.cacheWrite;
|
|
681
|
+
}
|
|
504
682
|
}
|
|
505
683
|
return totals;
|
|
506
684
|
}
|
|
@@ -526,6 +704,7 @@ function buildExchangeEnvelope({ duration, initialHistoryLength, input, options,
|
|
|
526
704
|
return {
|
|
527
705
|
ids: extractResponseIds(response.responses),
|
|
528
706
|
request: {
|
|
707
|
+
cache: options.cache,
|
|
529
708
|
data: options.data,
|
|
530
709
|
effort: options.effort,
|
|
531
710
|
explain: options.explain,
|
|
@@ -563,6 +742,38 @@ function buildExchangeEnvelope({ duration, initialHistoryLength, input, options,
|
|
|
563
742
|
};
|
|
564
743
|
}
|
|
565
744
|
|
|
745
|
+
const CACHE_TTL_DEFAULT = "5m";
|
|
746
|
+
/**
|
|
747
|
+
* Normalize the caller-facing `cache` option into a concrete decision.
|
|
748
|
+
* - `undefined` / `true` → enabled at the default TTL
|
|
749
|
+
* - `false` / `0` → disabled
|
|
750
|
+
* - `"5m"` / `"1h"` → enabled at that TTL
|
|
751
|
+
*/
|
|
752
|
+
function resolveCache(cache) {
|
|
753
|
+
if (cache === false || cache === 0) {
|
|
754
|
+
return { enabled: false, ttl: CACHE_TTL_DEFAULT };
|
|
755
|
+
}
|
|
756
|
+
if (cache === "5m" || cache === "1h") {
|
|
757
|
+
return { enabled: true, ttl: cache };
|
|
758
|
+
}
|
|
759
|
+
// undefined or true
|
|
760
|
+
return { enabled: true, ttl: CACHE_TTL_DEFAULT };
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Deterministic short key for providers with automatic, prefix-based caching
|
|
764
|
+
* (e.g. OpenAI `prompt_cache_key`). Derived from the stable prefix so the same
|
|
765
|
+
* system prompt + tools + model always routes to the same cache. Dependency-
|
|
766
|
+
* free FNV-1a; not cryptographic.
|
|
767
|
+
*/
|
|
768
|
+
function promptCacheKey(seed) {
|
|
769
|
+
let hash = 0x811c9dc5;
|
|
770
|
+
for (let i = 0; i < seed.length; i += 1) {
|
|
771
|
+
hash ^= seed.charCodeAt(i);
|
|
772
|
+
hash = Math.imul(hash, 0x01000193);
|
|
773
|
+
}
|
|
774
|
+
return `jaypie-${(hash >>> 0).toString(16)}`;
|
|
775
|
+
}
|
|
776
|
+
|
|
566
777
|
/**
|
|
567
778
|
* Type guard to check if an item is a dedicated reasoning item (OpenAI)
|
|
568
779
|
*/
|
|
@@ -1414,6 +1625,14 @@ function tallyOperate({ toolCallNames = [], turns, usage = [], }) {
|
|
|
1414
1625
|
usageByModel[key].output += item.output;
|
|
1415
1626
|
usageByModel[key].reasoning += item.reasoning;
|
|
1416
1627
|
usageByModel[key].total += item.total;
|
|
1628
|
+
if (item.cacheRead !== undefined) {
|
|
1629
|
+
usageByModel[key].cacheRead =
|
|
1630
|
+
(usageByModel[key].cacheRead ?? 0) + item.cacheRead;
|
|
1631
|
+
}
|
|
1632
|
+
if (item.cacheWrite !== undefined) {
|
|
1633
|
+
usageByModel[key].cacheWrite =
|
|
1634
|
+
(usageByModel[key].cacheWrite ?? 0) + item.cacheWrite;
|
|
1635
|
+
}
|
|
1417
1636
|
}
|
|
1418
1637
|
llm.usage = usageByModel;
|
|
1419
1638
|
}
|
|
@@ -1520,27 +1739,26 @@ const MODULE$1 = {
|
|
|
1520
1739
|
//
|
|
1521
1740
|
// Helpers
|
|
1522
1741
|
//
|
|
1523
|
-
//
|
|
1524
|
-
//
|
|
1525
|
-
//
|
|
1526
|
-
//
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
: module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
1742
|
+
// Native dynamic import that neither rollup nor tsc rewrites to require(), so
|
|
1743
|
+
// a CJS-bundled build still loads @jaypie/dynamodb's ESM entry and shares the
|
|
1744
|
+
// host's initialized module instance. A require()-based resolution would load
|
|
1745
|
+
// the CJS build, whose module-level client state is separate from the ESM
|
|
1746
|
+
// instance an ESM host initializes (dual-package hazard, issue #429).
|
|
1747
|
+
const dynamicImport = new Function("s", "return import(s)");
|
|
1530
1748
|
let resolved$1 = false;
|
|
1531
1749
|
let cachedSdk$2 = null;
|
|
1532
1750
|
/**
|
|
1533
1751
|
* Lazily resolve @jaypie/dynamodb's storeExchange. Returns null (and never
|
|
1534
1752
|
* throws) when the peer is absent. Cached after the first attempt.
|
|
1535
1753
|
*/
|
|
1536
|
-
function resolveExchangeStore() {
|
|
1754
|
+
async function resolveExchangeStore() {
|
|
1537
1755
|
if (resolved$1) {
|
|
1538
1756
|
return cachedSdk$2;
|
|
1539
1757
|
}
|
|
1540
1758
|
resolved$1 = true;
|
|
1541
1759
|
try {
|
|
1542
|
-
const dynamodb =
|
|
1543
|
-
const sdk = dynamodb?.default ?? dynamodb;
|
|
1760
|
+
const dynamodb = await dynamicImport(MODULE$1.JAYPIE_DYNAMODB);
|
|
1761
|
+
const sdk = (dynamodb?.default ?? dynamodb);
|
|
1544
1762
|
if (sdk && typeof sdk.storeExchange === "function") {
|
|
1545
1763
|
cachedSdk$2 = sdk;
|
|
1546
1764
|
}
|
|
@@ -1563,7 +1781,7 @@ async function persistExchange(envelope) {
|
|
|
1563
1781
|
if (!isExchangeStoreEnabled()) {
|
|
1564
1782
|
return;
|
|
1565
1783
|
}
|
|
1566
|
-
const sdk = resolveExchangeStore();
|
|
1784
|
+
const sdk = (await resolveExchangeStore());
|
|
1567
1785
|
if (!sdk) {
|
|
1568
1786
|
return;
|
|
1569
1787
|
}
|
|
@@ -2351,8 +2569,19 @@ class AnthropicAdapter extends BaseProviderAdapter {
|
|
|
2351
2569
|
PROVIDER.ANTHROPIC.MAX_TOKENS.DEFAULT,
|
|
2352
2570
|
stream: false,
|
|
2353
2571
|
};
|
|
2572
|
+
const cache = resolveCache(request.cache);
|
|
2573
|
+
const cacheControl = cache.enabled
|
|
2574
|
+
? {
|
|
2575
|
+
type: "ephemeral",
|
|
2576
|
+
...(cache.ttl === "1h" ? { ttl: "1h" } : {}),
|
|
2577
|
+
}
|
|
2578
|
+
: undefined;
|
|
2354
2579
|
if (request.system) {
|
|
2355
|
-
|
|
2580
|
+
// A cache breakpoint on the system block caches tools+system together
|
|
2581
|
+
// (render order is tools -> system -> messages).
|
|
2582
|
+
anthropicRequest.system = cacheControl
|
|
2583
|
+
? [{ type: "text", text: request.system, cache_control: cacheControl }]
|
|
2584
|
+
: request.system;
|
|
2356
2585
|
}
|
|
2357
2586
|
const useFallbackStructuredOutput = Boolean(request.format) &&
|
|
2358
2587
|
!this.supportsStructuredOutput(anthropicRequest.model);
|
|
@@ -2369,7 +2598,7 @@ class AnthropicAdapter extends BaseProviderAdapter {
|
|
|
2369
2598
|
});
|
|
2370
2599
|
}
|
|
2371
2600
|
if (allTools.length > 0) {
|
|
2372
|
-
anthropicRequest.tools = allTools.map((tool) => ({
|
|
2601
|
+
anthropicRequest.tools = allTools.map((tool, index) => ({
|
|
2373
2602
|
name: tool.name,
|
|
2374
2603
|
description: tool.description,
|
|
2375
2604
|
input_schema: {
|
|
@@ -2377,6 +2606,11 @@ class AnthropicAdapter extends BaseProviderAdapter {
|
|
|
2377
2606
|
type: "object",
|
|
2378
2607
|
},
|
|
2379
2608
|
type: "custom",
|
|
2609
|
+
// Breakpoint on the last tool caches the tool list (which renders
|
|
2610
|
+
// before system) when there is no system prompt to anchor it.
|
|
2611
|
+
...(cacheControl && index === allTools.length - 1
|
|
2612
|
+
? { cache_control: cacheControl }
|
|
2613
|
+
: {}),
|
|
2380
2614
|
}));
|
|
2381
2615
|
anthropicRequest.tool_choice = useFallbackStructuredOutput
|
|
2382
2616
|
? { type: "any" }
|
|
@@ -2679,6 +2913,12 @@ class AnthropicAdapter extends BaseProviderAdapter {
|
|
|
2679
2913
|
output: usage.output_tokens,
|
|
2680
2914
|
reasoning: usage.thinking_tokens || 0,
|
|
2681
2915
|
total: usage.input_tokens + usage.output_tokens,
|
|
2916
|
+
...(usage.cache_read_input_tokens !== undefined
|
|
2917
|
+
? { cacheRead: usage.cache_read_input_tokens }
|
|
2918
|
+
: {}),
|
|
2919
|
+
...(usage.cache_creation_input_tokens !== undefined
|
|
2920
|
+
? { cacheWrite: usage.cache_creation_input_tokens }
|
|
2921
|
+
: {}),
|
|
2682
2922
|
provider: this.name,
|
|
2683
2923
|
model,
|
|
2684
2924
|
};
|
|
@@ -2931,6 +3171,17 @@ function isTemperatureDeprecationError$3(error) {
|
|
|
2931
3171
|
const msg = error?.message ?? "";
|
|
2932
3172
|
return /temperature.*deprecated|deprecated.*temperature/i.test(msg);
|
|
2933
3173
|
}
|
|
3174
|
+
/** Exported for tests; not part of the package's public surface. */
|
|
3175
|
+
function isCachePointUnsupportedError(error) {
|
|
3176
|
+
const name = error?.constructor?.name ?? "";
|
|
3177
|
+
const msg = error?.message ?? "";
|
|
3178
|
+
// A model that cannot cache rejects the cachePoint block with a
|
|
3179
|
+
// ValidationException naming caching / cachePoint. Bedrock words this as
|
|
3180
|
+
// "You invoked an unsupported model or your request did not allow prompt
|
|
3181
|
+
// caching" — "unsupported" is one word, so it must be matched separately
|
|
3182
|
+
// from "not support".
|
|
3183
|
+
return (/ValidationException|invalid|not support|unsupported/i.test(name + " " + msg) && /cachePoint|cache_point|prompt caching|caching/i.test(msg));
|
|
3184
|
+
}
|
|
2934
3185
|
function extractJson(text) {
|
|
2935
3186
|
// Try direct parse first
|
|
2936
3187
|
try {
|
|
@@ -2966,6 +3217,13 @@ class BedrockAdapter extends BaseProviderAdapter {
|
|
|
2966
3217
|
this.defaultModel = PROVIDER.BEDROCK.DEFAULT;
|
|
2967
3218
|
this._modelsFallbackToStructuredOutputTool = new Set();
|
|
2968
3219
|
this._modelsWithoutTemperature = new Set();
|
|
3220
|
+
this._modelsWithoutCachePoint = new Set();
|
|
3221
|
+
}
|
|
3222
|
+
rememberModelRejectsCachePoint(model) {
|
|
3223
|
+
this._modelsWithoutCachePoint.add(model);
|
|
3224
|
+
}
|
|
3225
|
+
supportsCachePoint(model) {
|
|
3226
|
+
return !this._modelsWithoutCachePoint.has(model);
|
|
2969
3227
|
}
|
|
2970
3228
|
rememberModelRejectsOutputConfig(model) {
|
|
2971
3229
|
this._modelsFallbackToStructuredOutputTool.add(model);
|
|
@@ -3102,11 +3360,51 @@ class BedrockAdapter extends BaseProviderAdapter {
|
|
|
3102
3360
|
};
|
|
3103
3361
|
}
|
|
3104
3362
|
}
|
|
3363
|
+
// Prompt caching via Converse cachePoint blocks (5-min default TTL; the
|
|
3364
|
+
// `ttl` option does not apply). Gated per model — cachePoint 400s on
|
|
3365
|
+
// unsupported models, which executeRequest catches and denylists.
|
|
3366
|
+
if (resolveCache(request.cache).enabled && this.supportsCachePoint(model)) {
|
|
3367
|
+
const cachePoint = { cachePoint: { type: "default" } };
|
|
3368
|
+
if (bedrockRequest.system && bedrockRequest.system.length > 0) {
|
|
3369
|
+
bedrockRequest.system = [
|
|
3370
|
+
...bedrockRequest.system,
|
|
3371
|
+
cachePoint,
|
|
3372
|
+
];
|
|
3373
|
+
}
|
|
3374
|
+
if (bedrockRequest.toolConfig?.tools?.length) {
|
|
3375
|
+
bedrockRequest.toolConfig = {
|
|
3376
|
+
...bedrockRequest.toolConfig,
|
|
3377
|
+
tools: [
|
|
3378
|
+
...bedrockRequest.toolConfig.tools,
|
|
3379
|
+
cachePoint,
|
|
3380
|
+
],
|
|
3381
|
+
};
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3105
3384
|
if (request.providerOptions) {
|
|
3106
3385
|
Object.assign(bedrockRequest, request.providerOptions);
|
|
3107
3386
|
}
|
|
3108
3387
|
return bedrockRequest;
|
|
3109
3388
|
}
|
|
3389
|
+
/** Remove any cachePoint blocks so the request can be retried unsupported. */
|
|
3390
|
+
stripCachePoints(request) {
|
|
3391
|
+
const stripped = { ...request };
|
|
3392
|
+
if (stripped.system) {
|
|
3393
|
+
stripped.system = stripped.system.filter((block) => !("cachePoint" in block));
|
|
3394
|
+
}
|
|
3395
|
+
if (stripped.toolConfig?.tools) {
|
|
3396
|
+
stripped.toolConfig = {
|
|
3397
|
+
...stripped.toolConfig,
|
|
3398
|
+
tools: stripped.toolConfig.tools.filter((tool) => !("cachePoint" in tool)),
|
|
3399
|
+
};
|
|
3400
|
+
}
|
|
3401
|
+
return stripped;
|
|
3402
|
+
}
|
|
3403
|
+
requestHasCachePoints(request) {
|
|
3404
|
+
const inSystem = (request.system ?? []).some((block) => "cachePoint" in block);
|
|
3405
|
+
const inTools = (request.toolConfig?.tools ?? []).some((tool) => "cachePoint" in tool);
|
|
3406
|
+
return inSystem || inTools;
|
|
3407
|
+
}
|
|
3110
3408
|
formatTools(toolkit) {
|
|
3111
3409
|
return toolkit.tools.map((tool) => ({
|
|
3112
3410
|
name: tool.name,
|
|
@@ -3161,6 +3459,15 @@ class BedrockAdapter extends BaseProviderAdapter {
|
|
|
3161
3459
|
const fallbackRequest = this.toFallbackStructuredOutputRequest(bedrockRequest);
|
|
3162
3460
|
return (await bedrockClient.send(new ConverseCommand(fallbackRequest), signal ? { abortSignal: signal } : undefined));
|
|
3163
3461
|
}
|
|
3462
|
+
if (this.requestHasCachePoints(bedrockRequest) &&
|
|
3463
|
+
isCachePointUnsupportedError(error)) {
|
|
3464
|
+
this.rememberModelRejectsCachePoint(bedrockRequest.modelId || this.defaultModel);
|
|
3465
|
+
const retryRequest = this.stripCachePoints(bedrockRequest);
|
|
3466
|
+
const response = (await bedrockClient.send(new ConverseCommand(retryRequest), signal ? { abortSignal: signal } : undefined));
|
|
3467
|
+
if (wantsStructuredOutput)
|
|
3468
|
+
response.__jaypieStructuredOutput = true;
|
|
3469
|
+
return response;
|
|
3470
|
+
}
|
|
3164
3471
|
throw error;
|
|
3165
3472
|
}
|
|
3166
3473
|
}
|
|
@@ -3304,6 +3611,12 @@ class BedrockAdapter extends BaseProviderAdapter {
|
|
|
3304
3611
|
reasoning: 0,
|
|
3305
3612
|
total: usage?.totalTokens ??
|
|
3306
3613
|
(usage?.inputTokens ?? 0) + (usage?.outputTokens ?? 0),
|
|
3614
|
+
...(usage?.cacheReadInputTokens !== undefined
|
|
3615
|
+
? { cacheRead: usage.cacheReadInputTokens }
|
|
3616
|
+
: {}),
|
|
3617
|
+
...(usage?.cacheWriteInputTokens !== undefined
|
|
3618
|
+
? { cacheWrite: usage.cacheWriteInputTokens }
|
|
3619
|
+
: {}),
|
|
3307
3620
|
provider: this.name,
|
|
3308
3621
|
model,
|
|
3309
3622
|
};
|
|
@@ -5475,6 +5788,13 @@ class OpenAiAdapter extends BaseProviderAdapter {
|
|
|
5475
5788
|
supportsReasoningEffort(model) {
|
|
5476
5789
|
return isReasoningModel(model);
|
|
5477
5790
|
}
|
|
5791
|
+
/**
|
|
5792
|
+
* Whether to emit `prompt_cache_key` (OpenAI Responses API). Overridable by
|
|
5793
|
+
* OpenAI-compatible subclasses whose backend rejects the field.
|
|
5794
|
+
*/
|
|
5795
|
+
supportsPromptCacheKey() {
|
|
5796
|
+
return true;
|
|
5797
|
+
}
|
|
5478
5798
|
/** Translate a normalized effort to this provider's `reasoning.effort` value. */
|
|
5479
5799
|
mapReasoningEffort(effort, model) {
|
|
5480
5800
|
return toOpenAiEffort(effort, { model });
|
|
@@ -5514,6 +5834,18 @@ class OpenAiAdapter extends BaseProviderAdapter {
|
|
|
5514
5834
|
summary: "auto",
|
|
5515
5835
|
};
|
|
5516
5836
|
}
|
|
5837
|
+
// OpenAI prompt caching is automatic (prefix-based). Setting a stable
|
|
5838
|
+
// prompt_cache_key routes repeat traffic to the same cache across
|
|
5839
|
+
// instances. Keyed on the stable prefix only (system + instructions +
|
|
5840
|
+
// tools + model), never the volatile user turn.
|
|
5841
|
+
if (this.supportsPromptCacheKey() && resolveCache(request.cache).enabled) {
|
|
5842
|
+
openaiRequest.prompt_cache_key = promptCacheKey(JSON.stringify([
|
|
5843
|
+
model,
|
|
5844
|
+
request.system ?? "",
|
|
5845
|
+
request.instructions ?? "",
|
|
5846
|
+
request.tools ?? [],
|
|
5847
|
+
]));
|
|
5848
|
+
}
|
|
5517
5849
|
if (request.providerOptions) {
|
|
5518
5850
|
Object.assign(openaiRequest, request.providerOptions);
|
|
5519
5851
|
}
|
|
@@ -5772,11 +6104,13 @@ class OpenAiAdapter extends BaseProviderAdapter {
|
|
|
5772
6104
|
model,
|
|
5773
6105
|
};
|
|
5774
6106
|
}
|
|
6107
|
+
const cachedTokens = openaiResponse.usage.input_tokens_details?.cached_tokens;
|
|
5775
6108
|
return {
|
|
5776
6109
|
input: openaiResponse.usage.input_tokens || 0,
|
|
5777
6110
|
output: openaiResponse.usage.output_tokens || 0,
|
|
5778
6111
|
reasoning: openaiResponse.usage.output_tokens_details?.reasoning_tokens || 0,
|
|
5779
6112
|
total: openaiResponse.usage.total_tokens || 0,
|
|
6113
|
+
...(cachedTokens !== undefined ? { cacheRead: cachedTokens } : {}),
|
|
5780
6114
|
provider: this.name,
|
|
5781
6115
|
model,
|
|
5782
6116
|
};
|
|
@@ -6168,7 +6502,13 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
6168
6502
|
//
|
|
6169
6503
|
buildRequest(request) {
|
|
6170
6504
|
// Convert messages to OpenRouter format (OpenAI-compatible)
|
|
6171
|
-
const
|
|
6505
|
+
const cache = resolveCache(request.cache);
|
|
6506
|
+
const messages = this.convertMessagesToOpenRouter(request.messages, request.system, cache.enabled
|
|
6507
|
+
? {
|
|
6508
|
+
type: "ephemeral",
|
|
6509
|
+
...(cache.ttl === "1h" ? { ttl: "1h" } : {}),
|
|
6510
|
+
}
|
|
6511
|
+
: undefined);
|
|
6172
6512
|
// Append instructions to last message if provided
|
|
6173
6513
|
if (request.instructions && messages.length > 0) {
|
|
6174
6514
|
const lastMsg = messages[messages.length - 1];
|
|
@@ -6532,11 +6872,15 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
6532
6872
|
}
|
|
6533
6873
|
// SDK returns camelCase, but support snake_case as fallback
|
|
6534
6874
|
const usage = openRouterResponse.usage;
|
|
6875
|
+
const cachedTokens = usage.promptTokensDetails?.cachedTokens ??
|
|
6876
|
+
usage.promptTokensDetails?.cached_tokens ??
|
|
6877
|
+
usage.prompt_tokens_details?.cached_tokens;
|
|
6535
6878
|
return {
|
|
6536
6879
|
input: usage.promptTokens || usage.prompt_tokens || 0,
|
|
6537
6880
|
output: usage.completionTokens || usage.completion_tokens || 0,
|
|
6538
6881
|
reasoning: usage.completionTokensDetails?.reasoningTokens || 0,
|
|
6539
6882
|
total: usage.totalTokens || usage.total_tokens || 0,
|
|
6883
|
+
...(cachedTokens !== undefined ? { cacheRead: cachedTokens } : {}),
|
|
6540
6884
|
provider: this.name,
|
|
6541
6885
|
model,
|
|
6542
6886
|
};
|
|
@@ -6737,13 +7081,17 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
6737
7081
|
const choice = response.choices[0];
|
|
6738
7082
|
return choice?.message?.content ?? undefined;
|
|
6739
7083
|
}
|
|
6740
|
-
convertMessagesToOpenRouter(messages, system) {
|
|
7084
|
+
convertMessagesToOpenRouter(messages, system, cacheControl) {
|
|
6741
7085
|
const openRouterMessages = [];
|
|
6742
|
-
// Add system message if provided
|
|
7086
|
+
// Add system message if provided. A cache_control breakpoint on the system
|
|
7087
|
+
// content is forwarded by OpenRouter to Anthropic/Gemini backends (and
|
|
7088
|
+
// ignored by others), caching the stable system prefix.
|
|
6743
7089
|
if (system) {
|
|
6744
7090
|
openRouterMessages.push({
|
|
6745
7091
|
role: "system",
|
|
6746
|
-
content:
|
|
7092
|
+
content: cacheControl
|
|
7093
|
+
? [{ type: "text", text: system, cache_control: cacheControl }]
|
|
7094
|
+
: system,
|
|
6747
7095
|
});
|
|
6748
7096
|
}
|
|
6749
7097
|
for (const msg of messages) {
|
|
@@ -8455,6 +8803,7 @@ class OperateLoop {
|
|
|
8455
8803
|
}
|
|
8456
8804
|
buildInitialRequest(state, options) {
|
|
8457
8805
|
return {
|
|
8806
|
+
cache: options.cache,
|
|
8458
8807
|
effort: options.effort,
|
|
8459
8808
|
format: state.formattedFormat,
|
|
8460
8809
|
instructions: options.instructions,
|
|
@@ -9088,6 +9437,7 @@ class StreamLoop {
|
|
|
9088
9437
|
}
|
|
9089
9438
|
buildInitialRequest(state, options) {
|
|
9090
9439
|
return {
|
|
9440
|
+
cache: options.cache,
|
|
9091
9441
|
effort: options.effort,
|
|
9092
9442
|
format: state.formattedFormat,
|
|
9093
9443
|
instructions: options.instructions,
|