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