pi-smart-compact 9.2.1 → 9.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +2 -2
- package/CHANGELOG.md +95 -0
- package/dist/app/steps/extract.d.ts.map +1 -1
- package/dist/app/steps/synthesize.d.ts.map +1 -1
- package/dist/app/steps/verify.d.ts.map +1 -1
- package/dist/constants.d.ts +1 -4
- package/dist/constants.d.ts.map +1 -1
- package/dist/domain/scrub.d.ts.map +1 -1
- package/dist/domain/summary-parse.d.ts +5 -0
- package/dist/domain/summary-parse.d.ts.map +1 -1
- package/dist/index.js +715 -152
- package/dist/infra/llm-client.d.ts +1 -1
- package/dist/infra/llm-client.d.ts.map +1 -1
- package/dist/phases/synthesize.d.ts +3 -5
- package/dist/phases/synthesize.d.ts.map +1 -1
- package/dist/phases/verify.d.ts +2 -1
- package/dist/phases/verify.d.ts.map +1 -1
- package/dist/provider-eval.js +392 -58
- package/dist/provider-scenario-eval.js +800 -249
- package/dist/telemetry-report.js +364 -30
- package/dist/utils/extraction.d.ts.map +1 -1
- package/dist/utils/file-needles.d.ts.map +1 -1
- package/dist/utils/file-ref-detect.d.ts.map +1 -1
- package/dist/utils/state.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/provider-eval.js
CHANGED
|
@@ -156,7 +156,7 @@ function formatProviderEvaluation(report) {
|
|
|
156
156
|
import fs2 from "fs";
|
|
157
157
|
|
|
158
158
|
// src/constants.ts
|
|
159
|
-
var VERSION = "9.
|
|
159
|
+
var VERSION = "9.3.0";
|
|
160
160
|
var SETTLED_TRIGGER_COOLDOWN_MS = 10 * 60000;
|
|
161
161
|
var COMPACT_SYSTEM_PREFIX = "You are an expert conversation summarizer for a coding agent. " + "Produce structured markdown summaries. " + "Follow output format exactly. " + "Use EXACT names \u2014 never paraphrase code identifiers. " + "Trust deterministic extraction data over intuition.";
|
|
162
162
|
var PROFILES = {
|
|
@@ -400,6 +400,188 @@ function lruSet(m, key, value, max) {
|
|
|
400
400
|
}
|
|
401
401
|
|
|
402
402
|
// src/utils/tokens.ts
|
|
403
|
+
var PROVIDER_MAP = {
|
|
404
|
+
"zai-anthropic": {
|
|
405
|
+
maxOutputTokens: 8192,
|
|
406
|
+
supportsTools: "probe",
|
|
407
|
+
jsonReliability: "high",
|
|
408
|
+
instructionFollowing: "high",
|
|
409
|
+
tokenRatioEstimate: 3.5,
|
|
410
|
+
concurrencyLimit: 3,
|
|
411
|
+
cacheStrategy: "anthropic",
|
|
412
|
+
timeoutMultiplier: 1.2,
|
|
413
|
+
singlePassTokenMultiplier: 1,
|
|
414
|
+
multimodal: "metadata-only"
|
|
415
|
+
},
|
|
416
|
+
"kimi-coding": {
|
|
417
|
+
maxOutputTokens: 8192,
|
|
418
|
+
supportsTools: "probe",
|
|
419
|
+
jsonReliability: "high",
|
|
420
|
+
instructionFollowing: "high",
|
|
421
|
+
tokenRatioEstimate: 3.5,
|
|
422
|
+
concurrencyLimit: 2,
|
|
423
|
+
cacheStrategy: "anthropic",
|
|
424
|
+
timeoutMultiplier: 1.5,
|
|
425
|
+
singlePassTokenMultiplier: 0.95,
|
|
426
|
+
multimodal: "metadata-only"
|
|
427
|
+
},
|
|
428
|
+
anthropic: {
|
|
429
|
+
maxOutputTokens: 8192,
|
|
430
|
+
supportsTools: true,
|
|
431
|
+
jsonReliability: "high",
|
|
432
|
+
instructionFollowing: "high",
|
|
433
|
+
tokenRatioEstimate: 3.5,
|
|
434
|
+
concurrencyLimit: 3,
|
|
435
|
+
cacheStrategy: "anthropic",
|
|
436
|
+
timeoutMultiplier: 1.2,
|
|
437
|
+
singlePassTokenMultiplier: 1,
|
|
438
|
+
multimodal: "native"
|
|
439
|
+
},
|
|
440
|
+
openai: {
|
|
441
|
+
maxOutputTokens: 16384,
|
|
442
|
+
supportsTools: true,
|
|
443
|
+
jsonReliability: "high",
|
|
444
|
+
instructionFollowing: "high",
|
|
445
|
+
tokenRatioEstimate: 4,
|
|
446
|
+
concurrencyLimit: 5,
|
|
447
|
+
cacheStrategy: "openai",
|
|
448
|
+
timeoutMultiplier: 1,
|
|
449
|
+
singlePassTokenMultiplier: 1.15,
|
|
450
|
+
multimodal: "native"
|
|
451
|
+
},
|
|
452
|
+
google: {
|
|
453
|
+
maxOutputTokens: 8192,
|
|
454
|
+
supportsTools: true,
|
|
455
|
+
jsonReliability: "high",
|
|
456
|
+
instructionFollowing: "high",
|
|
457
|
+
tokenRatioEstimate: 3.8,
|
|
458
|
+
concurrencyLimit: 3,
|
|
459
|
+
cacheStrategy: "openai",
|
|
460
|
+
timeoutMultiplier: 1.15,
|
|
461
|
+
singlePassTokenMultiplier: 1.1,
|
|
462
|
+
multimodal: "native"
|
|
463
|
+
},
|
|
464
|
+
deepseek: {
|
|
465
|
+
maxOutputTokens: 8192,
|
|
466
|
+
supportsTools: true,
|
|
467
|
+
jsonReliability: "medium",
|
|
468
|
+
instructionFollowing: "medium",
|
|
469
|
+
tokenRatioEstimate: 3.6,
|
|
470
|
+
concurrencyLimit: 2,
|
|
471
|
+
cacheStrategy: "none",
|
|
472
|
+
timeoutMultiplier: 1.5,
|
|
473
|
+
singlePassTokenMultiplier: 0.85,
|
|
474
|
+
multimodal: "metadata-only"
|
|
475
|
+
},
|
|
476
|
+
minimax: {
|
|
477
|
+
maxOutputTokens: 4096,
|
|
478
|
+
supportsTools: "probe",
|
|
479
|
+
jsonReliability: "medium",
|
|
480
|
+
instructionFollowing: "medium",
|
|
481
|
+
tokenRatioEstimate: 3.8,
|
|
482
|
+
concurrencyLimit: 2,
|
|
483
|
+
cacheStrategy: "anthropic",
|
|
484
|
+
timeoutMultiplier: 1.6,
|
|
485
|
+
singlePassTokenMultiplier: 0.8,
|
|
486
|
+
multimodal: "metadata-only"
|
|
487
|
+
},
|
|
488
|
+
"xiaomi-token-plan": {
|
|
489
|
+
maxOutputTokens: 8192,
|
|
490
|
+
supportsTools: "probe",
|
|
491
|
+
jsonReliability: "medium",
|
|
492
|
+
instructionFollowing: "medium",
|
|
493
|
+
tokenRatioEstimate: 3.3,
|
|
494
|
+
concurrencyLimit: 2,
|
|
495
|
+
cacheStrategy: "openai",
|
|
496
|
+
timeoutMultiplier: 1.35,
|
|
497
|
+
singlePassTokenMultiplier: 0.9,
|
|
498
|
+
multimodal: "metadata-only"
|
|
499
|
+
},
|
|
500
|
+
"xiaomi-mimo": {
|
|
501
|
+
maxOutputTokens: 8192,
|
|
502
|
+
supportsTools: "probe",
|
|
503
|
+
jsonReliability: "medium",
|
|
504
|
+
instructionFollowing: "medium",
|
|
505
|
+
tokenRatioEstimate: 3.3,
|
|
506
|
+
concurrencyLimit: 2,
|
|
507
|
+
cacheStrategy: "anthropic",
|
|
508
|
+
timeoutMultiplier: 1.35,
|
|
509
|
+
singlePassTokenMultiplier: 0.9,
|
|
510
|
+
multimodal: "metadata-only"
|
|
511
|
+
},
|
|
512
|
+
crofai: {
|
|
513
|
+
maxOutputTokens: 8192,
|
|
514
|
+
supportsTools: "probe",
|
|
515
|
+
jsonReliability: "medium",
|
|
516
|
+
instructionFollowing: "medium",
|
|
517
|
+
tokenRatioEstimate: 3.8,
|
|
518
|
+
concurrencyLimit: 3,
|
|
519
|
+
cacheStrategy: "none",
|
|
520
|
+
timeoutMultiplier: 1.2,
|
|
521
|
+
singlePassTokenMultiplier: 0.95,
|
|
522
|
+
multimodal: "metadata-only"
|
|
523
|
+
},
|
|
524
|
+
mistral: {
|
|
525
|
+
maxOutputTokens: 8192,
|
|
526
|
+
supportsTools: true,
|
|
527
|
+
jsonReliability: "high",
|
|
528
|
+
instructionFollowing: "high",
|
|
529
|
+
tokenRatioEstimate: 3.5,
|
|
530
|
+
concurrencyLimit: 3,
|
|
531
|
+
cacheStrategy: "openai",
|
|
532
|
+
timeoutMultiplier: 1.2,
|
|
533
|
+
singlePassTokenMultiplier: 1,
|
|
534
|
+
multimodal: "metadata-only"
|
|
535
|
+
},
|
|
536
|
+
xai: {
|
|
537
|
+
maxOutputTokens: 8192,
|
|
538
|
+
supportsTools: true,
|
|
539
|
+
jsonReliability: "medium",
|
|
540
|
+
instructionFollowing: "high",
|
|
541
|
+
tokenRatioEstimate: 3.8,
|
|
542
|
+
concurrencyLimit: 3,
|
|
543
|
+
cacheStrategy: "openai",
|
|
544
|
+
timeoutMultiplier: 1.2,
|
|
545
|
+
singlePassTokenMultiplier: 1,
|
|
546
|
+
multimodal: "native"
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
var PROVIDER_ALIASES = [
|
|
550
|
+
{ pattern: /anthropic/i, provider: "anthropic" },
|
|
551
|
+
{ pattern: /kimi/i, provider: "kimi-coding" },
|
|
552
|
+
{ pattern: /zai/i, provider: "zai-anthropic" },
|
|
553
|
+
{ pattern: /openai/i, provider: "openai" },
|
|
554
|
+
{ pattern: /gpt/i, provider: "openai" },
|
|
555
|
+
{ pattern: /google|gemini/i, provider: "google" },
|
|
556
|
+
{ pattern: /deepseek/i, provider: "deepseek" },
|
|
557
|
+
{ pattern: /minimax/i, provider: "minimax" },
|
|
558
|
+
{ pattern: /xiaomi-mimo/i, provider: "xiaomi-mimo" },
|
|
559
|
+
{ pattern: /xiaomi/i, provider: "xiaomi-token-plan" },
|
|
560
|
+
{ pattern: /crofai/i, provider: "crofai" },
|
|
561
|
+
{ pattern: /mistral/i, provider: "mistral" },
|
|
562
|
+
{ pattern: /xai|grok/i, provider: "xai" }
|
|
563
|
+
];
|
|
564
|
+
var DEFAULT_CAPS = {
|
|
565
|
+
maxOutputTokens: 8192,
|
|
566
|
+
supportsTools: "probe",
|
|
567
|
+
jsonReliability: "medium",
|
|
568
|
+
instructionFollowing: "medium",
|
|
569
|
+
tokenRatioEstimate: 3.8,
|
|
570
|
+
concurrencyLimit: 2,
|
|
571
|
+
cacheStrategy: "none",
|
|
572
|
+
timeoutMultiplier: 1.35,
|
|
573
|
+
singlePassTokenMultiplier: 0.9,
|
|
574
|
+
multimodal: "metadata-only"
|
|
575
|
+
};
|
|
576
|
+
function getProviderCaps(provider) {
|
|
577
|
+
if (PROVIDER_MAP[provider])
|
|
578
|
+
return PROVIDER_MAP[provider];
|
|
579
|
+
for (const { pattern, provider: key } of PROVIDER_ALIASES) {
|
|
580
|
+
if (pattern.test(provider))
|
|
581
|
+
return PROVIDER_MAP[key] ?? DEFAULT_CAPS;
|
|
582
|
+
}
|
|
583
|
+
return DEFAULT_CAPS;
|
|
584
|
+
}
|
|
403
585
|
class TokenCalibrationStore {
|
|
404
586
|
maxEntries;
|
|
405
587
|
factors = new Map;
|
|
@@ -497,13 +679,53 @@ function buildUniquePathNeedles(filePath, allPaths) {
|
|
|
497
679
|
});
|
|
498
680
|
}
|
|
499
681
|
function isKnownPathReference(ref, knownPaths) {
|
|
500
|
-
const normalizedRef = normalizePath(ref);
|
|
682
|
+
const normalizedRef = normalizePath(ref).replace(/^\/+/, "");
|
|
683
|
+
if (!normalizedRef)
|
|
684
|
+
return false;
|
|
685
|
+
const pathShaped = normalizedRef.includes("/");
|
|
501
686
|
return knownPaths.some((path) => {
|
|
502
|
-
const normalizedPath = normalizePath(path);
|
|
503
|
-
|
|
687
|
+
const normalizedPath = normalizePath(path).replace(/^\/+/, "");
|
|
688
|
+
if (normalizedPath === normalizedRef || normalizedPath.endsWith("/" + normalizedRef))
|
|
689
|
+
return true;
|
|
690
|
+
if (normalizedPath.endsWith(normalizedRef)) {
|
|
691
|
+
const boundary = normalizedPath[normalizedPath.length - normalizedRef.length - 1];
|
|
692
|
+
if (boundary && !/[\w./-]/.test(boundary))
|
|
693
|
+
return true;
|
|
694
|
+
}
|
|
695
|
+
if (!pathShaped)
|
|
696
|
+
return false;
|
|
697
|
+
return normalizedPath.split("/").some((_, index, parts) => parts.slice(index).join("/").startsWith(normalizedRef + "/"));
|
|
504
698
|
});
|
|
505
699
|
}
|
|
506
700
|
|
|
701
|
+
// src/utils/logger.ts
|
|
702
|
+
var DEBUG = process.env.DEBUG?.includes("smart-compact") ?? false;
|
|
703
|
+
function warn(msg, err) {
|
|
704
|
+
const detail = err instanceof Error ? err.message : err ?? "";
|
|
705
|
+
console.error(LOG_PREFIX + " " + msg + (detail ? ": " + detail : ""));
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// src/infra/paths.ts
|
|
709
|
+
import path from "path";
|
|
710
|
+
function home() {
|
|
711
|
+
return process.env.HOME ?? "/tmp";
|
|
712
|
+
}
|
|
713
|
+
function piAgentDir() {
|
|
714
|
+
return path.join(home(), ".pi", "agent");
|
|
715
|
+
}
|
|
716
|
+
function cacheDir() {
|
|
717
|
+
return path.join(piAgentDir(), ".cache");
|
|
718
|
+
}
|
|
719
|
+
function smartCompactCacheDir() {
|
|
720
|
+
return path.join(cacheDir(), "smart-compact");
|
|
721
|
+
}
|
|
722
|
+
function metricsLogFile() {
|
|
723
|
+
return path.join(cacheDir(), "compact-metrics.jsonl");
|
|
724
|
+
}
|
|
725
|
+
function damageReportsFile() {
|
|
726
|
+
return path.join(smartCompactCacheDir(), "damage-reports.jsonl");
|
|
727
|
+
}
|
|
728
|
+
|
|
507
729
|
// src/domain/tool-semantics.ts
|
|
508
730
|
var PATH_KEYS = [
|
|
509
731
|
"path",
|
|
@@ -586,10 +808,20 @@ function isLikelyFileRef(candidate) {
|
|
|
586
808
|
return CODE_EXT_RE.test(candidate);
|
|
587
809
|
}
|
|
588
810
|
function extractFileRefs(summary) {
|
|
589
|
-
const
|
|
590
|
-
|
|
811
|
+
const matcher = new RegExp(FILE_REF_CANDIDATE_RE.source, FILE_REF_CANDIDATE_RE.flags);
|
|
812
|
+
const refs = [];
|
|
813
|
+
for (const match of summary.matchAll(matcher)) {
|
|
814
|
+
if (/[\\/]/.test(summary[(match.index ?? 0) + match[0].length] ?? ""))
|
|
815
|
+
continue;
|
|
816
|
+
if (isLikelyFileRef(match[0]))
|
|
817
|
+
refs.push(match[0]);
|
|
818
|
+
}
|
|
819
|
+
return refs;
|
|
591
820
|
}
|
|
592
821
|
|
|
822
|
+
// src/domain/summary-parse.ts
|
|
823
|
+
import { createHash } from "crypto";
|
|
824
|
+
|
|
593
825
|
// src/domain/summary-schema.ts
|
|
594
826
|
function classifyHeading(raw) {
|
|
595
827
|
const text = raw.replace(/^#+\s*/, "").replace(/[:\s]+$/, "").trim().toLowerCase();
|
|
@@ -629,6 +861,58 @@ var HEADING_RE = /^(#{1,3})\s+(.+?)\s*$/;
|
|
|
629
861
|
function summaryEvidenceLine(value, maxLength) {
|
|
630
862
|
return value.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, " ").replace(/\s+/g, " ").trim().replace(/^(?:(?:#{1,6}|[-*+]|>)\s+)+/, "").slice(0, maxLength).trim();
|
|
631
863
|
}
|
|
864
|
+
function summaryPathLine(value) {
|
|
865
|
+
return JSON.stringify(value);
|
|
866
|
+
}
|
|
867
|
+
function compactPathLine(value, maxLength, digest) {
|
|
868
|
+
const minimal = JSON.stringify("#" + digest);
|
|
869
|
+
if (minimal.length >= maxLength)
|
|
870
|
+
return minimal;
|
|
871
|
+
const chars = Array.from(value.replace(/\\/g, "/"));
|
|
872
|
+
let low = 0;
|
|
873
|
+
let high = chars.length;
|
|
874
|
+
let best = minimal;
|
|
875
|
+
while (low <= high) {
|
|
876
|
+
const length = Math.floor((low + high) / 2);
|
|
877
|
+
const candidate = JSON.stringify("\u2026/" + chars.slice(-length).join("") + "#" + digest);
|
|
878
|
+
if (candidate.length <= maxLength) {
|
|
879
|
+
best = candidate;
|
|
880
|
+
low = length + 1;
|
|
881
|
+
} else {
|
|
882
|
+
high = length - 1;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
return best;
|
|
886
|
+
}
|
|
887
|
+
function buildSummaryPathEvidence(paths, budgetTokens = PROFILES.balanced.summaryBudgetTokens) {
|
|
888
|
+
const unique = Array.from(new Set(paths.filter(Boolean)));
|
|
889
|
+
if (!unique.length)
|
|
890
|
+
return new Map;
|
|
891
|
+
const full = unique.map((path2) => [path2, summaryPathLine(path2)]);
|
|
892
|
+
const minimumPerLine = JSON.stringify("#" + "x".repeat(12)).length + 3;
|
|
893
|
+
const budgetChars = Math.max(unique.length * minimumPerLine, Math.min(20000, Math.max(4000, Math.floor(budgetTokens * 2))));
|
|
894
|
+
if (full.reduce((total, [, line]) => total + line.length + 3, 0) <= budgetChars) {
|
|
895
|
+
return new Map(full);
|
|
896
|
+
}
|
|
897
|
+
const digests = new Map;
|
|
898
|
+
const owners = new Map;
|
|
899
|
+
for (const path2 of unique) {
|
|
900
|
+
const fullDigest = createHash("sha256").update(path2).digest("base64url");
|
|
901
|
+
let digest = fullDigest.slice(0, 12);
|
|
902
|
+
const owner = owners.get(digest);
|
|
903
|
+
if (owner && owner !== path2) {
|
|
904
|
+
digest = fullDigest;
|
|
905
|
+
digests.set(owner, createHash("sha256").update(owner).digest("base64url"));
|
|
906
|
+
}
|
|
907
|
+
owners.set(digest, path2);
|
|
908
|
+
digests.set(path2, digest);
|
|
909
|
+
}
|
|
910
|
+
const perPath = Math.max(JSON.stringify("#" + "x".repeat(12)).length, Math.floor((budgetChars - unique.length * 3) / unique.length));
|
|
911
|
+
return new Map(unique.map((path2) => [
|
|
912
|
+
path2,
|
|
913
|
+
compactPathLine(path2, perPath, digests.get(path2) ?? "")
|
|
914
|
+
]));
|
|
915
|
+
}
|
|
632
916
|
function mergeBodies(first, second) {
|
|
633
917
|
const seen = new Set;
|
|
634
918
|
return [first, second].filter(Boolean).flatMap((body) => body.split(`
|
|
@@ -653,7 +937,11 @@ function parseSummary(markdown) {
|
|
|
653
937
|
if (existing)
|
|
654
938
|
existing.body = mergeBodies(existing.body, body);
|
|
655
939
|
else
|
|
656
|
-
sections.push({
|
|
940
|
+
sections.push({
|
|
941
|
+
kind: currentKind,
|
|
942
|
+
heading: currentHeading.trim(),
|
|
943
|
+
body
|
|
944
|
+
});
|
|
657
945
|
};
|
|
658
946
|
for (const line of lines) {
|
|
659
947
|
const fenceMatch = line.match(/^\s{0,3}(`{3,}|~{3,})(.*)$/);
|
|
@@ -744,7 +1032,11 @@ function buildToolCallIndex(msgs) {
|
|
|
744
1032
|
for (let t = 0;t < nested.length; t++) {
|
|
745
1033
|
const tool = nested[t];
|
|
746
1034
|
const id = nestedToolCallId(b.id, i, t, tool.id);
|
|
747
|
-
idx.set(id, {
|
|
1035
|
+
idx.set(id, {
|
|
1036
|
+
name: tool.name,
|
|
1037
|
+
arguments: tool.arguments,
|
|
1038
|
+
msgIndex: i
|
|
1039
|
+
});
|
|
748
1040
|
}
|
|
749
1041
|
}
|
|
750
1042
|
}
|
|
@@ -752,46 +1044,42 @@ function buildToolCallIndex(msgs) {
|
|
|
752
1044
|
return idx;
|
|
753
1045
|
}
|
|
754
1046
|
var CONSTRAINT_PATTERNS = [
|
|
755
|
-
{
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
{
|
|
1047
|
+
{
|
|
1048
|
+
re: /\b(?:must|need|require|has to|important)\b.*\b(?:be|use|have|include|support)\b/i,
|
|
1049
|
+
cat: "requirement",
|
|
1050
|
+
conf: TUNING.CONFIDENCE_HIGH
|
|
1051
|
+
},
|
|
1052
|
+
{
|
|
1053
|
+
re: /\b(?:don't|never|avoid|shouldn't|must not|do not|no\s+(?:need|want))\b/i,
|
|
1054
|
+
cat: "prohibition",
|
|
1055
|
+
conf: TUNING.CONFIDENCE_MEDIUM
|
|
1056
|
+
},
|
|
1057
|
+
{
|
|
1058
|
+
re: /\b(?:prefer|like|want|would rather|should)\b.*\b(?:use|be|have|with)\b/i,
|
|
1059
|
+
cat: "preference",
|
|
1060
|
+
conf: TUNING.CONFIDENCE_LOW
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
re: /(?<![A-Za-z0-9_])(?:yapma|kullanma|sak\u0131n|sak\u0131nha|asla(?:\s+(?:kullanma|yapma|getirme))?|bunu yapma)(?![A-Za-z0-9_])/iu,
|
|
1064
|
+
cat: "prohibition",
|
|
1065
|
+
conf: TUNING.CONFIDENCE_MEDIUM
|
|
1066
|
+
},
|
|
1067
|
+
{
|
|
1068
|
+
re: /(?<![A-Za-z0-9_])(?:kritik|kritikal|\u00F6nemli|onemli|\u015Fart|sart|zorunlu|\u015Fart ko\u015Ful|\u00F6nemli \u015Fart|kesinlikle|kesinlikle \u015Fart|b\u00F6yle olsun|b\u00F6yle yap\u0131n|\u015F\u00F6yle olsun|\u015F\u00F6yle yap\u0131n)(?![A-Za-z0-9_])/iu,
|
|
1069
|
+
cat: "requirement",
|
|
1070
|
+
conf: TUNING.CONFIDENCE_MEDIUM
|
|
1071
|
+
},
|
|
1072
|
+
{
|
|
1073
|
+
re: /(?<![A-Za-z0-9_])(?:tercih|isterim|olsun|kullanal\u0131m|yapal\u0131m|istiyorum)(?![A-Za-z0-9_])/iu,
|
|
1074
|
+
cat: "preference",
|
|
1075
|
+
conf: TUNING.CONFIDENCE_LOW
|
|
1076
|
+
}
|
|
761
1077
|
];
|
|
762
1078
|
function isDiagnosticConstraintText(text) {
|
|
763
1079
|
const candidate = text.replace(/^\s*[-*]\s+/, "").trim();
|
|
764
1080
|
return /^(?:\[[^\]]+\]\s*)?(?:npm\s+(?:error|warn|notice|audit|verbose|info)\b|(?:rg|grep):|command exited\b)/i.test(candidate);
|
|
765
1081
|
}
|
|
766
1082
|
|
|
767
|
-
// src/utils/logger.ts
|
|
768
|
-
var DEBUG = process.env.DEBUG?.includes("smart-compact") ?? false;
|
|
769
|
-
function warn(msg, err) {
|
|
770
|
-
const detail = err instanceof Error ? err.message : err ?? "";
|
|
771
|
-
console.error(LOG_PREFIX + " " + msg + (detail ? ": " + detail : ""));
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// src/infra/paths.ts
|
|
775
|
-
import path from "path";
|
|
776
|
-
function home() {
|
|
777
|
-
return process.env.HOME ?? "/tmp";
|
|
778
|
-
}
|
|
779
|
-
function piAgentDir() {
|
|
780
|
-
return path.join(home(), ".pi", "agent");
|
|
781
|
-
}
|
|
782
|
-
function cacheDir() {
|
|
783
|
-
return path.join(piAgentDir(), ".cache");
|
|
784
|
-
}
|
|
785
|
-
function smartCompactCacheDir() {
|
|
786
|
-
return path.join(cacheDir(), "smart-compact");
|
|
787
|
-
}
|
|
788
|
-
function metricsLogFile() {
|
|
789
|
-
return path.join(cacheDir(), "compact-metrics.jsonl");
|
|
790
|
-
}
|
|
791
|
-
function damageReportsFile() {
|
|
792
|
-
return path.join(smartCompactCacheDir(), "damage-reports.jsonl");
|
|
793
|
-
}
|
|
794
|
-
|
|
795
1083
|
// src/infra/fs.ts
|
|
796
1084
|
import fs from "fs";
|
|
797
1085
|
function readJsonlTail(target, limit, maxBytes = 512 * 1024) {
|
|
@@ -886,7 +1174,10 @@ function withCodexWireLimit(model, opts) {
|
|
|
886
1174
|
onPayload: async (payload, requestModel) => {
|
|
887
1175
|
const transformed = await previous?.(payload, requestModel);
|
|
888
1176
|
const body = transformed ?? payload;
|
|
889
|
-
return body && typeof body === "object" ? {
|
|
1177
|
+
return body && typeof body === "object" ? {
|
|
1178
|
+
...body,
|
|
1179
|
+
max_output_tokens: opts.maxTokens
|
|
1180
|
+
} : body;
|
|
890
1181
|
}
|
|
891
1182
|
};
|
|
892
1183
|
}
|
|
@@ -907,11 +1198,12 @@ function assertSuccessful(message) {
|
|
|
907
1198
|
}
|
|
908
1199
|
return message;
|
|
909
1200
|
}
|
|
910
|
-
async function withProviderDeadline(opts, invoke) {
|
|
1201
|
+
async function withProviderDeadline(opts, invoke, modelId) {
|
|
911
1202
|
if (opts.signal?.aborted)
|
|
912
1203
|
throw new Error("LLM request aborted before dispatch");
|
|
913
1204
|
const controller = new AbortController;
|
|
914
|
-
const
|
|
1205
|
+
const multiplier = modelId && !((opts.codexWatchdogMs ?? 0) > 0) ? getProviderCaps(modelId).timeoutMultiplier : 1;
|
|
1206
|
+
const watchdogMs = Math.round(resolveCodexWatchdogMs(opts.maxTokens, opts.codexWatchdogMs) * multiplier);
|
|
915
1207
|
const abort = Promise.withResolvers();
|
|
916
1208
|
const abortFromCaller = () => {
|
|
917
1209
|
controller.abort(opts.signal?.reason);
|
|
@@ -984,7 +1276,7 @@ var rawLlmClient = {
|
|
|
984
1276
|
return completeChatGptCodex(model, body, bounded);
|
|
985
1277
|
const response = bounded.reasoning === undefined ? await (await resolveComplete())(model, body, bounded) : await (await resolveCompleteSimple())(model, body, bounded);
|
|
986
1278
|
return assertSuccessful(response);
|
|
987
|
-
});
|
|
1279
|
+
}, model.id);
|
|
988
1280
|
}
|
|
989
1281
|
};
|
|
990
1282
|
var defaultLlmClient = rawLlmClient;
|
|
@@ -998,7 +1290,10 @@ import crypto from "crypto";
|
|
|
998
1290
|
|
|
999
1291
|
// src/domain/scrub.ts
|
|
1000
1292
|
var SECRET_PATTERNS = [
|
|
1001
|
-
{
|
|
1293
|
+
{
|
|
1294
|
+
kind: "private-key",
|
|
1295
|
+
regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g
|
|
1296
|
+
},
|
|
1002
1297
|
{ kind: "aws-access-key", regex: /\bAKIA[0-9A-Z]{16}\b/g },
|
|
1003
1298
|
{ kind: "google-api-key", regex: /\bAIza[0-9A-Za-z_-]{30,}\b/g },
|
|
1004
1299
|
{ kind: "stripe-key", regex: /\b[rs]k_(?:live|test)_[0-9A-Za-z]{16,}\b/g },
|
|
@@ -1007,8 +1302,15 @@ var SECRET_PATTERNS = [
|
|
|
1007
1302
|
{ kind: "github-token", regex: /\bgh[pousr]_[A-Za-z0-9]{20,}\b/g },
|
|
1008
1303
|
{ kind: "api-key", regex: /\bsk-(?:ant-)?[A-Za-z0-9_-]{20,}\b/g },
|
|
1009
1304
|
{ kind: "slack-token", regex: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g },
|
|
1010
|
-
{
|
|
1011
|
-
|
|
1305
|
+
{
|
|
1306
|
+
kind: "jwt",
|
|
1307
|
+
regex: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g
|
|
1308
|
+
},
|
|
1309
|
+
{
|
|
1310
|
+
kind: "bearer-token",
|
|
1311
|
+
regex: /\bBearer\s+[A-Za-z0-9._~+/-]{12,}=*/gi,
|
|
1312
|
+
replacement: () => "Bearer [REDACTED:bearer-token]"
|
|
1313
|
+
},
|
|
1012
1314
|
{
|
|
1013
1315
|
kind: "connection-password",
|
|
1014
1316
|
regex: /\b([a-z][a-z0-9+.-]*:\/\/[^:\s/@]+:)[^@\s/]+(@)/gi,
|
|
@@ -1017,12 +1319,35 @@ var SECRET_PATTERNS = [
|
|
|
1017
1319
|
{
|
|
1018
1320
|
kind: "credential",
|
|
1019
1321
|
regex: /\b((?:[A-Za-z0-9]+[_-])*(?:api[_-]?key|access[_-]?token|auth[_-]?token|token|password|passwd|secret(?:[_-]?(?:access)?[_-]?key)?|client[_-]?secret)(?:[_-][A-Za-z0-9]+)*)\s*([:=])\s*["']?([^\s"']{16,})["']?/gi,
|
|
1020
|
-
replacement: (name, separator) => name + separator + "[REDACTED:credential]"
|
|
1322
|
+
replacement: (name, separator, value, match) => /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)+$/.test(value) ? match : name + separator + "[REDACTED:credential]"
|
|
1021
1323
|
}
|
|
1022
1324
|
];
|
|
1325
|
+
function passesLuhn(candidate) {
|
|
1326
|
+
const digits = candidate.replace(/\D/g, "");
|
|
1327
|
+
if (digits.length < 13 || digits.length > 19)
|
|
1328
|
+
return false;
|
|
1329
|
+
if (/^(\d)\1+$/.test(digits))
|
|
1330
|
+
return false;
|
|
1331
|
+
let sum = 0, double = false;
|
|
1332
|
+
for (let i = digits.length - 1;i >= 0; i--) {
|
|
1333
|
+
let d = digits.charCodeAt(i) - 48;
|
|
1334
|
+
if (double) {
|
|
1335
|
+
d *= 2;
|
|
1336
|
+
if (d > 9)
|
|
1337
|
+
d -= 9;
|
|
1338
|
+
}
|
|
1339
|
+
sum += d;
|
|
1340
|
+
double = !double;
|
|
1341
|
+
}
|
|
1342
|
+
return sum % 10 === 0;
|
|
1343
|
+
}
|
|
1023
1344
|
var PII_PATTERNS = [
|
|
1024
1345
|
{ kind: "email", regex: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi },
|
|
1025
|
-
{
|
|
1346
|
+
{
|
|
1347
|
+
kind: "payment-card",
|
|
1348
|
+
regex: /\b(?:\d[ -]*?){13,19}\b/g,
|
|
1349
|
+
replacement: (candidate) => passesLuhn(candidate) ? "[REDACTED:payment-card]" : candidate
|
|
1350
|
+
},
|
|
1026
1351
|
{ kind: "phone", regex: /(?<![\w.])(?:\+?\d[\d ()-]{8,}\d)(?![\w.])/g }
|
|
1027
1352
|
];
|
|
1028
1353
|
function redact(text, patterns) {
|
|
@@ -1030,15 +1355,22 @@ function redact(text, patterns) {
|
|
|
1030
1355
|
let value = text;
|
|
1031
1356
|
for (const pattern of patterns) {
|
|
1032
1357
|
value = value.replace(pattern.regex, (...args) => {
|
|
1033
|
-
|
|
1358
|
+
const match = String(args[0]);
|
|
1359
|
+
let replacement = "[REDACTED:" + pattern.kind + "]";
|
|
1034
1360
|
if (pattern.replacement) {
|
|
1035
1361
|
const groups = args.slice(1, -2).map(String);
|
|
1036
|
-
|
|
1362
|
+
replacement = pattern.replacement(...groups, match);
|
|
1037
1363
|
}
|
|
1038
|
-
|
|
1364
|
+
if (replacement === match)
|
|
1365
|
+
return match;
|
|
1366
|
+
counts.set(pattern.kind, (counts.get(pattern.kind) ?? 0) + 1);
|
|
1367
|
+
return replacement;
|
|
1039
1368
|
});
|
|
1040
1369
|
}
|
|
1041
|
-
return {
|
|
1370
|
+
return {
|
|
1371
|
+
value,
|
|
1372
|
+
findings: [...counts].map(([kind, count]) => ({ kind, count }))
|
|
1373
|
+
};
|
|
1042
1374
|
}
|
|
1043
1375
|
function mergeFindings(target, findings) {
|
|
1044
1376
|
for (const finding of findings)
|
|
@@ -1068,7 +1400,6 @@ var SECRET_KEY_NAMES = {
|
|
|
1068
1400
|
set_cookie: true,
|
|
1069
1401
|
otp: true,
|
|
1070
1402
|
one_time_password: true,
|
|
1071
|
-
pin: true,
|
|
1072
1403
|
passcode: true
|
|
1073
1404
|
};
|
|
1074
1405
|
function normalizeObjectKey(key) {
|
|
@@ -1134,7 +1465,7 @@ class SecretScrubber {
|
|
|
1134
1465
|
const output = {};
|
|
1135
1466
|
seen.set(value2, output);
|
|
1136
1467
|
for (const [key, item] of Object.entries(value2)) {
|
|
1137
|
-
const carriesSecret = typeof item === "string"
|
|
1468
|
+
const carriesSecret = typeof item === "string" && item.length >= 8;
|
|
1138
1469
|
if (this.secretsEnabled && isSecretBearingKey(key) && carriesSecret) {
|
|
1139
1470
|
output[key] = "[REDACTED:credential]";
|
|
1140
1471
|
recordCredential();
|
|
@@ -1145,7 +1476,10 @@ class SecretScrubber {
|
|
|
1145
1476
|
return output;
|
|
1146
1477
|
};
|
|
1147
1478
|
const value = visit(input);
|
|
1148
|
-
return {
|
|
1479
|
+
return {
|
|
1480
|
+
value,
|
|
1481
|
+
findings: [...findings].map(([kind, count]) => ({ kind, count }))
|
|
1482
|
+
};
|
|
1149
1483
|
}
|
|
1150
1484
|
count() {
|
|
1151
1485
|
return this.total;
|