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