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