promptopskit 0.3.0 → 0.3.3

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 (58) hide show
  1. package/README.md +49 -0
  2. package/SKILL.md +134 -71
  3. package/dist/{chunk-VYVEVJC3.js → chunk-R5PKK6Y7.js} +28 -24
  4. package/dist/chunk-R5PKK6Y7.js.map +1 -0
  5. package/dist/chunk-S5YHGHK5.js +311 -0
  6. package/dist/chunk-S5YHGHK5.js.map +1 -0
  7. package/dist/{chunk-PU3UPUND.js → chunk-U7IDX2P7.js} +9 -6
  8. package/dist/chunk-U7IDX2P7.js.map +1 -0
  9. package/dist/{chunk-5BI5FP5L.js → chunk-UJA7XBQZ.js} +24 -20
  10. package/dist/chunk-UJA7XBQZ.js.map +1 -0
  11. package/dist/chunk-VU3WKLFI.js +87 -0
  12. package/dist/chunk-VU3WKLFI.js.map +1 -0
  13. package/dist/cli/index.js +44 -20
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/index.cjs +325 -245
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +7 -4
  18. package/dist/index.d.ts +7 -4
  19. package/dist/index.js +29 -195
  20. package/dist/index.js.map +1 -1
  21. package/dist/providers/anthropic.cjs +534 -21
  22. package/dist/providers/anthropic.cjs.map +1 -1
  23. package/dist/providers/anthropic.d.cts +2 -2
  24. package/dist/providers/anthropic.d.ts +2 -2
  25. package/dist/providers/anthropic.js +3 -2
  26. package/dist/providers/gemini.cjs +530 -17
  27. package/dist/providers/gemini.cjs.map +1 -1
  28. package/dist/providers/gemini.d.cts +2 -2
  29. package/dist/providers/gemini.d.ts +2 -2
  30. package/dist/providers/gemini.js +3 -2
  31. package/dist/providers/openai.cjs +535 -22
  32. package/dist/providers/openai.cjs.map +1 -1
  33. package/dist/providers/openai.d.cts +2 -2
  34. package/dist/providers/openai.d.ts +2 -2
  35. package/dist/providers/openai.js +3 -2
  36. package/dist/providers/openrouter.cjs +539 -26
  37. package/dist/providers/openrouter.cjs.map +1 -1
  38. package/dist/providers/openrouter.d.cts +2 -2
  39. package/dist/providers/openrouter.d.ts +2 -2
  40. package/dist/providers/openrouter.js +4 -3
  41. package/dist/testing.d.cts +1 -1
  42. package/dist/testing.d.ts +1 -1
  43. package/dist/types-CgA7_wNI.d.cts +68 -0
  44. package/dist/types-D_-336jx.d.ts +68 -0
  45. package/dist/usagetap/index.d.cts +2 -2
  46. package/dist/usagetap/index.d.ts +2 -2
  47. package/package.json +1 -1
  48. package/dist/chunk-5BI5FP5L.js.map +0 -1
  49. package/dist/chunk-6KGBPHSY.js +0 -56
  50. package/dist/chunk-6KGBPHSY.js.map +0 -1
  51. package/dist/chunk-PU3UPUND.js.map +0 -1
  52. package/dist/chunk-UYTUGV7Z.js +0 -83
  53. package/dist/chunk-UYTUGV7Z.js.map +0 -1
  54. package/dist/chunk-VYVEVJC3.js.map +0 -1
  55. package/dist/types-1zDDD-Ij.d.cts +0 -40
  56. package/dist/types-CQhlfAnR.d.ts +0 -40
  57. package/dist/{schema-DIOA4OiO.d.cts → schema-Dq0jKest.d.cts} +42 -42
  58. package/dist/{schema-DIOA4OiO.d.ts → schema-Dq0jKest.d.ts} +42 -42
package/dist/index.cjs CHANGED
@@ -64,10 +64,156 @@ __export(src_exports, {
64
64
  withUsageTapCall: () => withUsageTapCall
65
65
  });
66
66
  module.exports = __toCommonJS(src_exports);
67
+ var import_node_path4 = require("path");
68
+
69
+ // src/renderer/interpolate.ts
70
+ var VARIABLE_RE = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
71
+ var ESCAPED_OPEN = /\\\{\\\{/g;
72
+ var ESCAPE_PLACEHOLDER = "\0ESCAPED_OPEN\0";
73
+ function interpolate(template, variables, options = {}) {
74
+ const { strict = false } = options;
75
+ let result = template.replace(ESCAPED_OPEN, ESCAPE_PLACEHOLDER);
76
+ result = result.replace(VARIABLE_RE, (match, name) => {
77
+ if (name in variables) {
78
+ return variables[name];
79
+ }
80
+ if (strict) {
81
+ throw new Error(`Missing required variable: "${name}"`);
82
+ }
83
+ return match;
84
+ });
85
+ result = result.replaceAll(ESCAPE_PLACEHOLDER, "{{");
86
+ return result;
87
+ }
88
+ function extractVariables(template) {
89
+ const vars = /* @__PURE__ */ new Set();
90
+ let match;
91
+ const re = new RegExp(VARIABLE_RE.source, "g");
92
+ while ((match = re.exec(template)) !== null) {
93
+ vars.add(match[1]);
94
+ }
95
+ return [...vars];
96
+ }
97
+
98
+ // src/renderer/renderer.ts
99
+ function renderSections(asset, options = {}) {
100
+ const { variables = {}, strict = false } = options;
101
+ const result = {};
102
+ if (asset.sections.system_instructions) {
103
+ result.system_instructions = interpolate(
104
+ asset.sections.system_instructions,
105
+ variables,
106
+ { strict }
107
+ );
108
+ }
109
+ if (asset.sections.prompt_template) {
110
+ result.prompt_template = interpolate(
111
+ asset.sections.prompt_template,
112
+ variables,
113
+ { strict }
114
+ );
115
+ }
116
+ return result;
117
+ }
118
+
119
+ // src/overrides/apply-overrides.ts
120
+ function applyOverrides(asset, options = {}) {
121
+ let result = { ...asset };
122
+ if (options.environment && result.environments?.[options.environment]) {
123
+ result = mergeOverride(result, result.environments[options.environment]);
124
+ }
125
+ if (options.tier && result.tiers?.[options.tier]) {
126
+ result = mergeOverride(result, result.tiers[options.tier]);
127
+ }
128
+ if (options.runtime) {
129
+ result = mergeOverride(result, options.runtime);
130
+ }
131
+ return result;
132
+ }
133
+ function mergeOverride(base, override) {
134
+ const result = { ...base };
135
+ if (override.model !== void 0) result.model = override.model;
136
+ if (override.fallback_models !== void 0) result.fallback_models = override.fallback_models;
137
+ if (override.tools !== void 0) result.tools = override.tools;
138
+ if (override.reasoning !== void 0) {
139
+ result.reasoning = { ...result.reasoning, ...override.reasoning };
140
+ }
141
+ if (override.sampling !== void 0) {
142
+ result.sampling = { ...result.sampling, ...override.sampling };
143
+ }
144
+ if (override.response !== void 0) {
145
+ result.response = { ...result.response, ...override.response };
146
+ }
147
+ return result;
148
+ }
149
+
150
+ // src/providers/resolve-asset.ts
151
+ function resolveAssetForProvider(asset, runtime = {}) {
152
+ if (!runtime.environment && !runtime.tier && !runtime.runtime) {
153
+ return asset;
154
+ }
155
+ return applyOverrides(asset, {
156
+ environment: runtime.environment,
157
+ tier: runtime.tier,
158
+ runtime: runtime.runtime
159
+ });
160
+ }
161
+
162
+ // src/prompt-resolution.ts
67
163
  var import_promises3 = require("fs/promises");
68
164
  var import_node_fs2 = require("fs");
69
165
  var import_node_path3 = require("path");
70
166
 
167
+ // src/cache.ts
168
+ var import_node_fs = require("fs");
169
+ var PromptCache = class {
170
+ cache = /* @__PURE__ */ new Map();
171
+ maxSize;
172
+ constructor(maxSize = 100) {
173
+ this.maxSize = maxSize;
174
+ }
175
+ get(filePath) {
176
+ const entry = this.cache.get(filePath);
177
+ if (!entry) return void 0;
178
+ try {
179
+ const stat = (0, import_node_fs.statSync)(filePath);
180
+ if (stat.mtimeMs !== entry.mtime) {
181
+ this.cache.delete(filePath);
182
+ return void 0;
183
+ }
184
+ } catch {
185
+ this.cache.delete(filePath);
186
+ return void 0;
187
+ }
188
+ this.cache.delete(filePath);
189
+ this.cache.set(filePath, entry);
190
+ return entry.value;
191
+ }
192
+ set(filePath, value) {
193
+ try {
194
+ const stat = (0, import_node_fs.statSync)(filePath);
195
+ if (this.cache.has(filePath)) {
196
+ this.cache.delete(filePath);
197
+ } else if (this.cache.size >= this.maxSize) {
198
+ const oldest = this.cache.keys().next().value;
199
+ if (oldest) this.cache.delete(oldest);
200
+ }
201
+ this.cache.set(filePath, { value, mtime: stat.mtimeMs });
202
+ } catch {
203
+ }
204
+ }
205
+ clear() {
206
+ this.cache.clear();
207
+ }
208
+ get size() {
209
+ return this.cache.size;
210
+ }
211
+ };
212
+
213
+ // src/composition/resolve-includes.ts
214
+ var import_promises2 = require("fs/promises");
215
+ var import_node_path2 = require("path");
216
+
71
217
  // src/parser/parser.ts
72
218
  var import_gray_matter = __toESM(require("gray-matter"), 1);
73
219
 
@@ -324,8 +470,6 @@ function applyDefaults(asset, defaults) {
324
470
  }
325
471
 
326
472
  // src/composition/resolve-includes.ts
327
- var import_promises2 = require("fs/promises");
328
- var import_node_path2 = require("path");
329
473
  async function resolveIncludes(asset, basePath, visited = /* @__PURE__ */ new Set()) {
330
474
  if (!asset.includes || asset.includes.length === 0) {
331
475
  return asset;
@@ -362,103 +506,135 @@ async function resolveIncludes(asset, basePath, visited = /* @__PURE__ */ new Se
362
506
  };
363
507
  }
364
508
 
365
- // src/overrides/apply-overrides.ts
366
- function applyOverrides(asset, options = {}) {
367
- let result = { ...asset };
368
- if (options.environment && result.environments?.[options.environment]) {
369
- result = mergeOverride(result, result.environments[options.environment]);
370
- }
371
- if (options.tier && result.tiers?.[options.tier]) {
372
- result = mergeOverride(result, result.tiers[options.tier]);
373
- }
374
- if (options.runtime) {
375
- result = mergeOverride(result, options.runtime);
376
- }
377
- return result;
378
- }
379
- function mergeOverride(base, override) {
380
- const result = { ...base };
381
- if (override.model !== void 0) result.model = override.model;
382
- if (override.fallback_models !== void 0) result.fallback_models = override.fallback_models;
383
- if (override.tools !== void 0) result.tools = override.tools;
384
- if (override.reasoning !== void 0) {
385
- result.reasoning = { ...result.reasoning, ...override.reasoning };
386
- }
387
- if (override.sampling !== void 0) {
388
- result.sampling = { ...result.sampling, ...override.sampling };
389
- }
390
- if (override.response !== void 0) {
391
- result.response = { ...result.response, ...override.response };
509
+ // src/prompt-resolution.ts
510
+ var sharedPromptCache = new PromptCache();
511
+ async function loadPromptAsset(promptPath, config, promptCache = sharedPromptCache) {
512
+ const mode = config.mode ?? "auto";
513
+ if (mode !== "source-only" && config.compiledDir) {
514
+ const compiledFile = (0, import_node_path3.resolve)(config.compiledDir, promptPath + ".json");
515
+ if ((0, import_node_fs2.existsSync)(compiledFile)) {
516
+ if (mode === "auto") {
517
+ const sourceFile = (0, import_node_path3.resolve)(config.sourceDir, promptPath + ".md");
518
+ if ((0, import_node_fs2.existsSync)(sourceFile)) {
519
+ const compiledMtime = (0, import_node_fs2.statSync)(compiledFile).mtimeMs;
520
+ const sourceMtime = (0, import_node_fs2.statSync)(sourceFile).mtimeMs;
521
+ if (sourceMtime > compiledMtime) {
522
+ console.warn(
523
+ `[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
524
+ Run "promptopskit compile" or switch to source-only mode.`
525
+ );
526
+ }
527
+ }
528
+ }
529
+ const content = await (0, import_promises3.readFile)(compiledFile, "utf-8");
530
+ return JSON.parse(content);
531
+ }
532
+ if (mode === "compiled-only") {
533
+ throw new Error(
534
+ `Compiled artifact not found: ${compiledFile}
535
+ Run "promptopskit compile" to generate it.`
536
+ );
537
+ }
392
538
  }
393
- return result;
394
- }
395
-
396
- // src/renderer/interpolate.ts
397
- var VARIABLE_RE = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
398
- var ESCAPED_OPEN = /\\\{\\\{/g;
399
- var ESCAPE_PLACEHOLDER = "\0ESCAPED_OPEN\0";
400
- function interpolate(template, variables, options = {}) {
401
- const { strict = false } = options;
402
- let result = template.replace(ESCAPED_OPEN, ESCAPE_PLACEHOLDER);
403
- result = result.replace(VARIABLE_RE, (match, name) => {
404
- if (name in variables) {
405
- return variables[name];
539
+ if (mode !== "compiled-only") {
540
+ const sourceFile = (0, import_node_path3.resolve)(config.sourceDir, promptPath + ".md");
541
+ if (config.cache !== false) {
542
+ const cached = promptCache.get(sourceFile);
543
+ if (cached) {
544
+ return cached;
545
+ }
406
546
  }
407
- if (strict) {
408
- throw new Error(`Missing required variable: "${name}"`);
547
+ if (!(0, import_node_fs2.existsSync)(sourceFile)) {
548
+ const paths = [sourceFile];
549
+ if (config.compiledDir) {
550
+ paths.unshift((0, import_node_path3.resolve)(config.compiledDir, promptPath + ".json"));
551
+ }
552
+ throw new Error(
553
+ `Prompt not found: "${promptPath}"
554
+ Searched:
555
+ ${paths.map((candidate) => ` - ${candidate}`).join("\n")}`
556
+ );
409
557
  }
410
- return match;
558
+ const { asset } = await loadPromptFile(sourceFile, { defaultsRoot: config.sourceDir });
559
+ if (config.cache !== false) {
560
+ promptCache.set(sourceFile, asset);
561
+ }
562
+ return asset;
563
+ }
564
+ throw new Error(`Prompt not found: "${promptPath}"`);
565
+ }
566
+ async function resolvePromptAsset(promptPath, config, options = {}, promptCache = sharedPromptCache) {
567
+ let asset = await loadPromptAsset(promptPath, config, promptCache);
568
+ const sourceFile = (0, import_node_path3.resolve)(config.sourceDir, promptPath + ".md");
569
+ if (asset.includes && asset.includes.length > 0 && (0, import_node_fs2.existsSync)(sourceFile)) {
570
+ asset = await resolveIncludes(asset, sourceFile);
571
+ }
572
+ asset = applyOverrides(asset, {
573
+ environment: options.environment,
574
+ tier: options.tier,
575
+ runtime: options.runtime
411
576
  });
412
- result = result.replaceAll(ESCAPE_PLACEHOLDER, "{{");
413
- return result;
577
+ return asset;
414
578
  }
415
- function extractVariables(template) {
416
- const vars = /* @__PURE__ */ new Set();
417
- let match;
418
- const re = new RegExp(VARIABLE_RE.source, "g");
419
- while ((match = re.exec(template)) !== null) {
420
- vars.add(match[1]);
421
- }
422
- return [...vars];
579
+ function resolveInlinePromptSource(source, options = {}) {
580
+ const { asset } = parsePrompt(source);
581
+ return applyOverrides(asset, {
582
+ environment: options.environment,
583
+ tier: options.tier,
584
+ runtime: options.runtime
585
+ });
423
586
  }
424
587
 
425
- // src/renderer/renderer.ts
426
- function renderSections(asset, options = {}) {
427
- const { variables = {}, strict = false } = options;
428
- const result = {};
429
- if (asset.sections.system_instructions) {
430
- result.system_instructions = interpolate(
431
- asset.sections.system_instructions,
432
- variables,
433
- { strict }
434
- );
588
+ // src/providers/prompt-input.ts
589
+ function isPromptLookup(input) {
590
+ return "path" in input && typeof input.path === "string" && "sourceDir" in input;
591
+ }
592
+ function isInlinePromptSource(input) {
593
+ return "source" in input && typeof input.source === "string";
594
+ }
595
+ async function resolveProviderPromptInput(input, runtime) {
596
+ if (isPromptLookup(input)) {
597
+ return resolvePromptAsset(input.path, input, runtime);
435
598
  }
436
- if (asset.sections.prompt_template) {
437
- result.prompt_template = interpolate(
438
- asset.sections.prompt_template,
439
- variables,
440
- { strict }
441
- );
599
+ if (isInlinePromptSource(input)) {
600
+ return resolveInlinePromptSource(input.source, runtime);
442
601
  }
443
- return result;
602
+ return input;
603
+ }
604
+ function withPromptInputSupport(adapter) {
605
+ const validatePrompt = async (input, runtime) => {
606
+ const resolved = await resolveProviderPromptInput(input, runtime);
607
+ return adapter.validate(resolved, runtime);
608
+ };
609
+ const renderPrompt2 = async (input, runtime) => {
610
+ const resolved = await resolveProviderPromptInput(input, runtime);
611
+ return adapter.render(resolved, runtime);
612
+ };
613
+ return {
614
+ ...adapter,
615
+ validatePrompt,
616
+ renderPrompt: renderPrompt2
617
+ };
444
618
  }
445
619
 
446
620
  // src/providers/openai.ts
447
- var openaiAdapter = {
621
+ var openaiAdapter = withPromptInputSupport({
448
622
  name: "openai",
449
- validate(asset) {
623
+ validate(asset, runtime) {
624
+ const resolvedAsset = resolveAssetForProvider(asset, runtime);
450
625
  const errors = [];
451
626
  const warnings = [];
452
- if (!asset.model) {
627
+ if (!resolvedAsset.model) {
453
628
  errors.push("OpenAI adapter requires a model to be specified.");
454
629
  }
455
- if (asset.reasoning?.budget_tokens !== void 0) {
630
+ if (resolvedAsset.reasoning?.budget_tokens !== void 0) {
456
631
  warnings.push("OpenAI uses reasoning_effort, not budget_tokens. budget_tokens will be ignored.");
457
632
  }
458
633
  return { valid: errors.length === 0, errors, warnings };
459
634
  },
460
635
  render(asset, runtime) {
461
- const sections = renderSections(asset, {
636
+ const resolvedAsset = resolveAssetForProvider(asset, runtime);
637
+ const sections = renderSections(resolvedAsset, {
462
638
  variables: runtime.variables,
463
639
  strict: runtime.strict
464
640
  });
@@ -475,26 +651,26 @@ var openaiAdapter = {
475
651
  messages.push({ role: "user", content: sections.prompt_template });
476
652
  }
477
653
  const body = {
478
- model: asset.model,
654
+ model: resolvedAsset.model,
479
655
  messages
480
656
  };
481
- if (asset.sampling?.temperature !== void 0) body.temperature = asset.sampling.temperature;
482
- if (asset.sampling?.top_p !== void 0) body.top_p = asset.sampling.top_p;
483
- if (asset.sampling?.frequency_penalty !== void 0) body.frequency_penalty = asset.sampling.frequency_penalty;
484
- if (asset.sampling?.presence_penalty !== void 0) body.presence_penalty = asset.sampling.presence_penalty;
485
- if (asset.sampling?.stop !== void 0) body.stop = asset.sampling.stop;
486
- if (asset.sampling?.max_output_tokens !== void 0) body.max_tokens = asset.sampling.max_output_tokens;
487
- if (asset.reasoning?.effort) {
488
- body.reasoning_effort = asset.reasoning.effort;
489
- }
490
- if (asset.response?.format === "json") {
657
+ if (resolvedAsset.sampling?.temperature !== void 0) body.temperature = resolvedAsset.sampling.temperature;
658
+ if (resolvedAsset.sampling?.top_p !== void 0) body.top_p = resolvedAsset.sampling.top_p;
659
+ if (resolvedAsset.sampling?.frequency_penalty !== void 0) body.frequency_penalty = resolvedAsset.sampling.frequency_penalty;
660
+ if (resolvedAsset.sampling?.presence_penalty !== void 0) body.presence_penalty = resolvedAsset.sampling.presence_penalty;
661
+ if (resolvedAsset.sampling?.stop !== void 0) body.stop = resolvedAsset.sampling.stop;
662
+ if (resolvedAsset.sampling?.max_output_tokens !== void 0) body.max_tokens = resolvedAsset.sampling.max_output_tokens;
663
+ if (resolvedAsset.reasoning?.effort) {
664
+ body.reasoning_effort = resolvedAsset.reasoning.effort;
665
+ }
666
+ if (resolvedAsset.response?.format === "json") {
491
667
  body.response_format = { type: "json_object" };
492
668
  }
493
- if (asset.response?.stream !== void 0) {
494
- body.stream = asset.response.stream;
669
+ if (resolvedAsset.response?.stream !== void 0) {
670
+ body.stream = resolvedAsset.response.stream;
495
671
  }
496
- if (asset.tools && asset.tools.length > 0) {
497
- body.tools = asset.tools.map((tool) => {
672
+ if (resolvedAsset.tools && resolvedAsset.tools.length > 0) {
673
+ body.tools = resolvedAsset.tools.map((tool) => {
498
674
  if (typeof tool === "string") {
499
675
  const def = runtime.toolRegistry?.[tool];
500
676
  if (def) return def;
@@ -513,33 +689,35 @@ var openaiAdapter = {
513
689
  return {
514
690
  body,
515
691
  provider: "openai",
516
- model: asset.model ?? "unknown"
692
+ model: resolvedAsset.model ?? "unknown"
517
693
  };
518
694
  }
519
- };
695
+ });
520
696
 
521
697
  // src/providers/anthropic.ts
522
- var anthropicAdapter = {
698
+ var anthropicAdapter = withPromptInputSupport({
523
699
  name: "anthropic",
524
- validate(asset) {
700
+ validate(asset, runtime) {
701
+ const resolvedAsset = resolveAssetForProvider(asset, runtime);
525
702
  const errors = [];
526
703
  const warnings = [];
527
- if (!asset.model) {
704
+ if (!resolvedAsset.model) {
528
705
  errors.push("Anthropic adapter requires a model to be specified.");
529
706
  }
530
- if (asset.sampling?.frequency_penalty !== void 0) {
707
+ if (resolvedAsset.sampling?.frequency_penalty !== void 0) {
531
708
  warnings.push("Anthropic does not support frequency_penalty. It will be ignored.");
532
709
  }
533
- if (asset.sampling?.presence_penalty !== void 0) {
710
+ if (resolvedAsset.sampling?.presence_penalty !== void 0) {
534
711
  warnings.push("Anthropic does not support presence_penalty. It will be ignored.");
535
712
  }
536
- if (asset.reasoning?.effort !== void 0) {
713
+ if (resolvedAsset.reasoning?.effort !== void 0) {
537
714
  warnings.push("Anthropic uses budget_tokens for thinking, not effort. effort will be mapped approximately.");
538
715
  }
539
716
  return { valid: errors.length === 0, errors, warnings };
540
717
  },
541
718
  render(asset, runtime) {
542
- const sections = renderSections(asset, {
719
+ const resolvedAsset = resolveAssetForProvider(asset, runtime);
720
+ const sections = renderSections(resolvedAsset, {
543
721
  variables: runtime.variables,
544
722
  strict: runtime.strict
545
723
  });
@@ -553,31 +731,31 @@ var anthropicAdapter = {
553
731
  messages.push({ role: "user", content: sections.prompt_template });
554
732
  }
555
733
  const body = {
556
- model: asset.model,
734
+ model: resolvedAsset.model,
557
735
  messages
558
736
  };
559
737
  if (sections.system_instructions) {
560
738
  body.system = sections.system_instructions;
561
739
  }
562
- if (asset.sampling?.temperature !== void 0) body.temperature = asset.sampling.temperature;
563
- if (asset.sampling?.top_p !== void 0) body.top_p = asset.sampling.top_p;
564
- if (asset.sampling?.stop !== void 0) body.stop_sequences = asset.sampling.stop;
565
- if (asset.sampling?.max_output_tokens !== void 0) {
566
- body.max_tokens = asset.sampling.max_output_tokens;
740
+ if (resolvedAsset.sampling?.temperature !== void 0) body.temperature = resolvedAsset.sampling.temperature;
741
+ if (resolvedAsset.sampling?.top_p !== void 0) body.top_p = resolvedAsset.sampling.top_p;
742
+ if (resolvedAsset.sampling?.stop !== void 0) body.stop_sequences = resolvedAsset.sampling.stop;
743
+ if (resolvedAsset.sampling?.max_output_tokens !== void 0) {
744
+ body.max_tokens = resolvedAsset.sampling.max_output_tokens;
567
745
  } else {
568
746
  body.max_tokens = 4096;
569
747
  }
570
- if (asset.reasoning?.budget_tokens) {
748
+ if (resolvedAsset.reasoning?.budget_tokens) {
571
749
  body.thinking = {
572
750
  type: "enabled",
573
- budget_tokens: asset.reasoning.budget_tokens
751
+ budget_tokens: resolvedAsset.reasoning.budget_tokens
574
752
  };
575
753
  }
576
- if (asset.response?.stream !== void 0) {
577
- body.stream = asset.response.stream;
754
+ if (resolvedAsset.response?.stream !== void 0) {
755
+ body.stream = resolvedAsset.response.stream;
578
756
  }
579
- if (asset.tools && asset.tools.length > 0) {
580
- body.tools = asset.tools.map((tool) => {
757
+ if (resolvedAsset.tools && resolvedAsset.tools.length > 0) {
758
+ body.tools = resolvedAsset.tools.map((tool) => {
581
759
  if (typeof tool === "string") {
582
760
  const def = runtime.toolRegistry?.[tool];
583
761
  if (def) return def;
@@ -593,30 +771,32 @@ var anthropicAdapter = {
593
771
  return {
594
772
  body,
595
773
  provider: "anthropic",
596
- model: asset.model ?? "unknown"
774
+ model: resolvedAsset.model ?? "unknown"
597
775
  };
598
776
  }
599
- };
777
+ });
600
778
 
601
779
  // src/providers/gemini.ts
602
- var geminiAdapter = {
780
+ var geminiAdapter = withPromptInputSupport({
603
781
  name: "gemini",
604
- validate(asset) {
782
+ validate(asset, runtime) {
783
+ const resolvedAsset = resolveAssetForProvider(asset, runtime);
605
784
  const errors = [];
606
785
  const warnings = [];
607
- if (!asset.model) {
786
+ if (!resolvedAsset.model) {
608
787
  errors.push("Gemini adapter requires a model to be specified.");
609
788
  }
610
- if (asset.sampling?.frequency_penalty !== void 0) {
789
+ if (resolvedAsset.sampling?.frequency_penalty !== void 0) {
611
790
  warnings.push("Gemini does not support frequency_penalty. It will be ignored.");
612
791
  }
613
- if (asset.sampling?.presence_penalty !== void 0) {
792
+ if (resolvedAsset.sampling?.presence_penalty !== void 0) {
614
793
  warnings.push("Gemini does not support presence_penalty. It will be ignored.");
615
794
  }
616
795
  return { valid: errors.length === 0, errors, warnings };
617
796
  },
618
797
  render(asset, runtime) {
619
- const sections = renderSections(asset, {
798
+ const resolvedAsset = resolveAssetForProvider(asset, runtime);
799
+ const sections = renderSections(resolvedAsset, {
620
800
  variables: runtime.variables,
621
801
  strict: runtime.strict
622
802
  });
@@ -644,23 +824,23 @@ var geminiAdapter = {
644
824
  };
645
825
  }
646
826
  const generationConfig = {};
647
- if (asset.sampling?.temperature !== void 0) generationConfig.temperature = asset.sampling.temperature;
648
- if (asset.sampling?.top_p !== void 0) generationConfig.topP = asset.sampling.top_p;
649
- if (asset.sampling?.max_output_tokens !== void 0) generationConfig.maxOutputTokens = asset.sampling.max_output_tokens;
650
- if (asset.sampling?.stop !== void 0) generationConfig.stopSequences = asset.sampling.stop;
651
- if (asset.response?.format === "json") {
827
+ if (resolvedAsset.sampling?.temperature !== void 0) generationConfig.temperature = resolvedAsset.sampling.temperature;
828
+ if (resolvedAsset.sampling?.top_p !== void 0) generationConfig.topP = resolvedAsset.sampling.top_p;
829
+ if (resolvedAsset.sampling?.max_output_tokens !== void 0) generationConfig.maxOutputTokens = resolvedAsset.sampling.max_output_tokens;
830
+ if (resolvedAsset.sampling?.stop !== void 0) generationConfig.stopSequences = resolvedAsset.sampling.stop;
831
+ if (resolvedAsset.response?.format === "json") {
652
832
  generationConfig.responseMimeType = "application/json";
653
833
  }
654
- if (asset.reasoning?.effort) {
834
+ if (resolvedAsset.reasoning?.effort) {
655
835
  body.thinkingConfig = {
656
- thinkingBudget: asset.reasoning.effort === "high" ? 8192 : asset.reasoning.effort === "medium" ? 4096 : 1024
836
+ thinkingBudget: resolvedAsset.reasoning.effort === "high" ? 8192 : resolvedAsset.reasoning.effort === "medium" ? 4096 : 1024
657
837
  };
658
838
  }
659
839
  if (Object.keys(generationConfig).length > 0) {
660
840
  body.generationConfig = generationConfig;
661
841
  }
662
- if (asset.tools && asset.tools.length > 0) {
663
- const functionDeclarations = asset.tools.map((tool) => {
842
+ if (resolvedAsset.tools && resolvedAsset.tools.length > 0) {
843
+ const functionDeclarations = resolvedAsset.tools.map((tool) => {
664
844
  if (typeof tool === "string") {
665
845
  const def = runtime.toolRegistry?.[tool];
666
846
  if (def) return def;
@@ -677,16 +857,16 @@ var geminiAdapter = {
677
857
  return {
678
858
  body,
679
859
  provider: "gemini",
680
- model: asset.model ?? "unknown"
860
+ model: resolvedAsset.model ?? "unknown"
681
861
  };
682
862
  }
683
- };
863
+ });
684
864
 
685
865
  // src/providers/openrouter.ts
686
- var openrouterAdapter = {
866
+ var openrouterAdapter = withPromptInputSupport({
687
867
  name: "openrouter",
688
- validate(asset) {
689
- return openaiAdapter.validate(asset);
868
+ validate(asset, runtime) {
869
+ return openaiAdapter.validate(asset, runtime);
690
870
  },
691
871
  render(asset, runtime) {
692
872
  const result = openaiAdapter.render(asset, runtime);
@@ -695,7 +875,7 @@ var openrouterAdapter = {
695
875
  provider: "openrouter"
696
876
  };
697
877
  }
698
- };
878
+ });
699
879
 
700
880
  // src/providers/index.ts
701
881
  var adapters = {
@@ -905,48 +1085,6 @@ function findClosestMatch(input, candidates) {
905
1085
  return best;
906
1086
  }
907
1087
 
908
- // src/cache.ts
909
- var import_node_fs = require("fs");
910
- var PromptCache = class {
911
- cache = /* @__PURE__ */ new Map();
912
- maxSize;
913
- constructor(maxSize = 100) {
914
- this.maxSize = maxSize;
915
- }
916
- get(filePath) {
917
- const entry = this.cache.get(filePath);
918
- if (!entry) return void 0;
919
- try {
920
- const stat = (0, import_node_fs.statSync)(filePath);
921
- if (stat.mtimeMs !== entry.mtime) {
922
- this.cache.delete(filePath);
923
- return void 0;
924
- }
925
- } catch {
926
- this.cache.delete(filePath);
927
- return void 0;
928
- }
929
- return entry.value;
930
- }
931
- set(filePath, value) {
932
- if (this.cache.size >= this.maxSize) {
933
- const oldest = this.cache.keys().next().value;
934
- if (oldest) this.cache.delete(oldest);
935
- }
936
- try {
937
- const stat = (0, import_node_fs.statSync)(filePath);
938
- this.cache.set(filePath, { value, mtime: stat.mtimeMs });
939
- } catch {
940
- }
941
- }
942
- clear() {
943
- this.cache.clear();
944
- }
945
- get size() {
946
- return this.cache.size;
947
- }
948
- };
949
-
950
1088
  // src/usagetap/client.ts
951
1089
  var DEFAULT_BASE_URL = "https://api.usagetap.com";
952
1090
  var ACCEPT_HEADER = "application/vnd.usagetap.v1+json";
@@ -1354,72 +1492,13 @@ var PromptOpsKit = class {
1354
1492
  * Load a prompt asset from compiled or source, based on mode.
1355
1493
  */
1356
1494
  async loadPrompt(promptPath) {
1357
- const mode = this.config.mode;
1358
- if (mode !== "source-only" && this.config.compiledDir) {
1359
- const compiledFile = (0, import_node_path3.resolve)(this.config.compiledDir, promptPath + ".json");
1360
- if ((0, import_node_fs2.existsSync)(compiledFile)) {
1361
- if (mode === "auto") {
1362
- const sourceFile = (0, import_node_path3.resolve)(this.config.sourceDir, promptPath + ".md");
1363
- if ((0, import_node_fs2.existsSync)(sourceFile)) {
1364
- const compiledMtime = (0, import_node_fs2.statSync)(compiledFile).mtimeMs;
1365
- const sourceMtime = (0, import_node_fs2.statSync)(sourceFile).mtimeMs;
1366
- if (sourceMtime > compiledMtime) {
1367
- console.warn(
1368
- `[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
1369
- Run "promptopskit compile" or switch to source-only mode.`
1370
- );
1371
- }
1372
- }
1373
- }
1374
- const content = await (0, import_promises3.readFile)(compiledFile, "utf-8");
1375
- return JSON.parse(content);
1376
- }
1377
- if (mode === "compiled-only") {
1378
- throw new Error(
1379
- `Compiled artifact not found: ${compiledFile}
1380
- Run "promptopskit compile" to generate it.`
1381
- );
1382
- }
1383
- }
1384
- if (mode !== "compiled-only") {
1385
- const sourceFile = (0, import_node_path3.resolve)(this.config.sourceDir, promptPath + ".md");
1386
- if (this.config.cache) {
1387
- const cached = this.promptCache.get(sourceFile);
1388
- if (cached) return cached;
1389
- }
1390
- if (!(0, import_node_fs2.existsSync)(sourceFile)) {
1391
- const paths = [sourceFile];
1392
- if (this.config.compiledDir) {
1393
- paths.unshift((0, import_node_path3.resolve)(this.config.compiledDir, promptPath + ".json"));
1394
- }
1395
- throw new Error(
1396
- `Prompt not found: "${promptPath}"
1397
- Searched:
1398
- ${paths.map((p) => ` - ${p}`).join("\n")}`
1399
- );
1400
- }
1401
- const { asset } = await loadPromptFile(sourceFile, { defaultsRoot: this.config.sourceDir });
1402
- if (this.config.cache) {
1403
- this.promptCache.set(sourceFile, asset);
1404
- }
1405
- return asset;
1406
- }
1407
- throw new Error(`Prompt not found: "${promptPath}"`);
1495
+ return loadPromptAsset(promptPath, this.config, this.promptCache);
1408
1496
  }
1409
1497
  /**
1410
1498
  * Resolve a prompt: load, resolve includes, apply overrides.
1411
1499
  */
1412
1500
  async resolvePrompt(promptPath, options = {}) {
1413
- let asset = await this.loadPrompt(promptPath);
1414
- const sourceFile = (0, import_node_path3.resolve)(this.config.sourceDir, promptPath + ".md");
1415
- if (asset.includes && asset.includes.length > 0 && (0, import_node_fs2.existsSync)(sourceFile)) {
1416
- asset = await resolveIncludes(asset, sourceFile);
1417
- }
1418
- asset = applyOverrides(asset, {
1419
- environment: options.environment,
1420
- tier: options.tier
1421
- });
1422
- return asset;
1501
+ return resolvePromptAsset(promptPath, this.config, options, this.promptCache);
1423
1502
  }
1424
1503
  /**
1425
1504
  * Render a prompt for a specific provider.
@@ -1427,16 +1506,16 @@ ${paths.map((p) => ` - ${p}`).join("\n")}`
1427
1506
  async renderPrompt(options) {
1428
1507
  let resolved;
1429
1508
  if (options.source) {
1430
- const { asset } = parsePrompt(options.source);
1431
- const overridden = applyOverrides(asset, {
1509
+ resolved = resolveInlinePromptSource(options.source, {
1432
1510
  environment: options.environment,
1433
- tier: options.tier
1511
+ tier: options.tier,
1512
+ runtime: options.runtime
1434
1513
  });
1435
- resolved = overridden;
1436
1514
  } else if (options.path) {
1437
1515
  resolved = await this.resolvePrompt(options.path, {
1438
1516
  environment: options.environment,
1439
- tier: options.tier
1517
+ tier: options.tier,
1518
+ runtime: options.runtime
1440
1519
  });
1441
1520
  } else {
1442
1521
  throw new Error('Either "path" or "source" must be provided to renderPrompt()');
@@ -1475,7 +1554,8 @@ ${paths.map((p) => ` - ${p}`).join("\n")}`
1475
1554
  */
1476
1555
  async validatePrompt(promptPath) {
1477
1556
  const asset = await this.loadPrompt(promptPath);
1478
- return validateAsset(asset, void 0, promptPath);
1557
+ const sourceFile = (0, import_node_path4.resolve)(this.config.sourceDir, promptPath + ".md");
1558
+ return validateAssetWithIncludes(asset, sourceFile);
1479
1559
  }
1480
1560
  /**
1481
1561
  * Clear the internal cache.