promptopskit 0.3.9 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -7
- package/SKILL.md +69 -6
- package/dist/{chunk-YNIAA4ZJ.js → chunk-F6UJ73Y6.js} +5 -3
- package/dist/chunk-F6UJ73Y6.js.map +1 -0
- package/dist/{chunk-O6RQZYS4.js → chunk-HLNVKKMS.js} +16 -5
- package/dist/chunk-HLNVKKMS.js.map +1 -0
- package/dist/{chunk-4LEPCCSA.js → chunk-JBLUPKY4.js} +144 -3
- package/dist/chunk-JBLUPKY4.js.map +1 -0
- package/dist/{chunk-LMURMZUA.js → chunk-L2V7LDKD.js} +5 -3
- package/dist/chunk-L2V7LDKD.js.map +1 -0
- package/dist/{chunk-AN3OR7YC.js → chunk-RY5DVTLV.js} +7 -5
- package/dist/chunk-RY5DVTLV.js.map +1 -0
- package/dist/chunk-UPTCSWK3.js +60 -0
- package/dist/chunk-UPTCSWK3.js.map +1 -0
- package/dist/{chunk-V7QY7MRM.js → chunk-XNNDGDPI.js} +50 -3
- package/dist/chunk-XNNDGDPI.js.map +1 -0
- package/dist/cli/index.js +356 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +398 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +162 -10
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic.cjs +200 -5
- 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 +191 -5
- 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/openai-responses.cjs +189 -3
- 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 +189 -3
- 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 +224 -6
- 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-BKkg93rL.d.cts → schema-B9A1zLRk.d.cts} +482 -2
- package/dist/{schema-BKkg93rL.d.ts → schema-B9A1zLRk.d.ts} +482 -2
- package/dist/testing.cjs +217 -4
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +59 -2
- package/dist/testing.d.ts +59 -2
- package/dist/testing.js +70 -2
- package/dist/testing.js.map +1 -1
- package/dist/{types-CsQ8tON_.d.ts → types-DjGAwJxC.d.ts} +1 -1
- package/dist/{types-7cC17GWp.d.cts → types-DpbzzZO2.d.cts} +1 -1
- package/dist/usagetap/index.d.cts +2 -2
- package/dist/usagetap/index.d.ts +2 -2
- package/package.json +2 -2
- package/dist/chunk-4LEPCCSA.js.map +0 -1
- package/dist/chunk-AN3OR7YC.js.map +0 -1
- package/dist/chunk-LMURMZUA.js.map +0 -1
- package/dist/chunk-O6RQZYS4.js.map +0 -1
- package/dist/chunk-V7QY7MRM.js.map +0 -1
- package/dist/chunk-YAD6COQX.js +0 -26
- package/dist/chunk-YAD6COQX.js.map +0 -1
- package/dist/chunk-YNIAA4ZJ.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -145,6 +145,29 @@ function mergeOverride(base, override) {
|
|
|
145
145
|
if (override.response !== void 0) {
|
|
146
146
|
result.response = { ...result.response, ...override.response };
|
|
147
147
|
}
|
|
148
|
+
if (override.cache !== void 0) {
|
|
149
|
+
result.cache = {
|
|
150
|
+
...result.cache,
|
|
151
|
+
...override.cache,
|
|
152
|
+
openai: mergeRecordBlock(result.cache?.openai, override.cache.openai),
|
|
153
|
+
anthropic: mergeRecordBlock(result.cache?.anthropic, override.cache.anthropic),
|
|
154
|
+
gemini: mergeRecordBlock(result.cache?.gemini, override.cache.gemini),
|
|
155
|
+
google: mergeRecordBlock(result.cache?.google, override.cache.google)
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (override.raw !== void 0) {
|
|
159
|
+
result.raw = {
|
|
160
|
+
...result.raw,
|
|
161
|
+
...override.raw,
|
|
162
|
+
openai: mergeRecordBlock(result.raw?.openai, override.raw.openai),
|
|
163
|
+
"openai-responses": mergeRecordBlock(result.raw?.["openai-responses"], override.raw["openai-responses"]),
|
|
164
|
+
openai_responses: mergeRecordBlock(result.raw?.openai_responses, override.raw.openai_responses),
|
|
165
|
+
anthropic: mergeRecordBlock(result.raw?.anthropic, override.raw.anthropic),
|
|
166
|
+
gemini: mergeRecordBlock(result.raw?.gemini, override.raw.gemini),
|
|
167
|
+
google: mergeRecordBlock(result.raw?.google, override.raw.google),
|
|
168
|
+
openrouter: mergeRecordBlock(result.raw?.openrouter, override.raw.openrouter)
|
|
169
|
+
};
|
|
170
|
+
}
|
|
148
171
|
if (override.provider_options !== void 0) {
|
|
149
172
|
result.provider_options = {
|
|
150
173
|
...result.provider_options,
|
|
@@ -156,11 +179,19 @@ function mergeOverride(base, override) {
|
|
|
156
179
|
gemini: {
|
|
157
180
|
...result.provider_options?.gemini,
|
|
158
181
|
...override.provider_options.gemini
|
|
182
|
+
},
|
|
183
|
+
openrouter: {
|
|
184
|
+
...result.provider_options?.openrouter,
|
|
185
|
+
...override.provider_options.openrouter
|
|
159
186
|
}
|
|
160
187
|
};
|
|
161
188
|
}
|
|
162
189
|
return result;
|
|
163
190
|
}
|
|
191
|
+
function mergeRecordBlock(base, override) {
|
|
192
|
+
if (override === void 0) return base;
|
|
193
|
+
return { ...base, ...override };
|
|
194
|
+
}
|
|
164
195
|
|
|
165
196
|
// src/providers/resolve-asset.ts
|
|
166
197
|
function resolveAssetForProvider(asset, runtime = {}) {
|
|
@@ -264,23 +295,42 @@ var ResponseSchema = import_zod.z.object({
|
|
|
264
295
|
stream: import_zod.z.boolean().optional(),
|
|
265
296
|
schema: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
266
297
|
schema_name: import_zod.z.string().optional(),
|
|
298
|
+
schema_description: import_zod.z.string().optional(),
|
|
267
299
|
schema_strict: import_zod.z.boolean().optional()
|
|
268
300
|
});
|
|
269
301
|
var AnthropicProviderOptionsSchema = import_zod.z.object({
|
|
270
302
|
top_k: import_zod.z.number().int().min(0).optional(),
|
|
271
|
-
tool_choice: import_zod.z.record(import_zod.z.unknown()).optional()
|
|
303
|
+
tool_choice: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
304
|
+
output_config: import_zod.z.record(import_zod.z.unknown()).optional()
|
|
272
305
|
});
|
|
273
306
|
var GeminiProviderOptionsSchema = import_zod.z.object({
|
|
274
307
|
candidate_count: import_zod.z.number().int().positive().optional(),
|
|
275
308
|
top_k: import_zod.z.number().int().min(0).optional(),
|
|
276
309
|
seed: import_zod.z.number().int().optional(),
|
|
277
310
|
response_schema: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
311
|
+
response_json_schema: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
278
312
|
response_modalities: import_zod.z.array(import_zod.z.string()).optional(),
|
|
279
313
|
thinking_budget_tokens: import_zod.z.number().int().positive().optional()
|
|
280
314
|
});
|
|
315
|
+
var OpenRouterProviderOptionsSchema = import_zod.z.object({
|
|
316
|
+
provider: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
317
|
+
transforms: import_zod.z.array(import_zod.z.string()).optional(),
|
|
318
|
+
plugins: import_zod.z.array(import_zod.z.record(import_zod.z.unknown())).optional(),
|
|
319
|
+
models: import_zod.z.array(import_zod.z.string()).optional()
|
|
320
|
+
});
|
|
281
321
|
var ProviderOptionsSchema = import_zod.z.object({
|
|
282
322
|
anthropic: AnthropicProviderOptionsSchema.optional(),
|
|
283
|
-
gemini: GeminiProviderOptionsSchema.optional()
|
|
323
|
+
gemini: GeminiProviderOptionsSchema.optional(),
|
|
324
|
+
openrouter: OpenRouterProviderOptionsSchema.optional()
|
|
325
|
+
});
|
|
326
|
+
var RawProviderBodySchema = import_zod.z.object({
|
|
327
|
+
openai: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
328
|
+
"openai-responses": import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
329
|
+
openai_responses: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
330
|
+
anthropic: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
331
|
+
gemini: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
332
|
+
google: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
333
|
+
openrouter: import_zod.z.record(import_zod.z.unknown()).optional()
|
|
284
334
|
});
|
|
285
335
|
var OpenAICacheSchema = import_zod.z.object({
|
|
286
336
|
prompt_cache_key: import_zod.z.string().min(1).optional(),
|
|
@@ -353,6 +403,7 @@ var PromptAssetOverridesSchema = import_zod.z.object({
|
|
|
353
403
|
sampling: SamplingSchema.optional(),
|
|
354
404
|
response: ResponseSchema.optional(),
|
|
355
405
|
cache: CacheSchema.optional(),
|
|
406
|
+
raw: RawProviderBodySchema.optional(),
|
|
356
407
|
tools: import_zod.z.array(ToolRefSchema).optional(),
|
|
357
408
|
provider_options: ProviderOptionsSchema.optional()
|
|
358
409
|
});
|
|
@@ -385,6 +436,7 @@ var PromptAssetSchema = import_zod.z.object({
|
|
|
385
436
|
sampling: SamplingSchema.optional(),
|
|
386
437
|
response: ResponseSchema.optional(),
|
|
387
438
|
cache: CacheSchema.optional(),
|
|
439
|
+
raw: RawProviderBodySchema.optional(),
|
|
388
440
|
tools: import_zod.z.array(ToolRefSchema).optional(),
|
|
389
441
|
provider_options: ProviderOptionsSchema.optional(),
|
|
390
442
|
mcp: MCPSchema.optional(),
|
|
@@ -398,6 +450,123 @@ var PromptAssetSchema = import_zod.z.object({
|
|
|
398
450
|
source: SourceSchema.optional()
|
|
399
451
|
});
|
|
400
452
|
|
|
453
|
+
// src/parser/frontmatter-guard.ts
|
|
454
|
+
var FRONT_MATTER_DELIMITER = /^---[ \t]*$/;
|
|
455
|
+
var REGEX_FIELD = /^(?<indent>\s*)(?<field>allow_regex|deny_regex)\s*:\s*(?<value>.*)$/;
|
|
456
|
+
var PATTERN_FIELD = /^(?<indent>\s*)pattern\s*:\s*(?<value>.*)$/;
|
|
457
|
+
var INLINE_PATTERN_FIELD = /(?:^|[{,]\s*)pattern\s*:\s*(?<value>"(?:\\.|[^"\\])*")/;
|
|
458
|
+
function assertRegexFrontMatterQuoting(content, filePath) {
|
|
459
|
+
const frontMatter = extractFrontMatter(content);
|
|
460
|
+
if (!frontMatter) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
let pendingRegex;
|
|
464
|
+
for (const [index, line] of frontMatter.lines.entries()) {
|
|
465
|
+
const lineNumber = frontMatter.startLine + index;
|
|
466
|
+
const regexMatch = line.match(REGEX_FIELD);
|
|
467
|
+
if (regexMatch?.groups) {
|
|
468
|
+
const field = regexMatch.groups.field;
|
|
469
|
+
const indent2 = regexMatch.groups.indent.length;
|
|
470
|
+
const value = regexMatch.groups.value.trim();
|
|
471
|
+
pendingRegex = value === "" ? { field, indent: indent2 } : void 0;
|
|
472
|
+
assertNoUnescapedBackslashInDoubleQuotedRegex(value, field, filePath, lineNumber);
|
|
473
|
+
assertNoUnescapedBackslashInInlinePattern(value, field, filePath, lineNumber);
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
if (!pendingRegex) {
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
if (line.trim() === "" || line.trimStart().startsWith("#")) {
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
const indent = line.match(/^\s*/)?.[0].length ?? 0;
|
|
483
|
+
if (indent <= pendingRegex.indent) {
|
|
484
|
+
pendingRegex = void 0;
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
const patternMatch = line.match(PATTERN_FIELD);
|
|
488
|
+
if (!patternMatch?.groups) {
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
assertNoUnescapedBackslashInDoubleQuotedRegex(
|
|
492
|
+
patternMatch.groups.value.trim(),
|
|
493
|
+
`${pendingRegex.field}.pattern`,
|
|
494
|
+
filePath,
|
|
495
|
+
lineNumber
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
function assertNoUnescapedBackslashInInlinePattern(value, field, filePath, lineNumber) {
|
|
500
|
+
const match = value.match(INLINE_PATTERN_FIELD);
|
|
501
|
+
const pattern = match?.groups?.value;
|
|
502
|
+
if (!pattern) {
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
assertNoUnescapedBackslashInDoubleQuotedRegex(pattern, `${field}.pattern`, filePath, lineNumber);
|
|
506
|
+
}
|
|
507
|
+
function extractFrontMatter(content) {
|
|
508
|
+
const lines = content.split(/\r?\n/);
|
|
509
|
+
if (!FRONT_MATTER_DELIMITER.test(lines[0] ?? "")) {
|
|
510
|
+
return void 0;
|
|
511
|
+
}
|
|
512
|
+
for (let index = 1; index < lines.length; index += 1) {
|
|
513
|
+
if (FRONT_MATTER_DELIMITER.test(lines[index] ?? "")) {
|
|
514
|
+
return {
|
|
515
|
+
lines: lines.slice(1, index),
|
|
516
|
+
startLine: 2
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return void 0;
|
|
521
|
+
}
|
|
522
|
+
function assertNoUnescapedBackslashInDoubleQuotedRegex(value, field, filePath, lineNumber) {
|
|
523
|
+
if (!value.startsWith('"')) {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
const quoted = readDoubleQuotedScalar(value);
|
|
527
|
+
if (!quoted) {
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
if (!hasUnescapedBackslash(quoted)) {
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
const location = filePath ? `${filePath}:${lineNumber}` : `line ${lineNumber}`;
|
|
534
|
+
throw new Error(
|
|
535
|
+
`POK013: Invalid context regex YAML at ${location}, field "${field}": double-quoted regex strings treat backslashes as YAML escapes. Use unquoted /pattern/i literal form, single quotes, or double each backslash.`
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
function readDoubleQuotedScalar(value) {
|
|
539
|
+
let result = "";
|
|
540
|
+
for (let index = 1; index < value.length; index += 1) {
|
|
541
|
+
const char = value[index];
|
|
542
|
+
if (char === '"') {
|
|
543
|
+
return result;
|
|
544
|
+
}
|
|
545
|
+
result += char;
|
|
546
|
+
if (char === "\\" && index + 1 < value.length) {
|
|
547
|
+
index += 1;
|
|
548
|
+
result += value[index];
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
return void 0;
|
|
552
|
+
}
|
|
553
|
+
function hasUnescapedBackslash(value) {
|
|
554
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
555
|
+
if (value[index] !== "\\") {
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
let count = 1;
|
|
559
|
+
while (value[index + count] === "\\") {
|
|
560
|
+
count += 1;
|
|
561
|
+
}
|
|
562
|
+
if (count % 2 === 1) {
|
|
563
|
+
return true;
|
|
564
|
+
}
|
|
565
|
+
index += count - 1;
|
|
566
|
+
}
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
|
|
401
570
|
// src/parser/sections.ts
|
|
402
571
|
var SECTION_MAP = {
|
|
403
572
|
"system instructions": "system_instructions",
|
|
@@ -438,6 +607,7 @@ function extractSections(body) {
|
|
|
438
607
|
|
|
439
608
|
// src/parser/parser.ts
|
|
440
609
|
function parsePrompt(content, filePath) {
|
|
610
|
+
assertRegexFrontMatterQuoting(content, filePath);
|
|
441
611
|
const { data: frontMatter, content: body } = (0, import_gray_matter.default)(content);
|
|
442
612
|
const sections = extractSections(body);
|
|
443
613
|
const raw = {
|
|
@@ -1018,6 +1188,21 @@ function withPromptInputSupport(adapter) {
|
|
|
1018
1188
|
};
|
|
1019
1189
|
}
|
|
1020
1190
|
|
|
1191
|
+
// src/providers/raw.ts
|
|
1192
|
+
function applyRawProviderBody(body, asset, provider) {
|
|
1193
|
+
const raw = getRawProviderBody(asset, provider);
|
|
1194
|
+
return raw ? { ...body, ...raw } : body;
|
|
1195
|
+
}
|
|
1196
|
+
function getRawProviderBody(asset, provider) {
|
|
1197
|
+
if (provider === "openai-responses") {
|
|
1198
|
+
return asset.raw?.["openai-responses"] ?? asset.raw?.openai_responses;
|
|
1199
|
+
}
|
|
1200
|
+
if (provider === "gemini") {
|
|
1201
|
+
return asset.raw?.gemini ?? asset.raw?.google;
|
|
1202
|
+
}
|
|
1203
|
+
return asset.raw?.[provider];
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1021
1206
|
// src/providers/openai.ts
|
|
1022
1207
|
var openaiAdapter = withPromptInputSupport({
|
|
1023
1208
|
name: "openai",
|
|
@@ -1073,6 +1258,7 @@ var openaiAdapter = withPromptInputSupport({
|
|
|
1073
1258
|
type: "json_schema",
|
|
1074
1259
|
json_schema: {
|
|
1075
1260
|
name: resolvedAsset.response.schema_name ?? `${resolvedAsset.id}_response`,
|
|
1261
|
+
...resolvedAsset.response.schema_description ? { description: resolvedAsset.response.schema_description } : {},
|
|
1076
1262
|
schema: resolvedAsset.response.schema,
|
|
1077
1263
|
strict: resolvedAsset.response.schema_strict ?? true
|
|
1078
1264
|
}
|
|
@@ -1107,7 +1293,7 @@ var openaiAdapter = withPromptInputSupport({
|
|
|
1107
1293
|
});
|
|
1108
1294
|
}
|
|
1109
1295
|
return {
|
|
1110
|
-
body,
|
|
1296
|
+
body: applyRawProviderBody(body, resolvedAsset, "openai"),
|
|
1111
1297
|
provider: "openai",
|
|
1112
1298
|
model: resolvedAsset.model ?? "unknown"
|
|
1113
1299
|
};
|
|
@@ -1174,6 +1360,7 @@ var openaiResponsesAdapter = withPromptInputSupport({
|
|
|
1174
1360
|
format: {
|
|
1175
1361
|
type: "json_schema",
|
|
1176
1362
|
name: resolvedAsset.response.schema_name ?? `${resolvedAsset.id}_response`,
|
|
1363
|
+
...resolvedAsset.response.schema_description ? { description: resolvedAsset.response.schema_description } : {},
|
|
1177
1364
|
schema: resolvedAsset.response.schema,
|
|
1178
1365
|
strict: resolvedAsset.response.schema_strict ?? true
|
|
1179
1366
|
}
|
|
@@ -1208,7 +1395,7 @@ var openaiResponsesAdapter = withPromptInputSupport({
|
|
|
1208
1395
|
if (responseOptions?.include !== void 0) body.include = responseOptions.include;
|
|
1209
1396
|
if (responseOptions?.background !== void 0) body.background = responseOptions.background;
|
|
1210
1397
|
return {
|
|
1211
|
-
body,
|
|
1398
|
+
body: applyRawProviderBody(body, resolvedAsset, "openai-responses"),
|
|
1212
1399
|
provider: "openai-responses",
|
|
1213
1400
|
model: resolvedAsset.model ?? "unknown"
|
|
1214
1401
|
};
|
|
@@ -1234,8 +1421,8 @@ var anthropicAdapter = withPromptInputSupport({
|
|
|
1234
1421
|
if (resolvedAsset.reasoning?.effort !== void 0) {
|
|
1235
1422
|
warnings.push("Anthropic uses budget_tokens for thinking, not effort. effort will be mapped approximately.");
|
|
1236
1423
|
}
|
|
1237
|
-
if (resolvedAsset.response?.schema !== void 0) {
|
|
1238
|
-
warnings.push("Anthropic
|
|
1424
|
+
if (resolvedAsset.response?.schema !== void 0 && resolvedAsset.response?.format !== "json") {
|
|
1425
|
+
warnings.push("Anthropic response.schema is mapped to output_config.format and should usually be paired with response.format: json.");
|
|
1239
1426
|
}
|
|
1240
1427
|
if (resolvedAsset.provider_options?.anthropic?.top_k !== void 0 && resolvedAsset.provider_options.anthropic.top_k < 0) {
|
|
1241
1428
|
errors.push("Anthropic provider_options.top_k must be >= 0.");
|
|
@@ -1299,6 +1486,16 @@ var anthropicAdapter = withPromptInputSupport({
|
|
|
1299
1486
|
if (resolvedAsset.provider_options?.anthropic?.top_k !== void 0) {
|
|
1300
1487
|
body.top_k = resolvedAsset.provider_options.anthropic.top_k;
|
|
1301
1488
|
}
|
|
1489
|
+
if (resolvedAsset.provider_options?.anthropic?.output_config !== void 0) {
|
|
1490
|
+
body.output_config = resolvedAsset.provider_options.anthropic.output_config;
|
|
1491
|
+
} else if (resolvedAsset.response?.schema !== void 0) {
|
|
1492
|
+
body.output_config = {
|
|
1493
|
+
format: {
|
|
1494
|
+
type: "json_schema",
|
|
1495
|
+
schema: resolvedAsset.response.schema
|
|
1496
|
+
}
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1302
1499
|
if (resolvedAsset.response?.stream !== void 0) {
|
|
1303
1500
|
body.stream = resolvedAsset.response.stream;
|
|
1304
1501
|
}
|
|
@@ -1332,7 +1529,7 @@ var anthropicAdapter = withPromptInputSupport({
|
|
|
1332
1529
|
body.tool_choice = resolvedAsset.provider_options.anthropic.tool_choice;
|
|
1333
1530
|
}
|
|
1334
1531
|
return {
|
|
1335
|
-
body,
|
|
1532
|
+
body: applyRawProviderBody(body, resolvedAsset, "anthropic"),
|
|
1336
1533
|
provider: "anthropic",
|
|
1337
1534
|
model: resolvedAsset.model ?? "unknown"
|
|
1338
1535
|
};
|
|
@@ -1404,9 +1601,10 @@ var geminiAdapter = withPromptInputSupport({
|
|
|
1404
1601
|
if (geminiOptions?.candidate_count !== void 0) generationConfig.candidateCount = geminiOptions.candidate_count;
|
|
1405
1602
|
if (geminiOptions?.top_k !== void 0) generationConfig.topK = geminiOptions.top_k;
|
|
1406
1603
|
if (geminiOptions?.seed !== void 0) generationConfig.seed = geminiOptions.seed;
|
|
1407
|
-
if (geminiOptions?.response_schema !== void 0) generationConfig.responseSchema = geminiOptions.response_schema;
|
|
1408
1604
|
if (geminiOptions?.response_modalities !== void 0) generationConfig.responseModalities = geminiOptions.response_modalities;
|
|
1409
|
-
if (resolvedAsset.response?.schema !== void 0) generationConfig.
|
|
1605
|
+
if (resolvedAsset.response?.schema !== void 0) generationConfig.responseJsonSchema = resolvedAsset.response.schema;
|
|
1606
|
+
if (geminiOptions?.response_schema !== void 0) generationConfig.responseSchema = geminiOptions.response_schema;
|
|
1607
|
+
if (geminiOptions?.response_json_schema !== void 0) generationConfig.responseJsonSchema = geminiOptions.response_json_schema;
|
|
1410
1608
|
if (resolvedAsset.response?.format === "json") {
|
|
1411
1609
|
generationConfig.responseMimeType = "application/json";
|
|
1412
1610
|
}
|
|
@@ -1441,7 +1639,7 @@ var geminiAdapter = withPromptInputSupport({
|
|
|
1441
1639
|
body.tools = [{ functionDeclarations }];
|
|
1442
1640
|
}
|
|
1443
1641
|
return {
|
|
1444
|
-
body,
|
|
1642
|
+
body: applyRawProviderBody(body, resolvedAsset, "gemini"),
|
|
1445
1643
|
provider: "gemini",
|
|
1446
1644
|
model: resolvedAsset.model ?? "unknown"
|
|
1447
1645
|
};
|
|
@@ -1452,13 +1650,45 @@ var geminiAdapter = withPromptInputSupport({
|
|
|
1452
1650
|
var openrouterAdapter = withPromptInputSupport({
|
|
1453
1651
|
name: "openrouter",
|
|
1454
1652
|
validate(asset, runtime) {
|
|
1455
|
-
|
|
1653
|
+
const resolvedAsset = resolveAssetForProvider(asset, runtime);
|
|
1654
|
+
const validation = openaiAdapter.validate(asset, runtime);
|
|
1655
|
+
const hasOpenRouterModels = (resolvedAsset.provider_options?.openrouter?.models?.length ?? 0) > 0;
|
|
1656
|
+
if (!hasOpenRouterModels) {
|
|
1657
|
+
return validation;
|
|
1658
|
+
}
|
|
1659
|
+
const modelRequiredError = "OpenAI adapter requires a model to be specified.";
|
|
1660
|
+
const errors = validation.errors.filter((error) => error !== modelRequiredError);
|
|
1661
|
+
const warnings = validation.warnings.filter((warning) => warning !== modelRequiredError);
|
|
1662
|
+
return {
|
|
1663
|
+
valid: errors.length === 0,
|
|
1664
|
+
errors,
|
|
1665
|
+
warnings
|
|
1666
|
+
};
|
|
1456
1667
|
},
|
|
1457
1668
|
render(asset, runtime) {
|
|
1458
|
-
const
|
|
1669
|
+
const resolvedAsset = resolveAssetForProvider(asset, runtime);
|
|
1670
|
+
const result = openaiAdapter.render(
|
|
1671
|
+
{ ...resolvedAsset, raw: void 0 },
|
|
1672
|
+
{
|
|
1673
|
+
variables: runtime.variables,
|
|
1674
|
+
history: runtime.history,
|
|
1675
|
+
toolRegistry: runtime.toolRegistry,
|
|
1676
|
+
strict: runtime.strict
|
|
1677
|
+
}
|
|
1678
|
+
);
|
|
1679
|
+
const openrouterOptions = resolvedAsset.provider_options?.openrouter;
|
|
1680
|
+
let body = { ...result.body };
|
|
1681
|
+
if (openrouterOptions?.provider !== void 0) body.provider = openrouterOptions.provider;
|
|
1682
|
+
if (openrouterOptions?.transforms !== void 0) body.transforms = openrouterOptions.transforms;
|
|
1683
|
+
if (openrouterOptions?.plugins !== void 0) body.plugins = openrouterOptions.plugins;
|
|
1684
|
+
if (openrouterOptions?.models !== void 0) body.models = openrouterOptions.models;
|
|
1685
|
+
if (body.model === void 0) delete body.model;
|
|
1686
|
+
body = applyRawProviderBody(body, resolvedAsset, "openrouter");
|
|
1459
1687
|
return {
|
|
1460
1688
|
...result,
|
|
1461
|
-
|
|
1689
|
+
body,
|
|
1690
|
+
provider: "openrouter",
|
|
1691
|
+
model: resolvedAsset.model ?? openrouterOptions?.models?.[0] ?? "unknown"
|
|
1462
1692
|
};
|
|
1463
1693
|
}
|
|
1464
1694
|
});
|
|
@@ -1522,8 +1752,21 @@ var KNOWN_FRONT_MATTER_KEYS = /* @__PURE__ */ new Set([
|
|
|
1522
1752
|
"environments",
|
|
1523
1753
|
"tiers",
|
|
1524
1754
|
"metadata",
|
|
1525
|
-
"cache"
|
|
1755
|
+
"cache",
|
|
1756
|
+
"provider_options",
|
|
1757
|
+
"raw"
|
|
1526
1758
|
]);
|
|
1759
|
+
var RISKY_UNBOUNDED_INPUT_NAMES = [
|
|
1760
|
+
"message",
|
|
1761
|
+
"prompt",
|
|
1762
|
+
"history",
|
|
1763
|
+
"transcript",
|
|
1764
|
+
"document",
|
|
1765
|
+
"content",
|
|
1766
|
+
"input",
|
|
1767
|
+
"body",
|
|
1768
|
+
"context"
|
|
1769
|
+
];
|
|
1527
1770
|
function validateAsset(asset, frontMatterKeys, filePath) {
|
|
1528
1771
|
const errors = [];
|
|
1529
1772
|
const warnings = [];
|
|
@@ -1594,7 +1837,32 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
1594
1837
|
});
|
|
1595
1838
|
}
|
|
1596
1839
|
}
|
|
1840
|
+
if (usedVars.size > 0 && (!asset.context?.inputs || asset.context.inputs.length === 0)) {
|
|
1841
|
+
warnings.push({
|
|
1842
|
+
code: "POK046",
|
|
1843
|
+
message: `Template uses ${usedVars.size === 1 ? "a variable" : "variables"} but context.inputs is not declared.`,
|
|
1844
|
+
filePath,
|
|
1845
|
+
suggestion: "Declare context.inputs to enable input policy validation."
|
|
1846
|
+
});
|
|
1847
|
+
}
|
|
1597
1848
|
for (const input of getContextInputs(asset)) {
|
|
1849
|
+
const lowerName = input.name.toLowerCase();
|
|
1850
|
+
if (input.max_size === void 0 && RISKY_UNBOUNDED_INPUT_NAMES.some((needle) => lowerName.includes(needle))) {
|
|
1851
|
+
warnings.push({
|
|
1852
|
+
code: "POK040",
|
|
1853
|
+
message: `Context input "${input.name}" has no max_size and appears unbounded.`,
|
|
1854
|
+
filePath,
|
|
1855
|
+
suggestion: "Add max_size to constrain prompt payload growth."
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
if (input.allow_regex === void 0 && input.deny_regex === void 0 && input.non_empty === void 0 && input.reject_secrets === void 0) {
|
|
1859
|
+
warnings.push({
|
|
1860
|
+
code: "POK041",
|
|
1861
|
+
message: `Context input "${input.name}" has no input hardening validators.`,
|
|
1862
|
+
filePath,
|
|
1863
|
+
suggestion: "Consider non_empty/reject_secrets and allow/deny regex validators."
|
|
1864
|
+
});
|
|
1865
|
+
}
|
|
1598
1866
|
if (input.trim !== void 0 && input.trim !== false && input.max_size === void 0) {
|
|
1599
1867
|
warnings.push({
|
|
1600
1868
|
code: "POK014",
|
|
@@ -1622,6 +1890,91 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
1622
1890
|
}
|
|
1623
1891
|
}
|
|
1624
1892
|
}
|
|
1893
|
+
if (asset.provider) {
|
|
1894
|
+
let providerCache;
|
|
1895
|
+
let cacheSuggestionField;
|
|
1896
|
+
switch (asset.provider) {
|
|
1897
|
+
case "openai":
|
|
1898
|
+
providerCache = asset.cache?.openai;
|
|
1899
|
+
cacheSuggestionField = "cache.openai";
|
|
1900
|
+
break;
|
|
1901
|
+
case "anthropic":
|
|
1902
|
+
providerCache = asset.cache?.anthropic;
|
|
1903
|
+
cacheSuggestionField = "cache.anthropic";
|
|
1904
|
+
break;
|
|
1905
|
+
case "gemini":
|
|
1906
|
+
case "google":
|
|
1907
|
+
providerCache = asset.cache?.gemini ?? asset.cache?.google;
|
|
1908
|
+
cacheSuggestionField = "cache.gemini";
|
|
1909
|
+
break;
|
|
1910
|
+
default:
|
|
1911
|
+
break;
|
|
1912
|
+
}
|
|
1913
|
+
if (cacheSuggestionField && providerCache === void 0) {
|
|
1914
|
+
warnings.push({
|
|
1915
|
+
code: "POK042",
|
|
1916
|
+
message: `Provider "${asset.provider}" has no provider-specific cache settings.`,
|
|
1917
|
+
filePath,
|
|
1918
|
+
suggestion: `Consider configuring ${cacheSuggestionField} for better cache-hit behavior.`
|
|
1919
|
+
});
|
|
1920
|
+
}
|
|
1921
|
+
if (!asset.model) {
|
|
1922
|
+
warnings.push({
|
|
1923
|
+
code: "POK044",
|
|
1924
|
+
message: `Provider "${asset.provider}" is configured without a model.`,
|
|
1925
|
+
filePath,
|
|
1926
|
+
suggestion: "Set model in prompt or defaults to avoid adapter-time errors."
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
if (asset.cache?.gemini?.cached_content && asset.cache.google?.cached_content && asset.cache.gemini.cached_content !== asset.cache.google.cached_content) {
|
|
1931
|
+
warnings.push({
|
|
1932
|
+
code: "POK043",
|
|
1933
|
+
message: "cache.gemini.cached_content and cache.google.cached_content are both set to different values.",
|
|
1934
|
+
filePath,
|
|
1935
|
+
suggestion: "Use one canonical value; Gemini prefers cache.gemini.cached_content."
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1938
|
+
for (const [envName, overrides] of Object.entries(asset.environments ?? {})) {
|
|
1939
|
+
if (asset.cache && (!isRecord(overrides) || !overrides.cache)) {
|
|
1940
|
+
warnings.push({
|
|
1941
|
+
code: "POK045",
|
|
1942
|
+
message: `Environment "${envName}" does not override cache while prompt-level cache is defined.`,
|
|
1943
|
+
filePath,
|
|
1944
|
+
suggestion: "Confirm cache strategy is intentionally shared across environments."
|
|
1945
|
+
});
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
for (const [tierName, overrides] of Object.entries(asset.tiers ?? {})) {
|
|
1949
|
+
if (asset.cache && (!isRecord(overrides) || !overrides.cache)) {
|
|
1950
|
+
warnings.push({
|
|
1951
|
+
code: "POK045",
|
|
1952
|
+
message: `Tier "${tierName}" does not override cache while prompt-level cache is defined.`,
|
|
1953
|
+
filePath,
|
|
1954
|
+
suggestion: "Confirm cache strategy is intentionally shared across tiers."
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
for (const tool of asset.tools ?? []) {
|
|
1959
|
+
if (isRecord(tool)) {
|
|
1960
|
+
if (!tool.description) {
|
|
1961
|
+
warnings.push({
|
|
1962
|
+
code: "POK047",
|
|
1963
|
+
message: `Inline tool "${tool.name}" is missing a description.`,
|
|
1964
|
+
filePath,
|
|
1965
|
+
suggestion: "Add description to improve model tool-selection quality."
|
|
1966
|
+
});
|
|
1967
|
+
}
|
|
1968
|
+
if (!tool.input_schema) {
|
|
1969
|
+
warnings.push({
|
|
1970
|
+
code: "POK047",
|
|
1971
|
+
message: `Inline tool "${tool.name}" is missing input_schema.`,
|
|
1972
|
+
filePath,
|
|
1973
|
+
suggestion: "Add input_schema so tool inputs are strongly typed."
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1625
1978
|
return {
|
|
1626
1979
|
valid: errors.length === 0,
|
|
1627
1980
|
errors,
|
|
@@ -1658,6 +2011,9 @@ function findClosestMatch(input, candidates) {
|
|
|
1658
2011
|
}
|
|
1659
2012
|
return best;
|
|
1660
2013
|
}
|
|
2014
|
+
function isRecord(value) {
|
|
2015
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2016
|
+
}
|
|
1661
2017
|
|
|
1662
2018
|
// src/usagetap/client.ts
|
|
1663
2019
|
var DEFAULT_BASE_URL = "https://api.usagetap.com";
|
|
@@ -2141,9 +2497,21 @@ var PromptOpsKit = class {
|
|
|
2141
2497
|
* Validate a prompt file.
|
|
2142
2498
|
*/
|
|
2143
2499
|
async validatePrompt(promptPath) {
|
|
2144
|
-
const asset = await this.loadPrompt(promptPath);
|
|
2145
2500
|
const sourceFile = (0, import_node_path4.resolve)(this.config.sourceDir, promptPath + ".md");
|
|
2146
|
-
|
|
2501
|
+
try {
|
|
2502
|
+
const asset = await this.loadPrompt(promptPath);
|
|
2503
|
+
return validateAssetWithIncludes(asset, sourceFile);
|
|
2504
|
+
} catch (error) {
|
|
2505
|
+
const validationError = toPromptValidationError(error, sourceFile);
|
|
2506
|
+
if (validationError) {
|
|
2507
|
+
return {
|
|
2508
|
+
valid: false,
|
|
2509
|
+
errors: [validationError],
|
|
2510
|
+
warnings: []
|
|
2511
|
+
};
|
|
2512
|
+
}
|
|
2513
|
+
throw error;
|
|
2514
|
+
}
|
|
2147
2515
|
}
|
|
2148
2516
|
/**
|
|
2149
2517
|
* Clear the internal cache.
|
|
@@ -2155,6 +2523,20 @@ var PromptOpsKit = class {
|
|
|
2155
2523
|
function createPromptOpsKit(config = {}) {
|
|
2156
2524
|
return new PromptOpsKit(config);
|
|
2157
2525
|
}
|
|
2526
|
+
function toPromptValidationError(error, filePath) {
|
|
2527
|
+
if (!(error instanceof Error)) {
|
|
2528
|
+
return void 0;
|
|
2529
|
+
}
|
|
2530
|
+
const match = error.message.match(/^(POK\d+):\s*(.*)$/);
|
|
2531
|
+
if (!match) {
|
|
2532
|
+
return void 0;
|
|
2533
|
+
}
|
|
2534
|
+
return {
|
|
2535
|
+
code: match[1],
|
|
2536
|
+
message: match[2],
|
|
2537
|
+
filePath
|
|
2538
|
+
};
|
|
2539
|
+
}
|
|
2158
2540
|
async function renderPrompt(options) {
|
|
2159
2541
|
const kit = createPromptOpsKit({
|
|
2160
2542
|
sourceDir: options.sourceDir ?? DEFAULT_PROMPTS_DIR,
|