promptopskit 0.7.1 → 0.8.1
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 +39 -4
- package/SKILL.md +152 -2
- package/dist/{chunk-OWMP5NMV.js → chunk-5XH2GROP.js} +2 -2
- package/dist/{chunk-FICB2ZSK.js → chunk-DI7Q4T7A.js} +3 -3
- package/dist/{chunk-ULVY473P.js → chunk-E4GEKWVP.js} +31 -3
- package/dist/chunk-E4GEKWVP.js.map +1 -0
- package/dist/{chunk-3G3EAV7H.js → chunk-PDVUVZAU.js} +2 -2
- package/dist/chunk-RVAFVWR2.js +1760 -0
- package/dist/chunk-RVAFVWR2.js.map +1 -0
- package/dist/{chunk-35NN5F6O.js → chunk-UQLAWU67.js} +2 -2
- package/dist/{chunk-6NOUETAC.js → chunk-Z3DPPJNU.js} +2 -2
- package/dist/{chunk-R65RAHAG.js → chunk-ZVCKP4EM.js} +3 -3
- package/dist/cli/index.js +86 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +964 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -5
- package/dist/index.d.ts +45 -5
- package/dist/index.js +18 -10
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic.cjs +954 -42
- 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 +954 -42
- package/dist/providers/gemini.cjs.map +1 -1
- package/dist/providers/gemini.d.cts +2 -2
- package/dist/providers/gemini.d.ts +2 -2
- package/dist/providers/gemini.js +3 -3
- package/dist/providers/llmasaservice.cjs +954 -42
- package/dist/providers/llmasaservice.cjs.map +1 -1
- package/dist/providers/llmasaservice.d.cts +2 -2
- package/dist/providers/llmasaservice.d.ts +2 -2
- package/dist/providers/llmasaservice.js +4 -4
- package/dist/providers/openai-responses.cjs +954 -42
- 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 +954 -42
- 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 +954 -42
- 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-DBcSns_b.d.cts → schema-BgVLZ2u5.d.cts} +641 -0
- package/dist/{schema-DBcSns_b.d.ts → schema-BgVLZ2u5.d.ts} +641 -0
- package/dist/testing.cjs +27 -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-BlLXT5Qb.d.ts → types-2hnZmCkH.d.cts} +16 -3
- package/dist/{types-8T2D5KB5.d.cts → types-DgAT4jSR.d.ts} +16 -3
- package/dist/usagetap/index.d.cts +2 -2
- package/dist/usagetap/index.d.ts +2 -2
- package/package.json +1 -1
- package/dist/chunk-F552OBUV.js +0 -875
- package/dist/chunk-F552OBUV.js.map +0 -1
- package/dist/chunk-ULVY473P.js.map +0 -1
- /package/dist/{chunk-OWMP5NMV.js.map → chunk-5XH2GROP.js.map} +0 -0
- /package/dist/{chunk-FICB2ZSK.js.map → chunk-DI7Q4T7A.js.map} +0 -0
- /package/dist/{chunk-3G3EAV7H.js.map → chunk-PDVUVZAU.js.map} +0 -0
- /package/dist/{chunk-35NN5F6O.js.map → chunk-UQLAWU67.js.map} +0 -0
- /package/dist/{chunk-6NOUETAC.js.map → chunk-Z3DPPJNU.js.map} +0 -0
- /package/dist/{chunk-R65RAHAG.js.map → chunk-ZVCKP4EM.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -69,6 +69,7 @@ __export(src_exports, {
|
|
|
69
69
|
runLLMAsAServiceWithUsageTap: () => runLLMAsAServiceWithUsageTap,
|
|
70
70
|
runOpenAIWithUsageTap: () => runOpenAIWithUsageTap,
|
|
71
71
|
runOpenRouterWithUsageTap: () => runOpenRouterWithUsageTap,
|
|
72
|
+
summarizePromptCompression: () => summarizePromptCompression,
|
|
72
73
|
validateAsset: () => validateAsset,
|
|
73
74
|
validateAssetWithIncludes: () => validateAssetWithIncludes,
|
|
74
75
|
withUsageTapCall: () => withUsageTapCall
|
|
@@ -77,16 +78,17 @@ module.exports = __toCommonJS(src_exports);
|
|
|
77
78
|
var import_node_path5 = require("path");
|
|
78
79
|
|
|
79
80
|
// src/renderer/interpolate.ts
|
|
80
|
-
var VARIABLE_RE = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)
|
|
81
|
+
var VARIABLE_RE = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)(?:\s*\|\s*(compress|toon|compact|code))?\s*\}\}/g;
|
|
81
82
|
var ESCAPED_OPEN = /\\\{\\\{/g;
|
|
82
83
|
var ESCAPE_PLACEHOLDER = "\0ESCAPED_OPEN\0";
|
|
83
84
|
function interpolate(template, variables, options = {}) {
|
|
84
85
|
const { strict = false } = options;
|
|
85
86
|
const optionalVariables = new Set(options.optionalVariables ?? []);
|
|
86
87
|
let result = template.replace(ESCAPED_OPEN, ESCAPE_PLACEHOLDER);
|
|
87
|
-
result = result.replace(VARIABLE_RE, (match, name) => {
|
|
88
|
+
result = result.replace(VARIABLE_RE, (match, name, modifier) => {
|
|
88
89
|
if (name in variables) {
|
|
89
|
-
|
|
90
|
+
const value = variables[name];
|
|
91
|
+
return options.transformVariable ? options.transformVariable({ name, value, modifier, match }) : value;
|
|
90
92
|
}
|
|
91
93
|
if (strict && !optionalVariables.has(name)) {
|
|
92
94
|
throw new Error(`Missing required variable: "${name}"`);
|
|
@@ -123,12 +125,56 @@ function normalizeContextInput(input) {
|
|
|
123
125
|
warnings: input.warnings,
|
|
124
126
|
max_size: input.max_size,
|
|
125
127
|
trim: input.trim,
|
|
128
|
+
compression: normalizeContextInputCompression(input.compression),
|
|
126
129
|
allow_regex: normalizeContextRegex(input.allow_regex),
|
|
127
130
|
deny_regex: normalizeContextRegex(input.deny_regex),
|
|
128
131
|
non_empty: normalizeBuiltInValidator(input.non_empty),
|
|
129
132
|
reject_secrets: normalizeBuiltInValidator(input.reject_secrets)
|
|
130
133
|
};
|
|
131
134
|
}
|
|
135
|
+
function normalizeContextInputCompression(value) {
|
|
136
|
+
if (value === void 0) {
|
|
137
|
+
return void 0;
|
|
138
|
+
}
|
|
139
|
+
if (value === "heuristic") {
|
|
140
|
+
return { heuristic: { enabled: true } };
|
|
141
|
+
}
|
|
142
|
+
if (value === "code") {
|
|
143
|
+
return { code: { enabled: true } };
|
|
144
|
+
}
|
|
145
|
+
if (value.heuristic === void 0) {
|
|
146
|
+
return normalizeCodeCompression(value.code);
|
|
147
|
+
}
|
|
148
|
+
const normalized = {
|
|
149
|
+
heuristic: {
|
|
150
|
+
enabled: value.heuristic.enabled ?? true,
|
|
151
|
+
min_tokens: value.heuristic.min_tokens,
|
|
152
|
+
max_sentences: value.heuristic.max_sentences,
|
|
153
|
+
target_reduction: value.heuristic.target_reduction,
|
|
154
|
+
query: value.heuristic.query,
|
|
155
|
+
query_variable: value.heuristic.query_variable,
|
|
156
|
+
json_to_toon: value.heuristic.json_to_toon
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
const code = normalizeCodeCompression(value.code);
|
|
160
|
+
if (code?.code) {
|
|
161
|
+
normalized.code = code.code;
|
|
162
|
+
}
|
|
163
|
+
return normalized;
|
|
164
|
+
}
|
|
165
|
+
function normalizeCodeCompression(value) {
|
|
166
|
+
if (value === void 0) {
|
|
167
|
+
return void 0;
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
code: {
|
|
171
|
+
enabled: value.enabled ?? true,
|
|
172
|
+
remove_comments: value.remove_comments,
|
|
173
|
+
trim_indentation: value.trim_indentation,
|
|
174
|
+
collapse_blank_lines: value.collapse_blank_lines
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
132
178
|
function areContextInputWarningsEnabled(input) {
|
|
133
179
|
return input.warnings !== false;
|
|
134
180
|
}
|
|
@@ -409,27 +455,703 @@ function collectContextSizeWarnings(asset, variables = {}) {
|
|
|
409
455
|
return warnings;
|
|
410
456
|
}
|
|
411
457
|
|
|
458
|
+
// src/toon-encoding.ts
|
|
459
|
+
var DEFAULT_INDENT = 2;
|
|
460
|
+
var DEFAULT_DELIMITER = ",";
|
|
461
|
+
function tryJsonToToon(text, options = {}) {
|
|
462
|
+
const trimmed = text.trim();
|
|
463
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
|
|
464
|
+
return void 0;
|
|
465
|
+
}
|
|
466
|
+
let parsed;
|
|
467
|
+
try {
|
|
468
|
+
parsed = JSON.parse(trimmed);
|
|
469
|
+
} catch {
|
|
470
|
+
return void 0;
|
|
471
|
+
}
|
|
472
|
+
const value = normalizeJsonValue(parsed);
|
|
473
|
+
if (value === void 0) {
|
|
474
|
+
return void 0;
|
|
475
|
+
}
|
|
476
|
+
return {
|
|
477
|
+
output: encodeToon(value, options),
|
|
478
|
+
value
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
function encodeToon(value, options = {}) {
|
|
482
|
+
const resolved = {
|
|
483
|
+
indent: options.indent ?? DEFAULT_INDENT,
|
|
484
|
+
delimiter: options.delimiter ?? DEFAULT_DELIMITER
|
|
485
|
+
};
|
|
486
|
+
return encodeValue(value, void 0, 0, resolved).join("\n");
|
|
487
|
+
}
|
|
488
|
+
function normalizeJsonValue(value) {
|
|
489
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
490
|
+
return value;
|
|
491
|
+
}
|
|
492
|
+
if (typeof value === "number") {
|
|
493
|
+
return Number.isFinite(value) ? value : null;
|
|
494
|
+
}
|
|
495
|
+
if (Array.isArray(value)) {
|
|
496
|
+
return value.map((item) => normalizeJsonValue(item) ?? null);
|
|
497
|
+
}
|
|
498
|
+
if (isPlainObject(value)) {
|
|
499
|
+
const normalized = {};
|
|
500
|
+
for (const [key, child] of Object.entries(value)) {
|
|
501
|
+
normalized[key] = normalizeJsonValue(child) ?? null;
|
|
502
|
+
}
|
|
503
|
+
return normalized;
|
|
504
|
+
}
|
|
505
|
+
return void 0;
|
|
506
|
+
}
|
|
507
|
+
function encodeValue(value, key, depth, options) {
|
|
508
|
+
if (isPrimitive(value)) {
|
|
509
|
+
return [line(depth, key === void 0 ? encodePrimitive(value, options.delimiter) : `${encodeKey(key)}: ${encodePrimitive(value, options.delimiter)}`, options.indent)];
|
|
510
|
+
}
|
|
511
|
+
if (Array.isArray(value)) {
|
|
512
|
+
return encodeArray(value, key, depth, options);
|
|
513
|
+
}
|
|
514
|
+
return encodeObject(value, key, depth, options);
|
|
515
|
+
}
|
|
516
|
+
function encodeObject(value, key, depth, options) {
|
|
517
|
+
const entries = Object.entries(value);
|
|
518
|
+
const lines = [];
|
|
519
|
+
if (key !== void 0) {
|
|
520
|
+
lines.push(line(depth, `${encodeKey(key)}:`, options.indent));
|
|
521
|
+
}
|
|
522
|
+
const childDepth = key === void 0 ? depth : depth + 1;
|
|
523
|
+
for (const [childKey, childValue] of entries) {
|
|
524
|
+
lines.push(...encodeValue(childValue, childKey, childDepth, options));
|
|
525
|
+
}
|
|
526
|
+
return lines;
|
|
527
|
+
}
|
|
528
|
+
function encodeArray(value, key, depth, options) {
|
|
529
|
+
const prefix = key === void 0 ? "" : encodeKey(key);
|
|
530
|
+
if (value.length === 0) {
|
|
531
|
+
return [line(depth, key === void 0 ? "[]" : `${prefix}: []`, options.indent)];
|
|
532
|
+
}
|
|
533
|
+
if (value.every(isPrimitive)) {
|
|
534
|
+
const joined = value.map((item) => encodePrimitive(item, options.delimiter)).join(options.delimiter);
|
|
535
|
+
return [line(depth, `${prefix}[${value.length}]: ${joined}`, options.indent)];
|
|
536
|
+
}
|
|
537
|
+
const tabularFields = getTabularFields(value);
|
|
538
|
+
if (tabularFields) {
|
|
539
|
+
const lines2 = [
|
|
540
|
+
line(depth, `${prefix}[${value.length}]{${tabularFields.map(encodeKey).join(options.delimiter)}}:`, options.indent)
|
|
541
|
+
];
|
|
542
|
+
for (const row of value) {
|
|
543
|
+
lines2.push(line(depth + 1, tabularFields.map((field) => encodePrimitive(row[field], options.delimiter)).join(options.delimiter), options.indent));
|
|
544
|
+
}
|
|
545
|
+
return lines2;
|
|
546
|
+
}
|
|
547
|
+
const lines = [line(depth, `${prefix}[${value.length}]:`, options.indent)];
|
|
548
|
+
for (const item of value) {
|
|
549
|
+
lines.push(...encodeListItem(item, depth + 1, options));
|
|
550
|
+
}
|
|
551
|
+
return lines;
|
|
552
|
+
}
|
|
553
|
+
function encodeListItem(value, depth, options) {
|
|
554
|
+
if (isPrimitive(value)) {
|
|
555
|
+
return [line(depth, `- ${encodePrimitive(value, options.delimiter)}`, options.indent)];
|
|
556
|
+
}
|
|
557
|
+
if (Array.isArray(value)) {
|
|
558
|
+
const encoded = encodeArray(value, void 0, depth, options);
|
|
559
|
+
return encoded.map((item, index) => {
|
|
560
|
+
if (index === 0) {
|
|
561
|
+
return line(depth, `- ${item.trimStart()}`, options.indent);
|
|
562
|
+
}
|
|
563
|
+
return item;
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
const entries = Object.entries(value);
|
|
567
|
+
if (entries.length === 0) {
|
|
568
|
+
return [line(depth, "-", options.indent)];
|
|
569
|
+
}
|
|
570
|
+
const [firstKey, firstValue] = entries[0];
|
|
571
|
+
const rest = Object.fromEntries(entries.slice(1));
|
|
572
|
+
const firstLines = encodeValue(firstValue, firstKey, depth, options);
|
|
573
|
+
const lines = [line(depth, `- ${firstLines[0].trimStart()}`, options.indent)];
|
|
574
|
+
for (const continuation of firstLines.slice(1)) {
|
|
575
|
+
lines.push(continuation);
|
|
576
|
+
}
|
|
577
|
+
if (Object.keys(rest).length > 0) {
|
|
578
|
+
lines.push(...encodeObject(rest, void 0, depth + 1, options));
|
|
579
|
+
}
|
|
580
|
+
return lines;
|
|
581
|
+
}
|
|
582
|
+
function getTabularFields(value) {
|
|
583
|
+
if (value.length === 0 || !value.every(isObjectRecord)) {
|
|
584
|
+
return void 0;
|
|
585
|
+
}
|
|
586
|
+
const first = value[0];
|
|
587
|
+
const fields = Object.keys(first);
|
|
588
|
+
if (fields.length === 0) {
|
|
589
|
+
return void 0;
|
|
590
|
+
}
|
|
591
|
+
for (const row of value) {
|
|
592
|
+
const keys = Object.keys(row);
|
|
593
|
+
if (keys.length !== fields.length) {
|
|
594
|
+
return void 0;
|
|
595
|
+
}
|
|
596
|
+
for (const field of fields) {
|
|
597
|
+
if (!(field in row) || !isPrimitive(row[field])) {
|
|
598
|
+
return void 0;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return fields;
|
|
603
|
+
}
|
|
604
|
+
function encodePrimitive(value, delimiter) {
|
|
605
|
+
if (value === null) {
|
|
606
|
+
return "null";
|
|
607
|
+
}
|
|
608
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
609
|
+
return String(value);
|
|
610
|
+
}
|
|
611
|
+
return encodeString(value, delimiter);
|
|
612
|
+
}
|
|
613
|
+
function encodeString(value, delimiter) {
|
|
614
|
+
if (isSafeUnquotedString(value, delimiter)) {
|
|
615
|
+
return value;
|
|
616
|
+
}
|
|
617
|
+
return JSON.stringify(value);
|
|
618
|
+
}
|
|
619
|
+
function encodeKey(key) {
|
|
620
|
+
if (/^[A-Z_][\w.]*$/i.test(key)) {
|
|
621
|
+
return key;
|
|
622
|
+
}
|
|
623
|
+
return JSON.stringify(key);
|
|
624
|
+
}
|
|
625
|
+
function isSafeUnquotedString(value, delimiter) {
|
|
626
|
+
if (value.length === 0 || value !== value.trim()) {
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
if (/^(?:true|false|null)$/i.test(value) || /^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i.test(value) || /^0\d+$/.test(value)) {
|
|
630
|
+
return false;
|
|
631
|
+
}
|
|
632
|
+
if (value.includes(":") || value.includes('"') || value.includes("\\") || value.includes(delimiter)) {
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
if (/[[\]{}]|[\u0000-\u001F]/.test(value) || value.startsWith("-")) {
|
|
636
|
+
return false;
|
|
637
|
+
}
|
|
638
|
+
return true;
|
|
639
|
+
}
|
|
640
|
+
function isPrimitive(value) {
|
|
641
|
+
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
642
|
+
}
|
|
643
|
+
function isObjectRecord(value) {
|
|
644
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
645
|
+
}
|
|
646
|
+
function isPlainObject(value) {
|
|
647
|
+
if (value === null || typeof value !== "object") {
|
|
648
|
+
return false;
|
|
649
|
+
}
|
|
650
|
+
const prototype = Object.getPrototypeOf(value);
|
|
651
|
+
return prototype === null || prototype === Object.prototype;
|
|
652
|
+
}
|
|
653
|
+
function line(depth, content, indent) {
|
|
654
|
+
return `${" ".repeat(depth * indent)}${content}`;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// src/token-compression.ts
|
|
658
|
+
var TOKEN_REGEX = /[\p{L}\p{N}]+|[^\s]/gu;
|
|
659
|
+
var TOKEN_NORMALIZE_REGEX = /[^\p{L}\p{N}]/gu;
|
|
660
|
+
var DEDUPE_NORMALIZE_REGEX = /[^\p{L}\p{N}\s]/gu;
|
|
661
|
+
var BOILERPLATE_REGEX = /copyright|all rights reserved|disclaimer|confidential/i;
|
|
662
|
+
var MAX_SEGMENT_TOKENS = 120;
|
|
663
|
+
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
664
|
+
"a",
|
|
665
|
+
"an",
|
|
666
|
+
"and",
|
|
667
|
+
"are",
|
|
668
|
+
"as",
|
|
669
|
+
"at",
|
|
670
|
+
"be",
|
|
671
|
+
"by",
|
|
672
|
+
"for",
|
|
673
|
+
"from",
|
|
674
|
+
"how",
|
|
675
|
+
"in",
|
|
676
|
+
"is",
|
|
677
|
+
"it",
|
|
678
|
+
"of",
|
|
679
|
+
"on",
|
|
680
|
+
"or",
|
|
681
|
+
"that",
|
|
682
|
+
"the",
|
|
683
|
+
"this",
|
|
684
|
+
"to",
|
|
685
|
+
"was",
|
|
686
|
+
"we",
|
|
687
|
+
"with",
|
|
688
|
+
"you",
|
|
689
|
+
"your",
|
|
690
|
+
"our"
|
|
691
|
+
]);
|
|
692
|
+
var DEFAULT_OPTIONS = {
|
|
693
|
+
min_tokens: 80,
|
|
694
|
+
max_sentences: 10,
|
|
695
|
+
target_reduction: 0.45
|
|
696
|
+
};
|
|
697
|
+
function tokenizeForHeuristicCompression(text) {
|
|
698
|
+
if (!text) {
|
|
699
|
+
return [];
|
|
700
|
+
}
|
|
701
|
+
return text.match(TOKEN_REGEX) ?? [];
|
|
702
|
+
}
|
|
703
|
+
function estimateHeuristicTokens(text) {
|
|
704
|
+
return tokenizeForHeuristicCompression(text).length;
|
|
705
|
+
}
|
|
706
|
+
function compressHeuristicText(input, options = {}) {
|
|
707
|
+
const inputText = input ?? "";
|
|
708
|
+
const inputTokens = estimateHeuristicTokens(inputText);
|
|
709
|
+
if (options.json_to_toon === true) {
|
|
710
|
+
const toonResult = tryJsonToToon(inputText);
|
|
711
|
+
if (toonResult) {
|
|
712
|
+
const toonOutputTokens = estimateHeuristicTokens(toonResult.output);
|
|
713
|
+
if (toonOutputTokens <= inputTokens) {
|
|
714
|
+
return {
|
|
715
|
+
...toCompressionOutput(toonResult.output, inputTokens),
|
|
716
|
+
outputFormat: "toon"
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
return {
|
|
720
|
+
...toCompressionOutput(inputText, inputTokens),
|
|
721
|
+
warnings: ["JSON-to-TOON skipped because TOON was not smaller than the original JSON."]
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
return {
|
|
725
|
+
...toCompressionOutput(inputText, inputTokens),
|
|
726
|
+
warnings: ["JSON-to-TOON skipped because the input is not a complete valid JSON object or array."]
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
const analysis = preprocessContext(inputText);
|
|
730
|
+
if (inputTokens === 0) {
|
|
731
|
+
return toCompressionOutput(inputText, inputTokens);
|
|
732
|
+
}
|
|
733
|
+
const minTokens = options.min_tokens ?? DEFAULT_OPTIONS.min_tokens;
|
|
734
|
+
if (inputTokens <= minTokens) {
|
|
735
|
+
return toCompressionOutput(inputText, inputTokens);
|
|
736
|
+
}
|
|
737
|
+
const targetReduction = options.target_reduction ?? DEFAULT_OPTIONS.target_reduction;
|
|
738
|
+
const targetTokens = Math.max(1, Math.max(minTokens, Math.floor(inputTokens * (1 - targetReduction))));
|
|
739
|
+
const maxSentences = options.max_sentences ?? DEFAULT_OPTIONS.max_sentences;
|
|
740
|
+
const query = options.query ?? "";
|
|
741
|
+
const terms = queryTerms(query);
|
|
742
|
+
const scoredSentences = analysis.candidates.map((candidate) => ({
|
|
743
|
+
sentence: candidate.sentence,
|
|
744
|
+
index: candidate.index,
|
|
745
|
+
...scoreSentenceCandidate(candidate, terms),
|
|
746
|
+
tokens: candidate.tokenCount
|
|
747
|
+
}));
|
|
748
|
+
const selected = [];
|
|
749
|
+
const selectedIndices = /* @__PURE__ */ new Set();
|
|
750
|
+
const coveredTerms = /* @__PURE__ */ new Set();
|
|
751
|
+
let selectedTokens = 0;
|
|
752
|
+
while (selected.length < maxSentences) {
|
|
753
|
+
let bestCandidate;
|
|
754
|
+
let bestAdjustedScore = Number.NEGATIVE_INFINITY;
|
|
755
|
+
for (const candidate of scoredSentences) {
|
|
756
|
+
if (selectedIndices.has(candidate.index)) {
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
759
|
+
const underBudget = selectedTokens + candidate.tokens <= targetTokens;
|
|
760
|
+
const forceTopCandidate = selected.length === 0;
|
|
761
|
+
const forceRelevantSecond = selected.length === 1 && candidate.overlapCount > 0;
|
|
762
|
+
if (!underBudget && !forceTopCandidate && !forceRelevantSecond) {
|
|
763
|
+
continue;
|
|
764
|
+
}
|
|
765
|
+
let uncoveredOverlapCount = 0;
|
|
766
|
+
for (const term of candidate.overlapTerms) {
|
|
767
|
+
if (!coveredTerms.has(term)) {
|
|
768
|
+
uncoveredOverlapCount += 1;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
const adjustedScore = candidate.score + uncoveredOverlapCount * 1.2;
|
|
772
|
+
if (adjustedScore > bestAdjustedScore || adjustedScore === bestAdjustedScore && bestCandidate && isBetterTieBreak(candidate, bestCandidate)) {
|
|
773
|
+
bestAdjustedScore = adjustedScore;
|
|
774
|
+
bestCandidate = candidate;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
if (!bestCandidate) {
|
|
778
|
+
break;
|
|
779
|
+
}
|
|
780
|
+
selected.push(bestCandidate);
|
|
781
|
+
selectedIndices.add(bestCandidate.index);
|
|
782
|
+
selectedTokens += bestCandidate.tokens;
|
|
783
|
+
for (const term of bestCandidate.overlapTerms) {
|
|
784
|
+
coveredTerms.add(term);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
selected.sort((left, right) => left.index - right.index);
|
|
788
|
+
let output = selected.map((item) => item.sentence).join(" ");
|
|
789
|
+
if (!output) {
|
|
790
|
+
output = tokenizeForHeuristicCompression(inputText).slice(0, targetTokens).join(" ");
|
|
791
|
+
} else {
|
|
792
|
+
const outputTokens = tokenizeForHeuristicCompression(output);
|
|
793
|
+
if (outputTokens.length > targetTokens) {
|
|
794
|
+
output = outputTokens.slice(0, targetTokens).join(" ");
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return toCompressionOutput(output, inputTokens);
|
|
798
|
+
}
|
|
799
|
+
function toCompressionOutput(output, inputTokens) {
|
|
800
|
+
const outputTokens = estimateHeuristicTokens(output);
|
|
801
|
+
const tokensSaved = Math.max(0, inputTokens - outputTokens);
|
|
802
|
+
return {
|
|
803
|
+
output,
|
|
804
|
+
inputTokens,
|
|
805
|
+
outputTokens,
|
|
806
|
+
tokensSaved,
|
|
807
|
+
compressionRatio: outputTokens === 0 ? 0 : inputTokens / outputTokens
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
function isBetterTieBreak(candidate, bestCandidate) {
|
|
811
|
+
if (candidate.overlapCount !== bestCandidate.overlapCount) {
|
|
812
|
+
return candidate.overlapCount > bestCandidate.overlapCount;
|
|
813
|
+
}
|
|
814
|
+
if (candidate.tokens !== bestCandidate.tokens) {
|
|
815
|
+
return candidate.tokens < bestCandidate.tokens;
|
|
816
|
+
}
|
|
817
|
+
return candidate.index < bestCandidate.index;
|
|
818
|
+
}
|
|
819
|
+
function normalizeForDeduping(sentence) {
|
|
820
|
+
return sentence.toLowerCase().replace(DEDUPE_NORMALIZE_REGEX, " ").replace(/\s+/g, " ").trim();
|
|
821
|
+
}
|
|
822
|
+
function splitIntoSentences(text) {
|
|
823
|
+
return text.split(/(?<=[.!?])\s+|\n+/g).map((sentence) => sentence.trim()).filter(Boolean);
|
|
824
|
+
}
|
|
825
|
+
function chunkTokens(tokens, chunkSize) {
|
|
826
|
+
const chunks = [];
|
|
827
|
+
for (let index = 0; index < tokens.length; index += chunkSize) {
|
|
828
|
+
chunks.push(tokens.slice(index, index + chunkSize));
|
|
829
|
+
}
|
|
830
|
+
return chunks;
|
|
831
|
+
}
|
|
832
|
+
function splitOversizedSentence(sentence, maxTokens = MAX_SEGMENT_TOKENS) {
|
|
833
|
+
const rawTokens = tokenizeForHeuristicCompression(sentence);
|
|
834
|
+
if (rawTokens.length <= maxTokens) {
|
|
835
|
+
return [sentence];
|
|
836
|
+
}
|
|
837
|
+
const commaSplit = sentence.split(/(?<=[,;:])\s+|\s+-\s+/g).map((segment) => segment.trim()).filter(Boolean);
|
|
838
|
+
if (commaSplit.length > 1) {
|
|
839
|
+
return commaSplit.flatMap((segment) => {
|
|
840
|
+
if (estimateHeuristicTokens(segment) <= maxTokens) {
|
|
841
|
+
return [segment];
|
|
842
|
+
}
|
|
843
|
+
return chunkTokens(tokenizeForHeuristicCompression(segment), maxTokens).map((chunk) => chunk.join(" "));
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
return chunkTokens(rawTokens, maxTokens).map((chunk) => chunk.join(" "));
|
|
847
|
+
}
|
|
848
|
+
function normalizeToken(token) {
|
|
849
|
+
return token.replace(TOKEN_NORMALIZE_REGEX, "").trim();
|
|
850
|
+
}
|
|
851
|
+
function tokenizeNormalized(text) {
|
|
852
|
+
return tokenizeForHeuristicCompression(text.toLowerCase()).map(normalizeToken).filter(Boolean);
|
|
853
|
+
}
|
|
854
|
+
function queryTerms(query) {
|
|
855
|
+
return new Set(tokenizeNormalized(query).filter((term) => term.length >= 3 && !STOP_WORDS.has(term)));
|
|
856
|
+
}
|
|
857
|
+
function preprocessContext(context) {
|
|
858
|
+
const originalTokens = estimateHeuristicTokens(context);
|
|
859
|
+
const dedupeSet = /* @__PURE__ */ new Set();
|
|
860
|
+
const candidates = [];
|
|
861
|
+
for (const sentence of splitIntoSentences(context)) {
|
|
862
|
+
for (const segment of splitOversizedSentence(sentence)) {
|
|
863
|
+
const normalized = normalizeForDeduping(segment);
|
|
864
|
+
if (!normalized || dedupeSet.has(normalized)) {
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
867
|
+
dedupeSet.add(normalized);
|
|
868
|
+
const rawTokens = tokenizeForHeuristicCompression(segment);
|
|
869
|
+
const normalizedTerms = rawTokens.map((token) => normalizeToken(token.toLowerCase())).filter(Boolean);
|
|
870
|
+
const lowered = segment.toLowerCase();
|
|
871
|
+
candidates.push({
|
|
872
|
+
sentence: segment,
|
|
873
|
+
index: candidates.length,
|
|
874
|
+
tokenCount: rawTokens.length,
|
|
875
|
+
uniqueTerms: new Set(normalizedTerms),
|
|
876
|
+
isBoilerplate: BOILERPLATE_REGEX.test(lowered)
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
return { originalTokens, candidates };
|
|
881
|
+
}
|
|
882
|
+
function scoreSentenceCandidate(candidate, terms) {
|
|
883
|
+
if (candidate.tokenCount === 0) {
|
|
884
|
+
return {
|
|
885
|
+
score: 0,
|
|
886
|
+
overlapCount: 0,
|
|
887
|
+
overlapTerms: []
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
const overlapTerms = [];
|
|
891
|
+
let overlap = 0;
|
|
892
|
+
for (const term of terms) {
|
|
893
|
+
if (candidate.uniqueTerms.has(term)) {
|
|
894
|
+
overlap += 1;
|
|
895
|
+
overlapTerms.push(term);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
const overlapScore = overlap * 2;
|
|
899
|
+
const densityScore = terms.size > 0 ? overlap / terms.size : 0;
|
|
900
|
+
const lengthScore = Math.min(candidate.tokenCount, 40) / 40;
|
|
901
|
+
const boilerplatePenalty = candidate.isBoilerplate ? 0.5 : 0;
|
|
902
|
+
return {
|
|
903
|
+
score: overlapScore + densityScore + lengthScore - boilerplatePenalty,
|
|
904
|
+
overlapCount: overlap,
|
|
905
|
+
overlapTerms
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// src/code-compaction.ts
|
|
910
|
+
function compactCode(input, options = {}) {
|
|
911
|
+
const inputText = input ?? "";
|
|
912
|
+
const removeComments = options.remove_comments ?? true;
|
|
913
|
+
const trimIndentation = options.trim_indentation ?? true;
|
|
914
|
+
const collapseBlankLines = options.collapse_blank_lines ?? true;
|
|
915
|
+
let output = inputText.replace(/\r\n?/g, "\n");
|
|
916
|
+
if (removeComments) {
|
|
917
|
+
output = stripCodeComments(output);
|
|
918
|
+
}
|
|
919
|
+
output = output.split("\n").map((line2) => line2.replace(/[ \t]+$/g, "")).join("\n");
|
|
920
|
+
if (trimIndentation) {
|
|
921
|
+
output = stripCommonIndent(output);
|
|
922
|
+
}
|
|
923
|
+
if (collapseBlankLines) {
|
|
924
|
+
output = output.split("\n").filter((line2) => line2.trim().length > 0).join("\n");
|
|
925
|
+
}
|
|
926
|
+
output = output.trim();
|
|
927
|
+
const inputTokens = estimateHeuristicTokens(inputText);
|
|
928
|
+
const outputTokens = estimateHeuristicTokens(output);
|
|
929
|
+
return {
|
|
930
|
+
output,
|
|
931
|
+
inputTokens,
|
|
932
|
+
outputTokens,
|
|
933
|
+
tokensSaved: Math.max(0, inputTokens - outputTokens),
|
|
934
|
+
compressionRatio: outputTokens === 0 ? 0 : inputTokens / outputTokens
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
function stripCommonIndent(input) {
|
|
938
|
+
const lines = input.split("\n");
|
|
939
|
+
const nonEmptyLines = lines.filter((line2) => line2.trim().length > 0);
|
|
940
|
+
if (nonEmptyLines.length === 0) {
|
|
941
|
+
return "";
|
|
942
|
+
}
|
|
943
|
+
const commonIndent = Math.min(
|
|
944
|
+
...nonEmptyLines.map((line2) => {
|
|
945
|
+
const match = line2.match(/^[ \t]*/);
|
|
946
|
+
return match?.[0].length ?? 0;
|
|
947
|
+
})
|
|
948
|
+
);
|
|
949
|
+
if (commonIndent === 0) {
|
|
950
|
+
return input;
|
|
951
|
+
}
|
|
952
|
+
return lines.map((line2) => line2.slice(commonIndent)).join("\n");
|
|
953
|
+
}
|
|
954
|
+
function stripCodeComments(input) {
|
|
955
|
+
let output = "";
|
|
956
|
+
let index = 0;
|
|
957
|
+
let quote;
|
|
958
|
+
let escaped = false;
|
|
959
|
+
let atLineStart = true;
|
|
960
|
+
while (index < input.length) {
|
|
961
|
+
const char = input[index];
|
|
962
|
+
const next = input[index + 1];
|
|
963
|
+
if (quote) {
|
|
964
|
+
output += char;
|
|
965
|
+
if (escaped) {
|
|
966
|
+
escaped = false;
|
|
967
|
+
} else if (char === "\\") {
|
|
968
|
+
escaped = true;
|
|
969
|
+
} else if (char === quote) {
|
|
970
|
+
quote = void 0;
|
|
971
|
+
}
|
|
972
|
+
atLineStart = char === "\n";
|
|
973
|
+
index += 1;
|
|
974
|
+
continue;
|
|
975
|
+
}
|
|
976
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
977
|
+
quote = char;
|
|
978
|
+
output += char;
|
|
979
|
+
atLineStart = false;
|
|
980
|
+
index += 1;
|
|
981
|
+
continue;
|
|
982
|
+
}
|
|
983
|
+
if (atLineStart && char === "#" && next === "!") {
|
|
984
|
+
while (index < input.length && input[index] !== "\n") {
|
|
985
|
+
output += input[index];
|
|
986
|
+
index += 1;
|
|
987
|
+
}
|
|
988
|
+
continue;
|
|
989
|
+
}
|
|
990
|
+
if (char === "/" && next === "/") {
|
|
991
|
+
index += 2;
|
|
992
|
+
while (index < input.length && input[index] !== "\n") {
|
|
993
|
+
index += 1;
|
|
994
|
+
}
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
997
|
+
if (char === "/" && next === "*") {
|
|
998
|
+
index += 2;
|
|
999
|
+
while (index < input.length && !(input[index] === "*" && input[index + 1] === "/")) {
|
|
1000
|
+
if (input[index] === "\n") {
|
|
1001
|
+
output += "\n";
|
|
1002
|
+
}
|
|
1003
|
+
index += 1;
|
|
1004
|
+
}
|
|
1005
|
+
index += input[index] === "*" ? 2 : 0;
|
|
1006
|
+
continue;
|
|
1007
|
+
}
|
|
1008
|
+
if (char === "#" && (next === " " || next === " ")) {
|
|
1009
|
+
index += 1;
|
|
1010
|
+
while (index < input.length && input[index] !== "\n") {
|
|
1011
|
+
index += 1;
|
|
1012
|
+
}
|
|
1013
|
+
continue;
|
|
1014
|
+
}
|
|
1015
|
+
output += char;
|
|
1016
|
+
atLineStart = char === "\n" || atLineStart && (char === " " || char === " ");
|
|
1017
|
+
index += 1;
|
|
1018
|
+
}
|
|
1019
|
+
return output;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
412
1022
|
// src/renderer/renderer.ts
|
|
413
1023
|
function renderSections(asset, options = {}) {
|
|
414
1024
|
const { variables = {}, strict = false } = options;
|
|
415
|
-
const
|
|
1025
|
+
const contextInputs = getContextInputs(asset);
|
|
1026
|
+
const optionalVariables = contextInputs.filter((input) => input.optional === true).map((input) => input.name);
|
|
1027
|
+
const contextInputsByName = new Map(contextInputs.map((input) => [input.name, input]));
|
|
1028
|
+
const compressionCache = /* @__PURE__ */ new Map();
|
|
1029
|
+
const createTransformVariable = (template) => {
|
|
1030
|
+
return ({ name, value, modifier, match }) => {
|
|
1031
|
+
const input = contextInputsByName.get(name);
|
|
1032
|
+
const configuredHeuristic = input?.compression?.heuristic;
|
|
1033
|
+
const configuredCode = input?.compression?.code;
|
|
1034
|
+
const shouldCompactCode = modifier === "compact" || modifier === "code" || configuredCode?.enabled === true;
|
|
1035
|
+
const shouldCompress = modifier === "compress" || configuredHeuristic?.enabled === true;
|
|
1036
|
+
if (modifier === "toon") {
|
|
1037
|
+
const result3 = toToonPlaceholder(value);
|
|
1038
|
+
if (!result3) {
|
|
1039
|
+
options.compression?.onCompressionWarning?.(
|
|
1040
|
+
`POK031: JSON-to-TOON skipped for placeholder "${name}" because the value is not a complete valid JSON object or array.`
|
|
1041
|
+
);
|
|
1042
|
+
return value;
|
|
1043
|
+
}
|
|
1044
|
+
if (result3.tokensSaved > 0 || result3.output !== value) {
|
|
1045
|
+
options.compression?.onHeuristicCompression?.({
|
|
1046
|
+
scope: "placeholder",
|
|
1047
|
+
variable: name,
|
|
1048
|
+
...result3
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
return result3.output;
|
|
1052
|
+
}
|
|
1053
|
+
if (shouldCompactCode) {
|
|
1054
|
+
const result3 = compactCode(value, toCodeCompactionOptions(configuredCode));
|
|
1055
|
+
if (result3.tokensSaved > 0 || result3.output !== value) {
|
|
1056
|
+
options.compression?.onCodeCompaction?.({
|
|
1057
|
+
scope: "placeholder",
|
|
1058
|
+
variable: name,
|
|
1059
|
+
...result3
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
return result3.output;
|
|
1063
|
+
}
|
|
1064
|
+
if (!shouldCompress) {
|
|
1065
|
+
return value;
|
|
1066
|
+
}
|
|
1067
|
+
const query = resolveHeuristicQuery(configuredHeuristic, variables, template, match);
|
|
1068
|
+
const compressionOptions = {
|
|
1069
|
+
min_tokens: configuredHeuristic?.min_tokens,
|
|
1070
|
+
max_sentences: configuredHeuristic?.max_sentences,
|
|
1071
|
+
target_reduction: configuredHeuristic?.target_reduction,
|
|
1072
|
+
query,
|
|
1073
|
+
json_to_toon: configuredHeuristic?.json_to_toon
|
|
1074
|
+
};
|
|
1075
|
+
const cacheKey = JSON.stringify([name, value, compressionOptions]);
|
|
1076
|
+
const cached = compressionCache.get(cacheKey);
|
|
1077
|
+
if (cached !== void 0) {
|
|
1078
|
+
return cached;
|
|
1079
|
+
}
|
|
1080
|
+
const result2 = compressHeuristicText(value, compressionOptions);
|
|
1081
|
+
compressionCache.set(cacheKey, result2.output);
|
|
1082
|
+
reportHeuristicCompressionWarnings(options, result2, `placeholder "${name}"`);
|
|
1083
|
+
if (result2.tokensSaved > 0 || result2.output !== value) {
|
|
1084
|
+
options.compression?.onHeuristicCompression?.({
|
|
1085
|
+
scope: "placeholder",
|
|
1086
|
+
variable: name,
|
|
1087
|
+
...result2
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
return result2.output;
|
|
1091
|
+
};
|
|
1092
|
+
};
|
|
416
1093
|
const result = {};
|
|
417
1094
|
if (asset.sections.system_instructions) {
|
|
418
1095
|
result.system_instructions = interpolate(
|
|
419
1096
|
asset.sections.system_instructions,
|
|
420
1097
|
variables,
|
|
421
|
-
{
|
|
1098
|
+
{
|
|
1099
|
+
strict,
|
|
1100
|
+
optionalVariables,
|
|
1101
|
+
transformVariable: createTransformVariable(asset.sections.system_instructions)
|
|
1102
|
+
}
|
|
422
1103
|
);
|
|
423
1104
|
}
|
|
424
1105
|
if (asset.sections.prompt_template) {
|
|
425
1106
|
result.prompt_template = interpolate(
|
|
426
1107
|
asset.sections.prompt_template,
|
|
427
1108
|
variables,
|
|
428
|
-
{
|
|
1109
|
+
{
|
|
1110
|
+
strict,
|
|
1111
|
+
optionalVariables,
|
|
1112
|
+
transformVariable: createTransformVariable(asset.sections.prompt_template)
|
|
1113
|
+
}
|
|
429
1114
|
);
|
|
430
1115
|
}
|
|
431
1116
|
return result;
|
|
432
1117
|
}
|
|
1118
|
+
function resolveHeuristicQuery(options, variables, template, match) {
|
|
1119
|
+
if (options?.query !== void 0) {
|
|
1120
|
+
return options.query;
|
|
1121
|
+
}
|
|
1122
|
+
if (options?.query_variable && variables[options.query_variable] !== void 0) {
|
|
1123
|
+
return variables[options.query_variable];
|
|
1124
|
+
}
|
|
1125
|
+
return template.replace(match, " ");
|
|
1126
|
+
}
|
|
1127
|
+
function toToonPlaceholder(value) {
|
|
1128
|
+
const toon = tryJsonToToon(value);
|
|
1129
|
+
if (!toon) {
|
|
1130
|
+
return void 0;
|
|
1131
|
+
}
|
|
1132
|
+
const inputTokens = estimateHeuristicTokens(value);
|
|
1133
|
+
const outputTokens = estimateHeuristicTokens(toon.output);
|
|
1134
|
+
return {
|
|
1135
|
+
output: toon.output,
|
|
1136
|
+
inputTokens,
|
|
1137
|
+
outputTokens,
|
|
1138
|
+
tokensSaved: Math.max(0, inputTokens - outputTokens),
|
|
1139
|
+
compressionRatio: outputTokens === 0 ? 0 : inputTokens / outputTokens,
|
|
1140
|
+
outputFormat: "toon"
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
function toCodeCompactionOptions(options) {
|
|
1144
|
+
return {
|
|
1145
|
+
remove_comments: options?.remove_comments,
|
|
1146
|
+
trim_indentation: options?.trim_indentation,
|
|
1147
|
+
collapse_blank_lines: options?.collapse_blank_lines
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
function reportHeuristicCompressionWarnings(options, result, scope) {
|
|
1151
|
+
for (const warning of result.warnings ?? []) {
|
|
1152
|
+
options.compression?.onCompressionWarning?.(`POK031: ${warning} Scope: ${scope}.`);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
433
1155
|
|
|
434
1156
|
// src/overrides/apply-overrides.ts
|
|
435
1157
|
function applyOverrides(asset, options = {}) {
|
|
@@ -466,6 +1188,14 @@ function mergeOverride(base, override) {
|
|
|
466
1188
|
thetokencompany: mergeRecordBlock(
|
|
467
1189
|
result.compression?.thetokencompany,
|
|
468
1190
|
override.compression.thetokencompany
|
|
1191
|
+
),
|
|
1192
|
+
heuristic: mergeRecordBlock(
|
|
1193
|
+
result.compression?.heuristic,
|
|
1194
|
+
override.compression.heuristic
|
|
1195
|
+
),
|
|
1196
|
+
code: mergeRecordBlock(
|
|
1197
|
+
result.compression?.code,
|
|
1198
|
+
override.compression.code
|
|
469
1199
|
)
|
|
470
1200
|
};
|
|
471
1201
|
}
|
|
@@ -699,8 +1429,25 @@ var TheTokenCompanyCompressionSchema = import_zod.z.object({
|
|
|
699
1429
|
model: import_zod.z.string().min(1).optional(),
|
|
700
1430
|
aggressiveness: import_zod.z.number().min(0).max(1).optional()
|
|
701
1431
|
});
|
|
1432
|
+
var HeuristicCompressionSchema = import_zod.z.object({
|
|
1433
|
+
enabled: import_zod.z.boolean().optional(),
|
|
1434
|
+
min_tokens: import_zod.z.number().int().positive().optional(),
|
|
1435
|
+
max_sentences: import_zod.z.number().int().positive().optional(),
|
|
1436
|
+
target_reduction: import_zod.z.number().min(0).max(1).optional(),
|
|
1437
|
+
query: import_zod.z.string().optional(),
|
|
1438
|
+
query_variable: import_zod.z.string().min(1).optional(),
|
|
1439
|
+
json_to_toon: import_zod.z.boolean().optional()
|
|
1440
|
+
});
|
|
1441
|
+
var CodeCompactionSchema = import_zod.z.object({
|
|
1442
|
+
enabled: import_zod.z.boolean().optional(),
|
|
1443
|
+
remove_comments: import_zod.z.boolean().optional(),
|
|
1444
|
+
trim_indentation: import_zod.z.boolean().optional(),
|
|
1445
|
+
collapse_blank_lines: import_zod.z.boolean().optional()
|
|
1446
|
+
});
|
|
702
1447
|
var CompressionSchema = import_zod.z.object({
|
|
703
|
-
thetokencompany: TheTokenCompanyCompressionSchema.optional()
|
|
1448
|
+
thetokencompany: TheTokenCompanyCompressionSchema.optional(),
|
|
1449
|
+
heuristic: HeuristicCompressionSchema.optional(),
|
|
1450
|
+
code: CodeCompactionSchema.optional()
|
|
704
1451
|
});
|
|
705
1452
|
var OpenAICacheSchema = import_zod.z.object({
|
|
706
1453
|
prompt_cache_key: import_zod.z.string().min(1).optional(),
|
|
@@ -740,12 +1487,21 @@ var ContextBuiltInValidatorSchema = import_zod.z.union([
|
|
|
740
1487
|
return_message: import_zod.z.string().optional()
|
|
741
1488
|
})
|
|
742
1489
|
]);
|
|
1490
|
+
var ContextInputCompressionSchema = import_zod.z.union([
|
|
1491
|
+
import_zod.z.literal("heuristic"),
|
|
1492
|
+
import_zod.z.literal("code"),
|
|
1493
|
+
import_zod.z.object({
|
|
1494
|
+
heuristic: HeuristicCompressionSchema.optional(),
|
|
1495
|
+
code: CodeCompactionSchema.optional()
|
|
1496
|
+
})
|
|
1497
|
+
]);
|
|
743
1498
|
var ContextInputDefinitionObjectSchema = import_zod.z.object({
|
|
744
1499
|
name: import_zod.z.string(),
|
|
745
1500
|
optional: import_zod.z.boolean().optional(),
|
|
746
1501
|
warnings: import_zod.z.boolean().optional(),
|
|
747
1502
|
max_size: import_zod.z.number().int().positive().optional(),
|
|
748
1503
|
trim: import_zod.z.union([import_zod.z.boolean(), import_zod.z.enum(["start", "end", "both"])]).optional(),
|
|
1504
|
+
compression: ContextInputCompressionSchema.optional(),
|
|
749
1505
|
allow_regex: ContextRegexSchema.optional(),
|
|
750
1506
|
deny_regex: ContextRegexSchema.optional(),
|
|
751
1507
|
non_empty: ContextBuiltInValidatorSchema.optional(),
|
|
@@ -848,9 +1604,9 @@ function assertRegexFrontMatterQuoting(content, filePath) {
|
|
|
848
1604
|
return;
|
|
849
1605
|
}
|
|
850
1606
|
let pendingRegex;
|
|
851
|
-
for (const [index,
|
|
1607
|
+
for (const [index, line2] of frontMatter.lines.entries()) {
|
|
852
1608
|
const lineNumber = frontMatter.startLine + index;
|
|
853
|
-
const regexMatch =
|
|
1609
|
+
const regexMatch = line2.match(REGEX_FIELD);
|
|
854
1610
|
if (regexMatch?.groups) {
|
|
855
1611
|
const field = regexMatch.groups.field;
|
|
856
1612
|
const indent2 = regexMatch.groups.indent.length;
|
|
@@ -863,15 +1619,15 @@ function assertRegexFrontMatterQuoting(content, filePath) {
|
|
|
863
1619
|
if (!pendingRegex) {
|
|
864
1620
|
continue;
|
|
865
1621
|
}
|
|
866
|
-
if (
|
|
1622
|
+
if (line2.trim() === "" || line2.trimStart().startsWith("#")) {
|
|
867
1623
|
continue;
|
|
868
1624
|
}
|
|
869
|
-
const indent =
|
|
1625
|
+
const indent = line2.match(/^\s*/)?.[0].length ?? 0;
|
|
870
1626
|
if (indent <= pendingRegex.indent) {
|
|
871
1627
|
pendingRegex = void 0;
|
|
872
1628
|
continue;
|
|
873
1629
|
}
|
|
874
|
-
const patternMatch =
|
|
1630
|
+
const patternMatch = line2.match(PATTERN_FIELD);
|
|
875
1631
|
if (!patternMatch?.groups) {
|
|
876
1632
|
continue;
|
|
877
1633
|
}
|
|
@@ -966,8 +1722,8 @@ function extractSections(body) {
|
|
|
966
1722
|
let currentKey = null;
|
|
967
1723
|
let currentLines = [];
|
|
968
1724
|
let foundAnyH1 = false;
|
|
969
|
-
for (const
|
|
970
|
-
const h1Match =
|
|
1725
|
+
for (const line2 of lines) {
|
|
1726
|
+
const h1Match = line2.match(/^#\s+(.+)$/);
|
|
971
1727
|
if (h1Match) {
|
|
972
1728
|
if (currentKey) {
|
|
973
1729
|
sections[currentKey] = currentLines.join("\n").trim();
|
|
@@ -977,7 +1733,7 @@ function extractSections(body) {
|
|
|
977
1733
|
currentKey = SECTION_MAP[heading] ?? null;
|
|
978
1734
|
currentLines = [];
|
|
979
1735
|
} else {
|
|
980
|
-
currentLines.push(
|
|
1736
|
+
currentLines.push(line2);
|
|
981
1737
|
}
|
|
982
1738
|
}
|
|
983
1739
|
if (currentKey) {
|
|
@@ -1310,7 +2066,9 @@ function mergeCompression(base, local) {
|
|
|
1310
2066
|
const merged = {
|
|
1311
2067
|
...base ?? {},
|
|
1312
2068
|
...local ?? {},
|
|
1313
|
-
thetokencompany: mergeRecordBlock2(base?.thetokencompany, local?.thetokencompany)
|
|
2069
|
+
thetokencompany: mergeRecordBlock2(base?.thetokencompany, local?.thetokencompany),
|
|
2070
|
+
heuristic: mergeRecordBlock2(base?.heuristic, local?.heuristic),
|
|
2071
|
+
code: mergeRecordBlock2(base?.code, local?.code)
|
|
1314
2072
|
};
|
|
1315
2073
|
removeEmptyProviderBlocks(merged);
|
|
1316
2074
|
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
@@ -1564,33 +2322,152 @@ function compactHistoryForPrompt(asset, runtime) {
|
|
|
1564
2322
|
// src/compression.ts
|
|
1565
2323
|
var THETOKENCOMPANY_DEFAULT_MODEL = "bear-2";
|
|
1566
2324
|
var THETOKENCOMPANY_DEFAULT_BASE_URL = "https://api.thetokencompany.com";
|
|
2325
|
+
var HEURISTIC_COMPRESSION_MODEL = "local-heuristic-v1";
|
|
2326
|
+
var CODE_COMPACTION_MODEL = "local-code-compactor-v1";
|
|
2327
|
+
function summarizePromptCompression(compression = []) {
|
|
2328
|
+
const totals = compression.reduce(
|
|
2329
|
+
(accumulator, result) => {
|
|
2330
|
+
accumulator.inputTokens += result.inputTokens;
|
|
2331
|
+
accumulator.outputTokens += result.outputTokens;
|
|
2332
|
+
accumulator.tokensSaved += result.tokensSaved;
|
|
2333
|
+
return accumulator;
|
|
2334
|
+
},
|
|
2335
|
+
{
|
|
2336
|
+
inputTokens: 0,
|
|
2337
|
+
outputTokens: 0,
|
|
2338
|
+
tokensSaved: 0
|
|
2339
|
+
}
|
|
2340
|
+
);
|
|
2341
|
+
return {
|
|
2342
|
+
steps: compression.length,
|
|
2343
|
+
inputTokens: totals.inputTokens,
|
|
2344
|
+
outputTokens: totals.outputTokens,
|
|
2345
|
+
tokensSaved: totals.tokensSaved,
|
|
2346
|
+
reductionRatio: totals.inputTokens === 0 ? 0 : totals.tokensSaved / totals.inputTokens
|
|
2347
|
+
};
|
|
2348
|
+
}
|
|
1567
2349
|
async function applyPromptCompressionForRender(asset, runtime) {
|
|
1568
|
-
const
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
2350
|
+
const theTokenCompanyConfig = asset.compression?.thetokencompany;
|
|
2351
|
+
const heuristicConfig = asset.compression?.heuristic;
|
|
2352
|
+
const codeConfig = asset.compression?.code;
|
|
2353
|
+
const hasTheTokenCompanyCompression = theTokenCompanyConfig?.enabled === true && Boolean(asset.sections.prompt_template);
|
|
2354
|
+
const hasHeuristicPromptCompression = heuristicConfig?.enabled === true && Boolean(asset.sections.prompt_template);
|
|
2355
|
+
const hasCodePromptCompaction = codeConfig?.enabled === true && Boolean(asset.sections.prompt_template);
|
|
2356
|
+
const hasPlaceholderCompression = usesPlaceholderCompression(asset);
|
|
2357
|
+
if (!hasTheTokenCompanyCompression && !hasHeuristicPromptCompression && !hasCodePromptCompaction && !hasPlaceholderCompression) {
|
|
2358
|
+
return { asset, runtime, compression: [], warnings: [] };
|
|
2359
|
+
}
|
|
2360
|
+
const compression = [];
|
|
2361
|
+
const warnings = [];
|
|
1572
2362
|
const sections = renderSections(asset, {
|
|
1573
2363
|
variables: runtime.variables,
|
|
1574
|
-
strict: runtime.strict
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
2364
|
+
strict: runtime.strict,
|
|
2365
|
+
compression: {
|
|
2366
|
+
onHeuristicCompression: (event) => {
|
|
2367
|
+
compression.push({
|
|
2368
|
+
provider: "heuristic",
|
|
2369
|
+
model: HEURISTIC_COMPRESSION_MODEL,
|
|
2370
|
+
inputTokens: event.inputTokens,
|
|
2371
|
+
outputTokens: event.outputTokens,
|
|
2372
|
+
tokensSaved: event.tokensSaved,
|
|
2373
|
+
compressionRatio: event.compressionRatio,
|
|
2374
|
+
scope: event.scope,
|
|
2375
|
+
variable: event.variable,
|
|
2376
|
+
outputFormat: event.outputFormat
|
|
2377
|
+
});
|
|
2378
|
+
},
|
|
2379
|
+
onCodeCompaction: (event) => {
|
|
2380
|
+
compression.push({
|
|
2381
|
+
provider: "code",
|
|
2382
|
+
model: CODE_COMPACTION_MODEL,
|
|
2383
|
+
inputTokens: event.inputTokens,
|
|
2384
|
+
outputTokens: event.outputTokens,
|
|
2385
|
+
tokensSaved: event.tokensSaved,
|
|
2386
|
+
compressionRatio: event.compressionRatio,
|
|
2387
|
+
scope: event.scope,
|
|
2388
|
+
variable: event.variable,
|
|
2389
|
+
outputFormat: "code"
|
|
2390
|
+
});
|
|
2391
|
+
},
|
|
2392
|
+
onCompressionWarning: (warning) => {
|
|
2393
|
+
warnings.push(warning);
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
1586
2396
|
});
|
|
2397
|
+
let promptTemplate = sections.prompt_template;
|
|
2398
|
+
if (hasCodePromptCompaction && promptTemplate) {
|
|
2399
|
+
if (hasHeuristicPromptCompression) {
|
|
2400
|
+
warnings.push(
|
|
2401
|
+
"POK032: Local heuristic prompt compression skipped because compression.code is enabled for the prompt template."
|
|
2402
|
+
);
|
|
2403
|
+
}
|
|
2404
|
+
const result = compactCode(promptTemplate, toCodeCompactionOptions2(codeConfig));
|
|
2405
|
+
promptTemplate = result.output;
|
|
2406
|
+
if (result.tokensSaved > 0 || result.output !== sections.prompt_template) {
|
|
2407
|
+
compression.push({
|
|
2408
|
+
provider: "code",
|
|
2409
|
+
model: CODE_COMPACTION_MODEL,
|
|
2410
|
+
inputTokens: result.inputTokens,
|
|
2411
|
+
outputTokens: result.outputTokens,
|
|
2412
|
+
tokensSaved: result.tokensSaved,
|
|
2413
|
+
compressionRatio: result.compressionRatio,
|
|
2414
|
+
scope: "prompt_template",
|
|
2415
|
+
outputFormat: "code"
|
|
2416
|
+
});
|
|
2417
|
+
}
|
|
2418
|
+
} else if (hasHeuristicPromptCompression && promptTemplate) {
|
|
2419
|
+
const result = compressHeuristicText(promptTemplate, {
|
|
2420
|
+
min_tokens: heuristicConfig?.min_tokens,
|
|
2421
|
+
max_sentences: heuristicConfig?.max_sentences,
|
|
2422
|
+
target_reduction: heuristicConfig?.target_reduction,
|
|
2423
|
+
query: resolveHeuristicPromptQuery(heuristicConfig, runtime.variables, sections.system_instructions),
|
|
2424
|
+
json_to_toon: heuristicConfig?.json_to_toon
|
|
2425
|
+
});
|
|
2426
|
+
promptTemplate = result.output;
|
|
2427
|
+
reportHeuristicCompressionWarnings2(warnings, result.warnings, "prompt template");
|
|
2428
|
+
if (result.tokensSaved > 0 || result.output !== sections.prompt_template) {
|
|
2429
|
+
compression.push({
|
|
2430
|
+
provider: "heuristic",
|
|
2431
|
+
model: HEURISTIC_COMPRESSION_MODEL,
|
|
2432
|
+
inputTokens: result.inputTokens,
|
|
2433
|
+
outputTokens: result.outputTokens,
|
|
2434
|
+
tokensSaved: result.tokensSaved,
|
|
2435
|
+
compressionRatio: result.compressionRatio,
|
|
2436
|
+
scope: "prompt_template",
|
|
2437
|
+
outputFormat: result.outputFormat
|
|
2438
|
+
});
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
if (hasTheTokenCompanyCompression && hasCodePromptCompaction && promptTemplate) {
|
|
2442
|
+
warnings.push(
|
|
2443
|
+
"POK033: TheTokenCompany compression skipped because compression.code is enabled; code is compacted locally and not text-compressed."
|
|
2444
|
+
);
|
|
2445
|
+
} else if (hasTheTokenCompanyCompression && promptTemplate) {
|
|
2446
|
+
const model = theTokenCompanyConfig?.model ?? THETOKENCOMPANY_DEFAULT_MODEL;
|
|
2447
|
+
const result = await compressWithTheTokenCompany(promptTemplate, {
|
|
2448
|
+
apiKey: runtime.theTokenCompany?.apiKey,
|
|
2449
|
+
baseURL: runtime.theTokenCompany?.baseURL,
|
|
2450
|
+
fetch: runtime.theTokenCompany?.fetch,
|
|
2451
|
+
model,
|
|
2452
|
+
aggressiveness: theTokenCompanyConfig?.aggressiveness
|
|
2453
|
+
});
|
|
2454
|
+
promptTemplate = result.output;
|
|
2455
|
+
compression.push({
|
|
2456
|
+
provider: "thetokencompany",
|
|
2457
|
+
model,
|
|
2458
|
+
inputTokens: result.input_tokens,
|
|
2459
|
+
outputTokens: result.output_tokens,
|
|
2460
|
+
tokensSaved: result.tokens_saved,
|
|
2461
|
+
compressionRatio: result.compression_ratio
|
|
2462
|
+
});
|
|
2463
|
+
}
|
|
1587
2464
|
return {
|
|
1588
2465
|
asset: {
|
|
1589
2466
|
...asset,
|
|
1590
2467
|
sections: {
|
|
1591
2468
|
...asset.sections,
|
|
1592
2469
|
...sections,
|
|
1593
|
-
prompt_template:
|
|
2470
|
+
...promptTemplate !== void 0 ? { prompt_template: promptTemplate } : {}
|
|
1594
2471
|
}
|
|
1595
2472
|
},
|
|
1596
2473
|
runtime: {
|
|
@@ -1598,16 +2475,45 @@ async function applyPromptCompressionForRender(asset, runtime) {
|
|
|
1598
2475
|
variables: {},
|
|
1599
2476
|
strict: false
|
|
1600
2477
|
},
|
|
1601
|
-
compression
|
|
1602
|
-
|
|
1603
|
-
model,
|
|
1604
|
-
inputTokens: result.input_tokens,
|
|
1605
|
-
outputTokens: result.output_tokens,
|
|
1606
|
-
tokensSaved: result.tokens_saved,
|
|
1607
|
-
compressionRatio: result.compression_ratio
|
|
1608
|
-
}]
|
|
2478
|
+
compression,
|
|
2479
|
+
warnings
|
|
1609
2480
|
};
|
|
1610
2481
|
}
|
|
2482
|
+
function usesPlaceholderCompression(asset) {
|
|
2483
|
+
const hasContextInputCompression = getContextInputs(asset).some(
|
|
2484
|
+
(input) => input.compression?.heuristic?.enabled === true || input.compression?.code?.enabled === true
|
|
2485
|
+
);
|
|
2486
|
+
if (hasContextInputCompression) {
|
|
2487
|
+
return true;
|
|
2488
|
+
}
|
|
2489
|
+
return Boolean(
|
|
2490
|
+
asset.sections.system_instructions && hasCompressionModifier(asset.sections.system_instructions) || asset.sections.prompt_template && hasCompressionModifier(asset.sections.prompt_template)
|
|
2491
|
+
);
|
|
2492
|
+
}
|
|
2493
|
+
function hasCompressionModifier(template) {
|
|
2494
|
+
return /\{\{\s*[a-zA-Z_][a-zA-Z0-9_]*\s*\|\s*(?:compress|toon|compact|code)\s*\}\}/.test(template);
|
|
2495
|
+
}
|
|
2496
|
+
function resolveHeuristicPromptQuery(options, variables, systemInstructions) {
|
|
2497
|
+
if (options?.query !== void 0) {
|
|
2498
|
+
return options.query;
|
|
2499
|
+
}
|
|
2500
|
+
if (options?.query_variable && variables?.[options.query_variable] !== void 0) {
|
|
2501
|
+
return variables[options.query_variable];
|
|
2502
|
+
}
|
|
2503
|
+
return systemInstructions;
|
|
2504
|
+
}
|
|
2505
|
+
function toCodeCompactionOptions2(options) {
|
|
2506
|
+
return {
|
|
2507
|
+
remove_comments: options?.remove_comments,
|
|
2508
|
+
trim_indentation: options?.trim_indentation,
|
|
2509
|
+
collapse_blank_lines: options?.collapse_blank_lines
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
function reportHeuristicCompressionWarnings2(warnings, compressionWarnings, scope) {
|
|
2513
|
+
for (const warning of compressionWarnings ?? []) {
|
|
2514
|
+
warnings.push(`POK031: ${warning} Scope: ${scope}.`);
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
1611
2517
|
async function compressWithTheTokenCompany(input, options) {
|
|
1612
2518
|
const apiKey = options.apiKey ?? getEnv("THETOKENCOMPANY_API_KEY") ?? getEnv("TTC_API_KEY");
|
|
1613
2519
|
if (!apiKey) {
|
|
@@ -1695,7 +2601,14 @@ function withPromptInputSupport(adapter) {
|
|
|
1695
2601
|
history: compactHistoryForPrompt(resolvedForRender, runtime)
|
|
1696
2602
|
});
|
|
1697
2603
|
const request = adapter.render(prepared.asset, prepared.runtime);
|
|
1698
|
-
return prepared.compression.length > 0
|
|
2604
|
+
return prepared.compression.length > 0 || prepared.warnings.length > 0 ? {
|
|
2605
|
+
...request,
|
|
2606
|
+
...prepared.compression.length > 0 ? {
|
|
2607
|
+
compression: prepared.compression,
|
|
2608
|
+
compressionSummary: summarizePromptCompression(prepared.compression)
|
|
2609
|
+
} : {},
|
|
2610
|
+
...prepared.warnings.length > 0 ? { warnings: prepared.warnings } : {}
|
|
2611
|
+
} : request;
|
|
1699
2612
|
};
|
|
1700
2613
|
return {
|
|
1701
2614
|
...adapter,
|
|
@@ -3171,11 +4084,17 @@ var PromptOpsKit = class {
|
|
|
3171
4084
|
theTokenCompany: options.theTokenCompany
|
|
3172
4085
|
});
|
|
3173
4086
|
const request = adapter.render(prepared.asset, prepared.runtime);
|
|
4087
|
+
const compressionSummary = prepared.compression.length > 0 ? summarizePromptCompression(prepared.compression) : void 0;
|
|
3174
4088
|
return {
|
|
3175
4089
|
resolved,
|
|
3176
|
-
request: prepared.compression.length > 0
|
|
4090
|
+
request: prepared.compression.length > 0 || prepared.warnings.length > 0 ? {
|
|
4091
|
+
...request,
|
|
4092
|
+
...prepared.compression.length > 0 ? { compression: prepared.compression, compressionSummary } : {},
|
|
4093
|
+
...prepared.warnings.length > 0 ? { warnings: prepared.warnings } : {}
|
|
4094
|
+
} : request,
|
|
3177
4095
|
...prepared.compression.length > 0 ? { compression: prepared.compression } : {},
|
|
3178
|
-
|
|
4096
|
+
...compressionSummary ? { compressionSummary } : {},
|
|
4097
|
+
warnings: shouldIncludeContextWarningsInResult(contextWarningPolicy) ? [...validation.warnings, ...contextSizeWarnings, ...prepared.warnings] : [...validation.warnings, ...prepared.warnings]
|
|
3179
4098
|
};
|
|
3180
4099
|
}
|
|
3181
4100
|
/**
|
|
@@ -3271,6 +4190,7 @@ async function renderPrompt(options) {
|
|
|
3271
4190
|
runLLMAsAServiceWithUsageTap,
|
|
3272
4191
|
runOpenAIWithUsageTap,
|
|
3273
4192
|
runOpenRouterWithUsageTap,
|
|
4193
|
+
summarizePromptCompression,
|
|
3274
4194
|
validateAsset,
|
|
3275
4195
|
validateAssetWithIncludes,
|
|
3276
4196
|
withUsageTapCall
|