acp-kernel 0.0.73-pr.303.169 → 0.0.73-pr.305.170
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/dist/compress.d.ts.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/hide-consumed.d.ts.map +1 -1
- package/dist/index.js +135 -55
- package/dist/index.js.map +1 -1
- package/dist/parse-compress-input.d.ts.map +1 -1
- package/dist/persist/index.js +2 -1
- package/dist/persist/index.js.map +1 -1
- package/dist/persist/state-merge.d.ts.map +1 -1
- package/dist/pipeline.d.ts +2 -0
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/report.d.ts.map +1 -1
- package/dist/search/index.d.ts.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/truncate-tools.d.ts +7 -0
- package/dist/truncate-tools.d.ts.map +1 -1
- package/dist/truncate.d.ts +5 -0
- package/dist/truncate.d.ts.map +1 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/compress.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAIA,OAAO,EAAkC,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAgBhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAUvD,OAAO,EAGL,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAIA,OAAO,EAAkC,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAgBhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAUvD,OAAO,EAGL,KAAK,YAAY,EAGlB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EACV,sBAAsB,EACtB,gBAAgB,EAChB,gBAAgB,EAEhB,MAAM,EAEN,WAAW,EAGX,iBAAiB,EAEjB,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,KAAK;IACpB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACxC;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,CAAC;IACxD,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,sBAAsB,CAAC;IACvE,YAAY,IAAI,YAAY,EAAE,CAAC;IAC/B,UAAU,CACR,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,gBAAgB,GACtB,gBAAgB,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,gBAAgB,EAAE,CAAC;IACnE,MAAM,CACJ,KAAK,EAAE,gBAAgB,EACvB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,YAAY,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;CAC7B;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,EAAE,CAAC;IACJ,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACnC;AA2DD,wBAAgB,UAAU,CAAC,KAAK,GAAE,KAAU,GAAG,eAAe,CA+U7D;AA0lCD,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,wBAAgB,aAAa,CAC3B,iBAAiB,EAAE,MAAM,EACzB,SAAS,GAAE,OAAO,CAAC,MAAM,CAAM,GAC9B,MAAM,CA+CR;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,wBAAgB,aAAa,CAC3B,iBAAiB,EAAE,MAAM,EACzB,SAAS,GAAE,OAAO,CAAC,MAAM,CAAM,GAC9B,MAAM,CA+CR;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CA8DvD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hide-consumed.d.ts","sourceRoot":"","sources":["../src/hide-consumed.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hide-consumed.d.ts","sourceRoot":"","sources":["../src/hide-consumed.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAYhE,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAClB;AA8FD,wBAAgB,yBAAyB,CACrC,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,WAAW,EAAE,GACxB,kBAAkB,CAwFpB"}
|
package/dist/index.js
CHANGED
|
@@ -296,6 +296,7 @@ function syncBlocks(messages, state) {
|
|
|
296
296
|
nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },
|
|
297
297
|
stats: { ...state.stats },
|
|
298
298
|
absorbed: (state.absorbed ?? []).map((record) => ({ ...record })),
|
|
299
|
+
terminalStreak: state.terminalStreak,
|
|
299
300
|
nextBlockId: state.nextBlockId,
|
|
300
301
|
nextRunId: state.nextRunId
|
|
301
302
|
};
|
|
@@ -353,7 +354,7 @@ function defaultConfig(modelContextLimit, overrides = {}) {
|
|
|
353
354
|
tier2GrowthMultiplier: 1.5
|
|
354
355
|
},
|
|
355
356
|
promotionThreshold: 5,
|
|
356
|
-
truncate: { threshold: 0.95 },
|
|
357
|
+
truncate: { threshold: 0.95, terminalEscapeAfter: 3 },
|
|
357
358
|
compress: {
|
|
358
359
|
minCompressRange: 5e3,
|
|
359
360
|
maxSummaryLength: 2e4,
|
|
@@ -405,6 +406,9 @@ function validateConfig(config) {
|
|
|
405
406
|
if (config.truncate.threshold <= 0 || config.truncate.threshold > 1) {
|
|
406
407
|
errors.push("truncate.threshold must be in (0, 1]");
|
|
407
408
|
}
|
|
409
|
+
if (config.truncate.terminalEscapeAfter !== void 0 && (!Number.isInteger(config.truncate.terminalEscapeAfter) || config.truncate.terminalEscapeAfter < 0)) {
|
|
410
|
+
errors.push("truncate.terminalEscapeAfter must be an integer >= 0");
|
|
411
|
+
}
|
|
408
412
|
for (const tier of [config.tiers.tier2Trigger, config.tiers.tier3Trigger]) {
|
|
409
413
|
if (tier < 1) errors.push("tier triggers must be >= 1");
|
|
410
414
|
}
|
|
@@ -654,47 +658,89 @@ var DEFAULTS = {
|
|
|
654
658
|
};
|
|
655
659
|
function truncateLargeToolOutputs(messages, tokenCount, config, countTokens, options = {}) {
|
|
656
660
|
const opts = { ...DEFAULTS, ...options };
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
const protectedIndex = messages.length - opts.protectRecentMessages;
|
|
661
|
-
const candidates = [];
|
|
662
|
-
for (let index = 0; index < messages.length; index++) {
|
|
663
|
-
if (index >= protectedIndex) break;
|
|
664
|
-
const message = messages[index];
|
|
665
|
-
if (message.contentType !== "tool-result") continue;
|
|
666
|
-
const text = message.text ?? "";
|
|
667
|
-
if (text.length === 0 || text.includes(TRUNCATION_MARKER)) continue;
|
|
668
|
-
const tokens = countTokens(text);
|
|
669
|
-
if (tokens < opts.minOutputTokens) continue;
|
|
670
|
-
candidates.push({ index, tokens });
|
|
661
|
+
const limit = config.modelContextLimit;
|
|
662
|
+
if (limit <= 0 || tokenCount < config.truncate.threshold * limit) {
|
|
663
|
+
return { messages, truncatedCount: 0, savedTokens: 0, candidatesFound: 0 };
|
|
671
664
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
665
|
+
const protectedIndex = messages.length - opts.protectRecentMessages;
|
|
666
|
+
const findCandidates = (predicate) => {
|
|
667
|
+
const found = [];
|
|
668
|
+
for (let i = 0; i < protectedIndex; i++) {
|
|
669
|
+
const message = messages[i];
|
|
670
|
+
if (!predicate(message)) continue;
|
|
671
|
+
const text = message.text ?? "";
|
|
672
|
+
if (text.length === 0 || text.includes(TRUNCATION_MARKER)) continue;
|
|
673
|
+
if (countTokens(text) < opts.minOutputTokens) continue;
|
|
674
|
+
found.push(message);
|
|
675
|
+
}
|
|
676
|
+
return found.sort(
|
|
677
|
+
(a, b) => countTokens(b.text ?? "") - countTokens(a.text ?? "")
|
|
678
|
+
);
|
|
679
|
+
};
|
|
680
|
+
const toolResults = findCandidates((m) => m.contentType === "tool-result");
|
|
681
|
+
const textMessages = options.includeTextMessages ? findCandidates(
|
|
682
|
+
(m) => m.contentType === "text" && (m.role === "user" || m.role === "assistant") && !isRenderedSummaryMessage(m) && !m.text?.startsWith(SUMMARY_HEADER)
|
|
683
|
+
) : [];
|
|
684
|
+
const candidatesFound = toolResults.length + textMessages.length;
|
|
677
685
|
let truncatedCount = 0;
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
const
|
|
684
|
-
|
|
686
|
+
let savedTokens = 0;
|
|
687
|
+
let remaining = tokenCount;
|
|
688
|
+
const targetTokens = config.truncate.threshold * limit * 0.9;
|
|
689
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
690
|
+
const applyTo = (candidates) => {
|
|
691
|
+
for (const candidate of candidates) {
|
|
692
|
+
if (remaining <= targetTokens) break;
|
|
693
|
+
const original = candidate.text ?? "";
|
|
694
|
+
const tokens = countTokens(original);
|
|
695
|
+
if (original.length <= opts.keepPrefixChars + opts.keepSuffixChars) {
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
const prefix = original.slice(0, opts.keepPrefixChars);
|
|
699
|
+
const suffix = original.slice(-opts.keepSuffixChars);
|
|
700
|
+
const replacement = `${prefix}
|
|
685
701
|
|
|
686
|
-
...${TRUNCATION_MARKER} \u2014 original ~${
|
|
702
|
+
...${TRUNCATION_MARKER} \u2014 original ~${tokens} tokens]...
|
|
687
703
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
);
|
|
697
|
-
|
|
704
|
+
${suffix}`;
|
|
705
|
+
replacements.set(candidate.id, replacement);
|
|
706
|
+
truncatedCount++;
|
|
707
|
+
remaining -= tokens - countTokens(replacement);
|
|
708
|
+
savedTokens += tokens - countTokens(replacement);
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
applyTo(toolResults);
|
|
712
|
+
applyTo(textMessages);
|
|
713
|
+
if (replacements.size === 0) {
|
|
714
|
+
return { messages, truncatedCount: 0, savedTokens: 0, candidatesFound };
|
|
715
|
+
}
|
|
716
|
+
return {
|
|
717
|
+
messages: messages.map(
|
|
718
|
+
(m) => replacements.has(m.id) ? { ...m, text: replacements.get(m.id) } : m
|
|
719
|
+
),
|
|
720
|
+
truncatedCount,
|
|
721
|
+
savedTokens,
|
|
722
|
+
candidatesFound
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// src/truncate.ts
|
|
727
|
+
function isHighSurrogate(c) {
|
|
728
|
+
return c >= 55296 && c <= 56319;
|
|
729
|
+
}
|
|
730
|
+
function isLowSurrogate(c) {
|
|
731
|
+
return c >= 56320 && c <= 57343;
|
|
732
|
+
}
|
|
733
|
+
function clampPrefix(text, maxUnits) {
|
|
734
|
+
const cut = Math.min(maxUnits, text.length);
|
|
735
|
+
if (cut > 0 && isHighSurrogate(text.charCodeAt(cut - 1))) return text.slice(0, cut - 1);
|
|
736
|
+
return text.slice(0, cut);
|
|
737
|
+
}
|
|
738
|
+
function clampWindow(text, start, end) {
|
|
739
|
+
let s = Math.max(0, Math.min(start, text.length));
|
|
740
|
+
let e = Math.min(text.length, Math.max(s, end));
|
|
741
|
+
if (s > 0 && isLowSurrogate(text.charCodeAt(s))) s += 1;
|
|
742
|
+
if (e > s && isHighSurrogate(text.charCodeAt(e - 1))) e -= 1;
|
|
743
|
+
return text.slice(s, Math.max(s, e));
|
|
698
744
|
}
|
|
699
745
|
|
|
700
746
|
// src/hide-consumed.ts
|
|
@@ -749,7 +795,7 @@ function compactEntry(entry) {
|
|
|
749
795
|
if (!entry || typeof entry !== "object") return entry;
|
|
750
796
|
const e = entry;
|
|
751
797
|
if (typeof e.summary !== "string" || e.summary.length <= SUMMARY_STUB_CHARS) return entry;
|
|
752
|
-
return { ...e, summary: `${e.summary
|
|
798
|
+
return { ...e, summary: `${clampPrefix(e.summary, SUMMARY_STUB_CHARS - 1)}\u2026` };
|
|
753
799
|
}
|
|
754
800
|
function serializeCompacted(obj, content, contentWasString) {
|
|
755
801
|
let changed = false;
|
|
@@ -2323,6 +2369,7 @@ function createCore(ports = {}) {
|
|
|
2323
2369
|
state.nudge.lastPerMessageNudgeTokens = 0;
|
|
2324
2370
|
state.nudge.lastNudgeShownTokens = 0;
|
|
2325
2371
|
state.nudge.lastShownByTier = {};
|
|
2372
|
+
state.terminalStreak = 0;
|
|
2326
2373
|
}
|
|
2327
2374
|
return {
|
|
2328
2375
|
state,
|
|
@@ -2352,7 +2399,9 @@ function createCore(ports = {}) {
|
|
|
2352
2399
|
return {
|
|
2353
2400
|
messages: result.messages,
|
|
2354
2401
|
state: result.state,
|
|
2355
|
-
nudge: result.effects.nudge
|
|
2402
|
+
nudge: result.effects.nudge,
|
|
2403
|
+
terminalEscape: result.effects.terminalEscape,
|
|
2404
|
+
truncationSkipped: result.effects.truncationSkipped
|
|
2356
2405
|
};
|
|
2357
2406
|
}
|
|
2358
2407
|
function decompress(blockId, state) {
|
|
@@ -2545,18 +2594,49 @@ var emergencyTruncateNode = {
|
|
|
2545
2594
|
name: "emergency-truncate",
|
|
2546
2595
|
run(io, ctx) {
|
|
2547
2596
|
const usage = ctx.config.modelContextLimit > 0 ? ctx.tokenCount / ctx.config.modelContextLimit : 0;
|
|
2548
|
-
|
|
2597
|
+
const prevStreak = io.state.terminalStreak ?? 0;
|
|
2598
|
+
if (usage < ctx.config.truncate.threshold) {
|
|
2599
|
+
return prevStreak > 0 ? { ...io, state: { ...io.state, terminalStreak: 0 } } : io;
|
|
2600
|
+
}
|
|
2549
2601
|
const trunc = truncateLargeToolOutputs(
|
|
2550
2602
|
io.messages,
|
|
2551
2603
|
ctx.tokenCount,
|
|
2552
2604
|
ctx.config,
|
|
2553
2605
|
ctx.countTokens,
|
|
2554
|
-
{
|
|
2606
|
+
{
|
|
2607
|
+
protectRecentMessages: ctx.config.preserveRecentMessages,
|
|
2608
|
+
includeTextMessages: true
|
|
2609
|
+
}
|
|
2555
2610
|
);
|
|
2611
|
+
const nudge = io.effects.nudge;
|
|
2612
|
+
const minBenefit = nudge?.breakdown.minPressureBenefit ?? 0;
|
|
2613
|
+
const maxPending = nudge?.breakdown.maxPending ?? 0;
|
|
2614
|
+
const noViableCompression = nudge !== void 0 && (minBenefit > 0 ? maxPending < minBenefit : maxPending <= 0);
|
|
2615
|
+
const stuck = noViableCompression && trunc.savedTokens <= 0;
|
|
2616
|
+
const streak = stuck ? prevStreak + 1 : 0;
|
|
2617
|
+
const escapeAfter = ctx.config.truncate.terminalEscapeAfter ?? 3;
|
|
2618
|
+
const triggered = stuck && escapeAfter > 0 && streak >= escapeAfter;
|
|
2619
|
+
const effects = {
|
|
2620
|
+
...io.effects,
|
|
2621
|
+
truncatedCount: trunc.truncatedCount
|
|
2622
|
+
};
|
|
2623
|
+
if (trunc.savedTokens <= 0) {
|
|
2624
|
+
effects.truncationSkipped = trunc.candidatesFound === 0 ? `emergency-truncate ran at ${Math.round(usage * 100)}% usage but found no truncatable content (no oversized tool-result or text message outside the last ${ctx.config.preserveRecentMessages} messages)` : `emergency-truncate found ${trunc.candidatesFound} candidate(s) at ${Math.round(usage * 100)}% usage but none were large enough to save tokens`;
|
|
2625
|
+
}
|
|
2626
|
+
if (triggered) {
|
|
2627
|
+
effects.terminalEscape = {
|
|
2628
|
+
message: `Usage at ${Math.round(usage * 100)}% (${ctx.tokenCount}/${ctx.config.modelContextLimit} tokens) persists with nothing compressible above the benefit floor and no truncatable content: compression cannot reduce this context below the limit. Start a new session or use native compaction.`,
|
|
2629
|
+
usage,
|
|
2630
|
+
tokenCount: ctx.tokenCount,
|
|
2631
|
+
modelContextLimit: ctx.config.modelContextLimit,
|
|
2632
|
+
stuckEvents: streak
|
|
2633
|
+
};
|
|
2634
|
+
}
|
|
2556
2635
|
return {
|
|
2557
2636
|
...io,
|
|
2558
2637
|
messages: trunc.messages,
|
|
2559
|
-
|
|
2638
|
+
state: { ...io.state, terminalStreak: streak },
|
|
2639
|
+
effects
|
|
2560
2640
|
};
|
|
2561
2641
|
}
|
|
2562
2642
|
};
|
|
@@ -2649,7 +2729,8 @@ function applySingleRange(input) {
|
|
|
2649
2729
|
for (const m of input.messages) {
|
|
2650
2730
|
if (!m.id) continue;
|
|
2651
2731
|
if (m.contentType === "reasoning") reasoningIds.add(m.id);
|
|
2652
|
-
if (m.role === "assistant" && m.contentType === "tool-call")
|
|
2732
|
+
if (m.role === "assistant" && m.contentType === "tool-call")
|
|
2733
|
+
callIds.add(m.id);
|
|
2653
2734
|
}
|
|
2654
2735
|
const withdrawIds = /* @__PURE__ */ new Set();
|
|
2655
2736
|
let splitTurnCount = 0;
|
|
@@ -2920,6 +3001,7 @@ function decideNudge(input) {
|
|
|
2920
3001
|
const t1Eff = tiers[1]?.pending ?? 0;
|
|
2921
3002
|
const t2Pen = tiers[2]?.pending ?? 0;
|
|
2922
3003
|
const t3Pen = tiers[3]?.pending ?? 0;
|
|
3004
|
+
const maxPending = Math.max(0, t1Eff, t2Pen, t3Pen);
|
|
2923
3005
|
const firstSightMassReady = state.nudge.lastNudgeShownTokens === 0 && baseline === 0 && usage >= config.nudge.minContextLimitPct && Math.max(t1Eff, t2Pen, t3Pen) >= nudgeGrowthTokens;
|
|
2924
3006
|
const growthReady = firstSightMassReady || growthSinceReference >= growthFloor;
|
|
2925
3007
|
const t2Count = tiers[2]?.targetBlocks.length ?? 0;
|
|
@@ -2992,10 +3074,6 @@ function decideNudge(input) {
|
|
|
2992
3074
|
(t) => ((tiers[t]?.pending ?? 0) >= nudgeGrowthTokens || countReady(t)) && (state.nudge.lastShownByTier[t] ?? 0) > 0 && tokenCount - (state.nudge.lastShownByTier[t] ?? 0) < growthFloor
|
|
2993
3075
|
).map((t) => `T${t} (cadence)`);
|
|
2994
3076
|
const blockedHint = blocked.length > 0 ? `, blocked: ${blocked.join(", ")}` : "";
|
|
2995
|
-
const maxPending = Math.max(
|
|
2996
|
-
0,
|
|
2997
|
-
...Object.values(tiers).map((t) => t.pending)
|
|
2998
|
-
);
|
|
2999
3077
|
const pendingShort = maxPending < nudgeGrowthTokens;
|
|
3000
3078
|
const growthShort = growthSinceReference < growthFloor;
|
|
3001
3079
|
const parts = [];
|
|
@@ -3039,7 +3117,8 @@ function decideNudge(input) {
|
|
|
3039
3117
|
minPressureBenefit,
|
|
3040
3118
|
pendingT1: tiers[1].pending,
|
|
3041
3119
|
pendingT2: tiers[2].pending,
|
|
3042
|
-
pendingT3: tiers[3].pending
|
|
3120
|
+
pendingT3: tiers[3].pending,
|
|
3121
|
+
maxPending
|
|
3043
3122
|
},
|
|
3044
3123
|
contextBreakdown: ctxBreakdown
|
|
3045
3124
|
};
|
|
@@ -3079,6 +3158,7 @@ function cloneState(state) {
|
|
|
3079
3158
|
nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },
|
|
3080
3159
|
stats: { ...state.stats },
|
|
3081
3160
|
absorbed: (state.absorbed ?? []).map((record) => ({ ...record })),
|
|
3161
|
+
terminalStreak: state.terminalStreak,
|
|
3082
3162
|
nextBlockId: state.nextBlockId,
|
|
3083
3163
|
nextRunId: state.nextRunId
|
|
3084
3164
|
};
|
|
@@ -3765,7 +3845,7 @@ ${block.summary}
|
|
|
3765
3845
|
const lines = [`Active compression blocks (${activeBlocks2.length}):`];
|
|
3766
3846
|
for (const block of activeBlocks2) {
|
|
3767
3847
|
const range = `${block.effectiveMessageIds.length} messages`;
|
|
3768
|
-
const preview = block.summary
|
|
3848
|
+
const preview = clampPrefix(block.summary, 200);
|
|
3769
3849
|
lines.push(`
|
|
3770
3850
|
${block.blockId} | ${range} | "${block.topic ?? "(none)"}"`);
|
|
3771
3851
|
lines.push(` ${preview}${block.summary.length > 200 ? "..." : ""}`);
|
|
@@ -4047,7 +4127,7 @@ function deriveTopicFromSummary(summary) {
|
|
|
4047
4127
|
const source = heading !== null ? heading[1] : summary.split("\n").find((l) => l.trim().length > 0) ?? "";
|
|
4048
4128
|
const text = source.trim().replace(/^[\u2022\-*]\s+/, "");
|
|
4049
4129
|
if (text.length === 0) return void 0;
|
|
4050
|
-
return text.length > 60 ? text
|
|
4130
|
+
return text.length > 60 ? clampPrefix(text, 60).trimEnd() : text;
|
|
4051
4131
|
}
|
|
4052
4132
|
function splitLineEntries(content) {
|
|
4053
4133
|
const parts = content.split(/\n(?=\s*(?:["']\s*,\s*)?["']?\s*[mb]\d{1,7}\s*(?:[-\u2013\u2014\u2026~]|\.\.\.|to)\s*[mb]\d{1,7}\b)/i).map((p) => p.trim().replace(/^(?:["']\s*,?\s*)+/, "").replace(/["']\s*$/, "")).filter((p) => p.length > 0);
|
|
@@ -4631,7 +4711,7 @@ function messageDocs(msgs) {
|
|
|
4631
4711
|
kind: "message",
|
|
4632
4712
|
ref: m.ref,
|
|
4633
4713
|
text: m.text,
|
|
4634
|
-
title: `${m.role}: ${m.text
|
|
4714
|
+
title: `${m.role}: ${clampPrefix(m.text, 60)}`,
|
|
4635
4715
|
role: m.role,
|
|
4636
4716
|
blockId: m.blockId,
|
|
4637
4717
|
tier: m.tier,
|
|
@@ -4696,7 +4776,7 @@ async function searchBlocksAsync(docs, query, options = {}) {
|
|
|
4696
4776
|
function makePreview(text, query, len) {
|
|
4697
4777
|
if (!text) return "";
|
|
4698
4778
|
const terms = query.toLowerCase().trim().split(/\s+/).filter((t) => t.length > 1);
|
|
4699
|
-
if (terms.length === 0) return text
|
|
4779
|
+
if (terms.length === 0) return clampPrefix(text, len);
|
|
4700
4780
|
const lower = text.toLowerCase();
|
|
4701
4781
|
let hitIdx = -1;
|
|
4702
4782
|
for (const term of terms) {
|
|
@@ -4706,13 +4786,13 @@ function makePreview(text, query, len) {
|
|
|
4706
4786
|
break;
|
|
4707
4787
|
}
|
|
4708
4788
|
}
|
|
4709
|
-
if (hitIdx < 0) return text
|
|
4789
|
+
if (hitIdx < 0) return clampPrefix(text, len);
|
|
4710
4790
|
const half = Math.max(0, Math.floor(len / 2) - 10);
|
|
4711
4791
|
const start = Math.max(0, hitIdx - half);
|
|
4712
4792
|
const end = Math.min(text.length, start + len);
|
|
4713
4793
|
const prefix = start > 0 ? "\u2026" : "";
|
|
4714
4794
|
const suffix = end < text.length ? "\u2026" : "";
|
|
4715
|
-
return prefix + text
|
|
4795
|
+
return prefix + clampWindow(text, start, end).trim() + suffix;
|
|
4716
4796
|
}
|
|
4717
4797
|
export {
|
|
4718
4798
|
ABSORB_PROMPT_MARKER,
|