promptopskit 0.0.1 → 0.0.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/LICENSE +211 -211
- package/README.md +335 -309
- package/dist/{chunk-FSOJVXC4.js → chunk-5BI5FP5L.js} +2 -2
- package/dist/chunk-5BI5FP5L.js.map +1 -0
- package/dist/{chunk-HEFOFQ2K.js → chunk-6KGBPHSY.js} +1 -1
- package/dist/chunk-6KGBPHSY.js.map +1 -0
- package/dist/{chunk-X64JII57.js → chunk-NIZENC7D.js} +2 -2
- package/dist/chunk-NIZENC7D.js.map +1 -0
- package/dist/{chunk-YCRWYE6N.js → chunk-PU3UPUND.js} +2 -2
- package/dist/chunk-PU3UPUND.js.map +1 -0
- package/dist/{chunk-V375NQ6C.js → chunk-UYTUGV7Z.js} +2 -2
- package/dist/chunk-UYTUGV7Z.js.map +1 -0
- package/dist/{chunk-B5UFGNDV.js → chunk-VYVEVJC3.js} +2 -2
- package/dist/chunk-VYVEVJC3.js.map +1 -0
- package/dist/cli/index.js +452 -25
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +963 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +184 -0
- package/dist/index.d.ts +10 -5
- package/dist/index.js +32 -7
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic.cjs +151 -0
- package/dist/providers/anthropic.cjs.map +1 -0
- package/dist/providers/anthropic.d.cts +11 -0
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +2 -2
- package/dist/providers/gemini.cjs +155 -0
- package/dist/providers/gemini.cjs.map +1 -0
- package/dist/providers/gemini.d.cts +11 -0
- package/dist/providers/gemini.d.ts +2 -2
- package/dist/providers/gemini.js +2 -2
- package/dist/providers/openai.cjs +146 -0
- package/dist/providers/openai.cjs.map +1 -0
- package/dist/providers/openai.d.cts +11 -0
- package/dist/providers/openai.d.ts +2 -2
- package/dist/providers/openai.js +2 -2
- package/dist/providers/openrouter.cjs +161 -0
- package/dist/providers/openrouter.cjs.map +1 -0
- package/dist/providers/openrouter.d.cts +13 -0
- package/dist/providers/openrouter.d.ts +2 -2
- package/dist/providers/openrouter.js +3 -3
- package/dist/{schema-DHRI5Mzl.d.ts → schema-C6smABrt.d.cts} +3 -3
- package/dist/schema-C6smABrt.d.ts +695 -0
- package/dist/testing.cjs +228 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +17 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/{types-D9hquVja.d.ts → types-D7lW5IYT.d.ts} +1 -1
- package/dist/types-S_c-ZEfK.d.cts +40 -0
- package/package.json +116 -79
- package/dist/chunk-B5UFGNDV.js.map +0 -1
- package/dist/chunk-FSOJVXC4.js.map +0 -1
- package/dist/chunk-HEFOFQ2K.js.map +0 -1
- package/dist/chunk-V375NQ6C.js.map +0 -1
- package/dist/chunk-X64JII57.js.map +0 -1
- package/dist/chunk-YCRWYE6N.js.map +0 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,963 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
PromptAssetOverridesSchema: () => PromptAssetOverridesSchema,
|
|
34
|
+
PromptAssetSchema: () => PromptAssetSchema,
|
|
35
|
+
PromptOpsKit: () => PromptOpsKit,
|
|
36
|
+
anthropicAdapter: () => anthropicAdapter,
|
|
37
|
+
applyOverrides: () => applyOverrides,
|
|
38
|
+
createPromptOpsKit: () => createPromptOpsKit,
|
|
39
|
+
extractSections: () => extractSections,
|
|
40
|
+
extractVariables: () => extractVariables,
|
|
41
|
+
geminiAdapter: () => geminiAdapter,
|
|
42
|
+
getAdapter: () => getAdapter,
|
|
43
|
+
interpolate: () => interpolate,
|
|
44
|
+
loadPromptFile: () => loadPromptFile,
|
|
45
|
+
openaiAdapter: () => openaiAdapter,
|
|
46
|
+
openrouterAdapter: () => openrouterAdapter,
|
|
47
|
+
parsePrompt: () => parsePrompt,
|
|
48
|
+
renderPrompt: () => renderPrompt,
|
|
49
|
+
resolveIncludes: () => resolveIncludes,
|
|
50
|
+
validateAsset: () => validateAsset,
|
|
51
|
+
validateAssetWithIncludes: () => validateAssetWithIncludes
|
|
52
|
+
});
|
|
53
|
+
module.exports = __toCommonJS(src_exports);
|
|
54
|
+
var import_promises3 = require("fs/promises");
|
|
55
|
+
var import_node_fs2 = require("fs");
|
|
56
|
+
var import_node_path2 = require("path");
|
|
57
|
+
|
|
58
|
+
// src/parser/parser.ts
|
|
59
|
+
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
60
|
+
|
|
61
|
+
// src/schema/schema.ts
|
|
62
|
+
var import_zod = require("zod");
|
|
63
|
+
var InlineToolDefSchema = import_zod.z.object({
|
|
64
|
+
name: import_zod.z.string(),
|
|
65
|
+
description: import_zod.z.string().optional(),
|
|
66
|
+
input_schema: import_zod.z.record(import_zod.z.unknown()).optional()
|
|
67
|
+
});
|
|
68
|
+
var ToolRefSchema = import_zod.z.union([import_zod.z.string(), InlineToolDefSchema]);
|
|
69
|
+
var MCPServerRefSchema = import_zod.z.union([
|
|
70
|
+
import_zod.z.string(),
|
|
71
|
+
import_zod.z.object({
|
|
72
|
+
name: import_zod.z.string(),
|
|
73
|
+
config: import_zod.z.record(import_zod.z.unknown()).optional()
|
|
74
|
+
})
|
|
75
|
+
]);
|
|
76
|
+
var ReasoningSchema = import_zod.z.object({
|
|
77
|
+
effort: import_zod.z.enum(["low", "medium", "high"]).optional(),
|
|
78
|
+
budget_tokens: import_zod.z.number().int().positive().optional()
|
|
79
|
+
});
|
|
80
|
+
var SamplingSchema = import_zod.z.object({
|
|
81
|
+
temperature: import_zod.z.number().min(0).max(2).optional(),
|
|
82
|
+
top_p: import_zod.z.number().min(0).max(1).optional(),
|
|
83
|
+
frequency_penalty: import_zod.z.number().optional(),
|
|
84
|
+
presence_penalty: import_zod.z.number().optional(),
|
|
85
|
+
stop: import_zod.z.array(import_zod.z.string()).optional(),
|
|
86
|
+
max_output_tokens: import_zod.z.number().int().positive().optional()
|
|
87
|
+
});
|
|
88
|
+
var ResponseSchema = import_zod.z.object({
|
|
89
|
+
format: import_zod.z.enum(["text", "json", "markdown"]).optional(),
|
|
90
|
+
stream: import_zod.z.boolean().optional()
|
|
91
|
+
});
|
|
92
|
+
var HistorySchema = import_zod.z.object({
|
|
93
|
+
max_items: import_zod.z.number().int().positive().optional()
|
|
94
|
+
});
|
|
95
|
+
var ContextSchema = import_zod.z.object({
|
|
96
|
+
inputs: import_zod.z.array(import_zod.z.string()).optional(),
|
|
97
|
+
history: HistorySchema.optional()
|
|
98
|
+
});
|
|
99
|
+
var MetadataSchema = import_zod.z.object({
|
|
100
|
+
owner: import_zod.z.string().optional(),
|
|
101
|
+
tags: import_zod.z.array(import_zod.z.string()).optional(),
|
|
102
|
+
review_required: import_zod.z.boolean().optional(),
|
|
103
|
+
stable: import_zod.z.boolean().optional()
|
|
104
|
+
});
|
|
105
|
+
var MCPSchema = import_zod.z.object({
|
|
106
|
+
servers: import_zod.z.array(MCPServerRefSchema).optional()
|
|
107
|
+
});
|
|
108
|
+
var PromptAssetOverridesSchema = import_zod.z.object({
|
|
109
|
+
model: import_zod.z.string().optional(),
|
|
110
|
+
fallback_models: import_zod.z.array(import_zod.z.string()).optional(),
|
|
111
|
+
reasoning: ReasoningSchema.optional(),
|
|
112
|
+
sampling: SamplingSchema.optional(),
|
|
113
|
+
response: ResponseSchema.optional(),
|
|
114
|
+
tools: import_zod.z.array(ToolRefSchema).optional()
|
|
115
|
+
});
|
|
116
|
+
var SourceSchema = import_zod.z.object({
|
|
117
|
+
file_path: import_zod.z.string().optional(),
|
|
118
|
+
checksum: import_zod.z.string().optional()
|
|
119
|
+
});
|
|
120
|
+
var SectionsSchema = import_zod.z.object({
|
|
121
|
+
system_instructions: import_zod.z.string().optional(),
|
|
122
|
+
prompt_template: import_zod.z.string().optional(),
|
|
123
|
+
notes: import_zod.z.string().optional()
|
|
124
|
+
});
|
|
125
|
+
var PromptAssetSchema = import_zod.z.object({
|
|
126
|
+
id: import_zod.z.string(),
|
|
127
|
+
schema_version: import_zod.z.number().int().positive().default(1),
|
|
128
|
+
description: import_zod.z.string().optional(),
|
|
129
|
+
provider: import_zod.z.enum(["openai", "anthropic", "google", "gemini", "openrouter", "any"]).optional(),
|
|
130
|
+
model: import_zod.z.string().optional(),
|
|
131
|
+
fallback_models: import_zod.z.array(import_zod.z.string()).optional(),
|
|
132
|
+
reasoning: ReasoningSchema.optional(),
|
|
133
|
+
sampling: SamplingSchema.optional(),
|
|
134
|
+
response: ResponseSchema.optional(),
|
|
135
|
+
tools: import_zod.z.array(ToolRefSchema).optional(),
|
|
136
|
+
mcp: MCPSchema.optional(),
|
|
137
|
+
context: ContextSchema.optional(),
|
|
138
|
+
includes: import_zod.z.array(import_zod.z.string()).optional(),
|
|
139
|
+
environments: import_zod.z.record(PromptAssetOverridesSchema).optional(),
|
|
140
|
+
tiers: import_zod.z.record(PromptAssetOverridesSchema).optional(),
|
|
141
|
+
metadata: MetadataSchema.optional(),
|
|
142
|
+
// Populated by parser, not authored in YAML
|
|
143
|
+
sections: SectionsSchema.optional(),
|
|
144
|
+
source: SourceSchema.optional()
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// src/parser/sections.ts
|
|
148
|
+
var SECTION_MAP = {
|
|
149
|
+
"system instructions": "system_instructions",
|
|
150
|
+
"prompt template": "prompt_template",
|
|
151
|
+
"notes": "notes"
|
|
152
|
+
};
|
|
153
|
+
function extractSections(body) {
|
|
154
|
+
const lines = body.split("\n");
|
|
155
|
+
const sections = {};
|
|
156
|
+
let currentKey = null;
|
|
157
|
+
let currentLines = [];
|
|
158
|
+
let foundAnyH1 = false;
|
|
159
|
+
for (const line of lines) {
|
|
160
|
+
const h1Match = line.match(/^#\s+(.+)$/);
|
|
161
|
+
if (h1Match) {
|
|
162
|
+
if (currentKey) {
|
|
163
|
+
sections[currentKey] = currentLines.join("\n").trim();
|
|
164
|
+
}
|
|
165
|
+
foundAnyH1 = true;
|
|
166
|
+
const heading = h1Match[1].trim().toLowerCase();
|
|
167
|
+
currentKey = SECTION_MAP[heading] ?? null;
|
|
168
|
+
currentLines = [];
|
|
169
|
+
} else {
|
|
170
|
+
currentLines.push(line);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (currentKey) {
|
|
174
|
+
sections[currentKey] = currentLines.join("\n").trim();
|
|
175
|
+
}
|
|
176
|
+
if (!foundAnyH1) {
|
|
177
|
+
const trimmed = body.trim();
|
|
178
|
+
if (trimmed) {
|
|
179
|
+
sections.prompt_template = trimmed;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return sections;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// src/parser/parser.ts
|
|
186
|
+
function parsePrompt(content, filePath) {
|
|
187
|
+
const { data: frontMatter, content: body } = (0, import_gray_matter.default)(content);
|
|
188
|
+
const sections = extractSections(body);
|
|
189
|
+
const raw = {
|
|
190
|
+
...frontMatter,
|
|
191
|
+
sections,
|
|
192
|
+
source: filePath ? { file_path: filePath } : void 0
|
|
193
|
+
};
|
|
194
|
+
const asset = PromptAssetSchema.parse(raw);
|
|
195
|
+
return {
|
|
196
|
+
asset,
|
|
197
|
+
raw: {
|
|
198
|
+
frontMatter,
|
|
199
|
+
body
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// src/parser/loader.ts
|
|
205
|
+
var import_promises = require("fs/promises");
|
|
206
|
+
async function loadPromptFile(filePath) {
|
|
207
|
+
const content = await (0, import_promises.readFile)(filePath, "utf-8");
|
|
208
|
+
return parsePrompt(content, filePath);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/composition/resolve-includes.ts
|
|
212
|
+
var import_promises2 = require("fs/promises");
|
|
213
|
+
var import_node_path = require("path");
|
|
214
|
+
async function resolveIncludes(asset, basePath, visited = /* @__PURE__ */ new Set()) {
|
|
215
|
+
if (!asset.includes || asset.includes.length === 0) {
|
|
216
|
+
return asset;
|
|
217
|
+
}
|
|
218
|
+
const baseDir = (0, import_node_path.dirname)(basePath);
|
|
219
|
+
const resolvedPath = (0, import_node_path.resolve)(basePath);
|
|
220
|
+
if (visited.has(resolvedPath)) {
|
|
221
|
+
throw new Error(`Circular include detected: ${resolvedPath}`);
|
|
222
|
+
}
|
|
223
|
+
visited.add(resolvedPath);
|
|
224
|
+
let mergedSystemInstructions = "";
|
|
225
|
+
for (const includePath of asset.includes) {
|
|
226
|
+
const fullPath = (0, import_node_path.resolve)(baseDir, includePath);
|
|
227
|
+
if (visited.has(fullPath)) {
|
|
228
|
+
throw new Error(`Circular include detected: ${fullPath} (included from ${basePath})`);
|
|
229
|
+
}
|
|
230
|
+
const content = await (0, import_promises2.readFile)(fullPath, "utf-8");
|
|
231
|
+
const { asset: includedAsset } = parsePrompt(content, fullPath);
|
|
232
|
+
const resolved = await resolveIncludes(includedAsset, fullPath, new Set(visited));
|
|
233
|
+
if (resolved.sections?.system_instructions) {
|
|
234
|
+
mergedSystemInstructions += resolved.sections.system_instructions + "\n\n";
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const localSystem = asset.sections?.system_instructions ?? "";
|
|
238
|
+
const combinedSystem = (mergedSystemInstructions + localSystem).trim() || void 0;
|
|
239
|
+
return {
|
|
240
|
+
...asset,
|
|
241
|
+
sections: {
|
|
242
|
+
...asset.sections,
|
|
243
|
+
system_instructions: combinedSystem
|
|
244
|
+
},
|
|
245
|
+
// Drop includes from the resolved asset — they've been inlined
|
|
246
|
+
includes: void 0
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/overrides/apply-overrides.ts
|
|
251
|
+
function applyOverrides(asset, options = {}) {
|
|
252
|
+
let result = { ...asset };
|
|
253
|
+
if (options.environment && result.environments?.[options.environment]) {
|
|
254
|
+
result = mergeOverride(result, result.environments[options.environment]);
|
|
255
|
+
}
|
|
256
|
+
if (options.tier && result.tiers?.[options.tier]) {
|
|
257
|
+
result = mergeOverride(result, result.tiers[options.tier]);
|
|
258
|
+
}
|
|
259
|
+
if (options.runtime) {
|
|
260
|
+
result = mergeOverride(result, options.runtime);
|
|
261
|
+
}
|
|
262
|
+
return result;
|
|
263
|
+
}
|
|
264
|
+
function mergeOverride(base, override) {
|
|
265
|
+
const result = { ...base };
|
|
266
|
+
if (override.model !== void 0) result.model = override.model;
|
|
267
|
+
if (override.fallback_models !== void 0) result.fallback_models = override.fallback_models;
|
|
268
|
+
if (override.tools !== void 0) result.tools = override.tools;
|
|
269
|
+
if (override.reasoning !== void 0) {
|
|
270
|
+
result.reasoning = { ...result.reasoning, ...override.reasoning };
|
|
271
|
+
}
|
|
272
|
+
if (override.sampling !== void 0) {
|
|
273
|
+
result.sampling = { ...result.sampling, ...override.sampling };
|
|
274
|
+
}
|
|
275
|
+
if (override.response !== void 0) {
|
|
276
|
+
result.response = { ...result.response, ...override.response };
|
|
277
|
+
}
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// src/renderer/interpolate.ts
|
|
282
|
+
var VARIABLE_RE = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
|
|
283
|
+
var ESCAPED_OPEN = /\\\{\\\{/g;
|
|
284
|
+
var ESCAPE_PLACEHOLDER = "\0ESCAPED_OPEN\0";
|
|
285
|
+
function interpolate(template, variables, options = {}) {
|
|
286
|
+
const { strict = false } = options;
|
|
287
|
+
let result = template.replace(ESCAPED_OPEN, ESCAPE_PLACEHOLDER);
|
|
288
|
+
result = result.replace(VARIABLE_RE, (match, name) => {
|
|
289
|
+
if (name in variables) {
|
|
290
|
+
return variables[name];
|
|
291
|
+
}
|
|
292
|
+
if (strict) {
|
|
293
|
+
throw new Error(`Missing required variable: "${name}"`);
|
|
294
|
+
}
|
|
295
|
+
return match;
|
|
296
|
+
});
|
|
297
|
+
result = result.replaceAll(ESCAPE_PLACEHOLDER, "{{");
|
|
298
|
+
return result;
|
|
299
|
+
}
|
|
300
|
+
function extractVariables(template) {
|
|
301
|
+
const vars = /* @__PURE__ */ new Set();
|
|
302
|
+
let match;
|
|
303
|
+
const re = new RegExp(VARIABLE_RE.source, "g");
|
|
304
|
+
while ((match = re.exec(template)) !== null) {
|
|
305
|
+
vars.add(match[1]);
|
|
306
|
+
}
|
|
307
|
+
return [...vars];
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/renderer/renderer.ts
|
|
311
|
+
function renderSections(asset, options = {}) {
|
|
312
|
+
const { variables = {}, strict = false } = options;
|
|
313
|
+
const result = {};
|
|
314
|
+
if (asset.sections.system_instructions) {
|
|
315
|
+
result.system_instructions = interpolate(
|
|
316
|
+
asset.sections.system_instructions,
|
|
317
|
+
variables,
|
|
318
|
+
{ strict }
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
if (asset.sections.prompt_template) {
|
|
322
|
+
result.prompt_template = interpolate(
|
|
323
|
+
asset.sections.prompt_template,
|
|
324
|
+
variables,
|
|
325
|
+
{ strict }
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
return result;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// src/providers/openai.ts
|
|
332
|
+
var openaiAdapter = {
|
|
333
|
+
name: "openai",
|
|
334
|
+
validate(asset) {
|
|
335
|
+
const errors = [];
|
|
336
|
+
const warnings = [];
|
|
337
|
+
if (!asset.model) {
|
|
338
|
+
errors.push("OpenAI adapter requires a model to be specified.");
|
|
339
|
+
}
|
|
340
|
+
if (asset.reasoning?.budget_tokens !== void 0) {
|
|
341
|
+
warnings.push("OpenAI uses reasoning_effort, not budget_tokens. budget_tokens will be ignored.");
|
|
342
|
+
}
|
|
343
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
344
|
+
},
|
|
345
|
+
render(asset, runtime) {
|
|
346
|
+
const sections = renderSections(asset, {
|
|
347
|
+
variables: runtime.variables,
|
|
348
|
+
strict: runtime.strict
|
|
349
|
+
});
|
|
350
|
+
const messages = [];
|
|
351
|
+
if (sections.system_instructions) {
|
|
352
|
+
messages.push({ role: "system", content: sections.system_instructions });
|
|
353
|
+
}
|
|
354
|
+
if (runtime.history) {
|
|
355
|
+
for (const msg of runtime.history) {
|
|
356
|
+
messages.push({ role: msg.role, content: msg.content });
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (sections.prompt_template) {
|
|
360
|
+
messages.push({ role: "user", content: sections.prompt_template });
|
|
361
|
+
}
|
|
362
|
+
const body = {
|
|
363
|
+
model: asset.model,
|
|
364
|
+
messages
|
|
365
|
+
};
|
|
366
|
+
if (asset.sampling?.temperature !== void 0) body.temperature = asset.sampling.temperature;
|
|
367
|
+
if (asset.sampling?.top_p !== void 0) body.top_p = asset.sampling.top_p;
|
|
368
|
+
if (asset.sampling?.frequency_penalty !== void 0) body.frequency_penalty = asset.sampling.frequency_penalty;
|
|
369
|
+
if (asset.sampling?.presence_penalty !== void 0) body.presence_penalty = asset.sampling.presence_penalty;
|
|
370
|
+
if (asset.sampling?.stop !== void 0) body.stop = asset.sampling.stop;
|
|
371
|
+
if (asset.sampling?.max_output_tokens !== void 0) body.max_tokens = asset.sampling.max_output_tokens;
|
|
372
|
+
if (asset.reasoning?.effort) {
|
|
373
|
+
body.reasoning_effort = asset.reasoning.effort;
|
|
374
|
+
}
|
|
375
|
+
if (asset.response?.format === "json") {
|
|
376
|
+
body.response_format = { type: "json_object" };
|
|
377
|
+
}
|
|
378
|
+
if (asset.response?.stream !== void 0) {
|
|
379
|
+
body.stream = asset.response.stream;
|
|
380
|
+
}
|
|
381
|
+
if (asset.tools && asset.tools.length > 0) {
|
|
382
|
+
body.tools = asset.tools.map((tool) => {
|
|
383
|
+
if (typeof tool === "string") {
|
|
384
|
+
const def = runtime.toolRegistry?.[tool];
|
|
385
|
+
if (def) return def;
|
|
386
|
+
return { type: "function", function: { name: tool } };
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
type: "function",
|
|
390
|
+
function: {
|
|
391
|
+
name: tool.name,
|
|
392
|
+
description: tool.description,
|
|
393
|
+
parameters: tool.input_schema
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
return {
|
|
399
|
+
body,
|
|
400
|
+
provider: "openai",
|
|
401
|
+
model: asset.model ?? "unknown"
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
// src/providers/anthropic.ts
|
|
407
|
+
var anthropicAdapter = {
|
|
408
|
+
name: "anthropic",
|
|
409
|
+
validate(asset) {
|
|
410
|
+
const errors = [];
|
|
411
|
+
const warnings = [];
|
|
412
|
+
if (!asset.model) {
|
|
413
|
+
errors.push("Anthropic adapter requires a model to be specified.");
|
|
414
|
+
}
|
|
415
|
+
if (asset.sampling?.frequency_penalty !== void 0) {
|
|
416
|
+
warnings.push("Anthropic does not support frequency_penalty. It will be ignored.");
|
|
417
|
+
}
|
|
418
|
+
if (asset.sampling?.presence_penalty !== void 0) {
|
|
419
|
+
warnings.push("Anthropic does not support presence_penalty. It will be ignored.");
|
|
420
|
+
}
|
|
421
|
+
if (asset.reasoning?.effort !== void 0) {
|
|
422
|
+
warnings.push("Anthropic uses budget_tokens for thinking, not effort. effort will be mapped approximately.");
|
|
423
|
+
}
|
|
424
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
425
|
+
},
|
|
426
|
+
render(asset, runtime) {
|
|
427
|
+
const sections = renderSections(asset, {
|
|
428
|
+
variables: runtime.variables,
|
|
429
|
+
strict: runtime.strict
|
|
430
|
+
});
|
|
431
|
+
const messages = [];
|
|
432
|
+
if (runtime.history) {
|
|
433
|
+
for (const msg of runtime.history) {
|
|
434
|
+
messages.push({ role: msg.role, content: msg.content });
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
if (sections.prompt_template) {
|
|
438
|
+
messages.push({ role: "user", content: sections.prompt_template });
|
|
439
|
+
}
|
|
440
|
+
const body = {
|
|
441
|
+
model: asset.model,
|
|
442
|
+
messages
|
|
443
|
+
};
|
|
444
|
+
if (sections.system_instructions) {
|
|
445
|
+
body.system = sections.system_instructions;
|
|
446
|
+
}
|
|
447
|
+
if (asset.sampling?.temperature !== void 0) body.temperature = asset.sampling.temperature;
|
|
448
|
+
if (asset.sampling?.top_p !== void 0) body.top_p = asset.sampling.top_p;
|
|
449
|
+
if (asset.sampling?.stop !== void 0) body.stop_sequences = asset.sampling.stop;
|
|
450
|
+
if (asset.sampling?.max_output_tokens !== void 0) {
|
|
451
|
+
body.max_tokens = asset.sampling.max_output_tokens;
|
|
452
|
+
} else {
|
|
453
|
+
body.max_tokens = 4096;
|
|
454
|
+
}
|
|
455
|
+
if (asset.reasoning?.budget_tokens) {
|
|
456
|
+
body.thinking = {
|
|
457
|
+
type: "enabled",
|
|
458
|
+
budget_tokens: asset.reasoning.budget_tokens
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
if (asset.response?.stream !== void 0) {
|
|
462
|
+
body.stream = asset.response.stream;
|
|
463
|
+
}
|
|
464
|
+
if (asset.tools && asset.tools.length > 0) {
|
|
465
|
+
body.tools = asset.tools.map((tool) => {
|
|
466
|
+
if (typeof tool === "string") {
|
|
467
|
+
const def = runtime.toolRegistry?.[tool];
|
|
468
|
+
if (def) return def;
|
|
469
|
+
return { name: tool };
|
|
470
|
+
}
|
|
471
|
+
return {
|
|
472
|
+
name: tool.name,
|
|
473
|
+
description: tool.description,
|
|
474
|
+
input_schema: tool.input_schema ?? { type: "object", properties: {} }
|
|
475
|
+
};
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
return {
|
|
479
|
+
body,
|
|
480
|
+
provider: "anthropic",
|
|
481
|
+
model: asset.model ?? "unknown"
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
// src/providers/gemini.ts
|
|
487
|
+
var geminiAdapter = {
|
|
488
|
+
name: "gemini",
|
|
489
|
+
validate(asset) {
|
|
490
|
+
const errors = [];
|
|
491
|
+
const warnings = [];
|
|
492
|
+
if (!asset.model) {
|
|
493
|
+
errors.push("Gemini adapter requires a model to be specified.");
|
|
494
|
+
}
|
|
495
|
+
if (asset.sampling?.frequency_penalty !== void 0) {
|
|
496
|
+
warnings.push("Gemini does not support frequency_penalty. It will be ignored.");
|
|
497
|
+
}
|
|
498
|
+
if (asset.sampling?.presence_penalty !== void 0) {
|
|
499
|
+
warnings.push("Gemini does not support presence_penalty. It will be ignored.");
|
|
500
|
+
}
|
|
501
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
502
|
+
},
|
|
503
|
+
render(asset, runtime) {
|
|
504
|
+
const sections = renderSections(asset, {
|
|
505
|
+
variables: runtime.variables,
|
|
506
|
+
strict: runtime.strict
|
|
507
|
+
});
|
|
508
|
+
const contents = [];
|
|
509
|
+
if (runtime.history) {
|
|
510
|
+
for (const msg of runtime.history) {
|
|
511
|
+
contents.push({
|
|
512
|
+
role: msg.role === "assistant" ? "model" : "user",
|
|
513
|
+
parts: [{ text: msg.content }]
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (sections.prompt_template) {
|
|
518
|
+
contents.push({
|
|
519
|
+
role: "user",
|
|
520
|
+
parts: [{ text: sections.prompt_template }]
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
const body = {
|
|
524
|
+
contents
|
|
525
|
+
};
|
|
526
|
+
if (sections.system_instructions) {
|
|
527
|
+
body.systemInstruction = {
|
|
528
|
+
parts: [{ text: sections.system_instructions }]
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
const generationConfig = {};
|
|
532
|
+
if (asset.sampling?.temperature !== void 0) generationConfig.temperature = asset.sampling.temperature;
|
|
533
|
+
if (asset.sampling?.top_p !== void 0) generationConfig.topP = asset.sampling.top_p;
|
|
534
|
+
if (asset.sampling?.max_output_tokens !== void 0) generationConfig.maxOutputTokens = asset.sampling.max_output_tokens;
|
|
535
|
+
if (asset.sampling?.stop !== void 0) generationConfig.stopSequences = asset.sampling.stop;
|
|
536
|
+
if (asset.response?.format === "json") {
|
|
537
|
+
generationConfig.responseMimeType = "application/json";
|
|
538
|
+
}
|
|
539
|
+
if (asset.reasoning?.effort) {
|
|
540
|
+
body.thinkingConfig = {
|
|
541
|
+
thinkingBudget: asset.reasoning.effort === "high" ? 8192 : asset.reasoning.effort === "medium" ? 4096 : 1024
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
if (Object.keys(generationConfig).length > 0) {
|
|
545
|
+
body.generationConfig = generationConfig;
|
|
546
|
+
}
|
|
547
|
+
if (asset.tools && asset.tools.length > 0) {
|
|
548
|
+
const functionDeclarations = asset.tools.map((tool) => {
|
|
549
|
+
if (typeof tool === "string") {
|
|
550
|
+
const def = runtime.toolRegistry?.[tool];
|
|
551
|
+
if (def) return def;
|
|
552
|
+
return { name: tool };
|
|
553
|
+
}
|
|
554
|
+
return {
|
|
555
|
+
name: tool.name,
|
|
556
|
+
description: tool.description,
|
|
557
|
+
parameters: tool.input_schema
|
|
558
|
+
};
|
|
559
|
+
});
|
|
560
|
+
body.tools = [{ functionDeclarations }];
|
|
561
|
+
}
|
|
562
|
+
return {
|
|
563
|
+
body,
|
|
564
|
+
provider: "gemini",
|
|
565
|
+
model: asset.model ?? "unknown"
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
// src/providers/openrouter.ts
|
|
571
|
+
var openrouterAdapter = {
|
|
572
|
+
name: "openrouter",
|
|
573
|
+
validate(asset) {
|
|
574
|
+
return openaiAdapter.validate(asset);
|
|
575
|
+
},
|
|
576
|
+
render(asset, runtime) {
|
|
577
|
+
const result = openaiAdapter.render(asset, runtime);
|
|
578
|
+
return {
|
|
579
|
+
...result,
|
|
580
|
+
provider: "openrouter"
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
// src/providers/index.ts
|
|
586
|
+
var adapters = {
|
|
587
|
+
openai: openaiAdapter,
|
|
588
|
+
anthropic: anthropicAdapter,
|
|
589
|
+
google: geminiAdapter,
|
|
590
|
+
gemini: geminiAdapter,
|
|
591
|
+
openrouter: openrouterAdapter
|
|
592
|
+
};
|
|
593
|
+
function getAdapter(provider) {
|
|
594
|
+
const adapter = adapters[provider];
|
|
595
|
+
if (!adapter) {
|
|
596
|
+
throw new Error(
|
|
597
|
+
`Unknown provider: "${provider}". Supported: ${Object.keys(adapters).join(", ")}`
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
return adapter;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// src/validation/levenshtein.ts
|
|
604
|
+
function levenshtein(a, b) {
|
|
605
|
+
const m = a.length;
|
|
606
|
+
const n = b.length;
|
|
607
|
+
if (m === 0) return n;
|
|
608
|
+
if (n === 0) return m;
|
|
609
|
+
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
610
|
+
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
611
|
+
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
612
|
+
for (let i = 1; i <= m; i++) {
|
|
613
|
+
for (let j = 1; j <= n; j++) {
|
|
614
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
615
|
+
dp[i][j] = Math.min(
|
|
616
|
+
dp[i - 1][j] + 1,
|
|
617
|
+
dp[i][j - 1] + 1,
|
|
618
|
+
dp[i - 1][j - 1] + cost
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
return dp[m][n];
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// src/validation/validate.ts
|
|
626
|
+
var KNOWN_FRONT_MATTER_KEYS = /* @__PURE__ */ new Set([
|
|
627
|
+
"id",
|
|
628
|
+
"schema_version",
|
|
629
|
+
"description",
|
|
630
|
+
"provider",
|
|
631
|
+
"model",
|
|
632
|
+
"fallback_models",
|
|
633
|
+
"reasoning",
|
|
634
|
+
"sampling",
|
|
635
|
+
"response",
|
|
636
|
+
"tools",
|
|
637
|
+
"mcp",
|
|
638
|
+
"context",
|
|
639
|
+
"includes",
|
|
640
|
+
"environments",
|
|
641
|
+
"tiers",
|
|
642
|
+
"metadata"
|
|
643
|
+
]);
|
|
644
|
+
function validateAsset(asset, frontMatterKeys, filePath) {
|
|
645
|
+
const errors = [];
|
|
646
|
+
const warnings = [];
|
|
647
|
+
const result = PromptAssetSchema.safeParse(asset);
|
|
648
|
+
if (!result.success) {
|
|
649
|
+
for (const issue of result.error.issues) {
|
|
650
|
+
errors.push({
|
|
651
|
+
code: "POK001",
|
|
652
|
+
message: `Schema error at ${issue.path.join(".")}: ${issue.message}`,
|
|
653
|
+
filePath
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (!asset.id) {
|
|
658
|
+
errors.push({
|
|
659
|
+
code: "POK002",
|
|
660
|
+
message: 'Missing required field: "id"',
|
|
661
|
+
filePath
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
if (!asset.sections?.system_instructions && !asset.sections?.prompt_template) {
|
|
665
|
+
errors.push({
|
|
666
|
+
code: "POK003",
|
|
667
|
+
message: "Prompt must have at least one body section (System instructions or Prompt template)",
|
|
668
|
+
filePath
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
if (frontMatterKeys) {
|
|
672
|
+
for (const key of frontMatterKeys) {
|
|
673
|
+
if (!KNOWN_FRONT_MATTER_KEYS.has(key)) {
|
|
674
|
+
const suggestion = findClosestMatch(key, KNOWN_FRONT_MATTER_KEYS);
|
|
675
|
+
warnings.push({
|
|
676
|
+
code: "POK010",
|
|
677
|
+
message: `Unknown front matter field: "${key}"`,
|
|
678
|
+
filePath,
|
|
679
|
+
suggestion: suggestion ? `Did you mean "${suggestion}"?` : void 0
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
const declaredInputs = new Set(asset.context?.inputs ?? []);
|
|
685
|
+
const usedVars = /* @__PURE__ */ new Set();
|
|
686
|
+
if (asset.sections?.system_instructions) {
|
|
687
|
+
for (const v of extractVariables(asset.sections.system_instructions)) {
|
|
688
|
+
usedVars.add(v);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
if (asset.sections?.prompt_template) {
|
|
692
|
+
for (const v of extractVariables(asset.sections.prompt_template)) {
|
|
693
|
+
usedVars.add(v);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
for (const v of usedVars) {
|
|
697
|
+
if (declaredInputs.size > 0 && !declaredInputs.has(v)) {
|
|
698
|
+
warnings.push({
|
|
699
|
+
code: "POK011",
|
|
700
|
+
message: `Variable "{{ ${v} }}" is used but not declared in context.inputs`,
|
|
701
|
+
filePath
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
for (const v of declaredInputs) {
|
|
706
|
+
if (!usedVars.has(v)) {
|
|
707
|
+
warnings.push({
|
|
708
|
+
code: "POK012",
|
|
709
|
+
message: `Variable "${v}" is declared in context.inputs but never used`,
|
|
710
|
+
filePath
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return {
|
|
715
|
+
valid: errors.length === 0,
|
|
716
|
+
errors,
|
|
717
|
+
warnings
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
async function validateAssetWithIncludes(asset, filePath, frontMatterKeys) {
|
|
721
|
+
const result = validateAsset(asset, frontMatterKeys, filePath);
|
|
722
|
+
if (asset.includes && asset.includes.length > 0) {
|
|
723
|
+
try {
|
|
724
|
+
await resolveIncludes(asset, filePath);
|
|
725
|
+
} catch (err) {
|
|
726
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
727
|
+
const isCircular = message.includes("Circular include");
|
|
728
|
+
result.errors.push({
|
|
729
|
+
code: isCircular ? "POK021" : "POK020",
|
|
730
|
+
message: isCircular ? `Circular include detected: ${message}` : `Include resolution failed: ${message}`,
|
|
731
|
+
filePath
|
|
732
|
+
});
|
|
733
|
+
result.valid = false;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
return result;
|
|
737
|
+
}
|
|
738
|
+
function findClosestMatch(input, candidates) {
|
|
739
|
+
let best;
|
|
740
|
+
let bestDist = Infinity;
|
|
741
|
+
for (const candidate of candidates) {
|
|
742
|
+
const dist = levenshtein(input.toLowerCase(), candidate.toLowerCase());
|
|
743
|
+
if (dist < bestDist && dist <= 3) {
|
|
744
|
+
bestDist = dist;
|
|
745
|
+
best = candidate;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return best;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// src/cache.ts
|
|
752
|
+
var import_node_fs = require("fs");
|
|
753
|
+
var PromptCache = class {
|
|
754
|
+
cache = /* @__PURE__ */ new Map();
|
|
755
|
+
maxSize;
|
|
756
|
+
constructor(maxSize = 100) {
|
|
757
|
+
this.maxSize = maxSize;
|
|
758
|
+
}
|
|
759
|
+
get(filePath) {
|
|
760
|
+
const entry = this.cache.get(filePath);
|
|
761
|
+
if (!entry) return void 0;
|
|
762
|
+
try {
|
|
763
|
+
const stat = (0, import_node_fs.statSync)(filePath);
|
|
764
|
+
if (stat.mtimeMs !== entry.mtime) {
|
|
765
|
+
this.cache.delete(filePath);
|
|
766
|
+
return void 0;
|
|
767
|
+
}
|
|
768
|
+
} catch {
|
|
769
|
+
this.cache.delete(filePath);
|
|
770
|
+
return void 0;
|
|
771
|
+
}
|
|
772
|
+
return entry.value;
|
|
773
|
+
}
|
|
774
|
+
set(filePath, value) {
|
|
775
|
+
if (this.cache.size >= this.maxSize) {
|
|
776
|
+
const oldest = this.cache.keys().next().value;
|
|
777
|
+
if (oldest) this.cache.delete(oldest);
|
|
778
|
+
}
|
|
779
|
+
try {
|
|
780
|
+
const stat = (0, import_node_fs.statSync)(filePath);
|
|
781
|
+
this.cache.set(filePath, { value, mtime: stat.mtimeMs });
|
|
782
|
+
} catch {
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
clear() {
|
|
786
|
+
this.cache.clear();
|
|
787
|
+
}
|
|
788
|
+
get size() {
|
|
789
|
+
return this.cache.size;
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
// src/index.ts
|
|
794
|
+
var PromptOpsKit = class {
|
|
795
|
+
config;
|
|
796
|
+
promptCache;
|
|
797
|
+
constructor(config) {
|
|
798
|
+
this.config = {
|
|
799
|
+
...config,
|
|
800
|
+
mode: config.mode ?? "auto",
|
|
801
|
+
cache: config.cache ?? true
|
|
802
|
+
};
|
|
803
|
+
this.promptCache = new PromptCache();
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Load a prompt asset from compiled or source, based on mode.
|
|
807
|
+
*/
|
|
808
|
+
async loadPrompt(promptPath) {
|
|
809
|
+
const mode = this.config.mode;
|
|
810
|
+
if (mode !== "source-only" && this.config.compiledDir) {
|
|
811
|
+
const compiledFile = (0, import_node_path2.resolve)(this.config.compiledDir, promptPath + ".json");
|
|
812
|
+
if ((0, import_node_fs2.existsSync)(compiledFile)) {
|
|
813
|
+
if (mode === "auto") {
|
|
814
|
+
const sourceFile = (0, import_node_path2.resolve)(this.config.sourceDir, promptPath + ".md");
|
|
815
|
+
if ((0, import_node_fs2.existsSync)(sourceFile)) {
|
|
816
|
+
const compiledMtime = (0, import_node_fs2.statSync)(compiledFile).mtimeMs;
|
|
817
|
+
const sourceMtime = (0, import_node_fs2.statSync)(sourceFile).mtimeMs;
|
|
818
|
+
if (sourceMtime > compiledMtime) {
|
|
819
|
+
console.warn(
|
|
820
|
+
`[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
|
|
821
|
+
Run "promptopskit compile" or switch to source-only mode.`
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
const content = await (0, import_promises3.readFile)(compiledFile, "utf-8");
|
|
827
|
+
return JSON.parse(content);
|
|
828
|
+
}
|
|
829
|
+
if (mode === "compiled-only") {
|
|
830
|
+
throw new Error(
|
|
831
|
+
`Compiled artifact not found: ${compiledFile}
|
|
832
|
+
Run "promptopskit compile" to generate it.`
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
if (mode !== "compiled-only") {
|
|
837
|
+
const sourceFile = (0, import_node_path2.resolve)(this.config.sourceDir, promptPath + ".md");
|
|
838
|
+
if (this.config.cache) {
|
|
839
|
+
const cached = this.promptCache.get(sourceFile);
|
|
840
|
+
if (cached) return cached;
|
|
841
|
+
}
|
|
842
|
+
if (!(0, import_node_fs2.existsSync)(sourceFile)) {
|
|
843
|
+
const paths = [sourceFile];
|
|
844
|
+
if (this.config.compiledDir) {
|
|
845
|
+
paths.unshift((0, import_node_path2.resolve)(this.config.compiledDir, promptPath + ".json"));
|
|
846
|
+
}
|
|
847
|
+
throw new Error(
|
|
848
|
+
`Prompt not found: "${promptPath}"
|
|
849
|
+
Searched:
|
|
850
|
+
${paths.map((p) => ` - ${p}`).join("\n")}`
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
const content = await (0, import_promises3.readFile)(sourceFile, "utf-8");
|
|
854
|
+
const { asset } = parsePrompt(content, sourceFile);
|
|
855
|
+
if (this.config.cache) {
|
|
856
|
+
this.promptCache.set(sourceFile, asset);
|
|
857
|
+
}
|
|
858
|
+
return asset;
|
|
859
|
+
}
|
|
860
|
+
throw new Error(`Prompt not found: "${promptPath}"`);
|
|
861
|
+
}
|
|
862
|
+
/**
|
|
863
|
+
* Resolve a prompt: load, resolve includes, apply overrides.
|
|
864
|
+
*/
|
|
865
|
+
async resolvePrompt(promptPath, options = {}) {
|
|
866
|
+
let asset = await this.loadPrompt(promptPath);
|
|
867
|
+
const sourceFile = (0, import_node_path2.resolve)(this.config.sourceDir, promptPath + ".md");
|
|
868
|
+
if (asset.includes && asset.includes.length > 0 && (0, import_node_fs2.existsSync)(sourceFile)) {
|
|
869
|
+
asset = await resolveIncludes(asset, sourceFile);
|
|
870
|
+
}
|
|
871
|
+
asset = applyOverrides(asset, {
|
|
872
|
+
environment: options.environment,
|
|
873
|
+
tier: options.tier
|
|
874
|
+
});
|
|
875
|
+
return asset;
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Render a prompt for a specific provider.
|
|
879
|
+
*/
|
|
880
|
+
async renderPrompt(options) {
|
|
881
|
+
let resolved;
|
|
882
|
+
if (options.source) {
|
|
883
|
+
const { asset } = parsePrompt(options.source);
|
|
884
|
+
const overridden = applyOverrides(asset, {
|
|
885
|
+
environment: options.environment,
|
|
886
|
+
tier: options.tier
|
|
887
|
+
});
|
|
888
|
+
resolved = overridden;
|
|
889
|
+
} else if (options.path) {
|
|
890
|
+
resolved = await this.resolvePrompt(options.path, {
|
|
891
|
+
environment: options.environment,
|
|
892
|
+
tier: options.tier
|
|
893
|
+
});
|
|
894
|
+
} else {
|
|
895
|
+
throw new Error('Either "path" or "source" must be provided to renderPrompt()');
|
|
896
|
+
}
|
|
897
|
+
const adapter = getAdapter(options.provider);
|
|
898
|
+
const validation = adapter.validate(resolved);
|
|
899
|
+
if (!validation.valid) {
|
|
900
|
+
throw new Error(
|
|
901
|
+
`Provider validation failed for "${options.provider}":
|
|
902
|
+
` + validation.errors.map((e) => ` - ${e}`).join("\n")
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
const request = adapter.render(resolved, {
|
|
906
|
+
variables: options.variables,
|
|
907
|
+
history: options.history,
|
|
908
|
+
toolRegistry: options.toolRegistry,
|
|
909
|
+
strict: options.strict
|
|
910
|
+
});
|
|
911
|
+
return {
|
|
912
|
+
resolved,
|
|
913
|
+
request,
|
|
914
|
+
warnings: validation.warnings
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Validate a prompt file.
|
|
919
|
+
*/
|
|
920
|
+
async validatePrompt(promptPath) {
|
|
921
|
+
const asset = await this.loadPrompt(promptPath);
|
|
922
|
+
return validateAsset(asset, void 0, promptPath);
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Clear the internal cache.
|
|
926
|
+
*/
|
|
927
|
+
clearCache() {
|
|
928
|
+
this.promptCache.clear();
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
function createPromptOpsKit(config) {
|
|
932
|
+
return new PromptOpsKit(config);
|
|
933
|
+
}
|
|
934
|
+
async function renderPrompt(options) {
|
|
935
|
+
const kit = createPromptOpsKit({
|
|
936
|
+
sourceDir: options.sourceDir ?? ".",
|
|
937
|
+
cache: false
|
|
938
|
+
});
|
|
939
|
+
return kit.renderPrompt(options);
|
|
940
|
+
}
|
|
941
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
942
|
+
0 && (module.exports = {
|
|
943
|
+
PromptAssetOverridesSchema,
|
|
944
|
+
PromptAssetSchema,
|
|
945
|
+
PromptOpsKit,
|
|
946
|
+
anthropicAdapter,
|
|
947
|
+
applyOverrides,
|
|
948
|
+
createPromptOpsKit,
|
|
949
|
+
extractSections,
|
|
950
|
+
extractVariables,
|
|
951
|
+
geminiAdapter,
|
|
952
|
+
getAdapter,
|
|
953
|
+
interpolate,
|
|
954
|
+
loadPromptFile,
|
|
955
|
+
openaiAdapter,
|
|
956
|
+
openrouterAdapter,
|
|
957
|
+
parsePrompt,
|
|
958
|
+
renderPrompt,
|
|
959
|
+
resolveIncludes,
|
|
960
|
+
validateAsset,
|
|
961
|
+
validateAssetWithIncludes
|
|
962
|
+
});
|
|
963
|
+
//# sourceMappingURL=index.cjs.map
|