promptopskit 0.4.2 → 0.6.2
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 +105 -62
- package/SKILL.md +376 -16
- package/dist/{chunk-7MRMN3SW.js → chunk-55B7QQBK.js} +6 -4
- package/dist/chunk-55B7QQBK.js.map +1 -0
- package/dist/{chunk-HWEVRBKZ.js → chunk-AGTGIZMR.js} +6 -2
- package/dist/chunk-AGTGIZMR.js.map +1 -0
- package/dist/chunk-FNCIBZJF.js +130 -0
- package/dist/chunk-FNCIBZJF.js.map +1 -0
- package/dist/{chunk-XL76NHZR.js → chunk-GLT3YYWK.js} +6 -4
- package/dist/chunk-GLT3YYWK.js.map +1 -0
- package/dist/{chunk-5AAYDOPU.js → chunk-IPFD5Y3O.js} +4 -3
- package/dist/chunk-IPFD5Y3O.js.map +1 -0
- package/dist/{chunk-YI4LILPY.js → chunk-JR7252DG.js} +584 -520
- package/dist/chunk-JR7252DG.js.map +1 -0
- package/dist/{chunk-JKBWC5WJ.js → chunk-UY5OKMVP.js} +302 -21
- package/dist/chunk-UY5OKMVP.js.map +1 -0
- package/dist/{chunk-MI3M6KDD.js → chunk-VMLGUI4F.js} +6 -4
- package/dist/chunk-VMLGUI4F.js.map +1 -0
- package/dist/{chunk-Z4IPWEUU.js → chunk-XEZJZ3IG.js} +6 -4
- package/dist/chunk-XEZJZ3IG.js.map +1 -0
- package/dist/cli/index.js +435 -106
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +1159 -636
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -9
- package/dist/index.d.ts +10 -9
- package/dist/index.js +79 -17
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic.cjs +875 -533
- 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 +875 -533
- 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 +1735 -0
- package/dist/providers/llmasaservice.cjs.map +1 -0
- package/dist/providers/llmasaservice.d.cts +28 -0
- package/dist/providers/llmasaservice.d.ts +28 -0
- package/dist/providers/llmasaservice.js +20 -0
- package/dist/providers/llmasaservice.js.map +1 -0
- package/dist/providers/openai-responses.cjs +875 -533
- 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 +875 -533
- 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 +876 -533
- 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-B9A1zLRk.d.cts → schema-CuYsv8JA.d.cts} +853 -7
- package/dist/{schema-B9A1zLRk.d.ts → schema-CuYsv8JA.d.ts} +853 -7
- package/dist/testing.cjs +64 -9
- 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-DjGAwJxC.d.ts → types-DpK0mTHL.d.ts} +18 -6
- package/dist/{types-DpbzzZO2.d.cts → types-UA_p9uJy.d.cts} +18 -6
- package/dist/usagetap/index.cjs +6 -1
- package/dist/usagetap/index.cjs.map +1 -1
- package/dist/usagetap/index.d.cts +4 -3
- package/dist/usagetap/index.d.ts +4 -3
- package/dist/usagetap/index.js +3 -1
- package/package.json +19 -2
- package/dist/chunk-5AAYDOPU.js.map +0 -1
- package/dist/chunk-7MRMN3SW.js.map +0 -1
- package/dist/chunk-HWEVRBKZ.js.map +0 -1
- package/dist/chunk-JKBWC5WJ.js.map +0 -1
- package/dist/chunk-MI3M6KDD.js.map +0 -1
- package/dist/chunk-XL76NHZR.js.map +0 -1
- package/dist/chunk-YI4LILPY.js.map +0 -1
- package/dist/chunk-Z4IPWEUU.js.map +0 -1
|
@@ -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,156 +55,438 @@ function interpolate(template, variables, options = {}) {
|
|
|
54
55
|
return result;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
// src/
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
asset.sections.system_instructions,
|
|
64
|
-
variables,
|
|
65
|
-
{ strict }
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
if (asset.sections.prompt_template) {
|
|
69
|
-
result.prompt_template = interpolate(
|
|
70
|
-
asset.sections.prompt_template,
|
|
71
|
-
variables,
|
|
72
|
-
{ strict }
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
return result;
|
|
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);
|
|
76
64
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
let result = { ...asset };
|
|
81
|
-
if (options.environment && result.environments?.[options.environment]) {
|
|
82
|
-
result = mergeOverride(result, result.environments[options.environment]);
|
|
65
|
+
function normalizeContextInput(input) {
|
|
66
|
+
if (typeof input === "string") {
|
|
67
|
+
return { name: input };
|
|
83
68
|
}
|
|
84
|
-
|
|
85
|
-
|
|
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;
|
|
86
84
|
}
|
|
87
|
-
if (
|
|
88
|
-
|
|
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
|
+
};
|
|
89
100
|
}
|
|
90
|
-
return
|
|
101
|
+
return {
|
|
102
|
+
pattern: value.pattern,
|
|
103
|
+
flags: value.flags ?? "",
|
|
104
|
+
raw: JSON.stringify(value),
|
|
105
|
+
returnMessage: value.return_message
|
|
106
|
+
};
|
|
91
107
|
}
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (override.fallback_models !== void 0) result.fallback_models = override.fallback_models;
|
|
96
|
-
if (override.tools !== void 0) result.tools = override.tools;
|
|
97
|
-
if (override.reasoning !== void 0) {
|
|
98
|
-
result.reasoning = { ...result.reasoning, ...override.reasoning };
|
|
108
|
+
function normalizeBuiltInValidator(value) {
|
|
109
|
+
if (value === void 0 || value === false) {
|
|
110
|
+
return void 0;
|
|
99
111
|
}
|
|
100
|
-
if (
|
|
101
|
-
|
|
112
|
+
if (value === true) {
|
|
113
|
+
return {};
|
|
102
114
|
}
|
|
103
|
-
|
|
104
|
-
|
|
115
|
+
return {
|
|
116
|
+
returnMessage: value.return_message
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function parseRegexLiteral(value) {
|
|
120
|
+
if (!value.startsWith("/")) {
|
|
121
|
+
return void 0;
|
|
105
122
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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)
|
|
114
137
|
};
|
|
115
138
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
+
);
|
|
128
158
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
...result.provider_options?.anthropic,
|
|
135
|
-
...override.provider_options.anthropic
|
|
136
|
-
},
|
|
137
|
-
gemini: {
|
|
138
|
-
...result.provider_options?.gemini,
|
|
139
|
-
...override.provider_options.gemini
|
|
140
|
-
},
|
|
141
|
-
openrouter: {
|
|
142
|
-
...result.provider_options?.openrouter,
|
|
143
|
-
...override.provider_options.openrouter
|
|
144
|
-
}
|
|
145
|
-
};
|
|
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 })}`);
|
|
146
164
|
}
|
|
147
|
-
return result;
|
|
148
165
|
}
|
|
149
|
-
function
|
|
150
|
-
|
|
151
|
-
|
|
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
|
+
};
|
|
152
172
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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";
|
|
158
179
|
}
|
|
159
|
-
return
|
|
160
|
-
environment: runtime.environment,
|
|
161
|
-
tier: runtime.tier,
|
|
162
|
-
runtime: runtime.runtime
|
|
163
|
-
});
|
|
180
|
+
return "end";
|
|
164
181
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
var import_node_path3 = require("path");
|
|
170
|
-
|
|
171
|
-
// src/cache.ts
|
|
172
|
-
var import_node_fs = require("fs");
|
|
173
|
-
var PromptCache = class {
|
|
174
|
-
cache = /* @__PURE__ */ new Map();
|
|
175
|
-
maxSize;
|
|
176
|
-
constructor(maxSize = 100) {
|
|
177
|
-
this.maxSize = maxSize;
|
|
182
|
+
function trimToMaxSize(value, maxSize, mode) {
|
|
183
|
+
const measured = measureContextValueSize(value);
|
|
184
|
+
if (measured <= maxSize) {
|
|
185
|
+
return value;
|
|
178
186
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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;
|
|
187
197
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
return void 0;
|
|
198
|
+
collected2 = next + collected2;
|
|
199
|
+
size2 += charSize;
|
|
191
200
|
}
|
|
192
|
-
|
|
193
|
-
this.cache.set(filePath, entry);
|
|
194
|
-
return entry.value;
|
|
201
|
+
return collected2;
|
|
195
202
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
+
|
|
334
|
+
// src/renderer/renderer.ts
|
|
335
|
+
function renderSections(asset, options = {}) {
|
|
336
|
+
const { variables = {}, strict = false } = options;
|
|
337
|
+
const optionalVariables = getContextInputs(asset).filter((input) => input.optional === true).map((input) => input.name);
|
|
338
|
+
const result = {};
|
|
339
|
+
if (asset.sections.system_instructions) {
|
|
340
|
+
result.system_instructions = interpolate(
|
|
341
|
+
asset.sections.system_instructions,
|
|
342
|
+
variables,
|
|
343
|
+
{ strict, optionalVariables }
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
if (asset.sections.prompt_template) {
|
|
347
|
+
result.prompt_template = interpolate(
|
|
348
|
+
asset.sections.prompt_template,
|
|
349
|
+
variables,
|
|
350
|
+
{ strict, optionalVariables }
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
return result;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// src/overrides/apply-overrides.ts
|
|
357
|
+
function applyOverrides(asset, options = {}) {
|
|
358
|
+
let result = { ...asset };
|
|
359
|
+
if (options.environment && result.environments?.[options.environment]) {
|
|
360
|
+
result = mergeOverride(result, result.environments[options.environment]);
|
|
361
|
+
}
|
|
362
|
+
if (options.tier && result.tiers?.[options.tier]) {
|
|
363
|
+
result = mergeOverride(result, result.tiers[options.tier]);
|
|
364
|
+
}
|
|
365
|
+
if (options.runtime) {
|
|
366
|
+
result = mergeOverride(result, options.runtime);
|
|
367
|
+
}
|
|
368
|
+
return result;
|
|
369
|
+
}
|
|
370
|
+
function mergeOverride(base, override) {
|
|
371
|
+
const result = { ...base };
|
|
372
|
+
if (override.model !== void 0) result.model = override.model;
|
|
373
|
+
if (override.fallback_models !== void 0) result.fallback_models = override.fallback_models;
|
|
374
|
+
if (override.tools !== void 0) result.tools = override.tools;
|
|
375
|
+
if (override.reasoning !== void 0) {
|
|
376
|
+
result.reasoning = { ...result.reasoning, ...override.reasoning };
|
|
377
|
+
}
|
|
378
|
+
if (override.sampling !== void 0) {
|
|
379
|
+
result.sampling = { ...result.sampling, ...override.sampling };
|
|
380
|
+
}
|
|
381
|
+
if (override.response !== void 0) {
|
|
382
|
+
result.response = { ...result.response, ...override.response };
|
|
383
|
+
}
|
|
384
|
+
if (override.cache !== void 0) {
|
|
385
|
+
result.cache = {
|
|
386
|
+
...result.cache,
|
|
387
|
+
...override.cache,
|
|
388
|
+
openai: mergeRecordBlock(result.cache?.openai, override.cache.openai),
|
|
389
|
+
anthropic: mergeRecordBlock(result.cache?.anthropic, override.cache.anthropic),
|
|
390
|
+
gemini: mergeRecordBlock(result.cache?.gemini, override.cache.gemini),
|
|
391
|
+
google: mergeRecordBlock(result.cache?.google, override.cache.google)
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
if (override.raw !== void 0) {
|
|
395
|
+
result.raw = {
|
|
396
|
+
...result.raw,
|
|
397
|
+
...override.raw,
|
|
398
|
+
openai: mergeRecordBlock(result.raw?.openai, override.raw.openai),
|
|
399
|
+
"openai-responses": mergeRecordBlock(result.raw?.["openai-responses"], override.raw["openai-responses"]),
|
|
400
|
+
openai_responses: mergeRecordBlock(result.raw?.openai_responses, override.raw.openai_responses),
|
|
401
|
+
anthropic: mergeRecordBlock(result.raw?.anthropic, override.raw.anthropic),
|
|
402
|
+
gemini: mergeRecordBlock(result.raw?.gemini, override.raw.gemini),
|
|
403
|
+
google: mergeRecordBlock(result.raw?.google, override.raw.google),
|
|
404
|
+
openrouter: mergeRecordBlock(result.raw?.openrouter, override.raw.openrouter),
|
|
405
|
+
llmasaservice: mergeRecordBlock(result.raw?.llmasaservice, override.raw.llmasaservice)
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
if (override.provider_options !== void 0) {
|
|
409
|
+
result.provider_options = {
|
|
410
|
+
...result.provider_options,
|
|
411
|
+
...override.provider_options,
|
|
412
|
+
anthropic: {
|
|
413
|
+
...result.provider_options?.anthropic,
|
|
414
|
+
...override.provider_options.anthropic
|
|
415
|
+
},
|
|
416
|
+
gemini: {
|
|
417
|
+
...result.provider_options?.gemini,
|
|
418
|
+
...override.provider_options.gemini
|
|
419
|
+
},
|
|
420
|
+
openrouter: {
|
|
421
|
+
...result.provider_options?.openrouter,
|
|
422
|
+
...override.provider_options.openrouter
|
|
423
|
+
},
|
|
424
|
+
llmasaservice: {
|
|
425
|
+
...result.provider_options?.llmasaservice,
|
|
426
|
+
...override.provider_options.llmasaservice
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
return result;
|
|
431
|
+
}
|
|
432
|
+
function mergeRecordBlock(base, override) {
|
|
433
|
+
if (override === void 0) return base;
|
|
434
|
+
return { ...base, ...override };
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// src/providers/resolve-asset.ts
|
|
438
|
+
function resolveAssetForProvider(asset, runtime = {}) {
|
|
439
|
+
if (!runtime.environment && !runtime.tier && !runtime.runtime) {
|
|
440
|
+
return asset;
|
|
441
|
+
}
|
|
442
|
+
return applyOverrides(asset, {
|
|
443
|
+
environment: runtime.environment,
|
|
444
|
+
tier: runtime.tier,
|
|
445
|
+
runtime: runtime.runtime
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// src/prompt-resolution.ts
|
|
450
|
+
var import_promises4 = require("fs/promises");
|
|
451
|
+
var import_node_fs2 = require("fs");
|
|
452
|
+
var import_node_path4 = require("path");
|
|
453
|
+
|
|
454
|
+
// src/cache.ts
|
|
455
|
+
var import_node_fs = require("fs");
|
|
456
|
+
var PromptCache = class {
|
|
457
|
+
cache = /* @__PURE__ */ new Map();
|
|
458
|
+
maxSize;
|
|
459
|
+
constructor(maxSize = 100) {
|
|
460
|
+
this.maxSize = maxSize;
|
|
461
|
+
}
|
|
462
|
+
get(filePath) {
|
|
463
|
+
const entry = this.cache.get(filePath);
|
|
464
|
+
if (!entry) return void 0;
|
|
465
|
+
try {
|
|
466
|
+
const stat = (0, import_node_fs.statSync)(filePath);
|
|
467
|
+
if (stat.mtimeMs !== entry.mtime) {
|
|
468
|
+
this.cache.delete(filePath);
|
|
469
|
+
return void 0;
|
|
470
|
+
}
|
|
471
|
+
} catch {
|
|
472
|
+
this.cache.delete(filePath);
|
|
473
|
+
return void 0;
|
|
474
|
+
}
|
|
475
|
+
this.cache.delete(filePath);
|
|
476
|
+
this.cache.set(filePath, entry);
|
|
477
|
+
return entry.value;
|
|
478
|
+
}
|
|
479
|
+
set(filePath, value) {
|
|
480
|
+
try {
|
|
481
|
+
const stat = (0, import_node_fs.statSync)(filePath);
|
|
482
|
+
if (this.cache.has(filePath)) {
|
|
483
|
+
this.cache.delete(filePath);
|
|
484
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
485
|
+
const oldest = this.cache.keys().next().value;
|
|
486
|
+
if (oldest) this.cache.delete(oldest);
|
|
487
|
+
}
|
|
488
|
+
this.cache.set(filePath, { value, mtime: stat.mtimeMs });
|
|
489
|
+
} catch {
|
|
207
490
|
}
|
|
208
491
|
}
|
|
209
492
|
clear() {
|
|
@@ -215,8 +498,8 @@ var PromptCache = class {
|
|
|
215
498
|
};
|
|
216
499
|
|
|
217
500
|
// src/composition/resolve-includes.ts
|
|
218
|
-
var
|
|
219
|
-
var
|
|
501
|
+
var import_promises3 = require("fs/promises");
|
|
502
|
+
var import_node_path3 = require("path");
|
|
220
503
|
|
|
221
504
|
// src/parser/parser.ts
|
|
222
505
|
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
@@ -252,10 +535,26 @@ var ResponseSchema = import_zod.z.object({
|
|
|
252
535
|
format: import_zod.z.enum(["text", "json", "markdown"]).optional(),
|
|
253
536
|
stream: import_zod.z.boolean().optional(),
|
|
254
537
|
schema: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
538
|
+
schema_ref: import_zod.z.string().min(1).optional(),
|
|
539
|
+
schema_source: import_zod.z.object({
|
|
540
|
+
mode: import_zod.z.enum(["inline", "schema_ref_json", "schema_ref_zod_module"]).optional(),
|
|
541
|
+
ref: import_zod.z.string().optional(),
|
|
542
|
+
resolved_path: import_zod.z.string().optional(),
|
|
543
|
+
hash: import_zod.z.string().optional()
|
|
544
|
+
}).optional(),
|
|
255
545
|
schema_name: import_zod.z.string().optional(),
|
|
256
546
|
schema_description: import_zod.z.string().optional(),
|
|
257
547
|
schema_strict: import_zod.z.boolean().optional()
|
|
258
548
|
});
|
|
549
|
+
var ResponseSchemaWithValidation = ResponseSchema.superRefine((value, ctx) => {
|
|
550
|
+
if (value.schema !== void 0 && value.schema_ref !== void 0) {
|
|
551
|
+
ctx.addIssue({
|
|
552
|
+
code: import_zod.z.ZodIssueCode.custom,
|
|
553
|
+
message: "response.schema and response.schema_ref are mutually exclusive",
|
|
554
|
+
path: ["schema_ref"]
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
});
|
|
259
558
|
var AnthropicProviderOptionsSchema = import_zod.z.object({
|
|
260
559
|
top_k: import_zod.z.number().int().min(0).optional(),
|
|
261
560
|
tool_choice: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
@@ -276,10 +575,26 @@ var OpenRouterProviderOptionsSchema = import_zod.z.object({
|
|
|
276
575
|
plugins: import_zod.z.array(import_zod.z.record(import_zod.z.unknown())).optional(),
|
|
277
576
|
models: import_zod.z.array(import_zod.z.string()).optional()
|
|
278
577
|
});
|
|
578
|
+
var LLMAsAServiceCustomerSchema = import_zod.z.object({
|
|
579
|
+
customer_id: import_zod.z.string(),
|
|
580
|
+
customer_name: import_zod.z.string().optional(),
|
|
581
|
+
customer_user_id: import_zod.z.string().optional(),
|
|
582
|
+
customer_user_name: import_zod.z.string().optional(),
|
|
583
|
+
customer_user_email: import_zod.z.string().optional()
|
|
584
|
+
});
|
|
585
|
+
var LLMAsAServiceProviderOptionsSchema = import_zod.z.object({
|
|
586
|
+
base_url: import_zod.z.string().url().optional(),
|
|
587
|
+
project_id: import_zod.z.string().optional(),
|
|
588
|
+
customer: LLMAsAServiceCustomerSchema.optional(),
|
|
589
|
+
conversationId: import_zod.z.string().optional(),
|
|
590
|
+
conversationTitle: import_zod.z.string().optional(),
|
|
591
|
+
projectId: import_zod.z.string().optional()
|
|
592
|
+
});
|
|
279
593
|
var ProviderOptionsSchema = import_zod.z.object({
|
|
280
594
|
anthropic: AnthropicProviderOptionsSchema.optional(),
|
|
281
595
|
gemini: GeminiProviderOptionsSchema.optional(),
|
|
282
|
-
openrouter: OpenRouterProviderOptionsSchema.optional()
|
|
596
|
+
openrouter: OpenRouterProviderOptionsSchema.optional(),
|
|
597
|
+
llmasaservice: LLMAsAServiceProviderOptionsSchema.optional()
|
|
283
598
|
});
|
|
284
599
|
var RawProviderBodySchema = import_zod.z.object({
|
|
285
600
|
openai: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
@@ -288,7 +603,8 @@ var RawProviderBodySchema = import_zod.z.object({
|
|
|
288
603
|
anthropic: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
289
604
|
gemini: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
290
605
|
google: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
291
|
-
openrouter: import_zod.z.record(import_zod.z.unknown()).optional()
|
|
606
|
+
openrouter: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
607
|
+
llmasaservice: import_zod.z.record(import_zod.z.unknown()).optional()
|
|
292
608
|
});
|
|
293
609
|
var OpenAICacheSchema = import_zod.z.object({
|
|
294
610
|
prompt_cache_key: import_zod.z.string().min(1).optional(),
|
|
@@ -330,6 +646,8 @@ var ContextBuiltInValidatorSchema = import_zod.z.union([
|
|
|
330
646
|
]);
|
|
331
647
|
var ContextInputDefinitionObjectSchema = import_zod.z.object({
|
|
332
648
|
name: import_zod.z.string(),
|
|
649
|
+
optional: import_zod.z.boolean().optional(),
|
|
650
|
+
warnings: import_zod.z.boolean().optional(),
|
|
333
651
|
max_size: import_zod.z.number().int().positive().optional(),
|
|
334
652
|
trim: import_zod.z.union([import_zod.z.boolean(), import_zod.z.enum(["start", "end", "both"])]).optional(),
|
|
335
653
|
allow_regex: ContextRegexSchema.optional(),
|
|
@@ -359,7 +677,7 @@ var PromptAssetOverridesSchema = import_zod.z.object({
|
|
|
359
677
|
fallback_models: import_zod.z.array(import_zod.z.string()).optional(),
|
|
360
678
|
reasoning: ReasoningSchema.optional(),
|
|
361
679
|
sampling: SamplingSchema.optional(),
|
|
362
|
-
response:
|
|
680
|
+
response: ResponseSchemaWithValidation.optional(),
|
|
363
681
|
cache: CacheSchema.optional(),
|
|
364
682
|
raw: RawProviderBodySchema.optional(),
|
|
365
683
|
tools: import_zod.z.array(ToolRefSchema).optional(),
|
|
@@ -375,9 +693,21 @@ var SectionsSchema = import_zod.z.object({
|
|
|
375
693
|
notes: import_zod.z.string().optional()
|
|
376
694
|
});
|
|
377
695
|
var PromptDefaultsSchema = import_zod.z.object({
|
|
378
|
-
provider: import_zod.z.enum(["openai", "openai-responses", "anthropic", "google", "gemini", "openrouter", "any"]).optional(),
|
|
696
|
+
provider: import_zod.z.enum(["openai", "openai-responses", "anthropic", "google", "gemini", "openrouter", "llmasaservice", "any"]).optional(),
|
|
379
697
|
model: import_zod.z.string().optional(),
|
|
698
|
+
fallback_models: import_zod.z.array(import_zod.z.string()).optional(),
|
|
699
|
+
reasoning: ReasoningSchema.optional(),
|
|
700
|
+
sampling: SamplingSchema.optional(),
|
|
701
|
+
response: ResponseSchema.optional(),
|
|
380
702
|
cache: CacheSchema.optional(),
|
|
703
|
+
raw: RawProviderBodySchema.optional(),
|
|
704
|
+
tools: import_zod.z.array(ToolRefSchema).optional(),
|
|
705
|
+
provider_options: ProviderOptionsSchema.optional(),
|
|
706
|
+
mcp: MCPSchema.optional(),
|
|
707
|
+
context: ContextSchema.optional(),
|
|
708
|
+
includes: import_zod.z.array(import_zod.z.string()).optional(),
|
|
709
|
+
environments: import_zod.z.record(PromptAssetOverridesSchema).optional(),
|
|
710
|
+
tiers: import_zod.z.record(PromptAssetOverridesSchema).optional(),
|
|
381
711
|
metadata: MetadataSchema.optional(),
|
|
382
712
|
sections: import_zod.z.object({
|
|
383
713
|
system_instructions: import_zod.z.string().optional()
|
|
@@ -387,12 +717,12 @@ var PromptAssetSchema = import_zod.z.object({
|
|
|
387
717
|
id: import_zod.z.string(),
|
|
388
718
|
schema_version: import_zod.z.number().int().positive().default(1),
|
|
389
719
|
description: import_zod.z.string().optional(),
|
|
390
|
-
provider: import_zod.z.enum(["openai", "openai-responses", "anthropic", "google", "gemini", "openrouter", "any"]).optional(),
|
|
720
|
+
provider: import_zod.z.enum(["openai", "openai-responses", "anthropic", "google", "gemini", "openrouter", "llmasaservice", "any"]).optional(),
|
|
391
721
|
model: import_zod.z.string().optional(),
|
|
392
722
|
fallback_models: import_zod.z.array(import_zod.z.string()).optional(),
|
|
393
723
|
reasoning: ReasoningSchema.optional(),
|
|
394
724
|
sampling: SamplingSchema.optional(),
|
|
395
|
-
response:
|
|
725
|
+
response: ResponseSchemaWithValidation.optional(),
|
|
396
726
|
cache: CacheSchema.optional(),
|
|
397
727
|
raw: RawProviderBodySchema.optional(),
|
|
398
728
|
tools: import_zod.z.array(ToolRefSchema).optional(),
|
|
@@ -584,16 +914,122 @@ function parsePrompt(content, filePath) {
|
|
|
584
914
|
}
|
|
585
915
|
|
|
586
916
|
// src/parser/loader.ts
|
|
917
|
+
var import_promises2 = require("fs/promises");
|
|
918
|
+
var import_node_path2 = require("path");
|
|
919
|
+
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
920
|
+
|
|
921
|
+
// src/parser/response-schema-ref.ts
|
|
587
922
|
var import_promises = require("fs/promises");
|
|
923
|
+
var import_node_crypto = require("crypto");
|
|
588
924
|
var import_node_path = require("path");
|
|
589
|
-
var
|
|
925
|
+
var import_node_url = require("url");
|
|
926
|
+
var import_zod2 = require("zod");
|
|
927
|
+
var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
928
|
+
var SUPPORTED_SCHEMA_REF_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
|
|
929
|
+
async function resolveJsonSchemaRef(schemaRef, promptFilePath) {
|
|
930
|
+
const resolvedPath = (0, import_node_path.resolve)((0, import_node_path.dirname)(promptFilePath), schemaRef);
|
|
931
|
+
let raw;
|
|
932
|
+
try {
|
|
933
|
+
raw = await (0, import_promises.readFile)(resolvedPath, "utf-8");
|
|
934
|
+
} catch (error) {
|
|
935
|
+
const code = error.code;
|
|
936
|
+
if (code === "ENOENT") {
|
|
937
|
+
throw new Error(`POK050: response.schema_ref "${schemaRef}" not found (resolved from ${promptFilePath})`);
|
|
938
|
+
}
|
|
939
|
+
throw error;
|
|
940
|
+
}
|
|
941
|
+
let parsed;
|
|
942
|
+
try {
|
|
943
|
+
parsed = JSON.parse(raw);
|
|
944
|
+
} catch {
|
|
945
|
+
throw new Error(`POK050: response.schema_ref "${schemaRef}" is not valid JSON`);
|
|
946
|
+
}
|
|
947
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
948
|
+
throw new Error(`POK050: response.schema_ref "${schemaRef}" must resolve to a JSON object schema`);
|
|
949
|
+
}
|
|
950
|
+
return {
|
|
951
|
+
schema: parsed,
|
|
952
|
+
resolvedPath,
|
|
953
|
+
hash: (0, import_node_crypto.createHash)("sha256").update(raw).digest("hex")
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
async function resolveZodSchemaRef(schemaRef, promptFilePath) {
|
|
957
|
+
const resolvedPath = (0, import_node_path.resolve)((0, import_node_path.dirname)(promptFilePath), schemaRef);
|
|
958
|
+
let moduleSource;
|
|
959
|
+
try {
|
|
960
|
+
moduleSource = await (0, import_promises.readFile)(resolvedPath, "utf-8");
|
|
961
|
+
} catch (error) {
|
|
962
|
+
const code = error.code;
|
|
963
|
+
if (code === "ENOENT") {
|
|
964
|
+
throw new Error(`POK051: response.schema_ref "${schemaRef}" not found (resolved from ${promptFilePath})`);
|
|
965
|
+
}
|
|
966
|
+
throw error;
|
|
967
|
+
}
|
|
968
|
+
let imported;
|
|
969
|
+
try {
|
|
970
|
+
imported = await import((0, import_node_url.pathToFileURL)(resolvedPath).href);
|
|
971
|
+
} catch (error) {
|
|
972
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
973
|
+
throw new Error(`POK051: response.schema_ref "${schemaRef}" could not be imported as a module (${message})`);
|
|
974
|
+
}
|
|
975
|
+
const mod = imported;
|
|
976
|
+
const candidate = mod.default ?? mod.schema;
|
|
977
|
+
if (!(candidate instanceof import_zod2.z.ZodType)) {
|
|
978
|
+
throw new Error('POK051: zod schema modules must export a Zod schema as default export or named export "schema"');
|
|
979
|
+
}
|
|
980
|
+
const jsonSchema = (0, import_zod_to_json_schema.zodToJsonSchema)(candidate, {
|
|
981
|
+
target: "jsonSchema7",
|
|
982
|
+
$refStrategy: "none"
|
|
983
|
+
});
|
|
984
|
+
if (!jsonSchema || typeof jsonSchema !== "object" || Array.isArray(jsonSchema)) {
|
|
985
|
+
throw new Error(`POK051: response.schema_ref "${schemaRef}" did not produce a valid JSON schema object`);
|
|
986
|
+
}
|
|
987
|
+
return {
|
|
988
|
+
schema: jsonSchema,
|
|
989
|
+
resolvedPath,
|
|
990
|
+
hash: (0, import_node_crypto.createHash)("sha256").update(moduleSource).digest("hex")
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
async function resolveResponseSchemaRef(asset, promptFilePath) {
|
|
994
|
+
const schemaRef = asset.response?.schema_ref;
|
|
995
|
+
if (!schemaRef) return asset;
|
|
996
|
+
const ext = (0, import_node_path.extname)(schemaRef).toLowerCase();
|
|
997
|
+
if (!SUPPORTED_SCHEMA_REF_EXTENSIONS.has(ext)) {
|
|
998
|
+
throw new Error(`POK051: response.schema_ref "${schemaRef}" has unsupported extension "${ext}". Use .json, .js, .mjs, or .cjs`);
|
|
999
|
+
}
|
|
1000
|
+
const resolved = ext === ".json" ? await resolveJsonSchemaRef(schemaRef, promptFilePath) : await resolveZodSchemaRef(schemaRef, promptFilePath);
|
|
1001
|
+
return {
|
|
1002
|
+
...asset,
|
|
1003
|
+
response: {
|
|
1004
|
+
...asset.response,
|
|
1005
|
+
schema: resolved.schema,
|
|
1006
|
+
schema_ref: void 0,
|
|
1007
|
+
schema_source: {
|
|
1008
|
+
mode: ext === ".json" ? "schema_ref_json" : "schema_ref_zod_module",
|
|
1009
|
+
ref: schemaRef,
|
|
1010
|
+
resolved_path: resolved.resolvedPath,
|
|
1011
|
+
hash: resolved.hash
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// src/parser/loader.ts
|
|
590
1018
|
var DEFAULTS_FILE_NAME = "defaults.md";
|
|
591
1019
|
async function loadPromptFile(filePath, options = {}) {
|
|
592
|
-
const content = await (0,
|
|
1020
|
+
const content = await (0, import_promises2.readFile)(filePath, "utf-8");
|
|
593
1021
|
const parsed = parsePrompt(content, filePath);
|
|
594
|
-
const root = options.defaultsRoot ?? (0,
|
|
1022
|
+
const root = options.defaultsRoot ?? (0, import_node_path2.dirname)(filePath);
|
|
595
1023
|
const defaults = await loadDefaultsForPath(filePath, root);
|
|
596
|
-
const
|
|
1024
|
+
const withDefaults = applyDefaults(parsed.asset, defaults);
|
|
1025
|
+
const resolved = await resolveResponseSchemaRef(withDefaults, filePath);
|
|
1026
|
+
const asset = resolved.response?.schema !== void 0 && !resolved.response?.schema_source ? {
|
|
1027
|
+
...resolved,
|
|
1028
|
+
response: {
|
|
1029
|
+
...resolved.response,
|
|
1030
|
+
schema_source: { mode: "inline" }
|
|
1031
|
+
}
|
|
1032
|
+
} : resolved;
|
|
597
1033
|
return {
|
|
598
1034
|
...parsed,
|
|
599
1035
|
asset
|
|
@@ -603,10 +1039,10 @@ async function loadDefaultsForPath(filePath, defaultsRoot) {
|
|
|
603
1039
|
const directories = getDirectoriesToCheck(filePath, defaultsRoot);
|
|
604
1040
|
let merged = {};
|
|
605
1041
|
for (const dir of directories) {
|
|
606
|
-
const defaultsPath = (0,
|
|
1042
|
+
const defaultsPath = (0, import_node_path2.join)(dir, DEFAULTS_FILE_NAME);
|
|
607
1043
|
try {
|
|
608
|
-
const defaultsContent = await (0,
|
|
609
|
-
const defaults = parseDefaults(defaultsContent);
|
|
1044
|
+
const defaultsContent = await (0, import_promises2.readFile)(defaultsPath, "utf-8");
|
|
1045
|
+
const defaults = normalizeDefaultIncludes(parseDefaults(defaultsContent), defaultsPath, filePath);
|
|
610
1046
|
merged = mergeDefaults(merged, defaults);
|
|
611
1047
|
} catch (error) {
|
|
612
1048
|
if (error.code !== "ENOENT") {
|
|
@@ -618,14 +1054,14 @@ async function loadDefaultsForPath(filePath, defaultsRoot) {
|
|
|
618
1054
|
}
|
|
619
1055
|
function getDirectoriesToCheck(filePath, defaultsRoot) {
|
|
620
1056
|
const dirs = [];
|
|
621
|
-
let current = (0,
|
|
622
|
-
const boundary = defaultsRoot ? (0,
|
|
1057
|
+
let current = (0, import_node_path2.resolve)((0, import_node_path2.dirname)(filePath));
|
|
1058
|
+
const boundary = defaultsRoot ? (0, import_node_path2.resolve)(defaultsRoot) : void 0;
|
|
623
1059
|
while (true) {
|
|
624
1060
|
dirs.unshift(current);
|
|
625
|
-
if (boundary && current === boundary || current === (0,
|
|
1061
|
+
if (boundary && current === boundary || current === (0, import_node_path2.dirname)(current)) {
|
|
626
1062
|
break;
|
|
627
1063
|
}
|
|
628
|
-
current = (0,
|
|
1064
|
+
current = (0, import_node_path2.dirname)(current);
|
|
629
1065
|
}
|
|
630
1066
|
return dirs;
|
|
631
1067
|
}
|
|
@@ -643,7 +1079,19 @@ function mergeDefaults(base, local) {
|
|
|
643
1079
|
return {
|
|
644
1080
|
provider: local.provider ?? base.provider,
|
|
645
1081
|
model: local.model ?? base.model,
|
|
1082
|
+
fallback_models: local.fallback_models ?? base.fallback_models,
|
|
1083
|
+
reasoning: mergeRecordBlock2(base.reasoning, local.reasoning),
|
|
1084
|
+
sampling: mergeRecordBlock2(base.sampling, local.sampling),
|
|
1085
|
+
response: mergeRecordBlock2(base.response, local.response),
|
|
646
1086
|
cache: mergeCache(base.cache, local.cache),
|
|
1087
|
+
raw: mergeRaw(base.raw, local.raw),
|
|
1088
|
+
tools: local.tools ?? base.tools,
|
|
1089
|
+
provider_options: mergeProviderOptions(base.provider_options, local.provider_options),
|
|
1090
|
+
mcp: mergeMcp(base.mcp, local.mcp),
|
|
1091
|
+
context: mergeContext(base.context, local.context),
|
|
1092
|
+
includes: local.includes ?? base.includes,
|
|
1093
|
+
environments: mergeOverrideMap(base.environments, local.environments),
|
|
1094
|
+
tiers: mergeOverrideMap(base.tiers, local.tiers),
|
|
647
1095
|
metadata: {
|
|
648
1096
|
...base.metadata ?? {},
|
|
649
1097
|
...local.metadata ?? {}
|
|
@@ -656,11 +1104,20 @@ function mergeDefaults(base, local) {
|
|
|
656
1104
|
}
|
|
657
1105
|
function applyDefaults(asset, defaults) {
|
|
658
1106
|
const cache = mergeCache(defaults.cache, asset.cache);
|
|
1107
|
+
const raw = mergeRaw(defaults.raw, asset.raw);
|
|
1108
|
+
const providerOptions = mergeProviderOptions(defaults.provider_options, asset.provider_options);
|
|
1109
|
+
const reasoning = mergeRecordBlock2(defaults.reasoning, asset.reasoning);
|
|
1110
|
+
const sampling = mergeRecordBlock2(defaults.sampling, asset.sampling);
|
|
1111
|
+
const response = mergeRecordBlock2(defaults.response, asset.response);
|
|
1112
|
+
const mcp = mergeMcp(defaults.mcp, asset.mcp);
|
|
1113
|
+
const context = mergeContext(defaults.context, asset.context);
|
|
1114
|
+
const environments = mergeOverrideMap(defaults.environments, asset.environments);
|
|
1115
|
+
const tiers = mergeOverrideMap(defaults.tiers, asset.tiers);
|
|
659
1116
|
const hasDefaultMetadata = defaults.metadata && Object.keys(defaults.metadata).length > 0;
|
|
660
1117
|
const hasDefaultSystem = !!defaults.sections?.system_instructions;
|
|
661
|
-
const hasDefaultScalars = defaults.provider !== void 0 || defaults.model !== void 0;
|
|
662
|
-
const
|
|
663
|
-
if (!hasDefaultMetadata && !hasDefaultSystem && !hasDefaultScalars && !
|
|
1118
|
+
const hasDefaultScalars = defaults.provider !== void 0 || defaults.model !== void 0 || defaults.fallback_models !== void 0 || defaults.tools !== void 0 || defaults.includes !== void 0;
|
|
1119
|
+
const hasDefaultObjects = 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;
|
|
1120
|
+
if (!hasDefaultMetadata && !hasDefaultSystem && !hasDefaultScalars && !hasDefaultObjects) {
|
|
664
1121
|
return asset;
|
|
665
1122
|
}
|
|
666
1123
|
const mergedMetadata = {
|
|
@@ -674,11 +1131,52 @@ function applyDefaults(asset, defaults) {
|
|
|
674
1131
|
...asset,
|
|
675
1132
|
provider: asset.provider ?? defaults.provider,
|
|
676
1133
|
model: asset.model ?? defaults.model,
|
|
1134
|
+
fallback_models: asset.fallback_models ?? defaults.fallback_models,
|
|
1135
|
+
reasoning,
|
|
1136
|
+
sampling,
|
|
1137
|
+
response,
|
|
677
1138
|
cache,
|
|
1139
|
+
raw,
|
|
1140
|
+
tools: asset.tools ?? defaults.tools,
|
|
1141
|
+
provider_options: providerOptions,
|
|
1142
|
+
mcp,
|
|
1143
|
+
context,
|
|
1144
|
+
includes: asset.includes ?? defaults.includes,
|
|
1145
|
+
environments,
|
|
1146
|
+
tiers,
|
|
678
1147
|
metadata,
|
|
679
1148
|
sections
|
|
680
1149
|
};
|
|
681
1150
|
}
|
|
1151
|
+
function normalizeDefaultIncludes(defaults, defaultsPath, filePath) {
|
|
1152
|
+
if (!defaults.includes) return defaults;
|
|
1153
|
+
const promptDir = (0, import_node_path2.dirname)(filePath);
|
|
1154
|
+
const defaultsDir = (0, import_node_path2.dirname)(defaultsPath);
|
|
1155
|
+
const includes = defaults.includes.map((includePath) => {
|
|
1156
|
+
const relativePath = (0, import_node_path2.relative)(promptDir, (0, import_node_path2.resolve)(defaultsDir, includePath)).replace(/\\/g, "/");
|
|
1157
|
+
return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
1158
|
+
});
|
|
1159
|
+
return {
|
|
1160
|
+
...defaults,
|
|
1161
|
+
includes
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
function mergeRecordBlock2(base, local) {
|
|
1165
|
+
if (base === void 0) return local;
|
|
1166
|
+
if (local === void 0) return base;
|
|
1167
|
+
return { ...base, ...local };
|
|
1168
|
+
}
|
|
1169
|
+
function mergeMcp(base, local) {
|
|
1170
|
+
return mergeRecordBlock2(base, local);
|
|
1171
|
+
}
|
|
1172
|
+
function mergeContext(base, local) {
|
|
1173
|
+
const merged = {
|
|
1174
|
+
...base ?? {},
|
|
1175
|
+
...local ?? {},
|
|
1176
|
+
history: mergeRecordBlock2(base?.history, local?.history)
|
|
1177
|
+
};
|
|
1178
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
1179
|
+
}
|
|
682
1180
|
function mergeCache(base, local) {
|
|
683
1181
|
const merged = {
|
|
684
1182
|
...base ?? {},
|
|
@@ -706,406 +1204,248 @@ function mergeCache(base, local) {
|
|
|
706
1204
|
if (merged.google && Object.keys(merged.google).length === 0) delete merged.google;
|
|
707
1205
|
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
708
1206
|
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
let mergedSystemInstructions = "";
|
|
722
|
-
for (const includePath of asset.includes) {
|
|
723
|
-
const fullPath = (0, import_node_path2.resolve)(baseDir, includePath);
|
|
724
|
-
if (visited.has(fullPath)) {
|
|
725
|
-
throw new Error(`Circular include detected: ${fullPath} (included from ${basePath})`);
|
|
726
|
-
}
|
|
727
|
-
const content = await (0, import_promises2.readFile)(fullPath, "utf-8");
|
|
728
|
-
const { asset: includedAsset } = parsePrompt(content, fullPath);
|
|
729
|
-
const resolved = await resolveIncludes(includedAsset, fullPath, new Set(visited));
|
|
730
|
-
if (resolved.sections?.system_instructions) {
|
|
731
|
-
mergedSystemInstructions += resolved.sections.system_instructions + "\n\n";
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
const localSystem = asset.sections?.system_instructions ?? "";
|
|
735
|
-
const combinedSystem = (mergedSystemInstructions + localSystem).trim() || void 0;
|
|
736
|
-
return {
|
|
737
|
-
...asset,
|
|
738
|
-
sections: {
|
|
739
|
-
...asset.sections,
|
|
740
|
-
system_instructions: combinedSystem
|
|
741
|
-
},
|
|
742
|
-
// Drop includes from the resolved asset — they've been inlined
|
|
743
|
-
includes: void 0
|
|
744
|
-
};
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
// src/prompt-resolution.ts
|
|
748
|
-
var DEFAULT_PROMPTS_DIR = "./prompts";
|
|
749
|
-
var DEFAULT_COMPILED_JSON_DIR = "./.generated-prompts/json";
|
|
750
|
-
function withPromptResolutionDefaults(config) {
|
|
751
|
-
return {
|
|
752
|
-
...config,
|
|
753
|
-
sourceDir: config.sourceDir ?? DEFAULT_PROMPTS_DIR,
|
|
754
|
-
compiledDir: config.compiledDir ?? DEFAULT_COMPILED_JSON_DIR
|
|
755
|
-
};
|
|
756
|
-
}
|
|
757
|
-
var sharedPromptCache = new PromptCache();
|
|
758
|
-
async function loadPromptAsset(promptPath, config, promptCache = sharedPromptCache) {
|
|
759
|
-
const resolvedConfig = withPromptResolutionDefaults(config);
|
|
760
|
-
const mode = resolvedConfig.mode ?? "auto";
|
|
761
|
-
if (mode !== "source-only" && resolvedConfig.compiledDir) {
|
|
762
|
-
const compiledFile = (0, import_node_path3.resolve)(resolvedConfig.compiledDir, promptPath + ".json");
|
|
763
|
-
if ((0, import_node_fs2.existsSync)(compiledFile)) {
|
|
764
|
-
if (mode === "auto") {
|
|
765
|
-
const sourceFile = (0, import_node_path3.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
|
|
766
|
-
if ((0, import_node_fs2.existsSync)(sourceFile)) {
|
|
767
|
-
const compiledMtime = (0, import_node_fs2.statSync)(compiledFile).mtimeMs;
|
|
768
|
-
const sourceMtime = (0, import_node_fs2.statSync)(sourceFile).mtimeMs;
|
|
769
|
-
if (sourceMtime > compiledMtime) {
|
|
770
|
-
console.warn(
|
|
771
|
-
`[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
|
|
772
|
-
Run "promptopskit compile" or switch to source-only mode.`
|
|
773
|
-
);
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
const content = await (0, import_promises3.readFile)(compiledFile, "utf-8");
|
|
778
|
-
return JSON.parse(content);
|
|
779
|
-
}
|
|
780
|
-
if (mode === "compiled-only") {
|
|
781
|
-
throw new Error(
|
|
782
|
-
`Compiled artifact not found: ${compiledFile}
|
|
783
|
-
Run "promptopskit compile" to generate it.`
|
|
784
|
-
);
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
if (mode !== "compiled-only") {
|
|
788
|
-
const sourceFile = (0, import_node_path3.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
|
|
789
|
-
if (resolvedConfig.cache !== false) {
|
|
790
|
-
const cached = promptCache.get(sourceFile);
|
|
791
|
-
if (cached) {
|
|
792
|
-
return cached;
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
if (!(0, import_node_fs2.existsSync)(sourceFile)) {
|
|
796
|
-
const paths = [sourceFile];
|
|
797
|
-
if (resolvedConfig.compiledDir) {
|
|
798
|
-
paths.unshift((0, import_node_path3.resolve)(resolvedConfig.compiledDir, promptPath + ".json"));
|
|
799
|
-
}
|
|
800
|
-
throw new Error(
|
|
801
|
-
`Prompt not found: "${promptPath}"
|
|
802
|
-
Searched:
|
|
803
|
-
${paths.map((candidate) => ` - ${candidate}`).join("\n")}`
|
|
804
|
-
);
|
|
805
|
-
}
|
|
806
|
-
const { asset } = await loadPromptFile(sourceFile, { defaultsRoot: resolvedConfig.sourceDir });
|
|
807
|
-
if (resolvedConfig.cache !== false) {
|
|
808
|
-
promptCache.set(sourceFile, asset);
|
|
809
|
-
}
|
|
810
|
-
return asset;
|
|
811
|
-
}
|
|
812
|
-
throw new Error(`Prompt not found: "${promptPath}"`);
|
|
813
|
-
}
|
|
814
|
-
async function resolvePromptAsset(promptPath, config, options = {}, promptCache = sharedPromptCache) {
|
|
815
|
-
const resolvedConfig = withPromptResolutionDefaults(config);
|
|
816
|
-
let asset = await loadPromptAsset(promptPath, resolvedConfig, promptCache);
|
|
817
|
-
const sourceFile = (0, import_node_path3.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
|
|
818
|
-
if (asset.includes && asset.includes.length > 0 && (0, import_node_fs2.existsSync)(sourceFile)) {
|
|
819
|
-
asset = await resolveIncludes(asset, sourceFile);
|
|
820
|
-
}
|
|
821
|
-
asset = applyOverrides(asset, {
|
|
822
|
-
environment: options.environment,
|
|
823
|
-
tier: options.tier,
|
|
824
|
-
runtime: options.runtime
|
|
825
|
-
});
|
|
826
|
-
return asset;
|
|
827
|
-
}
|
|
828
|
-
function resolveInlinePromptSource(source, options = {}) {
|
|
829
|
-
const { asset } = parsePrompt(source);
|
|
830
|
-
return applyOverrides(asset, {
|
|
831
|
-
environment: options.environment,
|
|
832
|
-
tier: options.tier,
|
|
833
|
-
runtime: options.runtime
|
|
834
|
-
});
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
// src/context.ts
|
|
838
|
-
var textEncoder = new TextEncoder();
|
|
839
|
-
var REJECT_SECRETS_PATTERN = "(secret|api[_-]?key|password)";
|
|
840
|
-
var REJECT_SECRETS_FLAGS = "i";
|
|
841
|
-
function getContextInputs(asset) {
|
|
842
|
-
return (asset.context?.inputs ?? []).map(normalizeContextInput);
|
|
843
|
-
}
|
|
844
|
-
function normalizeContextInput(input) {
|
|
845
|
-
if (typeof input === "string") {
|
|
846
|
-
return { name: input };
|
|
847
|
-
}
|
|
848
|
-
return {
|
|
849
|
-
name: input.name,
|
|
850
|
-
max_size: input.max_size,
|
|
851
|
-
trim: input.trim,
|
|
852
|
-
allow_regex: normalizeContextRegex(input.allow_regex),
|
|
853
|
-
deny_regex: normalizeContextRegex(input.deny_regex),
|
|
854
|
-
non_empty: normalizeBuiltInValidator(input.non_empty),
|
|
855
|
-
reject_secrets: normalizeBuiltInValidator(input.reject_secrets)
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
|
-
function normalizeContextRegex(value) {
|
|
859
|
-
if (value === void 0) {
|
|
860
|
-
return void 0;
|
|
861
|
-
}
|
|
862
|
-
if (typeof value === "string") {
|
|
863
|
-
const literal = parseRegexLiteral(value);
|
|
864
|
-
if (value.startsWith("/") && !literal) {
|
|
865
|
-
return {
|
|
866
|
-
pattern: value,
|
|
867
|
-
flags: "",
|
|
868
|
-
raw: value,
|
|
869
|
-
invalidLiteral: true
|
|
870
|
-
};
|
|
871
|
-
}
|
|
872
|
-
return {
|
|
873
|
-
pattern: literal?.pattern ?? value,
|
|
874
|
-
flags: literal?.flags ?? "",
|
|
875
|
-
raw: value
|
|
876
|
-
};
|
|
877
|
-
}
|
|
878
|
-
return {
|
|
879
|
-
pattern: value.pattern,
|
|
880
|
-
flags: value.flags ?? "",
|
|
881
|
-
raw: JSON.stringify(value),
|
|
882
|
-
returnMessage: value.return_message
|
|
883
|
-
};
|
|
884
|
-
}
|
|
885
|
-
function normalizeBuiltInValidator(value) {
|
|
886
|
-
if (value === void 0 || value === false) {
|
|
887
|
-
return void 0;
|
|
888
|
-
}
|
|
889
|
-
if (value === true) {
|
|
890
|
-
return {};
|
|
891
|
-
}
|
|
892
|
-
return {
|
|
893
|
-
returnMessage: value.return_message
|
|
1207
|
+
function mergeRaw(base, local) {
|
|
1208
|
+
const merged = {
|
|
1209
|
+
...base ?? {},
|
|
1210
|
+
...local ?? {},
|
|
1211
|
+
openai: mergeRecordBlock2(base?.openai, local?.openai),
|
|
1212
|
+
"openai-responses": mergeRecordBlock2(base?.["openai-responses"], local?.["openai-responses"]),
|
|
1213
|
+
openai_responses: mergeRecordBlock2(base?.openai_responses, local?.openai_responses),
|
|
1214
|
+
anthropic: mergeRecordBlock2(base?.anthropic, local?.anthropic),
|
|
1215
|
+
gemini: mergeRecordBlock2(base?.gemini, local?.gemini),
|
|
1216
|
+
google: mergeRecordBlock2(base?.google, local?.google),
|
|
1217
|
+
openrouter: mergeRecordBlock2(base?.openrouter, local?.openrouter),
|
|
1218
|
+
llmasaservice: mergeRecordBlock2(base?.llmasaservice, local?.llmasaservice)
|
|
894
1219
|
};
|
|
1220
|
+
removeEmptyProviderBlocks(merged);
|
|
1221
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
895
1222
|
}
|
|
896
|
-
function
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
let backslashCount = 0;
|
|
905
|
-
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
|
|
906
|
-
backslashCount += 1;
|
|
907
|
-
}
|
|
908
|
-
if (backslashCount % 2 === 1) {
|
|
909
|
-
continue;
|
|
910
|
-
}
|
|
911
|
-
return {
|
|
912
|
-
pattern: value.slice(1, index),
|
|
913
|
-
flags: value.slice(index + 1)
|
|
914
|
-
};
|
|
915
|
-
}
|
|
916
|
-
return void 0;
|
|
917
|
-
}
|
|
918
|
-
function formatInvalidContextRegexMessage(details) {
|
|
919
|
-
return [
|
|
920
|
-
`Invalid context regex for prompt "${details.promptId}"`,
|
|
921
|
-
`variable "${details.variable}"`,
|
|
922
|
-
`field "${details.field}"`,
|
|
923
|
-
`value ${JSON.stringify(details.raw)}: ${details.reason}`
|
|
924
|
-
].join(", ");
|
|
925
|
-
}
|
|
926
|
-
function compileContextRegex(regex, details) {
|
|
927
|
-
if (regex.invalidLiteral) {
|
|
928
|
-
throw new Error(
|
|
929
|
-
`POK013: ${formatInvalidContextRegexMessage({
|
|
930
|
-
...details,
|
|
931
|
-
raw: regex.raw,
|
|
932
|
-
reason: "Malformed regex literal. Use /pattern/flags or { pattern, flags }."
|
|
933
|
-
})}`
|
|
934
|
-
);
|
|
935
|
-
}
|
|
936
|
-
try {
|
|
937
|
-
return new RegExp(regex.pattern, regex.flags);
|
|
938
|
-
} catch (error) {
|
|
939
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
940
|
-
throw new Error(`POK013: ${formatInvalidContextRegexMessage({ ...details, raw: regex.raw, reason })}`);
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
function getRejectSecretsRegex() {
|
|
944
|
-
return {
|
|
945
|
-
pattern: REJECT_SECRETS_PATTERN,
|
|
946
|
-
flags: REJECT_SECRETS_FLAGS,
|
|
947
|
-
raw: JSON.stringify({ pattern: REJECT_SECRETS_PATTERN, flags: REJECT_SECRETS_FLAGS })
|
|
1223
|
+
function mergeProviderOptions(base, local) {
|
|
1224
|
+
const merged = {
|
|
1225
|
+
...base ?? {},
|
|
1226
|
+
...local ?? {},
|
|
1227
|
+
anthropic: mergeRecordBlock2(base?.anthropic, local?.anthropic),
|
|
1228
|
+
gemini: mergeRecordBlock2(base?.gemini, local?.gemini),
|
|
1229
|
+
openrouter: mergeRecordBlock2(base?.openrouter, local?.openrouter),
|
|
1230
|
+
llmasaservice: mergeRecordBlock2(base?.llmasaservice, local?.llmasaservice)
|
|
948
1231
|
};
|
|
1232
|
+
removeEmptyProviderBlocks(merged);
|
|
1233
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
949
1234
|
}
|
|
950
|
-
function
|
|
951
|
-
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
if (mode === "start") {
|
|
955
|
-
return "start";
|
|
956
|
-
}
|
|
957
|
-
return "end";
|
|
958
|
-
}
|
|
959
|
-
function trimToMaxSize(value, maxSize, mode) {
|
|
960
|
-
const measured = measureContextValueSize(value);
|
|
961
|
-
if (measured <= maxSize) {
|
|
962
|
-
return value;
|
|
1235
|
+
function mergeOverrideMap(base, local) {
|
|
1236
|
+
const merged = { ...base ?? {} };
|
|
1237
|
+
for (const [name, localOverride] of Object.entries(local ?? {})) {
|
|
1238
|
+
merged[name] = mergeOverrideConfig(merged[name], localOverride);
|
|
963
1239
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1240
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
1241
|
+
}
|
|
1242
|
+
function mergeOverrideConfig(base, local) {
|
|
1243
|
+
const merged = {
|
|
1244
|
+
...base ?? {},
|
|
1245
|
+
...local
|
|
1246
|
+
};
|
|
1247
|
+
const reasoning = mergeRecordBlock2(base?.reasoning, local.reasoning);
|
|
1248
|
+
const sampling = mergeRecordBlock2(base?.sampling, local.sampling);
|
|
1249
|
+
const response = mergeRecordBlock2(base?.response, local.response);
|
|
1250
|
+
const cache = mergeCache(base?.cache, local.cache);
|
|
1251
|
+
const raw = mergeRaw(base?.raw, local.raw);
|
|
1252
|
+
const providerOptions = mergeProviderOptions(base?.provider_options, local.provider_options);
|
|
1253
|
+
if (reasoning !== void 0) merged.reasoning = reasoning;
|
|
1254
|
+
if (sampling !== void 0) merged.sampling = sampling;
|
|
1255
|
+
if (response !== void 0) merged.response = response;
|
|
1256
|
+
if (cache !== void 0) merged.cache = cache;
|
|
1257
|
+
if (raw !== void 0) merged.raw = raw;
|
|
1258
|
+
if (providerOptions !== void 0) merged.provider_options = providerOptions;
|
|
1259
|
+
return merged;
|
|
1260
|
+
}
|
|
1261
|
+
function removeEmptyProviderBlocks(value) {
|
|
1262
|
+
for (const key of Object.keys(value)) {
|
|
1263
|
+
const block = value[key];
|
|
1264
|
+
if (block === void 0) {
|
|
1265
|
+
delete value[key];
|
|
1266
|
+
continue;
|
|
977
1267
|
}
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
let collected = "";
|
|
981
|
-
let size = 0;
|
|
982
|
-
for (const char of characters) {
|
|
983
|
-
const charSize = measureContextValueSize(char);
|
|
984
|
-
if (size + charSize > maxSize) {
|
|
985
|
-
break;
|
|
1268
|
+
if (block !== null && typeof block === "object" && !Array.isArray(block) && Object.keys(block).length === 0) {
|
|
1269
|
+
delete value[key];
|
|
986
1270
|
}
|
|
987
|
-
collected += char;
|
|
988
|
-
size += charSize;
|
|
989
1271
|
}
|
|
990
|
-
return collected;
|
|
991
1272
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
actualSize
|
|
1010
|
-
});
|
|
1011
|
-
}
|
|
1273
|
+
|
|
1274
|
+
// src/composition/resolve-includes.ts
|
|
1275
|
+
async function resolveIncludes(asset, basePath, visited = /* @__PURE__ */ new Set()) {
|
|
1276
|
+
if (!asset.includes || asset.includes.length === 0) {
|
|
1277
|
+
return asset;
|
|
1278
|
+
}
|
|
1279
|
+
const baseDir = (0, import_node_path3.dirname)(basePath);
|
|
1280
|
+
const resolvedPath = (0, import_node_path3.resolve)(basePath);
|
|
1281
|
+
if (visited.has(resolvedPath)) {
|
|
1282
|
+
throw new Error(`Circular include detected: ${resolvedPath}`);
|
|
1283
|
+
}
|
|
1284
|
+
visited.add(resolvedPath);
|
|
1285
|
+
let mergedSystemInstructions = "";
|
|
1286
|
+
for (const includePath of asset.includes) {
|
|
1287
|
+
const fullPath = (0, import_node_path3.resolve)(baseDir, includePath);
|
|
1288
|
+
if (visited.has(fullPath)) {
|
|
1289
|
+
throw new Error(`Circular include detected: ${fullPath} (included from ${basePath})`);
|
|
1012
1290
|
}
|
|
1013
|
-
|
|
1014
|
-
|
|
1291
|
+
const content = await (0, import_promises3.readFile)(fullPath, "utf-8");
|
|
1292
|
+
const { asset: includedAsset } = parsePrompt(content, fullPath);
|
|
1293
|
+
const resolved = await resolveIncludes(includedAsset, fullPath, new Set(visited));
|
|
1294
|
+
if (resolved.sections?.system_instructions) {
|
|
1295
|
+
mergedSystemInstructions += resolved.sections.system_instructions + "\n\n";
|
|
1015
1296
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1297
|
+
}
|
|
1298
|
+
const localSystem = asset.sections?.system_instructions ?? "";
|
|
1299
|
+
const combinedSystem = (mergedSystemInstructions + localSystem).trim() || void 0;
|
|
1300
|
+
return {
|
|
1301
|
+
...asset,
|
|
1302
|
+
sections: {
|
|
1303
|
+
...asset.sections,
|
|
1304
|
+
system_instructions: combinedSystem
|
|
1305
|
+
},
|
|
1306
|
+
// Drop includes from the resolved asset — they've been inlined
|
|
1307
|
+
includes: void 0
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
// src/prompt-resolution.ts
|
|
1312
|
+
var DEFAULT_PROMPTS_DIR = "./prompts";
|
|
1313
|
+
var DEFAULT_COMPILED_JSON_DIR = "./.generated-prompts/json";
|
|
1314
|
+
function withPromptResolutionDefaults(config) {
|
|
1315
|
+
return {
|
|
1316
|
+
...config,
|
|
1317
|
+
sourceDir: config.sourceDir ?? DEFAULT_PROMPTS_DIR,
|
|
1318
|
+
compiledDir: config.compiledDir ?? DEFAULT_COMPILED_JSON_DIR
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
var sharedPromptCache = new PromptCache();
|
|
1322
|
+
async function loadPromptAsset(promptPath, config, promptCache = sharedPromptCache) {
|
|
1323
|
+
const resolvedConfig = withPromptResolutionDefaults(config);
|
|
1324
|
+
const mode = resolvedConfig.mode ?? "auto";
|
|
1325
|
+
if (mode !== "source-only" && resolvedConfig.compiledDir) {
|
|
1326
|
+
const compiledFile = (0, import_node_path4.resolve)(resolvedConfig.compiledDir, promptPath + ".json");
|
|
1327
|
+
if ((0, import_node_fs2.existsSync)(compiledFile)) {
|
|
1328
|
+
if (mode === "auto") {
|
|
1329
|
+
const sourceFile = (0, import_node_path4.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
|
|
1330
|
+
if ((0, import_node_fs2.existsSync)(sourceFile)) {
|
|
1331
|
+
const compiledMtime = (0, import_node_fs2.statSync)(compiledFile).mtimeMs;
|
|
1332
|
+
const sourceMtime = (0, import_node_fs2.statSync)(sourceFile).mtimeMs;
|
|
1333
|
+
if (sourceMtime > compiledMtime) {
|
|
1334
|
+
console.warn(
|
|
1335
|
+
`[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
|
|
1336
|
+
Run "promptopskit compile" or switch to source-only mode.`
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1035
1339
|
}
|
|
1036
|
-
throw new Error(
|
|
1037
|
-
`POK031: Context variable "${input.name}" failed allow_regex validation for prompt "${asset.id}".`
|
|
1038
|
-
);
|
|
1039
1340
|
}
|
|
1341
|
+
const content = await (0, import_promises4.readFile)(compiledFile, "utf-8");
|
|
1342
|
+
return JSON.parse(content);
|
|
1040
1343
|
}
|
|
1041
|
-
if (
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
code: "POK032",
|
|
1055
|
-
variable: input.name,
|
|
1056
|
-
field: "deny_regex"
|
|
1057
|
-
}
|
|
1058
|
-
};
|
|
1059
|
-
}
|
|
1060
|
-
throw new Error(
|
|
1061
|
-
`POK032: Context variable "${input.name}" matched deny_regex for prompt "${asset.id}".`
|
|
1062
|
-
);
|
|
1344
|
+
if (mode === "compiled-only") {
|
|
1345
|
+
throw new Error(
|
|
1346
|
+
`Compiled artifact not found: ${compiledFile}
|
|
1347
|
+
Run "promptopskit compile" to generate it.`
|
|
1348
|
+
);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
if (mode !== "compiled-only") {
|
|
1352
|
+
const sourceFile = (0, import_node_path4.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
|
|
1353
|
+
if (resolvedConfig.cache !== false) {
|
|
1354
|
+
const cached = promptCache.get(sourceFile);
|
|
1355
|
+
if (cached) {
|
|
1356
|
+
return cached;
|
|
1063
1357
|
}
|
|
1064
1358
|
}
|
|
1065
|
-
if (
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
shortCircuit: {
|
|
1070
|
-
returnMessage: input.non_empty.returnMessage,
|
|
1071
|
-
code: "POK033",
|
|
1072
|
-
variable: input.name,
|
|
1073
|
-
field: "non_empty"
|
|
1074
|
-
}
|
|
1075
|
-
};
|
|
1359
|
+
if (!(0, import_node_fs2.existsSync)(sourceFile)) {
|
|
1360
|
+
const paths = [sourceFile];
|
|
1361
|
+
if (resolvedConfig.compiledDir) {
|
|
1362
|
+
paths.unshift((0, import_node_path4.resolve)(resolvedConfig.compiledDir, promptPath + ".json"));
|
|
1076
1363
|
}
|
|
1077
1364
|
throw new Error(
|
|
1078
|
-
`
|
|
1365
|
+
`Prompt not found: "${promptPath}"
|
|
1366
|
+
Searched:
|
|
1367
|
+
${paths.map((candidate) => ` - ${candidate}`).join("\n")}`
|
|
1079
1368
|
);
|
|
1080
1369
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
variable: input.name,
|
|
1085
|
-
field: "reject_secrets"
|
|
1086
|
-
});
|
|
1087
|
-
if (matcher.test(candidate)) {
|
|
1088
|
-
if (input.reject_secrets.returnMessage) {
|
|
1089
|
-
return {
|
|
1090
|
-
variables: sanitized,
|
|
1091
|
-
shortCircuit: {
|
|
1092
|
-
returnMessage: input.reject_secrets.returnMessage,
|
|
1093
|
-
code: "POK034",
|
|
1094
|
-
variable: input.name,
|
|
1095
|
-
field: "reject_secrets"
|
|
1096
|
-
}
|
|
1097
|
-
};
|
|
1098
|
-
}
|
|
1099
|
-
throw new Error(
|
|
1100
|
-
`POK034: Context variable "${input.name}" matched reject_secrets validation for prompt "${asset.id}".`
|
|
1101
|
-
);
|
|
1102
|
-
}
|
|
1370
|
+
const { asset } = await loadPromptFile(sourceFile, { defaultsRoot: resolvedConfig.sourceDir });
|
|
1371
|
+
if (resolvedConfig.cache !== false) {
|
|
1372
|
+
promptCache.set(sourceFile, asset);
|
|
1103
1373
|
}
|
|
1374
|
+
return asset;
|
|
1104
1375
|
}
|
|
1105
|
-
|
|
1376
|
+
throw new Error(`Prompt not found: "${promptPath}"`);
|
|
1106
1377
|
}
|
|
1107
|
-
function
|
|
1108
|
-
|
|
1378
|
+
async function resolvePromptAsset(promptPath, config, options = {}, promptCache = sharedPromptCache) {
|
|
1379
|
+
const resolvedConfig = withPromptResolutionDefaults(config);
|
|
1380
|
+
let asset = await loadPromptAsset(promptPath, resolvedConfig, promptCache);
|
|
1381
|
+
const sourceFile = (0, import_node_path4.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
|
|
1382
|
+
if (asset.includes && asset.includes.length > 0 && (0, import_node_fs2.existsSync)(sourceFile)) {
|
|
1383
|
+
asset = await resolveIncludes(asset, sourceFile);
|
|
1384
|
+
}
|
|
1385
|
+
asset = applyOverrides(asset, {
|
|
1386
|
+
environment: options.environment,
|
|
1387
|
+
tier: options.tier,
|
|
1388
|
+
runtime: options.runtime
|
|
1389
|
+
});
|
|
1390
|
+
return asset;
|
|
1391
|
+
}
|
|
1392
|
+
function resolveInlinePromptSource(source, options = {}) {
|
|
1393
|
+
const { asset } = parsePrompt(source);
|
|
1394
|
+
return applyOverrides(asset, {
|
|
1395
|
+
environment: options.environment,
|
|
1396
|
+
tier: options.tier,
|
|
1397
|
+
runtime: options.runtime
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// src/history.ts
|
|
1402
|
+
function defaultCompactHistory(info) {
|
|
1403
|
+
const content = info.overflow.map((message) => `${message.role}: ${message.content}`).join("\n\n");
|
|
1404
|
+
return {
|
|
1405
|
+
role: "user",
|
|
1406
|
+
content: `Earlier conversation compacted to preserve history:
|
|
1407
|
+
|
|
1408
|
+
${content}`
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
function normalizeCompactionResult(result) {
|
|
1412
|
+
if (typeof result === "string") {
|
|
1413
|
+
return {
|
|
1414
|
+
role: "user",
|
|
1415
|
+
content: result
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
return result;
|
|
1419
|
+
}
|
|
1420
|
+
function compactHistoryForPrompt(asset, runtime) {
|
|
1421
|
+
const history = runtime.history;
|
|
1422
|
+
const maxItems = asset.context?.history?.max_items;
|
|
1423
|
+
if (!history || maxItems === void 0 || history.length <= maxItems) {
|
|
1424
|
+
return history;
|
|
1425
|
+
}
|
|
1426
|
+
if (maxItems === 1) {
|
|
1427
|
+
const info2 = {
|
|
1428
|
+
promptId: asset.id,
|
|
1429
|
+
maxItems,
|
|
1430
|
+
overflow: history,
|
|
1431
|
+
preserved: [],
|
|
1432
|
+
history
|
|
1433
|
+
};
|
|
1434
|
+
const compacted2 = runtime.onHistoryCompaction ? normalizeCompactionResult(runtime.onHistoryCompaction(info2)) : defaultCompactHistory(info2);
|
|
1435
|
+
return [compacted2];
|
|
1436
|
+
}
|
|
1437
|
+
const preservedCount = maxItems - 1;
|
|
1438
|
+
const overflow = history.slice(0, history.length - preservedCount);
|
|
1439
|
+
const preserved = history.slice(-preservedCount);
|
|
1440
|
+
const info = {
|
|
1441
|
+
promptId: asset.id,
|
|
1442
|
+
maxItems,
|
|
1443
|
+
overflow,
|
|
1444
|
+
preserved,
|
|
1445
|
+
history
|
|
1446
|
+
};
|
|
1447
|
+
const compacted = runtime.onHistoryCompaction ? normalizeCompactionResult(runtime.onHistoryCompaction(info)) : defaultCompactHistory(info);
|
|
1448
|
+
return [compacted, ...preserved];
|
|
1109
1449
|
}
|
|
1110
1450
|
|
|
1111
1451
|
// src/providers/prompt-input.ts
|
|
@@ -1143,7 +1483,8 @@ function withPromptInputSupport(adapter) {
|
|
|
1143
1483
|
}
|
|
1144
1484
|
return adapter.render(resolved, {
|
|
1145
1485
|
...runtime,
|
|
1146
|
-
variables: sanitization.variables
|
|
1486
|
+
variables: sanitization.variables,
|
|
1487
|
+
history: compactHistoryForPrompt(resolved, runtime)
|
|
1147
1488
|
});
|
|
1148
1489
|
};
|
|
1149
1490
|
return {
|
|
@@ -1201,8 +1542,9 @@ var geminiAdapter = withPromptInputSupport({
|
|
|
1201
1542
|
strict: runtime.strict
|
|
1202
1543
|
});
|
|
1203
1544
|
const contents = [];
|
|
1204
|
-
|
|
1205
|
-
|
|
1545
|
+
const history = compactHistoryForPrompt(resolvedAsset, runtime);
|
|
1546
|
+
if (history) {
|
|
1547
|
+
for (const msg of history) {
|
|
1206
1548
|
contents.push({
|
|
1207
1549
|
role: msg.role === "assistant" ? "model" : "user",
|
|
1208
1550
|
parts: [{ text: msg.content }]
|