promptopskit 0.3.5 → 0.3.7
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 +12 -5
- package/SKILL.md +8 -1
- package/dist/{chunk-7RWTFGMS.js → chunk-5TLHYSP7.js} +2 -2
- package/dist/{chunk-M5VKRDIY.js → chunk-6XKV4YVK.js} +256 -3
- package/dist/chunk-6XKV4YVK.js.map +1 -0
- package/dist/{chunk-ROBYCHAW.js → chunk-DGLLQ3FR.js} +3 -3
- package/dist/{chunk-2LK6IILW.js → chunk-IXPIBZXT.js} +14 -2
- package/dist/chunk-IXPIBZXT.js.map +1 -0
- package/dist/{chunk-4QW4BSGE.js → chunk-KFSP5KN4.js} +2 -2
- package/dist/{chunk-2X5HFPSD.js → chunk-QPOHKVY5.js} +2 -2
- package/dist/cli/index.js +256 -93
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +295 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +44 -50
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic.cjs +238 -2
- 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 +238 -2
- 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.cjs +238 -2
- 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 +238 -2
- 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-Dq0jKest.d.cts → schema-Bgoff-CN.d.cts} +89 -0
- package/dist/{schema-Dq0jKest.d.ts → schema-Bgoff-CN.d.ts} +89 -0
- package/dist/testing.cjs +13 -1
- 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-ClXTFaX-.d.cts → types-7U58bgVW.d.cts} +8 -1
- package/dist/{types-lLD7m02V.d.ts → types-HnZ46u5Q.d.ts} +8 -1
- package/dist/usagetap/index.d.cts +2 -2
- package/dist/usagetap/index.d.ts +2 -2
- package/package.json +1 -1
- package/dist/chunk-2LK6IILW.js.map +0 -1
- package/dist/chunk-M5VKRDIY.js.map +0 -1
- /package/dist/{chunk-7RWTFGMS.js.map → chunk-5TLHYSP7.js.map} +0 -0
- /package/dist/{chunk-ROBYCHAW.js.map → chunk-DGLLQ3FR.js.map} +0 -0
- /package/dist/{chunk-4QW4BSGE.js.map → chunk-KFSP5KN4.js.map} +0 -0
- /package/dist/{chunk-2X5HFPSD.js.map → chunk-QPOHKVY5.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -251,9 +251,21 @@ var ResponseSchema = import_zod.z.object({
|
|
|
251
251
|
var HistorySchema = import_zod.z.object({
|
|
252
252
|
max_items: import_zod.z.number().int().positive().optional()
|
|
253
253
|
});
|
|
254
|
+
var ContextRegexSchema = import_zod.z.union([
|
|
255
|
+
import_zod.z.string(),
|
|
256
|
+
import_zod.z.object({
|
|
257
|
+
pattern: import_zod.z.string(),
|
|
258
|
+
flags: import_zod.z.string().optional()
|
|
259
|
+
})
|
|
260
|
+
]);
|
|
254
261
|
var ContextInputDefinitionObjectSchema = import_zod.z.object({
|
|
255
262
|
name: import_zod.z.string(),
|
|
256
|
-
max_size: import_zod.z.number().int().positive().optional()
|
|
263
|
+
max_size: import_zod.z.number().int().positive().optional(),
|
|
264
|
+
trim: import_zod.z.union([import_zod.z.boolean(), import_zod.z.enum(["start", "end", "both"])]).optional(),
|
|
265
|
+
allow_regex: ContextRegexSchema.optional(),
|
|
266
|
+
deny_regex: ContextRegexSchema.optional(),
|
|
267
|
+
non_empty: import_zod.z.boolean().optional(),
|
|
268
|
+
reject_secrets: import_zod.z.boolean().optional()
|
|
257
269
|
});
|
|
258
270
|
var ContextInputDefinitionSchema = import_zod.z.union([
|
|
259
271
|
import_zod.z.string(),
|
|
@@ -596,6 +608,248 @@ function resolveInlinePromptSource(source, options = {}) {
|
|
|
596
608
|
});
|
|
597
609
|
}
|
|
598
610
|
|
|
611
|
+
// src/context.ts
|
|
612
|
+
var textEncoder = new TextEncoder();
|
|
613
|
+
var REJECT_SECRETS_PATTERN = "(secret|api[_-]?key|password)";
|
|
614
|
+
var REJECT_SECRETS_FLAGS = "i";
|
|
615
|
+
function getContextInputs(asset) {
|
|
616
|
+
return (asset.context?.inputs ?? []).map(normalizeContextInput);
|
|
617
|
+
}
|
|
618
|
+
function getContextInputNames(asset) {
|
|
619
|
+
return getContextInputs(asset).map((input) => input.name);
|
|
620
|
+
}
|
|
621
|
+
function normalizeContextInput(input) {
|
|
622
|
+
if (typeof input === "string") {
|
|
623
|
+
return { name: input };
|
|
624
|
+
}
|
|
625
|
+
return {
|
|
626
|
+
name: input.name,
|
|
627
|
+
max_size: input.max_size,
|
|
628
|
+
trim: input.trim,
|
|
629
|
+
allow_regex: normalizeContextRegex(input.allow_regex),
|
|
630
|
+
deny_regex: normalizeContextRegex(input.deny_regex),
|
|
631
|
+
non_empty: input.non_empty,
|
|
632
|
+
reject_secrets: input.reject_secrets
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
function normalizeContextRegex(value) {
|
|
636
|
+
if (value === void 0) {
|
|
637
|
+
return void 0;
|
|
638
|
+
}
|
|
639
|
+
if (typeof value === "string") {
|
|
640
|
+
const literal = parseRegexLiteral(value);
|
|
641
|
+
if (value.startsWith("/") && !literal) {
|
|
642
|
+
return {
|
|
643
|
+
pattern: value,
|
|
644
|
+
flags: "",
|
|
645
|
+
raw: value,
|
|
646
|
+
invalidLiteral: true
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
return {
|
|
650
|
+
pattern: literal?.pattern ?? value,
|
|
651
|
+
flags: literal?.flags ?? "",
|
|
652
|
+
raw: value
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
return {
|
|
656
|
+
pattern: value.pattern,
|
|
657
|
+
flags: value.flags ?? "",
|
|
658
|
+
raw: JSON.stringify(value)
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
function parseRegexLiteral(value) {
|
|
662
|
+
if (!value.startsWith("/")) {
|
|
663
|
+
return void 0;
|
|
664
|
+
}
|
|
665
|
+
for (let index = value.length - 1; index > 0; index -= 1) {
|
|
666
|
+
if (value[index] !== "/") {
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
let backslashCount = 0;
|
|
670
|
+
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
|
|
671
|
+
backslashCount += 1;
|
|
672
|
+
}
|
|
673
|
+
if (backslashCount % 2 === 1) {
|
|
674
|
+
continue;
|
|
675
|
+
}
|
|
676
|
+
return {
|
|
677
|
+
pattern: value.slice(1, index),
|
|
678
|
+
flags: value.slice(index + 1)
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
return void 0;
|
|
682
|
+
}
|
|
683
|
+
function formatInvalidContextRegexMessage(details) {
|
|
684
|
+
return [
|
|
685
|
+
`Invalid context regex for prompt "${details.promptId}"`,
|
|
686
|
+
`variable "${details.variable}"`,
|
|
687
|
+
`field "${details.field}"`,
|
|
688
|
+
`value ${JSON.stringify(details.raw)}: ${details.reason}`
|
|
689
|
+
].join(", ");
|
|
690
|
+
}
|
|
691
|
+
function compileContextRegex(regex, details) {
|
|
692
|
+
if (regex.invalidLiteral) {
|
|
693
|
+
throw new Error(
|
|
694
|
+
`POK013: ${formatInvalidContextRegexMessage({
|
|
695
|
+
...details,
|
|
696
|
+
raw: regex.raw,
|
|
697
|
+
reason: "Malformed regex literal. Use /pattern/flags or { pattern, flags }."
|
|
698
|
+
})}`
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
try {
|
|
702
|
+
return new RegExp(regex.pattern, regex.flags);
|
|
703
|
+
} catch (error) {
|
|
704
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
705
|
+
throw new Error(`POK013: ${formatInvalidContextRegexMessage({ ...details, raw: regex.raw, reason })}`);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
function getRejectSecretsRegex() {
|
|
709
|
+
return {
|
|
710
|
+
pattern: REJECT_SECRETS_PATTERN,
|
|
711
|
+
flags: REJECT_SECRETS_FLAGS,
|
|
712
|
+
raw: JSON.stringify({ pattern: REJECT_SECRETS_PATTERN, flags: REJECT_SECRETS_FLAGS })
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
function isTrimEnabled(mode) {
|
|
716
|
+
return mode === true || mode === "start" || mode === "end" || mode === "both";
|
|
717
|
+
}
|
|
718
|
+
function normalizeTrimMode(mode) {
|
|
719
|
+
if (mode === "start") {
|
|
720
|
+
return "start";
|
|
721
|
+
}
|
|
722
|
+
return "end";
|
|
723
|
+
}
|
|
724
|
+
function trimToMaxSize(value, maxSize, mode) {
|
|
725
|
+
const measured = measureContextValueSize(value);
|
|
726
|
+
if (measured <= maxSize) {
|
|
727
|
+
return value;
|
|
728
|
+
}
|
|
729
|
+
const characters = Array.from(value);
|
|
730
|
+
const normalizedMode = normalizeTrimMode(mode);
|
|
731
|
+
if (normalizedMode === "start") {
|
|
732
|
+
let collected2 = "";
|
|
733
|
+
let size2 = 0;
|
|
734
|
+
for (let i = characters.length - 1; i >= 0; i -= 1) {
|
|
735
|
+
const next = characters[i];
|
|
736
|
+
const charSize = measureContextValueSize(next);
|
|
737
|
+
if (size2 + charSize > maxSize) {
|
|
738
|
+
break;
|
|
739
|
+
}
|
|
740
|
+
collected2 = next + collected2;
|
|
741
|
+
size2 += charSize;
|
|
742
|
+
}
|
|
743
|
+
return collected2;
|
|
744
|
+
}
|
|
745
|
+
let collected = "";
|
|
746
|
+
let size = 0;
|
|
747
|
+
for (const char of characters) {
|
|
748
|
+
const charSize = measureContextValueSize(char);
|
|
749
|
+
if (size + charSize > maxSize) {
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
752
|
+
collected += char;
|
|
753
|
+
size += charSize;
|
|
754
|
+
}
|
|
755
|
+
return collected;
|
|
756
|
+
}
|
|
757
|
+
function sanitizeContextVariables(asset, variables = {}, options = {}) {
|
|
758
|
+
const { onContextOverflow } = options;
|
|
759
|
+
const sanitized = { ...variables };
|
|
760
|
+
for (const input of getContextInputs(asset)) {
|
|
761
|
+
const value = sanitized[input.name];
|
|
762
|
+
if (value === void 0) {
|
|
763
|
+
continue;
|
|
764
|
+
}
|
|
765
|
+
let candidate = value;
|
|
766
|
+
if (input.max_size !== void 0) {
|
|
767
|
+
const actualSize = measureContextValueSize(candidate);
|
|
768
|
+
if (actualSize > input.max_size && onContextOverflow) {
|
|
769
|
+
candidate = onContextOverflow({
|
|
770
|
+
promptId: asset.id,
|
|
771
|
+
variable: input.name,
|
|
772
|
+
value: candidate,
|
|
773
|
+
maxSize: input.max_size,
|
|
774
|
+
actualSize
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
if (isTrimEnabled(input.trim) && input.max_size !== void 0) {
|
|
779
|
+
candidate = trimToMaxSize(candidate, input.max_size, input.trim);
|
|
780
|
+
}
|
|
781
|
+
sanitized[input.name] = candidate;
|
|
782
|
+
if (input.allow_regex) {
|
|
783
|
+
const candidate2 = sanitized[input.name];
|
|
784
|
+
const matcher = compileContextRegex(input.allow_regex, {
|
|
785
|
+
promptId: asset.id,
|
|
786
|
+
variable: input.name,
|
|
787
|
+
field: "allow_regex"
|
|
788
|
+
});
|
|
789
|
+
if (!matcher.test(candidate2)) {
|
|
790
|
+
throw new Error(
|
|
791
|
+
`POK031: Context variable "${input.name}" failed allow_regex validation for prompt "${asset.id}".`
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
if (input.deny_regex) {
|
|
796
|
+
const candidate2 = sanitized[input.name];
|
|
797
|
+
const matcher = compileContextRegex(input.deny_regex, {
|
|
798
|
+
promptId: asset.id,
|
|
799
|
+
variable: input.name,
|
|
800
|
+
field: "deny_regex"
|
|
801
|
+
});
|
|
802
|
+
if (matcher.test(candidate2)) {
|
|
803
|
+
throw new Error(
|
|
804
|
+
`POK032: Context variable "${input.name}" matched deny_regex for prompt "${asset.id}".`
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
if (input.non_empty && candidate.trim().length === 0) {
|
|
809
|
+
throw new Error(
|
|
810
|
+
`POK033: Context variable "${input.name}" failed non_empty validation for prompt "${asset.id}".`
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
if (input.reject_secrets) {
|
|
814
|
+
const matcher = compileContextRegex(getRejectSecretsRegex(), {
|
|
815
|
+
promptId: asset.id,
|
|
816
|
+
variable: input.name,
|
|
817
|
+
field: "reject_secrets"
|
|
818
|
+
});
|
|
819
|
+
if (matcher.test(candidate)) {
|
|
820
|
+
throw new Error(
|
|
821
|
+
`POK034: Context variable "${input.name}" matched reject_secrets validation for prompt "${asset.id}".`
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
return sanitized;
|
|
827
|
+
}
|
|
828
|
+
function measureContextValueSize(value) {
|
|
829
|
+
return textEncoder.encode(value).length;
|
|
830
|
+
}
|
|
831
|
+
function collectContextSizeWarnings(asset, variables = {}) {
|
|
832
|
+
const warnings = [];
|
|
833
|
+
for (const input of getContextInputs(asset)) {
|
|
834
|
+
if (input.max_size === void 0) {
|
|
835
|
+
continue;
|
|
836
|
+
}
|
|
837
|
+
const value = variables[input.name];
|
|
838
|
+
if (value === void 0) {
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
841
|
+
const actualSize = measureContextValueSize(value);
|
|
842
|
+
if (actualSize > input.max_size) {
|
|
843
|
+
warnings.push({
|
|
844
|
+
variable: input.name,
|
|
845
|
+
maxSize: input.max_size,
|
|
846
|
+
actualSize
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
return warnings;
|
|
851
|
+
}
|
|
852
|
+
|
|
599
853
|
// src/providers/prompt-input.ts
|
|
600
854
|
function isPromptLookup(input) {
|
|
601
855
|
return "path" in input && typeof input.path === "string";
|
|
@@ -619,7 +873,13 @@ function withPromptInputSupport(adapter) {
|
|
|
619
873
|
};
|
|
620
874
|
const renderPrompt2 = async (input, runtime) => {
|
|
621
875
|
const resolved = await resolveProviderPromptInput(input, runtime);
|
|
622
|
-
|
|
876
|
+
const variables = sanitizeContextVariables(resolved, runtime.variables, {
|
|
877
|
+
onContextOverflow: runtime.onContextOverflow
|
|
878
|
+
});
|
|
879
|
+
return adapter.render(resolved, {
|
|
880
|
+
...runtime,
|
|
881
|
+
variables
|
|
882
|
+
});
|
|
623
883
|
};
|
|
624
884
|
return {
|
|
625
885
|
...adapter,
|
|
@@ -906,48 +1166,6 @@ function getAdapter(provider) {
|
|
|
906
1166
|
return adapter;
|
|
907
1167
|
}
|
|
908
1168
|
|
|
909
|
-
// src/context.ts
|
|
910
|
-
var textEncoder = new TextEncoder();
|
|
911
|
-
function getContextInputs(asset) {
|
|
912
|
-
return (asset.context?.inputs ?? []).map(normalizeContextInput);
|
|
913
|
-
}
|
|
914
|
-
function getContextInputNames(asset) {
|
|
915
|
-
return getContextInputs(asset).map((input) => input.name);
|
|
916
|
-
}
|
|
917
|
-
function normalizeContextInput(input) {
|
|
918
|
-
if (typeof input === "string") {
|
|
919
|
-
return { name: input };
|
|
920
|
-
}
|
|
921
|
-
return {
|
|
922
|
-
name: input.name,
|
|
923
|
-
max_size: input.max_size
|
|
924
|
-
};
|
|
925
|
-
}
|
|
926
|
-
function measureContextValueSize(value) {
|
|
927
|
-
return textEncoder.encode(value).length;
|
|
928
|
-
}
|
|
929
|
-
function collectContextSizeWarnings(asset, variables = {}) {
|
|
930
|
-
const warnings = [];
|
|
931
|
-
for (const input of getContextInputs(asset)) {
|
|
932
|
-
if (input.max_size === void 0) {
|
|
933
|
-
continue;
|
|
934
|
-
}
|
|
935
|
-
const value = variables[input.name];
|
|
936
|
-
if (value === void 0) {
|
|
937
|
-
continue;
|
|
938
|
-
}
|
|
939
|
-
const actualSize = measureContextValueSize(value);
|
|
940
|
-
if (actualSize > input.max_size) {
|
|
941
|
-
warnings.push({
|
|
942
|
-
variable: input.name,
|
|
943
|
-
maxSize: input.max_size,
|
|
944
|
-
actualSize
|
|
945
|
-
});
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
return warnings;
|
|
949
|
-
}
|
|
950
|
-
|
|
951
1169
|
// src/validation/levenshtein.ts
|
|
952
1170
|
function levenshtein(a, b) {
|
|
953
1171
|
const m = a.length;
|
|
@@ -1059,6 +1277,34 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
1059
1277
|
});
|
|
1060
1278
|
}
|
|
1061
1279
|
}
|
|
1280
|
+
for (const input of getContextInputs(asset)) {
|
|
1281
|
+
if (input.trim !== void 0 && input.trim !== false && input.max_size === void 0) {
|
|
1282
|
+
warnings.push({
|
|
1283
|
+
code: "POK014",
|
|
1284
|
+
message: `Context input "${input.name}" sets trim but has no max_size; trim-to-budget will be skipped.`,
|
|
1285
|
+
filePath
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
const checks = [];
|
|
1289
|
+
if (input.allow_regex) checks.push({ regex: input.allow_regex, kind: "allow_regex" });
|
|
1290
|
+
if (input.deny_regex) checks.push({ regex: input.deny_regex, kind: "deny_regex" });
|
|
1291
|
+
for (const check of checks) {
|
|
1292
|
+
try {
|
|
1293
|
+
compileContextRegex(check.regex, {
|
|
1294
|
+
promptId: asset.id,
|
|
1295
|
+
variable: input.name,
|
|
1296
|
+
field: check.kind
|
|
1297
|
+
});
|
|
1298
|
+
} catch (error) {
|
|
1299
|
+
const reason = error instanceof Error ? error.message.replace(/^POK013:\s*/, "") : String(error);
|
|
1300
|
+
errors.push({
|
|
1301
|
+
code: "POK013",
|
|
1302
|
+
message: reason,
|
|
1303
|
+
filePath
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1062
1308
|
return {
|
|
1063
1309
|
valid: errors.length === 0,
|
|
1064
1310
|
errors,
|
|
@@ -1540,7 +1786,10 @@ var PromptOpsKit = class {
|
|
|
1540
1786
|
` + validation.errors.map((e) => ` - ${e}`).join("\n")
|
|
1541
1787
|
);
|
|
1542
1788
|
}
|
|
1543
|
-
const
|
|
1789
|
+
const sanitizedVariables = sanitizeContextVariables(resolved, options.variables, {
|
|
1790
|
+
onContextOverflow: options.onContextOverflow
|
|
1791
|
+
});
|
|
1792
|
+
const contextSizeWarnings = collectContextSizeWarnings(resolved, sanitizedVariables).map(
|
|
1544
1793
|
(warning) => formatContextSizeWarning(resolved, warning)
|
|
1545
1794
|
);
|
|
1546
1795
|
const contextWarningPolicy = this.config.warnings?.contextSize;
|
|
@@ -1550,7 +1799,7 @@ var PromptOpsKit = class {
|
|
|
1550
1799
|
}
|
|
1551
1800
|
}
|
|
1552
1801
|
const request = adapter.render(resolved, {
|
|
1553
|
-
variables:
|
|
1802
|
+
variables: sanitizedVariables,
|
|
1554
1803
|
history: options.history,
|
|
1555
1804
|
toolRegistry: options.toolRegistry,
|
|
1556
1805
|
strict: options.strict
|