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
package/README.md CHANGED
@@ -11,6 +11,31 @@ Your prompts are already in Git. PromptOpsKit makes them manageable. It replaces
11
11
 
12
12
  Provider adapters for OpenAI, Anthropic, Gemini, and OpenRouter produce a ready-to-send **request body only** — no HTTP client, no auth, no headers. Your application owns transport, so PromptOpsKit slots into any stack without opinions about how you call the API.
13
13
 
14
+ ## How is this different from GitHub Models?
15
+
16
+ GitHub Models is a great place to prototype prompts, compare models, and run evaluations inside GitHub.
17
+
18
+ PromptOpsKit is focused on the application runtime layer.
19
+
20
+ It helps you turn prompt behavior into repo-native assets that your application can load, validate, compose, compile, and render into provider-specific request bodies.
21
+
22
+ Use GitHub Models when you want:
23
+
24
+ - a GitHub-hosted prompt editor and playground
25
+ - side-by-side model comparisons
26
+ - structured evaluations inside GitHub
27
+ - `.prompt.yml` files for prompt experiments and evals
28
+
29
+ Use PromptOpsKit when you want:
30
+
31
+ - Markdown prompt assets with YAML metadata
32
+ - production input hardening and validation
33
+ - environment-specific model and parameter overrides
34
+ - reusable prompt composition
35
+ - compiled artifacts for deployment
36
+ - provider-specific request bodies for your own runtime code
37
+ - control over SDKs, auth, retries, routing, observability, and billing
38
+
14
39
  ### Why PromptOpsKit?
15
40
 
16
41
  - **Centralized, not scattered** — each prompt is a single Markdown file that captures prompt text, model config, tool bindings, and context rules together.
@@ -44,9 +69,12 @@ This creates:
44
69
  prompts/
45
70
  ├── defaults.md # Folder-level defaults (provider, model, metadata, system instructions)
46
71
  ├── hello.md # Sample prompt with variables
47
- ├── hello.test.yaml # Test sidecar with sample inputs
72
+ ├── hello.test.yaml # Test sidecar with sample inputs and hardcoded responses
48
73
  └── shared/
49
74
  └── tone.md # Shared system instructions (included via composition)
75
+
76
+ tests/
77
+ └── hello.prompt.test.mjs # Executable starter test for the hello prompt
50
78
  ```
51
79
 
52
80
  ### 2. Write a prompt
@@ -69,9 +97,7 @@ context:
69
97
  reject_secrets: true
70
98
  - name: app_context
71
99
  max_size: 2000
72
- allow_regex:
73
- pattern: "^[A-Za-z0-9 _-]+$"
74
- flags: "i"
100
+ allow_regex: /^[A-Za-z0-9 _-]+$/i
75
101
  includes:
76
102
  - ./shared/tone.md
77
103
  ---
@@ -135,9 +161,11 @@ Supported values for `warnings.contextSize` are `auto`, `off`, `result-only`, `c
135
161
  - **Composition** — `includes` to share system instructions across prompts, with circular detection
136
162
  - **Folder defaults** — `defaults.md` inheritance for shared provider, model, metadata, and system instructions
137
163
  - **Overrides** — Environment and tier-based overrides (base → env → tier → runtime)
138
- - **4 provider adapters** — OpenAI, Anthropic, Gemini, OpenRouter — body-only output
164
+ - **5 provider adapters** — OpenAI (Chat), OpenAI (Responses), Anthropic, Gemini, OpenRouter — body-only output
165
+ - **Provider-aware input caching controls** — optional `cache` front matter maps to OpenAI prompt cache hints, Anthropic `cache_control`, and Gemini `cachedContent`
166
+ - **Vendor escape hatch** — optional `raw.<provider>` blocks shallow-merge unmodeled request-body fields into the final provider payload
139
167
  - **Validation** — Zod schema validation, Levenshtein-based "did you mean?" for typos, variable usage checks
140
- - **Context hardening** — structured regexes with flags, `/pattern/i` convenience syntax, and built-in `non_empty` / `reject_secrets` validators
168
+ - **Context hardening** — copyable `/pattern/i` regex literals, structured regexes with `return_message`, and built-in `non_empty` / `reject_secrets` validators
141
169
  - **Optional short-circuit messages** — validators can return a structured `returnMessage` instead of throwing when configured
142
170
  - **Context size guardrails** — optional per-input `max_size` metadata with non-blocking render-time warnings
143
171
  - **Warning controls** — top-level config can suppress or emit context size warnings differently in dev and prod
@@ -193,6 +221,7 @@ Provider adapters are also available as direct imports:
193
221
 
194
222
  ```typescript
195
223
  import { openaiAdapter } from 'promptopskit/openai';
224
+ import { openaiResponsesAdapter } from 'promptopskit/openai-responses';
196
225
  import { anthropicAdapter } from 'promptopskit/anthropic';
197
226
  import { geminiAdapter } from 'promptopskit/gemini';
198
227
  import { openrouterAdapter } from 'promptopskit/openrouter';
@@ -223,6 +252,48 @@ const request = openaiAdapter.render(prompt, {
223
252
 
224
253
  In browser or client-side code, keep provider credentials on the server. Use the rendered request body with your own server endpoint, server action, or edge function rather than calling a provider directly from the client.
225
254
 
255
+ ### Provider-specific fields and raw passthrough
256
+
257
+ Use normalized fields first (`sampling`, `response`, `cache`, `tools`) so prompts stay portable. `response.schema` is the neutral JSON Schema path; adapters emit it as OpenAI/OpenRouter `response_format`, OpenAI Responses `text.format`, Anthropic `output_config.format`, and Gemini `generationConfig.responseJsonSchema`.
258
+
259
+ Use `provider_options` when PromptOpsKit has a known provider-specific mapping, such as Anthropic `top_k`, Gemini's native `response_schema`, or OpenRouter routing fields.
260
+
261
+ ```yaml
262
+ response:
263
+ format: json
264
+ schema_name: support_reply
265
+ schema_description: Structured support reply
266
+ schema:
267
+ type: object
268
+ properties:
269
+ answer:
270
+ type: string
271
+ provider_options:
272
+ openrouter:
273
+ provider:
274
+ order: ["anthropic", "openai"]
275
+ transforms: ["middle-out"]
276
+ ```
277
+
278
+ When a provider adds a body field PromptOpsKit does not model yet, use `raw`:
279
+
280
+ ```yaml
281
+ raw:
282
+ openai:
283
+ service_tier: flex
284
+ anthropic:
285
+ service_tier: auto
286
+ gemini:
287
+ safetySettings:
288
+ - category: HARM_CATEGORY_DANGEROUS_CONTENT
289
+ threshold: BLOCK_ONLY_HIGH
290
+ openrouter:
291
+ usage:
292
+ include: true
293
+ ```
294
+
295
+ Each adapter reads only its matching raw block and shallow-merges it into the generated request body after normalized mappings. This is intentionally an escape hatch; prefer first-class fields when they exist.
296
+
226
297
  On the server, adapters also provide async prompt-aware helpers so you can use the default `./prompts` and `./.generated-prompts/json` directories without creating a `PromptOpsKit` instance:
227
298
 
228
299
  ```typescript
@@ -472,11 +543,21 @@ Hello {{ name }}!`,
472
543
  ## Testing Helpers
473
544
 
474
545
  ```typescript
475
- import { createMockAsset, createMockResolvedAsset, parseTestPrompt } from 'promptopskit/testing';
546
+ import {
547
+ createHardcodedPromptResponder,
548
+ createMockAsset,
549
+ createMockResolvedAsset,
550
+ loadPromptTestSidecar,
551
+ parseTestPrompt,
552
+ } from 'promptopskit/testing';
476
553
 
477
554
  const asset = createMockAsset({ model: 'gpt-5.4' });
478
555
  const resolved = createMockResolvedAsset();
479
556
  const parsed = parseTestPrompt('---\nid: test\nschema_version: 1\n---\n\nHello');
557
+
558
+ const sidecar = await loadPromptTestSidecar('./prompts/hello.test.yaml');
559
+ const respond = createHardcodedPromptResponder(sidecar);
560
+ const response = respond('basic-greeting');
480
561
  ```
481
562
 
482
563
  ## API Reference
@@ -501,7 +582,7 @@ Renders a prompt for a specific provider. Returns `{ resolved, request?, returnM
501
582
  |--------|------|-------------|
502
583
  | `path` | `string` | Prompt path (no extension), e.g. `'support/reply'` |
503
584
  | `source` | `string` | Inline prompt source (alternative to path) |
504
- | `provider` | `string` | `'openai'`, `'anthropic'`, `'gemini'`, `'openrouter'` |
585
+ | `provider` | `string` | `'openai'`, `'openai-responses'`, `'anthropic'`, `'gemini'`, `'openrouter'` |
505
586
  | `variables` | `Record<string, string>` | Template variables |
506
587
  | `onContextOverflow` | `(info) => string` | Optional callback to transform oversized context values before rendering |
507
588
  | `environment` | `string` | Environment override name |
@@ -509,6 +590,7 @@ Renders a prompt for a specific provider. Returns `{ resolved, request?, returnM
509
590
  | `history` | `Array<{ role, content }>` | Conversation history |
510
591
  | `toolRegistry` | `Record<string, unknown>` | Tool definitions for resolving string tool references |
511
592
  | `strict` | `boolean` | Fail on missing variables |
593
+ | `openaiResponses` | `object` | Optional Responses API extras (`previous_response_id`, `conversation`, `instructions`, `parallel_tool_calls`, `max_tool_calls`, `store`, `metadata`, `include`, `background`) |
512
594
 
513
595
  ### `kit.loadPrompt(path)` / `kit.resolvePrompt(path, options)` / `kit.validatePrompt(path)`
514
596
 
@@ -528,13 +610,16 @@ Prompt files use YAML front matter with these fields:
528
610
  |-------|------|-------------|
529
611
  | `id` | `string` | Unique prompt identifier (required) |
530
612
  | `schema_version` | `number` | Schema version, currently `1` |
531
- | `provider` | `string` | `openai`, `anthropic`, `gemini` (or `google`), `openrouter`, `any` |
613
+ | `provider` | `string` | `openai`, `openai-responses`, `anthropic`, `gemini` (or `google`), `openrouter`, `any` |
532
614
  | `model` | `string` | Model name |
533
615
  | `fallback_models` | `string[]` | Fallback model list |
534
616
  | `reasoning` | `object` | `{ effort, budget_tokens }` |
535
617
  | `sampling` | `object` | `{ temperature, top_p, frequency_penalty, presence_penalty, stop, max_output_tokens }` |
536
- | `response` | `object` | `{ format, stream }` |
618
+ | `response` | `object` | `{ format, stream, schema, schema_name, schema_description, schema_strict }` |
619
+ | `cache` | `object` | Provider-specific cache controls (`openai`, `anthropic`, `gemini`/`google`) |
537
620
  | `tools` | `array` | Tool references (string names or inline definitions) |
621
+ | `provider_options` | `object` | Provider-specific non-portable options (`anthropic`, `gemini`, `openrouter`) |
622
+ | `raw` | `object` | Provider-scoped request-body passthrough (`openai`, `openai-responses`, `anthropic`, `gemini`/`google`, `openrouter`) |
538
623
  | `mcp` | `object` | MCP server references |
539
624
  | `context` | `object` | `{ inputs, history }` — declare expected variables, with optional per-input `max_size`, `trim`, structured or literal `allow_regex`/`deny_regex`, and built-in `non_empty` / `reject_secrets` validators |
540
625
  | `includes` | `string[]` | Paths to included prompt files |
@@ -542,6 +627,8 @@ Prompt files use YAML front matter with these fields:
542
627
  | `tiers` | `object` | Named tier overrides |
543
628
  | `metadata` | `object` | `{ owner, tags, review_required, stable }` |
544
629
 
630
+ For `allow_regex` and `deny_regex`, prefer unquoted `/pattern/i` literal form so regex escapes such as `\s` and `\b` stay copyable from tools like regex101. If you use structured `pattern:` form, use single-quoted YAML strings or double each backslash in double-quoted strings.
631
+
545
632
  ## Website
546
633
 
547
634
  The `website/` directory contains a standalone marketing website for PromptOpsKit.
package/SKILL.md CHANGED
@@ -8,7 +8,7 @@ description: Guidance for creating and editing promptopskit prompt files, defaul
8
8
  This project uses **promptopskit** to manage LLM prompts as code.
9
9
  Prompts live in markdown files with YAML front matter, are validated against
10
10
  a schema, and render into provider-specific request bodies (OpenAI, Anthropic,
11
- Gemini, OpenRouter). Follow these instructions when creating or editing prompts.
11
+ Gemini, OpenRouter, and OpenAI Responses). Follow these instructions when creating or editing prompts.
12
12
 
13
13
  ---
14
14
 
@@ -58,13 +58,16 @@ the fields required by that specific file:
58
58
  | `id` | string | **yes** | Unique identifier for the prompt |
59
59
  | `schema_version` | number | yes | Always `1` |
60
60
  | `description` | string | no | Human-readable description |
61
- | `provider` | enum | no | `openai`, `anthropic`, `google`, `gemini`, `openrouter`, or `any` |
61
+ | `provider` | enum | no | `openai`, `openai-responses`, `anthropic`, `google`, `gemini`, `openrouter`, or `any` |
62
62
  | `model` | string | no | Model identifier (e.g. `gpt-5.4`, `claude-sonnet-4-20250514`) |
63
63
  | `fallback_models` | string[] | no | Ordered fallback model list |
64
64
  | `reasoning` | object | no | `{ effort: low|medium|high, budget_tokens: number }` |
65
65
  | `sampling` | object | no | `{ temperature, top_p, frequency_penalty, presence_penalty, stop, max_output_tokens }` |
66
- | `response` | object | no | `{ format: text|json|markdown, stream: boolean }` |
66
+ | `response` | object | no | `{ format: text|json|markdown, stream: boolean, schema?: object, schema_name?: string, schema_description?: string, schema_strict?: boolean }` |
67
+ | `cache` | object | no | Provider-specific cache controls (`openai`, `anthropic`, `gemini`/`google`) |
67
68
  | `tools` | array | no | Tool names (strings) or inline definitions with `{ name, description, input_schema }` |
69
+ | `provider_options` | object | no | Provider-specific advanced options (`anthropic`, `gemini`, `openrouter`) |
70
+ | `raw` | object | no | Provider-scoped request-body passthrough for unmodeled vendor fields |
68
71
  | `mcp` | object | no | `{ servers: [string | { name, config }] }` |
69
72
  | `context.inputs` | `Array<string | { name, max_size?, trim?, allow_regex?, deny_regex?, non_empty?, reject_secrets? }>` | no | Declared variable names used in templates, with optional size budgets and runtime hardening controls |
70
73
  | `context.history` | object | no | `{ max_items: number }` |
@@ -102,7 +105,9 @@ Rules:
102
105
  - Use object-form inputs with `max_size` when a variable is likely to grow large and should trigger early warnings
103
106
  - Use `trim` to enforce byte budgets before interpolation when `max_size` is set
104
107
  - Use `allow_regex` for allowlist checks and `deny_regex` for blocklist checks on risky inputs
105
- - Prefer structured regexes like `{ pattern, flags }`; `/pattern/i` strings are also accepted and normalized internally
108
+ - Prefer unquoted `/pattern/i` literals for regex validators so backslash escapes such as `\s` and `\b` stay copyable from regex tools
109
+ - Use structured regexes like `{ pattern, flags, return_message }` when the validator needs a fallback message or separate flags
110
+ - In structured `pattern:` YAML, use single quotes for patterns with backslashes or double each backslash in double-quoted strings
106
111
  - Use `non_empty: true` for required user text and `reject_secrets: true` for common secret redaction checks
107
112
  - When the caller should receive a structured fallback message instead of an exception, use object form with `return_message` on `allow_regex`, `deny_regex`, `non_empty`, or `reject_secrets`
108
113
  - Escape literal braces with `\{{` and `\}}`
@@ -124,7 +129,7 @@ At render time, callers can also pass `onContextOverflow` to transform oversized
124
129
 
125
130
  If a validator declares `return_message`, `renderPrompt()` returns that message in a structured result and omits the provider request instead of throwing for that validation failure. Invalid regex definitions still fail during `validate` and `compile` as `POK013` prompt-authoring errors.
126
131
 
127
- Malformed `allow_regex` and `deny_regex` values fail during `validate` and `compile`, not just at render time. When regex compilation fails, the error includes the prompt id, variable name, field name, and raw configured value.
132
+ Malformed `allow_regex` and `deny_regex` values fail during `validate` and `compile`, not just at render time. When regex compilation fails, the error includes the prompt id, variable name, field name, and raw configured value. Double-quoted YAML regex strings with raw backslashes fail as `POK013`; use `/pattern/i`, single-quoted `pattern: '...'`, or doubled backslashes.
128
133
 
129
134
  Example: this is the minimal valid shape for a prompt that references
130
135
  `{{ pull_request }}` even when provider/model are inherited from defaults:
@@ -182,6 +187,7 @@ prompts/
182
187
  Supported default fields:
183
188
  - `provider` (front matter) — default provider for the folder
184
189
  - `model` (front matter) — default model for the folder
190
+ - `cache` (front matter) — default provider-specific cache hints
185
191
  - `metadata` (front matter) — merged with prompt-local metadata
186
192
  - `# System instructions` (body section) — used when the prompt has none
187
193
 
@@ -229,12 +235,69 @@ tiers:
229
235
  ```
230
236
 
231
237
  Overridable fields: `model`, `fallback_models`, `reasoning`, `sampling`,
232
- `response`, `tools`.
238
+ `response`, `cache`, `raw`, `tools`, `provider_options`.
233
239
 
234
240
  Override application order: **base → environment → tier → runtime**.
235
241
 
236
242
  ---
237
243
 
244
+ ## Provider-specific fields
245
+
246
+ Prefer portable fields first:
247
+
248
+ - Use `sampling` for common sampling controls
249
+ - Use `response.schema`, `response.schema_name`, `response.schema_description`, and `response.schema_strict` for structured output when possible
250
+ - Use `cache` for provider cache hints
251
+ - Use `tools` for tool definitions
252
+
253
+ Treat `response.schema` as the provider-neutral JSON Schema contract. The adapters emit it through provider-specific request fields: OpenAI/OpenRouter `response_format`, OpenAI Responses `text.format`, Anthropic `output_config.format`, and Gemini `generationConfig.responseJsonSchema`.
254
+
255
+ Use `provider_options` for known non-portable mappings:
256
+
257
+ ```yaml
258
+ provider_options:
259
+ anthropic:
260
+ top_k: 40
261
+ tool_choice:
262
+ type: auto
263
+ output_config:
264
+ format:
265
+ type: json_schema
266
+ schema:
267
+ type: object
268
+ gemini:
269
+ # Use only when Gemini's native schema dialect is required.
270
+ response_schema:
271
+ type: object
272
+ response_json_schema:
273
+ type: object
274
+ openrouter:
275
+ provider:
276
+ order: ["anthropic", "openai"]
277
+ transforms: ["middle-out"]
278
+ ```
279
+
280
+ Use `raw` only when a vendor request-body field is important and PromptOpsKit does not model it yet:
281
+
282
+ ```yaml
283
+ raw:
284
+ openai:
285
+ service_tier: flex
286
+ anthropic:
287
+ service_tier: auto
288
+ gemini:
289
+ safetySettings:
290
+ - category: HARM_CATEGORY_DANGEROUS_CONTENT
291
+ threshold: BLOCK_ONLY_HIGH
292
+ openrouter:
293
+ usage:
294
+ include: true
295
+ ```
296
+
297
+ Raw blocks are provider-scoped (`openai`, `openai-responses`/`openai_responses`, `anthropic`, `gemini`/`google`, `openrouter`) and are shallow-merged into the final request body after normalized fields. When adding `raw`, include a short note in `# Notes` explaining why a first-class field is not being used.
298
+
299
+ ---
300
+
238
301
  ## Test sidecars
239
302
 
240
303
  Create a `.test.yaml` file alongside a prompt to define test cases:
@@ -0,0 +1,113 @@
1
+ import {
2
+ applyRawProviderBody,
3
+ renderSections,
4
+ resolveAssetForProvider,
5
+ withPromptInputSupport
6
+ } from "./chunk-XNNDGDPI.js";
7
+
8
+ // src/providers/openai-responses.ts
9
+ var openaiResponsesAdapter = withPromptInputSupport({
10
+ name: "openai-responses",
11
+ validate(asset, runtime) {
12
+ const resolvedAsset = resolveAssetForProvider(asset, runtime);
13
+ const errors = [];
14
+ const warnings = [];
15
+ if (!resolvedAsset.model) {
16
+ errors.push("OpenAI Responses adapter requires a model to be specified.");
17
+ }
18
+ if (resolvedAsset.reasoning?.budget_tokens !== void 0) {
19
+ warnings.push("OpenAI Responses uses reasoning.effort, not budget_tokens. budget_tokens will be ignored.");
20
+ }
21
+ if (resolvedAsset.response?.schema !== void 0 && resolvedAsset.response?.format !== "json") {
22
+ warnings.push("OpenAI Responses response.schema requires response.format: json. schema will still be applied as JSON schema output.");
23
+ }
24
+ if (runtime?.openaiResponses?.conversation !== void 0 && runtime?.openaiResponses?.previous_response_id !== void 0) {
25
+ errors.push('OpenAI Responses options "conversation" and "previous_response_id" cannot both be set.');
26
+ }
27
+ return { valid: errors.length === 0, errors, warnings };
28
+ },
29
+ render(asset, runtime) {
30
+ const resolvedAsset = resolveAssetForProvider(asset, runtime);
31
+ const sections = renderSections(resolvedAsset, {
32
+ variables: runtime.variables,
33
+ strict: runtime.strict
34
+ });
35
+ const responseOptions = runtime.openaiResponses;
36
+ const input = [];
37
+ if (runtime.history) {
38
+ for (const msg of runtime.history) {
39
+ input.push({ role: msg.role, content: msg.content });
40
+ }
41
+ }
42
+ if (sections.prompt_template) {
43
+ input.push({ role: "user", content: sections.prompt_template });
44
+ }
45
+ const body = {
46
+ model: resolvedAsset.model,
47
+ input
48
+ };
49
+ if (responseOptions?.instructions !== void 0) {
50
+ body.instructions = responseOptions.instructions;
51
+ } else if (sections.system_instructions) {
52
+ body.instructions = sections.system_instructions;
53
+ }
54
+ if (resolvedAsset.sampling?.temperature !== void 0) body.temperature = resolvedAsset.sampling.temperature;
55
+ if (resolvedAsset.sampling?.top_p !== void 0) body.top_p = resolvedAsset.sampling.top_p;
56
+ if (resolvedAsset.sampling?.frequency_penalty !== void 0) body.frequency_penalty = resolvedAsset.sampling.frequency_penalty;
57
+ if (resolvedAsset.sampling?.presence_penalty !== void 0) body.presence_penalty = resolvedAsset.sampling.presence_penalty;
58
+ if (resolvedAsset.sampling?.stop !== void 0) body.stop = resolvedAsset.sampling.stop;
59
+ if (resolvedAsset.sampling?.max_output_tokens !== void 0) body.max_output_tokens = resolvedAsset.sampling.max_output_tokens;
60
+ if (resolvedAsset.reasoning?.effort) {
61
+ body.reasoning = { effort: resolvedAsset.reasoning.effort };
62
+ }
63
+ if (resolvedAsset.response?.schema) {
64
+ body.text = {
65
+ format: {
66
+ type: "json_schema",
67
+ name: resolvedAsset.response.schema_name ?? `${resolvedAsset.id}_response`,
68
+ ...resolvedAsset.response.schema_description ? { description: resolvedAsset.response.schema_description } : {},
69
+ schema: resolvedAsset.response.schema,
70
+ strict: resolvedAsset.response.schema_strict ?? true
71
+ }
72
+ };
73
+ } else if (resolvedAsset.response?.format === "json") {
74
+ body.text = { format: { type: "json_object" } };
75
+ }
76
+ if (resolvedAsset.response?.stream !== void 0) {
77
+ body.stream = resolvedAsset.response.stream;
78
+ }
79
+ if (resolvedAsset.tools && resolvedAsset.tools.length > 0) {
80
+ body.tools = resolvedAsset.tools.map((tool) => {
81
+ if (typeof tool === "string") {
82
+ const def = runtime.toolRegistry?.[tool];
83
+ if (def) return def;
84
+ return { type: "function", name: tool };
85
+ }
86
+ return {
87
+ type: "function",
88
+ name: tool.name,
89
+ description: tool.description,
90
+ parameters: tool.input_schema
91
+ };
92
+ });
93
+ }
94
+ if (responseOptions?.previous_response_id !== void 0) body.previous_response_id = responseOptions.previous_response_id;
95
+ if (responseOptions?.conversation !== void 0) body.conversation = responseOptions.conversation;
96
+ if (responseOptions?.parallel_tool_calls !== void 0) body.parallel_tool_calls = responseOptions.parallel_tool_calls;
97
+ if (responseOptions?.max_tool_calls !== void 0) body.max_tool_calls = responseOptions.max_tool_calls;
98
+ if (responseOptions?.store !== void 0) body.store = responseOptions.store;
99
+ if (responseOptions?.metadata !== void 0) body.metadata = responseOptions.metadata;
100
+ if (responseOptions?.include !== void 0) body.include = responseOptions.include;
101
+ if (responseOptions?.background !== void 0) body.background = responseOptions.background;
102
+ return {
103
+ body: applyRawProviderBody(body, resolvedAsset, "openai-responses"),
104
+ provider: "openai-responses",
105
+ model: resolvedAsset.model ?? "unknown"
106
+ };
107
+ }
108
+ });
109
+
110
+ export {
111
+ openaiResponsesAdapter
112
+ };
113
+ //# sourceMappingURL=chunk-F6UJ73Y6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/openai-responses.ts"],"sourcesContent":["import type { ResolvedPromptAsset } from '../schema/index.js';\nimport type {\n ProviderAdapter,\n ProviderRequest,\n ValidationResult,\n RuntimeRenderOptions,\n} from './types.js';\nimport { renderSections } from '../renderer/index.js';\nimport { resolveAssetForProvider } from './resolve-asset.js';\nimport { withPromptInputSupport } from './prompt-input.js';\nimport { applyRawProviderBody } from './raw.js';\n\n/**\n * OpenAI Responses provider adapter.\n * Produces request bodies compatible with the OpenAI Responses API.\n */\nexport const openaiResponsesAdapter: ProviderAdapter = withPromptInputSupport({\n name: 'openai-responses',\n\n validate(asset: ResolvedPromptAsset, runtime?: RuntimeRenderOptions): ValidationResult {\n const resolvedAsset = resolveAssetForProvider(asset, runtime);\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!resolvedAsset.model) {\n errors.push('OpenAI Responses adapter requires a model to be specified.');\n }\n\n if (resolvedAsset.reasoning?.budget_tokens !== undefined) {\n warnings.push('OpenAI Responses uses reasoning.effort, not budget_tokens. budget_tokens will be ignored.');\n }\n\n if (resolvedAsset.response?.schema !== undefined && resolvedAsset.response?.format !== 'json') {\n warnings.push('OpenAI Responses response.schema requires response.format: json. schema will still be applied as JSON schema output.');\n }\n\n if (runtime?.openaiResponses?.conversation !== undefined && runtime?.openaiResponses?.previous_response_id !== undefined) {\n errors.push('OpenAI Responses options \"conversation\" and \"previous_response_id\" cannot both be set.');\n }\n\n return { valid: errors.length === 0, errors, warnings };\n },\n\n render(asset: ResolvedPromptAsset, runtime: RuntimeRenderOptions): ProviderRequest {\n const resolvedAsset = resolveAssetForProvider(asset, runtime);\n const sections = renderSections(resolvedAsset, {\n variables: runtime.variables,\n strict: runtime.strict,\n });\n const responseOptions = runtime.openaiResponses;\n\n const input: Array<Record<string, unknown>> = [];\n\n if (runtime.history) {\n for (const msg of runtime.history) {\n input.push({ role: msg.role, content: msg.content });\n }\n }\n\n if (sections.prompt_template) {\n input.push({ role: 'user', content: sections.prompt_template });\n }\n\n const body: Record<string, unknown> = {\n model: resolvedAsset.model,\n input,\n };\n\n if (responseOptions?.instructions !== undefined) {\n body.instructions = responseOptions.instructions;\n } else if (sections.system_instructions) {\n body.instructions = sections.system_instructions;\n }\n\n // Sampling params\n if (resolvedAsset.sampling?.temperature !== undefined) body.temperature = resolvedAsset.sampling.temperature;\n if (resolvedAsset.sampling?.top_p !== undefined) body.top_p = resolvedAsset.sampling.top_p;\n if (resolvedAsset.sampling?.frequency_penalty !== undefined) body.frequency_penalty = resolvedAsset.sampling.frequency_penalty;\n if (resolvedAsset.sampling?.presence_penalty !== undefined) body.presence_penalty = resolvedAsset.sampling.presence_penalty;\n if (resolvedAsset.sampling?.stop !== undefined) body.stop = resolvedAsset.sampling.stop;\n if (resolvedAsset.sampling?.max_output_tokens !== undefined) body.max_output_tokens = resolvedAsset.sampling.max_output_tokens;\n\n // Reasoning\n if (resolvedAsset.reasoning?.effort) {\n body.reasoning = { effort: resolvedAsset.reasoning.effort };\n }\n\n // Structured output / response format\n if (resolvedAsset.response?.schema) {\n body.text = {\n format: {\n type: 'json_schema',\n name: resolvedAsset.response.schema_name ?? `${resolvedAsset.id}_response`,\n ...(resolvedAsset.response.schema_description ? { description: resolvedAsset.response.schema_description } : {}),\n schema: resolvedAsset.response.schema,\n strict: resolvedAsset.response.schema_strict ?? true,\n },\n };\n } else if (resolvedAsset.response?.format === 'json') {\n body.text = { format: { type: 'json_object' } };\n }\n\n // Streaming\n if (resolvedAsset.response?.stream !== undefined) {\n body.stream = resolvedAsset.response.stream;\n }\n\n // Tools\n if (resolvedAsset.tools && resolvedAsset.tools.length > 0) {\n body.tools = resolvedAsset.tools.map((tool) => {\n if (typeof tool === 'string') {\n const def = runtime.toolRegistry?.[tool];\n if (def) return def;\n return { type: 'function', name: tool };\n }\n return {\n type: 'function',\n name: tool.name,\n description: tool.description,\n parameters: tool.input_schema,\n };\n });\n }\n\n if (responseOptions?.previous_response_id !== undefined) body.previous_response_id = responseOptions.previous_response_id;\n if (responseOptions?.conversation !== undefined) body.conversation = responseOptions.conversation;\n if (responseOptions?.parallel_tool_calls !== undefined) body.parallel_tool_calls = responseOptions.parallel_tool_calls;\n if (responseOptions?.max_tool_calls !== undefined) body.max_tool_calls = responseOptions.max_tool_calls;\n if (responseOptions?.store !== undefined) body.store = responseOptions.store;\n if (responseOptions?.metadata !== undefined) body.metadata = responseOptions.metadata;\n if (responseOptions?.include !== undefined) body.include = responseOptions.include;\n if (responseOptions?.background !== undefined) body.background = responseOptions.background;\n\n return {\n body: applyRawProviderBody(body, resolvedAsset, 'openai-responses'),\n provider: 'openai-responses',\n model: resolvedAsset.model ?? 'unknown',\n };\n },\n});\n"],"mappings":"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","names":[]}
@@ -0,0 +1,145 @@
1
+ import {
2
+ applyRawProviderBody,
3
+ renderSections,
4
+ resolveAssetForProvider,
5
+ withPromptInputSupport
6
+ } from "./chunk-XNNDGDPI.js";
7
+
8
+ // src/providers/anthropic.ts
9
+ var anthropicAdapter = withPromptInputSupport({
10
+ name: "anthropic",
11
+ validate(asset, runtime) {
12
+ const resolvedAsset = resolveAssetForProvider(asset, runtime);
13
+ const errors = [];
14
+ const warnings = [];
15
+ if (!resolvedAsset.model) {
16
+ errors.push("Anthropic adapter requires a model to be specified.");
17
+ }
18
+ if (resolvedAsset.sampling?.frequency_penalty !== void 0) {
19
+ warnings.push("Anthropic does not support frequency_penalty. It will be ignored.");
20
+ }
21
+ if (resolvedAsset.sampling?.presence_penalty !== void 0) {
22
+ warnings.push("Anthropic does not support presence_penalty. It will be ignored.");
23
+ }
24
+ if (resolvedAsset.reasoning?.effort !== void 0) {
25
+ warnings.push("Anthropic uses budget_tokens for thinking, not effort. effort will be mapped approximately.");
26
+ }
27
+ if (resolvedAsset.response?.schema !== void 0 && resolvedAsset.response?.format !== "json") {
28
+ warnings.push("Anthropic response.schema is mapped to output_config.format and should usually be paired with response.format: json.");
29
+ }
30
+ if (resolvedAsset.provider_options?.anthropic?.top_k !== void 0 && resolvedAsset.provider_options.anthropic.top_k < 0) {
31
+ errors.push("Anthropic provider_options.top_k must be >= 0.");
32
+ }
33
+ return { valid: errors.length === 0, errors, warnings };
34
+ },
35
+ render(asset, runtime) {
36
+ const resolvedAsset = resolveAssetForProvider(asset, runtime);
37
+ const sections = renderSections(resolvedAsset, {
38
+ variables: runtime.variables,
39
+ strict: runtime.strict
40
+ });
41
+ const messages = [];
42
+ const anthropicCacheConfig = resolvedAsset.cache?.anthropic;
43
+ const cacheType = anthropicCacheConfig?.type ?? "ephemeral";
44
+ const cacheControl = anthropicCacheConfig ? {
45
+ type: cacheType,
46
+ ...anthropicCacheConfig.ttl ? { ttl: anthropicCacheConfig.ttl } : {}
47
+ } : void 0;
48
+ const cacheMode = anthropicCacheConfig?.mode ?? "automatic";
49
+ if (runtime.history) {
50
+ for (const msg of runtime.history) {
51
+ messages.push({ role: msg.role, content: msg.content });
52
+ }
53
+ }
54
+ if (sections.prompt_template) {
55
+ if (cacheControl && cacheMode === "explicit" && anthropicCacheConfig?.cache_prompt_template) {
56
+ messages.push({
57
+ role: "user",
58
+ content: [{ type: "text", text: sections.prompt_template, cache_control: cacheControl }]
59
+ });
60
+ } else {
61
+ messages.push({ role: "user", content: sections.prompt_template });
62
+ }
63
+ }
64
+ const body = {
65
+ model: resolvedAsset.model,
66
+ messages
67
+ };
68
+ if (sections.system_instructions) {
69
+ if (cacheControl && cacheMode === "explicit" && anthropicCacheConfig?.cache_system_instructions !== false) {
70
+ body.system = [{ type: "text", text: sections.system_instructions, cache_control: cacheControl }];
71
+ } else {
72
+ body.system = sections.system_instructions;
73
+ }
74
+ }
75
+ if (resolvedAsset.sampling?.temperature !== void 0) body.temperature = resolvedAsset.sampling.temperature;
76
+ if (resolvedAsset.sampling?.top_p !== void 0) body.top_p = resolvedAsset.sampling.top_p;
77
+ if (resolvedAsset.sampling?.stop !== void 0) body.stop_sequences = resolvedAsset.sampling.stop;
78
+ if (resolvedAsset.sampling?.max_output_tokens !== void 0) {
79
+ body.max_tokens = resolvedAsset.sampling.max_output_tokens;
80
+ } else {
81
+ body.max_tokens = 4096;
82
+ }
83
+ if (resolvedAsset.reasoning?.budget_tokens) {
84
+ body.thinking = {
85
+ type: "enabled",
86
+ budget_tokens: resolvedAsset.reasoning.budget_tokens
87
+ };
88
+ }
89
+ if (resolvedAsset.provider_options?.anthropic?.top_k !== void 0) {
90
+ body.top_k = resolvedAsset.provider_options.anthropic.top_k;
91
+ }
92
+ if (resolvedAsset.provider_options?.anthropic?.output_config !== void 0) {
93
+ body.output_config = resolvedAsset.provider_options.anthropic.output_config;
94
+ } else if (resolvedAsset.response?.schema !== void 0) {
95
+ body.output_config = {
96
+ format: {
97
+ type: "json_schema",
98
+ schema: resolvedAsset.response.schema
99
+ }
100
+ };
101
+ }
102
+ if (resolvedAsset.response?.stream !== void 0) {
103
+ body.stream = resolvedAsset.response.stream;
104
+ }
105
+ if (cacheControl && cacheMode === "automatic") {
106
+ body.cache_control = cacheControl;
107
+ }
108
+ if (resolvedAsset.tools && resolvedAsset.tools.length > 0) {
109
+ body.tools = resolvedAsset.tools.map((tool) => {
110
+ if (typeof tool === "string") {
111
+ const def = runtime.toolRegistry?.[tool];
112
+ if (def) {
113
+ if (cacheControl && cacheMode === "explicit" && anthropicCacheConfig?.cache_tools) {
114
+ return { ...def, cache_control: cacheControl };
115
+ }
116
+ return def;
117
+ }
118
+ return {
119
+ name: tool,
120
+ ...cacheControl && cacheMode === "explicit" && anthropicCacheConfig?.cache_tools ? { cache_control: cacheControl } : {}
121
+ };
122
+ }
123
+ return {
124
+ name: tool.name,
125
+ description: tool.description,
126
+ input_schema: tool.input_schema ?? { type: "object", properties: {} },
127
+ ...cacheControl && cacheMode === "explicit" && anthropicCacheConfig?.cache_tools ? { cache_control: cacheControl } : {}
128
+ };
129
+ });
130
+ }
131
+ if (resolvedAsset.provider_options?.anthropic?.tool_choice !== void 0) {
132
+ body.tool_choice = resolvedAsset.provider_options.anthropic.tool_choice;
133
+ }
134
+ return {
135
+ body: applyRawProviderBody(body, resolvedAsset, "anthropic"),
136
+ provider: "anthropic",
137
+ model: resolvedAsset.model ?? "unknown"
138
+ };
139
+ }
140
+ });
141
+
142
+ export {
143
+ anthropicAdapter
144
+ };
145
+ //# sourceMappingURL=chunk-HLNVKKMS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/anthropic.ts"],"sourcesContent":["import type { ResolvedPromptAsset } from '../schema/index.js';\nimport type {\n ProviderAdapter,\n ProviderRequest,\n ValidationResult,\n RuntimeRenderOptions,\n} from './types.js';\nimport { renderSections } from '../renderer/index.js';\nimport { resolveAssetForProvider } from './resolve-asset.js';\nimport { withPromptInputSupport } from './prompt-input.js';\nimport { applyRawProviderBody } from './raw.js';\n\n/**\n * Anthropic provider adapter.\n * Produces request bodies compatible with the Anthropic Messages API.\n */\nexport const anthropicAdapter: ProviderAdapter = withPromptInputSupport({\n name: 'anthropic',\n\n validate(asset: ResolvedPromptAsset, runtime?: RuntimeRenderOptions): ValidationResult {\n const resolvedAsset = resolveAssetForProvider(asset, runtime);\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!resolvedAsset.model) {\n errors.push('Anthropic adapter requires a model to be specified.');\n }\n\n if (resolvedAsset.sampling?.frequency_penalty !== undefined) {\n warnings.push('Anthropic does not support frequency_penalty. It will be ignored.');\n }\n if (resolvedAsset.sampling?.presence_penalty !== undefined) {\n warnings.push('Anthropic does not support presence_penalty. It will be ignored.');\n }\n if (resolvedAsset.reasoning?.effort !== undefined) {\n warnings.push('Anthropic uses budget_tokens for thinking, not effort. effort will be mapped approximately.');\n }\n if (resolvedAsset.response?.schema !== undefined && resolvedAsset.response?.format !== 'json') {\n warnings.push('Anthropic response.schema is mapped to output_config.format and should usually be paired with response.format: json.');\n }\n\n if (resolvedAsset.provider_options?.anthropic?.top_k !== undefined && resolvedAsset.provider_options.anthropic.top_k < 0) {\n errors.push('Anthropic provider_options.top_k must be >= 0.');\n }\n\n return { valid: errors.length === 0, errors, warnings };\n },\n\n render(asset: ResolvedPromptAsset, runtime: RuntimeRenderOptions): ProviderRequest {\n const resolvedAsset = resolveAssetForProvider(asset, runtime);\n const sections = renderSections(resolvedAsset, {\n variables: runtime.variables,\n strict: runtime.strict,\n });\n\n const messages: Array<Record<string, unknown>> = [];\n const anthropicCacheConfig = resolvedAsset.cache?.anthropic;\n const cacheType = anthropicCacheConfig?.type ?? 'ephemeral';\n const cacheControl = anthropicCacheConfig\n ? {\n type: cacheType,\n ...(anthropicCacheConfig.ttl ? { ttl: anthropicCacheConfig.ttl } : {}),\n }\n : undefined;\n const cacheMode = anthropicCacheConfig?.mode ?? 'automatic';\n\n // History\n if (runtime.history) {\n for (const msg of runtime.history) {\n messages.push({ role: msg.role, content: msg.content });\n }\n }\n\n // User message (prompt template)\n if (sections.prompt_template) {\n if (cacheControl && cacheMode === 'explicit' && anthropicCacheConfig?.cache_prompt_template) {\n messages.push({\n role: 'user',\n content: [{ type: 'text', text: sections.prompt_template, cache_control: cacheControl }],\n });\n } else {\n messages.push({ role: 'user', content: sections.prompt_template });\n }\n }\n\n const body: Record<string, unknown> = {\n model: resolvedAsset.model,\n messages,\n };\n\n // System goes as top-level field in Anthropic\n if (sections.system_instructions) {\n if (cacheControl && cacheMode === 'explicit' && anthropicCacheConfig?.cache_system_instructions !== false) {\n body.system = [{ type: 'text', text: sections.system_instructions, cache_control: cacheControl }];\n } else {\n body.system = sections.system_instructions;\n }\n }\n\n // Sampling params\n if (resolvedAsset.sampling?.temperature !== undefined) body.temperature = resolvedAsset.sampling.temperature;\n if (resolvedAsset.sampling?.top_p !== undefined) body.top_p = resolvedAsset.sampling.top_p;\n if (resolvedAsset.sampling?.stop !== undefined) body.stop_sequences = resolvedAsset.sampling.stop;\n if (resolvedAsset.sampling?.max_output_tokens !== undefined) {\n body.max_tokens = resolvedAsset.sampling.max_output_tokens;\n } else {\n // Anthropic requires max_tokens\n body.max_tokens = 4096;\n }\n\n // Thinking/reasoning\n if (resolvedAsset.reasoning?.budget_tokens) {\n body.thinking = {\n type: 'enabled',\n budget_tokens: resolvedAsset.reasoning.budget_tokens,\n };\n }\n\n // Provider-specific options\n if (resolvedAsset.provider_options?.anthropic?.top_k !== undefined) {\n body.top_k = resolvedAsset.provider_options.anthropic.top_k;\n }\n\n if (resolvedAsset.provider_options?.anthropic?.output_config !== undefined) {\n body.output_config = resolvedAsset.provider_options.anthropic.output_config;\n } else if (resolvedAsset.response?.schema !== undefined) {\n body.output_config = {\n format: {\n type: 'json_schema',\n schema: resolvedAsset.response.schema,\n },\n };\n }\n\n // Streaming\n if (resolvedAsset.response?.stream !== undefined) {\n body.stream = resolvedAsset.response.stream;\n }\n\n if (cacheControl && cacheMode === 'automatic') {\n body.cache_control = cacheControl;\n }\n\n // Tools\n if (resolvedAsset.tools && resolvedAsset.tools.length > 0) {\n body.tools = resolvedAsset.tools.map((tool) => {\n if (typeof tool === 'string') {\n const def = runtime.toolRegistry?.[tool];\n if (def) {\n if (cacheControl && cacheMode === 'explicit' && anthropicCacheConfig?.cache_tools) {\n return { ...(def as Record<string, unknown>), cache_control: cacheControl };\n }\n return def;\n }\n return {\n name: tool,\n ...(cacheControl && cacheMode === 'explicit' && anthropicCacheConfig?.cache_tools\n ? { cache_control: cacheControl }\n : {}),\n };\n }\n return {\n name: tool.name,\n description: tool.description,\n input_schema: tool.input_schema ?? { type: 'object', properties: {} },\n ...(cacheControl && cacheMode === 'explicit' && anthropicCacheConfig?.cache_tools\n ? { cache_control: cacheControl }\n : {}),\n };\n });\n }\n\n if (resolvedAsset.provider_options?.anthropic?.tool_choice !== undefined) {\n body.tool_choice = resolvedAsset.provider_options.anthropic.tool_choice;\n }\n\n return {\n body: applyRawProviderBody(body, resolvedAsset, 'anthropic'),\n provider: 'anthropic',\n model: resolvedAsset.model ?? 'unknown',\n };\n },\n});\n"],"mappings":"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","names":[]}