promptopskit 0.3.8 → 0.4.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/README.md +97 -10
  2. package/SKILL.md +69 -6
  3. package/dist/chunk-F6UJ73Y6.js +113 -0
  4. package/dist/chunk-F6UJ73Y6.js.map +1 -0
  5. package/dist/chunk-HLNVKKMS.js +145 -0
  6. package/dist/chunk-HLNVKKMS.js.map +1 -0
  7. package/dist/{chunk-5OYWNRNC.js → chunk-JBLUPKY4.js} +191 -5
  8. package/dist/chunk-JBLUPKY4.js.map +1 -0
  9. package/dist/{chunk-UJU5XERR.js → chunk-L2V7LDKD.js} +25 -4
  10. package/dist/chunk-L2V7LDKD.js.map +1 -0
  11. package/dist/{chunk-E6NPZOJL.js → chunk-RY5DVTLV.js} +29 -4
  12. package/dist/chunk-RY5DVTLV.js.map +1 -0
  13. package/dist/chunk-UPTCSWK3.js +60 -0
  14. package/dist/chunk-UPTCSWK3.js.map +1 -0
  15. package/dist/{chunk-X73VG645.js → chunk-XNNDGDPI.js} +64 -3
  16. package/dist/chunk-XNNDGDPI.js.map +1 -0
  17. package/dist/cli/index.js +423 -7
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/index.cjs +655 -22
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +7 -4
  22. package/dist/index.d.ts +7 -4
  23. package/dist/index.js +172 -11
  24. package/dist/index.js.map +1 -1
  25. package/dist/providers/anthropic.cjs +306 -10
  26. package/dist/providers/anthropic.cjs.map +1 -1
  27. package/dist/providers/anthropic.d.cts +2 -2
  28. package/dist/providers/anthropic.d.ts +2 -2
  29. package/dist/providers/anthropic.js +3 -3
  30. package/dist/providers/gemini.cjs +274 -6
  31. package/dist/providers/gemini.cjs.map +1 -1
  32. package/dist/providers/gemini.d.cts +2 -2
  33. package/dist/providers/gemini.d.ts +2 -2
  34. package/dist/providers/gemini.js +3 -3
  35. package/dist/providers/openai-responses.cjs +1245 -0
  36. package/dist/providers/openai-responses.cjs.map +1 -0
  37. package/dist/providers/openai-responses.d.cts +11 -0
  38. package/dist/providers/openai-responses.d.ts +11 -0
  39. package/dist/providers/openai-responses.js +9 -0
  40. package/dist/providers/openai-responses.js.map +1 -0
  41. package/dist/providers/openai.cjs +270 -6
  42. package/dist/providers/openai.cjs.map +1 -1
  43. package/dist/providers/openai.d.cts +2 -2
  44. package/dist/providers/openai.d.ts +2 -2
  45. package/dist/providers/openai.js +3 -3
  46. package/dist/providers/openrouter.cjs +305 -9
  47. package/dist/providers/openrouter.cjs.map +1 -1
  48. package/dist/providers/openrouter.d.cts +2 -2
  49. package/dist/providers/openrouter.d.ts +2 -2
  50. package/dist/providers/openrouter.js +4 -4
  51. package/dist/schema-B9A1zLRk.d.cts +2403 -0
  52. package/dist/schema-B9A1zLRk.d.ts +2403 -0
  53. package/dist/testing.cjs +264 -6
  54. package/dist/testing.cjs.map +1 -1
  55. package/dist/testing.d.cts +59 -2
  56. package/dist/testing.d.ts +59 -2
  57. package/dist/testing.js +70 -2
  58. package/dist/testing.js.map +1 -1
  59. package/dist/{types-fBvo_d4k.d.ts → types-DjGAwJxC.d.ts} +13 -1
  60. package/dist/{types-C6RG0Si0.d.cts → types-DpbzzZO2.d.cts} +13 -1
  61. package/dist/usagetap/index.d.cts +2 -2
  62. package/dist/usagetap/index.d.ts +2 -2
  63. package/package.json +12 -2
  64. package/dist/chunk-5OYWNRNC.js.map +0 -1
  65. package/dist/chunk-BBVVA27J.js +0 -92
  66. package/dist/chunk-BBVVA27J.js.map +0 -1
  67. package/dist/chunk-E2NXJLS6.js +0 -26
  68. package/dist/chunk-E2NXJLS6.js.map +0 -1
  69. package/dist/chunk-E6NPZOJL.js.map +0 -1
  70. package/dist/chunk-UJU5XERR.js.map +0 -1
  71. package/dist/chunk-X73VG645.js.map +0 -1
  72. package/dist/schema-DwzYbZba.d.cts +0 -859
  73. package/dist/schema-DwzYbZba.d.ts +0 -859
@@ -103,8 +103,53 @@ function mergeOverride(base, override) {
103
103
  if (override.response !== void 0) {
104
104
  result.response = { ...result.response, ...override.response };
105
105
  }
106
+ if (override.cache !== void 0) {
107
+ result.cache = {
108
+ ...result.cache,
109
+ ...override.cache,
110
+ openai: mergeRecordBlock(result.cache?.openai, override.cache.openai),
111
+ anthropic: mergeRecordBlock(result.cache?.anthropic, override.cache.anthropic),
112
+ gemini: mergeRecordBlock(result.cache?.gemini, override.cache.gemini),
113
+ google: mergeRecordBlock(result.cache?.google, override.cache.google)
114
+ };
115
+ }
116
+ if (override.raw !== void 0) {
117
+ result.raw = {
118
+ ...result.raw,
119
+ ...override.raw,
120
+ openai: mergeRecordBlock(result.raw?.openai, override.raw.openai),
121
+ "openai-responses": mergeRecordBlock(result.raw?.["openai-responses"], override.raw["openai-responses"]),
122
+ openai_responses: mergeRecordBlock(result.raw?.openai_responses, override.raw.openai_responses),
123
+ anthropic: mergeRecordBlock(result.raw?.anthropic, override.raw.anthropic),
124
+ gemini: mergeRecordBlock(result.raw?.gemini, override.raw.gemini),
125
+ google: mergeRecordBlock(result.raw?.google, override.raw.google),
126
+ openrouter: mergeRecordBlock(result.raw?.openrouter, override.raw.openrouter)
127
+ };
128
+ }
129
+ if (override.provider_options !== void 0) {
130
+ result.provider_options = {
131
+ ...result.provider_options,
132
+ ...override.provider_options,
133
+ anthropic: {
134
+ ...result.provider_options?.anthropic,
135
+ ...override.provider_options.anthropic
136
+ },
137
+ gemini: {
138
+ ...result.provider_options?.gemini,
139
+ ...override.provider_options.gemini
140
+ },
141
+ openrouter: {
142
+ ...result.provider_options?.openrouter,
143
+ ...override.provider_options.openrouter
144
+ }
145
+ };
146
+ }
106
147
  return result;
107
148
  }
149
+ function mergeRecordBlock(base, override) {
150
+ if (override === void 0) return base;
151
+ return { ...base, ...override };
152
+ }
108
153
 
109
154
  // src/providers/resolve-asset.ts
110
155
  function resolveAssetForProvider(asset, runtime = {}) {
@@ -205,7 +250,66 @@ var SamplingSchema = import_zod.z.object({
205
250
  });
206
251
  var ResponseSchema = import_zod.z.object({
207
252
  format: import_zod.z.enum(["text", "json", "markdown"]).optional(),
208
- stream: import_zod.z.boolean().optional()
253
+ stream: import_zod.z.boolean().optional(),
254
+ schema: import_zod.z.record(import_zod.z.unknown()).optional(),
255
+ schema_name: import_zod.z.string().optional(),
256
+ schema_description: import_zod.z.string().optional(),
257
+ schema_strict: import_zod.z.boolean().optional()
258
+ });
259
+ var AnthropicProviderOptionsSchema = import_zod.z.object({
260
+ top_k: import_zod.z.number().int().min(0).optional(),
261
+ tool_choice: import_zod.z.record(import_zod.z.unknown()).optional(),
262
+ output_config: import_zod.z.record(import_zod.z.unknown()).optional()
263
+ });
264
+ var GeminiProviderOptionsSchema = import_zod.z.object({
265
+ candidate_count: import_zod.z.number().int().positive().optional(),
266
+ top_k: import_zod.z.number().int().min(0).optional(),
267
+ seed: import_zod.z.number().int().optional(),
268
+ response_schema: import_zod.z.record(import_zod.z.unknown()).optional(),
269
+ response_json_schema: import_zod.z.record(import_zod.z.unknown()).optional(),
270
+ response_modalities: import_zod.z.array(import_zod.z.string()).optional(),
271
+ thinking_budget_tokens: import_zod.z.number().int().positive().optional()
272
+ });
273
+ var OpenRouterProviderOptionsSchema = import_zod.z.object({
274
+ provider: import_zod.z.record(import_zod.z.unknown()).optional(),
275
+ transforms: import_zod.z.array(import_zod.z.string()).optional(),
276
+ plugins: import_zod.z.array(import_zod.z.record(import_zod.z.unknown())).optional(),
277
+ models: import_zod.z.array(import_zod.z.string()).optional()
278
+ });
279
+ var ProviderOptionsSchema = import_zod.z.object({
280
+ anthropic: AnthropicProviderOptionsSchema.optional(),
281
+ gemini: GeminiProviderOptionsSchema.optional(),
282
+ openrouter: OpenRouterProviderOptionsSchema.optional()
283
+ });
284
+ var RawProviderBodySchema = import_zod.z.object({
285
+ openai: import_zod.z.record(import_zod.z.unknown()).optional(),
286
+ "openai-responses": import_zod.z.record(import_zod.z.unknown()).optional(),
287
+ openai_responses: import_zod.z.record(import_zod.z.unknown()).optional(),
288
+ anthropic: import_zod.z.record(import_zod.z.unknown()).optional(),
289
+ gemini: import_zod.z.record(import_zod.z.unknown()).optional(),
290
+ google: import_zod.z.record(import_zod.z.unknown()).optional(),
291
+ openrouter: import_zod.z.record(import_zod.z.unknown()).optional()
292
+ });
293
+ var OpenAICacheSchema = import_zod.z.object({
294
+ prompt_cache_key: import_zod.z.string().min(1).optional(),
295
+ retention: import_zod.z.enum(["in_memory", "24h"]).optional()
296
+ });
297
+ var AnthropicCacheSchema = import_zod.z.object({
298
+ mode: import_zod.z.enum(["automatic", "explicit"]).optional(),
299
+ type: import_zod.z.literal("ephemeral").optional(),
300
+ ttl: import_zod.z.enum(["5m", "1h"]).optional(),
301
+ cache_system_instructions: import_zod.z.boolean().optional(),
302
+ cache_tools: import_zod.z.boolean().optional(),
303
+ cache_prompt_template: import_zod.z.boolean().optional()
304
+ });
305
+ var GeminiCacheSchema = import_zod.z.object({
306
+ cached_content: import_zod.z.string().min(1).optional()
307
+ });
308
+ var CacheSchema = import_zod.z.object({
309
+ openai: OpenAICacheSchema.optional(),
310
+ anthropic: AnthropicCacheSchema.optional(),
311
+ gemini: GeminiCacheSchema.optional(),
312
+ google: GeminiCacheSchema.optional()
209
313
  });
210
314
  var HistorySchema = import_zod.z.object({
211
315
  max_items: import_zod.z.number().int().positive().optional()
@@ -256,7 +360,10 @@ var PromptAssetOverridesSchema = import_zod.z.object({
256
360
  reasoning: ReasoningSchema.optional(),
257
361
  sampling: SamplingSchema.optional(),
258
362
  response: ResponseSchema.optional(),
259
- tools: import_zod.z.array(ToolRefSchema).optional()
363
+ cache: CacheSchema.optional(),
364
+ raw: RawProviderBodySchema.optional(),
365
+ tools: import_zod.z.array(ToolRefSchema).optional(),
366
+ provider_options: ProviderOptionsSchema.optional()
260
367
  });
261
368
  var SourceSchema = import_zod.z.object({
262
369
  file_path: import_zod.z.string().optional(),
@@ -268,8 +375,9 @@ var SectionsSchema = import_zod.z.object({
268
375
  notes: import_zod.z.string().optional()
269
376
  });
270
377
  var PromptDefaultsSchema = import_zod.z.object({
271
- provider: import_zod.z.enum(["openai", "anthropic", "google", "gemini", "openrouter", "any"]).optional(),
378
+ provider: import_zod.z.enum(["openai", "openai-responses", "anthropic", "google", "gemini", "openrouter", "any"]).optional(),
272
379
  model: import_zod.z.string().optional(),
380
+ cache: CacheSchema.optional(),
273
381
  metadata: MetadataSchema.optional(),
274
382
  sections: import_zod.z.object({
275
383
  system_instructions: import_zod.z.string().optional()
@@ -279,13 +387,16 @@ var PromptAssetSchema = import_zod.z.object({
279
387
  id: import_zod.z.string(),
280
388
  schema_version: import_zod.z.number().int().positive().default(1),
281
389
  description: import_zod.z.string().optional(),
282
- provider: import_zod.z.enum(["openai", "anthropic", "google", "gemini", "openrouter", "any"]).optional(),
390
+ provider: import_zod.z.enum(["openai", "openai-responses", "anthropic", "google", "gemini", "openrouter", "any"]).optional(),
283
391
  model: import_zod.z.string().optional(),
284
392
  fallback_models: import_zod.z.array(import_zod.z.string()).optional(),
285
393
  reasoning: ReasoningSchema.optional(),
286
394
  sampling: SamplingSchema.optional(),
287
395
  response: ResponseSchema.optional(),
396
+ cache: CacheSchema.optional(),
397
+ raw: RawProviderBodySchema.optional(),
288
398
  tools: import_zod.z.array(ToolRefSchema).optional(),
399
+ provider_options: ProviderOptionsSchema.optional(),
289
400
  mcp: MCPSchema.optional(),
290
401
  context: ContextSchema.optional(),
291
402
  includes: import_zod.z.array(import_zod.z.string()).optional(),
@@ -297,6 +408,123 @@ var PromptAssetSchema = import_zod.z.object({
297
408
  source: SourceSchema.optional()
298
409
  });
299
410
 
411
+ // src/parser/frontmatter-guard.ts
412
+ var FRONT_MATTER_DELIMITER = /^---[ \t]*$/;
413
+ var REGEX_FIELD = /^(?<indent>\s*)(?<field>allow_regex|deny_regex)\s*:\s*(?<value>.*)$/;
414
+ var PATTERN_FIELD = /^(?<indent>\s*)pattern\s*:\s*(?<value>.*)$/;
415
+ var INLINE_PATTERN_FIELD = /(?:^|[{,]\s*)pattern\s*:\s*(?<value>"(?:\\.|[^"\\])*")/;
416
+ function assertRegexFrontMatterQuoting(content, filePath) {
417
+ const frontMatter = extractFrontMatter(content);
418
+ if (!frontMatter) {
419
+ return;
420
+ }
421
+ let pendingRegex;
422
+ for (const [index, line] of frontMatter.lines.entries()) {
423
+ const lineNumber = frontMatter.startLine + index;
424
+ const regexMatch = line.match(REGEX_FIELD);
425
+ if (regexMatch?.groups) {
426
+ const field = regexMatch.groups.field;
427
+ const indent2 = regexMatch.groups.indent.length;
428
+ const value = regexMatch.groups.value.trim();
429
+ pendingRegex = value === "" ? { field, indent: indent2 } : void 0;
430
+ assertNoUnescapedBackslashInDoubleQuotedRegex(value, field, filePath, lineNumber);
431
+ assertNoUnescapedBackslashInInlinePattern(value, field, filePath, lineNumber);
432
+ continue;
433
+ }
434
+ if (!pendingRegex) {
435
+ continue;
436
+ }
437
+ if (line.trim() === "" || line.trimStart().startsWith("#")) {
438
+ continue;
439
+ }
440
+ const indent = line.match(/^\s*/)?.[0].length ?? 0;
441
+ if (indent <= pendingRegex.indent) {
442
+ pendingRegex = void 0;
443
+ continue;
444
+ }
445
+ const patternMatch = line.match(PATTERN_FIELD);
446
+ if (!patternMatch?.groups) {
447
+ continue;
448
+ }
449
+ assertNoUnescapedBackslashInDoubleQuotedRegex(
450
+ patternMatch.groups.value.trim(),
451
+ `${pendingRegex.field}.pattern`,
452
+ filePath,
453
+ lineNumber
454
+ );
455
+ }
456
+ }
457
+ function assertNoUnescapedBackslashInInlinePattern(value, field, filePath, lineNumber) {
458
+ const match = value.match(INLINE_PATTERN_FIELD);
459
+ const pattern = match?.groups?.value;
460
+ if (!pattern) {
461
+ return;
462
+ }
463
+ assertNoUnescapedBackslashInDoubleQuotedRegex(pattern, `${field}.pattern`, filePath, lineNumber);
464
+ }
465
+ function extractFrontMatter(content) {
466
+ const lines = content.split(/\r?\n/);
467
+ if (!FRONT_MATTER_DELIMITER.test(lines[0] ?? "")) {
468
+ return void 0;
469
+ }
470
+ for (let index = 1; index < lines.length; index += 1) {
471
+ if (FRONT_MATTER_DELIMITER.test(lines[index] ?? "")) {
472
+ return {
473
+ lines: lines.slice(1, index),
474
+ startLine: 2
475
+ };
476
+ }
477
+ }
478
+ return void 0;
479
+ }
480
+ function assertNoUnescapedBackslashInDoubleQuotedRegex(value, field, filePath, lineNumber) {
481
+ if (!value.startsWith('"')) {
482
+ return;
483
+ }
484
+ const quoted = readDoubleQuotedScalar(value);
485
+ if (!quoted) {
486
+ return;
487
+ }
488
+ if (!hasUnescapedBackslash(quoted)) {
489
+ return;
490
+ }
491
+ const location = filePath ? `${filePath}:${lineNumber}` : `line ${lineNumber}`;
492
+ throw new Error(
493
+ `POK013: Invalid context regex YAML at ${location}, field "${field}": double-quoted regex strings treat backslashes as YAML escapes. Use unquoted /pattern/i literal form, single quotes, or double each backslash.`
494
+ );
495
+ }
496
+ function readDoubleQuotedScalar(value) {
497
+ let result = "";
498
+ for (let index = 1; index < value.length; index += 1) {
499
+ const char = value[index];
500
+ if (char === '"') {
501
+ return result;
502
+ }
503
+ result += char;
504
+ if (char === "\\" && index + 1 < value.length) {
505
+ index += 1;
506
+ result += value[index];
507
+ }
508
+ }
509
+ return void 0;
510
+ }
511
+ function hasUnescapedBackslash(value) {
512
+ for (let index = 0; index < value.length; index += 1) {
513
+ if (value[index] !== "\\") {
514
+ continue;
515
+ }
516
+ let count = 1;
517
+ while (value[index + count] === "\\") {
518
+ count += 1;
519
+ }
520
+ if (count % 2 === 1) {
521
+ return true;
522
+ }
523
+ index += count - 1;
524
+ }
525
+ return false;
526
+ }
527
+
300
528
  // src/parser/sections.ts
301
529
  var SECTION_MAP = {
302
530
  "system instructions": "system_instructions",
@@ -337,6 +565,7 @@ function extractSections(body) {
337
565
 
338
566
  // src/parser/parser.ts
339
567
  function parsePrompt(content, filePath) {
568
+ assertRegexFrontMatterQuoting(content, filePath);
340
569
  const { data: frontMatter, content: body } = (0, import_gray_matter.default)(content);
341
570
  const sections = extractSections(body);
342
571
  const raw = {
@@ -893,6 +1122,21 @@ function withPromptInputSupport(adapter) {
893
1122
  };
894
1123
  }
895
1124
 
1125
+ // src/providers/raw.ts
1126
+ function applyRawProviderBody(body, asset, provider) {
1127
+ const raw = getRawProviderBody(asset, provider);
1128
+ return raw ? { ...body, ...raw } : body;
1129
+ }
1130
+ function getRawProviderBody(asset, provider) {
1131
+ if (provider === "openai-responses") {
1132
+ return asset.raw?.["openai-responses"] ?? asset.raw?.openai_responses;
1133
+ }
1134
+ if (provider === "gemini") {
1135
+ return asset.raw?.gemini ?? asset.raw?.google;
1136
+ }
1137
+ return asset.raw?.[provider];
1138
+ }
1139
+
896
1140
  // src/providers/anthropic.ts
897
1141
  var anthropicAdapter = withPromptInputSupport({
898
1142
  name: "anthropic",
@@ -912,6 +1156,12 @@ var anthropicAdapter = withPromptInputSupport({
912
1156
  if (resolvedAsset.reasoning?.effort !== void 0) {
913
1157
  warnings.push("Anthropic uses budget_tokens for thinking, not effort. effort will be mapped approximately.");
914
1158
  }
1159
+ if (resolvedAsset.response?.schema !== void 0 && resolvedAsset.response?.format !== "json") {
1160
+ warnings.push("Anthropic response.schema is mapped to output_config.format and should usually be paired with response.format: json.");
1161
+ }
1162
+ if (resolvedAsset.provider_options?.anthropic?.top_k !== void 0 && resolvedAsset.provider_options.anthropic.top_k < 0) {
1163
+ errors.push("Anthropic provider_options.top_k must be >= 0.");
1164
+ }
915
1165
  return { valid: errors.length === 0, errors, warnings };
916
1166
  },
917
1167
  render(asset, runtime) {
@@ -921,20 +1171,38 @@ var anthropicAdapter = withPromptInputSupport({
921
1171
  strict: runtime.strict
922
1172
  });
923
1173
  const messages = [];
1174
+ const anthropicCacheConfig = resolvedAsset.cache?.anthropic;
1175
+ const cacheType = anthropicCacheConfig?.type ?? "ephemeral";
1176
+ const cacheControl = anthropicCacheConfig ? {
1177
+ type: cacheType,
1178
+ ...anthropicCacheConfig.ttl ? { ttl: anthropicCacheConfig.ttl } : {}
1179
+ } : void 0;
1180
+ const cacheMode = anthropicCacheConfig?.mode ?? "automatic";
924
1181
  if (runtime.history) {
925
1182
  for (const msg of runtime.history) {
926
1183
  messages.push({ role: msg.role, content: msg.content });
927
1184
  }
928
1185
  }
929
1186
  if (sections.prompt_template) {
930
- messages.push({ role: "user", content: sections.prompt_template });
1187
+ if (cacheControl && cacheMode === "explicit" && anthropicCacheConfig?.cache_prompt_template) {
1188
+ messages.push({
1189
+ role: "user",
1190
+ content: [{ type: "text", text: sections.prompt_template, cache_control: cacheControl }]
1191
+ });
1192
+ } else {
1193
+ messages.push({ role: "user", content: sections.prompt_template });
1194
+ }
931
1195
  }
932
1196
  const body = {
933
1197
  model: resolvedAsset.model,
934
1198
  messages
935
1199
  };
936
1200
  if (sections.system_instructions) {
937
- body.system = sections.system_instructions;
1201
+ if (cacheControl && cacheMode === "explicit" && anthropicCacheConfig?.cache_system_instructions !== false) {
1202
+ body.system = [{ type: "text", text: sections.system_instructions, cache_control: cacheControl }];
1203
+ } else {
1204
+ body.system = sections.system_instructions;
1205
+ }
938
1206
  }
939
1207
  if (resolvedAsset.sampling?.temperature !== void 0) body.temperature = resolvedAsset.sampling.temperature;
940
1208
  if (resolvedAsset.sampling?.top_p !== void 0) body.top_p = resolvedAsset.sampling.top_p;
@@ -950,25 +1218,53 @@ var anthropicAdapter = withPromptInputSupport({
950
1218
  budget_tokens: resolvedAsset.reasoning.budget_tokens
951
1219
  };
952
1220
  }
1221
+ if (resolvedAsset.provider_options?.anthropic?.top_k !== void 0) {
1222
+ body.top_k = resolvedAsset.provider_options.anthropic.top_k;
1223
+ }
1224
+ if (resolvedAsset.provider_options?.anthropic?.output_config !== void 0) {
1225
+ body.output_config = resolvedAsset.provider_options.anthropic.output_config;
1226
+ } else if (resolvedAsset.response?.schema !== void 0) {
1227
+ body.output_config = {
1228
+ format: {
1229
+ type: "json_schema",
1230
+ schema: resolvedAsset.response.schema
1231
+ }
1232
+ };
1233
+ }
953
1234
  if (resolvedAsset.response?.stream !== void 0) {
954
1235
  body.stream = resolvedAsset.response.stream;
955
1236
  }
1237
+ if (cacheControl && cacheMode === "automatic") {
1238
+ body.cache_control = cacheControl;
1239
+ }
956
1240
  if (resolvedAsset.tools && resolvedAsset.tools.length > 0) {
957
1241
  body.tools = resolvedAsset.tools.map((tool) => {
958
1242
  if (typeof tool === "string") {
959
1243
  const def = runtime.toolRegistry?.[tool];
960
- if (def) return def;
961
- return { name: tool };
1244
+ if (def) {
1245
+ if (cacheControl && cacheMode === "explicit" && anthropicCacheConfig?.cache_tools) {
1246
+ return { ...def, cache_control: cacheControl };
1247
+ }
1248
+ return def;
1249
+ }
1250
+ return {
1251
+ name: tool,
1252
+ ...cacheControl && cacheMode === "explicit" && anthropicCacheConfig?.cache_tools ? { cache_control: cacheControl } : {}
1253
+ };
962
1254
  }
963
1255
  return {
964
1256
  name: tool.name,
965
1257
  description: tool.description,
966
- input_schema: tool.input_schema ?? { type: "object", properties: {} }
1258
+ input_schema: tool.input_schema ?? { type: "object", properties: {} },
1259
+ ...cacheControl && cacheMode === "explicit" && anthropicCacheConfig?.cache_tools ? { cache_control: cacheControl } : {}
967
1260
  };
968
1261
  });
969
1262
  }
1263
+ if (resolvedAsset.provider_options?.anthropic?.tool_choice !== void 0) {
1264
+ body.tool_choice = resolvedAsset.provider_options.anthropic.tool_choice;
1265
+ }
970
1266
  return {
971
- body,
1267
+ body: applyRawProviderBody(body, resolvedAsset, "anthropic"),
972
1268
  provider: "anthropic",
973
1269
  model: resolvedAsset.model ?? "unknown"
974
1270
  };