@modelprofile.com/flexharness-models 10.13.0 → 10.15.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.
@@ -3,6 +3,6 @@ export { generateText, jsonSchema, RetryError, StreamProviderError, streamText,
3
3
  export type { ModelMessage, StreamTextResult, ToolSet } from 'ai';
4
4
  import { APICallError } from '@ai-sdk/provider';
5
5
  export { APICallError };
6
- export type { JSONObject, JSONValue, LanguageModelV3, LanguageModelV3Prompt, LanguageModelV4, LanguageModelV4Middleware, LanguageModelV4Prompt, LanguageModelV4StreamPart, SharedV4Headers, } from '@ai-sdk/provider';
6
+ export type { JSONObject, JSONValue, LanguageModelV3, LanguageModelV3Prompt, LanguageModelV4, LanguageModelV4CallOptions, LanguageModelV4Middleware, LanguageModelV4Prompt, LanguageModelV4StreamPart, SharedV4Headers, } from '@ai-sdk/provider';
7
7
  import { isAbortError, isProviderStreamError } from '@ai-sdk/provider-utils';
8
8
  export { isAbortError, isProviderStreamError };
@@ -7,4 +7,4 @@ export { APICallError };
7
7
  // ai-sdk provider utilities
8
8
  import { isAbortError, isProviderStreamError } from '@ai-sdk/provider-utils';
9
9
  export { isAbortError, isProviderStreamError };
10
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX21vZGVscy9wbHVnaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWM7QUFDZCxPQUFPLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsbUJBQW1CLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxNQUFNLElBQUksQ0FBQztBQUVqRyxPQUFPLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsbUJBQW1CLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxDQUFDO0FBR3ZGLDRCQUE0QjtBQUM1QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFaEQsT0FBTyxFQUFFLFlBQVksRUFBRSxDQUFDO0FBYXhCLDRCQUE0QjtBQUM1QixPQUFPLEVBQUUsWUFBWSxFQUFFLHFCQUFxQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFN0UsT0FBTyxFQUFFLFlBQVksRUFBRSxxQkFBcUIsRUFBRSxDQUFDIn0=
10
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX21vZGVscy9wbHVnaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWM7QUFDZCxPQUFPLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsbUJBQW1CLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxNQUFNLElBQUksQ0FBQztBQUVqRyxPQUFPLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsbUJBQW1CLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxDQUFDO0FBR3ZGLDRCQUE0QjtBQUM1QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFaEQsT0FBTyxFQUFFLFlBQVksRUFBRSxDQUFDO0FBY3hCLDRCQUE0QjtBQUM1QixPQUFPLEVBQUUsWUFBWSxFQUFFLHFCQUFxQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFN0UsT0FBTyxFQUFFLFlBQVksRUFBRSxxQkFBcUIsRUFBRSxDQUFDIn0=
@@ -5,10 +5,37 @@ export type TSmartAiCacheRetention = 'ephemeral' | '1h' | 'in_memory' | '24h';
5
5
  export interface ISmartAiCacheOptions {
6
6
  /** Provider-specific message cache marker namespace. Usually inferred from the model. */
7
7
  provider?: TSmartAiMessageCacheProvider;
8
- /** Stable session/request key for providers that support request-level prompt cache affinity. */
8
+ /**
9
+ * The OpenAI `prompt_cache_key`, sent as given. Without it the key is derived from the request's
10
+ * stable prefix, its instructions and tool definitions, so sessions that share a prefix share
11
+ * the provider's cache; see `deriveSmartAiPromptCacheKey`.
12
+ */
9
13
  key?: string;
10
- /** Short retention is the default; longer retention is opt-in. */
14
+ /**
15
+ * Mixed into the derived key: requests of different scopes, such as tenants, never share a key,
16
+ * which keeps their cache routing and the provider's cache accounting apart.
17
+ */
18
+ keyScope?: string;
19
+ /**
20
+ * How many keys a derived key is spread over on OpenAI models that route by key (before GPT-5.6),
21
+ * each session keeping one. OpenAI suggests about 15 requests a minute per key, so size it as the
22
+ * prefix's peak requests a minute across all processes divided by 15. Defaults to 1.
23
+ */
24
+ keyBuckets?: number;
25
+ /**
26
+ * Anthropic: `'1h'` writes one-hour breakpoints instead of the five-minute default. OpenAI models
27
+ * before GPT-5.6: `'in_memory'` or `'24h'` is sent as `prompt_cache_retention`; without it the
28
+ * provider's default applies (24 hours, or in memory for Zero Data Retention organizations).
29
+ */
11
30
  retention?: TSmartAiCacheRetention;
31
+ /**
32
+ * Anthropic: the lifetime of the stable prefix's breakpoints, the tool definitions and system
33
+ * prompt, apart from the conversation's. `'1h'` (the default) keeps the prefix for sessions that
34
+ * start minutes apart while the growing conversation keeps five-minute breakpoints; writing it
35
+ * costs twice the input price instead of 1.25 times, once an hour on steady traffic.
36
+ * `'ephemeral'` writes it for five minutes. Never shorter than `retention`.
37
+ */
38
+ prefixRetention?: 'ephemeral' | '1h';
12
39
  /** Configured maximum idle scheduling budget, not a promise of cache retention or a cache hit. */
13
40
  warmDurationMs?: number;
14
41
  }
@@ -16,12 +43,62 @@ export type TSmartAiCacheSetting = boolean | 'auto' | ISmartAiCacheOptions;
16
43
  export declare function mergeSmartAiProviderOptions(defaults?: TSmartAiProviderOptions, overrides?: TSmartAiProviderOptions): TSmartAiProviderOptions | undefined;
17
44
  export declare function resolveSmartAiCacheProvider(provider?: string, modelId?: string): TSmartAiMessageCacheProvider | undefined;
18
45
  export declare function getSmartAiMessageCacheProviderOptions(provider: TSmartAiMessageCacheProvider, options?: ISmartAiCacheOptions): TSmartAiProviderOptions;
46
+ type TSmartAiCacheableTool = NonNullable<plugins.LanguageModelV4CallOptions['tools']>[number];
19
47
  export declare function applySmartAiPromptCaching(prompt: plugins.LanguageModelV4Prompt, options?: ISmartAiCacheOptions): plugins.LanguageModelV4Prompt;
48
+ /**
49
+ * Places cache markers on a request: its prompt and, for Anthropic, its tool definitions. See
50
+ * `planCacheMarkers` for where they go.
51
+ */
52
+ export declare function applySmartAiRequestCaching<TRequest extends {
53
+ prompt: plugins.LanguageModelV4Prompt;
54
+ tools?: TSmartAiCacheableTool[];
55
+ }>(request: TRequest, options?: ISmartAiCacheOptions): TRequest;
20
56
  export declare function createSmartAiCachingMiddleware(options?: ISmartAiCacheOptions): plugins.LanguageModelV4Middleware;
57
+ /**
58
+ * OpenAI routes a request to the machine that holds its cached prefix by a hash of the prefix's
59
+ * first tokens and the `prompt_cache_key`, and a key is meant to carry about 15 requests a minute
60
+ * across all prefixes using it before traffic overflows to other machines
61
+ * (https://developers.openai.com/api/docs/guides/prompt-caching, "Prompt cache keys" and
62
+ * "Cache location", read 2026-10-07). `keyBuckets` is sized by it.
63
+ */
64
+ export declare const OPENAI_PROMPT_CACHE_KEY_REQUESTS_PER_MINUTE = 15;
65
+ /** A tool definition as a request sends it, for deriving a prompt cache key. */
66
+ export interface ISmartAiPromptCacheTool {
67
+ type?: string;
68
+ name: string;
69
+ description?: string;
70
+ inputSchema?: unknown;
71
+ strict?: boolean;
72
+ }
73
+ /**
74
+ * A `prompt_cache_key` for the prefix every turn of a request repeats: its instructions and tool
75
+ * definitions, in the order they are sent, and the host's scope. Requests with the same prefix get
76
+ * the same key, so their sessions reach the machine holding it; any change to the prefix changes
77
+ * the key. A scope of letters, digits, `_` and `-` up to 40 characters stays readable in the key,
78
+ * any other is hashed. With `buckets`, sessions spread over that many keys, each keeping one, so a
79
+ * session's growing conversation stays with the machine that caches it.
80
+ */
81
+ export declare function deriveSmartAiPromptCacheKey(input: {
82
+ system?: string;
83
+ tools?: readonly ISmartAiPromptCacheTool[];
84
+ scope?: string;
85
+ /** With `buckets` above 1: the session, which keeps its bucket for every request it sends. */
86
+ affinity?: string;
87
+ buckets?: number;
88
+ }): string;
89
+ /**
90
+ * Whether an OpenAI model routes its prompt cache by itself: from GPT-5.6 on the key only separates
91
+ * cache accounting (https://developers.openai.com/api/docs/guides/prompt-caching, "Summary of model
92
+ * differences", read 2026-10-07). Earlier and unrecognized models are routed by the key.
93
+ */
94
+ export declare function openAiRoutesPromptCacheAutomatically(modelId: string | undefined): boolean;
21
95
  export declare function getSmartAiCacheProviderOptions(input: {
22
96
  provider?: string;
23
97
  modelId?: string;
24
98
  cache?: TSmartAiCacheSetting;
99
+ /** The derived `prompt_cache_key` (`deriveSmartAiPromptCacheKey`); a configured `key` takes precedence. */
100
+ promptCacheKey?: string;
101
+ /** The key used when neither a configured nor a derived key is given. */
25
102
  sessionId?: string;
26
103
  }): TSmartAiProviderOptions | undefined;
27
104
  export declare function applySmartAiCacheProviderOptions(input: {
@@ -29,6 +106,7 @@ export declare function applySmartAiCacheProviderOptions(input: {
29
106
  modelId?: string;
30
107
  providerOptions?: TSmartAiProviderOptions;
31
108
  cache?: TSmartAiCacheSetting;
109
+ promptCacheKey?: string;
32
110
  sessionId?: string;
33
111
  }): TSmartAiProviderOptions | undefined;
34
112
  /** Observation at the model dispatch boundary; no field certifies a cache write or hit. */
@@ -126,37 +126,181 @@ function applyCacheToMessage(message, provider, options) {
126
126
  }
127
127
  return applyProviderOptionsDefaults(message, providerOptions);
128
128
  }
129
- export function applySmartAiPromptCaching(prompt, options = {}) {
130
- const provider = options.provider ?? 'anthropic';
131
- const targetIndexes = new Set();
132
- const nonSystemIndexes = [];
133
- let systemCount = 0;
134
- for (let i = 0; i < prompt.length; i++) {
135
- const message = prompt[i];
136
- if (message.role === 'system') {
137
- if (systemCount < 2)
138
- targetIndexes.add(i);
139
- systemCount++;
129
+ /** Anthropic accepts at most four cache breakpoints per request; the AI SDK ignores any beyond. */
130
+ const MAX_CACHE_MARKERS = 4;
131
+ /** Whether a message, one of its parts, or a tool already carries a caller's cache marker. */
132
+ function hasCacheMarker(item, provider) {
133
+ if (!item)
134
+ return false;
135
+ const [namespace, controls] = Object.entries(getSmartAiMessageCacheProviderOptions(provider))[0];
136
+ const caller = item.providerOptions?.[namespace];
137
+ return isObject(caller) && (Object.keys(controls).some((key) => Object.prototype.hasOwnProperty.call(caller, key))
138
+ || (namespace === 'anthropic' && Object.prototype.hasOwnProperty.call(caller, 'cache_control')));
139
+ }
140
+ function cacheMarkerCount(message, provider) {
141
+ const own = hasCacheMarker(message, provider) ? 1 : 0;
142
+ const parts = Array.isArray(message.content)
143
+ ? message.content.filter((part) => hasCacheMarker(part, provider)).length
144
+ : 0;
145
+ return own + parts;
146
+ }
147
+ /**
148
+ * Where a request's cache markers go, within the provider's limit of four, counting markers a
149
+ * caller set itself. The first two system messages are the stable ones (later system messages may
150
+ * carry per-request content); the second, or the only one, ends the stable prefix and also caches
151
+ * the tool definitions rendered before it. Without a system message the last tool definition ends
152
+ * the prefix. In order: that end of the prefix, the last message, the message before it (the rolling
153
+ * breakpoints of a growing conversation), and the first system message.
154
+ */
155
+ function planCacheMarkers(prompt, tools, provider) {
156
+ const marked = new Set();
157
+ const plan = { messages: new Set(), prefixMessages: new Set(), callerMarkers: 0 };
158
+ // The provider counts every block that carries a marker: a message's own and each marked part.
159
+ prompt.forEach((message, index) => {
160
+ const blocks = cacheMarkerCount(message, provider);
161
+ if (blocks > 0)
162
+ marked.add(index);
163
+ plan.callerMarkers += blocks;
164
+ });
165
+ const markedTools = (tools ?? []).filter((definition) => hasCacheMarker(definition, provider)).length;
166
+ const toolMarked = markedTools > 0;
167
+ plan.callerMarkers += markedTools;
168
+ let budget = MAX_CACHE_MARKERS - plan.callerMarkers;
169
+ const system = prompt.flatMap((message, index) => message.role === 'system' ? [index] : []).slice(0, 2);
170
+ const nonSystem = prompt.flatMap((message, index) => message.role === 'system' ? [] : [index]);
171
+ const rolling = nonSystem.slice(-2).reverse();
172
+ // A one-hour prefix marker must precede every five-minute one.
173
+ const isPrefix = (index) => rolling.every((rollingIndex) => index < rollingIndex) ? true : undefined;
174
+ const candidates = [];
175
+ if (system.length > 0) {
176
+ candidates.push({ message: system[system.length - 1], prefix: isPrefix(system[system.length - 1]) });
177
+ }
178
+ else if (provider === 'anthropic' && tools && tools.length > 0 && !toolMarked) {
179
+ candidates.push({ tool: tools.length - 1 });
180
+ }
181
+ for (const index of rolling)
182
+ candidates.push({ message: index });
183
+ if (system.length > 1)
184
+ candidates.push({ message: system[0], prefix: isPrefix(system[0]) });
185
+ for (const candidate of candidates) {
186
+ if ('tool' in candidate) {
187
+ if (budget <= 0)
188
+ continue;
189
+ plan.tool = candidate.tool;
190
+ budget--;
140
191
  continue;
141
192
  }
142
- nonSystemIndexes.push(i);
143
- }
144
- for (const index of nonSystemIndexes.slice(-2)) {
145
- targetIndexes.add(index);
193
+ if (plan.messages.has(candidate.message))
194
+ continue;
195
+ if (!marked.has(candidate.message)) {
196
+ if (budget <= 0)
197
+ continue;
198
+ budget--;
199
+ }
200
+ plan.messages.add(candidate.message);
201
+ if (candidate.prefix)
202
+ plan.prefixMessages.add(candidate.message);
146
203
  }
147
- if (targetIndexes.size === 0)
148
- return prompt;
149
- return prompt.map((message, index) => targetIndexes.has(index) ? applyCacheToMessage(message, provider, options) : message);
204
+ return plan;
205
+ }
206
+ export function applySmartAiPromptCaching(prompt, options = {}) {
207
+ return applySmartAiRequestCaching({ prompt }, options).prompt;
208
+ }
209
+ /**
210
+ * Places cache markers on a request: its prompt and, for Anthropic, its tool definitions. See
211
+ * `planCacheMarkers` for where they go.
212
+ */
213
+ export function applySmartAiRequestCaching(request, options = {}) {
214
+ const provider = options.provider ?? 'anthropic';
215
+ const plan = planCacheMarkers(request.prompt, request.tools, provider);
216
+ // A one-hour breakpoint must precede five-minute ones: the prefix never lives shorter than the
217
+ // rest, and a caller's own markers, whose lifetimes and places are its own, keep the prefix at the
218
+ // request's retention.
219
+ const prefixOptions = options.retention === '1h'
220
+ || ((options.prefixRetention ?? '1h') === '1h' && plan.callerMarkers === 0)
221
+ ? { ...options, retention: '1h' }
222
+ : options;
223
+ const prompt = plan.messages.size === 0
224
+ ? request.prompt
225
+ : request.prompt.map((message, index) => plan.messages.has(index)
226
+ ? applyCacheToMessage(message, provider, plan.prefixMessages.has(index) ? prefixOptions : options)
227
+ : message);
228
+ const tools = plan.tool === undefined || !request.tools
229
+ ? request.tools
230
+ : request.tools.map((definition, index) => index === plan.tool
231
+ ? applyProviderOptionsDefaults(definition, getSmartAiMessageCacheProviderOptions(provider, prefixOptions))
232
+ : definition);
233
+ return { ...request, prompt, ...(tools ? { tools } : {}) };
150
234
  }
151
235
  export function createSmartAiCachingMiddleware(options = {}) {
152
236
  return {
153
237
  specificationVersion: 'v4',
154
- transformParams: async ({ params }) => ({
155
- ...params,
156
- prompt: applySmartAiPromptCaching(params.prompt, options),
157
- }),
238
+ transformParams: async ({ params }) => applySmartAiRequestCaching(params, options),
158
239
  };
159
240
  }
241
+ /**
242
+ * OpenAI routes a request to the machine that holds its cached prefix by a hash of the prefix's
243
+ * first tokens and the `prompt_cache_key`, and a key is meant to carry about 15 requests a minute
244
+ * across all prefixes using it before traffic overflows to other machines
245
+ * (https://developers.openai.com/api/docs/guides/prompt-caching, "Prompt cache keys" and
246
+ * "Cache location", read 2026-10-07). `keyBuckets` is sized by it.
247
+ */
248
+ export const OPENAI_PROMPT_CACHE_KEY_REQUESTS_PER_MINUTE = 15;
249
+ const hash64 = (text) => {
250
+ // Two 32-bit FNV-1a lanes: a routing key needs a stable digest, not a cryptographic one.
251
+ let low = 0x811c9dc5;
252
+ let high = 0xcbf29ce4;
253
+ for (let index = 0; index < text.length; index++) {
254
+ const code = text.charCodeAt(index);
255
+ low = Math.imul(low ^ code, 0x01000193) >>> 0;
256
+ high = Math.imul(high ^ code ^ (low >>> 7), 0x01000193) >>> 0;
257
+ }
258
+ return high.toString(16).padStart(8, '0') + low.toString(16).padStart(8, '0');
259
+ };
260
+ /**
261
+ * A `prompt_cache_key` for the prefix every turn of a request repeats: its instructions and tool
262
+ * definitions, in the order they are sent, and the host's scope. Requests with the same prefix get
263
+ * the same key, so their sessions reach the machine holding it; any change to the prefix changes
264
+ * the key. A scope of letters, digits, `_` and `-` up to 40 characters stays readable in the key,
265
+ * any other is hashed. With `buckets`, sessions spread over that many keys, each keeping one, so a
266
+ * session's growing conversation stays with the machine that caches it.
267
+ */
268
+ export function deriveSmartAiPromptCacheKey(input) {
269
+ const prefix = hash64(JSON.stringify([
270
+ input.system ?? '',
271
+ (input.tools ?? []).map((definition) => [
272
+ definition.type ?? 'function',
273
+ definition.name,
274
+ definition.description ?? '',
275
+ definition.inputSchema ?? null,
276
+ definition.strict ?? null,
277
+ ]),
278
+ ]));
279
+ const buckets = input.buckets ?? 1;
280
+ if (!Number.isSafeInteger(buckets) || buckets < 1)
281
+ throw new Error('keyBuckets must be a positive integer.');
282
+ const bucket = buckets > 1 && input.affinity !== undefined
283
+ ? Number.parseInt(hash64(input.affinity).slice(8), 16) % buckets
284
+ : 0;
285
+ const key = bucket === 0 ? prefix : `${prefix}.${bucket}`;
286
+ if (input.scope === undefined || input.scope === '')
287
+ return key;
288
+ const scope = /^[A-Za-z0-9_-]{1,40}$/.test(input.scope) ? input.scope : `s${hash64(input.scope)}`;
289
+ return `${scope}.${key}`;
290
+ }
291
+ /**
292
+ * Whether an OpenAI model routes its prompt cache by itself: from GPT-5.6 on the key only separates
293
+ * cache accounting (https://developers.openai.com/api/docs/guides/prompt-caching, "Summary of model
294
+ * differences", read 2026-10-07). Earlier and unrecognized models are routed by the key.
295
+ */
296
+ export function openAiRoutesPromptCacheAutomatically(modelId) {
297
+ const match = /(?:^|[^a-z0-9])gpt-(\d+)(?:\.(\d+))?/i.exec(modelId ?? '');
298
+ if (!match)
299
+ return false;
300
+ const major = Number(match[1]);
301
+ const minor = Number(match[2] ?? 0);
302
+ return major > 5 || (major === 5 && minor >= 6);
303
+ }
160
304
  function isOpenAiProvider(provider) {
161
305
  const providerLower = provider?.toLowerCase() ?? '';
162
306
  return providerLower === 'openai' || providerLower.startsWith('openai.') || providerLower.includes('@ai-sdk/openai');
@@ -166,16 +310,17 @@ export function getSmartAiCacheProviderOptions(input) {
166
310
  if (!cacheOptions)
167
311
  return undefined;
168
312
  if (isOpenAiProvider(input.provider)) {
169
- const key = cacheOptions.key ?? input.sessionId;
313
+ const key = cacheOptions.key ?? input.promptCacheKey ?? input.sessionId;
314
+ // GPT-5.6 and later take `prompt_cache_options.ttl` instead, whose only value is its default.
315
+ const retention = (cacheOptions.retention === '24h' || cacheOptions.retention === 'in_memory')
316
+ && !openAiRoutesPromptCacheAutomatically(input.modelId)
317
+ ? cacheOptions.retention
318
+ : undefined;
170
319
  return {
171
320
  openai: {
172
321
  store: false,
173
322
  ...(key ? { promptCacheKey: key } : {}),
174
- ...(cacheOptions.retention === '24h' || cacheOptions.retention === 'in_memory'
175
- ? { promptCacheRetention: cacheOptions.retention }
176
- : key
177
- ? { promptCacheRetention: 'in_memory' }
178
- : {}),
323
+ ...(retention ? { promptCacheRetention: retention } : {}),
179
324
  },
180
325
  };
181
326
  }
@@ -258,4 +403,4 @@ export function getSmartAiCacheWaitMs(requestedMs, dispatch, now = Date.now()) {
258
403
  const headroom = Math.min(1000, Math.ceil(dispatch.warmDurationMs / 10));
259
404
  return Math.max(0, Math.min(maximum, Math.floor(dispatch.idleDeadline - now - headroom)));
260
405
  }
261
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhaS5jYWNoZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX21vZGVscy9zbWFydGFpLmNhY2hlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQTBCQSxTQUFTLFFBQVEsQ0FBQyxLQUFjO0lBQzlCLE9BQU8sT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQzlFLENBQUM7QUFFRCxTQUFTLGlCQUFpQixDQUFDLFFBQTRCLEVBQUUsU0FBOEI7SUFDckYsTUFBTSxNQUFNLEdBQXVCLEVBQUUsR0FBRyxRQUFRLEVBQUUsQ0FBQztJQUVuRCxJQUFJLENBQUMsU0FBUztRQUFFLE9BQU8sTUFBTSxDQUFDO0lBRTlCLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDckQsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzdCLElBQUksUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxpQkFBaUIsQ0FBQyxRQUE4QixFQUFFLEtBQTJCLENBQUMsQ0FBQztZQUM3RixTQUFTO1FBQ1gsQ0FBQztRQUNELE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUEwQixDQUFDO0lBQzNDLENBQUM7SUFFRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQsTUFBTSxVQUFVLDJCQUEyQixDQUN6QyxRQUFrQyxFQUNsQyxTQUFtQztJQUVuQyxJQUFJLENBQUMsUUFBUTtRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ2hDLElBQUksQ0FBQyxTQUFTO1FBQUUsT0FBTyxRQUFRLENBQUM7SUFDaEMsT0FBTyxpQkFBaUIs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
406
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhaS5jYWNoZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX21vZGVscy9zbWFydGFpLmNhY2hlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQXFEQSxTQUFTLFFBQVEsQ0FBQyxLQUFjO0lBQzlCLE9BQU8sT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQzlFLENBQUM7QUFFRCxTQUFTLGlCQUFpQixDQUFDLFFBQTRCLEVBQUUsU0FBOEI7SUFDckYsTUFBTSxNQUFNLEdBQXVCLEVBQUUsR0FBRyxRQUFRLEVBQUUsQ0FBQztJQUVuRCxJQUFJLENBQUMsU0FBUztRQUFFLE9BQU8sTUFBTSxDQUFDO0lBRTlCLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDckQsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzdCLElBQUksUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxpQkFBaUIsQ0FBQyxRQUE4QixFQUFFLEtBQTJCLENBQUMsQ0FBQztZQUM3RixTQUFTO1FBQ1gsQ0FBQztRQUNELE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUEwQixDQUFDO0lBQzNDLENBQUM7SUFFRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQsTUFBTSxVQUFVLDJCQUEyQixDQUN6QyxRQUFrQyxFQUNsQyxTQUFtQztJQUVuQyxJQUFJLENBQUMsUUFBUTtRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ2hDLElBQUksQ0FBQyxTQUFTO1FBQUUsT0FBTyxRQUFRLENBQUM7SUFDaEMsT0FBTyxpQkFBaUIs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
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "Task Venture Capital GmbH",
3
3
  "license": "MIT",
4
4
  "name": "@modelprofile.com/flexharness-models",
5
- "version": "10.13.0",
5
+ "version": "10.15.0",
6
6
  "type": "module",
7
7
  "description": "Provider-independent model contracts, prompt caching and explicit model registration.",
8
8
  "main": "./dist_ts_models/index.js",
package/readme.md CHANGED
@@ -48,6 +48,43 @@ media type and the content decoded in the stated charset (UTF-8 by default), in
48
48
  than any backtick run in the content. Images, PDFs, other binary files, URLs and file references
49
49
  pass unchanged; a file that names text but does not decode fails before the request is sent.
50
50
 
51
+ ### Prompt caching
52
+
53
+ `TSmartAiCacheSetting` is `'auto'` (the default of a FlexHarness session), `false`, or an
54
+ `ISmartAiCacheOptions` object. It decides the cache hints a request carries:
55
+
56
+ - **Anthropic** (and the message-level dialects of OpenRouter, Bedrock and OpenAI-compatible
57
+ servers): `applySmartAiRequestCaching({ prompt, tools }, options)` places at most four
58
+ breakpoints, counting markers the caller set itself. The first two system messages are the stable
59
+ ones; the second, or the only one, ends the stable prefix and caches the tool definitions rendered
60
+ before it. Without a system message the last tool definition ends the prefix, so sessions share
61
+ it. The last message and the one before it carry the rolling breakpoints of a growing
62
+ conversation, then the first system message. On Anthropic the stable prefix's breakpoints last an
63
+ hour (`prefixRetention`, default `'1h'`), so sessions that start minutes apart still read it, while the
64
+ conversation keeps five-minute breakpoints; a one-hour write costs twice the input price, a
65
+ five-minute write 1.25 times, and on steady traffic the prefix is written once an hour.
66
+ `prefixRetention: 'ephemeral'` writes the prefix for five minutes; `retention: '1h'` makes every
67
+ breakpoint last an hour. A request that carries markers of the caller's own
68
+ keeps the prefix at `retention`, since a one-hour breakpoint may not follow a five-minute one.
69
+ `createSmartAiCachingMiddleware(options)` applies it to every call of a model. Each model has a
70
+ minimum cacheable prefix (512 to 4,096 tokens); a breakpoint below it neither writes nor reads and
71
+ costs nothing, so the planner places breakpoints without counting tokens it cannot count before
72
+ the request is sent.
73
+ - **OpenAI** (Responses and the ChatGPT Codex backend): `store: false` and a `prompt_cache_key`.
74
+ `deriveSmartAiPromptCacheKey({ system, tools, scope })` derives the key from the instructions and
75
+ tool definitions every turn repeats, so sessions with one prefix reach the machine that caches it;
76
+ any change to the prefix changes the key. `keyScope` keeps tenants apart, and `key` replaces the
77
+ derived key. OpenAI suggests about 15 requests a minute per key
78
+ (`OPENAI_PROMPT_CACHE_KEY_REQUESTS_PER_MINUTE`); `keyBuckets` spreads a prefix over that many keys,
79
+ each session keeping one by its session id, on models that route by key; requests without a
80
+ session id take the first. From GPT-5.6 on OpenAI routes by itself
81
+ and the key only separates cache accounting (`openAiRoutesPromptCacheAutomatically`).
82
+ `retention: 'in_memory' | '24h'` is sent as `prompt_cache_retention` to earlier models; without it
83
+ the provider's default applies.
84
+
85
+ `getSmartAiCacheProviderOptions` and `applySmartAiCacheProviderOptions` return the provider options
86
+ of a setting; a caller's own options win.
87
+
51
88
  ## License and Legal Information
52
89
 
53
90
  This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the repository license file.
@@ -14,6 +14,7 @@ export type {
14
14
  LanguageModelV3,
15
15
  LanguageModelV3Prompt,
16
16
  LanguageModelV4,
17
+ LanguageModelV4CallOptions,
17
18
  LanguageModelV4Middleware,
18
19
  LanguageModelV4Prompt,
19
20
  LanguageModelV4StreamPart,
@@ -48,6 +48,43 @@ media type and the content decoded in the stated charset (UTF-8 by default), in
48
48
  than any backtick run in the content. Images, PDFs, other binary files, URLs and file references
49
49
  pass unchanged; a file that names text but does not decode fails before the request is sent.
50
50
 
51
+ ### Prompt caching
52
+
53
+ `TSmartAiCacheSetting` is `'auto'` (the default of a FlexHarness session), `false`, or an
54
+ `ISmartAiCacheOptions` object. It decides the cache hints a request carries:
55
+
56
+ - **Anthropic** (and the message-level dialects of OpenRouter, Bedrock and OpenAI-compatible
57
+ servers): `applySmartAiRequestCaching({ prompt, tools }, options)` places at most four
58
+ breakpoints, counting markers the caller set itself. The first two system messages are the stable
59
+ ones; the second, or the only one, ends the stable prefix and caches the tool definitions rendered
60
+ before it. Without a system message the last tool definition ends the prefix, so sessions share
61
+ it. The last message and the one before it carry the rolling breakpoints of a growing
62
+ conversation, then the first system message. On Anthropic the stable prefix's breakpoints last an
63
+ hour (`prefixRetention`, default `'1h'`), so sessions that start minutes apart still read it, while the
64
+ conversation keeps five-minute breakpoints; a one-hour write costs twice the input price, a
65
+ five-minute write 1.25 times, and on steady traffic the prefix is written once an hour.
66
+ `prefixRetention: 'ephemeral'` writes the prefix for five minutes; `retention: '1h'` makes every
67
+ breakpoint last an hour. A request that carries markers of the caller's own
68
+ keeps the prefix at `retention`, since a one-hour breakpoint may not follow a five-minute one.
69
+ `createSmartAiCachingMiddleware(options)` applies it to every call of a model. Each model has a
70
+ minimum cacheable prefix (512 to 4,096 tokens); a breakpoint below it neither writes nor reads and
71
+ costs nothing, so the planner places breakpoints without counting tokens it cannot count before
72
+ the request is sent.
73
+ - **OpenAI** (Responses and the ChatGPT Codex backend): `store: false` and a `prompt_cache_key`.
74
+ `deriveSmartAiPromptCacheKey({ system, tools, scope })` derives the key from the instructions and
75
+ tool definitions every turn repeats, so sessions with one prefix reach the machine that caches it;
76
+ any change to the prefix changes the key. `keyScope` keeps tenants apart, and `key` replaces the
77
+ derived key. OpenAI suggests about 15 requests a minute per key
78
+ (`OPENAI_PROMPT_CACHE_KEY_REQUESTS_PER_MINUTE`); `keyBuckets` spreads a prefix over that many keys,
79
+ each session keeping one by its session id, on models that route by key; requests without a
80
+ session id take the first. From GPT-5.6 on OpenAI routes by itself
81
+ and the key only separates cache accounting (`openAiRoutesPromptCacheAutomatically`).
82
+ `retention: 'in_memory' | '24h'` is sent as `prompt_cache_retention` to earlier models; without it
83
+ the provider's default applies.
84
+
85
+ `getSmartAiCacheProviderOptions` and `applySmartAiCacheProviderOptions` return the provider options
86
+ of a setting; a caller's own options win.
87
+
51
88
  ## License and Legal Information
52
89
 
53
90
  This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the repository license file.
@@ -14,10 +14,37 @@ export type TSmartAiCacheRetention = 'ephemeral' | '1h' | 'in_memory' | '24h';
14
14
  export interface ISmartAiCacheOptions {
15
15
  /** Provider-specific message cache marker namespace. Usually inferred from the model. */
16
16
  provider?: TSmartAiMessageCacheProvider;
17
- /** Stable session/request key for providers that support request-level prompt cache affinity. */
17
+ /**
18
+ * The OpenAI `prompt_cache_key`, sent as given. Without it the key is derived from the request's
19
+ * stable prefix, its instructions and tool definitions, so sessions that share a prefix share
20
+ * the provider's cache; see `deriveSmartAiPromptCacheKey`.
21
+ */
18
22
  key?: string;
19
- /** Short retention is the default; longer retention is opt-in. */
23
+ /**
24
+ * Mixed into the derived key: requests of different scopes, such as tenants, never share a key,
25
+ * which keeps their cache routing and the provider's cache accounting apart.
26
+ */
27
+ keyScope?: string;
28
+ /**
29
+ * How many keys a derived key is spread over on OpenAI models that route by key (before GPT-5.6),
30
+ * each session keeping one. OpenAI suggests about 15 requests a minute per key, so size it as the
31
+ * prefix's peak requests a minute across all processes divided by 15. Defaults to 1.
32
+ */
33
+ keyBuckets?: number;
34
+ /**
35
+ * Anthropic: `'1h'` writes one-hour breakpoints instead of the five-minute default. OpenAI models
36
+ * before GPT-5.6: `'in_memory'` or `'24h'` is sent as `prompt_cache_retention`; without it the
37
+ * provider's default applies (24 hours, or in memory for Zero Data Retention organizations).
38
+ */
20
39
  retention?: TSmartAiCacheRetention;
40
+ /**
41
+ * Anthropic: the lifetime of the stable prefix's breakpoints, the tool definitions and system
42
+ * prompt, apart from the conversation's. `'1h'` (the default) keeps the prefix for sessions that
43
+ * start minutes apart while the growing conversation keeps five-minute breakpoints; writing it
44
+ * costs twice the input price instead of 1.25 times, once an hour on steady traffic.
45
+ * `'ephemeral'` writes it for five minutes. Never shorter than `retention`.
46
+ */
47
+ prefixRetention?: 'ephemeral' | '1h';
21
48
  /** Configured maximum idle scheduling budget, not a promise of cache retention or a cache hit. */
22
49
  warmDurationMs?: number;
23
50
  }
@@ -176,46 +203,229 @@ function applyCacheToMessage(
176
203
  return applyProviderOptionsDefaults(message, providerOptions);
177
204
  }
178
205
 
179
- export function applySmartAiPromptCaching(
206
+ /** Anthropic accepts at most four cache breakpoints per request; the AI SDK ignores any beyond. */
207
+ const MAX_CACHE_MARKERS = 4;
208
+
209
+ type TSmartAiPromptMessage = plugins.LanguageModelV4Prompt[number];
210
+ type TSmartAiCacheableTool = NonNullable<plugins.LanguageModelV4CallOptions['tools']>[number];
211
+
212
+ /** Whether a message, one of its parts, or a tool already carries a caller's cache marker. */
213
+ function hasCacheMarker(
214
+ item: { providerOptions?: TSmartAiProviderOptions } | undefined,
215
+ provider: TSmartAiMessageCacheProvider,
216
+ ): boolean {
217
+ if (!item) return false;
218
+ const [namespace, controls] = Object.entries(getSmartAiMessageCacheProviderOptions(provider))[0];
219
+ const caller = item.providerOptions?.[namespace];
220
+ return isObject(caller) && (
221
+ Object.keys(controls).some((key) => Object.prototype.hasOwnProperty.call(caller, key))
222
+ || (namespace === 'anthropic' && Object.prototype.hasOwnProperty.call(caller, 'cache_control'))
223
+ );
224
+ }
225
+
226
+ function cacheMarkerCount(message: TSmartAiPromptMessage, provider: TSmartAiMessageCacheProvider): number {
227
+ const own = hasCacheMarker(message as { providerOptions?: TSmartAiProviderOptions }, provider) ? 1 : 0;
228
+ const parts = Array.isArray(message.content)
229
+ ? message.content.filter((part) => hasCacheMarker(part as { providerOptions?: TSmartAiProviderOptions }, provider)).length
230
+ : 0;
231
+ return own + parts;
232
+ }
233
+
234
+ interface ICacheMarkerPlan {
235
+ /** Markers the caller set itself, counted per block as the provider counts them. */
236
+ callerMarkers: number;
237
+ messages: Set<number>;
238
+ /** The messages among `messages` that end the stable prefix rather than the conversation. */
239
+ prefixMessages: Set<number>;
240
+ /** The tool definition that ends the stable prefix of a request without a system message. */
241
+ tool?: number;
242
+ }
243
+
244
+ /**
245
+ * Where a request's cache markers go, within the provider's limit of four, counting markers a
246
+ * caller set itself. The first two system messages are the stable ones (later system messages may
247
+ * carry per-request content); the second, or the only one, ends the stable prefix and also caches
248
+ * the tool definitions rendered before it. Without a system message the last tool definition ends
249
+ * the prefix. In order: that end of the prefix, the last message, the message before it (the rolling
250
+ * breakpoints of a growing conversation), and the first system message.
251
+ */
252
+ function planCacheMarkers(
180
253
  prompt: plugins.LanguageModelV4Prompt,
181
- options: ISmartAiCacheOptions = {},
182
- ): plugins.LanguageModelV4Prompt {
183
- const provider = options.provider ?? 'anthropic';
184
- const targetIndexes = new Set<number>();
185
- const nonSystemIndexes: number[] = [];
186
- let systemCount = 0;
187
-
188
- for (let i = 0; i < prompt.length; i++) {
189
- const message = prompt[i];
190
- if (message.role === 'system') {
191
- if (systemCount < 2) targetIndexes.add(i);
192
- systemCount++;
254
+ tools: readonly TSmartAiCacheableTool[] | undefined,
255
+ provider: TSmartAiMessageCacheProvider,
256
+ ): ICacheMarkerPlan {
257
+ const marked = new Set<number>();
258
+ const plan: ICacheMarkerPlan = { messages: new Set(), prefixMessages: new Set(), callerMarkers: 0 };
259
+ // The provider counts every block that carries a marker: a message's own and each marked part.
260
+ prompt.forEach((message, index) => {
261
+ const blocks = cacheMarkerCount(message, provider);
262
+ if (blocks > 0) marked.add(index);
263
+ plan.callerMarkers += blocks;
264
+ });
265
+ const markedTools = (tools ?? []).filter((definition) =>
266
+ hasCacheMarker(definition as { providerOptions?: TSmartAiProviderOptions }, provider)).length;
267
+ const toolMarked = markedTools > 0;
268
+ plan.callerMarkers += markedTools;
269
+ let budget = MAX_CACHE_MARKERS - plan.callerMarkers;
270
+ const system = prompt.flatMap((message, index) => message.role === 'system' ? [index] : []).slice(0, 2);
271
+ const nonSystem = prompt.flatMap((message, index) => message.role === 'system' ? [] : [index]);
272
+ const rolling = nonSystem.slice(-2).reverse();
273
+ // A one-hour prefix marker must precede every five-minute one.
274
+ const isPrefix = (index: number): true | undefined => rolling.every((rollingIndex) => index < rollingIndex) ? true : undefined;
275
+ const candidates: Array<{ message: number; prefix?: true | undefined } | { tool: number }> = [];
276
+ if (system.length > 0) {
277
+ candidates.push({ message: system[system.length - 1], prefix: isPrefix(system[system.length - 1]) });
278
+ } else if (provider === 'anthropic' && tools && tools.length > 0 && !toolMarked) {
279
+ candidates.push({ tool: tools.length - 1 });
280
+ }
281
+ for (const index of rolling) candidates.push({ message: index });
282
+ if (system.length > 1) candidates.push({ message: system[0], prefix: isPrefix(system[0]) });
283
+ for (const candidate of candidates) {
284
+ if ('tool' in candidate) {
285
+ if (budget <= 0) continue;
286
+ plan.tool = candidate.tool;
287
+ budget--;
193
288
  continue;
194
289
  }
195
- nonSystemIndexes.push(i);
196
- }
197
-
198
- for (const index of nonSystemIndexes.slice(-2)) {
199
- targetIndexes.add(index);
290
+ if (plan.messages.has(candidate.message)) continue;
291
+ if (!marked.has(candidate.message)) {
292
+ if (budget <= 0) continue;
293
+ budget--;
294
+ }
295
+ plan.messages.add(candidate.message);
296
+ if (candidate.prefix) plan.prefixMessages.add(candidate.message);
200
297
  }
298
+ return plan;
299
+ }
201
300
 
202
- if (targetIndexes.size === 0) return prompt;
301
+ export function applySmartAiPromptCaching(
302
+ prompt: plugins.LanguageModelV4Prompt,
303
+ options: ISmartAiCacheOptions = {},
304
+ ): plugins.LanguageModelV4Prompt {
305
+ return applySmartAiRequestCaching({ prompt }, options).prompt;
306
+ }
203
307
 
204
- return prompt.map((message, index) =>
205
- targetIndexes.has(index) ? applyCacheToMessage(message, provider, options) : message,
206
- ) as plugins.LanguageModelV4Prompt;
308
+ /**
309
+ * Places cache markers on a request: its prompt and, for Anthropic, its tool definitions. See
310
+ * `planCacheMarkers` for where they go.
311
+ */
312
+ export function applySmartAiRequestCaching<
313
+ TRequest extends { prompt: plugins.LanguageModelV4Prompt; tools?: TSmartAiCacheableTool[] },
314
+ >(request: TRequest, options: ISmartAiCacheOptions = {}): TRequest {
315
+ const provider = options.provider ?? 'anthropic';
316
+ const plan = planCacheMarkers(request.prompt, request.tools, provider);
317
+ // A one-hour breakpoint must precede five-minute ones: the prefix never lives shorter than the
318
+ // rest, and a caller's own markers, whose lifetimes and places are its own, keep the prefix at the
319
+ // request's retention.
320
+ const prefixOptions: ISmartAiCacheOptions = options.retention === '1h'
321
+ || ((options.prefixRetention ?? '1h') === '1h' && plan.callerMarkers === 0)
322
+ ? { ...options, retention: '1h' }
323
+ : options;
324
+ const prompt = plan.messages.size === 0
325
+ ? request.prompt
326
+ : request.prompt.map((message, index) => plan.messages.has(index)
327
+ ? applyCacheToMessage(message, provider, plan.prefixMessages.has(index) ? prefixOptions : options)
328
+ : message,
329
+ ) as plugins.LanguageModelV4Prompt;
330
+ const tools = plan.tool === undefined || !request.tools
331
+ ? request.tools
332
+ : request.tools.map((definition, index) => index === plan.tool
333
+ ? applyProviderOptionsDefaults(
334
+ definition as TSmartAiCacheableTool & { providerOptions?: TSmartAiProviderOptions },
335
+ getSmartAiMessageCacheProviderOptions(provider, prefixOptions),
336
+ )
337
+ : definition);
338
+ return { ...request, prompt, ...(tools ? { tools } : {}) };
207
339
  }
208
340
 
209
341
  export function createSmartAiCachingMiddleware(options: ISmartAiCacheOptions = {}): plugins.LanguageModelV4Middleware {
210
342
  return {
211
343
  specificationVersion: 'v4',
212
- transformParams: async ({ params }) => ({
213
- ...params,
214
- prompt: applySmartAiPromptCaching(params.prompt, options),
215
- }),
344
+ transformParams: async ({ params }) => applySmartAiRequestCaching(params, options),
216
345
  };
217
346
  }
218
347
 
348
+ /**
349
+ * OpenAI routes a request to the machine that holds its cached prefix by a hash of the prefix's
350
+ * first tokens and the `prompt_cache_key`, and a key is meant to carry about 15 requests a minute
351
+ * across all prefixes using it before traffic overflows to other machines
352
+ * (https://developers.openai.com/api/docs/guides/prompt-caching, "Prompt cache keys" and
353
+ * "Cache location", read 2026-10-07). `keyBuckets` is sized by it.
354
+ */
355
+ export const OPENAI_PROMPT_CACHE_KEY_REQUESTS_PER_MINUTE = 15;
356
+
357
+ /** A tool definition as a request sends it, for deriving a prompt cache key. */
358
+ export interface ISmartAiPromptCacheTool {
359
+ type?: string;
360
+ name: string;
361
+ description?: string;
362
+ inputSchema?: unknown;
363
+ strict?: boolean;
364
+ }
365
+
366
+ const hash64 = (text: string): string => {
367
+ // Two 32-bit FNV-1a lanes: a routing key needs a stable digest, not a cryptographic one.
368
+ let low = 0x811c9dc5;
369
+ let high = 0xcbf29ce4;
370
+ for (let index = 0; index < text.length; index++) {
371
+ const code = text.charCodeAt(index);
372
+ low = Math.imul(low ^ code, 0x01000193) >>> 0;
373
+ high = Math.imul(high ^ code ^ (low >>> 7), 0x01000193) >>> 0;
374
+ }
375
+ return high.toString(16).padStart(8, '0') + low.toString(16).padStart(8, '0');
376
+ };
377
+
378
+ /**
379
+ * A `prompt_cache_key` for the prefix every turn of a request repeats: its instructions and tool
380
+ * definitions, in the order they are sent, and the host's scope. Requests with the same prefix get
381
+ * the same key, so their sessions reach the machine holding it; any change to the prefix changes
382
+ * the key. A scope of letters, digits, `_` and `-` up to 40 characters stays readable in the key,
383
+ * any other is hashed. With `buckets`, sessions spread over that many keys, each keeping one, so a
384
+ * session's growing conversation stays with the machine that caches it.
385
+ */
386
+ export function deriveSmartAiPromptCacheKey(input: {
387
+ system?: string;
388
+ tools?: readonly ISmartAiPromptCacheTool[];
389
+ scope?: string;
390
+ /** With `buckets` above 1: the session, which keeps its bucket for every request it sends. */
391
+ affinity?: string;
392
+ buckets?: number;
393
+ }): string {
394
+ const prefix = hash64(JSON.stringify([
395
+ input.system ?? '',
396
+ (input.tools ?? []).map((definition) => [
397
+ definition.type ?? 'function',
398
+ definition.name,
399
+ definition.description ?? '',
400
+ definition.inputSchema ?? null,
401
+ definition.strict ?? null,
402
+ ]),
403
+ ]));
404
+ const buckets = input.buckets ?? 1;
405
+ if (!Number.isSafeInteger(buckets) || buckets < 1) throw new Error('keyBuckets must be a positive integer.');
406
+ const bucket = buckets > 1 && input.affinity !== undefined
407
+ ? Number.parseInt(hash64(input.affinity).slice(8), 16) % buckets
408
+ : 0;
409
+ const key = bucket === 0 ? prefix : `${prefix}.${bucket}`;
410
+ if (input.scope === undefined || input.scope === '') return key;
411
+ const scope = /^[A-Za-z0-9_-]{1,40}$/.test(input.scope) ? input.scope : `s${hash64(input.scope)}`;
412
+ return `${scope}.${key}`;
413
+ }
414
+
415
+ /**
416
+ * Whether an OpenAI model routes its prompt cache by itself: from GPT-5.6 on the key only separates
417
+ * cache accounting (https://developers.openai.com/api/docs/guides/prompt-caching, "Summary of model
418
+ * differences", read 2026-10-07). Earlier and unrecognized models are routed by the key.
419
+ */
420
+ export function openAiRoutesPromptCacheAutomatically(modelId: string | undefined): boolean {
421
+ const match = /(?:^|[^a-z0-9])gpt-(\d+)(?:\.(\d+))?/i.exec(modelId ?? '');
422
+ if (!match) return false;
423
+ const major = Number(match[1]);
424
+ const minor = Number(match[2] ?? 0);
425
+ return major > 5 || (major === 5 && minor >= 6);
426
+ }
427
+
428
+
219
429
  function isOpenAiProvider(provider?: string): boolean {
220
430
  const providerLower = provider?.toLowerCase() ?? '';
221
431
  return providerLower === 'openai' || providerLower.startsWith('openai.') || providerLower.includes('@ai-sdk/openai');
@@ -225,22 +435,26 @@ export function getSmartAiCacheProviderOptions(input: {
225
435
  provider?: string;
226
436
  modelId?: string;
227
437
  cache?: TSmartAiCacheSetting;
438
+ /** The derived `prompt_cache_key` (`deriveSmartAiPromptCacheKey`); a configured `key` takes precedence. */
439
+ promptCacheKey?: string;
440
+ /** The key used when neither a configured nor a derived key is given. */
228
441
  sessionId?: string;
229
442
  }): TSmartAiProviderOptions | undefined {
230
443
  const cacheOptions = cacheOptionsFromSetting(input.cache);
231
444
  if (!cacheOptions) return undefined;
232
445
 
233
446
  if (isOpenAiProvider(input.provider)) {
234
- const key = cacheOptions.key ?? input.sessionId;
447
+ const key = cacheOptions.key ?? input.promptCacheKey ?? input.sessionId;
448
+ // GPT-5.6 and later take `prompt_cache_options.ttl` instead, whose only value is its default.
449
+ const retention = (cacheOptions.retention === '24h' || cacheOptions.retention === 'in_memory')
450
+ && !openAiRoutesPromptCacheAutomatically(input.modelId)
451
+ ? cacheOptions.retention
452
+ : undefined;
235
453
  return {
236
454
  openai: {
237
455
  store: false,
238
456
  ...(key ? { promptCacheKey: key } : {}),
239
- ...(cacheOptions.retention === '24h' || cacheOptions.retention === 'in_memory'
240
- ? { promptCacheRetention: cacheOptions.retention }
241
- : key
242
- ? { promptCacheRetention: 'in_memory' }
243
- : {}),
457
+ ...(retention ? { promptCacheRetention: retention } : {}),
244
458
  },
245
459
  };
246
460
  }
@@ -253,6 +467,7 @@ export function applySmartAiCacheProviderOptions(input: {
253
467
  modelId?: string;
254
468
  providerOptions?: TSmartAiProviderOptions;
255
469
  cache?: TSmartAiCacheSetting;
470
+ promptCacheKey?: string;
256
471
  sessionId?: string;
257
472
  }): TSmartAiProviderOptions | undefined {
258
473
  return mergeSmartAiProviderOptions(