promptopskit 0.8.2 → 0.9.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.
Files changed (69) hide show
  1. package/README.md +20 -6
  2. package/SKILL.md +10 -4
  3. package/dist/{chunk-DI7Q4T7A.js → chunk-7GMCNHXJ.js} +3 -3
  4. package/dist/{chunk-PDVUVZAU.js → chunk-C5HHTLZX.js} +2 -2
  5. package/dist/{chunk-Z3DPPJNU.js → chunk-D23T3X4V.js} +2 -2
  6. package/dist/{chunk-ZVCKP4EM.js → chunk-EDHPVR2F.js} +3 -3
  7. package/dist/{chunk-UQLAWU67.js → chunk-O3SRIDTH.js} +2 -2
  8. package/dist/{chunk-5XH2GROP.js → chunk-QHAIOVQ3.js} +2 -2
  9. package/dist/{chunk-RVAFVWR2.js → chunk-QZHR2YMK.js} +136 -36
  10. package/dist/chunk-QZHR2YMK.js.map +1 -0
  11. package/dist/{chunk-E4GEKWVP.js → chunk-VOXMOGU5.js} +5 -2
  12. package/dist/chunk-VOXMOGU5.js.map +1 -0
  13. package/dist/cli/index.js +8 -2
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/index.cjs +138 -35
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +4 -4
  18. package/dist/index.d.ts +4 -4
  19. package/dist/index.js +8 -8
  20. package/dist/providers/anthropic.cjs +138 -35
  21. package/dist/providers/anthropic.cjs.map +1 -1
  22. package/dist/providers/anthropic.d.cts +2 -2
  23. package/dist/providers/anthropic.d.ts +2 -2
  24. package/dist/providers/anthropic.js +3 -3
  25. package/dist/providers/gemini.cjs +138 -35
  26. package/dist/providers/gemini.cjs.map +1 -1
  27. package/dist/providers/gemini.d.cts +2 -2
  28. package/dist/providers/gemini.d.ts +2 -2
  29. package/dist/providers/gemini.js +3 -3
  30. package/dist/providers/llmasaservice.cjs +138 -35
  31. package/dist/providers/llmasaservice.cjs.map +1 -1
  32. package/dist/providers/llmasaservice.d.cts +2 -2
  33. package/dist/providers/llmasaservice.d.ts +2 -2
  34. package/dist/providers/llmasaservice.js +4 -4
  35. package/dist/providers/openai-responses.cjs +138 -35
  36. package/dist/providers/openai-responses.cjs.map +1 -1
  37. package/dist/providers/openai-responses.d.cts +2 -2
  38. package/dist/providers/openai-responses.d.ts +2 -2
  39. package/dist/providers/openai-responses.js +3 -3
  40. package/dist/providers/openai.cjs +138 -35
  41. package/dist/providers/openai.cjs.map +1 -1
  42. package/dist/providers/openai.d.cts +2 -2
  43. package/dist/providers/openai.d.ts +2 -2
  44. package/dist/providers/openai.js +3 -3
  45. package/dist/providers/openrouter.cjs +138 -35
  46. package/dist/providers/openrouter.cjs.map +1 -1
  47. package/dist/providers/openrouter.d.cts +2 -2
  48. package/dist/providers/openrouter.d.ts +2 -2
  49. package/dist/providers/openrouter.js +4 -4
  50. package/dist/{schema-BgVLZ2u5.d.cts → schema-BkOMklgI.d.cts} +129 -0
  51. package/dist/{schema-BgVLZ2u5.d.ts → schema-BkOMklgI.d.ts} +129 -0
  52. package/dist/testing.cjs +4 -1
  53. package/dist/testing.cjs.map +1 -1
  54. package/dist/testing.d.cts +1 -1
  55. package/dist/testing.d.ts +1 -1
  56. package/dist/testing.js +1 -1
  57. package/dist/{types-2hnZmCkH.d.cts → types-B4TWRzUY.d.cts} +1 -1
  58. package/dist/{types-DgAT4jSR.d.ts → types-D6VJJo1x.d.ts} +1 -1
  59. package/dist/usagetap/index.d.cts +2 -2
  60. package/dist/usagetap/index.d.ts +2 -2
  61. package/package.json +1 -1
  62. package/dist/chunk-E4GEKWVP.js.map +0 -1
  63. package/dist/chunk-RVAFVWR2.js.map +0 -1
  64. /package/dist/{chunk-DI7Q4T7A.js.map → chunk-7GMCNHXJ.js.map} +0 -0
  65. /package/dist/{chunk-PDVUVZAU.js.map → chunk-C5HHTLZX.js.map} +0 -0
  66. /package/dist/{chunk-Z3DPPJNU.js.map → chunk-D23T3X4V.js.map} +0 -0
  67. /package/dist/{chunk-ZVCKP4EM.js.map → chunk-EDHPVR2F.js.map} +0 -0
  68. /package/dist/{chunk-UQLAWU67.js.map → chunk-O3SRIDTH.js.map} +0 -0
  69. /package/dist/{chunk-5XH2GROP.js.map → chunk-QHAIOVQ3.js.map} +0 -0
@@ -1,5 +1,5 @@
1
- import { P as ProviderAdapter } from '../types-2hnZmCkH.cjs';
2
- import '../schema-BgVLZ2u5.cjs';
1
+ import { P as ProviderAdapter } from '../types-B4TWRzUY.cjs';
2
+ import '../schema-BkOMklgI.cjs';
3
3
  import 'zod';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { P as ProviderAdapter } from '../types-DgAT4jSR.js';
2
- import '../schema-BgVLZ2u5.js';
1
+ import { P as ProviderAdapter } from '../types-D6VJJo1x.js';
2
+ import '../schema-BkOMklgI.js';
3
3
  import 'zod';
4
4
 
5
5
  /**
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  geminiAdapter
3
- } from "../chunk-UQLAWU67.js";
4
- import "../chunk-RVAFVWR2.js";
5
- import "../chunk-E4GEKWVP.js";
3
+ } from "../chunk-O3SRIDTH.js";
4
+ import "../chunk-QZHR2YMK.js";
5
+ import "../chunk-VOXMOGU5.js";
6
6
  export {
7
7
  geminiAdapter
8
8
  };
@@ -106,7 +106,10 @@ function normalizeContextInputCompression(value) {
106
106
  target_reduction: value.heuristic.target_reduction,
107
107
  query: value.heuristic.query,
108
108
  query_variable: value.heuristic.query_variable,
109
- json_to_toon: value.heuristic.json_to_toon
109
+ json_to_toon: value.heuristic.json_to_toon,
110
+ mode: value.heuristic.mode,
111
+ preserve_neighbors: value.heuristic.preserve_neighbors,
112
+ fail_on_low_confidence: value.heuristic.fail_on_low_confidence
110
113
  }
111
114
  };
112
115
  const code = normalizeCodeCompression(value.code);
@@ -584,7 +587,10 @@ function line(depth, content, indent) {
584
587
  var TOKEN_REGEX = /[\p{L}\p{N}]+|[^\s]/gu;
585
588
  var TOKEN_NORMALIZE_REGEX = /[^\p{L}\p{N}]/gu;
586
589
  var DEDUPE_NORMALIZE_REGEX = /[^\p{L}\p{N}\s]/gu;
587
- var BOILERPLATE_REGEX = /copyright|all rights reserved|disclaimer|confidential/i;
590
+ var BOILERPLATE_REGEX = /copyright|all rights reserved|disclaimer/i;
591
+ var STRUCTURED_BLOCK_REGEX = /(^|\n)\s*```|(^|\n)\s*\|.+\|\s*(\n|$)/;
592
+ var PROTECTED_SIGNAL_REGEX = /\b(?:must|shall|should|required|requires|requirement|never|do not|don't|only|except|unless|however|but|constraint|constraints|safety|security|deadline|sla)\b|output\s+format/i;
593
+ var EVIDENCE_SIGNAL_REGEX = /https?:\/\/|\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b|[$€£]\s?\d|\b\d+(?:[.,:/-]\d+)*%?\b|\b[A-Z]{2,}[-_A-Z0-9]*\b|\b[A-Z]\d\b/i;
588
594
  var MAX_SEGMENT_TOKENS = 120;
589
595
  var STOP_WORDS = /* @__PURE__ */ new Set([
590
596
  "a",
@@ -618,7 +624,8 @@ var STOP_WORDS = /* @__PURE__ */ new Set([
618
624
  var DEFAULT_OPTIONS = {
619
625
  min_tokens: 80,
620
626
  max_sentences: 10,
621
- target_reduction: 0.45
627
+ target_reduction: 0.45,
628
+ mode: "conservative"
622
629
  };
623
630
  function tokenizeForHeuristicCompression(text) {
624
631
  if (!text) {
@@ -652,25 +659,46 @@ function compressHeuristicText(input, options = {}) {
652
659
  warnings: ["JSON-to-TOON skipped because the input is not a complete valid JSON object or array."]
653
660
  };
654
661
  }
655
- const analysis = preprocessContext(inputText);
656
662
  if (inputTokens === 0) {
657
663
  return toCompressionOutput(inputText, inputTokens);
658
664
  }
665
+ const mode = options.mode ?? DEFAULT_OPTIONS.mode;
666
+ const isConservative = mode === "conservative";
667
+ const failOnLowConfidence = options.fail_on_low_confidence ?? isConservative;
668
+ const preserveNeighbors = options.preserve_neighbors ?? isConservative;
659
669
  const minTokens = options.min_tokens ?? DEFAULT_OPTIONS.min_tokens;
660
670
  if (inputTokens <= minTokens) {
661
671
  return toCompressionOutput(inputText, inputTokens);
662
672
  }
673
+ if (isConservative && looksStructured(inputText)) {
674
+ return toCompressionOutput(inputText, inputTokens, [
675
+ "Heuristic compression skipped because the input appears to contain structured blocks; use TOON or code compaction for structured content."
676
+ ]);
677
+ }
678
+ const analysis = preprocessContext(inputText);
663
679
  const targetReduction = options.target_reduction ?? DEFAULT_OPTIONS.target_reduction;
664
680
  const targetTokens = Math.max(1, Math.max(minTokens, Math.floor(inputTokens * (1 - targetReduction))));
665
681
  const maxSentences = options.max_sentences ?? DEFAULT_OPTIONS.max_sentences;
666
682
  const query = options.query ?? "";
667
683
  const terms = queryTerms(query);
684
+ if (failOnLowConfidence && terms.size === 0) {
685
+ return toCompressionOutput(inputText, inputTokens, [
686
+ "Heuristic compression skipped because no usable relevance query terms were available."
687
+ ]);
688
+ }
668
689
  const scoredSentences = analysis.candidates.map((candidate) => ({
669
690
  sentence: candidate.sentence,
670
691
  index: candidate.index,
671
692
  ...scoreSentenceCandidate(candidate, terms),
672
- tokens: candidate.tokenCount
693
+ tokens: candidate.tokenCount,
694
+ isProtected: candidate.isProtected,
695
+ hasEvidence: candidate.hasEvidence
673
696
  }));
697
+ if (failOnLowConfidence && terms.size > 0 && !scoredSentences.some((candidate) => candidate.overlapCount > 0)) {
698
+ return toCompressionOutput(inputText, inputTokens, [
699
+ "Heuristic compression skipped because no sentence matched the relevance query."
700
+ ]);
701
+ }
674
702
  const selected = [];
675
703
  const selectedIndices = /* @__PURE__ */ new Set();
676
704
  const coveredTerms = /* @__PURE__ */ new Set();
@@ -710,19 +738,15 @@ function compressHeuristicText(input, options = {}) {
710
738
  coveredTerms.add(term);
711
739
  }
712
740
  }
713
- selected.sort((left, right) => left.index - right.index);
714
- let output = selected.map((item) => item.sentence).join(" ");
741
+ const finalSelection = preserveNeighbors ? expandSelectionWithNeighbors(selected, scoredSentences, maxSentences) : selected;
742
+ finalSelection.sort((left, right) => left.index - right.index);
743
+ let output = finalSelection.map((item) => item.sentence).join(" ");
715
744
  if (!output) {
716
- output = tokenizeForHeuristicCompression(inputText).slice(0, targetTokens).join(" ");
717
- } else {
718
- const outputTokens = tokenizeForHeuristicCompression(output);
719
- if (outputTokens.length > targetTokens) {
720
- output = outputTokens.slice(0, targetTokens).join(" ");
721
- }
745
+ output = takeWholeCandidatesWithinBudget(analysis.candidates, targetTokens) || inputText;
722
746
  }
723
747
  return toCompressionOutput(output, inputTokens);
724
748
  }
725
- function toCompressionOutput(output, inputTokens) {
749
+ function toCompressionOutput(output, inputTokens, warnings = []) {
726
750
  const outputTokens = estimateHeuristicTokens(output);
727
751
  const tokensSaved = Math.max(0, inputTokens - outputTokens);
728
752
  return {
@@ -730,7 +754,8 @@ function toCompressionOutput(output, inputTokens) {
730
754
  inputTokens,
731
755
  outputTokens,
732
756
  tokensSaved,
733
- compressionRatio: outputTokens === 0 ? 0 : inputTokens / outputTokens
757
+ compressionRatio: outputTokens === 0 ? 0 : inputTokens / outputTokens,
758
+ ...warnings.length > 0 ? { warnings } : {}
734
759
  };
735
760
  }
736
761
  function isBetterTieBreak(candidate, bestCandidate) {
@@ -748,13 +773,6 @@ function normalizeForDeduping(sentence) {
748
773
  function splitIntoSentences(text) {
749
774
  return text.split(/(?<=[.!?])\s+|\n+/g).map((sentence) => sentence.trim()).filter(Boolean);
750
775
  }
751
- function chunkTokens(tokens, chunkSize) {
752
- const chunks = [];
753
- for (let index = 0; index < tokens.length; index += chunkSize) {
754
- chunks.push(tokens.slice(index, index + chunkSize));
755
- }
756
- return chunks;
757
- }
758
776
  function splitOversizedSentence(sentence, maxTokens = MAX_SEGMENT_TOKENS) {
759
777
  const rawTokens = tokenizeForHeuristicCompression(sentence);
760
778
  if (rawTokens.length <= maxTokens) {
@@ -766,10 +784,10 @@ function splitOversizedSentence(sentence, maxTokens = MAX_SEGMENT_TOKENS) {
766
784
  if (estimateHeuristicTokens(segment) <= maxTokens) {
767
785
  return [segment];
768
786
  }
769
- return chunkTokens(tokenizeForHeuristicCompression(segment), maxTokens).map((chunk) => chunk.join(" "));
787
+ return [segment];
770
788
  });
771
789
  }
772
- return chunkTokens(rawTokens, maxTokens).map((chunk) => chunk.join(" "));
790
+ return [sentence];
773
791
  }
774
792
  function normalizeToken(token) {
775
793
  return token.replace(TOKEN_NORMALIZE_REGEX, "").trim();
@@ -778,19 +796,24 @@ function tokenizeNormalized(text) {
778
796
  return tokenizeForHeuristicCompression(text.toLowerCase()).map(normalizeToken).filter(Boolean);
779
797
  }
780
798
  function queryTerms(query) {
781
- return new Set(tokenizeNormalized(query).filter((term) => term.length >= 3 && !STOP_WORDS.has(term)));
799
+ return new Set(tokenizeNormalized(query).filter((term) => {
800
+ if (STOP_WORDS.has(term)) {
801
+ return false;
802
+ }
803
+ return term.length >= 3 || /^(?:[a-z]\d|\d+[a-z]?|[a-z]{2})$/i.test(term);
804
+ }));
782
805
  }
783
806
  function preprocessContext(context) {
784
807
  const originalTokens = estimateHeuristicTokens(context);
785
- const dedupeSet = /* @__PURE__ */ new Set();
786
808
  const candidates = [];
809
+ let previousNormalized = "";
787
810
  for (const sentence of splitIntoSentences(context)) {
788
811
  for (const segment of splitOversizedSentence(sentence)) {
789
812
  const normalized = normalizeForDeduping(segment);
790
- if (!normalized || dedupeSet.has(normalized)) {
813
+ if (!normalized || normalized === previousNormalized) {
791
814
  continue;
792
815
  }
793
- dedupeSet.add(normalized);
816
+ previousNormalized = normalized;
794
817
  const rawTokens = tokenizeForHeuristicCompression(segment);
795
818
  const normalizedTerms = rawTokens.map((token) => normalizeToken(token.toLowerCase())).filter(Boolean);
796
819
  const lowered = segment.toLowerCase();
@@ -799,7 +822,9 @@ function preprocessContext(context) {
799
822
  index: candidates.length,
800
823
  tokenCount: rawTokens.length,
801
824
  uniqueTerms: new Set(normalizedTerms),
802
- isBoilerplate: BOILERPLATE_REGEX.test(lowered)
825
+ isBoilerplate: BOILERPLATE_REGEX.test(lowered),
826
+ isProtected: PROTECTED_SIGNAL_REGEX.test(segment),
827
+ hasEvidence: EVIDENCE_SIGNAL_REGEX.test(segment)
803
828
  });
804
829
  }
805
830
  }
@@ -825,12 +850,62 @@ function scoreSentenceCandidate(candidate, terms) {
825
850
  const densityScore = terms.size > 0 ? overlap / terms.size : 0;
826
851
  const lengthScore = Math.min(candidate.tokenCount, 40) / 40;
827
852
  const boilerplatePenalty = candidate.isBoilerplate ? 0.5 : 0;
853
+ const protectedScore = candidate.isProtected ? 0.9 : 0;
854
+ const evidenceScore = candidate.hasEvidence ? 0.4 : 0;
828
855
  return {
829
- score: overlapScore + densityScore + lengthScore - boilerplatePenalty,
856
+ score: overlapScore + densityScore + lengthScore + protectedScore + evidenceScore - boilerplatePenalty,
830
857
  overlapCount: overlap,
831
858
  overlapTerms
832
859
  };
833
860
  }
861
+ function looksStructured(text) {
862
+ if (STRUCTURED_BLOCK_REGEX.test(text)) {
863
+ return true;
864
+ }
865
+ const lines = text.split(/\r?\n/).map((line2) => line2.trim()).filter(Boolean);
866
+ if (lines.length < 3) {
867
+ return false;
868
+ }
869
+ const listLikeLines = lines.filter((line2) => /^[-*+] |\d+[.)] /.test(line2)).length;
870
+ return listLikeLines >= 3 && listLikeLines / lines.length >= 0.6;
871
+ }
872
+ function expandSelectionWithNeighbors(selected, scoredSentences, maxSentences) {
873
+ if (selected.length === 0 || selected.length >= maxSentences) {
874
+ return selected;
875
+ }
876
+ const byIndex = new Map(scoredSentences.map((candidate) => [candidate.index, candidate]));
877
+ const expanded = new Map(selected.map((candidate) => [candidate.index, candidate]));
878
+ for (const candidate of selected) {
879
+ if (expanded.size >= maxSentences) {
880
+ break;
881
+ }
882
+ if (candidate.overlapCount === 0 && !candidate.isProtected && !candidate.hasEvidence) {
883
+ continue;
884
+ }
885
+ for (const neighborIndex of [candidate.index - 1, candidate.index + 1]) {
886
+ if (expanded.size >= maxSentences) {
887
+ break;
888
+ }
889
+ const neighbor = byIndex.get(neighborIndex);
890
+ if (neighbor && !expanded.has(neighbor.index)) {
891
+ expanded.set(neighbor.index, neighbor);
892
+ }
893
+ }
894
+ }
895
+ return [...expanded.values()];
896
+ }
897
+ function takeWholeCandidatesWithinBudget(candidates, targetTokens) {
898
+ const selected = [];
899
+ let tokens = 0;
900
+ for (const candidate of candidates) {
901
+ if (tokens + candidate.tokenCount > targetTokens) {
902
+ break;
903
+ }
904
+ selected.push(candidate.sentence);
905
+ tokens += candidate.tokenCount;
906
+ }
907
+ return selected.join(" ");
908
+ }
834
909
 
835
910
  // src/code-compaction.ts
836
911
  function compactCode(input, options = {}) {
@@ -996,7 +1071,10 @@ function renderSections(asset, options = {}) {
996
1071
  max_sentences: configuredHeuristic?.max_sentences,
997
1072
  target_reduction: configuredHeuristic?.target_reduction,
998
1073
  query,
999
- json_to_toon: configuredHeuristic?.json_to_toon
1074
+ json_to_toon: configuredHeuristic?.json_to_toon,
1075
+ mode: configuredHeuristic?.mode,
1076
+ preserve_neighbors: configuredHeuristic?.preserve_neighbors,
1077
+ fail_on_low_confidence: configuredHeuristic?.fail_on_low_confidence
1000
1078
  };
1001
1079
  const cacheKey = JSON.stringify([name, value, compressionOptions]);
1002
1080
  const cached = compressionCache.get(cacheKey);
@@ -1362,7 +1440,10 @@ var HeuristicCompressionSchema = import_zod.z.object({
1362
1440
  target_reduction: import_zod.z.number().min(0).max(1).optional(),
1363
1441
  query: import_zod.z.string().optional(),
1364
1442
  query_variable: import_zod.z.string().min(1).optional(),
1365
- json_to_toon: import_zod.z.boolean().optional()
1443
+ json_to_toon: import_zod.z.boolean().optional(),
1444
+ mode: import_zod.z.enum(["conservative", "balanced"]).optional(),
1445
+ preserve_neighbors: import_zod.z.boolean().optional(),
1446
+ fail_on_low_confidence: import_zod.z.boolean().optional()
1366
1447
  });
1367
1448
  var CodeCompactionSchema = import_zod.z.object({
1368
1449
  enabled: import_zod.z.boolean().optional(),
@@ -2347,7 +2428,10 @@ async function applyPromptCompressionForRender(asset, runtime) {
2347
2428
  max_sentences: heuristicConfig?.max_sentences,
2348
2429
  target_reduction: heuristicConfig?.target_reduction,
2349
2430
  query: resolveHeuristicPromptQuery(heuristicConfig, runtime.variables, sections.system_instructions),
2350
- json_to_toon: heuristicConfig?.json_to_toon
2431
+ json_to_toon: heuristicConfig?.json_to_toon,
2432
+ mode: heuristicConfig?.mode,
2433
+ preserve_neighbors: heuristicConfig?.preserve_neighbors,
2434
+ fail_on_low_confidence: heuristicConfig?.fail_on_low_confidence
2351
2435
  });
2352
2436
  promptTemplate = result.output;
2353
2437
  reportHeuristicCompressionWarnings2(warnings, result.warnings, "prompt template");
@@ -2472,10 +2556,29 @@ async function compressWithTheTokenCompany(input, options) {
2472
2556
  );
2473
2557
  }
2474
2558
  const data = await response.json();
2475
- if (typeof data.output !== "string" || typeof data.output_tokens !== "number" || typeof data.input_tokens !== "number" || typeof data.tokens_saved !== "number" || typeof data.compression_ratio !== "number") {
2559
+ const normalized = normalizeTheTokenCompanyCompressResponse(data);
2560
+ if (!normalized) {
2476
2561
  throw new Error("TheTokenCompany compression returned an invalid response payload.");
2477
2562
  }
2478
- return data;
2563
+ return normalized;
2564
+ }
2565
+ function normalizeTheTokenCompanyCompressResponse(data) {
2566
+ if (typeof data.output !== "string" || typeof data.output_tokens !== "number") {
2567
+ return void 0;
2568
+ }
2569
+ const inputTokens = typeof data.input_tokens === "number" ? data.input_tokens : data.original_input_tokens;
2570
+ if (typeof inputTokens !== "number") {
2571
+ return void 0;
2572
+ }
2573
+ const tokensSaved = typeof data.tokens_saved === "number" ? data.tokens_saved : inputTokens - data.output_tokens;
2574
+ const compressionRatio = typeof data.compression_ratio === "number" ? data.compression_ratio : data.output_tokens === 0 ? 0 : inputTokens / data.output_tokens;
2575
+ return {
2576
+ output: data.output,
2577
+ output_tokens: data.output_tokens,
2578
+ input_tokens: inputTokens,
2579
+ tokens_saved: tokensSaved,
2580
+ compression_ratio: compressionRatio
2581
+ };
2479
2582
  }
2480
2583
  function getEnv(name) {
2481
2584
  if (typeof process === "undefined") {