promptopskit 0.5.0 → 0.7.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 (70) hide show
  1. package/README.md +9 -7
  2. package/SKILL.md +16 -10
  3. package/dist/{chunk-QK3WKE3K.js → chunk-35NN5F6O.js} +2 -2
  4. package/dist/{chunk-D75HKF64.js → chunk-3G3EAV7H.js} +2 -2
  5. package/dist/{chunk-LNGHGGJN.js → chunk-6NOUETAC.js} +2 -2
  6. package/dist/{chunk-KN7H4JRK.js → chunk-F552OBUV.js} +619 -502
  7. package/dist/chunk-F552OBUV.js.map +1 -0
  8. package/dist/{chunk-6BOUQVSX.js → chunk-FICB2ZSK.js} +3 -3
  9. package/dist/{chunk-6VLKZCNS.js → chunk-OWMP5NMV.js} +2 -2
  10. package/dist/{chunk-IN4KT5EU.js → chunk-R65RAHAG.js} +3 -3
  11. package/dist/{chunk-K6ZU3CGV.js → chunk-ULVY473P.js} +306 -17
  12. package/dist/chunk-ULVY473P.js.map +1 -0
  13. package/dist/cli/index.js +446 -103
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/index.cjs +1223 -772
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +9 -5
  18. package/dist/index.d.ts +9 -5
  19. package/dist/index.js +67 -18
  20. package/dist/index.js.map +1 -1
  21. package/dist/providers/anthropic.cjs +902 -502
  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 -3
  26. package/dist/providers/gemini.cjs +902 -502
  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 -3
  31. package/dist/providers/llmasaservice.cjs +901 -501
  32. package/dist/providers/llmasaservice.cjs.map +1 -1
  33. package/dist/providers/llmasaservice.d.cts +2 -2
  34. package/dist/providers/llmasaservice.d.ts +2 -2
  35. package/dist/providers/llmasaservice.js +4 -4
  36. package/dist/providers/openai-responses.cjs +902 -502
  37. package/dist/providers/openai-responses.cjs.map +1 -1
  38. package/dist/providers/openai-responses.d.cts +2 -2
  39. package/dist/providers/openai-responses.d.ts +2 -2
  40. package/dist/providers/openai-responses.js +3 -3
  41. package/dist/providers/openai.cjs +902 -502
  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 +902 -502
  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-D-RI4w-k.d.cts → schema-DBcSns_b.d.cts} +732 -206
  52. package/dist/{schema-D-RI4w-k.d.ts → schema-DBcSns_b.d.ts} +732 -206
  53. package/dist/testing.cjs +54 -5
  54. package/dist/testing.cjs.map +1 -1
  55. package/dist/testing.d.cts +1 -1
  56. package/dist/testing.d.ts +1 -1
  57. package/dist/testing.js +1 -1
  58. package/dist/{types-B3dxBGu6.d.ts → types-8T2D5KB5.d.cts} +20 -2
  59. package/dist/{types-DbTAjlTN.d.cts → types-BlLXT5Qb.d.ts} +20 -2
  60. package/dist/usagetap/index.d.cts +2 -2
  61. package/dist/usagetap/index.d.ts +2 -2
  62. package/package.json +9 -2
  63. package/dist/chunk-K6ZU3CGV.js.map +0 -1
  64. package/dist/chunk-KN7H4JRK.js.map +0 -1
  65. /package/dist/{chunk-QK3WKE3K.js.map → chunk-35NN5F6O.js.map} +0 -0
  66. /package/dist/{chunk-D75HKF64.js.map → chunk-3G3EAV7H.js.map} +0 -0
  67. /package/dist/{chunk-LNGHGGJN.js.map → chunk-6NOUETAC.js.map} +0 -0
  68. /package/dist/{chunk-6BOUQVSX.js.map → chunk-FICB2ZSK.js.map} +0 -0
  69. /package/dist/{chunk-6VLKZCNS.js.map → chunk-OWMP5NMV.js.map} +0 -0
  70. /package/dist/{chunk-IN4KT5EU.js.map → chunk-R65RAHAG.js.map} +0 -0
@@ -45,12 +45,13 @@ var ESCAPED_OPEN = /\\\{\\\{/g;
45
45
  var ESCAPE_PLACEHOLDER = "\0ESCAPED_OPEN\0";
46
46
  function interpolate(template, variables, options = {}) {
47
47
  const { strict = false } = options;
48
+ const optionalVariables = new Set(options.optionalVariables ?? []);
48
49
  let result = template.replace(ESCAPED_OPEN, ESCAPE_PLACEHOLDER);
49
50
  result = result.replace(VARIABLE_RE, (match, name) => {
50
51
  if (name in variables) {
51
52
  return variables[name];
52
53
  }
53
- if (strict) {
54
+ if (strict && !optionalVariables.has(name)) {
54
55
  throw new Error(`Missing required variable: "${name}"`);
55
56
  }
56
57
  return match;
@@ -59,22 +60,299 @@ function interpolate(template, variables, options = {}) {
59
60
  return result;
60
61
  }
61
62
 
63
+ // src/context.ts
64
+ var textEncoder = new TextEncoder();
65
+ var REJECT_SECRETS_PATTERN = "(secret|api[_-]?key|password)";
66
+ var REJECT_SECRETS_FLAGS = "i";
67
+ function getContextInputs(asset) {
68
+ return (asset.context?.inputs ?? []).map(normalizeContextInput);
69
+ }
70
+ function normalizeContextInput(input) {
71
+ if (typeof input === "string") {
72
+ return { name: input };
73
+ }
74
+ return {
75
+ name: input.name,
76
+ optional: input.optional,
77
+ warnings: input.warnings,
78
+ max_size: input.max_size,
79
+ trim: input.trim,
80
+ allow_regex: normalizeContextRegex(input.allow_regex),
81
+ deny_regex: normalizeContextRegex(input.deny_regex),
82
+ non_empty: normalizeBuiltInValidator(input.non_empty),
83
+ reject_secrets: normalizeBuiltInValidator(input.reject_secrets)
84
+ };
85
+ }
86
+ function normalizeContextRegex(value) {
87
+ if (value === void 0) {
88
+ return void 0;
89
+ }
90
+ if (typeof value === "string") {
91
+ const literal = parseRegexLiteral(value);
92
+ if (value.startsWith("/") && !literal) {
93
+ return {
94
+ pattern: value,
95
+ flags: "",
96
+ raw: value,
97
+ invalidLiteral: true
98
+ };
99
+ }
100
+ return {
101
+ pattern: literal?.pattern ?? value,
102
+ flags: literal?.flags ?? "",
103
+ raw: value
104
+ };
105
+ }
106
+ return {
107
+ pattern: value.pattern,
108
+ flags: value.flags ?? "",
109
+ raw: JSON.stringify(value),
110
+ returnMessage: value.return_message
111
+ };
112
+ }
113
+ function normalizeBuiltInValidator(value) {
114
+ if (value === void 0 || value === false) {
115
+ return void 0;
116
+ }
117
+ if (value === true) {
118
+ return {};
119
+ }
120
+ return {
121
+ returnMessage: value.return_message
122
+ };
123
+ }
124
+ function parseRegexLiteral(value) {
125
+ if (!value.startsWith("/")) {
126
+ return void 0;
127
+ }
128
+ for (let index = value.length - 1; index > 0; index -= 1) {
129
+ if (value[index] !== "/") {
130
+ continue;
131
+ }
132
+ let backslashCount = 0;
133
+ for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
134
+ backslashCount += 1;
135
+ }
136
+ if (backslashCount % 2 === 1) {
137
+ continue;
138
+ }
139
+ return {
140
+ pattern: value.slice(1, index),
141
+ flags: value.slice(index + 1)
142
+ };
143
+ }
144
+ return void 0;
145
+ }
146
+ function formatInvalidContextRegexMessage(details) {
147
+ return [
148
+ `Invalid context regex for prompt "${details.promptId}"`,
149
+ `variable "${details.variable}"`,
150
+ `field "${details.field}"`,
151
+ `value ${JSON.stringify(details.raw)}: ${details.reason}`
152
+ ].join(", ");
153
+ }
154
+ function compileContextRegex(regex, details) {
155
+ if (regex.invalidLiteral) {
156
+ throw new Error(
157
+ `POK013: ${formatInvalidContextRegexMessage({
158
+ ...details,
159
+ raw: regex.raw,
160
+ reason: "Malformed regex literal. Use /pattern/flags or { pattern, flags }."
161
+ })}`
162
+ );
163
+ }
164
+ try {
165
+ return new RegExp(regex.pattern, regex.flags);
166
+ } catch (error) {
167
+ const reason = error instanceof Error ? error.message : String(error);
168
+ throw new Error(`POK013: ${formatInvalidContextRegexMessage({ ...details, raw: regex.raw, reason })}`);
169
+ }
170
+ }
171
+ function getRejectSecretsRegex() {
172
+ return {
173
+ pattern: REJECT_SECRETS_PATTERN,
174
+ flags: REJECT_SECRETS_FLAGS,
175
+ raw: JSON.stringify({ pattern: REJECT_SECRETS_PATTERN, flags: REJECT_SECRETS_FLAGS })
176
+ };
177
+ }
178
+ function isTrimEnabled(mode) {
179
+ return mode === true || mode === "start" || mode === "end" || mode === "both";
180
+ }
181
+ function normalizeTrimMode(mode) {
182
+ if (mode === "start") {
183
+ return "start";
184
+ }
185
+ return "end";
186
+ }
187
+ function trimToMaxSize(value, maxSize, mode) {
188
+ const measured = measureContextValueSize(value);
189
+ if (measured <= maxSize) {
190
+ return value;
191
+ }
192
+ const characters = Array.from(value);
193
+ const normalizedMode = normalizeTrimMode(mode);
194
+ if (normalizedMode === "start") {
195
+ let collected2 = "";
196
+ let size2 = 0;
197
+ for (let i = characters.length - 1; i >= 0; i -= 1) {
198
+ const next = characters[i];
199
+ const charSize = measureContextValueSize(next);
200
+ if (size2 + charSize > maxSize) {
201
+ break;
202
+ }
203
+ collected2 = next + collected2;
204
+ size2 += charSize;
205
+ }
206
+ return collected2;
207
+ }
208
+ let collected = "";
209
+ let size = 0;
210
+ for (const char of characters) {
211
+ const charSize = measureContextValueSize(char);
212
+ if (size + charSize > maxSize) {
213
+ break;
214
+ }
215
+ collected += char;
216
+ size += charSize;
217
+ }
218
+ return collected;
219
+ }
220
+ function sanitizeContextVariables(asset, variables = {}, options = {}) {
221
+ const { onContextOverflow } = options;
222
+ const sanitized = { ...variables };
223
+ for (const input of getContextInputs(asset)) {
224
+ const value = sanitized[input.name];
225
+ if (value === void 0) {
226
+ continue;
227
+ }
228
+ let candidate = value;
229
+ if (input.max_size !== void 0) {
230
+ const actualSize = measureContextValueSize(candidate);
231
+ if (actualSize > input.max_size && onContextOverflow) {
232
+ candidate = onContextOverflow({
233
+ promptId: asset.id,
234
+ variable: input.name,
235
+ value: candidate,
236
+ maxSize: input.max_size,
237
+ actualSize
238
+ });
239
+ }
240
+ }
241
+ if (isTrimEnabled(input.trim) && input.max_size !== void 0) {
242
+ candidate = trimToMaxSize(candidate, input.max_size, input.trim);
243
+ }
244
+ sanitized[input.name] = candidate;
245
+ if (input.allow_regex) {
246
+ const candidate2 = sanitized[input.name];
247
+ const matcher = compileContextRegex(input.allow_regex, {
248
+ promptId: asset.id,
249
+ variable: input.name,
250
+ field: "allow_regex"
251
+ });
252
+ if (!matcher.test(candidate2)) {
253
+ if (input.allow_regex.returnMessage) {
254
+ return {
255
+ variables: sanitized,
256
+ shortCircuit: {
257
+ returnMessage: input.allow_regex.returnMessage,
258
+ code: "POK031",
259
+ variable: input.name,
260
+ field: "allow_regex"
261
+ }
262
+ };
263
+ }
264
+ throw new Error(
265
+ `POK031: Context variable "${input.name}" failed allow_regex validation for prompt "${asset.id}".`
266
+ );
267
+ }
268
+ }
269
+ if (input.deny_regex) {
270
+ const candidate2 = sanitized[input.name];
271
+ const matcher = compileContextRegex(input.deny_regex, {
272
+ promptId: asset.id,
273
+ variable: input.name,
274
+ field: "deny_regex"
275
+ });
276
+ if (matcher.test(candidate2)) {
277
+ if (input.deny_regex.returnMessage) {
278
+ return {
279
+ variables: sanitized,
280
+ shortCircuit: {
281
+ returnMessage: input.deny_regex.returnMessage,
282
+ code: "POK032",
283
+ variable: input.name,
284
+ field: "deny_regex"
285
+ }
286
+ };
287
+ }
288
+ throw new Error(
289
+ `POK032: Context variable "${input.name}" matched deny_regex for prompt "${asset.id}".`
290
+ );
291
+ }
292
+ }
293
+ if (input.non_empty && candidate.trim().length === 0) {
294
+ if (input.non_empty.returnMessage) {
295
+ return {
296
+ variables: sanitized,
297
+ shortCircuit: {
298
+ returnMessage: input.non_empty.returnMessage,
299
+ code: "POK033",
300
+ variable: input.name,
301
+ field: "non_empty"
302
+ }
303
+ };
304
+ }
305
+ throw new Error(
306
+ `POK033: Context variable "${input.name}" failed non_empty validation for prompt "${asset.id}".`
307
+ );
308
+ }
309
+ if (input.reject_secrets) {
310
+ const matcher = compileContextRegex(getRejectSecretsRegex(), {
311
+ promptId: asset.id,
312
+ variable: input.name,
313
+ field: "reject_secrets"
314
+ });
315
+ if (matcher.test(candidate)) {
316
+ if (input.reject_secrets.returnMessage) {
317
+ return {
318
+ variables: sanitized,
319
+ shortCircuit: {
320
+ returnMessage: input.reject_secrets.returnMessage,
321
+ code: "POK034",
322
+ variable: input.name,
323
+ field: "reject_secrets"
324
+ }
325
+ };
326
+ }
327
+ throw new Error(
328
+ `POK034: Context variable "${input.name}" matched reject_secrets validation for prompt "${asset.id}".`
329
+ );
330
+ }
331
+ }
332
+ }
333
+ return { variables: sanitized };
334
+ }
335
+ function measureContextValueSize(value) {
336
+ return textEncoder.encode(value).length;
337
+ }
338
+
62
339
  // src/renderer/renderer.ts
63
340
  function renderSections(asset, options = {}) {
64
341
  const { variables = {}, strict = false } = options;
342
+ const optionalVariables = getContextInputs(asset).filter((input) => input.optional === true).map((input) => input.name);
65
343
  const result = {};
66
344
  if (asset.sections.system_instructions) {
67
345
  result.system_instructions = interpolate(
68
346
  asset.sections.system_instructions,
69
347
  variables,
70
- { strict }
348
+ { strict, optionalVariables }
71
349
  );
72
350
  }
73
351
  if (asset.sections.prompt_template) {
74
352
  result.prompt_template = interpolate(
75
353
  asset.sections.prompt_template,
76
354
  variables,
77
- { strict }
355
+ { strict, optionalVariables }
78
356
  );
79
357
  }
80
358
  return result;
@@ -108,6 +386,16 @@ function mergeOverride(base, override) {
108
386
  if (override.response !== void 0) {
109
387
  result.response = { ...result.response, ...override.response };
110
388
  }
389
+ if (override.compression !== void 0) {
390
+ result.compression = {
391
+ ...result.compression,
392
+ ...override.compression,
393
+ thetokencompany: mergeRecordBlock(
394
+ result.compression?.thetokencompany,
395
+ override.compression.thetokencompany
396
+ )
397
+ };
398
+ }
111
399
  if (override.cache !== void 0) {
112
400
  result.cache = {
113
401
  ...result.cache,
@@ -174,9 +462,9 @@ function resolveAssetForProvider(asset, runtime = {}) {
174
462
  }
175
463
 
176
464
  // src/prompt-resolution.ts
177
- var import_promises3 = require("fs/promises");
465
+ var import_promises4 = require("fs/promises");
178
466
  var import_node_fs2 = require("fs");
179
- var import_node_path3 = require("path");
467
+ var import_node_path4 = require("path");
180
468
 
181
469
  // src/cache.ts
182
470
  var import_node_fs = require("fs");
@@ -225,8 +513,8 @@ var PromptCache = class {
225
513
  };
226
514
 
227
515
  // src/composition/resolve-includes.ts
228
- var import_promises2 = require("fs/promises");
229
- var import_node_path2 = require("path");
516
+ var import_promises3 = require("fs/promises");
517
+ var import_node_path3 = require("path");
230
518
 
231
519
  // src/parser/parser.ts
232
520
  var import_gray_matter = __toESM(require("gray-matter"), 1);
@@ -262,10 +550,26 @@ var ResponseSchema = import_zod.z.object({
262
550
  format: import_zod.z.enum(["text", "json", "markdown"]).optional(),
263
551
  stream: import_zod.z.boolean().optional(),
264
552
  schema: import_zod.z.record(import_zod.z.unknown()).optional(),
553
+ schema_ref: import_zod.z.string().min(1).optional(),
554
+ schema_source: import_zod.z.object({
555
+ mode: import_zod.z.enum(["inline", "schema_ref_json", "schema_ref_zod_module"]).optional(),
556
+ ref: import_zod.z.string().optional(),
557
+ resolved_path: import_zod.z.string().optional(),
558
+ hash: import_zod.z.string().optional()
559
+ }).optional(),
265
560
  schema_name: import_zod.z.string().optional(),
266
561
  schema_description: import_zod.z.string().optional(),
267
562
  schema_strict: import_zod.z.boolean().optional()
268
563
  });
564
+ var ResponseSchemaWithValidation = ResponseSchema.superRefine((value, ctx) => {
565
+ if (value.schema !== void 0 && value.schema_ref !== void 0) {
566
+ ctx.addIssue({
567
+ code: import_zod.z.ZodIssueCode.custom,
568
+ message: "response.schema and response.schema_ref are mutually exclusive",
569
+ path: ["schema_ref"]
570
+ });
571
+ }
572
+ });
269
573
  var AnthropicProviderOptionsSchema = import_zod.z.object({
270
574
  top_k: import_zod.z.number().int().min(0).optional(),
271
575
  tool_choice: import_zod.z.record(import_zod.z.unknown()).optional(),
@@ -317,6 +621,14 @@ var RawProviderBodySchema = import_zod.z.object({
317
621
  openrouter: import_zod.z.record(import_zod.z.unknown()).optional(),
318
622
  llmasaservice: import_zod.z.record(import_zod.z.unknown()).optional()
319
623
  });
624
+ var TheTokenCompanyCompressionSchema = import_zod.z.object({
625
+ enabled: import_zod.z.boolean().optional(),
626
+ model: import_zod.z.string().min(1).optional(),
627
+ aggressiveness: import_zod.z.number().min(0).max(1).optional()
628
+ });
629
+ var CompressionSchema = import_zod.z.object({
630
+ thetokencompany: TheTokenCompanyCompressionSchema.optional()
631
+ });
320
632
  var OpenAICacheSchema = import_zod.z.object({
321
633
  prompt_cache_key: import_zod.z.string().min(1).optional(),
322
634
  retention: import_zod.z.enum(["in_memory", "24h"]).optional()
@@ -357,6 +669,8 @@ var ContextBuiltInValidatorSchema = import_zod.z.union([
357
669
  ]);
358
670
  var ContextInputDefinitionObjectSchema = import_zod.z.object({
359
671
  name: import_zod.z.string(),
672
+ optional: import_zod.z.boolean().optional(),
673
+ warnings: import_zod.z.boolean().optional(),
360
674
  max_size: import_zod.z.number().int().positive().optional(),
361
675
  trim: import_zod.z.union([import_zod.z.boolean(), import_zod.z.enum(["start", "end", "both"])]).optional(),
362
676
  allow_regex: ContextRegexSchema.optional(),
@@ -386,7 +700,8 @@ var PromptAssetOverridesSchema = import_zod.z.object({
386
700
  fallback_models: import_zod.z.array(import_zod.z.string()).optional(),
387
701
  reasoning: ReasoningSchema.optional(),
388
702
  sampling: SamplingSchema.optional(),
389
- response: ResponseSchema.optional(),
703
+ response: ResponseSchemaWithValidation.optional(),
704
+ compression: CompressionSchema.optional(),
390
705
  cache: CacheSchema.optional(),
391
706
  raw: RawProviderBodySchema.optional(),
392
707
  tools: import_zod.z.array(ToolRefSchema).optional(),
@@ -404,7 +719,20 @@ var SectionsSchema = import_zod.z.object({
404
719
  var PromptDefaultsSchema = import_zod.z.object({
405
720
  provider: import_zod.z.enum(["openai", "openai-responses", "anthropic", "google", "gemini", "openrouter", "llmasaservice", "any"]).optional(),
406
721
  model: import_zod.z.string().optional(),
722
+ fallback_models: import_zod.z.array(import_zod.z.string()).optional(),
723
+ reasoning: ReasoningSchema.optional(),
724
+ sampling: SamplingSchema.optional(),
725
+ response: ResponseSchema.optional(),
726
+ compression: CompressionSchema.optional(),
407
727
  cache: CacheSchema.optional(),
728
+ raw: RawProviderBodySchema.optional(),
729
+ tools: import_zod.z.array(ToolRefSchema).optional(),
730
+ provider_options: ProviderOptionsSchema.optional(),
731
+ mcp: MCPSchema.optional(),
732
+ context: ContextSchema.optional(),
733
+ includes: import_zod.z.array(import_zod.z.string()).optional(),
734
+ environments: import_zod.z.record(PromptAssetOverridesSchema).optional(),
735
+ tiers: import_zod.z.record(PromptAssetOverridesSchema).optional(),
408
736
  metadata: MetadataSchema.optional(),
409
737
  sections: import_zod.z.object({
410
738
  system_instructions: import_zod.z.string().optional()
@@ -419,7 +747,8 @@ var PromptAssetSchema = import_zod.z.object({
419
747
  fallback_models: import_zod.z.array(import_zod.z.string()).optional(),
420
748
  reasoning: ReasoningSchema.optional(),
421
749
  sampling: SamplingSchema.optional(),
422
- response: ResponseSchema.optional(),
750
+ response: ResponseSchemaWithValidation.optional(),
751
+ compression: CompressionSchema.optional(),
423
752
  cache: CacheSchema.optional(),
424
753
  raw: RawProviderBodySchema.optional(),
425
754
  tools: import_zod.z.array(ToolRefSchema).optional(),
@@ -599,540 +928,514 @@ function parsePrompt(content, filePath) {
599
928
  ...frontMatter,
600
929
  sections,
601
930
  source: filePath ? { file_path: filePath } : void 0
602
- };
603
- const asset = PromptAssetSchema.parse(raw);
604
- return {
605
- asset,
606
- raw: {
607
- frontMatter,
608
- body
609
- }
610
- };
611
- }
612
-
613
- // src/parser/loader.ts
614
- var import_promises = require("fs/promises");
615
- var import_node_path = require("path");
616
- var import_gray_matter2 = __toESM(require("gray-matter"), 1);
617
- var DEFAULTS_FILE_NAME = "defaults.md";
618
- async function loadPromptFile(filePath, options = {}) {
619
- const content = await (0, import_promises.readFile)(filePath, "utf-8");
620
- const parsed = parsePrompt(content, filePath);
621
- const root = options.defaultsRoot ?? (0, import_node_path.dirname)(filePath);
622
- const defaults = await loadDefaultsForPath(filePath, root);
623
- const asset = applyDefaults(parsed.asset, defaults);
624
- return {
625
- ...parsed,
626
- asset
627
- };
628
- }
629
- async function loadDefaultsForPath(filePath, defaultsRoot) {
630
- const directories = getDirectoriesToCheck(filePath, defaultsRoot);
631
- let merged = {};
632
- for (const dir of directories) {
633
- const defaultsPath = (0, import_node_path.join)(dir, DEFAULTS_FILE_NAME);
634
- try {
635
- const defaultsContent = await (0, import_promises.readFile)(defaultsPath, "utf-8");
636
- const defaults = parseDefaults(defaultsContent);
637
- merged = mergeDefaults(merged, defaults);
638
- } catch (error) {
639
- if (error.code !== "ENOENT") {
640
- throw error;
641
- }
642
- }
643
- }
644
- return merged;
645
- }
646
- function getDirectoriesToCheck(filePath, defaultsRoot) {
647
- const dirs = [];
648
- let current = (0, import_node_path.resolve)((0, import_node_path.dirname)(filePath));
649
- const boundary = defaultsRoot ? (0, import_node_path.resolve)(defaultsRoot) : void 0;
650
- while (true) {
651
- dirs.unshift(current);
652
- if (boundary && current === boundary || current === (0, import_node_path.dirname)(current)) {
653
- break;
654
- }
655
- current = (0, import_node_path.dirname)(current);
656
- }
657
- return dirs;
658
- }
659
- function parseDefaults(content) {
660
- const { data: frontMatter, content: body } = (0, import_gray_matter2.default)(content);
661
- const sections = extractSections(body);
662
- return PromptDefaultsSchema.parse({
663
- ...frontMatter,
664
- sections: {
665
- system_instructions: sections.system_instructions
666
- }
667
- });
668
- }
669
- function mergeDefaults(base, local) {
670
- return {
671
- provider: local.provider ?? base.provider,
672
- model: local.model ?? base.model,
673
- cache: mergeCache(base.cache, local.cache),
674
- metadata: {
675
- ...base.metadata ?? {},
676
- ...local.metadata ?? {}
677
- },
678
- sections: {
679
- ...base.sections ?? {},
680
- ...local.sections ?? {}
681
- }
682
- };
683
- }
684
- function applyDefaults(asset, defaults) {
685
- const cache = mergeCache(defaults.cache, asset.cache);
686
- const hasDefaultMetadata = defaults.metadata && Object.keys(defaults.metadata).length > 0;
687
- const hasDefaultSystem = !!defaults.sections?.system_instructions;
688
- const hasDefaultScalars = defaults.provider !== void 0 || defaults.model !== void 0;
689
- const hasDefaultCache = cache !== void 0;
690
- if (!hasDefaultMetadata && !hasDefaultSystem && !hasDefaultScalars && !hasDefaultCache) {
691
- return asset;
692
- }
693
- const mergedMetadata = {
694
- ...defaults.metadata ?? {},
695
- ...asset.metadata ?? {}
696
- };
697
- const metadata = Object.keys(mergedMetadata).length > 0 ? mergedMetadata : void 0;
698
- const systemInstructions = asset.sections?.system_instructions ?? defaults.sections?.system_instructions;
699
- const sections = asset.sections ? { ...asset.sections, system_instructions: systemInstructions } : systemInstructions ? { system_instructions: systemInstructions } : void 0;
700
- return {
701
- ...asset,
702
- provider: asset.provider ?? defaults.provider,
703
- model: asset.model ?? defaults.model,
704
- cache,
705
- metadata,
706
- sections
707
- };
708
- }
709
- function mergeCache(base, local) {
710
- const merged = {
711
- ...base ?? {},
712
- ...local ?? {},
713
- openai: {
714
- ...base?.openai ?? {},
715
- ...local?.openai ?? {}
716
- },
717
- anthropic: {
718
- ...base?.anthropic ?? {},
719
- ...local?.anthropic ?? {}
720
- },
721
- gemini: {
722
- ...base?.gemini ?? {},
723
- ...local?.gemini ?? {}
724
- },
725
- google: {
726
- ...base?.google ?? {},
727
- ...local?.google ?? {}
728
- }
729
- };
730
- if (merged.openai && Object.keys(merged.openai).length === 0) delete merged.openai;
731
- if (merged.anthropic && Object.keys(merged.anthropic).length === 0) delete merged.anthropic;
732
- if (merged.gemini && Object.keys(merged.gemini).length === 0) delete merged.gemini;
733
- if (merged.google && Object.keys(merged.google).length === 0) delete merged.google;
734
- return Object.keys(merged).length > 0 ? merged : void 0;
735
- }
736
-
737
- // src/composition/resolve-includes.ts
738
- async function resolveIncludes(asset, basePath, visited = /* @__PURE__ */ new Set()) {
739
- if (!asset.includes || asset.includes.length === 0) {
740
- return asset;
741
- }
742
- const baseDir = (0, import_node_path2.dirname)(basePath);
743
- const resolvedPath = (0, import_node_path2.resolve)(basePath);
744
- if (visited.has(resolvedPath)) {
745
- throw new Error(`Circular include detected: ${resolvedPath}`);
746
- }
747
- visited.add(resolvedPath);
748
- let mergedSystemInstructions = "";
749
- for (const includePath of asset.includes) {
750
- const fullPath = (0, import_node_path2.resolve)(baseDir, includePath);
751
- if (visited.has(fullPath)) {
752
- throw new Error(`Circular include detected: ${fullPath} (included from ${basePath})`);
753
- }
754
- const content = await (0, import_promises2.readFile)(fullPath, "utf-8");
755
- const { asset: includedAsset } = parsePrompt(content, fullPath);
756
- const resolved = await resolveIncludes(includedAsset, fullPath, new Set(visited));
757
- if (resolved.sections?.system_instructions) {
758
- mergedSystemInstructions += resolved.sections.system_instructions + "\n\n";
759
- }
760
- }
761
- const localSystem = asset.sections?.system_instructions ?? "";
762
- const combinedSystem = (mergedSystemInstructions + localSystem).trim() || void 0;
763
- return {
764
- ...asset,
765
- sections: {
766
- ...asset.sections,
767
- system_instructions: combinedSystem
768
- },
769
- // Drop includes from the resolved asset — they've been inlined
770
- includes: void 0
771
- };
772
- }
773
-
774
- // src/prompt-resolution.ts
775
- var DEFAULT_PROMPTS_DIR = "./prompts";
776
- var DEFAULT_COMPILED_JSON_DIR = "./.generated-prompts/json";
777
- function withPromptResolutionDefaults(config) {
778
- return {
779
- ...config,
780
- sourceDir: config.sourceDir ?? DEFAULT_PROMPTS_DIR,
781
- compiledDir: config.compiledDir ?? DEFAULT_COMPILED_JSON_DIR
782
- };
783
- }
784
- var sharedPromptCache = new PromptCache();
785
- async function loadPromptAsset(promptPath, config, promptCache = sharedPromptCache) {
786
- const resolvedConfig = withPromptResolutionDefaults(config);
787
- const mode = resolvedConfig.mode ?? "auto";
788
- if (mode !== "source-only" && resolvedConfig.compiledDir) {
789
- const compiledFile = (0, import_node_path3.resolve)(resolvedConfig.compiledDir, promptPath + ".json");
790
- if ((0, import_node_fs2.existsSync)(compiledFile)) {
791
- if (mode === "auto") {
792
- const sourceFile = (0, import_node_path3.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
793
- if ((0, import_node_fs2.existsSync)(sourceFile)) {
794
- const compiledMtime = (0, import_node_fs2.statSync)(compiledFile).mtimeMs;
795
- const sourceMtime = (0, import_node_fs2.statSync)(sourceFile).mtimeMs;
796
- if (sourceMtime > compiledMtime) {
797
- console.warn(
798
- `[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
799
- Run "promptopskit compile" or switch to source-only mode.`
800
- );
801
- }
802
- }
803
- }
804
- const content = await (0, import_promises3.readFile)(compiledFile, "utf-8");
805
- return JSON.parse(content);
806
- }
807
- if (mode === "compiled-only") {
808
- throw new Error(
809
- `Compiled artifact not found: ${compiledFile}
810
- Run "promptopskit compile" to generate it.`
811
- );
812
- }
813
- }
814
- if (mode !== "compiled-only") {
815
- const sourceFile = (0, import_node_path3.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
816
- if (resolvedConfig.cache !== false) {
817
- const cached = promptCache.get(sourceFile);
818
- if (cached) {
819
- return cached;
820
- }
821
- }
822
- if (!(0, import_node_fs2.existsSync)(sourceFile)) {
823
- const paths = [sourceFile];
824
- if (resolvedConfig.compiledDir) {
825
- paths.unshift((0, import_node_path3.resolve)(resolvedConfig.compiledDir, promptPath + ".json"));
826
- }
827
- throw new Error(
828
- `Prompt not found: "${promptPath}"
829
- Searched:
830
- ${paths.map((candidate) => ` - ${candidate}`).join("\n")}`
831
- );
832
- }
833
- const { asset } = await loadPromptFile(sourceFile, { defaultsRoot: resolvedConfig.sourceDir });
834
- if (resolvedConfig.cache !== false) {
835
- promptCache.set(sourceFile, asset);
836
- }
837
- return asset;
838
- }
839
- throw new Error(`Prompt not found: "${promptPath}"`);
840
- }
841
- async function resolvePromptAsset(promptPath, config, options = {}, promptCache = sharedPromptCache) {
842
- const resolvedConfig = withPromptResolutionDefaults(config);
843
- let asset = await loadPromptAsset(promptPath, resolvedConfig, promptCache);
844
- const sourceFile = (0, import_node_path3.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
845
- if (asset.includes && asset.includes.length > 0 && (0, import_node_fs2.existsSync)(sourceFile)) {
846
- asset = await resolveIncludes(asset, sourceFile);
847
- }
848
- asset = applyOverrides(asset, {
849
- environment: options.environment,
850
- tier: options.tier,
851
- runtime: options.runtime
852
- });
853
- return asset;
854
- }
855
- function resolveInlinePromptSource(source, options = {}) {
856
- const { asset } = parsePrompt(source);
857
- return applyOverrides(asset, {
858
- environment: options.environment,
859
- tier: options.tier,
860
- runtime: options.runtime
861
- });
862
- }
863
-
864
- // src/context.ts
865
- var textEncoder = new TextEncoder();
866
- var REJECT_SECRETS_PATTERN = "(secret|api[_-]?key|password)";
867
- var REJECT_SECRETS_FLAGS = "i";
868
- function getContextInputs(asset) {
869
- return (asset.context?.inputs ?? []).map(normalizeContextInput);
870
- }
871
- function normalizeContextInput(input) {
872
- if (typeof input === "string") {
873
- return { name: input };
874
- }
931
+ };
932
+ const asset = PromptAssetSchema.parse(raw);
875
933
  return {
876
- name: input.name,
877
- max_size: input.max_size,
878
- trim: input.trim,
879
- allow_regex: normalizeContextRegex(input.allow_regex),
880
- deny_regex: normalizeContextRegex(input.deny_regex),
881
- non_empty: normalizeBuiltInValidator(input.non_empty),
882
- reject_secrets: normalizeBuiltInValidator(input.reject_secrets)
934
+ asset,
935
+ raw: {
936
+ frontMatter,
937
+ body
938
+ }
883
939
  };
884
940
  }
885
- function normalizeContextRegex(value) {
886
- if (value === void 0) {
887
- return void 0;
888
- }
889
- if (typeof value === "string") {
890
- const literal = parseRegexLiteral(value);
891
- if (value.startsWith("/") && !literal) {
892
- return {
893
- pattern: value,
894
- flags: "",
895
- raw: value,
896
- invalidLiteral: true
897
- };
941
+
942
+ // src/parser/loader.ts
943
+ var import_promises2 = require("fs/promises");
944
+ var import_node_path2 = require("path");
945
+ var import_gray_matter2 = __toESM(require("gray-matter"), 1);
946
+
947
+ // src/parser/response-schema-ref.ts
948
+ var import_promises = require("fs/promises");
949
+ var import_node_crypto = require("crypto");
950
+ var import_node_path = require("path");
951
+ var import_node_url = require("url");
952
+ var import_zod2 = require("zod");
953
+ var import_zod_to_json_schema = require("zod-to-json-schema");
954
+ var SUPPORTED_SCHEMA_REF_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
955
+ async function resolveJsonSchemaRef(schemaRef, promptFilePath) {
956
+ const resolvedPath = (0, import_node_path.resolve)((0, import_node_path.dirname)(promptFilePath), schemaRef);
957
+ let raw;
958
+ try {
959
+ raw = await (0, import_promises.readFile)(resolvedPath, "utf-8");
960
+ } catch (error) {
961
+ const code = error.code;
962
+ if (code === "ENOENT") {
963
+ throw new Error(`POK050: response.schema_ref "${schemaRef}" not found (resolved from ${promptFilePath})`);
898
964
  }
899
- return {
900
- pattern: literal?.pattern ?? value,
901
- flags: literal?.flags ?? "",
902
- raw: value
903
- };
965
+ throw error;
966
+ }
967
+ let parsed;
968
+ try {
969
+ parsed = JSON.parse(raw);
970
+ } catch {
971
+ throw new Error(`POK050: response.schema_ref "${schemaRef}" is not valid JSON`);
972
+ }
973
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
974
+ throw new Error(`POK050: response.schema_ref "${schemaRef}" must resolve to a JSON object schema`);
904
975
  }
905
976
  return {
906
- pattern: value.pattern,
907
- flags: value.flags ?? "",
908
- raw: JSON.stringify(value),
909
- returnMessage: value.return_message
977
+ schema: parsed,
978
+ resolvedPath,
979
+ hash: (0, import_node_crypto.createHash)("sha256").update(raw).digest("hex")
910
980
  };
911
981
  }
912
- function normalizeBuiltInValidator(value) {
913
- if (value === void 0 || value === false) {
914
- return void 0;
982
+ async function resolveZodSchemaRef(schemaRef, promptFilePath) {
983
+ const resolvedPath = (0, import_node_path.resolve)((0, import_node_path.dirname)(promptFilePath), schemaRef);
984
+ let moduleSource;
985
+ try {
986
+ moduleSource = await (0, import_promises.readFile)(resolvedPath, "utf-8");
987
+ } catch (error) {
988
+ const code = error.code;
989
+ if (code === "ENOENT") {
990
+ throw new Error(`POK051: response.schema_ref "${schemaRef}" not found (resolved from ${promptFilePath})`);
991
+ }
992
+ throw error;
915
993
  }
916
- if (value === true) {
917
- return {};
994
+ let imported;
995
+ try {
996
+ imported = await import((0, import_node_url.pathToFileURL)(resolvedPath).href);
997
+ } catch (error) {
998
+ const message = error instanceof Error ? error.message : String(error);
999
+ throw new Error(`POK051: response.schema_ref "${schemaRef}" could not be imported as a module (${message})`);
1000
+ }
1001
+ const mod = imported;
1002
+ const candidate = mod.default ?? mod.schema;
1003
+ if (!(candidate instanceof import_zod2.z.ZodType)) {
1004
+ throw new Error('POK051: zod schema modules must export a Zod schema as default export or named export "schema"');
1005
+ }
1006
+ const jsonSchema = (0, import_zod_to_json_schema.zodToJsonSchema)(candidate, {
1007
+ target: "jsonSchema7",
1008
+ $refStrategy: "none"
1009
+ });
1010
+ if (!jsonSchema || typeof jsonSchema !== "object" || Array.isArray(jsonSchema)) {
1011
+ throw new Error(`POK051: response.schema_ref "${schemaRef}" did not produce a valid JSON schema object`);
918
1012
  }
919
1013
  return {
920
- returnMessage: value.return_message
1014
+ schema: jsonSchema,
1015
+ resolvedPath,
1016
+ hash: (0, import_node_crypto.createHash)("sha256").update(moduleSource).digest("hex")
921
1017
  };
922
1018
  }
923
- function parseRegexLiteral(value) {
924
- if (!value.startsWith("/")) {
925
- return void 0;
1019
+ async function resolveResponseSchemaRef(asset, promptFilePath) {
1020
+ const schemaRef = asset.response?.schema_ref;
1021
+ if (!schemaRef) return asset;
1022
+ const ext = (0, import_node_path.extname)(schemaRef).toLowerCase();
1023
+ if (!SUPPORTED_SCHEMA_REF_EXTENSIONS.has(ext)) {
1024
+ throw new Error(`POK051: response.schema_ref "${schemaRef}" has unsupported extension "${ext}". Use .json, .js, .mjs, or .cjs`);
926
1025
  }
927
- for (let index = value.length - 1; index > 0; index -= 1) {
928
- if (value[index] !== "/") {
929
- continue;
1026
+ const resolved = ext === ".json" ? await resolveJsonSchemaRef(schemaRef, promptFilePath) : await resolveZodSchemaRef(schemaRef, promptFilePath);
1027
+ return {
1028
+ ...asset,
1029
+ response: {
1030
+ ...asset.response,
1031
+ schema: resolved.schema,
1032
+ schema_ref: void 0,
1033
+ schema_source: {
1034
+ mode: ext === ".json" ? "schema_ref_json" : "schema_ref_zod_module",
1035
+ ref: schemaRef,
1036
+ resolved_path: resolved.resolvedPath,
1037
+ hash: resolved.hash
1038
+ }
930
1039
  }
931
- let backslashCount = 0;
932
- for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
933
- backslashCount += 1;
1040
+ };
1041
+ }
1042
+
1043
+ // src/parser/loader.ts
1044
+ var DEFAULTS_FILE_NAME = "defaults.md";
1045
+ async function loadPromptFile(filePath, options = {}) {
1046
+ const content = await (0, import_promises2.readFile)(filePath, "utf-8");
1047
+ const parsed = parsePrompt(content, filePath);
1048
+ const root = options.defaultsRoot ?? (0, import_node_path2.dirname)(filePath);
1049
+ const defaults = await loadDefaultsForPath(filePath, root);
1050
+ const withDefaults = applyDefaults(parsed.asset, defaults);
1051
+ const resolved = await resolveResponseSchemaRef(withDefaults, filePath);
1052
+ const asset = resolved.response?.schema !== void 0 && !resolved.response?.schema_source ? {
1053
+ ...resolved,
1054
+ response: {
1055
+ ...resolved.response,
1056
+ schema_source: { mode: "inline" }
934
1057
  }
935
- if (backslashCount % 2 === 1) {
936
- continue;
1058
+ } : resolved;
1059
+ return {
1060
+ ...parsed,
1061
+ asset
1062
+ };
1063
+ }
1064
+ async function loadDefaultsForPath(filePath, defaultsRoot) {
1065
+ const directories = getDirectoriesToCheck(filePath, defaultsRoot);
1066
+ let merged = {};
1067
+ for (const dir of directories) {
1068
+ const defaultsPath = (0, import_node_path2.join)(dir, DEFAULTS_FILE_NAME);
1069
+ try {
1070
+ const defaultsContent = await (0, import_promises2.readFile)(defaultsPath, "utf-8");
1071
+ const defaults = normalizeDefaultIncludes(parseDefaults(defaultsContent), defaultsPath, filePath);
1072
+ merged = mergeDefaults(merged, defaults);
1073
+ } catch (error) {
1074
+ if (error.code !== "ENOENT") {
1075
+ throw error;
1076
+ }
937
1077
  }
938
- return {
939
- pattern: value.slice(1, index),
940
- flags: value.slice(index + 1)
941
- };
942
1078
  }
943
- return void 0;
944
- }
945
- function formatInvalidContextRegexMessage(details) {
946
- return [
947
- `Invalid context regex for prompt "${details.promptId}"`,
948
- `variable "${details.variable}"`,
949
- `field "${details.field}"`,
950
- `value ${JSON.stringify(details.raw)}: ${details.reason}`
951
- ].join(", ");
1079
+ return merged;
952
1080
  }
953
- function compileContextRegex(regex, details) {
954
- if (regex.invalidLiteral) {
955
- throw new Error(
956
- `POK013: ${formatInvalidContextRegexMessage({
957
- ...details,
958
- raw: regex.raw,
959
- reason: "Malformed regex literal. Use /pattern/flags or { pattern, flags }."
960
- })}`
961
- );
1081
+ function getDirectoriesToCheck(filePath, defaultsRoot) {
1082
+ const dirs = [];
1083
+ let current = (0, import_node_path2.resolve)((0, import_node_path2.dirname)(filePath));
1084
+ const boundary = defaultsRoot ? (0, import_node_path2.resolve)(defaultsRoot) : void 0;
1085
+ while (true) {
1086
+ dirs.unshift(current);
1087
+ if (boundary && current === boundary || current === (0, import_node_path2.dirname)(current)) {
1088
+ break;
1089
+ }
1090
+ current = (0, import_node_path2.dirname)(current);
962
1091
  }
963
- try {
964
- return new RegExp(regex.pattern, regex.flags);
965
- } catch (error) {
966
- const reason = error instanceof Error ? error.message : String(error);
967
- throw new Error(`POK013: ${formatInvalidContextRegexMessage({ ...details, raw: regex.raw, reason })}`);
1092
+ return dirs;
1093
+ }
1094
+ function parseDefaults(content) {
1095
+ const { data: frontMatter, content: body } = (0, import_gray_matter2.default)(content);
1096
+ const sections = extractSections(body);
1097
+ return PromptDefaultsSchema.parse({
1098
+ ...frontMatter,
1099
+ sections: {
1100
+ system_instructions: sections.system_instructions
1101
+ }
1102
+ });
1103
+ }
1104
+ function mergeDefaults(base, local) {
1105
+ return {
1106
+ provider: local.provider ?? base.provider,
1107
+ model: local.model ?? base.model,
1108
+ fallback_models: local.fallback_models ?? base.fallback_models,
1109
+ reasoning: mergeRecordBlock2(base.reasoning, local.reasoning),
1110
+ sampling: mergeRecordBlock2(base.sampling, local.sampling),
1111
+ response: mergeRecordBlock2(base.response, local.response),
1112
+ compression: mergeCompression(base.compression, local.compression),
1113
+ cache: mergeCache(base.cache, local.cache),
1114
+ raw: mergeRaw(base.raw, local.raw),
1115
+ tools: local.tools ?? base.tools,
1116
+ provider_options: mergeProviderOptions(base.provider_options, local.provider_options),
1117
+ mcp: mergeMcp(base.mcp, local.mcp),
1118
+ context: mergeContext(base.context, local.context),
1119
+ includes: local.includes ?? base.includes,
1120
+ environments: mergeOverrideMap(base.environments, local.environments),
1121
+ tiers: mergeOverrideMap(base.tiers, local.tiers),
1122
+ metadata: {
1123
+ ...base.metadata ?? {},
1124
+ ...local.metadata ?? {}
1125
+ },
1126
+ sections: {
1127
+ ...base.sections ?? {},
1128
+ ...local.sections ?? {}
1129
+ }
1130
+ };
1131
+ }
1132
+ function applyDefaults(asset, defaults) {
1133
+ const compression = mergeCompression(defaults.compression, asset.compression);
1134
+ const cache = mergeCache(defaults.cache, asset.cache);
1135
+ const raw = mergeRaw(defaults.raw, asset.raw);
1136
+ const providerOptions = mergeProviderOptions(defaults.provider_options, asset.provider_options);
1137
+ const reasoning = mergeRecordBlock2(defaults.reasoning, asset.reasoning);
1138
+ const sampling = mergeRecordBlock2(defaults.sampling, asset.sampling);
1139
+ const response = mergeRecordBlock2(defaults.response, asset.response);
1140
+ const mcp = mergeMcp(defaults.mcp, asset.mcp);
1141
+ const context = mergeContext(defaults.context, asset.context);
1142
+ const environments = mergeOverrideMap(defaults.environments, asset.environments);
1143
+ const tiers = mergeOverrideMap(defaults.tiers, asset.tiers);
1144
+ const hasDefaultMetadata = defaults.metadata && Object.keys(defaults.metadata).length > 0;
1145
+ const hasDefaultSystem = !!defaults.sections?.system_instructions;
1146
+ const hasDefaultScalars = defaults.provider !== void 0 || defaults.model !== void 0 || defaults.fallback_models !== void 0 || defaults.tools !== void 0 || defaults.includes !== void 0;
1147
+ const hasDefaultObjects = compression !== void 0 || cache !== void 0 || raw !== void 0 || providerOptions !== void 0 || reasoning !== void 0 || sampling !== void 0 || response !== void 0 || mcp !== void 0 || context !== void 0 || environments !== void 0 || tiers !== void 0;
1148
+ if (!hasDefaultMetadata && !hasDefaultSystem && !hasDefaultScalars && !hasDefaultObjects) {
1149
+ return asset;
968
1150
  }
1151
+ const mergedMetadata = {
1152
+ ...defaults.metadata ?? {},
1153
+ ...asset.metadata ?? {}
1154
+ };
1155
+ const metadata = Object.keys(mergedMetadata).length > 0 ? mergedMetadata : void 0;
1156
+ const systemInstructions = asset.sections?.system_instructions ?? defaults.sections?.system_instructions;
1157
+ const sections = asset.sections ? { ...asset.sections, system_instructions: systemInstructions } : systemInstructions ? { system_instructions: systemInstructions } : void 0;
1158
+ return {
1159
+ ...asset,
1160
+ provider: asset.provider ?? defaults.provider,
1161
+ model: asset.model ?? defaults.model,
1162
+ fallback_models: asset.fallback_models ?? defaults.fallback_models,
1163
+ reasoning,
1164
+ sampling,
1165
+ response,
1166
+ compression,
1167
+ cache,
1168
+ raw,
1169
+ tools: asset.tools ?? defaults.tools,
1170
+ provider_options: providerOptions,
1171
+ mcp,
1172
+ context,
1173
+ includes: asset.includes ?? defaults.includes,
1174
+ environments,
1175
+ tiers,
1176
+ metadata,
1177
+ sections
1178
+ };
969
1179
  }
970
- function getRejectSecretsRegex() {
1180
+ function normalizeDefaultIncludes(defaults, defaultsPath, filePath) {
1181
+ if (!defaults.includes) return defaults;
1182
+ const promptDir = (0, import_node_path2.dirname)(filePath);
1183
+ const defaultsDir = (0, import_node_path2.dirname)(defaultsPath);
1184
+ const includes = defaults.includes.map((includePath) => {
1185
+ const relativePath = (0, import_node_path2.relative)(promptDir, (0, import_node_path2.resolve)(defaultsDir, includePath)).replace(/\\/g, "/");
1186
+ return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
1187
+ });
971
1188
  return {
972
- pattern: REJECT_SECRETS_PATTERN,
973
- flags: REJECT_SECRETS_FLAGS,
974
- raw: JSON.stringify({ pattern: REJECT_SECRETS_PATTERN, flags: REJECT_SECRETS_FLAGS })
1189
+ ...defaults,
1190
+ includes
975
1191
  };
976
1192
  }
977
- function isTrimEnabled(mode) {
978
- return mode === true || mode === "start" || mode === "end" || mode === "both";
1193
+ function mergeRecordBlock2(base, local) {
1194
+ if (base === void 0) return local;
1195
+ if (local === void 0) return base;
1196
+ return { ...base, ...local };
979
1197
  }
980
- function normalizeTrimMode(mode) {
981
- if (mode === "start") {
982
- return "start";
983
- }
984
- return "end";
1198
+ function mergeMcp(base, local) {
1199
+ return mergeRecordBlock2(base, local);
985
1200
  }
986
- function trimToMaxSize(value, maxSize, mode) {
987
- const measured = measureContextValueSize(value);
988
- if (measured <= maxSize) {
989
- return value;
990
- }
991
- const characters = Array.from(value);
992
- const normalizedMode = normalizeTrimMode(mode);
993
- if (normalizedMode === "start") {
994
- let collected2 = "";
995
- let size2 = 0;
996
- for (let i = characters.length - 1; i >= 0; i -= 1) {
997
- const next = characters[i];
998
- const charSize = measureContextValueSize(next);
999
- if (size2 + charSize > maxSize) {
1000
- break;
1001
- }
1002
- collected2 = next + collected2;
1003
- size2 += charSize;
1004
- }
1005
- return collected2;
1006
- }
1007
- let collected = "";
1008
- let size = 0;
1009
- for (const char of characters) {
1010
- const charSize = measureContextValueSize(char);
1011
- if (size + charSize > maxSize) {
1012
- break;
1201
+ function mergeContext(base, local) {
1202
+ const merged = {
1203
+ ...base ?? {},
1204
+ ...local ?? {},
1205
+ history: mergeRecordBlock2(base?.history, local?.history)
1206
+ };
1207
+ return Object.keys(merged).length > 0 ? merged : void 0;
1208
+ }
1209
+ function mergeCache(base, local) {
1210
+ const merged = {
1211
+ ...base ?? {},
1212
+ ...local ?? {},
1213
+ openai: {
1214
+ ...base?.openai ?? {},
1215
+ ...local?.openai ?? {}
1216
+ },
1217
+ anthropic: {
1218
+ ...base?.anthropic ?? {},
1219
+ ...local?.anthropic ?? {}
1220
+ },
1221
+ gemini: {
1222
+ ...base?.gemini ?? {},
1223
+ ...local?.gemini ?? {}
1224
+ },
1225
+ google: {
1226
+ ...base?.google ?? {},
1227
+ ...local?.google ?? {}
1013
1228
  }
1014
- collected += char;
1015
- size += charSize;
1229
+ };
1230
+ if (merged.openai && Object.keys(merged.openai).length === 0) delete merged.openai;
1231
+ if (merged.anthropic && Object.keys(merged.anthropic).length === 0) delete merged.anthropic;
1232
+ if (merged.gemini && Object.keys(merged.gemini).length === 0) delete merged.gemini;
1233
+ if (merged.google && Object.keys(merged.google).length === 0) delete merged.google;
1234
+ return Object.keys(merged).length > 0 ? merged : void 0;
1235
+ }
1236
+ function mergeCompression(base, local) {
1237
+ const merged = {
1238
+ ...base ?? {},
1239
+ ...local ?? {},
1240
+ thetokencompany: mergeRecordBlock2(base?.thetokencompany, local?.thetokencompany)
1241
+ };
1242
+ removeEmptyProviderBlocks(merged);
1243
+ return Object.keys(merged).length > 0 ? merged : void 0;
1244
+ }
1245
+ function mergeRaw(base, local) {
1246
+ const merged = {
1247
+ ...base ?? {},
1248
+ ...local ?? {},
1249
+ openai: mergeRecordBlock2(base?.openai, local?.openai),
1250
+ "openai-responses": mergeRecordBlock2(base?.["openai-responses"], local?.["openai-responses"]),
1251
+ openai_responses: mergeRecordBlock2(base?.openai_responses, local?.openai_responses),
1252
+ anthropic: mergeRecordBlock2(base?.anthropic, local?.anthropic),
1253
+ gemini: mergeRecordBlock2(base?.gemini, local?.gemini),
1254
+ google: mergeRecordBlock2(base?.google, local?.google),
1255
+ openrouter: mergeRecordBlock2(base?.openrouter, local?.openrouter),
1256
+ llmasaservice: mergeRecordBlock2(base?.llmasaservice, local?.llmasaservice)
1257
+ };
1258
+ removeEmptyProviderBlocks(merged);
1259
+ return Object.keys(merged).length > 0 ? merged : void 0;
1260
+ }
1261
+ function mergeProviderOptions(base, local) {
1262
+ const merged = {
1263
+ ...base ?? {},
1264
+ ...local ?? {},
1265
+ anthropic: mergeRecordBlock2(base?.anthropic, local?.anthropic),
1266
+ gemini: mergeRecordBlock2(base?.gemini, local?.gemini),
1267
+ openrouter: mergeRecordBlock2(base?.openrouter, local?.openrouter),
1268
+ llmasaservice: mergeRecordBlock2(base?.llmasaservice, local?.llmasaservice)
1269
+ };
1270
+ removeEmptyProviderBlocks(merged);
1271
+ return Object.keys(merged).length > 0 ? merged : void 0;
1272
+ }
1273
+ function mergeOverrideMap(base, local) {
1274
+ const merged = { ...base ?? {} };
1275
+ for (const [name, localOverride] of Object.entries(local ?? {})) {
1276
+ merged[name] = mergeOverrideConfig(merged[name], localOverride);
1016
1277
  }
1017
- return collected;
1278
+ return Object.keys(merged).length > 0 ? merged : void 0;
1018
1279
  }
1019
- function sanitizeContextVariables(asset, variables = {}, options = {}) {
1020
- const { onContextOverflow } = options;
1021
- const sanitized = { ...variables };
1022
- for (const input of getContextInputs(asset)) {
1023
- const value = sanitized[input.name];
1024
- if (value === void 0) {
1280
+ function mergeOverrideConfig(base, local) {
1281
+ const merged = {
1282
+ ...base ?? {},
1283
+ ...local
1284
+ };
1285
+ const reasoning = mergeRecordBlock2(base?.reasoning, local.reasoning);
1286
+ const sampling = mergeRecordBlock2(base?.sampling, local.sampling);
1287
+ const response = mergeRecordBlock2(base?.response, local.response);
1288
+ const compression = mergeCompression(base?.compression, local.compression);
1289
+ const cache = mergeCache(base?.cache, local.cache);
1290
+ const raw = mergeRaw(base?.raw, local.raw);
1291
+ const providerOptions = mergeProviderOptions(base?.provider_options, local.provider_options);
1292
+ if (reasoning !== void 0) merged.reasoning = reasoning;
1293
+ if (sampling !== void 0) merged.sampling = sampling;
1294
+ if (response !== void 0) merged.response = response;
1295
+ if (compression !== void 0) merged.compression = compression;
1296
+ if (cache !== void 0) merged.cache = cache;
1297
+ if (raw !== void 0) merged.raw = raw;
1298
+ if (providerOptions !== void 0) merged.provider_options = providerOptions;
1299
+ return merged;
1300
+ }
1301
+ function removeEmptyProviderBlocks(value) {
1302
+ for (const key of Object.keys(value)) {
1303
+ const block = value[key];
1304
+ if (block === void 0) {
1305
+ delete value[key];
1025
1306
  continue;
1026
1307
  }
1027
- let candidate = value;
1028
- if (input.max_size !== void 0) {
1029
- const actualSize = measureContextValueSize(candidate);
1030
- if (actualSize > input.max_size && onContextOverflow) {
1031
- candidate = onContextOverflow({
1032
- promptId: asset.id,
1033
- variable: input.name,
1034
- value: candidate,
1035
- maxSize: input.max_size,
1036
- actualSize
1037
- });
1038
- }
1308
+ if (block !== null && typeof block === "object" && !Array.isArray(block) && Object.keys(block).length === 0) {
1309
+ delete value[key];
1039
1310
  }
1040
- if (isTrimEnabled(input.trim) && input.max_size !== void 0) {
1041
- candidate = trimToMaxSize(candidate, input.max_size, input.trim);
1311
+ }
1312
+ }
1313
+
1314
+ // src/composition/resolve-includes.ts
1315
+ async function resolveIncludes(asset, basePath, visited = /* @__PURE__ */ new Set()) {
1316
+ if (!asset.includes || asset.includes.length === 0) {
1317
+ return asset;
1318
+ }
1319
+ const baseDir = (0, import_node_path3.dirname)(basePath);
1320
+ const resolvedPath = (0, import_node_path3.resolve)(basePath);
1321
+ if (visited.has(resolvedPath)) {
1322
+ throw new Error(`Circular include detected: ${resolvedPath}`);
1323
+ }
1324
+ visited.add(resolvedPath);
1325
+ let mergedSystemInstructions = "";
1326
+ for (const includePath of asset.includes) {
1327
+ const fullPath = (0, import_node_path3.resolve)(baseDir, includePath);
1328
+ if (visited.has(fullPath)) {
1329
+ throw new Error(`Circular include detected: ${fullPath} (included from ${basePath})`);
1042
1330
  }
1043
- sanitized[input.name] = candidate;
1044
- if (input.allow_regex) {
1045
- const candidate2 = sanitized[input.name];
1046
- const matcher = compileContextRegex(input.allow_regex, {
1047
- promptId: asset.id,
1048
- variable: input.name,
1049
- field: "allow_regex"
1050
- });
1051
- if (!matcher.test(candidate2)) {
1052
- if (input.allow_regex.returnMessage) {
1053
- return {
1054
- variables: sanitized,
1055
- shortCircuit: {
1056
- returnMessage: input.allow_regex.returnMessage,
1057
- code: "POK031",
1058
- variable: input.name,
1059
- field: "allow_regex"
1060
- }
1061
- };
1331
+ const content = await (0, import_promises3.readFile)(fullPath, "utf-8");
1332
+ const { asset: includedAsset } = parsePrompt(content, fullPath);
1333
+ const resolved = await resolveIncludes(includedAsset, fullPath, new Set(visited));
1334
+ if (resolved.sections?.system_instructions) {
1335
+ mergedSystemInstructions += resolved.sections.system_instructions + "\n\n";
1336
+ }
1337
+ }
1338
+ const localSystem = asset.sections?.system_instructions ?? "";
1339
+ const combinedSystem = (mergedSystemInstructions + localSystem).trim() || void 0;
1340
+ return {
1341
+ ...asset,
1342
+ sections: {
1343
+ ...asset.sections,
1344
+ system_instructions: combinedSystem
1345
+ },
1346
+ // Drop includes from the resolved asset — they've been inlined
1347
+ includes: void 0
1348
+ };
1349
+ }
1350
+
1351
+ // src/prompt-resolution.ts
1352
+ var DEFAULT_PROMPTS_DIR = "./prompts";
1353
+ var DEFAULT_COMPILED_JSON_DIR = "./.generated-prompts/json";
1354
+ function withPromptResolutionDefaults(config) {
1355
+ return {
1356
+ ...config,
1357
+ sourceDir: config.sourceDir ?? DEFAULT_PROMPTS_DIR,
1358
+ compiledDir: config.compiledDir ?? DEFAULT_COMPILED_JSON_DIR
1359
+ };
1360
+ }
1361
+ var sharedPromptCache = new PromptCache();
1362
+ async function loadPromptAsset(promptPath, config, promptCache = sharedPromptCache) {
1363
+ const resolvedConfig = withPromptResolutionDefaults(config);
1364
+ const mode = resolvedConfig.mode ?? "auto";
1365
+ if (mode !== "source-only" && resolvedConfig.compiledDir) {
1366
+ const compiledFile = (0, import_node_path4.resolve)(resolvedConfig.compiledDir, promptPath + ".json");
1367
+ if ((0, import_node_fs2.existsSync)(compiledFile)) {
1368
+ if (mode === "auto") {
1369
+ const sourceFile = (0, import_node_path4.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
1370
+ if ((0, import_node_fs2.existsSync)(sourceFile)) {
1371
+ const compiledMtime = (0, import_node_fs2.statSync)(compiledFile).mtimeMs;
1372
+ const sourceMtime = (0, import_node_fs2.statSync)(sourceFile).mtimeMs;
1373
+ if (sourceMtime > compiledMtime) {
1374
+ console.warn(
1375
+ `[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
1376
+ Run "promptopskit compile" or switch to source-only mode.`
1377
+ );
1378
+ }
1062
1379
  }
1063
- throw new Error(
1064
- `POK031: Context variable "${input.name}" failed allow_regex validation for prompt "${asset.id}".`
1065
- );
1066
1380
  }
1381
+ const content = await (0, import_promises4.readFile)(compiledFile, "utf-8");
1382
+ return JSON.parse(content);
1067
1383
  }
1068
- if (input.deny_regex) {
1069
- const candidate2 = sanitized[input.name];
1070
- const matcher = compileContextRegex(input.deny_regex, {
1071
- promptId: asset.id,
1072
- variable: input.name,
1073
- field: "deny_regex"
1074
- });
1075
- if (matcher.test(candidate2)) {
1076
- if (input.deny_regex.returnMessage) {
1077
- return {
1078
- variables: sanitized,
1079
- shortCircuit: {
1080
- returnMessage: input.deny_regex.returnMessage,
1081
- code: "POK032",
1082
- variable: input.name,
1083
- field: "deny_regex"
1084
- }
1085
- };
1086
- }
1087
- throw new Error(
1088
- `POK032: Context variable "${input.name}" matched deny_regex for prompt "${asset.id}".`
1089
- );
1384
+ if (mode === "compiled-only") {
1385
+ throw new Error(
1386
+ `Compiled artifact not found: ${compiledFile}
1387
+ Run "promptopskit compile" to generate it.`
1388
+ );
1389
+ }
1390
+ }
1391
+ if (mode !== "compiled-only") {
1392
+ const sourceFile = (0, import_node_path4.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
1393
+ if (resolvedConfig.cache !== false) {
1394
+ const cached = promptCache.get(sourceFile);
1395
+ if (cached) {
1396
+ return cached;
1090
1397
  }
1091
1398
  }
1092
- if (input.non_empty && candidate.trim().length === 0) {
1093
- if (input.non_empty.returnMessage) {
1094
- return {
1095
- variables: sanitized,
1096
- shortCircuit: {
1097
- returnMessage: input.non_empty.returnMessage,
1098
- code: "POK033",
1099
- variable: input.name,
1100
- field: "non_empty"
1101
- }
1102
- };
1399
+ if (!(0, import_node_fs2.existsSync)(sourceFile)) {
1400
+ const paths = [sourceFile];
1401
+ if (resolvedConfig.compiledDir) {
1402
+ paths.unshift((0, import_node_path4.resolve)(resolvedConfig.compiledDir, promptPath + ".json"));
1103
1403
  }
1104
1404
  throw new Error(
1105
- `POK033: Context variable "${input.name}" failed non_empty validation for prompt "${asset.id}".`
1405
+ `Prompt not found: "${promptPath}"
1406
+ Searched:
1407
+ ${paths.map((candidate) => ` - ${candidate}`).join("\n")}`
1106
1408
  );
1107
1409
  }
1108
- if (input.reject_secrets) {
1109
- const matcher = compileContextRegex(getRejectSecretsRegex(), {
1110
- promptId: asset.id,
1111
- variable: input.name,
1112
- field: "reject_secrets"
1113
- });
1114
- if (matcher.test(candidate)) {
1115
- if (input.reject_secrets.returnMessage) {
1116
- return {
1117
- variables: sanitized,
1118
- shortCircuit: {
1119
- returnMessage: input.reject_secrets.returnMessage,
1120
- code: "POK034",
1121
- variable: input.name,
1122
- field: "reject_secrets"
1123
- }
1124
- };
1125
- }
1126
- throw new Error(
1127
- `POK034: Context variable "${input.name}" matched reject_secrets validation for prompt "${asset.id}".`
1128
- );
1129
- }
1410
+ const { asset } = await loadPromptFile(sourceFile, { defaultsRoot: resolvedConfig.sourceDir });
1411
+ if (resolvedConfig.cache !== false) {
1412
+ promptCache.set(sourceFile, asset);
1130
1413
  }
1414
+ return asset;
1131
1415
  }
1132
- return { variables: sanitized };
1416
+ throw new Error(`Prompt not found: "${promptPath}"`);
1133
1417
  }
1134
- function measureContextValueSize(value) {
1135
- return textEncoder.encode(value).length;
1418
+ async function resolvePromptAsset(promptPath, config, options = {}, promptCache = sharedPromptCache) {
1419
+ const resolvedConfig = withPromptResolutionDefaults(config);
1420
+ let asset = await loadPromptAsset(promptPath, resolvedConfig, promptCache);
1421
+ const sourceFile = (0, import_node_path4.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
1422
+ if (asset.includes && asset.includes.length > 0 && (0, import_node_fs2.existsSync)(sourceFile)) {
1423
+ asset = await resolveIncludes(asset, sourceFile);
1424
+ }
1425
+ asset = applyOverrides(asset, {
1426
+ environment: options.environment,
1427
+ tier: options.tier,
1428
+ runtime: options.runtime
1429
+ });
1430
+ return asset;
1431
+ }
1432
+ function resolveInlinePromptSource(source, options = {}) {
1433
+ const { asset } = parsePrompt(source);
1434
+ return applyOverrides(asset, {
1435
+ environment: options.environment,
1436
+ tier: options.tier,
1437
+ runtime: options.runtime
1438
+ });
1136
1439
  }
1137
1440
 
1138
1441
  // src/history.ts
@@ -1185,6 +1488,97 @@ function compactHistoryForPrompt(asset, runtime) {
1185
1488
  return [compacted, ...preserved];
1186
1489
  }
1187
1490
 
1491
+ // src/compression.ts
1492
+ var THETOKENCOMPANY_DEFAULT_MODEL = "bear-2";
1493
+ var THETOKENCOMPANY_DEFAULT_BASE_URL = "https://api.thetokencompany.com";
1494
+ async function applyPromptCompressionForRender(asset, runtime) {
1495
+ const config = asset.compression?.thetokencompany;
1496
+ if (config?.enabled !== true || !asset.sections.prompt_template) {
1497
+ return { asset, runtime, compression: [] };
1498
+ }
1499
+ const sections = renderSections(asset, {
1500
+ variables: runtime.variables,
1501
+ strict: runtime.strict
1502
+ });
1503
+ if (!sections.prompt_template) {
1504
+ return { asset, runtime, compression: [] };
1505
+ }
1506
+ const model = config.model ?? THETOKENCOMPANY_DEFAULT_MODEL;
1507
+ const result = await compressWithTheTokenCompany(sections.prompt_template, {
1508
+ apiKey: runtime.theTokenCompany?.apiKey,
1509
+ baseURL: runtime.theTokenCompany?.baseURL,
1510
+ fetch: runtime.theTokenCompany?.fetch,
1511
+ model,
1512
+ aggressiveness: config.aggressiveness
1513
+ });
1514
+ return {
1515
+ asset: {
1516
+ ...asset,
1517
+ sections: {
1518
+ ...asset.sections,
1519
+ ...sections,
1520
+ prompt_template: result.output
1521
+ }
1522
+ },
1523
+ runtime: {
1524
+ ...runtime,
1525
+ variables: {},
1526
+ strict: false
1527
+ },
1528
+ compression: [{
1529
+ provider: "thetokencompany",
1530
+ model,
1531
+ inputTokens: result.input_tokens,
1532
+ outputTokens: result.output_tokens,
1533
+ tokensSaved: result.tokens_saved,
1534
+ compressionRatio: result.compression_ratio
1535
+ }]
1536
+ };
1537
+ }
1538
+ async function compressWithTheTokenCompany(input, options) {
1539
+ const apiKey = options.apiKey ?? getEnv("THETOKENCOMPANY_API_KEY") ?? getEnv("TTC_API_KEY");
1540
+ if (!apiKey) {
1541
+ throw new Error(
1542
+ "TheTokenCompany compression is enabled, but no API key was provided. Pass theTokenCompany.apiKey to renderPrompt() or set THETOKENCOMPANY_API_KEY."
1543
+ );
1544
+ }
1545
+ const fetchImpl = options.fetch ?? globalThis.fetch;
1546
+ if (!fetchImpl) {
1547
+ throw new Error("TheTokenCompany compression requires a runtime with fetch support.");
1548
+ }
1549
+ const baseURL = (options.baseURL ?? THETOKENCOMPANY_DEFAULT_BASE_URL).replace(/\/+$/, "");
1550
+ const compressionSettings = options.aggressiveness === void 0 ? void 0 : { aggressiveness: options.aggressiveness };
1551
+ const response = await fetchImpl(`${baseURL}/v1/compress`, {
1552
+ method: "POST",
1553
+ headers: {
1554
+ Authorization: `Bearer ${apiKey}`,
1555
+ "Content-Type": "application/json"
1556
+ },
1557
+ body: JSON.stringify({
1558
+ model: options.model,
1559
+ input,
1560
+ ...compressionSettings ? { compression_settings: compressionSettings } : {}
1561
+ })
1562
+ });
1563
+ if (!response.ok) {
1564
+ const body = await response.text().catch(() => "");
1565
+ throw new Error(
1566
+ `TheTokenCompany compression failed with HTTP ${response.status}` + (body ? `: ${body}` : ".")
1567
+ );
1568
+ }
1569
+ const data = await response.json();
1570
+ if (typeof data.output !== "string" || typeof data.output_tokens !== "number" || typeof data.input_tokens !== "number" || typeof data.tokens_saved !== "number" || typeof data.compression_ratio !== "number") {
1571
+ throw new Error("TheTokenCompany compression returned an invalid response payload.");
1572
+ }
1573
+ return data;
1574
+ }
1575
+ function getEnv(name) {
1576
+ if (typeof process === "undefined") {
1577
+ return void 0;
1578
+ }
1579
+ return process.env[name];
1580
+ }
1581
+
1188
1582
  // src/providers/prompt-input.ts
1189
1583
  function isPromptLookup(input) {
1190
1584
  return "path" in input && typeof input.path === "string";
@@ -1208,21 +1602,27 @@ function withPromptInputSupport(adapter) {
1208
1602
  };
1209
1603
  const renderPrompt = async (input, runtime) => {
1210
1604
  const resolved = await resolveProviderPromptInput(input, runtime);
1211
- const sanitization = sanitizeContextVariables(resolved, runtime.variables, {
1605
+ const resolvedForRender = resolveAssetForProvider(resolved, runtime);
1606
+ const sanitization = sanitizeContextVariables(resolvedForRender, runtime.variables, {
1212
1607
  onContextOverflow: runtime.onContextOverflow
1213
1608
  });
1214
1609
  if (sanitization.shortCircuit) {
1215
1610
  return {
1216
1611
  provider: adapter.name,
1217
- model: resolved.model ?? "",
1612
+ model: resolvedForRender.model ?? "",
1218
1613
  returnMessage: sanitization.shortCircuit.returnMessage
1219
1614
  };
1220
1615
  }
1221
- return adapter.render(resolved, {
1616
+ const prepared = await applyPromptCompressionForRender(resolvedForRender, {
1222
1617
  ...runtime,
1618
+ environment: void 0,
1619
+ tier: void 0,
1620
+ runtime: void 0,
1223
1621
  variables: sanitization.variables,
1224
- history: compactHistoryForPrompt(resolved, runtime)
1622
+ history: compactHistoryForPrompt(resolvedForRender, runtime)
1225
1623
  });
1624
+ const request = adapter.render(prepared.asset, prepared.runtime);
1625
+ return prepared.compression.length > 0 ? { ...request, compression: prepared.compression } : request;
1226
1626
  };
1227
1627
  return {
1228
1628
  ...adapter,