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
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
|
+
LLMASASERVICE_BASE_URL: () => LLMASASERVICE_BASE_URL,
|
|
34
|
+
LLMASASERVICE_DEFAULT_MODEL: () => LLMASASERVICE_DEFAULT_MODEL,
|
|
35
|
+
LLMASASERVICE_RESPONSE_HEADER_NAMES: () => LLMASASERVICE_RESPONSE_HEADER_NAMES,
|
|
36
|
+
LLMASASERVICE_SDK_PLACEHOLDER_API_KEY: () => LLMASASERVICE_SDK_PLACEHOLDER_API_KEY,
|
|
33
37
|
PromptAssetOverridesSchema: () => PromptAssetOverridesSchema,
|
|
34
38
|
PromptAssetSchema: () => PromptAssetSchema,
|
|
35
39
|
PromptOpsKit: () => PromptOpsKit,
|
|
@@ -37,6 +41,7 @@ __export(src_exports, {
|
|
|
37
41
|
applyOverrides: () => applyOverrides,
|
|
38
42
|
applyUsageTapEntitlements: () => applyUsageTapEntitlements,
|
|
39
43
|
beginUsageTapCall: () => beginUsageTapCall,
|
|
44
|
+
createLLMAsAServiceOpenAIConfig: () => createLLMAsAServiceOpenAIConfig,
|
|
40
45
|
createPromptOpsKit: () => createPromptOpsKit,
|
|
41
46
|
createUsageTapClient: () => createUsageTapClient,
|
|
42
47
|
defaultUsageTapErrorMapper: () => defaultUsageTapErrorMapper,
|
|
@@ -49,6 +54,7 @@ __export(src_exports, {
|
|
|
49
54
|
geminiAdapter: () => geminiAdapter,
|
|
50
55
|
getAdapter: () => getAdapter,
|
|
51
56
|
interpolate: () => interpolate,
|
|
57
|
+
llmasaserviceAdapter: () => llmasaserviceAdapter,
|
|
52
58
|
loadPromptFile: () => loadPromptFile,
|
|
53
59
|
openaiAdapter: () => openaiAdapter,
|
|
54
60
|
openaiResponsesAdapter: () => openaiResponsesAdapter,
|
|
@@ -58,6 +64,7 @@ __export(src_exports, {
|
|
|
58
64
|
resolveIncludes: () => resolveIncludes,
|
|
59
65
|
runAnthropicWithUsageTap: () => runAnthropicWithUsageTap,
|
|
60
66
|
runGeminiWithUsageTap: () => runGeminiWithUsageTap,
|
|
67
|
+
runLLMAsAServiceWithUsageTap: () => runLLMAsAServiceWithUsageTap,
|
|
61
68
|
runOpenAIWithUsageTap: () => runOpenAIWithUsageTap,
|
|
62
69
|
runOpenRouterWithUsageTap: () => runOpenRouterWithUsageTap,
|
|
63
70
|
validateAsset: () => validateAsset,
|
|
@@ -65,7 +72,7 @@ __export(src_exports, {
|
|
|
65
72
|
withUsageTapCall: () => withUsageTapCall
|
|
66
73
|
});
|
|
67
74
|
module.exports = __toCommonJS(src_exports);
|
|
68
|
-
var
|
|
75
|
+
var import_node_path5 = require("path");
|
|
69
76
|
|
|
70
77
|
// src/renderer/interpolate.ts
|
|
71
78
|
var VARIABLE_RE = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
|
|
@@ -73,12 +80,13 @@ var ESCAPED_OPEN = /\\\{\\\{/g;
|
|
|
73
80
|
var ESCAPE_PLACEHOLDER = "\0ESCAPED_OPEN\0";
|
|
74
81
|
function interpolate(template, variables, options = {}) {
|
|
75
82
|
const { strict = false } = options;
|
|
83
|
+
const optionalVariables = new Set(options.optionalVariables ?? []);
|
|
76
84
|
let result = template.replace(ESCAPED_OPEN, ESCAPE_PLACEHOLDER);
|
|
77
85
|
result = result.replace(VARIABLE_RE, (match, name) => {
|
|
78
86
|
if (name in variables) {
|
|
79
87
|
return variables[name];
|
|
80
88
|
}
|
|
81
|
-
if (strict) {
|
|
89
|
+
if (strict && !optionalVariables.has(name)) {
|
|
82
90
|
throw new Error(`Missing required variable: "${name}"`);
|
|
83
91
|
}
|
|
84
92
|
return match;
|
|
@@ -96,160 +104,469 @@ function extractVariables(template) {
|
|
|
96
104
|
return [...vars];
|
|
97
105
|
}
|
|
98
106
|
|
|
99
|
-
// src/
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
asset.sections.system_instructions,
|
|
106
|
-
variables,
|
|
107
|
-
{ strict }
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
if (asset.sections.prompt_template) {
|
|
111
|
-
result.prompt_template = interpolate(
|
|
112
|
-
asset.sections.prompt_template,
|
|
113
|
-
variables,
|
|
114
|
-
{ strict }
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
return result;
|
|
107
|
+
// src/context.ts
|
|
108
|
+
var textEncoder = new TextEncoder();
|
|
109
|
+
var REJECT_SECRETS_PATTERN = "(secret|api[_-]?key|password)";
|
|
110
|
+
var REJECT_SECRETS_FLAGS = "i";
|
|
111
|
+
function getContextInputs(asset) {
|
|
112
|
+
return (asset.context?.inputs ?? []).map(normalizeContextInput);
|
|
118
113
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
let result = { ...asset };
|
|
123
|
-
if (options.environment && result.environments?.[options.environment]) {
|
|
124
|
-
result = mergeOverride(result, result.environments[options.environment]);
|
|
114
|
+
function normalizeContextInput(input) {
|
|
115
|
+
if (typeof input === "string") {
|
|
116
|
+
return { name: input };
|
|
125
117
|
}
|
|
126
|
-
|
|
127
|
-
|
|
118
|
+
return {
|
|
119
|
+
name: input.name,
|
|
120
|
+
optional: input.optional,
|
|
121
|
+
warnings: input.warnings,
|
|
122
|
+
max_size: input.max_size,
|
|
123
|
+
trim: input.trim,
|
|
124
|
+
allow_regex: normalizeContextRegex(input.allow_regex),
|
|
125
|
+
deny_regex: normalizeContextRegex(input.deny_regex),
|
|
126
|
+
non_empty: normalizeBuiltInValidator(input.non_empty),
|
|
127
|
+
reject_secrets: normalizeBuiltInValidator(input.reject_secrets)
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function areContextInputWarningsEnabled(input) {
|
|
131
|
+
return input.warnings !== false;
|
|
132
|
+
}
|
|
133
|
+
function normalizeContextRegex(value) {
|
|
134
|
+
if (value === void 0) {
|
|
135
|
+
return void 0;
|
|
128
136
|
}
|
|
129
|
-
if (
|
|
130
|
-
|
|
137
|
+
if (typeof value === "string") {
|
|
138
|
+
const literal = parseRegexLiteral(value);
|
|
139
|
+
if (value.startsWith("/") && !literal) {
|
|
140
|
+
return {
|
|
141
|
+
pattern: value,
|
|
142
|
+
flags: "",
|
|
143
|
+
raw: value,
|
|
144
|
+
invalidLiteral: true
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
pattern: literal?.pattern ?? value,
|
|
149
|
+
flags: literal?.flags ?? "",
|
|
150
|
+
raw: value
|
|
151
|
+
};
|
|
131
152
|
}
|
|
132
|
-
return
|
|
153
|
+
return {
|
|
154
|
+
pattern: value.pattern,
|
|
155
|
+
flags: value.flags ?? "",
|
|
156
|
+
raw: JSON.stringify(value),
|
|
157
|
+
returnMessage: value.return_message
|
|
158
|
+
};
|
|
133
159
|
}
|
|
134
|
-
function
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (override.fallback_models !== void 0) result.fallback_models = override.fallback_models;
|
|
138
|
-
if (override.tools !== void 0) result.tools = override.tools;
|
|
139
|
-
if (override.reasoning !== void 0) {
|
|
140
|
-
result.reasoning = { ...result.reasoning, ...override.reasoning };
|
|
160
|
+
function normalizeBuiltInValidator(value) {
|
|
161
|
+
if (value === void 0 || value === false) {
|
|
162
|
+
return void 0;
|
|
141
163
|
}
|
|
142
|
-
if (
|
|
143
|
-
|
|
164
|
+
if (value === true) {
|
|
165
|
+
return {};
|
|
144
166
|
}
|
|
145
|
-
|
|
146
|
-
|
|
167
|
+
return {
|
|
168
|
+
returnMessage: value.return_message
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function parseRegexLiteral(value) {
|
|
172
|
+
if (!value.startsWith("/")) {
|
|
173
|
+
return void 0;
|
|
147
174
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
175
|
+
for (let index = value.length - 1; index > 0; index -= 1) {
|
|
176
|
+
if (value[index] !== "/") {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
let backslashCount = 0;
|
|
180
|
+
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
|
|
181
|
+
backslashCount += 1;
|
|
182
|
+
}
|
|
183
|
+
if (backslashCount % 2 === 1) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
pattern: value.slice(1, index),
|
|
188
|
+
flags: value.slice(index + 1)
|
|
156
189
|
};
|
|
157
190
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
191
|
+
return void 0;
|
|
192
|
+
}
|
|
193
|
+
function formatInvalidContextRegexMessage(details) {
|
|
194
|
+
return [
|
|
195
|
+
`Invalid context regex for prompt "${details.promptId}"`,
|
|
196
|
+
`variable "${details.variable}"`,
|
|
197
|
+
`field "${details.field}"`,
|
|
198
|
+
`value ${JSON.stringify(details.raw)}: ${details.reason}`
|
|
199
|
+
].join(", ");
|
|
200
|
+
}
|
|
201
|
+
function compileContextRegex(regex, details) {
|
|
202
|
+
if (regex.invalidLiteral) {
|
|
203
|
+
throw new Error(
|
|
204
|
+
`POK013: ${formatInvalidContextRegexMessage({
|
|
205
|
+
...details,
|
|
206
|
+
raw: regex.raw,
|
|
207
|
+
reason: "Malformed regex literal. Use /pattern/flags or { pattern, flags }."
|
|
208
|
+
})}`
|
|
209
|
+
);
|
|
170
210
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
...result.provider_options?.anthropic,
|
|
177
|
-
...override.provider_options.anthropic
|
|
178
|
-
},
|
|
179
|
-
gemini: {
|
|
180
|
-
...result.provider_options?.gemini,
|
|
181
|
-
...override.provider_options.gemini
|
|
182
|
-
},
|
|
183
|
-
openrouter: {
|
|
184
|
-
...result.provider_options?.openrouter,
|
|
185
|
-
...override.provider_options.openrouter
|
|
186
|
-
}
|
|
187
|
-
};
|
|
211
|
+
try {
|
|
212
|
+
return new RegExp(regex.pattern, regex.flags);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
215
|
+
throw new Error(`POK013: ${formatInvalidContextRegexMessage({ ...details, raw: regex.raw, reason })}`);
|
|
188
216
|
}
|
|
189
|
-
return result;
|
|
190
217
|
}
|
|
191
|
-
function
|
|
192
|
-
|
|
193
|
-
|
|
218
|
+
function getRejectSecretsRegex() {
|
|
219
|
+
return {
|
|
220
|
+
pattern: REJECT_SECRETS_PATTERN,
|
|
221
|
+
flags: REJECT_SECRETS_FLAGS,
|
|
222
|
+
raw: JSON.stringify({ pattern: REJECT_SECRETS_PATTERN, flags: REJECT_SECRETS_FLAGS })
|
|
223
|
+
};
|
|
194
224
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
function resolveAssetForProvider(asset, runtime = {}) {
|
|
198
|
-
if (!runtime.environment && !runtime.tier && !runtime.runtime) {
|
|
199
|
-
return asset;
|
|
200
|
-
}
|
|
201
|
-
return applyOverrides(asset, {
|
|
202
|
-
environment: runtime.environment,
|
|
203
|
-
tier: runtime.tier,
|
|
204
|
-
runtime: runtime.runtime
|
|
205
|
-
});
|
|
225
|
+
function isTrimEnabled(mode) {
|
|
226
|
+
return mode === true || mode === "start" || mode === "end" || mode === "both";
|
|
206
227
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
var import_node_fs2 = require("fs");
|
|
211
|
-
var import_node_path3 = require("path");
|
|
212
|
-
|
|
213
|
-
// src/cache.ts
|
|
214
|
-
var import_node_fs = require("fs");
|
|
215
|
-
var PromptCache = class {
|
|
216
|
-
cache = /* @__PURE__ */ new Map();
|
|
217
|
-
maxSize;
|
|
218
|
-
constructor(maxSize = 100) {
|
|
219
|
-
this.maxSize = maxSize;
|
|
228
|
+
function normalizeTrimMode(mode) {
|
|
229
|
+
if (mode === "start") {
|
|
230
|
+
return "start";
|
|
220
231
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
this.cache.delete(filePath);
|
|
228
|
-
return void 0;
|
|
229
|
-
}
|
|
230
|
-
} catch {
|
|
231
|
-
this.cache.delete(filePath);
|
|
232
|
-
return void 0;
|
|
233
|
-
}
|
|
234
|
-
this.cache.delete(filePath);
|
|
235
|
-
this.cache.set(filePath, entry);
|
|
236
|
-
return entry.value;
|
|
232
|
+
return "end";
|
|
233
|
+
}
|
|
234
|
+
function trimToMaxSize(value, maxSize, mode) {
|
|
235
|
+
const measured = measureContextValueSize(value);
|
|
236
|
+
if (measured <= maxSize) {
|
|
237
|
+
return value;
|
|
237
238
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
239
|
+
const characters = Array.from(value);
|
|
240
|
+
const normalizedMode = normalizeTrimMode(mode);
|
|
241
|
+
if (normalizedMode === "start") {
|
|
242
|
+
let collected2 = "";
|
|
243
|
+
let size2 = 0;
|
|
244
|
+
for (let i = characters.length - 1; i >= 0; i -= 1) {
|
|
245
|
+
const next = characters[i];
|
|
246
|
+
const charSize = measureContextValueSize(next);
|
|
247
|
+
if (size2 + charSize > maxSize) {
|
|
248
|
+
break;
|
|
246
249
|
}
|
|
247
|
-
|
|
248
|
-
|
|
250
|
+
collected2 = next + collected2;
|
|
251
|
+
size2 += charSize;
|
|
249
252
|
}
|
|
253
|
+
return collected2;
|
|
250
254
|
}
|
|
251
|
-
|
|
252
|
-
|
|
255
|
+
let collected = "";
|
|
256
|
+
let size = 0;
|
|
257
|
+
for (const char of characters) {
|
|
258
|
+
const charSize = measureContextValueSize(char);
|
|
259
|
+
if (size + charSize > maxSize) {
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
collected += char;
|
|
263
|
+
size += charSize;
|
|
264
|
+
}
|
|
265
|
+
return collected;
|
|
266
|
+
}
|
|
267
|
+
function sanitizeContextVariables(asset, variables = {}, options = {}) {
|
|
268
|
+
const { onContextOverflow } = options;
|
|
269
|
+
const sanitized = { ...variables };
|
|
270
|
+
for (const input of getContextInputs(asset)) {
|
|
271
|
+
const value = sanitized[input.name];
|
|
272
|
+
if (value === void 0) {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
let candidate = value;
|
|
276
|
+
if (input.max_size !== void 0) {
|
|
277
|
+
const actualSize = measureContextValueSize(candidate);
|
|
278
|
+
if (actualSize > input.max_size && onContextOverflow) {
|
|
279
|
+
candidate = onContextOverflow({
|
|
280
|
+
promptId: asset.id,
|
|
281
|
+
variable: input.name,
|
|
282
|
+
value: candidate,
|
|
283
|
+
maxSize: input.max_size,
|
|
284
|
+
actualSize
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (isTrimEnabled(input.trim) && input.max_size !== void 0) {
|
|
289
|
+
candidate = trimToMaxSize(candidate, input.max_size, input.trim);
|
|
290
|
+
}
|
|
291
|
+
sanitized[input.name] = candidate;
|
|
292
|
+
if (input.allow_regex) {
|
|
293
|
+
const candidate2 = sanitized[input.name];
|
|
294
|
+
const matcher = compileContextRegex(input.allow_regex, {
|
|
295
|
+
promptId: asset.id,
|
|
296
|
+
variable: input.name,
|
|
297
|
+
field: "allow_regex"
|
|
298
|
+
});
|
|
299
|
+
if (!matcher.test(candidate2)) {
|
|
300
|
+
if (input.allow_regex.returnMessage) {
|
|
301
|
+
return {
|
|
302
|
+
variables: sanitized,
|
|
303
|
+
shortCircuit: {
|
|
304
|
+
returnMessage: input.allow_regex.returnMessage,
|
|
305
|
+
code: "POK031",
|
|
306
|
+
variable: input.name,
|
|
307
|
+
field: "allow_regex"
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
throw new Error(
|
|
312
|
+
`POK031: Context variable "${input.name}" failed allow_regex validation for prompt "${asset.id}".`
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (input.deny_regex) {
|
|
317
|
+
const candidate2 = sanitized[input.name];
|
|
318
|
+
const matcher = compileContextRegex(input.deny_regex, {
|
|
319
|
+
promptId: asset.id,
|
|
320
|
+
variable: input.name,
|
|
321
|
+
field: "deny_regex"
|
|
322
|
+
});
|
|
323
|
+
if (matcher.test(candidate2)) {
|
|
324
|
+
if (input.deny_regex.returnMessage) {
|
|
325
|
+
return {
|
|
326
|
+
variables: sanitized,
|
|
327
|
+
shortCircuit: {
|
|
328
|
+
returnMessage: input.deny_regex.returnMessage,
|
|
329
|
+
code: "POK032",
|
|
330
|
+
variable: input.name,
|
|
331
|
+
field: "deny_regex"
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
throw new Error(
|
|
336
|
+
`POK032: Context variable "${input.name}" matched deny_regex for prompt "${asset.id}".`
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (input.non_empty && candidate.trim().length === 0) {
|
|
341
|
+
if (input.non_empty.returnMessage) {
|
|
342
|
+
return {
|
|
343
|
+
variables: sanitized,
|
|
344
|
+
shortCircuit: {
|
|
345
|
+
returnMessage: input.non_empty.returnMessage,
|
|
346
|
+
code: "POK033",
|
|
347
|
+
variable: input.name,
|
|
348
|
+
field: "non_empty"
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
throw new Error(
|
|
353
|
+
`POK033: Context variable "${input.name}" failed non_empty validation for prompt "${asset.id}".`
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
if (input.reject_secrets) {
|
|
357
|
+
const matcher = compileContextRegex(getRejectSecretsRegex(), {
|
|
358
|
+
promptId: asset.id,
|
|
359
|
+
variable: input.name,
|
|
360
|
+
field: "reject_secrets"
|
|
361
|
+
});
|
|
362
|
+
if (matcher.test(candidate)) {
|
|
363
|
+
if (input.reject_secrets.returnMessage) {
|
|
364
|
+
return {
|
|
365
|
+
variables: sanitized,
|
|
366
|
+
shortCircuit: {
|
|
367
|
+
returnMessage: input.reject_secrets.returnMessage,
|
|
368
|
+
code: "POK034",
|
|
369
|
+
variable: input.name,
|
|
370
|
+
field: "reject_secrets"
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
throw new Error(
|
|
375
|
+
`POK034: Context variable "${input.name}" matched reject_secrets validation for prompt "${asset.id}".`
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return { variables: sanitized };
|
|
381
|
+
}
|
|
382
|
+
function measureContextValueSize(value) {
|
|
383
|
+
return textEncoder.encode(value).length;
|
|
384
|
+
}
|
|
385
|
+
function collectContextSizeWarnings(asset, variables = {}) {
|
|
386
|
+
const warnings = [];
|
|
387
|
+
for (const input of getContextInputs(asset)) {
|
|
388
|
+
if (!areContextInputWarningsEnabled(input)) {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
if (input.max_size === void 0) {
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
const value = variables[input.name];
|
|
395
|
+
if (value === void 0) {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
const actualSize = measureContextValueSize(value);
|
|
399
|
+
if (actualSize > input.max_size) {
|
|
400
|
+
warnings.push({
|
|
401
|
+
variable: input.name,
|
|
402
|
+
maxSize: input.max_size,
|
|
403
|
+
actualSize
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return warnings;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// src/renderer/renderer.ts
|
|
411
|
+
function renderSections(asset, options = {}) {
|
|
412
|
+
const { variables = {}, strict = false } = options;
|
|
413
|
+
const optionalVariables = getContextInputs(asset).filter((input) => input.optional === true).map((input) => input.name);
|
|
414
|
+
const result = {};
|
|
415
|
+
if (asset.sections.system_instructions) {
|
|
416
|
+
result.system_instructions = interpolate(
|
|
417
|
+
asset.sections.system_instructions,
|
|
418
|
+
variables,
|
|
419
|
+
{ strict, optionalVariables }
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
if (asset.sections.prompt_template) {
|
|
423
|
+
result.prompt_template = interpolate(
|
|
424
|
+
asset.sections.prompt_template,
|
|
425
|
+
variables,
|
|
426
|
+
{ strict, optionalVariables }
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
return result;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// src/overrides/apply-overrides.ts
|
|
433
|
+
function applyOverrides(asset, options = {}) {
|
|
434
|
+
let result = { ...asset };
|
|
435
|
+
if (options.environment && result.environments?.[options.environment]) {
|
|
436
|
+
result = mergeOverride(result, result.environments[options.environment]);
|
|
437
|
+
}
|
|
438
|
+
if (options.tier && result.tiers?.[options.tier]) {
|
|
439
|
+
result = mergeOverride(result, result.tiers[options.tier]);
|
|
440
|
+
}
|
|
441
|
+
if (options.runtime) {
|
|
442
|
+
result = mergeOverride(result, options.runtime);
|
|
443
|
+
}
|
|
444
|
+
return result;
|
|
445
|
+
}
|
|
446
|
+
function mergeOverride(base, override) {
|
|
447
|
+
const result = { ...base };
|
|
448
|
+
if (override.model !== void 0) result.model = override.model;
|
|
449
|
+
if (override.fallback_models !== void 0) result.fallback_models = override.fallback_models;
|
|
450
|
+
if (override.tools !== void 0) result.tools = override.tools;
|
|
451
|
+
if (override.reasoning !== void 0) {
|
|
452
|
+
result.reasoning = { ...result.reasoning, ...override.reasoning };
|
|
453
|
+
}
|
|
454
|
+
if (override.sampling !== void 0) {
|
|
455
|
+
result.sampling = { ...result.sampling, ...override.sampling };
|
|
456
|
+
}
|
|
457
|
+
if (override.response !== void 0) {
|
|
458
|
+
result.response = { ...result.response, ...override.response };
|
|
459
|
+
}
|
|
460
|
+
if (override.cache !== void 0) {
|
|
461
|
+
result.cache = {
|
|
462
|
+
...result.cache,
|
|
463
|
+
...override.cache,
|
|
464
|
+
openai: mergeRecordBlock(result.cache?.openai, override.cache.openai),
|
|
465
|
+
anthropic: mergeRecordBlock(result.cache?.anthropic, override.cache.anthropic),
|
|
466
|
+
gemini: mergeRecordBlock(result.cache?.gemini, override.cache.gemini),
|
|
467
|
+
google: mergeRecordBlock(result.cache?.google, override.cache.google)
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
if (override.raw !== void 0) {
|
|
471
|
+
result.raw = {
|
|
472
|
+
...result.raw,
|
|
473
|
+
...override.raw,
|
|
474
|
+
openai: mergeRecordBlock(result.raw?.openai, override.raw.openai),
|
|
475
|
+
"openai-responses": mergeRecordBlock(result.raw?.["openai-responses"], override.raw["openai-responses"]),
|
|
476
|
+
openai_responses: mergeRecordBlock(result.raw?.openai_responses, override.raw.openai_responses),
|
|
477
|
+
anthropic: mergeRecordBlock(result.raw?.anthropic, override.raw.anthropic),
|
|
478
|
+
gemini: mergeRecordBlock(result.raw?.gemini, override.raw.gemini),
|
|
479
|
+
google: mergeRecordBlock(result.raw?.google, override.raw.google),
|
|
480
|
+
openrouter: mergeRecordBlock(result.raw?.openrouter, override.raw.openrouter),
|
|
481
|
+
llmasaservice: mergeRecordBlock(result.raw?.llmasaservice, override.raw.llmasaservice)
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
if (override.provider_options !== void 0) {
|
|
485
|
+
result.provider_options = {
|
|
486
|
+
...result.provider_options,
|
|
487
|
+
...override.provider_options,
|
|
488
|
+
anthropic: {
|
|
489
|
+
...result.provider_options?.anthropic,
|
|
490
|
+
...override.provider_options.anthropic
|
|
491
|
+
},
|
|
492
|
+
gemini: {
|
|
493
|
+
...result.provider_options?.gemini,
|
|
494
|
+
...override.provider_options.gemini
|
|
495
|
+
},
|
|
496
|
+
openrouter: {
|
|
497
|
+
...result.provider_options?.openrouter,
|
|
498
|
+
...override.provider_options.openrouter
|
|
499
|
+
},
|
|
500
|
+
llmasaservice: {
|
|
501
|
+
...result.provider_options?.llmasaservice,
|
|
502
|
+
...override.provider_options.llmasaservice
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
return result;
|
|
507
|
+
}
|
|
508
|
+
function mergeRecordBlock(base, override) {
|
|
509
|
+
if (override === void 0) return base;
|
|
510
|
+
return { ...base, ...override };
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// src/providers/resolve-asset.ts
|
|
514
|
+
function resolveAssetForProvider(asset, runtime = {}) {
|
|
515
|
+
if (!runtime.environment && !runtime.tier && !runtime.runtime) {
|
|
516
|
+
return asset;
|
|
517
|
+
}
|
|
518
|
+
return applyOverrides(asset, {
|
|
519
|
+
environment: runtime.environment,
|
|
520
|
+
tier: runtime.tier,
|
|
521
|
+
runtime: runtime.runtime
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// src/prompt-resolution.ts
|
|
526
|
+
var import_promises4 = require("fs/promises");
|
|
527
|
+
var import_node_fs2 = require("fs");
|
|
528
|
+
var import_node_path4 = require("path");
|
|
529
|
+
|
|
530
|
+
// src/cache.ts
|
|
531
|
+
var import_node_fs = require("fs");
|
|
532
|
+
var PromptCache = class {
|
|
533
|
+
cache = /* @__PURE__ */ new Map();
|
|
534
|
+
maxSize;
|
|
535
|
+
constructor(maxSize = 100) {
|
|
536
|
+
this.maxSize = maxSize;
|
|
537
|
+
}
|
|
538
|
+
get(filePath) {
|
|
539
|
+
const entry = this.cache.get(filePath);
|
|
540
|
+
if (!entry) return void 0;
|
|
541
|
+
try {
|
|
542
|
+
const stat = (0, import_node_fs.statSync)(filePath);
|
|
543
|
+
if (stat.mtimeMs !== entry.mtime) {
|
|
544
|
+
this.cache.delete(filePath);
|
|
545
|
+
return void 0;
|
|
546
|
+
}
|
|
547
|
+
} catch {
|
|
548
|
+
this.cache.delete(filePath);
|
|
549
|
+
return void 0;
|
|
550
|
+
}
|
|
551
|
+
this.cache.delete(filePath);
|
|
552
|
+
this.cache.set(filePath, entry);
|
|
553
|
+
return entry.value;
|
|
554
|
+
}
|
|
555
|
+
set(filePath, value) {
|
|
556
|
+
try {
|
|
557
|
+
const stat = (0, import_node_fs.statSync)(filePath);
|
|
558
|
+
if (this.cache.has(filePath)) {
|
|
559
|
+
this.cache.delete(filePath);
|
|
560
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
561
|
+
const oldest = this.cache.keys().next().value;
|
|
562
|
+
if (oldest) this.cache.delete(oldest);
|
|
563
|
+
}
|
|
564
|
+
this.cache.set(filePath, { value, mtime: stat.mtimeMs });
|
|
565
|
+
} catch {
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
clear() {
|
|
569
|
+
this.cache.clear();
|
|
253
570
|
}
|
|
254
571
|
get size() {
|
|
255
572
|
return this.cache.size;
|
|
@@ -257,8 +574,8 @@ var PromptCache = class {
|
|
|
257
574
|
};
|
|
258
575
|
|
|
259
576
|
// src/composition/resolve-includes.ts
|
|
260
|
-
var
|
|
261
|
-
var
|
|
577
|
+
var import_promises3 = require("fs/promises");
|
|
578
|
+
var import_node_path3 = require("path");
|
|
262
579
|
|
|
263
580
|
// src/parser/parser.ts
|
|
264
581
|
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
@@ -294,10 +611,26 @@ var ResponseSchema = import_zod.z.object({
|
|
|
294
611
|
format: import_zod.z.enum(["text", "json", "markdown"]).optional(),
|
|
295
612
|
stream: import_zod.z.boolean().optional(),
|
|
296
613
|
schema: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
614
|
+
schema_ref: import_zod.z.string().min(1).optional(),
|
|
615
|
+
schema_source: import_zod.z.object({
|
|
616
|
+
mode: import_zod.z.enum(["inline", "schema_ref_json", "schema_ref_zod_module"]).optional(),
|
|
617
|
+
ref: import_zod.z.string().optional(),
|
|
618
|
+
resolved_path: import_zod.z.string().optional(),
|
|
619
|
+
hash: import_zod.z.string().optional()
|
|
620
|
+
}).optional(),
|
|
297
621
|
schema_name: import_zod.z.string().optional(),
|
|
298
622
|
schema_description: import_zod.z.string().optional(),
|
|
299
623
|
schema_strict: import_zod.z.boolean().optional()
|
|
300
624
|
});
|
|
625
|
+
var ResponseSchemaWithValidation = ResponseSchema.superRefine((value, ctx) => {
|
|
626
|
+
if (value.schema !== void 0 && value.schema_ref !== void 0) {
|
|
627
|
+
ctx.addIssue({
|
|
628
|
+
code: import_zod.z.ZodIssueCode.custom,
|
|
629
|
+
message: "response.schema and response.schema_ref are mutually exclusive",
|
|
630
|
+
path: ["schema_ref"]
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
});
|
|
301
634
|
var AnthropicProviderOptionsSchema = import_zod.z.object({
|
|
302
635
|
top_k: import_zod.z.number().int().min(0).optional(),
|
|
303
636
|
tool_choice: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
@@ -318,10 +651,26 @@ var OpenRouterProviderOptionsSchema = import_zod.z.object({
|
|
|
318
651
|
plugins: import_zod.z.array(import_zod.z.record(import_zod.z.unknown())).optional(),
|
|
319
652
|
models: import_zod.z.array(import_zod.z.string()).optional()
|
|
320
653
|
});
|
|
654
|
+
var LLMAsAServiceCustomerSchema = import_zod.z.object({
|
|
655
|
+
customer_id: import_zod.z.string(),
|
|
656
|
+
customer_name: import_zod.z.string().optional(),
|
|
657
|
+
customer_user_id: import_zod.z.string().optional(),
|
|
658
|
+
customer_user_name: import_zod.z.string().optional(),
|
|
659
|
+
customer_user_email: import_zod.z.string().optional()
|
|
660
|
+
});
|
|
661
|
+
var LLMAsAServiceProviderOptionsSchema = import_zod.z.object({
|
|
662
|
+
base_url: import_zod.z.string().url().optional(),
|
|
663
|
+
project_id: import_zod.z.string().optional(),
|
|
664
|
+
customer: LLMAsAServiceCustomerSchema.optional(),
|
|
665
|
+
conversationId: import_zod.z.string().optional(),
|
|
666
|
+
conversationTitle: import_zod.z.string().optional(),
|
|
667
|
+
projectId: import_zod.z.string().optional()
|
|
668
|
+
});
|
|
321
669
|
var ProviderOptionsSchema = import_zod.z.object({
|
|
322
670
|
anthropic: AnthropicProviderOptionsSchema.optional(),
|
|
323
671
|
gemini: GeminiProviderOptionsSchema.optional(),
|
|
324
|
-
openrouter: OpenRouterProviderOptionsSchema.optional()
|
|
672
|
+
openrouter: OpenRouterProviderOptionsSchema.optional(),
|
|
673
|
+
llmasaservice: LLMAsAServiceProviderOptionsSchema.optional()
|
|
325
674
|
});
|
|
326
675
|
var RawProviderBodySchema = import_zod.z.object({
|
|
327
676
|
openai: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
@@ -330,7 +679,8 @@ var RawProviderBodySchema = import_zod.z.object({
|
|
|
330
679
|
anthropic: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
331
680
|
gemini: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
332
681
|
google: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
333
|
-
openrouter: import_zod.z.record(import_zod.z.unknown()).optional()
|
|
682
|
+
openrouter: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
683
|
+
llmasaservice: import_zod.z.record(import_zod.z.unknown()).optional()
|
|
334
684
|
});
|
|
335
685
|
var OpenAICacheSchema = import_zod.z.object({
|
|
336
686
|
prompt_cache_key: import_zod.z.string().min(1).optional(),
|
|
@@ -372,6 +722,8 @@ var ContextBuiltInValidatorSchema = import_zod.z.union([
|
|
|
372
722
|
]);
|
|
373
723
|
var ContextInputDefinitionObjectSchema = import_zod.z.object({
|
|
374
724
|
name: import_zod.z.string(),
|
|
725
|
+
optional: import_zod.z.boolean().optional(),
|
|
726
|
+
warnings: import_zod.z.boolean().optional(),
|
|
375
727
|
max_size: import_zod.z.number().int().positive().optional(),
|
|
376
728
|
trim: import_zod.z.union([import_zod.z.boolean(), import_zod.z.enum(["start", "end", "both"])]).optional(),
|
|
377
729
|
allow_regex: ContextRegexSchema.optional(),
|
|
@@ -401,7 +753,7 @@ var PromptAssetOverridesSchema = import_zod.z.object({
|
|
|
401
753
|
fallback_models: import_zod.z.array(import_zod.z.string()).optional(),
|
|
402
754
|
reasoning: ReasoningSchema.optional(),
|
|
403
755
|
sampling: SamplingSchema.optional(),
|
|
404
|
-
response:
|
|
756
|
+
response: ResponseSchemaWithValidation.optional(),
|
|
405
757
|
cache: CacheSchema.optional(),
|
|
406
758
|
raw: RawProviderBodySchema.optional(),
|
|
407
759
|
tools: import_zod.z.array(ToolRefSchema).optional(),
|
|
@@ -417,9 +769,21 @@ var SectionsSchema = import_zod.z.object({
|
|
|
417
769
|
notes: import_zod.z.string().optional()
|
|
418
770
|
});
|
|
419
771
|
var PromptDefaultsSchema = import_zod.z.object({
|
|
420
|
-
provider: import_zod.z.enum(["openai", "openai-responses", "anthropic", "google", "gemini", "openrouter", "any"]).optional(),
|
|
772
|
+
provider: import_zod.z.enum(["openai", "openai-responses", "anthropic", "google", "gemini", "openrouter", "llmasaservice", "any"]).optional(),
|
|
421
773
|
model: import_zod.z.string().optional(),
|
|
774
|
+
fallback_models: import_zod.z.array(import_zod.z.string()).optional(),
|
|
775
|
+
reasoning: ReasoningSchema.optional(),
|
|
776
|
+
sampling: SamplingSchema.optional(),
|
|
777
|
+
response: ResponseSchema.optional(),
|
|
422
778
|
cache: CacheSchema.optional(),
|
|
779
|
+
raw: RawProviderBodySchema.optional(),
|
|
780
|
+
tools: import_zod.z.array(ToolRefSchema).optional(),
|
|
781
|
+
provider_options: ProviderOptionsSchema.optional(),
|
|
782
|
+
mcp: MCPSchema.optional(),
|
|
783
|
+
context: ContextSchema.optional(),
|
|
784
|
+
includes: import_zod.z.array(import_zod.z.string()).optional(),
|
|
785
|
+
environments: import_zod.z.record(PromptAssetOverridesSchema).optional(),
|
|
786
|
+
tiers: import_zod.z.record(PromptAssetOverridesSchema).optional(),
|
|
423
787
|
metadata: MetadataSchema.optional(),
|
|
424
788
|
sections: import_zod.z.object({
|
|
425
789
|
system_instructions: import_zod.z.string().optional()
|
|
@@ -429,12 +793,12 @@ var PromptAssetSchema = import_zod.z.object({
|
|
|
429
793
|
id: import_zod.z.string(),
|
|
430
794
|
schema_version: import_zod.z.number().int().positive().default(1),
|
|
431
795
|
description: import_zod.z.string().optional(),
|
|
432
|
-
provider: import_zod.z.enum(["openai", "openai-responses", "anthropic", "google", "gemini", "openrouter", "any"]).optional(),
|
|
796
|
+
provider: import_zod.z.enum(["openai", "openai-responses", "anthropic", "google", "gemini", "openrouter", "llmasaservice", "any"]).optional(),
|
|
433
797
|
model: import_zod.z.string().optional(),
|
|
434
798
|
fallback_models: import_zod.z.array(import_zod.z.string()).optional(),
|
|
435
799
|
reasoning: ReasoningSchema.optional(),
|
|
436
800
|
sampling: SamplingSchema.optional(),
|
|
437
|
-
response:
|
|
801
|
+
response: ResponseSchemaWithValidation.optional(),
|
|
438
802
|
cache: CacheSchema.optional(),
|
|
439
803
|
raw: RawProviderBodySchema.optional(),
|
|
440
804
|
tools: import_zod.z.array(ToolRefSchema).optional(),
|
|
@@ -626,16 +990,122 @@ function parsePrompt(content, filePath) {
|
|
|
626
990
|
}
|
|
627
991
|
|
|
628
992
|
// src/parser/loader.ts
|
|
993
|
+
var import_promises2 = require("fs/promises");
|
|
994
|
+
var import_node_path2 = require("path");
|
|
995
|
+
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
996
|
+
|
|
997
|
+
// src/parser/response-schema-ref.ts
|
|
629
998
|
var import_promises = require("fs/promises");
|
|
999
|
+
var import_node_crypto = require("crypto");
|
|
630
1000
|
var import_node_path = require("path");
|
|
631
|
-
var
|
|
1001
|
+
var import_node_url = require("url");
|
|
1002
|
+
var import_zod2 = require("zod");
|
|
1003
|
+
var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
1004
|
+
var SUPPORTED_SCHEMA_REF_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".js", ".mjs", ".cjs"]);
|
|
1005
|
+
async function resolveJsonSchemaRef(schemaRef, promptFilePath) {
|
|
1006
|
+
const resolvedPath = (0, import_node_path.resolve)((0, import_node_path.dirname)(promptFilePath), schemaRef);
|
|
1007
|
+
let raw;
|
|
1008
|
+
try {
|
|
1009
|
+
raw = await (0, import_promises.readFile)(resolvedPath, "utf-8");
|
|
1010
|
+
} catch (error) {
|
|
1011
|
+
const code = error.code;
|
|
1012
|
+
if (code === "ENOENT") {
|
|
1013
|
+
throw new Error(`POK050: response.schema_ref "${schemaRef}" not found (resolved from ${promptFilePath})`);
|
|
1014
|
+
}
|
|
1015
|
+
throw error;
|
|
1016
|
+
}
|
|
1017
|
+
let parsed;
|
|
1018
|
+
try {
|
|
1019
|
+
parsed = JSON.parse(raw);
|
|
1020
|
+
} catch {
|
|
1021
|
+
throw new Error(`POK050: response.schema_ref "${schemaRef}" is not valid JSON`);
|
|
1022
|
+
}
|
|
1023
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1024
|
+
throw new Error(`POK050: response.schema_ref "${schemaRef}" must resolve to a JSON object schema`);
|
|
1025
|
+
}
|
|
1026
|
+
return {
|
|
1027
|
+
schema: parsed,
|
|
1028
|
+
resolvedPath,
|
|
1029
|
+
hash: (0, import_node_crypto.createHash)("sha256").update(raw).digest("hex")
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
async function resolveZodSchemaRef(schemaRef, promptFilePath) {
|
|
1033
|
+
const resolvedPath = (0, import_node_path.resolve)((0, import_node_path.dirname)(promptFilePath), schemaRef);
|
|
1034
|
+
let moduleSource;
|
|
1035
|
+
try {
|
|
1036
|
+
moduleSource = await (0, import_promises.readFile)(resolvedPath, "utf-8");
|
|
1037
|
+
} catch (error) {
|
|
1038
|
+
const code = error.code;
|
|
1039
|
+
if (code === "ENOENT") {
|
|
1040
|
+
throw new Error(`POK051: response.schema_ref "${schemaRef}" not found (resolved from ${promptFilePath})`);
|
|
1041
|
+
}
|
|
1042
|
+
throw error;
|
|
1043
|
+
}
|
|
1044
|
+
let imported;
|
|
1045
|
+
try {
|
|
1046
|
+
imported = await import((0, import_node_url.pathToFileURL)(resolvedPath).href);
|
|
1047
|
+
} catch (error) {
|
|
1048
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1049
|
+
throw new Error(`POK051: response.schema_ref "${schemaRef}" could not be imported as a module (${message})`);
|
|
1050
|
+
}
|
|
1051
|
+
const mod = imported;
|
|
1052
|
+
const candidate = mod.default ?? mod.schema;
|
|
1053
|
+
if (!(candidate instanceof import_zod2.z.ZodType)) {
|
|
1054
|
+
throw new Error('POK051: zod schema modules must export a Zod schema as default export or named export "schema"');
|
|
1055
|
+
}
|
|
1056
|
+
const jsonSchema = (0, import_zod_to_json_schema.zodToJsonSchema)(candidate, {
|
|
1057
|
+
target: "jsonSchema7",
|
|
1058
|
+
$refStrategy: "none"
|
|
1059
|
+
});
|
|
1060
|
+
if (!jsonSchema || typeof jsonSchema !== "object" || Array.isArray(jsonSchema)) {
|
|
1061
|
+
throw new Error(`POK051: response.schema_ref "${schemaRef}" did not produce a valid JSON schema object`);
|
|
1062
|
+
}
|
|
1063
|
+
return {
|
|
1064
|
+
schema: jsonSchema,
|
|
1065
|
+
resolvedPath,
|
|
1066
|
+
hash: (0, import_node_crypto.createHash)("sha256").update(moduleSource).digest("hex")
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
async function resolveResponseSchemaRef(asset, promptFilePath) {
|
|
1070
|
+
const schemaRef = asset.response?.schema_ref;
|
|
1071
|
+
if (!schemaRef) return asset;
|
|
1072
|
+
const ext = (0, import_node_path.extname)(schemaRef).toLowerCase();
|
|
1073
|
+
if (!SUPPORTED_SCHEMA_REF_EXTENSIONS.has(ext)) {
|
|
1074
|
+
throw new Error(`POK051: response.schema_ref "${schemaRef}" has unsupported extension "${ext}". Use .json, .js, .mjs, or .cjs`);
|
|
1075
|
+
}
|
|
1076
|
+
const resolved = ext === ".json" ? await resolveJsonSchemaRef(schemaRef, promptFilePath) : await resolveZodSchemaRef(schemaRef, promptFilePath);
|
|
1077
|
+
return {
|
|
1078
|
+
...asset,
|
|
1079
|
+
response: {
|
|
1080
|
+
...asset.response,
|
|
1081
|
+
schema: resolved.schema,
|
|
1082
|
+
schema_ref: void 0,
|
|
1083
|
+
schema_source: {
|
|
1084
|
+
mode: ext === ".json" ? "schema_ref_json" : "schema_ref_zod_module",
|
|
1085
|
+
ref: schemaRef,
|
|
1086
|
+
resolved_path: resolved.resolvedPath,
|
|
1087
|
+
hash: resolved.hash
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
// src/parser/loader.ts
|
|
632
1094
|
var DEFAULTS_FILE_NAME = "defaults.md";
|
|
633
1095
|
async function loadPromptFile(filePath, options = {}) {
|
|
634
|
-
const content = await (0,
|
|
1096
|
+
const content = await (0, import_promises2.readFile)(filePath, "utf-8");
|
|
635
1097
|
const parsed = parsePrompt(content, filePath);
|
|
636
|
-
const root = options.defaultsRoot ?? (0,
|
|
1098
|
+
const root = options.defaultsRoot ?? (0, import_node_path2.dirname)(filePath);
|
|
637
1099
|
const defaults = await loadDefaultsForPath(filePath, root);
|
|
638
|
-
const
|
|
1100
|
+
const withDefaults = applyDefaults(parsed.asset, defaults);
|
|
1101
|
+
const resolved = await resolveResponseSchemaRef(withDefaults, filePath);
|
|
1102
|
+
const asset = resolved.response?.schema !== void 0 && !resolved.response?.schema_source ? {
|
|
1103
|
+
...resolved,
|
|
1104
|
+
response: {
|
|
1105
|
+
...resolved.response,
|
|
1106
|
+
schema_source: { mode: "inline" }
|
|
1107
|
+
}
|
|
1108
|
+
} : resolved;
|
|
639
1109
|
return {
|
|
640
1110
|
...parsed,
|
|
641
1111
|
asset
|
|
@@ -645,10 +1115,10 @@ async function loadDefaultsForPath(filePath, defaultsRoot) {
|
|
|
645
1115
|
const directories = getDirectoriesToCheck(filePath, defaultsRoot);
|
|
646
1116
|
let merged = {};
|
|
647
1117
|
for (const dir of directories) {
|
|
648
|
-
const defaultsPath = (0,
|
|
1118
|
+
const defaultsPath = (0, import_node_path2.join)(dir, DEFAULTS_FILE_NAME);
|
|
649
1119
|
try {
|
|
650
|
-
const defaultsContent = await (0,
|
|
651
|
-
const defaults = parseDefaults(defaultsContent);
|
|
1120
|
+
const defaultsContent = await (0, import_promises2.readFile)(defaultsPath, "utf-8");
|
|
1121
|
+
const defaults = normalizeDefaultIncludes(parseDefaults(defaultsContent), defaultsPath, filePath);
|
|
652
1122
|
merged = mergeDefaults(merged, defaults);
|
|
653
1123
|
} catch (error) {
|
|
654
1124
|
if (error.code !== "ENOENT") {
|
|
@@ -660,14 +1130,14 @@ async function loadDefaultsForPath(filePath, defaultsRoot) {
|
|
|
660
1130
|
}
|
|
661
1131
|
function getDirectoriesToCheck(filePath, defaultsRoot) {
|
|
662
1132
|
const dirs = [];
|
|
663
|
-
let current = (0,
|
|
664
|
-
const boundary = defaultsRoot ? (0,
|
|
1133
|
+
let current = (0, import_node_path2.resolve)((0, import_node_path2.dirname)(filePath));
|
|
1134
|
+
const boundary = defaultsRoot ? (0, import_node_path2.resolve)(defaultsRoot) : void 0;
|
|
665
1135
|
while (true) {
|
|
666
1136
|
dirs.unshift(current);
|
|
667
|
-
if (boundary && current === boundary || current === (0,
|
|
1137
|
+
if (boundary && current === boundary || current === (0, import_node_path2.dirname)(current)) {
|
|
668
1138
|
break;
|
|
669
1139
|
}
|
|
670
|
-
current = (0,
|
|
1140
|
+
current = (0, import_node_path2.dirname)(current);
|
|
671
1141
|
}
|
|
672
1142
|
return dirs;
|
|
673
1143
|
}
|
|
@@ -677,501 +1147,381 @@ function parseDefaults(content) {
|
|
|
677
1147
|
return PromptDefaultsSchema.parse({
|
|
678
1148
|
...frontMatter,
|
|
679
1149
|
sections: {
|
|
680
|
-
system_instructions: sections.system_instructions
|
|
681
|
-
}
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
function mergeDefaults(base, local) {
|
|
685
|
-
return {
|
|
686
|
-
provider: local.provider ?? base.provider,
|
|
687
|
-
model: local.model ?? base.model,
|
|
688
|
-
cache: mergeCache(base.cache, local.cache),
|
|
689
|
-
metadata: {
|
|
690
|
-
...base.metadata ?? {},
|
|
691
|
-
...local.metadata ?? {}
|
|
692
|
-
},
|
|
693
|
-
sections: {
|
|
694
|
-
...base.sections ?? {},
|
|
695
|
-
...local.sections ?? {}
|
|
696
|
-
}
|
|
697
|
-
};
|
|
698
|
-
}
|
|
699
|
-
function applyDefaults(asset, defaults) {
|
|
700
|
-
const cache = mergeCache(defaults.cache, asset.cache);
|
|
701
|
-
const hasDefaultMetadata = defaults.metadata && Object.keys(defaults.metadata).length > 0;
|
|
702
|
-
const hasDefaultSystem = !!defaults.sections?.system_instructions;
|
|
703
|
-
const hasDefaultScalars = defaults.provider !== void 0 || defaults.model !== void 0;
|
|
704
|
-
const hasDefaultCache = cache !== void 0;
|
|
705
|
-
if (!hasDefaultMetadata && !hasDefaultSystem && !hasDefaultScalars && !hasDefaultCache) {
|
|
706
|
-
return asset;
|
|
707
|
-
}
|
|
708
|
-
const mergedMetadata = {
|
|
709
|
-
...defaults.metadata ?? {},
|
|
710
|
-
...asset.metadata ?? {}
|
|
711
|
-
};
|
|
712
|
-
const metadata = Object.keys(mergedMetadata).length > 0 ? mergedMetadata : void 0;
|
|
713
|
-
const systemInstructions = asset.sections?.system_instructions ?? defaults.sections?.system_instructions;
|
|
714
|
-
const sections = asset.sections ? { ...asset.sections, system_instructions: systemInstructions } : systemInstructions ? { system_instructions: systemInstructions } : void 0;
|
|
715
|
-
return {
|
|
716
|
-
...asset,
|
|
717
|
-
provider: asset.provider ?? defaults.provider,
|
|
718
|
-
model: asset.model ?? defaults.model,
|
|
719
|
-
cache,
|
|
720
|
-
metadata,
|
|
721
|
-
sections
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
function mergeCache(base, local) {
|
|
725
|
-
const merged = {
|
|
726
|
-
...base ?? {},
|
|
727
|
-
...local ?? {},
|
|
728
|
-
openai: {
|
|
729
|
-
...base?.openai ?? {},
|
|
730
|
-
...local?.openai ?? {}
|
|
731
|
-
},
|
|
732
|
-
anthropic: {
|
|
733
|
-
...base?.anthropic ?? {},
|
|
734
|
-
...local?.anthropic ?? {}
|
|
735
|
-
},
|
|
736
|
-
gemini: {
|
|
737
|
-
...base?.gemini ?? {},
|
|
738
|
-
...local?.gemini ?? {}
|
|
739
|
-
},
|
|
740
|
-
google: {
|
|
741
|
-
...base?.google ?? {},
|
|
742
|
-
...local?.google ?? {}
|
|
743
|
-
}
|
|
744
|
-
};
|
|
745
|
-
if (merged.openai && Object.keys(merged.openai).length === 0) delete merged.openai;
|
|
746
|
-
if (merged.anthropic && Object.keys(merged.anthropic).length === 0) delete merged.anthropic;
|
|
747
|
-
if (merged.gemini && Object.keys(merged.gemini).length === 0) delete merged.gemini;
|
|
748
|
-
if (merged.google && Object.keys(merged.google).length === 0) delete merged.google;
|
|
749
|
-
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
// src/composition/resolve-includes.ts
|
|
753
|
-
async function resolveIncludes(asset, basePath, visited = /* @__PURE__ */ new Set()) {
|
|
754
|
-
if (!asset.includes || asset.includes.length === 0) {
|
|
755
|
-
return asset;
|
|
756
|
-
}
|
|
757
|
-
const baseDir = (0, import_node_path2.dirname)(basePath);
|
|
758
|
-
const resolvedPath = (0, import_node_path2.resolve)(basePath);
|
|
759
|
-
if (visited.has(resolvedPath)) {
|
|
760
|
-
throw new Error(`Circular include detected: ${resolvedPath}`);
|
|
761
|
-
}
|
|
762
|
-
visited.add(resolvedPath);
|
|
763
|
-
let mergedSystemInstructions = "";
|
|
764
|
-
for (const includePath of asset.includes) {
|
|
765
|
-
const fullPath = (0, import_node_path2.resolve)(baseDir, includePath);
|
|
766
|
-
if (visited.has(fullPath)) {
|
|
767
|
-
throw new Error(`Circular include detected: ${fullPath} (included from ${basePath})`);
|
|
768
|
-
}
|
|
769
|
-
const content = await (0, import_promises2.readFile)(fullPath, "utf-8");
|
|
770
|
-
const { asset: includedAsset } = parsePrompt(content, fullPath);
|
|
771
|
-
const resolved = await resolveIncludes(includedAsset, fullPath, new Set(visited));
|
|
772
|
-
if (resolved.sections?.system_instructions) {
|
|
773
|
-
mergedSystemInstructions += resolved.sections.system_instructions + "\n\n";
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
const localSystem = asset.sections?.system_instructions ?? "";
|
|
777
|
-
const combinedSystem = (mergedSystemInstructions + localSystem).trim() || void 0;
|
|
778
|
-
return {
|
|
779
|
-
...asset,
|
|
780
|
-
sections: {
|
|
781
|
-
...asset.sections,
|
|
782
|
-
system_instructions: combinedSystem
|
|
783
|
-
},
|
|
784
|
-
// Drop includes from the resolved asset — they've been inlined
|
|
785
|
-
includes: void 0
|
|
786
|
-
};
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
// src/prompt-resolution.ts
|
|
790
|
-
var DEFAULT_PROMPTS_DIR = "./prompts";
|
|
791
|
-
var DEFAULT_COMPILED_JSON_DIR = "./.generated-prompts/json";
|
|
792
|
-
function withPromptResolutionDefaults(config) {
|
|
793
|
-
return {
|
|
794
|
-
...config,
|
|
795
|
-
sourceDir: config.sourceDir ?? DEFAULT_PROMPTS_DIR,
|
|
796
|
-
compiledDir: config.compiledDir ?? DEFAULT_COMPILED_JSON_DIR
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
var sharedPromptCache = new PromptCache();
|
|
800
|
-
async function loadPromptAsset(promptPath, config, promptCache = sharedPromptCache) {
|
|
801
|
-
const resolvedConfig = withPromptResolutionDefaults(config);
|
|
802
|
-
const mode = resolvedConfig.mode ?? "auto";
|
|
803
|
-
if (mode !== "source-only" && resolvedConfig.compiledDir) {
|
|
804
|
-
const compiledFile = (0, import_node_path3.resolve)(resolvedConfig.compiledDir, promptPath + ".json");
|
|
805
|
-
if ((0, import_node_fs2.existsSync)(compiledFile)) {
|
|
806
|
-
if (mode === "auto") {
|
|
807
|
-
const sourceFile = (0, import_node_path3.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
|
|
808
|
-
if ((0, import_node_fs2.existsSync)(sourceFile)) {
|
|
809
|
-
const compiledMtime = (0, import_node_fs2.statSync)(compiledFile).mtimeMs;
|
|
810
|
-
const sourceMtime = (0, import_node_fs2.statSync)(sourceFile).mtimeMs;
|
|
811
|
-
if (sourceMtime > compiledMtime) {
|
|
812
|
-
console.warn(
|
|
813
|
-
`[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
|
|
814
|
-
Run "promptopskit compile" or switch to source-only mode.`
|
|
815
|
-
);
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
const content = await (0, import_promises3.readFile)(compiledFile, "utf-8");
|
|
820
|
-
return JSON.parse(content);
|
|
821
|
-
}
|
|
822
|
-
if (mode === "compiled-only") {
|
|
823
|
-
throw new Error(
|
|
824
|
-
`Compiled artifact not found: ${compiledFile}
|
|
825
|
-
Run "promptopskit compile" to generate it.`
|
|
826
|
-
);
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
if (mode !== "compiled-only") {
|
|
830
|
-
const sourceFile = (0, import_node_path3.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
|
|
831
|
-
if (resolvedConfig.cache !== false) {
|
|
832
|
-
const cached = promptCache.get(sourceFile);
|
|
833
|
-
if (cached) {
|
|
834
|
-
return cached;
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
if (!(0, import_node_fs2.existsSync)(sourceFile)) {
|
|
838
|
-
const paths = [sourceFile];
|
|
839
|
-
if (resolvedConfig.compiledDir) {
|
|
840
|
-
paths.unshift((0, import_node_path3.resolve)(resolvedConfig.compiledDir, promptPath + ".json"));
|
|
841
|
-
}
|
|
842
|
-
throw new Error(
|
|
843
|
-
`Prompt not found: "${promptPath}"
|
|
844
|
-
Searched:
|
|
845
|
-
${paths.map((candidate) => ` - ${candidate}`).join("\n")}`
|
|
846
|
-
);
|
|
847
|
-
}
|
|
848
|
-
const { asset } = await loadPromptFile(sourceFile, { defaultsRoot: resolvedConfig.sourceDir });
|
|
849
|
-
if (resolvedConfig.cache !== false) {
|
|
850
|
-
promptCache.set(sourceFile, asset);
|
|
851
|
-
}
|
|
852
|
-
return asset;
|
|
853
|
-
}
|
|
854
|
-
throw new Error(`Prompt not found: "${promptPath}"`);
|
|
855
|
-
}
|
|
856
|
-
async function resolvePromptAsset(promptPath, config, options = {}, promptCache = sharedPromptCache) {
|
|
857
|
-
const resolvedConfig = withPromptResolutionDefaults(config);
|
|
858
|
-
let asset = await loadPromptAsset(promptPath, resolvedConfig, promptCache);
|
|
859
|
-
const sourceFile = (0, import_node_path3.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
|
|
860
|
-
if (asset.includes && asset.includes.length > 0 && (0, import_node_fs2.existsSync)(sourceFile)) {
|
|
861
|
-
asset = await resolveIncludes(asset, sourceFile);
|
|
862
|
-
}
|
|
863
|
-
asset = applyOverrides(asset, {
|
|
864
|
-
environment: options.environment,
|
|
865
|
-
tier: options.tier,
|
|
866
|
-
runtime: options.runtime
|
|
867
|
-
});
|
|
868
|
-
return asset;
|
|
869
|
-
}
|
|
870
|
-
function resolveInlinePromptSource(source, options = {}) {
|
|
871
|
-
const { asset } = parsePrompt(source);
|
|
872
|
-
return applyOverrides(asset, {
|
|
873
|
-
environment: options.environment,
|
|
874
|
-
tier: options.tier,
|
|
875
|
-
runtime: options.runtime
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
// src/context.ts
|
|
880
|
-
var textEncoder = new TextEncoder();
|
|
881
|
-
var REJECT_SECRETS_PATTERN = "(secret|api[_-]?key|password)";
|
|
882
|
-
var REJECT_SECRETS_FLAGS = "i";
|
|
883
|
-
function getContextInputs(asset) {
|
|
884
|
-
return (asset.context?.inputs ?? []).map(normalizeContextInput);
|
|
885
|
-
}
|
|
886
|
-
function getContextInputNames(asset) {
|
|
887
|
-
return getContextInputs(asset).map((input) => input.name);
|
|
1150
|
+
system_instructions: sections.system_instructions
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
888
1153
|
}
|
|
889
|
-
function
|
|
890
|
-
if (typeof input === "string") {
|
|
891
|
-
return { name: input };
|
|
892
|
-
}
|
|
1154
|
+
function mergeDefaults(base, local) {
|
|
893
1155
|
return {
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
1156
|
+
provider: local.provider ?? base.provider,
|
|
1157
|
+
model: local.model ?? base.model,
|
|
1158
|
+
fallback_models: local.fallback_models ?? base.fallback_models,
|
|
1159
|
+
reasoning: mergeRecordBlock2(base.reasoning, local.reasoning),
|
|
1160
|
+
sampling: mergeRecordBlock2(base.sampling, local.sampling),
|
|
1161
|
+
response: mergeRecordBlock2(base.response, local.response),
|
|
1162
|
+
cache: mergeCache(base.cache, local.cache),
|
|
1163
|
+
raw: mergeRaw(base.raw, local.raw),
|
|
1164
|
+
tools: local.tools ?? base.tools,
|
|
1165
|
+
provider_options: mergeProviderOptions(base.provider_options, local.provider_options),
|
|
1166
|
+
mcp: mergeMcp(base.mcp, local.mcp),
|
|
1167
|
+
context: mergeContext(base.context, local.context),
|
|
1168
|
+
includes: local.includes ?? base.includes,
|
|
1169
|
+
environments: mergeOverrideMap(base.environments, local.environments),
|
|
1170
|
+
tiers: mergeOverrideMap(base.tiers, local.tiers),
|
|
1171
|
+
metadata: {
|
|
1172
|
+
...base.metadata ?? {},
|
|
1173
|
+
...local.metadata ?? {}
|
|
1174
|
+
},
|
|
1175
|
+
sections: {
|
|
1176
|
+
...base.sections ?? {},
|
|
1177
|
+
...local.sections ?? {}
|
|
1178
|
+
}
|
|
901
1179
|
};
|
|
902
1180
|
}
|
|
903
|
-
function
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
raw: value
|
|
921
|
-
};
|
|
1181
|
+
function applyDefaults(asset, defaults) {
|
|
1182
|
+
const cache = mergeCache(defaults.cache, asset.cache);
|
|
1183
|
+
const raw = mergeRaw(defaults.raw, asset.raw);
|
|
1184
|
+
const providerOptions = mergeProviderOptions(defaults.provider_options, asset.provider_options);
|
|
1185
|
+
const reasoning = mergeRecordBlock2(defaults.reasoning, asset.reasoning);
|
|
1186
|
+
const sampling = mergeRecordBlock2(defaults.sampling, asset.sampling);
|
|
1187
|
+
const response = mergeRecordBlock2(defaults.response, asset.response);
|
|
1188
|
+
const mcp = mergeMcp(defaults.mcp, asset.mcp);
|
|
1189
|
+
const context = mergeContext(defaults.context, asset.context);
|
|
1190
|
+
const environments = mergeOverrideMap(defaults.environments, asset.environments);
|
|
1191
|
+
const tiers = mergeOverrideMap(defaults.tiers, asset.tiers);
|
|
1192
|
+
const hasDefaultMetadata = defaults.metadata && Object.keys(defaults.metadata).length > 0;
|
|
1193
|
+
const hasDefaultSystem = !!defaults.sections?.system_instructions;
|
|
1194
|
+
const hasDefaultScalars = defaults.provider !== void 0 || defaults.model !== void 0 || defaults.fallback_models !== void 0 || defaults.tools !== void 0 || defaults.includes !== void 0;
|
|
1195
|
+
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;
|
|
1196
|
+
if (!hasDefaultMetadata && !hasDefaultSystem && !hasDefaultScalars && !hasDefaultObjects) {
|
|
1197
|
+
return asset;
|
|
922
1198
|
}
|
|
1199
|
+
const mergedMetadata = {
|
|
1200
|
+
...defaults.metadata ?? {},
|
|
1201
|
+
...asset.metadata ?? {}
|
|
1202
|
+
};
|
|
1203
|
+
const metadata = Object.keys(mergedMetadata).length > 0 ? mergedMetadata : void 0;
|
|
1204
|
+
const systemInstructions = asset.sections?.system_instructions ?? defaults.sections?.system_instructions;
|
|
1205
|
+
const sections = asset.sections ? { ...asset.sections, system_instructions: systemInstructions } : systemInstructions ? { system_instructions: systemInstructions } : void 0;
|
|
923
1206
|
return {
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1207
|
+
...asset,
|
|
1208
|
+
provider: asset.provider ?? defaults.provider,
|
|
1209
|
+
model: asset.model ?? defaults.model,
|
|
1210
|
+
fallback_models: asset.fallback_models ?? defaults.fallback_models,
|
|
1211
|
+
reasoning,
|
|
1212
|
+
sampling,
|
|
1213
|
+
response,
|
|
1214
|
+
cache,
|
|
1215
|
+
raw,
|
|
1216
|
+
tools: asset.tools ?? defaults.tools,
|
|
1217
|
+
provider_options: providerOptions,
|
|
1218
|
+
mcp,
|
|
1219
|
+
context,
|
|
1220
|
+
includes: asset.includes ?? defaults.includes,
|
|
1221
|
+
environments,
|
|
1222
|
+
tiers,
|
|
1223
|
+
metadata,
|
|
1224
|
+
sections
|
|
928
1225
|
};
|
|
929
1226
|
}
|
|
930
|
-
function
|
|
931
|
-
if (
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1227
|
+
function normalizeDefaultIncludes(defaults, defaultsPath, filePath) {
|
|
1228
|
+
if (!defaults.includes) return defaults;
|
|
1229
|
+
const promptDir = (0, import_node_path2.dirname)(filePath);
|
|
1230
|
+
const defaultsDir = (0, import_node_path2.dirname)(defaultsPath);
|
|
1231
|
+
const includes = defaults.includes.map((includePath) => {
|
|
1232
|
+
const relativePath = (0, import_node_path2.relative)(promptDir, (0, import_node_path2.resolve)(defaultsDir, includePath)).replace(/\\/g, "/");
|
|
1233
|
+
return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
1234
|
+
});
|
|
937
1235
|
return {
|
|
938
|
-
|
|
1236
|
+
...defaults,
|
|
1237
|
+
includes
|
|
939
1238
|
};
|
|
940
1239
|
}
|
|
941
|
-
function
|
|
942
|
-
if (
|
|
943
|
-
|
|
944
|
-
}
|
|
945
|
-
for (let index = value.length - 1; index > 0; index -= 1) {
|
|
946
|
-
if (value[index] !== "/") {
|
|
947
|
-
continue;
|
|
948
|
-
}
|
|
949
|
-
let backslashCount = 0;
|
|
950
|
-
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
|
|
951
|
-
backslashCount += 1;
|
|
952
|
-
}
|
|
953
|
-
if (backslashCount % 2 === 1) {
|
|
954
|
-
continue;
|
|
955
|
-
}
|
|
956
|
-
return {
|
|
957
|
-
pattern: value.slice(1, index),
|
|
958
|
-
flags: value.slice(index + 1)
|
|
959
|
-
};
|
|
960
|
-
}
|
|
961
|
-
return void 0;
|
|
1240
|
+
function mergeRecordBlock2(base, local) {
|
|
1241
|
+
if (base === void 0) return local;
|
|
1242
|
+
if (local === void 0) return base;
|
|
1243
|
+
return { ...base, ...local };
|
|
962
1244
|
}
|
|
963
|
-
function
|
|
964
|
-
return
|
|
965
|
-
`Invalid context regex for prompt "${details.promptId}"`,
|
|
966
|
-
`variable "${details.variable}"`,
|
|
967
|
-
`field "${details.field}"`,
|
|
968
|
-
`value ${JSON.stringify(details.raw)}: ${details.reason}`
|
|
969
|
-
].join(", ");
|
|
1245
|
+
function mergeMcp(base, local) {
|
|
1246
|
+
return mergeRecordBlock2(base, local);
|
|
970
1247
|
}
|
|
971
|
-
function
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
})}`
|
|
979
|
-
);
|
|
980
|
-
}
|
|
981
|
-
try {
|
|
982
|
-
return new RegExp(regex.pattern, regex.flags);
|
|
983
|
-
} catch (error) {
|
|
984
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
985
|
-
throw new Error(`POK013: ${formatInvalidContextRegexMessage({ ...details, raw: regex.raw, reason })}`);
|
|
986
|
-
}
|
|
1248
|
+
function mergeContext(base, local) {
|
|
1249
|
+
const merged = {
|
|
1250
|
+
...base ?? {},
|
|
1251
|
+
...local ?? {},
|
|
1252
|
+
history: mergeRecordBlock2(base?.history, local?.history)
|
|
1253
|
+
};
|
|
1254
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
987
1255
|
}
|
|
988
|
-
function
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1256
|
+
function mergeCache(base, local) {
|
|
1257
|
+
const merged = {
|
|
1258
|
+
...base ?? {},
|
|
1259
|
+
...local ?? {},
|
|
1260
|
+
openai: {
|
|
1261
|
+
...base?.openai ?? {},
|
|
1262
|
+
...local?.openai ?? {}
|
|
1263
|
+
},
|
|
1264
|
+
anthropic: {
|
|
1265
|
+
...base?.anthropic ?? {},
|
|
1266
|
+
...local?.anthropic ?? {}
|
|
1267
|
+
},
|
|
1268
|
+
gemini: {
|
|
1269
|
+
...base?.gemini ?? {},
|
|
1270
|
+
...local?.gemini ?? {}
|
|
1271
|
+
},
|
|
1272
|
+
google: {
|
|
1273
|
+
...base?.google ?? {},
|
|
1274
|
+
...local?.google ?? {}
|
|
1275
|
+
}
|
|
993
1276
|
};
|
|
1277
|
+
if (merged.openai && Object.keys(merged.openai).length === 0) delete merged.openai;
|
|
1278
|
+
if (merged.anthropic && Object.keys(merged.anthropic).length === 0) delete merged.anthropic;
|
|
1279
|
+
if (merged.gemini && Object.keys(merged.gemini).length === 0) delete merged.gemini;
|
|
1280
|
+
if (merged.google && Object.keys(merged.google).length === 0) delete merged.google;
|
|
1281
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
994
1282
|
}
|
|
995
|
-
function
|
|
996
|
-
|
|
1283
|
+
function mergeRaw(base, local) {
|
|
1284
|
+
const merged = {
|
|
1285
|
+
...base ?? {},
|
|
1286
|
+
...local ?? {},
|
|
1287
|
+
openai: mergeRecordBlock2(base?.openai, local?.openai),
|
|
1288
|
+
"openai-responses": mergeRecordBlock2(base?.["openai-responses"], local?.["openai-responses"]),
|
|
1289
|
+
openai_responses: mergeRecordBlock2(base?.openai_responses, local?.openai_responses),
|
|
1290
|
+
anthropic: mergeRecordBlock2(base?.anthropic, local?.anthropic),
|
|
1291
|
+
gemini: mergeRecordBlock2(base?.gemini, local?.gemini),
|
|
1292
|
+
google: mergeRecordBlock2(base?.google, local?.google),
|
|
1293
|
+
openrouter: mergeRecordBlock2(base?.openrouter, local?.openrouter),
|
|
1294
|
+
llmasaservice: mergeRecordBlock2(base?.llmasaservice, local?.llmasaservice)
|
|
1295
|
+
};
|
|
1296
|
+
removeEmptyProviderBlocks(merged);
|
|
1297
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
997
1298
|
}
|
|
998
|
-
function
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1299
|
+
function mergeProviderOptions(base, local) {
|
|
1300
|
+
const merged = {
|
|
1301
|
+
...base ?? {},
|
|
1302
|
+
...local ?? {},
|
|
1303
|
+
anthropic: mergeRecordBlock2(base?.anthropic, local?.anthropic),
|
|
1304
|
+
gemini: mergeRecordBlock2(base?.gemini, local?.gemini),
|
|
1305
|
+
openrouter: mergeRecordBlock2(base?.openrouter, local?.openrouter),
|
|
1306
|
+
llmasaservice: mergeRecordBlock2(base?.llmasaservice, local?.llmasaservice)
|
|
1307
|
+
};
|
|
1308
|
+
removeEmptyProviderBlocks(merged);
|
|
1309
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
1003
1310
|
}
|
|
1004
|
-
function
|
|
1005
|
-
const
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
}
|
|
1009
|
-
const characters = Array.from(value);
|
|
1010
|
-
const normalizedMode = normalizeTrimMode(mode);
|
|
1011
|
-
if (normalizedMode === "start") {
|
|
1012
|
-
let collected2 = "";
|
|
1013
|
-
let size2 = 0;
|
|
1014
|
-
for (let i = characters.length - 1; i >= 0; i -= 1) {
|
|
1015
|
-
const next = characters[i];
|
|
1016
|
-
const charSize = measureContextValueSize(next);
|
|
1017
|
-
if (size2 + charSize > maxSize) {
|
|
1018
|
-
break;
|
|
1019
|
-
}
|
|
1020
|
-
collected2 = next + collected2;
|
|
1021
|
-
size2 += charSize;
|
|
1022
|
-
}
|
|
1023
|
-
return collected2;
|
|
1311
|
+
function mergeOverrideMap(base, local) {
|
|
1312
|
+
const merged = { ...base ?? {} };
|
|
1313
|
+
for (const [name, localOverride] of Object.entries(local ?? {})) {
|
|
1314
|
+
merged[name] = mergeOverrideConfig(merged[name], localOverride);
|
|
1024
1315
|
}
|
|
1025
|
-
|
|
1026
|
-
let size = 0;
|
|
1027
|
-
for (const char of characters) {
|
|
1028
|
-
const charSize = measureContextValueSize(char);
|
|
1029
|
-
if (size + charSize > maxSize) {
|
|
1030
|
-
break;
|
|
1031
|
-
}
|
|
1032
|
-
collected += char;
|
|
1033
|
-
size += charSize;
|
|
1034
|
-
}
|
|
1035
|
-
return collected;
|
|
1316
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
1036
1317
|
}
|
|
1037
|
-
function
|
|
1038
|
-
const
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1318
|
+
function mergeOverrideConfig(base, local) {
|
|
1319
|
+
const merged = {
|
|
1320
|
+
...base ?? {},
|
|
1321
|
+
...local
|
|
1322
|
+
};
|
|
1323
|
+
const reasoning = mergeRecordBlock2(base?.reasoning, local.reasoning);
|
|
1324
|
+
const sampling = mergeRecordBlock2(base?.sampling, local.sampling);
|
|
1325
|
+
const response = mergeRecordBlock2(base?.response, local.response);
|
|
1326
|
+
const cache = mergeCache(base?.cache, local.cache);
|
|
1327
|
+
const raw = mergeRaw(base?.raw, local.raw);
|
|
1328
|
+
const providerOptions = mergeProviderOptions(base?.provider_options, local.provider_options);
|
|
1329
|
+
if (reasoning !== void 0) merged.reasoning = reasoning;
|
|
1330
|
+
if (sampling !== void 0) merged.sampling = sampling;
|
|
1331
|
+
if (response !== void 0) merged.response = response;
|
|
1332
|
+
if (cache !== void 0) merged.cache = cache;
|
|
1333
|
+
if (raw !== void 0) merged.raw = raw;
|
|
1334
|
+
if (providerOptions !== void 0) merged.provider_options = providerOptions;
|
|
1335
|
+
return merged;
|
|
1336
|
+
}
|
|
1337
|
+
function removeEmptyProviderBlocks(value) {
|
|
1338
|
+
for (const key of Object.keys(value)) {
|
|
1339
|
+
const block = value[key];
|
|
1340
|
+
if (block === void 0) {
|
|
1341
|
+
delete value[key];
|
|
1043
1342
|
continue;
|
|
1044
1343
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
const actualSize = measureContextValueSize(candidate);
|
|
1048
|
-
if (actualSize > input.max_size && onContextOverflow) {
|
|
1049
|
-
candidate = onContextOverflow({
|
|
1050
|
-
promptId: asset.id,
|
|
1051
|
-
variable: input.name,
|
|
1052
|
-
value: candidate,
|
|
1053
|
-
maxSize: input.max_size,
|
|
1054
|
-
actualSize
|
|
1055
|
-
});
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
if (isTrimEnabled(input.trim) && input.max_size !== void 0) {
|
|
1059
|
-
candidate = trimToMaxSize(candidate, input.max_size, input.trim);
|
|
1344
|
+
if (block !== null && typeof block === "object" && !Array.isArray(block) && Object.keys(block).length === 0) {
|
|
1345
|
+
delete value[key];
|
|
1060
1346
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
// src/composition/resolve-includes.ts
|
|
1351
|
+
async function resolveIncludes(asset, basePath, visited = /* @__PURE__ */ new Set()) {
|
|
1352
|
+
if (!asset.includes || asset.includes.length === 0) {
|
|
1353
|
+
return asset;
|
|
1354
|
+
}
|
|
1355
|
+
const baseDir = (0, import_node_path3.dirname)(basePath);
|
|
1356
|
+
const resolvedPath = (0, import_node_path3.resolve)(basePath);
|
|
1357
|
+
if (visited.has(resolvedPath)) {
|
|
1358
|
+
throw new Error(`Circular include detected: ${resolvedPath}`);
|
|
1359
|
+
}
|
|
1360
|
+
visited.add(resolvedPath);
|
|
1361
|
+
let mergedSystemInstructions = "";
|
|
1362
|
+
for (const includePath of asset.includes) {
|
|
1363
|
+
const fullPath = (0, import_node_path3.resolve)(baseDir, includePath);
|
|
1364
|
+
if (visited.has(fullPath)) {
|
|
1365
|
+
throw new Error(`Circular include detected: ${fullPath} (included from ${basePath})`);
|
|
1366
|
+
}
|
|
1367
|
+
const content = await (0, import_promises3.readFile)(fullPath, "utf-8");
|
|
1368
|
+
const { asset: includedAsset } = parsePrompt(content, fullPath);
|
|
1369
|
+
const resolved = await resolveIncludes(includedAsset, fullPath, new Set(visited));
|
|
1370
|
+
if (resolved.sections?.system_instructions) {
|
|
1371
|
+
mergedSystemInstructions += resolved.sections.system_instructions + "\n\n";
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
const localSystem = asset.sections?.system_instructions ?? "";
|
|
1375
|
+
const combinedSystem = (mergedSystemInstructions + localSystem).trim() || void 0;
|
|
1376
|
+
return {
|
|
1377
|
+
...asset,
|
|
1378
|
+
sections: {
|
|
1379
|
+
...asset.sections,
|
|
1380
|
+
system_instructions: combinedSystem
|
|
1381
|
+
},
|
|
1382
|
+
// Drop includes from the resolved asset — they've been inlined
|
|
1383
|
+
includes: void 0
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
// src/prompt-resolution.ts
|
|
1388
|
+
var DEFAULT_PROMPTS_DIR = "./prompts";
|
|
1389
|
+
var DEFAULT_COMPILED_JSON_DIR = "./.generated-prompts/json";
|
|
1390
|
+
function withPromptResolutionDefaults(config) {
|
|
1391
|
+
return {
|
|
1392
|
+
...config,
|
|
1393
|
+
sourceDir: config.sourceDir ?? DEFAULT_PROMPTS_DIR,
|
|
1394
|
+
compiledDir: config.compiledDir ?? DEFAULT_COMPILED_JSON_DIR
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
var sharedPromptCache = new PromptCache();
|
|
1398
|
+
async function loadPromptAsset(promptPath, config, promptCache = sharedPromptCache) {
|
|
1399
|
+
const resolvedConfig = withPromptResolutionDefaults(config);
|
|
1400
|
+
const mode = resolvedConfig.mode ?? "auto";
|
|
1401
|
+
if (mode !== "source-only" && resolvedConfig.compiledDir) {
|
|
1402
|
+
const compiledFile = (0, import_node_path4.resolve)(resolvedConfig.compiledDir, promptPath + ".json");
|
|
1403
|
+
if ((0, import_node_fs2.existsSync)(compiledFile)) {
|
|
1404
|
+
if (mode === "auto") {
|
|
1405
|
+
const sourceFile = (0, import_node_path4.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
|
|
1406
|
+
if ((0, import_node_fs2.existsSync)(sourceFile)) {
|
|
1407
|
+
const compiledMtime = (0, import_node_fs2.statSync)(compiledFile).mtimeMs;
|
|
1408
|
+
const sourceMtime = (0, import_node_fs2.statSync)(sourceFile).mtimeMs;
|
|
1409
|
+
if (sourceMtime > compiledMtime) {
|
|
1410
|
+
console.warn(
|
|
1411
|
+
`[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
|
|
1412
|
+
Run "promptopskit compile" or switch to source-only mode.`
|
|
1413
|
+
);
|
|
1414
|
+
}
|
|
1080
1415
|
}
|
|
1081
|
-
throw new Error(
|
|
1082
|
-
`POK031: Context variable "${input.name}" failed allow_regex validation for prompt "${asset.id}".`
|
|
1083
|
-
);
|
|
1084
1416
|
}
|
|
1417
|
+
const content = await (0, import_promises4.readFile)(compiledFile, "utf-8");
|
|
1418
|
+
return JSON.parse(content);
|
|
1085
1419
|
}
|
|
1086
|
-
if (
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
code: "POK032",
|
|
1100
|
-
variable: input.name,
|
|
1101
|
-
field: "deny_regex"
|
|
1102
|
-
}
|
|
1103
|
-
};
|
|
1104
|
-
}
|
|
1105
|
-
throw new Error(
|
|
1106
|
-
`POK032: Context variable "${input.name}" matched deny_regex for prompt "${asset.id}".`
|
|
1107
|
-
);
|
|
1420
|
+
if (mode === "compiled-only") {
|
|
1421
|
+
throw new Error(
|
|
1422
|
+
`Compiled artifact not found: ${compiledFile}
|
|
1423
|
+
Run "promptopskit compile" to generate it.`
|
|
1424
|
+
);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
if (mode !== "compiled-only") {
|
|
1428
|
+
const sourceFile = (0, import_node_path4.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
|
|
1429
|
+
if (resolvedConfig.cache !== false) {
|
|
1430
|
+
const cached = promptCache.get(sourceFile);
|
|
1431
|
+
if (cached) {
|
|
1432
|
+
return cached;
|
|
1108
1433
|
}
|
|
1109
1434
|
}
|
|
1110
|
-
if (
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
shortCircuit: {
|
|
1115
|
-
returnMessage: input.non_empty.returnMessage,
|
|
1116
|
-
code: "POK033",
|
|
1117
|
-
variable: input.name,
|
|
1118
|
-
field: "non_empty"
|
|
1119
|
-
}
|
|
1120
|
-
};
|
|
1435
|
+
if (!(0, import_node_fs2.existsSync)(sourceFile)) {
|
|
1436
|
+
const paths = [sourceFile];
|
|
1437
|
+
if (resolvedConfig.compiledDir) {
|
|
1438
|
+
paths.unshift((0, import_node_path4.resolve)(resolvedConfig.compiledDir, promptPath + ".json"));
|
|
1121
1439
|
}
|
|
1122
1440
|
throw new Error(
|
|
1123
|
-
`
|
|
1441
|
+
`Prompt not found: "${promptPath}"
|
|
1442
|
+
Searched:
|
|
1443
|
+
${paths.map((candidate) => ` - ${candidate}`).join("\n")}`
|
|
1124
1444
|
);
|
|
1125
1445
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
variable: input.name,
|
|
1130
|
-
field: "reject_secrets"
|
|
1131
|
-
});
|
|
1132
|
-
if (matcher.test(candidate)) {
|
|
1133
|
-
if (input.reject_secrets.returnMessage) {
|
|
1134
|
-
return {
|
|
1135
|
-
variables: sanitized,
|
|
1136
|
-
shortCircuit: {
|
|
1137
|
-
returnMessage: input.reject_secrets.returnMessage,
|
|
1138
|
-
code: "POK034",
|
|
1139
|
-
variable: input.name,
|
|
1140
|
-
field: "reject_secrets"
|
|
1141
|
-
}
|
|
1142
|
-
};
|
|
1143
|
-
}
|
|
1144
|
-
throw new Error(
|
|
1145
|
-
`POK034: Context variable "${input.name}" matched reject_secrets validation for prompt "${asset.id}".`
|
|
1146
|
-
);
|
|
1147
|
-
}
|
|
1446
|
+
const { asset } = await loadPromptFile(sourceFile, { defaultsRoot: resolvedConfig.sourceDir });
|
|
1447
|
+
if (resolvedConfig.cache !== false) {
|
|
1448
|
+
promptCache.set(sourceFile, asset);
|
|
1148
1449
|
}
|
|
1450
|
+
return asset;
|
|
1149
1451
|
}
|
|
1150
|
-
|
|
1452
|
+
throw new Error(`Prompt not found: "${promptPath}"`);
|
|
1151
1453
|
}
|
|
1152
|
-
function
|
|
1153
|
-
|
|
1454
|
+
async function resolvePromptAsset(promptPath, config, options = {}, promptCache = sharedPromptCache) {
|
|
1455
|
+
const resolvedConfig = withPromptResolutionDefaults(config);
|
|
1456
|
+
let asset = await loadPromptAsset(promptPath, resolvedConfig, promptCache);
|
|
1457
|
+
const sourceFile = (0, import_node_path4.resolve)(resolvedConfig.sourceDir, promptPath + ".md");
|
|
1458
|
+
if (asset.includes && asset.includes.length > 0 && (0, import_node_fs2.existsSync)(sourceFile)) {
|
|
1459
|
+
asset = await resolveIncludes(asset, sourceFile);
|
|
1460
|
+
}
|
|
1461
|
+
asset = applyOverrides(asset, {
|
|
1462
|
+
environment: options.environment,
|
|
1463
|
+
tier: options.tier,
|
|
1464
|
+
runtime: options.runtime
|
|
1465
|
+
});
|
|
1466
|
+
return asset;
|
|
1154
1467
|
}
|
|
1155
|
-
function
|
|
1156
|
-
const
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1468
|
+
function resolveInlinePromptSource(source, options = {}) {
|
|
1469
|
+
const { asset } = parsePrompt(source);
|
|
1470
|
+
return applyOverrides(asset, {
|
|
1471
|
+
environment: options.environment,
|
|
1472
|
+
tier: options.tier,
|
|
1473
|
+
runtime: options.runtime
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
// src/history.ts
|
|
1478
|
+
function defaultCompactHistory(info) {
|
|
1479
|
+
const content = info.overflow.map((message) => `${message.role}: ${message.content}`).join("\n\n");
|
|
1480
|
+
return {
|
|
1481
|
+
role: "user",
|
|
1482
|
+
content: `Earlier conversation compacted to preserve history:
|
|
1483
|
+
|
|
1484
|
+
${content}`
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
function normalizeCompactionResult(result) {
|
|
1488
|
+
if (typeof result === "string") {
|
|
1489
|
+
return {
|
|
1490
|
+
role: "user",
|
|
1491
|
+
content: result
|
|
1492
|
+
};
|
|
1173
1493
|
}
|
|
1174
|
-
return
|
|
1494
|
+
return result;
|
|
1495
|
+
}
|
|
1496
|
+
function compactHistoryForPrompt(asset, runtime) {
|
|
1497
|
+
const history = runtime.history;
|
|
1498
|
+
const maxItems = asset.context?.history?.max_items;
|
|
1499
|
+
if (!history || maxItems === void 0 || history.length <= maxItems) {
|
|
1500
|
+
return history;
|
|
1501
|
+
}
|
|
1502
|
+
if (maxItems === 1) {
|
|
1503
|
+
const info2 = {
|
|
1504
|
+
promptId: asset.id,
|
|
1505
|
+
maxItems,
|
|
1506
|
+
overflow: history,
|
|
1507
|
+
preserved: [],
|
|
1508
|
+
history
|
|
1509
|
+
};
|
|
1510
|
+
const compacted2 = runtime.onHistoryCompaction ? normalizeCompactionResult(runtime.onHistoryCompaction(info2)) : defaultCompactHistory(info2);
|
|
1511
|
+
return [compacted2];
|
|
1512
|
+
}
|
|
1513
|
+
const preservedCount = maxItems - 1;
|
|
1514
|
+
const overflow = history.slice(0, history.length - preservedCount);
|
|
1515
|
+
const preserved = history.slice(-preservedCount);
|
|
1516
|
+
const info = {
|
|
1517
|
+
promptId: asset.id,
|
|
1518
|
+
maxItems,
|
|
1519
|
+
overflow,
|
|
1520
|
+
preserved,
|
|
1521
|
+
history
|
|
1522
|
+
};
|
|
1523
|
+
const compacted = runtime.onHistoryCompaction ? normalizeCompactionResult(runtime.onHistoryCompaction(info)) : defaultCompactHistory(info);
|
|
1524
|
+
return [compacted, ...preserved];
|
|
1175
1525
|
}
|
|
1176
1526
|
|
|
1177
1527
|
// src/providers/prompt-input.ts
|
|
@@ -1209,7 +1559,8 @@ function withPromptInputSupport(adapter) {
|
|
|
1209
1559
|
}
|
|
1210
1560
|
return adapter.render(resolved, {
|
|
1211
1561
|
...runtime,
|
|
1212
|
-
variables: sanitization.variables
|
|
1562
|
+
variables: sanitization.variables,
|
|
1563
|
+
history: compactHistoryForPrompt(resolved, runtime)
|
|
1213
1564
|
});
|
|
1214
1565
|
};
|
|
1215
1566
|
return {
|
|
@@ -1262,8 +1613,9 @@ var openaiAdapter = withPromptInputSupport({
|
|
|
1262
1613
|
if (sections.system_instructions) {
|
|
1263
1614
|
messages.push({ role: "system", content: sections.system_instructions });
|
|
1264
1615
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1616
|
+
const history = compactHistoryForPrompt(resolvedAsset, runtime);
|
|
1617
|
+
if (history) {
|
|
1618
|
+
for (const msg of history) {
|
|
1267
1619
|
messages.push({ role: msg.role, content: msg.content });
|
|
1268
1620
|
}
|
|
1269
1621
|
}
|
|
@@ -1360,8 +1712,9 @@ var openaiResponsesAdapter = withPromptInputSupport({
|
|
|
1360
1712
|
});
|
|
1361
1713
|
const responseOptions = runtime.openaiResponses;
|
|
1362
1714
|
const input = [];
|
|
1363
|
-
|
|
1364
|
-
|
|
1715
|
+
const history = compactHistoryForPrompt(resolvedAsset, runtime);
|
|
1716
|
+
if (history) {
|
|
1717
|
+
for (const msg of history) {
|
|
1365
1718
|
input.push({ role: msg.role, content: msg.content });
|
|
1366
1719
|
}
|
|
1367
1720
|
}
|
|
@@ -1474,8 +1827,9 @@ var anthropicAdapter = withPromptInputSupport({
|
|
|
1474
1827
|
...anthropicCacheConfig.ttl ? { ttl: anthropicCacheConfig.ttl } : {}
|
|
1475
1828
|
} : void 0;
|
|
1476
1829
|
const cacheMode = anthropicCacheConfig?.mode ?? "automatic";
|
|
1477
|
-
|
|
1478
|
-
|
|
1830
|
+
const history = compactHistoryForPrompt(resolvedAsset, runtime);
|
|
1831
|
+
if (history) {
|
|
1832
|
+
for (const msg of history) {
|
|
1479
1833
|
messages.push({ role: msg.role, content: msg.content });
|
|
1480
1834
|
}
|
|
1481
1835
|
}
|
|
@@ -1600,8 +1954,9 @@ var geminiAdapter = withPromptInputSupport({
|
|
|
1600
1954
|
strict: runtime.strict
|
|
1601
1955
|
});
|
|
1602
1956
|
const contents = [];
|
|
1603
|
-
|
|
1604
|
-
|
|
1957
|
+
const history = compactHistoryForPrompt(resolvedAsset, runtime);
|
|
1958
|
+
if (history) {
|
|
1959
|
+
for (const msg of history) {
|
|
1605
1960
|
contents.push({
|
|
1606
1961
|
role: msg.role === "assistant" ? "model" : "user",
|
|
1607
1962
|
parts: [{ text: msg.content }]
|
|
@@ -1703,6 +2058,7 @@ var openrouterAdapter = withPromptInputSupport({
|
|
|
1703
2058
|
{
|
|
1704
2059
|
variables: runtime.variables,
|
|
1705
2060
|
history: runtime.history,
|
|
2061
|
+
onHistoryCompaction: runtime.onHistoryCompaction,
|
|
1706
2062
|
toolRegistry: runtime.toolRegistry,
|
|
1707
2063
|
strict: runtime.strict
|
|
1708
2064
|
}
|
|
@@ -1724,6 +2080,118 @@ var openrouterAdapter = withPromptInputSupport({
|
|
|
1724
2080
|
}
|
|
1725
2081
|
});
|
|
1726
2082
|
|
|
2083
|
+
// src/providers/llmasaservice.ts
|
|
2084
|
+
var LLMASASERVICE_BASE_URL = "https://gateway.llmasaservice.io";
|
|
2085
|
+
var LLMASASERVICE_SDK_PLACEHOLDER_API_KEY = "not-used-by-llm-gateway";
|
|
2086
|
+
var LLMASASERVICE_DEFAULT_MODEL = "group:standard";
|
|
2087
|
+
var LLMASASERVICE_RESPONSE_HEADER_NAMES = [
|
|
2088
|
+
"x-request-id",
|
|
2089
|
+
"x-llm-model-id",
|
|
2090
|
+
"x-llm-model-group"
|
|
2091
|
+
];
|
|
2092
|
+
function createLLMAsAServiceOpenAIConfig(options = {}) {
|
|
2093
|
+
return {
|
|
2094
|
+
baseURL: options.baseURL ?? LLMASASERVICE_BASE_URL,
|
|
2095
|
+
apiKey: LLMASASERVICE_SDK_PLACEHOLDER_API_KEY,
|
|
2096
|
+
defaultHeaders: {
|
|
2097
|
+
"x-project-id": options.projectId ?? ""
|
|
2098
|
+
}
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
function isGPT5ModelSelector(model) {
|
|
2102
|
+
if (!model) return false;
|
|
2103
|
+
return model.split(/[|,]/).map((candidate) => candidate.trim()).some((candidate) => candidate.startsWith("gpt-5") || candidate.startsWith("openai:gpt-5"));
|
|
2104
|
+
}
|
|
2105
|
+
function defaultModel() {
|
|
2106
|
+
return LLMASASERVICE_DEFAULT_MODEL;
|
|
2107
|
+
}
|
|
2108
|
+
function isRecord(value) {
|
|
2109
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2110
|
+
}
|
|
2111
|
+
function rawCustomerId(asset) {
|
|
2112
|
+
const customer = isRecord(asset.raw?.llmasaservice?.customer) ? asset.raw.llmasaservice.customer : void 0;
|
|
2113
|
+
return customer?.customer_id;
|
|
2114
|
+
}
|
|
2115
|
+
function isGatewayRenderValidation(runtime) {
|
|
2116
|
+
return runtime?.runtime !== void 0;
|
|
2117
|
+
}
|
|
2118
|
+
var llmasaserviceAdapter = withPromptInputSupport({
|
|
2119
|
+
name: "llmasaservice",
|
|
2120
|
+
validate(asset, runtime) {
|
|
2121
|
+
const resolvedAsset = resolveAssetForProvider(asset, runtime);
|
|
2122
|
+
const validation = openaiAdapter.validate(
|
|
2123
|
+
{
|
|
2124
|
+
...resolvedAsset,
|
|
2125
|
+
model: resolvedAsset.model ?? defaultModel()
|
|
2126
|
+
},
|
|
2127
|
+
runtime
|
|
2128
|
+
);
|
|
2129
|
+
const warnings = validation.warnings.filter(
|
|
2130
|
+
(warning) => warning !== "OpenAI adapter requires a model to be specified."
|
|
2131
|
+
);
|
|
2132
|
+
const errors = [...validation.errors];
|
|
2133
|
+
const gatewayOptions = resolvedAsset.provider_options?.llmasaservice;
|
|
2134
|
+
const missingProjectId = !gatewayOptions?.project_id;
|
|
2135
|
+
const missingCustomerId = !gatewayOptions?.customer?.customer_id && typeof rawCustomerId(resolvedAsset) !== "string";
|
|
2136
|
+
const validateRenderMetadata = isGatewayRenderValidation(runtime);
|
|
2137
|
+
if (missingProjectId && validateRenderMetadata) {
|
|
2138
|
+
errors.push(
|
|
2139
|
+
"LLMAsAService adapter requires provider_options.llmasaservice.project_id for x-project-id routing."
|
|
2140
|
+
);
|
|
2141
|
+
}
|
|
2142
|
+
if (missingCustomerId && validateRenderMetadata) {
|
|
2143
|
+
errors.push(
|
|
2144
|
+
"LLMAsAService adapter requires customer.customer_id in provider_options.llmasaservice.customer or raw.llmasaservice.customer."
|
|
2145
|
+
);
|
|
2146
|
+
}
|
|
2147
|
+
if ((missingProjectId || missingCustomerId) && !validateRenderMetadata) {
|
|
2148
|
+
warnings.push(
|
|
2149
|
+
"LLMAsAService project_id and customer.customer_id must be supplied before rendering, usually through runtime provider_options."
|
|
2150
|
+
);
|
|
2151
|
+
}
|
|
2152
|
+
return {
|
|
2153
|
+
valid: errors.length === 0,
|
|
2154
|
+
errors,
|
|
2155
|
+
warnings
|
|
2156
|
+
};
|
|
2157
|
+
},
|
|
2158
|
+
render(asset, runtime) {
|
|
2159
|
+
const resolvedAsset = resolveAssetForProvider(asset, runtime);
|
|
2160
|
+
const options = resolvedAsset.provider_options?.llmasaservice;
|
|
2161
|
+
const model = resolvedAsset.model ?? defaultModel();
|
|
2162
|
+
const result = openaiAdapter.render(
|
|
2163
|
+
{ ...resolvedAsset, model, raw: void 0 },
|
|
2164
|
+
{
|
|
2165
|
+
variables: runtime.variables,
|
|
2166
|
+
history: runtime.history,
|
|
2167
|
+
onHistoryCompaction: runtime.onHistoryCompaction,
|
|
2168
|
+
toolRegistry: runtime.toolRegistry,
|
|
2169
|
+
strict: runtime.strict
|
|
2170
|
+
}
|
|
2171
|
+
);
|
|
2172
|
+
let body = { ...result.body };
|
|
2173
|
+
if (isGPT5ModelSelector(model) && body.max_tokens !== void 0 && body.max_completion_tokens === void 0) {
|
|
2174
|
+
body.max_completion_tokens = body.max_tokens;
|
|
2175
|
+
delete body.max_tokens;
|
|
2176
|
+
}
|
|
2177
|
+
if (options?.customer !== void 0) body.customer = options.customer;
|
|
2178
|
+
if (options?.conversationId !== void 0) body.conversationId = options.conversationId;
|
|
2179
|
+
if (options?.conversationTitle !== void 0) body.conversationTitle = options.conversationTitle;
|
|
2180
|
+
if (options?.projectId !== void 0) body.projectId = options.projectId;
|
|
2181
|
+
body = applyRawProviderBody(body, resolvedAsset, "llmasaservice");
|
|
2182
|
+
const projectId = options?.project_id ?? "";
|
|
2183
|
+
return {
|
|
2184
|
+
body,
|
|
2185
|
+
provider: "llmasaservice",
|
|
2186
|
+
model,
|
|
2187
|
+
baseURL: options?.base_url ?? LLMASASERVICE_BASE_URL,
|
|
2188
|
+
headers: {
|
|
2189
|
+
"x-project-id": projectId
|
|
2190
|
+
}
|
|
2191
|
+
};
|
|
2192
|
+
}
|
|
2193
|
+
});
|
|
2194
|
+
|
|
1727
2195
|
// src/providers/index.ts
|
|
1728
2196
|
var adapters = {
|
|
1729
2197
|
openai: openaiAdapter,
|
|
@@ -1731,7 +2199,8 @@ var adapters = {
|
|
|
1731
2199
|
anthropic: anthropicAdapter,
|
|
1732
2200
|
google: geminiAdapter,
|
|
1733
2201
|
gemini: geminiAdapter,
|
|
1734
|
-
openrouter: openrouterAdapter
|
|
2202
|
+
openrouter: openrouterAdapter,
|
|
2203
|
+
llmasaservice: llmasaserviceAdapter
|
|
1735
2204
|
};
|
|
1736
2205
|
function getAdapter(provider) {
|
|
1737
2206
|
const adapter = adapters[provider];
|
|
@@ -1787,6 +2256,18 @@ var KNOWN_FRONT_MATTER_KEYS = /* @__PURE__ */ new Set([
|
|
|
1787
2256
|
"provider_options",
|
|
1788
2257
|
"raw"
|
|
1789
2258
|
]);
|
|
2259
|
+
function collectSchemaKeywords(value, acc) {
|
|
2260
|
+
if (!value || typeof value !== "object") return;
|
|
2261
|
+
if (Array.isArray(value)) {
|
|
2262
|
+
for (const item of value) collectSchemaKeywords(item, acc);
|
|
2263
|
+
return;
|
|
2264
|
+
}
|
|
2265
|
+
const record = value;
|
|
2266
|
+
for (const [key, child] of Object.entries(record)) {
|
|
2267
|
+
acc.add(key);
|
|
2268
|
+
collectSchemaKeywords(child, acc);
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
1790
2271
|
var RISKY_UNBOUNDED_INPUT_NAMES = [
|
|
1791
2272
|
"message",
|
|
1792
2273
|
"prompt",
|
|
@@ -1838,7 +2319,9 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
1838
2319
|
}
|
|
1839
2320
|
}
|
|
1840
2321
|
}
|
|
1841
|
-
const
|
|
2322
|
+
const contextInputs = getContextInputs(asset);
|
|
2323
|
+
const declaredInputs = new Set(contextInputs.map((input) => input.name));
|
|
2324
|
+
const declaredInputsByName = new Map(contextInputs.map((input) => [input.name, input]));
|
|
1842
2325
|
const usedVars = /* @__PURE__ */ new Set();
|
|
1843
2326
|
if (asset.sections?.system_instructions) {
|
|
1844
2327
|
for (const v of extractVariables(asset.sections.system_instructions)) {
|
|
@@ -1860,7 +2343,8 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
1860
2343
|
}
|
|
1861
2344
|
}
|
|
1862
2345
|
for (const v of declaredInputs) {
|
|
1863
|
-
|
|
2346
|
+
const input = declaredInputsByName.get(v);
|
|
2347
|
+
if (!usedVars.has(v) && input?.optional !== true && areContextInputWarningsEnabled(input ?? {})) {
|
|
1864
2348
|
warnings.push({
|
|
1865
2349
|
code: "POK012",
|
|
1866
2350
|
message: `Variable "${v}" is declared in context.inputs but never used`,
|
|
@@ -1876,9 +2360,10 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
1876
2360
|
suggestion: "Declare context.inputs to enable input policy validation."
|
|
1877
2361
|
});
|
|
1878
2362
|
}
|
|
1879
|
-
for (const input of
|
|
2363
|
+
for (const input of contextInputs) {
|
|
1880
2364
|
const lowerName = input.name.toLowerCase();
|
|
1881
|
-
|
|
2365
|
+
const inputWarningsEnabled = areContextInputWarningsEnabled(input);
|
|
2366
|
+
if (inputWarningsEnabled && input.max_size === void 0 && RISKY_UNBOUNDED_INPUT_NAMES.some((needle) => lowerName.includes(needle))) {
|
|
1882
2367
|
warnings.push({
|
|
1883
2368
|
code: "POK040",
|
|
1884
2369
|
message: `Context input "${input.name}" has no max_size and appears unbounded.`,
|
|
@@ -1886,7 +2371,7 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
1886
2371
|
suggestion: "Add max_size to constrain prompt payload growth."
|
|
1887
2372
|
});
|
|
1888
2373
|
}
|
|
1889
|
-
if (input.allow_regex === void 0 && input.deny_regex === void 0 && input.non_empty === void 0 && input.reject_secrets === void 0) {
|
|
2374
|
+
if (inputWarningsEnabled && input.optional !== true && input.allow_regex === void 0 && input.deny_regex === void 0 && input.non_empty === void 0 && input.reject_secrets === void 0) {
|
|
1890
2375
|
warnings.push({
|
|
1891
2376
|
code: "POK041",
|
|
1892
2377
|
message: `Context input "${input.name}" has no input hardening validators.`,
|
|
@@ -1894,7 +2379,7 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
1894
2379
|
suggestion: "Consider non_empty/reject_secrets and allow/deny regex validators."
|
|
1895
2380
|
});
|
|
1896
2381
|
}
|
|
1897
|
-
if (input.trim !== void 0 && input.trim !== false && input.max_size === void 0) {
|
|
2382
|
+
if (inputWarningsEnabled && input.trim !== void 0 && input.trim !== false && input.max_size === void 0) {
|
|
1898
2383
|
warnings.push({
|
|
1899
2384
|
code: "POK014",
|
|
1900
2385
|
message: `Context input "${input.name}" sets trim but has no max_size; trim-to-budget will be skipped.`,
|
|
@@ -1921,6 +2406,30 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
1921
2406
|
}
|
|
1922
2407
|
}
|
|
1923
2408
|
}
|
|
2409
|
+
if (asset.response?.schema && asset.provider) {
|
|
2410
|
+
const keywords = /* @__PURE__ */ new Set();
|
|
2411
|
+
collectSchemaKeywords(asset.response.schema, keywords);
|
|
2412
|
+
const openAIUnsupported = ["patternProperties", "unevaluatedProperties", "$dynamicRef"];
|
|
2413
|
+
const geminiUnsupported = ["patternProperties", "$dynamicRef", "dependentSchemas"];
|
|
2414
|
+
const anthropicCaution = ["if", "then", "else"];
|
|
2415
|
+
const checks = [
|
|
2416
|
+
{ provider: ["openai", "openai-responses", "openrouter", "llmasaservice"], unsupported: openAIUnsupported, code: "POK052" },
|
|
2417
|
+
{ provider: ["gemini", "google"], unsupported: geminiUnsupported, code: "POK053" },
|
|
2418
|
+
{ provider: ["anthropic"], unsupported: anthropicCaution, code: "POK054" }
|
|
2419
|
+
];
|
|
2420
|
+
for (const check of checks) {
|
|
2421
|
+
if (!check.provider.includes(asset.provider)) continue;
|
|
2422
|
+
const hits = check.unsupported.filter((k) => keywords.has(k));
|
|
2423
|
+
if (hits.length > 0) {
|
|
2424
|
+
warnings.push({
|
|
2425
|
+
code: check.code,
|
|
2426
|
+
message: `response.schema includes provider-sensitive JSON Schema keywords for "${asset.provider}": ${hits.join(", ")}`,
|
|
2427
|
+
filePath,
|
|
2428
|
+
suggestion: "Validate schema compatibility with your provider docs or simplify the schema dialect."
|
|
2429
|
+
});
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
1924
2433
|
if (asset.provider) {
|
|
1925
2434
|
let providerCache;
|
|
1926
2435
|
let cacheSuggestionField;
|
|
@@ -1967,7 +2476,7 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
1967
2476
|
});
|
|
1968
2477
|
}
|
|
1969
2478
|
for (const [envName, overrides] of Object.entries(asset.environments ?? {})) {
|
|
1970
|
-
if (asset.cache && (!
|
|
2479
|
+
if (asset.cache && (!isRecord2(overrides) || !overrides.cache)) {
|
|
1971
2480
|
warnings.push({
|
|
1972
2481
|
code: "POK045",
|
|
1973
2482
|
message: `Environment "${envName}" does not override cache while prompt-level cache is defined.`,
|
|
@@ -1977,7 +2486,7 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
1977
2486
|
}
|
|
1978
2487
|
}
|
|
1979
2488
|
for (const [tierName, overrides] of Object.entries(asset.tiers ?? {})) {
|
|
1980
|
-
if (asset.cache && (!
|
|
2489
|
+
if (asset.cache && (!isRecord2(overrides) || !overrides.cache)) {
|
|
1981
2490
|
warnings.push({
|
|
1982
2491
|
code: "POK045",
|
|
1983
2492
|
message: `Tier "${tierName}" does not override cache while prompt-level cache is defined.`,
|
|
@@ -1987,7 +2496,7 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
1987
2496
|
}
|
|
1988
2497
|
}
|
|
1989
2498
|
for (const tool of asset.tools ?? []) {
|
|
1990
|
-
if (
|
|
2499
|
+
if (isRecord2(tool)) {
|
|
1991
2500
|
if (!tool.description) {
|
|
1992
2501
|
warnings.push({
|
|
1993
2502
|
code: "POK047",
|
|
@@ -2042,7 +2551,7 @@ function findClosestMatch(input, candidates) {
|
|
|
2042
2551
|
}
|
|
2043
2552
|
return best;
|
|
2044
2553
|
}
|
|
2045
|
-
function
|
|
2554
|
+
function isRecord2(value) {
|
|
2046
2555
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2047
2556
|
}
|
|
2048
2557
|
|
|
@@ -2321,7 +2830,7 @@ function applyUsageTapEntitlements(request, begin, options = {}) {
|
|
|
2321
2830
|
if (!isObject2(nextRequest.body)) {
|
|
2322
2831
|
return nextRequest;
|
|
2323
2832
|
}
|
|
2324
|
-
if (nextRequest.provider === "openai" || nextRequest.provider === "openrouter") {
|
|
2833
|
+
if (nextRequest.provider === "openai" || nextRequest.provider === "openrouter" || nextRequest.provider === "llmasaservice") {
|
|
2325
2834
|
capOpenAIReasoning(nextRequest.body, allowed);
|
|
2326
2835
|
if (isRecordArray(nextRequest.body.tools)) {
|
|
2327
2836
|
nextRequest.body.tools = filterOpenAITools(nextRequest.body.tools, allowed, options);
|
|
@@ -2410,6 +2919,9 @@ function runOpenAIWithUsageTap(client, options) {
|
|
|
2410
2919
|
function runOpenRouterWithUsageTap(client, options) {
|
|
2411
2920
|
return runProviderWithUsageTap(client, options, extractOpenAIUsage);
|
|
2412
2921
|
}
|
|
2922
|
+
function runLLMAsAServiceWithUsageTap(client, options) {
|
|
2923
|
+
return runProviderWithUsageTap(client, options, extractOpenAIUsage);
|
|
2924
|
+
}
|
|
2413
2925
|
function runAnthropicWithUsageTap(client, options) {
|
|
2414
2926
|
return runProviderWithUsageTap(client, options, extractAnthropicUsage);
|
|
2415
2927
|
}
|
|
@@ -2513,7 +3025,11 @@ var PromptOpsKit = class {
|
|
|
2513
3025
|
}
|
|
2514
3026
|
const request = adapter.render(resolved, {
|
|
2515
3027
|
variables: sanitization.variables,
|
|
2516
|
-
history:
|
|
3028
|
+
history: compactHistoryForPrompt(resolved, {
|
|
3029
|
+
history: options.history,
|
|
3030
|
+
onHistoryCompaction: options.onHistoryCompaction
|
|
3031
|
+
}),
|
|
3032
|
+
onHistoryCompaction: options.onHistoryCompaction,
|
|
2517
3033
|
toolRegistry: options.toolRegistry,
|
|
2518
3034
|
strict: options.strict,
|
|
2519
3035
|
openaiResponses: options.openaiResponses
|
|
@@ -2528,7 +3044,7 @@ var PromptOpsKit = class {
|
|
|
2528
3044
|
* Validate a prompt file.
|
|
2529
3045
|
*/
|
|
2530
3046
|
async validatePrompt(promptPath) {
|
|
2531
|
-
const sourceFile = (0,
|
|
3047
|
+
const sourceFile = (0, import_node_path5.resolve)(this.config.sourceDir, promptPath + ".md");
|
|
2532
3048
|
try {
|
|
2533
3049
|
const asset = await this.loadPrompt(promptPath);
|
|
2534
3050
|
return validateAssetWithIncludes(asset, sourceFile);
|
|
@@ -2578,6 +3094,10 @@ async function renderPrompt(options) {
|
|
|
2578
3094
|
}
|
|
2579
3095
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2580
3096
|
0 && (module.exports = {
|
|
3097
|
+
LLMASASERVICE_BASE_URL,
|
|
3098
|
+
LLMASASERVICE_DEFAULT_MODEL,
|
|
3099
|
+
LLMASASERVICE_RESPONSE_HEADER_NAMES,
|
|
3100
|
+
LLMASASERVICE_SDK_PLACEHOLDER_API_KEY,
|
|
2581
3101
|
PromptAssetOverridesSchema,
|
|
2582
3102
|
PromptAssetSchema,
|
|
2583
3103
|
PromptOpsKit,
|
|
@@ -2585,6 +3105,7 @@ async function renderPrompt(options) {
|
|
|
2585
3105
|
applyOverrides,
|
|
2586
3106
|
applyUsageTapEntitlements,
|
|
2587
3107
|
beginUsageTapCall,
|
|
3108
|
+
createLLMAsAServiceOpenAIConfig,
|
|
2588
3109
|
createPromptOpsKit,
|
|
2589
3110
|
createUsageTapClient,
|
|
2590
3111
|
defaultUsageTapErrorMapper,
|
|
@@ -2597,6 +3118,7 @@ async function renderPrompt(options) {
|
|
|
2597
3118
|
geminiAdapter,
|
|
2598
3119
|
getAdapter,
|
|
2599
3120
|
interpolate,
|
|
3121
|
+
llmasaserviceAdapter,
|
|
2600
3122
|
loadPromptFile,
|
|
2601
3123
|
openaiAdapter,
|
|
2602
3124
|
openaiResponsesAdapter,
|
|
@@ -2606,6 +3128,7 @@ async function renderPrompt(options) {
|
|
|
2606
3128
|
resolveIncludes,
|
|
2607
3129
|
runAnthropicWithUsageTap,
|
|
2608
3130
|
runGeminiWithUsageTap,
|
|
3131
|
+
runLLMAsAServiceWithUsageTap,
|
|
2609
3132
|
runOpenAIWithUsageTap,
|
|
2610
3133
|
runOpenRouterWithUsageTap,
|
|
2611
3134
|
validateAsset,
|