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.
- package/README.md +9 -7
- package/SKILL.md +16 -10
- package/dist/{chunk-QK3WKE3K.js → chunk-35NN5F6O.js} +2 -2
- package/dist/{chunk-D75HKF64.js → chunk-3G3EAV7H.js} +2 -2
- package/dist/{chunk-LNGHGGJN.js → chunk-6NOUETAC.js} +2 -2
- package/dist/{chunk-KN7H4JRK.js → chunk-F552OBUV.js} +619 -502
- package/dist/chunk-F552OBUV.js.map +1 -0
- package/dist/{chunk-6BOUQVSX.js → chunk-FICB2ZSK.js} +3 -3
- package/dist/{chunk-6VLKZCNS.js → chunk-OWMP5NMV.js} +2 -2
- package/dist/{chunk-IN4KT5EU.js → chunk-R65RAHAG.js} +3 -3
- package/dist/{chunk-K6ZU3CGV.js → chunk-ULVY473P.js} +306 -17
- package/dist/chunk-ULVY473P.js.map +1 -0
- package/dist/cli/index.js +446 -103
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +1223 -772
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -5
- package/dist/index.d.ts +9 -5
- package/dist/index.js +67 -18
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic.cjs +902 -502
- package/dist/providers/anthropic.cjs.map +1 -1
- package/dist/providers/anthropic.d.cts +2 -2
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +3 -3
- package/dist/providers/gemini.cjs +902 -502
- package/dist/providers/gemini.cjs.map +1 -1
- package/dist/providers/gemini.d.cts +2 -2
- package/dist/providers/gemini.d.ts +2 -2
- package/dist/providers/gemini.js +3 -3
- package/dist/providers/llmasaservice.cjs +901 -501
- package/dist/providers/llmasaservice.cjs.map +1 -1
- package/dist/providers/llmasaservice.d.cts +2 -2
- package/dist/providers/llmasaservice.d.ts +2 -2
- package/dist/providers/llmasaservice.js +4 -4
- package/dist/providers/openai-responses.cjs +902 -502
- package/dist/providers/openai-responses.cjs.map +1 -1
- package/dist/providers/openai-responses.d.cts +2 -2
- package/dist/providers/openai-responses.d.ts +2 -2
- package/dist/providers/openai-responses.js +3 -3
- package/dist/providers/openai.cjs +902 -502
- package/dist/providers/openai.cjs.map +1 -1
- package/dist/providers/openai.d.cts +2 -2
- package/dist/providers/openai.d.ts +2 -2
- package/dist/providers/openai.js +3 -3
- package/dist/providers/openrouter.cjs +902 -502
- package/dist/providers/openrouter.cjs.map +1 -1
- package/dist/providers/openrouter.d.cts +2 -2
- package/dist/providers/openrouter.d.ts +2 -2
- package/dist/providers/openrouter.js +4 -4
- package/dist/{schema-D-RI4w-k.d.cts → schema-DBcSns_b.d.cts} +732 -206
- package/dist/{schema-D-RI4w-k.d.ts → schema-DBcSns_b.d.ts} +732 -206
- package/dist/testing.cjs +54 -5
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/{types-B3dxBGu6.d.ts → types-8T2D5KB5.d.cts} +20 -2
- package/dist/{types-DbTAjlTN.d.cts → types-BlLXT5Qb.d.ts} +20 -2
- package/dist/usagetap/index.d.cts +2 -2
- package/dist/usagetap/index.d.ts +2 -2
- package/package.json +9 -2
- package/dist/chunk-K6ZU3CGV.js.map +0 -1
- package/dist/chunk-KN7H4JRK.js.map +0 -1
- /package/dist/{chunk-QK3WKE3K.js.map → chunk-35NN5F6O.js.map} +0 -0
- /package/dist/{chunk-D75HKF64.js.map → chunk-3G3EAV7H.js.map} +0 -0
- /package/dist/{chunk-LNGHGGJN.js.map → chunk-6NOUETAC.js.map} +0 -0
- /package/dist/{chunk-6BOUQVSX.js.map → chunk-FICB2ZSK.js.map} +0 -0
- /package/dist/{chunk-6VLKZCNS.js.map → chunk-OWMP5NMV.js.map} +0 -0
- /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-
|
|
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
|
-
|
|
398
|
-
|
|
399
|
-
backslashCount += 1;
|
|
320
|
+
if (input.max_size === void 0) {
|
|
321
|
+
continue;
|
|
400
322
|
}
|
|
401
|
-
|
|
323
|
+
const value = variables[input.name];
|
|
324
|
+
if (value === void 0) {
|
|
402
325
|
continue;
|
|
403
326
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
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
|
|
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
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
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
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
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
|
|
444
|
-
|
|
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
|
|
447
|
-
if (
|
|
448
|
-
|
|
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
|
|
457
|
+
return applyOverrides(asset, {
|
|
458
|
+
environment: runtime.environment,
|
|
459
|
+
tier: runtime.tier,
|
|
460
|
+
runtime: runtime.runtime
|
|
461
|
+
});
|
|
451
462
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
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
|
-
|
|
469
|
-
|
|
481
|
+
} catch {
|
|
482
|
+
this.cache.delete(filePath);
|
|
483
|
+
return void 0;
|
|
470
484
|
}
|
|
471
|
-
|
|
485
|
+
this.cache.delete(filePath);
|
|
486
|
+
this.cache.set(filePath, entry);
|
|
487
|
+
return entry.value;
|
|
472
488
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
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
|
-
|
|
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
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
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 (
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
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 (
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
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
|
-
`
|
|
606
|
+
`Prompt not found: "${promptPath}"
|
|
607
|
+
Searched:
|
|
608
|
+
${paths.map((candidate) => ` - ${candidate}`).join("\n")}`
|
|
572
609
|
);
|
|
573
610
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
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
|
-
|
|
599
|
-
}
|
|
600
|
-
function measureContextValueSize(value) {
|
|
601
|
-
return textEncoder.encode(value).length;
|
|
617
|
+
throw new Error(`Prompt not found: "${promptPath}"`);
|
|
602
618
|
}
|
|
603
|
-
function
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
813
|
+
model: resolvedForRender.model ?? "",
|
|
705
814
|
returnMessage: sanitization.shortCircuit.returnMessage
|
|
706
815
|
};
|
|
707
816
|
}
|
|
708
|
-
|
|
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(
|
|
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-
|
|
875
|
+
//# sourceMappingURL=chunk-F552OBUV.js.map
|