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
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  loadPromptFile,
3
3
  parsePrompt
4
- } from "./chunk-K6ZU3CGV.js";
4
+ } from "./chunk-ULVY473P.js";
5
5
 
6
6
  // src/renderer/interpolate.ts
7
7
  var VARIABLE_RE = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
@@ -9,12 +9,13 @@ var ESCAPED_OPEN = /\\\{\\\{/g;
9
9
  var ESCAPE_PLACEHOLDER = "\0ESCAPED_OPEN\0";
10
10
  function interpolate(template, variables, options = {}) {
11
11
  const { strict = false } = options;
12
+ const optionalVariables = new Set(options.optionalVariables ?? []);
12
13
  let result = template.replace(ESCAPED_OPEN, ESCAPE_PLACEHOLDER);
13
14
  result = result.replace(VARIABLE_RE, (match, name) => {
14
15
  if (name in variables) {
15
16
  return variables[name];
16
17
  }
17
- if (strict) {
18
+ if (strict && !optionalVariables.has(name)) {
18
19
  throw new Error(`Missing required variable: "${name}"`);
19
20
  }
20
21
  return match;
@@ -32,298 +33,6 @@ function extractVariables(template) {
32
33
  return [...vars];
33
34
  }
34
35
 
35
- // src/renderer/renderer.ts
36
- function renderSections(asset, options = {}) {
37
- const { variables = {}, strict = false } = options;
38
- const result = {};
39
- if (asset.sections.system_instructions) {
40
- result.system_instructions = interpolate(
41
- asset.sections.system_instructions,
42
- variables,
43
- { strict }
44
- );
45
- }
46
- if (asset.sections.prompt_template) {
47
- result.prompt_template = interpolate(
48
- asset.sections.prompt_template,
49
- variables,
50
- { strict }
51
- );
52
- }
53
- return result;
54
- }
55
-
56
- // src/overrides/apply-overrides.ts
57
- function applyOverrides(asset, options = {}) {
58
- let result = { ...asset };
59
- if (options.environment && result.environments?.[options.environment]) {
60
- result = mergeOverride(result, result.environments[options.environment]);
61
- }
62
- if (options.tier && result.tiers?.[options.tier]) {
63
- result = mergeOverride(result, result.tiers[options.tier]);
64
- }
65
- if (options.runtime) {
66
- result = mergeOverride(result, options.runtime);
67
- }
68
- return result;
69
- }
70
- function mergeOverride(base, override) {
71
- const result = { ...base };
72
- if (override.model !== void 0) result.model = override.model;
73
- if (override.fallback_models !== void 0) result.fallback_models = override.fallback_models;
74
- if (override.tools !== void 0) result.tools = override.tools;
75
- if (override.reasoning !== void 0) {
76
- result.reasoning = { ...result.reasoning, ...override.reasoning };
77
- }
78
- if (override.sampling !== void 0) {
79
- result.sampling = { ...result.sampling, ...override.sampling };
80
- }
81
- if (override.response !== void 0) {
82
- result.response = { ...result.response, ...override.response };
83
- }
84
- if (override.cache !== void 0) {
85
- result.cache = {
86
- ...result.cache,
87
- ...override.cache,
88
- openai: mergeRecordBlock(result.cache?.openai, override.cache.openai),
89
- anthropic: mergeRecordBlock(result.cache?.anthropic, override.cache.anthropic),
90
- gemini: mergeRecordBlock(result.cache?.gemini, override.cache.gemini),
91
- google: mergeRecordBlock(result.cache?.google, override.cache.google)
92
- };
93
- }
94
- if (override.raw !== void 0) {
95
- result.raw = {
96
- ...result.raw,
97
- ...override.raw,
98
- openai: mergeRecordBlock(result.raw?.openai, override.raw.openai),
99
- "openai-responses": mergeRecordBlock(result.raw?.["openai-responses"], override.raw["openai-responses"]),
100
- openai_responses: mergeRecordBlock(result.raw?.openai_responses, override.raw.openai_responses),
101
- anthropic: mergeRecordBlock(result.raw?.anthropic, override.raw.anthropic),
102
- gemini: mergeRecordBlock(result.raw?.gemini, override.raw.gemini),
103
- google: mergeRecordBlock(result.raw?.google, override.raw.google),
104
- openrouter: mergeRecordBlock(result.raw?.openrouter, override.raw.openrouter),
105
- llmasaservice: mergeRecordBlock(result.raw?.llmasaservice, override.raw.llmasaservice)
106
- };
107
- }
108
- if (override.provider_options !== void 0) {
109
- result.provider_options = {
110
- ...result.provider_options,
111
- ...override.provider_options,
112
- anthropic: {
113
- ...result.provider_options?.anthropic,
114
- ...override.provider_options.anthropic
115
- },
116
- gemini: {
117
- ...result.provider_options?.gemini,
118
- ...override.provider_options.gemini
119
- },
120
- openrouter: {
121
- ...result.provider_options?.openrouter,
122
- ...override.provider_options.openrouter
123
- },
124
- llmasaservice: {
125
- ...result.provider_options?.llmasaservice,
126
- ...override.provider_options.llmasaservice
127
- }
128
- };
129
- }
130
- return result;
131
- }
132
- function mergeRecordBlock(base, override) {
133
- if (override === void 0) return base;
134
- return { ...base, ...override };
135
- }
136
-
137
- // src/providers/resolve-asset.ts
138
- function resolveAssetForProvider(asset, runtime = {}) {
139
- if (!runtime.environment && !runtime.tier && !runtime.runtime) {
140
- return asset;
141
- }
142
- return applyOverrides(asset, {
143
- environment: runtime.environment,
144
- tier: runtime.tier,
145
- runtime: runtime.runtime
146
- });
147
- }
148
-
149
- // src/cache.ts
150
- import { statSync } from "fs";
151
- var PromptCache = class {
152
- cache = /* @__PURE__ */ new Map();
153
- maxSize;
154
- constructor(maxSize = 100) {
155
- this.maxSize = maxSize;
156
- }
157
- get(filePath) {
158
- const entry = this.cache.get(filePath);
159
- if (!entry) return void 0;
160
- try {
161
- const stat = statSync(filePath);
162
- if (stat.mtimeMs !== entry.mtime) {
163
- this.cache.delete(filePath);
164
- return void 0;
165
- }
166
- } catch {
167
- this.cache.delete(filePath);
168
- return void 0;
169
- }
170
- this.cache.delete(filePath);
171
- this.cache.set(filePath, entry);
172
- return entry.value;
173
- }
174
- set(filePath, value) {
175
- try {
176
- const stat = statSync(filePath);
177
- if (this.cache.has(filePath)) {
178
- this.cache.delete(filePath);
179
- } else if (this.cache.size >= this.maxSize) {
180
- const oldest = this.cache.keys().next().value;
181
- if (oldest) this.cache.delete(oldest);
182
- }
183
- this.cache.set(filePath, { value, mtime: stat.mtimeMs });
184
- } catch {
185
- }
186
- }
187
- clear() {
188
- this.cache.clear();
189
- }
190
- get size() {
191
- return this.cache.size;
192
- }
193
- };
194
-
195
- // src/composition/resolve-includes.ts
196
- import { readFile } from "fs/promises";
197
- import { resolve, dirname } from "path";
198
- async function resolveIncludes(asset, basePath, visited = /* @__PURE__ */ new Set()) {
199
- if (!asset.includes || asset.includes.length === 0) {
200
- return asset;
201
- }
202
- const baseDir = dirname(basePath);
203
- const resolvedPath = resolve(basePath);
204
- if (visited.has(resolvedPath)) {
205
- throw new Error(`Circular include detected: ${resolvedPath}`);
206
- }
207
- visited.add(resolvedPath);
208
- let mergedSystemInstructions = "";
209
- for (const includePath of asset.includes) {
210
- const fullPath = resolve(baseDir, includePath);
211
- if (visited.has(fullPath)) {
212
- throw new Error(`Circular include detected: ${fullPath} (included from ${basePath})`);
213
- }
214
- const content = await readFile(fullPath, "utf-8");
215
- const { asset: includedAsset } = parsePrompt(content, fullPath);
216
- const resolved = await resolveIncludes(includedAsset, fullPath, new Set(visited));
217
- if (resolved.sections?.system_instructions) {
218
- mergedSystemInstructions += resolved.sections.system_instructions + "\n\n";
219
- }
220
- }
221
- const localSystem = asset.sections?.system_instructions ?? "";
222
- const combinedSystem = (mergedSystemInstructions + localSystem).trim() || void 0;
223
- return {
224
- ...asset,
225
- sections: {
226
- ...asset.sections,
227
- system_instructions: combinedSystem
228
- },
229
- // Drop includes from the resolved asset — they've been inlined
230
- includes: void 0
231
- };
232
- }
233
-
234
- // src/prompt-resolution.ts
235
- import { readFile as readFile2 } from "fs/promises";
236
- import { existsSync, statSync as statSync2 } from "fs";
237
- import { resolve as resolve2 } from "path";
238
- var DEFAULT_PROMPTS_DIR = "./prompts";
239
- var DEFAULT_COMPILED_JSON_DIR = "./.generated-prompts/json";
240
- function withPromptResolutionDefaults(config) {
241
- return {
242
- ...config,
243
- sourceDir: config.sourceDir ?? DEFAULT_PROMPTS_DIR,
244
- compiledDir: config.compiledDir ?? DEFAULT_COMPILED_JSON_DIR
245
- };
246
- }
247
- var sharedPromptCache = new PromptCache();
248
- async function loadPromptAsset(promptPath, config, promptCache = sharedPromptCache) {
249
- const resolvedConfig = withPromptResolutionDefaults(config);
250
- const mode = resolvedConfig.mode ?? "auto";
251
- if (mode !== "source-only" && resolvedConfig.compiledDir) {
252
- const compiledFile = resolve2(resolvedConfig.compiledDir, promptPath + ".json");
253
- if (existsSync(compiledFile)) {
254
- if (mode === "auto") {
255
- const sourceFile = resolve2(resolvedConfig.sourceDir, promptPath + ".md");
256
- if (existsSync(sourceFile)) {
257
- const compiledMtime = statSync2(compiledFile).mtimeMs;
258
- const sourceMtime = statSync2(sourceFile).mtimeMs;
259
- if (sourceMtime > compiledMtime) {
260
- console.warn(
261
- `[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
262
- Run "promptopskit compile" or switch to source-only mode.`
263
- );
264
- }
265
- }
266
- }
267
- const content = await readFile2(compiledFile, "utf-8");
268
- return JSON.parse(content);
269
- }
270
- if (mode === "compiled-only") {
271
- throw new Error(
272
- `Compiled artifact not found: ${compiledFile}
273
- Run "promptopskit compile" to generate it.`
274
- );
275
- }
276
- }
277
- if (mode !== "compiled-only") {
278
- const sourceFile = resolve2(resolvedConfig.sourceDir, promptPath + ".md");
279
- if (resolvedConfig.cache !== false) {
280
- const cached = promptCache.get(sourceFile);
281
- if (cached) {
282
- return cached;
283
- }
284
- }
285
- if (!existsSync(sourceFile)) {
286
- const paths = [sourceFile];
287
- if (resolvedConfig.compiledDir) {
288
- paths.unshift(resolve2(resolvedConfig.compiledDir, promptPath + ".json"));
289
- }
290
- throw new Error(
291
- `Prompt not found: "${promptPath}"
292
- Searched:
293
- ${paths.map((candidate) => ` - ${candidate}`).join("\n")}`
294
- );
295
- }
296
- const { asset } = await loadPromptFile(sourceFile, { defaultsRoot: resolvedConfig.sourceDir });
297
- if (resolvedConfig.cache !== false) {
298
- promptCache.set(sourceFile, asset);
299
- }
300
- return asset;
301
- }
302
- throw new Error(`Prompt not found: "${promptPath}"`);
303
- }
304
- async function resolvePromptAsset(promptPath, config, options = {}, promptCache = sharedPromptCache) {
305
- const resolvedConfig = withPromptResolutionDefaults(config);
306
- let asset = await loadPromptAsset(promptPath, resolvedConfig, promptCache);
307
- const sourceFile = resolve2(resolvedConfig.sourceDir, promptPath + ".md");
308
- if (asset.includes && asset.includes.length > 0 && existsSync(sourceFile)) {
309
- asset = await resolveIncludes(asset, sourceFile);
310
- }
311
- asset = applyOverrides(asset, {
312
- environment: options.environment,
313
- tier: options.tier,
314
- runtime: options.runtime
315
- });
316
- return asset;
317
- }
318
- function resolveInlinePromptSource(source, options = {}) {
319
- const { asset } = parsePrompt(source);
320
- return applyOverrides(asset, {
321
- environment: options.environment,
322
- tier: options.tier,
323
- runtime: options.runtime
324
- });
325
- }
326
-
327
36
  // src/context.ts
328
37
  var textEncoder = new TextEncoder();
329
38
  var REJECT_SECRETS_PATTERN = "(secret|api[_-]?key|password)";
@@ -331,15 +40,14 @@ var REJECT_SECRETS_FLAGS = "i";
331
40
  function getContextInputs(asset) {
332
41
  return (asset.context?.inputs ?? []).map(normalizeContextInput);
333
42
  }
334
- function getContextInputNames(asset) {
335
- return getContextInputs(asset).map((input) => input.name);
336
- }
337
43
  function normalizeContextInput(input) {
338
44
  if (typeof input === "string") {
339
45
  return { name: input };
340
46
  }
341
47
  return {
342
48
  name: input.name,
49
+ optional: input.optional,
50
+ warnings: input.warnings,
343
51
  max_size: input.max_size,
344
52
  trim: input.trim,
345
53
  allow_regex: normalizeContextRegex(input.allow_regex),
@@ -348,6 +56,9 @@ function normalizeContextInput(input) {
348
56
  reject_secrets: normalizeBuiltInValidator(input.reject_secrets)
349
57
  };
350
58
  }
59
+ function areContextInputWarningsEnabled(input) {
60
+ return input.warnings !== false;
61
+ }
351
62
  function normalizeContextRegex(value) {
352
63
  if (value === void 0) {
353
64
  return void 0;
@@ -390,236 +101,542 @@ function parseRegexLiteral(value) {
390
101
  if (!value.startsWith("/")) {
391
102
  return void 0;
392
103
  }
393
- for (let index = value.length - 1; index > 0; index -= 1) {
394
- if (value[index] !== "/") {
104
+ for (let index = value.length - 1; index > 0; index -= 1) {
105
+ if (value[index] !== "/") {
106
+ continue;
107
+ }
108
+ let backslashCount = 0;
109
+ for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
110
+ backslashCount += 1;
111
+ }
112
+ if (backslashCount % 2 === 1) {
113
+ continue;
114
+ }
115
+ return {
116
+ pattern: value.slice(1, index),
117
+ flags: value.slice(index + 1)
118
+ };
119
+ }
120
+ return void 0;
121
+ }
122
+ function formatInvalidContextRegexMessage(details) {
123
+ return [
124
+ `Invalid context regex for prompt "${details.promptId}"`,
125
+ `variable "${details.variable}"`,
126
+ `field "${details.field}"`,
127
+ `value ${JSON.stringify(details.raw)}: ${details.reason}`
128
+ ].join(", ");
129
+ }
130
+ function compileContextRegex(regex, details) {
131
+ if (regex.invalidLiteral) {
132
+ throw new Error(
133
+ `POK013: ${formatInvalidContextRegexMessage({
134
+ ...details,
135
+ raw: regex.raw,
136
+ reason: "Malformed regex literal. Use /pattern/flags or { pattern, flags }."
137
+ })}`
138
+ );
139
+ }
140
+ try {
141
+ return new RegExp(regex.pattern, regex.flags);
142
+ } catch (error) {
143
+ const reason = error instanceof Error ? error.message : String(error);
144
+ throw new Error(`POK013: ${formatInvalidContextRegexMessage({ ...details, raw: regex.raw, reason })}`);
145
+ }
146
+ }
147
+ function getRejectSecretsRegex() {
148
+ return {
149
+ pattern: REJECT_SECRETS_PATTERN,
150
+ flags: REJECT_SECRETS_FLAGS,
151
+ raw: JSON.stringify({ pattern: REJECT_SECRETS_PATTERN, flags: REJECT_SECRETS_FLAGS })
152
+ };
153
+ }
154
+ function isTrimEnabled(mode) {
155
+ return mode === true || mode === "start" || mode === "end" || mode === "both";
156
+ }
157
+ function normalizeTrimMode(mode) {
158
+ if (mode === "start") {
159
+ return "start";
160
+ }
161
+ return "end";
162
+ }
163
+ function trimToMaxSize(value, maxSize, mode) {
164
+ const measured = measureContextValueSize(value);
165
+ if (measured <= maxSize) {
166
+ return value;
167
+ }
168
+ const characters = Array.from(value);
169
+ const normalizedMode = normalizeTrimMode(mode);
170
+ if (normalizedMode === "start") {
171
+ let collected2 = "";
172
+ let size2 = 0;
173
+ for (let i = characters.length - 1; i >= 0; i -= 1) {
174
+ const next = characters[i];
175
+ const charSize = measureContextValueSize(next);
176
+ if (size2 + charSize > maxSize) {
177
+ break;
178
+ }
179
+ collected2 = next + collected2;
180
+ size2 += charSize;
181
+ }
182
+ return collected2;
183
+ }
184
+ let collected = "";
185
+ let size = 0;
186
+ for (const char of characters) {
187
+ const charSize = measureContextValueSize(char);
188
+ if (size + charSize > maxSize) {
189
+ break;
190
+ }
191
+ collected += char;
192
+ size += charSize;
193
+ }
194
+ return collected;
195
+ }
196
+ function sanitizeContextVariables(asset, variables = {}, options = {}) {
197
+ const { onContextOverflow } = options;
198
+ const sanitized = { ...variables };
199
+ for (const input of getContextInputs(asset)) {
200
+ const value = sanitized[input.name];
201
+ if (value === void 0) {
202
+ continue;
203
+ }
204
+ let candidate = value;
205
+ if (input.max_size !== void 0) {
206
+ const actualSize = measureContextValueSize(candidate);
207
+ if (actualSize > input.max_size && onContextOverflow) {
208
+ candidate = onContextOverflow({
209
+ promptId: asset.id,
210
+ variable: input.name,
211
+ value: candidate,
212
+ maxSize: input.max_size,
213
+ actualSize
214
+ });
215
+ }
216
+ }
217
+ if (isTrimEnabled(input.trim) && input.max_size !== void 0) {
218
+ candidate = trimToMaxSize(candidate, input.max_size, input.trim);
219
+ }
220
+ sanitized[input.name] = candidate;
221
+ if (input.allow_regex) {
222
+ const candidate2 = sanitized[input.name];
223
+ const matcher = compileContextRegex(input.allow_regex, {
224
+ promptId: asset.id,
225
+ variable: input.name,
226
+ field: "allow_regex"
227
+ });
228
+ if (!matcher.test(candidate2)) {
229
+ if (input.allow_regex.returnMessage) {
230
+ return {
231
+ variables: sanitized,
232
+ shortCircuit: {
233
+ returnMessage: input.allow_regex.returnMessage,
234
+ code: "POK031",
235
+ variable: input.name,
236
+ field: "allow_regex"
237
+ }
238
+ };
239
+ }
240
+ throw new Error(
241
+ `POK031: Context variable "${input.name}" failed allow_regex validation for prompt "${asset.id}".`
242
+ );
243
+ }
244
+ }
245
+ if (input.deny_regex) {
246
+ const candidate2 = sanitized[input.name];
247
+ const matcher = compileContextRegex(input.deny_regex, {
248
+ promptId: asset.id,
249
+ variable: input.name,
250
+ field: "deny_regex"
251
+ });
252
+ if (matcher.test(candidate2)) {
253
+ if (input.deny_regex.returnMessage) {
254
+ return {
255
+ variables: sanitized,
256
+ shortCircuit: {
257
+ returnMessage: input.deny_regex.returnMessage,
258
+ code: "POK032",
259
+ variable: input.name,
260
+ field: "deny_regex"
261
+ }
262
+ };
263
+ }
264
+ throw new Error(
265
+ `POK032: Context variable "${input.name}" matched deny_regex for prompt "${asset.id}".`
266
+ );
267
+ }
268
+ }
269
+ if (input.non_empty && candidate.trim().length === 0) {
270
+ if (input.non_empty.returnMessage) {
271
+ return {
272
+ variables: sanitized,
273
+ shortCircuit: {
274
+ returnMessage: input.non_empty.returnMessage,
275
+ code: "POK033",
276
+ variable: input.name,
277
+ field: "non_empty"
278
+ }
279
+ };
280
+ }
281
+ throw new Error(
282
+ `POK033: Context variable "${input.name}" failed non_empty validation for prompt "${asset.id}".`
283
+ );
284
+ }
285
+ if (input.reject_secrets) {
286
+ const matcher = compileContextRegex(getRejectSecretsRegex(), {
287
+ promptId: asset.id,
288
+ variable: input.name,
289
+ field: "reject_secrets"
290
+ });
291
+ if (matcher.test(candidate)) {
292
+ if (input.reject_secrets.returnMessage) {
293
+ return {
294
+ variables: sanitized,
295
+ shortCircuit: {
296
+ returnMessage: input.reject_secrets.returnMessage,
297
+ code: "POK034",
298
+ variable: input.name,
299
+ field: "reject_secrets"
300
+ }
301
+ };
302
+ }
303
+ throw new Error(
304
+ `POK034: Context variable "${input.name}" matched reject_secrets validation for prompt "${asset.id}".`
305
+ );
306
+ }
307
+ }
308
+ }
309
+ return { variables: sanitized };
310
+ }
311
+ function measureContextValueSize(value) {
312
+ return textEncoder.encode(value).length;
313
+ }
314
+ function collectContextSizeWarnings(asset, variables = {}) {
315
+ const warnings = [];
316
+ for (const input of getContextInputs(asset)) {
317
+ if (!areContextInputWarningsEnabled(input)) {
395
318
  continue;
396
319
  }
397
- let backslashCount = 0;
398
- for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
399
- backslashCount += 1;
320
+ if (input.max_size === void 0) {
321
+ continue;
400
322
  }
401
- if (backslashCount % 2 === 1) {
323
+ const value = variables[input.name];
324
+ if (value === void 0) {
402
325
  continue;
403
326
  }
404
- return {
405
- pattern: value.slice(1, index),
406
- flags: value.slice(index + 1)
407
- };
327
+ const actualSize = measureContextValueSize(value);
328
+ if (actualSize > input.max_size) {
329
+ warnings.push({
330
+ variable: input.name,
331
+ maxSize: input.max_size,
332
+ actualSize
333
+ });
334
+ }
408
335
  }
409
- return void 0;
410
- }
411
- function formatInvalidContextRegexMessage(details) {
412
- return [
413
- `Invalid context regex for prompt "${details.promptId}"`,
414
- `variable "${details.variable}"`,
415
- `field "${details.field}"`,
416
- `value ${JSON.stringify(details.raw)}: ${details.reason}`
417
- ].join(", ");
336
+ return warnings;
418
337
  }
419
- function compileContextRegex(regex, details) {
420
- if (regex.invalidLiteral) {
421
- throw new Error(
422
- `POK013: ${formatInvalidContextRegexMessage({
423
- ...details,
424
- raw: regex.raw,
425
- reason: "Malformed regex literal. Use /pattern/flags or { pattern, flags }."
426
- })}`
338
+
339
+ // src/renderer/renderer.ts
340
+ function renderSections(asset, options = {}) {
341
+ const { variables = {}, strict = false } = options;
342
+ const optionalVariables = getContextInputs(asset).filter((input) => input.optional === true).map((input) => input.name);
343
+ const result = {};
344
+ if (asset.sections.system_instructions) {
345
+ result.system_instructions = interpolate(
346
+ asset.sections.system_instructions,
347
+ variables,
348
+ { strict, optionalVariables }
427
349
  );
428
350
  }
429
- try {
430
- return new RegExp(regex.pattern, regex.flags);
431
- } catch (error) {
432
- const reason = error instanceof Error ? error.message : String(error);
433
- throw new Error(`POK013: ${formatInvalidContextRegexMessage({ ...details, raw: regex.raw, reason })}`);
351
+ if (asset.sections.prompt_template) {
352
+ result.prompt_template = interpolate(
353
+ asset.sections.prompt_template,
354
+ variables,
355
+ { strict, optionalVariables }
356
+ );
434
357
  }
358
+ return result;
435
359
  }
436
- function getRejectSecretsRegex() {
437
- return {
438
- pattern: REJECT_SECRETS_PATTERN,
439
- flags: REJECT_SECRETS_FLAGS,
440
- raw: JSON.stringify({ pattern: REJECT_SECRETS_PATTERN, flags: REJECT_SECRETS_FLAGS })
441
- };
360
+
361
+ // src/overrides/apply-overrides.ts
362
+ function applyOverrides(asset, options = {}) {
363
+ let result = { ...asset };
364
+ if (options.environment && result.environments?.[options.environment]) {
365
+ result = mergeOverride(result, result.environments[options.environment]);
366
+ }
367
+ if (options.tier && result.tiers?.[options.tier]) {
368
+ result = mergeOverride(result, result.tiers[options.tier]);
369
+ }
370
+ if (options.runtime) {
371
+ result = mergeOverride(result, options.runtime);
372
+ }
373
+ return result;
442
374
  }
443
- function isTrimEnabled(mode) {
444
- return mode === true || mode === "start" || mode === "end" || mode === "both";
375
+ function mergeOverride(base, override) {
376
+ const result = { ...base };
377
+ if (override.model !== void 0) result.model = override.model;
378
+ if (override.fallback_models !== void 0) result.fallback_models = override.fallback_models;
379
+ if (override.tools !== void 0) result.tools = override.tools;
380
+ if (override.reasoning !== void 0) {
381
+ result.reasoning = { ...result.reasoning, ...override.reasoning };
382
+ }
383
+ if (override.sampling !== void 0) {
384
+ result.sampling = { ...result.sampling, ...override.sampling };
385
+ }
386
+ if (override.response !== void 0) {
387
+ result.response = { ...result.response, ...override.response };
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
+ }
399
+ if (override.cache !== void 0) {
400
+ result.cache = {
401
+ ...result.cache,
402
+ ...override.cache,
403
+ openai: mergeRecordBlock(result.cache?.openai, override.cache.openai),
404
+ anthropic: mergeRecordBlock(result.cache?.anthropic, override.cache.anthropic),
405
+ gemini: mergeRecordBlock(result.cache?.gemini, override.cache.gemini),
406
+ google: mergeRecordBlock(result.cache?.google, override.cache.google)
407
+ };
408
+ }
409
+ if (override.raw !== void 0) {
410
+ result.raw = {
411
+ ...result.raw,
412
+ ...override.raw,
413
+ openai: mergeRecordBlock(result.raw?.openai, override.raw.openai),
414
+ "openai-responses": mergeRecordBlock(result.raw?.["openai-responses"], override.raw["openai-responses"]),
415
+ openai_responses: mergeRecordBlock(result.raw?.openai_responses, override.raw.openai_responses),
416
+ anthropic: mergeRecordBlock(result.raw?.anthropic, override.raw.anthropic),
417
+ gemini: mergeRecordBlock(result.raw?.gemini, override.raw.gemini),
418
+ google: mergeRecordBlock(result.raw?.google, override.raw.google),
419
+ openrouter: mergeRecordBlock(result.raw?.openrouter, override.raw.openrouter),
420
+ llmasaservice: mergeRecordBlock(result.raw?.llmasaservice, override.raw.llmasaservice)
421
+ };
422
+ }
423
+ if (override.provider_options !== void 0) {
424
+ result.provider_options = {
425
+ ...result.provider_options,
426
+ ...override.provider_options,
427
+ anthropic: {
428
+ ...result.provider_options?.anthropic,
429
+ ...override.provider_options.anthropic
430
+ },
431
+ gemini: {
432
+ ...result.provider_options?.gemini,
433
+ ...override.provider_options.gemini
434
+ },
435
+ openrouter: {
436
+ ...result.provider_options?.openrouter,
437
+ ...override.provider_options.openrouter
438
+ },
439
+ llmasaservice: {
440
+ ...result.provider_options?.llmasaservice,
441
+ ...override.provider_options.llmasaservice
442
+ }
443
+ };
444
+ }
445
+ return result;
445
446
  }
446
- function normalizeTrimMode(mode) {
447
- if (mode === "start") {
448
- return "start";
447
+ function mergeRecordBlock(base, override) {
448
+ if (override === void 0) return base;
449
+ return { ...base, ...override };
450
+ }
451
+
452
+ // src/providers/resolve-asset.ts
453
+ function resolveAssetForProvider(asset, runtime = {}) {
454
+ if (!runtime.environment && !runtime.tier && !runtime.runtime) {
455
+ return asset;
449
456
  }
450
- return "end";
457
+ return applyOverrides(asset, {
458
+ environment: runtime.environment,
459
+ tier: runtime.tier,
460
+ runtime: runtime.runtime
461
+ });
451
462
  }
452
- function trimToMaxSize(value, maxSize, mode) {
453
- const measured = measureContextValueSize(value);
454
- if (measured <= maxSize) {
455
- return value;
463
+
464
+ // src/cache.ts
465
+ import { statSync } from "fs";
466
+ var PromptCache = class {
467
+ cache = /* @__PURE__ */ new Map();
468
+ maxSize;
469
+ constructor(maxSize = 100) {
470
+ this.maxSize = maxSize;
456
471
  }
457
- const characters = Array.from(value);
458
- const normalizedMode = normalizeTrimMode(mode);
459
- if (normalizedMode === "start") {
460
- let collected2 = "";
461
- let size2 = 0;
462
- for (let i = characters.length - 1; i >= 0; i -= 1) {
463
- const next = characters[i];
464
- const charSize = measureContextValueSize(next);
465
- if (size2 + charSize > maxSize) {
466
- break;
472
+ get(filePath) {
473
+ const entry = this.cache.get(filePath);
474
+ if (!entry) return void 0;
475
+ try {
476
+ const stat = statSync(filePath);
477
+ if (stat.mtimeMs !== entry.mtime) {
478
+ this.cache.delete(filePath);
479
+ return void 0;
467
480
  }
468
- collected2 = next + collected2;
469
- size2 += charSize;
481
+ } catch {
482
+ this.cache.delete(filePath);
483
+ return void 0;
470
484
  }
471
- return collected2;
485
+ this.cache.delete(filePath);
486
+ this.cache.set(filePath, entry);
487
+ return entry.value;
472
488
  }
473
- let collected = "";
474
- let size = 0;
475
- for (const char of characters) {
476
- const charSize = measureContextValueSize(char);
477
- if (size + charSize > maxSize) {
478
- break;
489
+ set(filePath, value) {
490
+ try {
491
+ const stat = statSync(filePath);
492
+ if (this.cache.has(filePath)) {
493
+ this.cache.delete(filePath);
494
+ } else if (this.cache.size >= this.maxSize) {
495
+ const oldest = this.cache.keys().next().value;
496
+ if (oldest) this.cache.delete(oldest);
497
+ }
498
+ this.cache.set(filePath, { value, mtime: stat.mtimeMs });
499
+ } catch {
500
+ }
501
+ }
502
+ clear() {
503
+ this.cache.clear();
504
+ }
505
+ get size() {
506
+ return this.cache.size;
507
+ }
508
+ };
509
+
510
+ // src/composition/resolve-includes.ts
511
+ import { readFile } from "fs/promises";
512
+ import { resolve, dirname } from "path";
513
+ async function resolveIncludes(asset, basePath, visited = /* @__PURE__ */ new Set()) {
514
+ if (!asset.includes || asset.includes.length === 0) {
515
+ return asset;
516
+ }
517
+ const baseDir = dirname(basePath);
518
+ const resolvedPath = resolve(basePath);
519
+ if (visited.has(resolvedPath)) {
520
+ throw new Error(`Circular include detected: ${resolvedPath}`);
521
+ }
522
+ visited.add(resolvedPath);
523
+ let mergedSystemInstructions = "";
524
+ for (const includePath of asset.includes) {
525
+ const fullPath = resolve(baseDir, includePath);
526
+ if (visited.has(fullPath)) {
527
+ throw new Error(`Circular include detected: ${fullPath} (included from ${basePath})`);
528
+ }
529
+ const content = await readFile(fullPath, "utf-8");
530
+ const { asset: includedAsset } = parsePrompt(content, fullPath);
531
+ const resolved = await resolveIncludes(includedAsset, fullPath, new Set(visited));
532
+ if (resolved.sections?.system_instructions) {
533
+ mergedSystemInstructions += resolved.sections.system_instructions + "\n\n";
479
534
  }
480
- collected += char;
481
- size += charSize;
482
535
  }
483
- return collected;
536
+ const localSystem = asset.sections?.system_instructions ?? "";
537
+ const combinedSystem = (mergedSystemInstructions + localSystem).trim() || void 0;
538
+ return {
539
+ ...asset,
540
+ sections: {
541
+ ...asset.sections,
542
+ system_instructions: combinedSystem
543
+ },
544
+ // Drop includes from the resolved asset — they've been inlined
545
+ includes: void 0
546
+ };
484
547
  }
485
- function sanitizeContextVariables(asset, variables = {}, options = {}) {
486
- const { onContextOverflow } = options;
487
- const sanitized = { ...variables };
488
- for (const input of getContextInputs(asset)) {
489
- const value = sanitized[input.name];
490
- if (value === void 0) {
491
- continue;
492
- }
493
- let candidate = value;
494
- if (input.max_size !== void 0) {
495
- const actualSize = measureContextValueSize(candidate);
496
- if (actualSize > input.max_size && onContextOverflow) {
497
- candidate = onContextOverflow({
498
- promptId: asset.id,
499
- variable: input.name,
500
- value: candidate,
501
- maxSize: input.max_size,
502
- actualSize
503
- });
504
- }
505
- }
506
- if (isTrimEnabled(input.trim) && input.max_size !== void 0) {
507
- candidate = trimToMaxSize(candidate, input.max_size, input.trim);
508
- }
509
- sanitized[input.name] = candidate;
510
- if (input.allow_regex) {
511
- const candidate2 = sanitized[input.name];
512
- const matcher = compileContextRegex(input.allow_regex, {
513
- promptId: asset.id,
514
- variable: input.name,
515
- field: "allow_regex"
516
- });
517
- if (!matcher.test(candidate2)) {
518
- if (input.allow_regex.returnMessage) {
519
- return {
520
- variables: sanitized,
521
- shortCircuit: {
522
- returnMessage: input.allow_regex.returnMessage,
523
- code: "POK031",
524
- variable: input.name,
525
- field: "allow_regex"
526
- }
527
- };
548
+
549
+ // src/prompt-resolution.ts
550
+ import { readFile as readFile2 } from "fs/promises";
551
+ import { existsSync, statSync as statSync2 } from "fs";
552
+ import { resolve as resolve2 } from "path";
553
+ var DEFAULT_PROMPTS_DIR = "./prompts";
554
+ var DEFAULT_COMPILED_JSON_DIR = "./.generated-prompts/json";
555
+ function withPromptResolutionDefaults(config) {
556
+ return {
557
+ ...config,
558
+ sourceDir: config.sourceDir ?? DEFAULT_PROMPTS_DIR,
559
+ compiledDir: config.compiledDir ?? DEFAULT_COMPILED_JSON_DIR
560
+ };
561
+ }
562
+ var sharedPromptCache = new PromptCache();
563
+ async function loadPromptAsset(promptPath, config, promptCache = sharedPromptCache) {
564
+ const resolvedConfig = withPromptResolutionDefaults(config);
565
+ const mode = resolvedConfig.mode ?? "auto";
566
+ if (mode !== "source-only" && resolvedConfig.compiledDir) {
567
+ const compiledFile = resolve2(resolvedConfig.compiledDir, promptPath + ".json");
568
+ if (existsSync(compiledFile)) {
569
+ if (mode === "auto") {
570
+ const sourceFile = resolve2(resolvedConfig.sourceDir, promptPath + ".md");
571
+ if (existsSync(sourceFile)) {
572
+ const compiledMtime = statSync2(compiledFile).mtimeMs;
573
+ const sourceMtime = statSync2(sourceFile).mtimeMs;
574
+ if (sourceMtime > compiledMtime) {
575
+ console.warn(
576
+ `[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
577
+ Run "promptopskit compile" or switch to source-only mode.`
578
+ );
579
+ }
528
580
  }
529
- throw new Error(
530
- `POK031: Context variable "${input.name}" failed allow_regex validation for prompt "${asset.id}".`
531
- );
532
581
  }
582
+ const content = await readFile2(compiledFile, "utf-8");
583
+ return JSON.parse(content);
533
584
  }
534
- if (input.deny_regex) {
535
- const candidate2 = sanitized[input.name];
536
- const matcher = compileContextRegex(input.deny_regex, {
537
- promptId: asset.id,
538
- variable: input.name,
539
- field: "deny_regex"
540
- });
541
- if (matcher.test(candidate2)) {
542
- if (input.deny_regex.returnMessage) {
543
- return {
544
- variables: sanitized,
545
- shortCircuit: {
546
- returnMessage: input.deny_regex.returnMessage,
547
- code: "POK032",
548
- variable: input.name,
549
- field: "deny_regex"
550
- }
551
- };
552
- }
553
- throw new Error(
554
- `POK032: Context variable "${input.name}" matched deny_regex for prompt "${asset.id}".`
555
- );
585
+ if (mode === "compiled-only") {
586
+ throw new Error(
587
+ `Compiled artifact not found: ${compiledFile}
588
+ Run "promptopskit compile" to generate it.`
589
+ );
590
+ }
591
+ }
592
+ if (mode !== "compiled-only") {
593
+ const sourceFile = resolve2(resolvedConfig.sourceDir, promptPath + ".md");
594
+ if (resolvedConfig.cache !== false) {
595
+ const cached = promptCache.get(sourceFile);
596
+ if (cached) {
597
+ return cached;
556
598
  }
557
599
  }
558
- if (input.non_empty && candidate.trim().length === 0) {
559
- if (input.non_empty.returnMessage) {
560
- return {
561
- variables: sanitized,
562
- shortCircuit: {
563
- returnMessage: input.non_empty.returnMessage,
564
- code: "POK033",
565
- variable: input.name,
566
- field: "non_empty"
567
- }
568
- };
600
+ if (!existsSync(sourceFile)) {
601
+ const paths = [sourceFile];
602
+ if (resolvedConfig.compiledDir) {
603
+ paths.unshift(resolve2(resolvedConfig.compiledDir, promptPath + ".json"));
569
604
  }
570
605
  throw new Error(
571
- `POK033: Context variable "${input.name}" failed non_empty validation for prompt "${asset.id}".`
606
+ `Prompt not found: "${promptPath}"
607
+ Searched:
608
+ ${paths.map((candidate) => ` - ${candidate}`).join("\n")}`
572
609
  );
573
610
  }
574
- if (input.reject_secrets) {
575
- const matcher = compileContextRegex(getRejectSecretsRegex(), {
576
- promptId: asset.id,
577
- variable: input.name,
578
- field: "reject_secrets"
579
- });
580
- if (matcher.test(candidate)) {
581
- if (input.reject_secrets.returnMessage) {
582
- return {
583
- variables: sanitized,
584
- shortCircuit: {
585
- returnMessage: input.reject_secrets.returnMessage,
586
- code: "POK034",
587
- variable: input.name,
588
- field: "reject_secrets"
589
- }
590
- };
591
- }
592
- throw new Error(
593
- `POK034: Context variable "${input.name}" matched reject_secrets validation for prompt "${asset.id}".`
594
- );
595
- }
611
+ const { asset } = await loadPromptFile(sourceFile, { defaultsRoot: resolvedConfig.sourceDir });
612
+ if (resolvedConfig.cache !== false) {
613
+ promptCache.set(sourceFile, asset);
596
614
  }
615
+ return asset;
597
616
  }
598
- return { variables: sanitized };
599
- }
600
- function measureContextValueSize(value) {
601
- return textEncoder.encode(value).length;
617
+ throw new Error(`Prompt not found: "${promptPath}"`);
602
618
  }
603
- function collectContextSizeWarnings(asset, variables = {}) {
604
- const warnings = [];
605
- for (const input of getContextInputs(asset)) {
606
- if (input.max_size === void 0) {
607
- continue;
608
- }
609
- const value = variables[input.name];
610
- if (value === void 0) {
611
- continue;
612
- }
613
- const actualSize = measureContextValueSize(value);
614
- if (actualSize > input.max_size) {
615
- warnings.push({
616
- variable: input.name,
617
- maxSize: input.max_size,
618
- actualSize
619
- });
620
- }
619
+ async function resolvePromptAsset(promptPath, config, options = {}, promptCache = sharedPromptCache) {
620
+ const resolvedConfig = withPromptResolutionDefaults(config);
621
+ let asset = await loadPromptAsset(promptPath, resolvedConfig, promptCache);
622
+ const sourceFile = resolve2(resolvedConfig.sourceDir, promptPath + ".md");
623
+ if (asset.includes && asset.includes.length > 0 && existsSync(sourceFile)) {
624
+ asset = await resolveIncludes(asset, sourceFile);
621
625
  }
622
- return warnings;
626
+ asset = applyOverrides(asset, {
627
+ environment: options.environment,
628
+ tier: options.tier,
629
+ runtime: options.runtime
630
+ });
631
+ return asset;
632
+ }
633
+ function resolveInlinePromptSource(source, options = {}) {
634
+ const { asset } = parsePrompt(source);
635
+ return applyOverrides(asset, {
636
+ environment: options.environment,
637
+ tier: options.tier,
638
+ runtime: options.runtime
639
+ });
623
640
  }
624
641
 
625
642
  // src/history.ts
@@ -672,6 +689,97 @@ function compactHistoryForPrompt(asset, runtime) {
672
689
  return [compacted, ...preserved];
673
690
  }
674
691
 
692
+ // src/compression.ts
693
+ var THETOKENCOMPANY_DEFAULT_MODEL = "bear-2";
694
+ var THETOKENCOMPANY_DEFAULT_BASE_URL = "https://api.thetokencompany.com";
695
+ async function applyPromptCompressionForRender(asset, runtime) {
696
+ const config = asset.compression?.thetokencompany;
697
+ if (config?.enabled !== true || !asset.sections.prompt_template) {
698
+ return { asset, runtime, compression: [] };
699
+ }
700
+ const sections = renderSections(asset, {
701
+ variables: runtime.variables,
702
+ strict: runtime.strict
703
+ });
704
+ if (!sections.prompt_template) {
705
+ return { asset, runtime, compression: [] };
706
+ }
707
+ const model = config.model ?? THETOKENCOMPANY_DEFAULT_MODEL;
708
+ const result = await compressWithTheTokenCompany(sections.prompt_template, {
709
+ apiKey: runtime.theTokenCompany?.apiKey,
710
+ baseURL: runtime.theTokenCompany?.baseURL,
711
+ fetch: runtime.theTokenCompany?.fetch,
712
+ model,
713
+ aggressiveness: config.aggressiveness
714
+ });
715
+ return {
716
+ asset: {
717
+ ...asset,
718
+ sections: {
719
+ ...asset.sections,
720
+ ...sections,
721
+ prompt_template: result.output
722
+ }
723
+ },
724
+ runtime: {
725
+ ...runtime,
726
+ variables: {},
727
+ strict: false
728
+ },
729
+ compression: [{
730
+ provider: "thetokencompany",
731
+ model,
732
+ inputTokens: result.input_tokens,
733
+ outputTokens: result.output_tokens,
734
+ tokensSaved: result.tokens_saved,
735
+ compressionRatio: result.compression_ratio
736
+ }]
737
+ };
738
+ }
739
+ async function compressWithTheTokenCompany(input, options) {
740
+ const apiKey = options.apiKey ?? getEnv("THETOKENCOMPANY_API_KEY") ?? getEnv("TTC_API_KEY");
741
+ if (!apiKey) {
742
+ throw new Error(
743
+ "TheTokenCompany compression is enabled, but no API key was provided. Pass theTokenCompany.apiKey to renderPrompt() or set THETOKENCOMPANY_API_KEY."
744
+ );
745
+ }
746
+ const fetchImpl = options.fetch ?? globalThis.fetch;
747
+ if (!fetchImpl) {
748
+ throw new Error("TheTokenCompany compression requires a runtime with fetch support.");
749
+ }
750
+ const baseURL = (options.baseURL ?? THETOKENCOMPANY_DEFAULT_BASE_URL).replace(/\/+$/, "");
751
+ const compressionSettings = options.aggressiveness === void 0 ? void 0 : { aggressiveness: options.aggressiveness };
752
+ const response = await fetchImpl(`${baseURL}/v1/compress`, {
753
+ method: "POST",
754
+ headers: {
755
+ Authorization: `Bearer ${apiKey}`,
756
+ "Content-Type": "application/json"
757
+ },
758
+ body: JSON.stringify({
759
+ model: options.model,
760
+ input,
761
+ ...compressionSettings ? { compression_settings: compressionSettings } : {}
762
+ })
763
+ });
764
+ if (!response.ok) {
765
+ const body = await response.text().catch(() => "");
766
+ throw new Error(
767
+ `TheTokenCompany compression failed with HTTP ${response.status}` + (body ? `: ${body}` : ".")
768
+ );
769
+ }
770
+ const data = await response.json();
771
+ 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") {
772
+ throw new Error("TheTokenCompany compression returned an invalid response payload.");
773
+ }
774
+ return data;
775
+ }
776
+ function getEnv(name) {
777
+ if (typeof process === "undefined") {
778
+ return void 0;
779
+ }
780
+ return process.env[name];
781
+ }
782
+
675
783
  // src/providers/prompt-input.ts
676
784
  function isPromptLookup(input) {
677
785
  return "path" in input && typeof input.path === "string";
@@ -695,21 +803,27 @@ function withPromptInputSupport(adapter) {
695
803
  };
696
804
  const renderPrompt = async (input, runtime) => {
697
805
  const resolved = await resolveProviderPromptInput(input, runtime);
698
- const sanitization = sanitizeContextVariables(resolved, runtime.variables, {
806
+ const resolvedForRender = resolveAssetForProvider(resolved, runtime);
807
+ const sanitization = sanitizeContextVariables(resolvedForRender, runtime.variables, {
699
808
  onContextOverflow: runtime.onContextOverflow
700
809
  });
701
810
  if (sanitization.shortCircuit) {
702
811
  return {
703
812
  provider: adapter.name,
704
- model: resolved.model ?? "",
813
+ model: resolvedForRender.model ?? "",
705
814
  returnMessage: sanitization.shortCircuit.returnMessage
706
815
  };
707
816
  }
708
- return adapter.render(resolved, {
817
+ const prepared = await applyPromptCompressionForRender(resolvedForRender, {
709
818
  ...runtime,
819
+ environment: void 0,
820
+ tier: void 0,
821
+ runtime: void 0,
710
822
  variables: sanitization.variables,
711
- history: compactHistoryForPrompt(resolved, runtime)
823
+ history: compactHistoryForPrompt(resolvedForRender, runtime)
712
824
  });
825
+ const request = adapter.render(prepared.asset, prepared.runtime);
826
+ return prepared.compression.length > 0 ? { ...request, compression: prepared.compression } : request;
713
827
  };
714
828
  return {
715
829
  ...adapter,
@@ -736,6 +850,11 @@ function getRawProviderBody(asset, provider) {
736
850
  export {
737
851
  interpolate,
738
852
  extractVariables,
853
+ getContextInputs,
854
+ areContextInputWarningsEnabled,
855
+ compileContextRegex,
856
+ sanitizeContextVariables,
857
+ collectContextSizeWarnings,
739
858
  renderSections,
740
859
  applyOverrides,
741
860
  resolveAssetForProvider,
@@ -746,13 +865,11 @@ export {
746
865
  loadPromptAsset,
747
866
  resolvePromptAsset,
748
867
  resolveInlinePromptSource,
749
- getContextInputs,
750
- getContextInputNames,
751
- compileContextRegex,
752
- sanitizeContextVariables,
753
- collectContextSizeWarnings,
754
868
  compactHistoryForPrompt,
869
+ THETOKENCOMPANY_DEFAULT_MODEL,
870
+ THETOKENCOMPANY_DEFAULT_BASE_URL,
871
+ applyPromptCompressionForRender,
755
872
  withPromptInputSupport,
756
873
  applyRawProviderBody
757
874
  };
758
- //# sourceMappingURL=chunk-KN7H4JRK.js.map
875
+ //# sourceMappingURL=chunk-F552OBUV.js.map