opencode-acp 1.14.4 → 1.14.5
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 +10 -23
- package/README.zh-CN.md +10 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +144 -899
- package/dist/index.js.map +1 -1
- package/dist/lib/commands/context.d.ts.map +1 -1
- package/dist/lib/commands/help.d.ts.map +1 -1
- package/dist/lib/commands/index.d.ts +0 -1
- package/dist/lib/commands/index.d.ts.map +1 -1
- package/dist/lib/compress/index.d.ts +1 -2
- package/dist/lib/compress/index.d.ts.map +1 -1
- package/dist/lib/compress/pipeline.d.ts.map +1 -1
- package/dist/lib/config-validation.d.ts.map +1 -1
- package/dist/lib/config.d.ts +0 -14
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/hooks.d.ts.map +1 -1
- package/dist/lib/messages/inject/inject.d.ts.map +1 -1
- package/dist/lib/messages/prune.d.ts.map +1 -1
- package/dist/lib/messages/truncate-tools.d.ts +10 -0
- package/dist/lib/messages/truncate-tools.d.ts.map +1 -0
- package/dist/lib/prompts/extensions/nudge.d.ts +1 -2
- package/dist/lib/prompts/extensions/nudge.d.ts.map +1 -1
- package/dist/lib/prompts/system.d.ts +1 -1
- package/dist/lib/prompts/system.d.ts.map +1 -1
- package/dist/lib/state/persistence.d.ts.map +1 -1
- package/dist/lib/state/state.d.ts.map +1 -1
- package/dist/lib/state/types.d.ts +12 -1
- package/dist/lib/state/types.d.ts.map +1 -1
- package/dist/lib/state/utils.d.ts +0 -1
- package/dist/lib/state/utils.d.ts.map +1 -1
- package/dist/lib/ui/notification.d.ts +0 -2
- package/dist/lib/ui/notification.d.ts.map +1 -1
- package/dist/lib/ui/utils.d.ts +1 -3
- package/dist/lib/ui/utils.d.ts.map +1 -1
- package/package.json +2 -1
- package/dist/lib/commands/sweep.d.ts +0 -23
- package/dist/lib/commands/sweep.d.ts.map +0 -1
- package/dist/lib/compress/prune-tool.d.ts +0 -4
- package/dist/lib/compress/prune-tool.d.ts.map +0 -1
- package/dist/lib/gc/truncate.d.ts +0 -15
- package/dist/lib/gc/truncate.d.ts.map +0 -1
- package/dist/lib/strategies/deduplication.d.ts +0 -10
- package/dist/lib/strategies/deduplication.d.ts.map +0 -1
- package/dist/lib/strategies/index.d.ts +0 -3
- package/dist/lib/strategies/index.d.ts.map +0 -1
- package/dist/lib/strategies/purge-errors.d.ts +0 -13
- package/dist/lib/strategies/purge-errors.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -883,7 +883,6 @@ var VALID_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
883
883
|
"commands.protectedTools",
|
|
884
884
|
"manualMode",
|
|
885
885
|
"manualMode.enabled",
|
|
886
|
-
"manualMode.automaticStrategies",
|
|
887
886
|
"compress",
|
|
888
887
|
"compress.mode",
|
|
889
888
|
"compress.permission",
|
|
@@ -923,14 +922,6 @@ var VALID_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
923
922
|
"gc.batchCleanup.lowThreshold",
|
|
924
923
|
"gc.batchCleanup.highThreshold",
|
|
925
924
|
"gc.batchCleanup.forceThreshold",
|
|
926
|
-
"strategies",
|
|
927
|
-
"strategies.deduplication",
|
|
928
|
-
"strategies.deduplication.enabled",
|
|
929
|
-
"strategies.deduplication.protectedTools",
|
|
930
|
-
"strategies.purgeErrors",
|
|
931
|
-
"strategies.purgeErrors.enabled",
|
|
932
|
-
"strategies.purgeErrors.turns",
|
|
933
|
-
"strategies.purgeErrors.protectedTools",
|
|
934
925
|
"qualityGate",
|
|
935
926
|
"qualityGate.enabled",
|
|
936
927
|
"qualityGate.algorithm",
|
|
@@ -1089,13 +1080,6 @@ function validateConfigTypes(config) {
|
|
|
1089
1080
|
actual: typeof manualMode.enabled
|
|
1090
1081
|
});
|
|
1091
1082
|
}
|
|
1092
|
-
if (manualMode.automaticStrategies !== void 0 && typeof manualMode.automaticStrategies !== "boolean") {
|
|
1093
|
-
errors.push({
|
|
1094
|
-
key: "manualMode.automaticStrategies",
|
|
1095
|
-
expected: "boolean",
|
|
1096
|
-
actual: typeof manualMode.automaticStrategies
|
|
1097
|
-
});
|
|
1098
|
-
}
|
|
1099
1083
|
}
|
|
1100
1084
|
}
|
|
1101
1085
|
const compress = config.compress;
|
|
@@ -1470,81 +1454,6 @@ function validateConfigTypes(config) {
|
|
|
1470
1454
|
}
|
|
1471
1455
|
}
|
|
1472
1456
|
}
|
|
1473
|
-
const strategies = config.strategies;
|
|
1474
|
-
if (strategies !== void 0) {
|
|
1475
|
-
if (typeof strategies !== "object" || strategies === null || Array.isArray(strategies)) {
|
|
1476
|
-
errors.push({
|
|
1477
|
-
key: "strategies",
|
|
1478
|
-
expected: "object",
|
|
1479
|
-
actual: typeof strategies
|
|
1480
|
-
});
|
|
1481
|
-
} else {
|
|
1482
|
-
const dedup = strategies.deduplication;
|
|
1483
|
-
if (dedup !== void 0) {
|
|
1484
|
-
if (typeof dedup !== "object" || dedup === null || Array.isArray(dedup)) {
|
|
1485
|
-
errors.push({
|
|
1486
|
-
key: "strategies.deduplication",
|
|
1487
|
-
expected: "object",
|
|
1488
|
-
actual: typeof dedup
|
|
1489
|
-
});
|
|
1490
|
-
} else {
|
|
1491
|
-
if (dedup.enabled !== void 0 && typeof dedup.enabled !== "boolean") {
|
|
1492
|
-
errors.push({
|
|
1493
|
-
key: "strategies.deduplication.enabled",
|
|
1494
|
-
expected: "boolean",
|
|
1495
|
-
actual: typeof dedup.enabled
|
|
1496
|
-
});
|
|
1497
|
-
}
|
|
1498
|
-
if (dedup.protectedTools !== void 0 && !Array.isArray(dedup.protectedTools)) {
|
|
1499
|
-
errors.push({
|
|
1500
|
-
key: "strategies.deduplication.protectedTools",
|
|
1501
|
-
expected: "string[]",
|
|
1502
|
-
actual: typeof dedup.protectedTools
|
|
1503
|
-
});
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
const purge = strategies.purgeErrors;
|
|
1508
|
-
if (purge !== void 0) {
|
|
1509
|
-
if (typeof purge !== "object" || purge === null || Array.isArray(purge)) {
|
|
1510
|
-
errors.push({
|
|
1511
|
-
key: "strategies.purgeErrors",
|
|
1512
|
-
expected: "object",
|
|
1513
|
-
actual: typeof purge
|
|
1514
|
-
});
|
|
1515
|
-
} else {
|
|
1516
|
-
if (purge.enabled !== void 0 && typeof purge.enabled !== "boolean") {
|
|
1517
|
-
errors.push({
|
|
1518
|
-
key: "strategies.purgeErrors.enabled",
|
|
1519
|
-
expected: "boolean",
|
|
1520
|
-
actual: typeof purge.enabled
|
|
1521
|
-
});
|
|
1522
|
-
}
|
|
1523
|
-
if (purge.turns !== void 0 && typeof purge.turns !== "number") {
|
|
1524
|
-
errors.push({
|
|
1525
|
-
key: "strategies.purgeErrors.turns",
|
|
1526
|
-
expected: "number",
|
|
1527
|
-
actual: typeof purge.turns
|
|
1528
|
-
});
|
|
1529
|
-
}
|
|
1530
|
-
if (typeof purge.turns === "number" && purge.turns < 1) {
|
|
1531
|
-
errors.push({
|
|
1532
|
-
key: "strategies.purgeErrors.turns",
|
|
1533
|
-
expected: "positive number (>= 1)",
|
|
1534
|
-
actual: `${purge.turns} (will be clamped to 1)`
|
|
1535
|
-
});
|
|
1536
|
-
}
|
|
1537
|
-
if (purge.protectedTools !== void 0 && !Array.isArray(purge.protectedTools)) {
|
|
1538
|
-
errors.push({
|
|
1539
|
-
key: "strategies.purgeErrors.protectedTools",
|
|
1540
|
-
expected: "string[]",
|
|
1541
|
-
actual: typeof purge.protectedTools
|
|
1542
|
-
});
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
1547
|
-
}
|
|
1548
1457
|
return errors;
|
|
1549
1458
|
}
|
|
1550
1459
|
|
|
@@ -1614,8 +1523,7 @@ var defaultConfig = {
|
|
|
1614
1523
|
protectedTools: [...DEFAULT_PROTECTED_TOOLS]
|
|
1615
1524
|
},
|
|
1616
1525
|
manualMode: {
|
|
1617
|
-
enabled: false
|
|
1618
|
-
automaticStrategies: true
|
|
1526
|
+
enabled: false
|
|
1619
1527
|
},
|
|
1620
1528
|
turnProtection: {
|
|
1621
1529
|
enabled: false,
|
|
@@ -1652,17 +1560,6 @@ var defaultConfig = {
|
|
|
1652
1560
|
preserveRecentTokens: 5e3,
|
|
1653
1561
|
preserveLastUserMessage: true
|
|
1654
1562
|
},
|
|
1655
|
-
strategies: {
|
|
1656
|
-
deduplication: {
|
|
1657
|
-
enabled: true,
|
|
1658
|
-
protectedTools: []
|
|
1659
|
-
},
|
|
1660
|
-
purgeErrors: {
|
|
1661
|
-
enabled: true,
|
|
1662
|
-
turns: 4,
|
|
1663
|
-
protectedTools: []
|
|
1664
|
-
}
|
|
1665
|
-
},
|
|
1666
1563
|
gc: {
|
|
1667
1564
|
algorithm: "truncate",
|
|
1668
1565
|
promotionThreshold: 5,
|
|
@@ -1770,32 +1667,6 @@ function loadConfigFile(configPath) {
|
|
|
1770
1667
|
return { data: null, parseError: error.message || "Failed to parse config" };
|
|
1771
1668
|
}
|
|
1772
1669
|
}
|
|
1773
|
-
function mergeStrategies(base, override) {
|
|
1774
|
-
if (!override) {
|
|
1775
|
-
return base;
|
|
1776
|
-
}
|
|
1777
|
-
return {
|
|
1778
|
-
deduplication: {
|
|
1779
|
-
enabled: override.deduplication?.enabled ?? base.deduplication.enabled,
|
|
1780
|
-
protectedTools: [
|
|
1781
|
-
.../* @__PURE__ */ new Set([
|
|
1782
|
-
...base.deduplication.protectedTools,
|
|
1783
|
-
...override.deduplication?.protectedTools ?? []
|
|
1784
|
-
])
|
|
1785
|
-
]
|
|
1786
|
-
},
|
|
1787
|
-
purgeErrors: {
|
|
1788
|
-
enabled: override.purgeErrors?.enabled ?? base.purgeErrors.enabled,
|
|
1789
|
-
turns: override.purgeErrors?.turns ?? base.purgeErrors.turns,
|
|
1790
|
-
protectedTools: [
|
|
1791
|
-
.../* @__PURE__ */ new Set([
|
|
1792
|
-
...base.purgeErrors.protectedTools,
|
|
1793
|
-
...override.purgeErrors?.protectedTools ?? []
|
|
1794
|
-
])
|
|
1795
|
-
]
|
|
1796
|
-
}
|
|
1797
|
-
};
|
|
1798
|
-
}
|
|
1799
1670
|
function mergeCompress(base, override) {
|
|
1800
1671
|
if (!override) {
|
|
1801
1672
|
return base;
|
|
@@ -1843,8 +1714,7 @@ function mergeCommands(base, override) {
|
|
|
1843
1714
|
function mergeManualMode(base, override) {
|
|
1844
1715
|
if (override === void 0) return base;
|
|
1845
1716
|
return {
|
|
1846
|
-
enabled: override.enabled ?? base.enabled
|
|
1847
|
-
automaticStrategies: override.automaticStrategies ?? base.automaticStrategies
|
|
1717
|
+
enabled: override.enabled ?? base.enabled
|
|
1848
1718
|
};
|
|
1849
1719
|
}
|
|
1850
1720
|
function mergeExperimental(base, override) {
|
|
@@ -1862,8 +1732,7 @@ function deepCloneConfig(config) {
|
|
|
1862
1732
|
protectedTools: [...config.commands.protectedTools]
|
|
1863
1733
|
},
|
|
1864
1734
|
manualMode: {
|
|
1865
|
-
enabled: config.manualMode.enabled
|
|
1866
|
-
automaticStrategies: config.manualMode.automaticStrategies
|
|
1735
|
+
enabled: config.manualMode.enabled
|
|
1867
1736
|
},
|
|
1868
1737
|
turnProtection: { ...config.turnProtection },
|
|
1869
1738
|
experimental: { ...config.experimental },
|
|
@@ -1874,16 +1743,6 @@ function deepCloneConfig(config) {
|
|
|
1874
1743
|
modelMinLimits: { ...config.compress.modelMinLimits },
|
|
1875
1744
|
protectedTools: [...config.compress.protectedTools]
|
|
1876
1745
|
},
|
|
1877
|
-
strategies: {
|
|
1878
|
-
deduplication: {
|
|
1879
|
-
...config.strategies.deduplication,
|
|
1880
|
-
protectedTools: [...config.strategies.deduplication.protectedTools]
|
|
1881
|
-
},
|
|
1882
|
-
purgeErrors: {
|
|
1883
|
-
...config.strategies.purgeErrors,
|
|
1884
|
-
protectedTools: [...config.strategies.purgeErrors.protectedTools]
|
|
1885
|
-
}
|
|
1886
|
-
},
|
|
1887
1746
|
gc: {
|
|
1888
1747
|
...config.gc,
|
|
1889
1748
|
batchCleanup: { ...config.gc.batchCleanup }
|
|
@@ -1932,7 +1791,6 @@ function mergeLayer(config, data) {
|
|
|
1932
1791
|
],
|
|
1933
1792
|
compress: mergeCompress(config.compress, data.compress),
|
|
1934
1793
|
gc: mergeGC(config.gc, data.gc),
|
|
1935
|
-
strategies: mergeStrategies(config.strategies, data.strategies),
|
|
1936
1794
|
qualityGate: mergeQualityGate(config.qualityGate, data.qualityGate)
|
|
1937
1795
|
};
|
|
1938
1796
|
}
|
|
@@ -2000,6 +1858,9 @@ Using previous/default values`
|
|
|
2000
1858
|
return config;
|
|
2001
1859
|
}
|
|
2002
1860
|
|
|
1861
|
+
// lib/compress/message.ts
|
|
1862
|
+
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
1863
|
+
|
|
2003
1864
|
// lib/compress/types.ts
|
|
2004
1865
|
function resolveToolContext(factoryCtx, sessionID) {
|
|
2005
1866
|
const state = factoryCtx.registry.get(sessionID);
|
|
@@ -2017,9 +1878,6 @@ function resolveToolContext(factoryCtx, sessionID) {
|
|
|
2017
1878
|
};
|
|
2018
1879
|
}
|
|
2019
1880
|
|
|
2020
|
-
// lib/compress/message.ts
|
|
2021
|
-
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
2022
|
-
|
|
2023
1881
|
// lib/token-utils.ts
|
|
2024
1882
|
import * as _anthropicTokenizer from "@anthropic-ai/tokenizer";
|
|
2025
1883
|
|
|
@@ -2207,14 +2065,6 @@ function extractToolContent(part) {
|
|
|
2207
2065
|
}
|
|
2208
2066
|
return contents;
|
|
2209
2067
|
}
|
|
2210
|
-
function getTotalToolTokens(state, toolIds) {
|
|
2211
|
-
let total = 0;
|
|
2212
|
-
for (const id of toolIds) {
|
|
2213
|
-
const entry = state.toolParameters.get(id);
|
|
2214
|
-
total += entry?.tokenCount ?? 0;
|
|
2215
|
-
}
|
|
2216
|
-
return total;
|
|
2217
|
-
}
|
|
2218
2068
|
function countAllMessageTokens(msg) {
|
|
2219
2069
|
const parts = Array.isArray(msg.parts) ? msg.parts : [];
|
|
2220
2070
|
const texts = [];
|
|
@@ -2860,20 +2710,20 @@ function matchesGlob(inputPath, pattern) {
|
|
|
2860
2710
|
regex += "$";
|
|
2861
2711
|
return new RegExp(regex).test(input);
|
|
2862
2712
|
}
|
|
2863
|
-
function getFilePathsFromParameters(
|
|
2713
|
+
function getFilePathsFromParameters(tool7, parameters) {
|
|
2864
2714
|
if (typeof parameters !== "object" || parameters === null) {
|
|
2865
2715
|
return [];
|
|
2866
2716
|
}
|
|
2867
2717
|
const paths = [];
|
|
2868
2718
|
const params = parameters;
|
|
2869
|
-
if (
|
|
2719
|
+
if (tool7 === "apply_patch" && typeof params.patchText === "string") {
|
|
2870
2720
|
const pathRegex = /\*\*\* (?:Add|Delete|Update) File: ([^\n\r]+)/g;
|
|
2871
2721
|
let match;
|
|
2872
2722
|
while ((match = pathRegex.exec(params.patchText)) !== null) {
|
|
2873
2723
|
paths.push(match[1].trim());
|
|
2874
2724
|
}
|
|
2875
2725
|
}
|
|
2876
|
-
if (
|
|
2726
|
+
if (tool7 === "multiedit") {
|
|
2877
2727
|
if (typeof params.filePath === "string") {
|
|
2878
2728
|
paths.push(params.filePath);
|
|
2879
2729
|
}
|
|
@@ -3696,15 +3546,6 @@ function countTurns(state, messages) {
|
|
|
3696
3546
|
}
|
|
3697
3547
|
return turnCount;
|
|
3698
3548
|
}
|
|
3699
|
-
function loadPruneMap(obj) {
|
|
3700
|
-
if (!obj || typeof obj !== "object") {
|
|
3701
|
-
return /* @__PURE__ */ new Map();
|
|
3702
|
-
}
|
|
3703
|
-
const entries = Object.entries(obj).filter(
|
|
3704
|
-
(entry) => typeof entry[0] === "string" && typeof entry[1] === "number"
|
|
3705
|
-
);
|
|
3706
|
-
return new Map(entries);
|
|
3707
|
-
}
|
|
3708
3549
|
function createPruneMessagesState() {
|
|
3709
3550
|
return {
|
|
3710
3551
|
byMessageId: /* @__PURE__ */ new Map(),
|
|
@@ -3892,7 +3733,6 @@ function getTierTokenUsage(state) {
|
|
|
3892
3733
|
}
|
|
3893
3734
|
function resetOnCompaction(state) {
|
|
3894
3735
|
state.toolParameters.clear();
|
|
3895
|
-
state.prune.tools = /* @__PURE__ */ new Map();
|
|
3896
3736
|
state.nudges = {
|
|
3897
3737
|
contextLimitAnchors: /* @__PURE__ */ new Set(),
|
|
3898
3738
|
turnNudgeAnchors: /* @__PURE__ */ new Set(),
|
|
@@ -3904,7 +3744,8 @@ function resetOnCompaction(state) {
|
|
|
3904
3744
|
lastTier2NudgeTokens: void 0,
|
|
3905
3745
|
lastTier3NudgeTokens: void 0,
|
|
3906
3746
|
shouldInjectThisTurn: void 0,
|
|
3907
|
-
compressBaselineSet: false
|
|
3747
|
+
compressBaselineSet: false,
|
|
3748
|
+
lastProcessedCompressMessageId: void 0
|
|
3908
3749
|
};
|
|
3909
3750
|
state.messageIds = {
|
|
3910
3751
|
byRawId: /* @__PURE__ */ new Map(),
|
|
@@ -3968,7 +3809,6 @@ async function saveSessionState(sessionState, logger, sessionName) {
|
|
|
3968
3809
|
const state = {
|
|
3969
3810
|
sessionName,
|
|
3970
3811
|
prune: {
|
|
3971
|
-
tools: Object.fromEntries(sessionState.prune.tools),
|
|
3972
3812
|
messages: serializePruneMessagesState(sessionState.prune.messages)
|
|
3973
3813
|
},
|
|
3974
3814
|
nudges: {
|
|
@@ -4003,10 +3843,9 @@ async function loadSessionState(sessionId, logger) {
|
|
|
4003
3843
|
}
|
|
4004
3844
|
const content = await fs.readFile(filePath, "utf-8");
|
|
4005
3845
|
const state = JSON.parse(content);
|
|
4006
|
-
const hasPruneTools = state?.prune?.tools && typeof state.prune.tools === "object";
|
|
4007
3846
|
const hasPruneMessages = state?.prune?.messages && typeof state.prune.messages === "object";
|
|
4008
3847
|
const hasNudgeFormat = state?.nudges && typeof state.nudges === "object";
|
|
4009
|
-
if (!state || !state.prune || !
|
|
3848
|
+
if (!state || !state.prune || !hasPruneMessages || !state.stats || !hasNudgeFormat) {
|
|
4010
3849
|
logger.warn("Invalid session state file, ignoring", {
|
|
4011
3850
|
sessionId
|
|
4012
3851
|
});
|
|
@@ -4094,7 +3933,8 @@ async function loadAllSessionStats(logger) {
|
|
|
4094
3933
|
const state = JSON.parse(content);
|
|
4095
3934
|
if (state?.stats?.totalPruneTokens && state?.prune) {
|
|
4096
3935
|
result.totalTokens += state.stats.totalPruneTokens;
|
|
4097
|
-
|
|
3936
|
+
const legacy = state.prune.tools;
|
|
3937
|
+
result.totalTools += legacy ? Object.keys(legacy).length : 0;
|
|
4098
3938
|
result.totalMessages += state.prune.messages?.byMessageId ? Object.keys(state.prune.messages.byMessageId).length : 0;
|
|
4099
3939
|
result.sessionCount++;
|
|
4100
3940
|
}
|
|
@@ -4582,7 +4422,6 @@ function createSessionState() {
|
|
|
4582
4422
|
compressPermission: void 0,
|
|
4583
4423
|
pendingManualTrigger: null,
|
|
4584
4424
|
prune: {
|
|
4585
|
-
tools: /* @__PURE__ */ new Map(),
|
|
4586
4425
|
messages: createPruneMessagesState()
|
|
4587
4426
|
},
|
|
4588
4427
|
nudges: {
|
|
@@ -4596,7 +4435,8 @@ function createSessionState() {
|
|
|
4596
4435
|
lastTier2NudgeTokens: void 0,
|
|
4597
4436
|
lastTier3NudgeTokens: void 0,
|
|
4598
4437
|
shouldInjectThisTurn: void 0,
|
|
4599
|
-
compressBaselineSet: false
|
|
4438
|
+
compressBaselineSet: false,
|
|
4439
|
+
lastProcessedCompressMessageId: void 0
|
|
4600
4440
|
},
|
|
4601
4441
|
stats: {
|
|
4602
4442
|
pruneTokenCounter: 0,
|
|
@@ -4627,7 +4467,6 @@ function resetSessionState(state) {
|
|
|
4627
4467
|
state.compressPermission = void 0;
|
|
4628
4468
|
state.pendingManualTrigger = null;
|
|
4629
4469
|
state.prune = {
|
|
4630
|
-
tools: /* @__PURE__ */ new Map(),
|
|
4631
4470
|
messages: createPruneMessagesState()
|
|
4632
4471
|
};
|
|
4633
4472
|
state.nudges = {
|
|
@@ -4641,7 +4480,8 @@ function resetSessionState(state) {
|
|
|
4641
4480
|
lastTier2NudgeTokens: void 0,
|
|
4642
4481
|
lastTier3NudgeTokens: void 0,
|
|
4643
4482
|
shouldInjectThisTurn: void 0,
|
|
4644
|
-
compressBaselineSet: false
|
|
4483
|
+
compressBaselineSet: false,
|
|
4484
|
+
lastProcessedCompressMessageId: void 0
|
|
4645
4485
|
};
|
|
4646
4486
|
state.stats = {
|
|
4647
4487
|
pruneTokenCounter: 0,
|
|
@@ -4682,7 +4522,6 @@ async function ensureSessionInitialized(client, state, sessionId, logger, messag
|
|
|
4682
4522
|
}
|
|
4683
4523
|
return;
|
|
4684
4524
|
}
|
|
4685
|
-
state.prune.tools = loadPruneMap(persisted.prune.tools);
|
|
4686
4525
|
state.prune.messages = loadPruneMessagesState(persisted.prune.messages);
|
|
4687
4526
|
state.nudges.contextLimitAnchors = new Set(persisted.nudges.contextLimitAnchors || []);
|
|
4688
4527
|
state.nudges.turnNudgeAnchors = /* @__PURE__ */ new Set([
|
|
@@ -4808,255 +4647,7 @@ function trimToolParametersCache(state) {
|
|
|
4808
4647
|
}
|
|
4809
4648
|
}
|
|
4810
4649
|
|
|
4811
|
-
// lib/strategies/deduplication.ts
|
|
4812
|
-
var deduplicate = (state, logger, config, messages) => {
|
|
4813
|
-
if (state.manualMode && !config.manualMode.automaticStrategies) {
|
|
4814
|
-
return;
|
|
4815
|
-
}
|
|
4816
|
-
if (!config.strategies.deduplication.enabled) {
|
|
4817
|
-
return;
|
|
4818
|
-
}
|
|
4819
|
-
const allToolIds = state.toolIdList;
|
|
4820
|
-
if (allToolIds.length === 0) {
|
|
4821
|
-
return;
|
|
4822
|
-
}
|
|
4823
|
-
const unprunedIds = allToolIds.filter((id) => !state.prune.tools.has(id));
|
|
4824
|
-
if (unprunedIds.length === 0) {
|
|
4825
|
-
return;
|
|
4826
|
-
}
|
|
4827
|
-
const protectedTools = config.strategies.deduplication.protectedTools;
|
|
4828
|
-
const signatureMap = /* @__PURE__ */ new Map();
|
|
4829
|
-
for (const id of unprunedIds) {
|
|
4830
|
-
const metadata = state.toolParameters.get(id);
|
|
4831
|
-
if (!metadata) {
|
|
4832
|
-
continue;
|
|
4833
|
-
}
|
|
4834
|
-
if (isToolNameProtected(metadata.tool, protectedTools)) {
|
|
4835
|
-
continue;
|
|
4836
|
-
}
|
|
4837
|
-
const filePaths = getFilePathsFromParameters(metadata.tool, metadata.parameters);
|
|
4838
|
-
if (isFilePathProtected(filePaths, config.protectedFilePatterns)) {
|
|
4839
|
-
continue;
|
|
4840
|
-
}
|
|
4841
|
-
const signature = createToolSignature(metadata.tool, metadata.parameters);
|
|
4842
|
-
if (!signatureMap.has(signature)) {
|
|
4843
|
-
signatureMap.set(signature, []);
|
|
4844
|
-
}
|
|
4845
|
-
const ids = signatureMap.get(signature);
|
|
4846
|
-
if (ids) {
|
|
4847
|
-
ids.push(id);
|
|
4848
|
-
}
|
|
4849
|
-
}
|
|
4850
|
-
const newPruneIds = [];
|
|
4851
|
-
for (const [, ids] of signatureMap.entries()) {
|
|
4852
|
-
if (ids.length > 1) {
|
|
4853
|
-
const idsToRemove = ids.slice(0, -1);
|
|
4854
|
-
newPruneIds.push(...idsToRemove);
|
|
4855
|
-
}
|
|
4856
|
-
}
|
|
4857
|
-
state.stats.totalPruneTokens += getTotalToolTokens(state, newPruneIds);
|
|
4858
|
-
if (newPruneIds.length > 0) {
|
|
4859
|
-
for (const id of newPruneIds) {
|
|
4860
|
-
const entry = state.toolParameters.get(id);
|
|
4861
|
-
state.prune.tools.set(id, entry?.tokenCount ?? 0);
|
|
4862
|
-
}
|
|
4863
|
-
logger.debug(`Marked ${newPruneIds.length} duplicate tool calls for pruning`);
|
|
4864
|
-
}
|
|
4865
|
-
};
|
|
4866
|
-
function createToolSignature(tool8, parameters) {
|
|
4867
|
-
if (!parameters) {
|
|
4868
|
-
return tool8;
|
|
4869
|
-
}
|
|
4870
|
-
const normalized = normalizeParameters(parameters);
|
|
4871
|
-
const sorted = sortObjectKeys(normalized);
|
|
4872
|
-
return `${tool8}::${JSON.stringify(sorted)}`;
|
|
4873
|
-
}
|
|
4874
|
-
function normalizeParameters(params) {
|
|
4875
|
-
if (typeof params !== "object" || params === null) return params;
|
|
4876
|
-
if (Array.isArray(params)) return params;
|
|
4877
|
-
const normalized = {};
|
|
4878
|
-
for (const [key, value] of Object.entries(params)) {
|
|
4879
|
-
if (value !== void 0 && value !== null) {
|
|
4880
|
-
normalized[key] = value;
|
|
4881
|
-
}
|
|
4882
|
-
}
|
|
4883
|
-
return normalized;
|
|
4884
|
-
}
|
|
4885
|
-
function sortObjectKeys(obj) {
|
|
4886
|
-
if (typeof obj !== "object" || obj === null) return obj;
|
|
4887
|
-
if (Array.isArray(obj)) return obj.map(sortObjectKeys);
|
|
4888
|
-
const sorted = {};
|
|
4889
|
-
for (const key of Object.keys(obj).sort()) {
|
|
4890
|
-
sorted[key] = sortObjectKeys(obj[key]);
|
|
4891
|
-
}
|
|
4892
|
-
return sorted;
|
|
4893
|
-
}
|
|
4894
|
-
|
|
4895
|
-
// lib/strategies/purge-errors.ts
|
|
4896
|
-
var purgeErrors = (state, logger, config, messages) => {
|
|
4897
|
-
if (state.manualMode && !config.manualMode.automaticStrategies) {
|
|
4898
|
-
return;
|
|
4899
|
-
}
|
|
4900
|
-
if (!config.strategies.purgeErrors.enabled) {
|
|
4901
|
-
return;
|
|
4902
|
-
}
|
|
4903
|
-
const allToolIds = state.toolIdList;
|
|
4904
|
-
if (allToolIds.length === 0) {
|
|
4905
|
-
return;
|
|
4906
|
-
}
|
|
4907
|
-
const unprunedIds = allToolIds.filter((id) => !state.prune.tools.has(id));
|
|
4908
|
-
if (unprunedIds.length === 0) {
|
|
4909
|
-
return;
|
|
4910
|
-
}
|
|
4911
|
-
const protectedTools = config.strategies.purgeErrors.protectedTools;
|
|
4912
|
-
const turnThreshold = Math.max(1, config.strategies.purgeErrors.turns);
|
|
4913
|
-
const newPruneIds = [];
|
|
4914
|
-
for (const id of unprunedIds) {
|
|
4915
|
-
const metadata = state.toolParameters.get(id);
|
|
4916
|
-
if (!metadata) {
|
|
4917
|
-
continue;
|
|
4918
|
-
}
|
|
4919
|
-
if (isToolNameProtected(metadata.tool, protectedTools)) {
|
|
4920
|
-
continue;
|
|
4921
|
-
}
|
|
4922
|
-
const filePaths = getFilePathsFromParameters(metadata.tool, metadata.parameters);
|
|
4923
|
-
if (isFilePathProtected(filePaths, config.protectedFilePatterns)) {
|
|
4924
|
-
continue;
|
|
4925
|
-
}
|
|
4926
|
-
if (metadata.status !== "error") {
|
|
4927
|
-
continue;
|
|
4928
|
-
}
|
|
4929
|
-
const turnAge = state.currentTurn - metadata.turn;
|
|
4930
|
-
if (turnAge >= turnThreshold) {
|
|
4931
|
-
newPruneIds.push(id);
|
|
4932
|
-
}
|
|
4933
|
-
}
|
|
4934
|
-
if (newPruneIds.length > 0) {
|
|
4935
|
-
state.stats.totalPruneTokens += getTotalToolTokens(state, newPruneIds);
|
|
4936
|
-
for (const id of newPruneIds) {
|
|
4937
|
-
const entry = state.toolParameters.get(id);
|
|
4938
|
-
state.prune.tools.set(id, entry?.tokenCount ?? 0);
|
|
4939
|
-
}
|
|
4940
|
-
logger.debug(
|
|
4941
|
-
`Marked ${newPruneIds.length} error tool calls for pruning (older than ${turnThreshold} turns)`
|
|
4942
|
-
);
|
|
4943
|
-
}
|
|
4944
|
-
};
|
|
4945
|
-
|
|
4946
4650
|
// lib/ui/utils.ts
|
|
4947
|
-
function extractParameterKey(tool8, parameters) {
|
|
4948
|
-
if (!parameters) return "";
|
|
4949
|
-
if (tool8 === "read" && parameters.filePath) {
|
|
4950
|
-
const offset = parameters.offset;
|
|
4951
|
-
const limit = parameters.limit;
|
|
4952
|
-
if (offset !== void 0 && limit !== void 0) {
|
|
4953
|
-
return `${parameters.filePath} (lines ${offset}-${offset + limit})`;
|
|
4954
|
-
}
|
|
4955
|
-
if (offset !== void 0) {
|
|
4956
|
-
return `${parameters.filePath} (lines ${offset}+)`;
|
|
4957
|
-
}
|
|
4958
|
-
if (limit !== void 0) {
|
|
4959
|
-
return `${parameters.filePath} (lines 0-${limit})`;
|
|
4960
|
-
}
|
|
4961
|
-
return parameters.filePath;
|
|
4962
|
-
}
|
|
4963
|
-
if ((tool8 === "write" || tool8 === "edit" || tool8 === "multiedit") && parameters.filePath) {
|
|
4964
|
-
return parameters.filePath;
|
|
4965
|
-
}
|
|
4966
|
-
if (tool8 === "apply_patch" && typeof parameters.patchText === "string") {
|
|
4967
|
-
const pathRegex = /\*\*\* (?:Add|Delete|Update) File: ([^\n\r]+)/g;
|
|
4968
|
-
const paths = [];
|
|
4969
|
-
let match;
|
|
4970
|
-
while ((match = pathRegex.exec(parameters.patchText)) !== null) {
|
|
4971
|
-
paths.push(match[1].trim());
|
|
4972
|
-
}
|
|
4973
|
-
if (paths.length > 0) {
|
|
4974
|
-
const uniquePaths = [...new Set(paths)];
|
|
4975
|
-
const count = uniquePaths.length;
|
|
4976
|
-
const plural = count > 1 ? "s" : "";
|
|
4977
|
-
if (count === 1) return uniquePaths[0];
|
|
4978
|
-
if (count === 2) return uniquePaths.join(", ");
|
|
4979
|
-
return `${count} file${plural}: ${uniquePaths[0]}, ${uniquePaths[1]}...`;
|
|
4980
|
-
}
|
|
4981
|
-
return "patch";
|
|
4982
|
-
}
|
|
4983
|
-
if (tool8 === "list") {
|
|
4984
|
-
return parameters.path || "(current directory)";
|
|
4985
|
-
}
|
|
4986
|
-
if (tool8 === "glob") {
|
|
4987
|
-
if (parameters.pattern) {
|
|
4988
|
-
const pathInfo = parameters.path ? ` in ${parameters.path}` : "";
|
|
4989
|
-
return `"${parameters.pattern}"${pathInfo}`;
|
|
4990
|
-
}
|
|
4991
|
-
return "(unknown pattern)";
|
|
4992
|
-
}
|
|
4993
|
-
if (tool8 === "grep") {
|
|
4994
|
-
if (parameters.pattern) {
|
|
4995
|
-
const pathInfo = parameters.path ? ` in ${parameters.path}` : "";
|
|
4996
|
-
return `"${parameters.pattern}"${pathInfo}`;
|
|
4997
|
-
}
|
|
4998
|
-
return "(unknown pattern)";
|
|
4999
|
-
}
|
|
5000
|
-
if (tool8 === "bash") {
|
|
5001
|
-
if (parameters.description) return parameters.description;
|
|
5002
|
-
if (parameters.command) {
|
|
5003
|
-
return parameters.command.length > 50 ? parameters.command.substring(0, 50) + "..." : parameters.command;
|
|
5004
|
-
}
|
|
5005
|
-
}
|
|
5006
|
-
if (tool8 === "webfetch" && parameters.url) {
|
|
5007
|
-
return parameters.url;
|
|
5008
|
-
}
|
|
5009
|
-
if (tool8 === "websearch" && parameters.query) {
|
|
5010
|
-
return `"${parameters.query}"`;
|
|
5011
|
-
}
|
|
5012
|
-
if (tool8 === "codesearch" && parameters.query) {
|
|
5013
|
-
return `"${parameters.query}"`;
|
|
5014
|
-
}
|
|
5015
|
-
if (tool8 === "todowrite") {
|
|
5016
|
-
return `${parameters.todos?.length || 0} todos`;
|
|
5017
|
-
}
|
|
5018
|
-
if (tool8 === "todoread") {
|
|
5019
|
-
return "read todo list";
|
|
5020
|
-
}
|
|
5021
|
-
if (tool8 === "task" && parameters.description) {
|
|
5022
|
-
return parameters.description;
|
|
5023
|
-
}
|
|
5024
|
-
if (tool8 === "skill" && parameters.name) {
|
|
5025
|
-
return parameters.name;
|
|
5026
|
-
}
|
|
5027
|
-
if (tool8 === "lsp") {
|
|
5028
|
-
const op = parameters.operation || "lsp";
|
|
5029
|
-
const path = parameters.filePath || "";
|
|
5030
|
-
const line = parameters.line;
|
|
5031
|
-
const char = parameters.character;
|
|
5032
|
-
if (path && line !== void 0 && char !== void 0) {
|
|
5033
|
-
return `${op} ${path}:${line}:${char}`;
|
|
5034
|
-
}
|
|
5035
|
-
if (path) {
|
|
5036
|
-
return `${op} ${path}`;
|
|
5037
|
-
}
|
|
5038
|
-
return op;
|
|
5039
|
-
}
|
|
5040
|
-
if (tool8 === "question") {
|
|
5041
|
-
const questions = parameters.questions;
|
|
5042
|
-
if (Array.isArray(questions) && questions.length > 0) {
|
|
5043
|
-
const headers = questions.map((q) => q.header || "").filter(Boolean).slice(0, 3);
|
|
5044
|
-
const count = questions.length;
|
|
5045
|
-
const plural = count > 1 ? "s" : "";
|
|
5046
|
-
if (headers.length > 0) {
|
|
5047
|
-
const suffix = count > 3 ? ` (+${count - 3} more)` : "";
|
|
5048
|
-
return `${count} question${plural}: ${headers.join(", ")}${suffix}`;
|
|
5049
|
-
}
|
|
5050
|
-
return `${count} question${plural}`;
|
|
5051
|
-
}
|
|
5052
|
-
return "question";
|
|
5053
|
-
}
|
|
5054
|
-
const paramStr = JSON.stringify(parameters);
|
|
5055
|
-
if (paramStr === "{}" || paramStr === "[]" || paramStr === "null") {
|
|
5056
|
-
return "";
|
|
5057
|
-
}
|
|
5058
|
-
return paramStr.substring(0, 50);
|
|
5059
|
-
}
|
|
5060
4651
|
function formatAge(createdAt) {
|
|
5061
4652
|
const elapsed = Date.now() - createdAt;
|
|
5062
4653
|
if (elapsed < 6e4) return "just now";
|
|
@@ -5071,10 +4662,6 @@ function formatTokenCount(tokens, compact) {
|
|
|
5071
4662
|
}
|
|
5072
4663
|
return tokens.toString() + suffix;
|
|
5073
4664
|
}
|
|
5074
|
-
function truncate(str, maxLen = 60) {
|
|
5075
|
-
if (str.length <= maxLen) return str;
|
|
5076
|
-
return str.slice(0, maxLen - 3) + "...";
|
|
5077
|
-
}
|
|
5078
4665
|
function formatProgressBar(messageIds, prunedMessages, recentMessageIds, width = 50) {
|
|
5079
4666
|
const ACTIVE = "\u2588";
|
|
5080
4667
|
const PRUNED = "\u2591";
|
|
@@ -5134,48 +4721,6 @@ function cacheSystemPromptTokens(state, messages) {
|
|
|
5134
4721
|
const estimatedSystemTokens = Math.max(0, firstInputTokens - countTokens2(firstUserText));
|
|
5135
4722
|
state.systemPromptTokens = estimatedSystemTokens > 0 ? estimatedSystemTokens : void 0;
|
|
5136
4723
|
}
|
|
5137
|
-
function shortenPath(input, workingDirectory) {
|
|
5138
|
-
const inPathMatch = input.match(/^(.+) in (.+)$/);
|
|
5139
|
-
if (inPathMatch) {
|
|
5140
|
-
const prefix = inPathMatch[1];
|
|
5141
|
-
const pathPart = inPathMatch[2];
|
|
5142
|
-
const shortenedPath = shortenSinglePath(pathPart, workingDirectory);
|
|
5143
|
-
return `${prefix} in ${shortenedPath}`;
|
|
5144
|
-
}
|
|
5145
|
-
return shortenSinglePath(input, workingDirectory);
|
|
5146
|
-
}
|
|
5147
|
-
function shortenSinglePath(path, workingDirectory) {
|
|
5148
|
-
if (workingDirectory) {
|
|
5149
|
-
if (path.startsWith(workingDirectory + "/")) {
|
|
5150
|
-
return path.slice(workingDirectory.length + 1);
|
|
5151
|
-
}
|
|
5152
|
-
if (path === workingDirectory) {
|
|
5153
|
-
return ".";
|
|
5154
|
-
}
|
|
5155
|
-
}
|
|
5156
|
-
return path;
|
|
5157
|
-
}
|
|
5158
|
-
function formatPrunedItemsList(pruneToolIds, toolMetadata, workingDirectory) {
|
|
5159
|
-
const lines = [];
|
|
5160
|
-
for (const id of pruneToolIds) {
|
|
5161
|
-
const metadata = toolMetadata.get(id);
|
|
5162
|
-
if (metadata) {
|
|
5163
|
-
const paramKey = extractParameterKey(metadata.tool, metadata.parameters);
|
|
5164
|
-
if (paramKey) {
|
|
5165
|
-
const displayKey = truncate(shortenPath(paramKey, workingDirectory), 60);
|
|
5166
|
-
lines.push(`\u2192 ${metadata.tool}: ${displayKey}`);
|
|
5167
|
-
} else {
|
|
5168
|
-
lines.push(`\u2192 ${metadata.tool}`);
|
|
5169
|
-
}
|
|
5170
|
-
}
|
|
5171
|
-
}
|
|
5172
|
-
const knownCount = pruneToolIds.filter((id) => toolMetadata.has(id)).length;
|
|
5173
|
-
const unknownCount = pruneToolIds.length - knownCount;
|
|
5174
|
-
if (unknownCount > 0) {
|
|
5175
|
-
lines.push(`\u2192 (${unknownCount} tool${unknownCount > 1 ? "s" : ""} with unknown metadata)`);
|
|
5176
|
-
}
|
|
5177
|
-
return lines;
|
|
5178
|
-
}
|
|
5179
4724
|
|
|
5180
4725
|
// lib/ui/notification.ts
|
|
5181
4726
|
var TOAST_BODY_MAX_LINES = 12;
|
|
@@ -6413,8 +5958,6 @@ async function prepareSession(ctx, toolCtx, title) {
|
|
|
6413
5958
|
ctx.config
|
|
6414
5959
|
);
|
|
6415
5960
|
assignMessageRefs(ctx.state, rawMessages);
|
|
6416
|
-
deduplicate(ctx.state, ctx.logger, ctx.config, rawMessages);
|
|
6417
|
-
purgeErrors(ctx.state, ctx.logger, ctx.config, rawMessages);
|
|
6418
5961
|
return {
|
|
6419
5962
|
rawMessages,
|
|
6420
5963
|
searchContext: buildSearchContext(ctx.state, rawMessages)
|
|
@@ -6537,7 +6080,7 @@ function normalizeRef(ref) {
|
|
|
6537
6080
|
}
|
|
6538
6081
|
function formatKeptMessage(msg, ref, maxChars) {
|
|
6539
6082
|
const formatted = formatByType(msg);
|
|
6540
|
-
const truncated =
|
|
6083
|
+
const truncated = truncate(formatted, maxChars);
|
|
6541
6084
|
return `
|
|
6542
6085
|
--- [${ref}: ${labelForMessage(msg)}] ---
|
|
6543
6086
|
${truncated}
|
|
@@ -6550,11 +6093,11 @@ function formatByType(msg) {
|
|
|
6550
6093
|
return part.text;
|
|
6551
6094
|
}
|
|
6552
6095
|
if (part.type === "tool") {
|
|
6553
|
-
const
|
|
6096
|
+
const tool7 = part.tool || "unknown";
|
|
6554
6097
|
const state = part.state || {};
|
|
6555
6098
|
const input = state.input || {};
|
|
6556
6099
|
const output = state.output || "";
|
|
6557
|
-
switch (
|
|
6100
|
+
switch (tool7) {
|
|
6558
6101
|
case "bash":
|
|
6559
6102
|
case "interactive_bash": {
|
|
6560
6103
|
const cmd = typeof input === "string" ? input : input.command || JSON.stringify(input);
|
|
@@ -6583,7 +6126,7 @@ ${content}`;
|
|
|
6583
6126
|
if (output && typeof output === "string" && output.length > 0) {
|
|
6584
6127
|
return output;
|
|
6585
6128
|
}
|
|
6586
|
-
const compact = JSON.stringify({ tool:
|
|
6129
|
+
const compact = JSON.stringify({ tool: tool7, input }, null, 0);
|
|
6587
6130
|
return compact.length > 500 ? compact.slice(0, 500) + "..." : compact;
|
|
6588
6131
|
}
|
|
6589
6132
|
}
|
|
@@ -6594,15 +6137,15 @@ ${content}`;
|
|
|
6594
6137
|
function labelForMessage(msg) {
|
|
6595
6138
|
for (const part of msg.parts || []) {
|
|
6596
6139
|
if (part.type === "tool") {
|
|
6597
|
-
const
|
|
6140
|
+
const tool7 = part.tool || "unknown";
|
|
6598
6141
|
const input = part.state?.input || {};
|
|
6599
6142
|
const fp = input.filePath || input.path || input.command || "";
|
|
6600
|
-
return fp ? `${
|
|
6143
|
+
return fp ? `${tool7}: ${String(fp).slice(0, 60)}` : tool7;
|
|
6601
6144
|
}
|
|
6602
6145
|
}
|
|
6603
6146
|
return msg.info.role === "user" ? "user" : "text";
|
|
6604
6147
|
}
|
|
6605
|
-
function
|
|
6148
|
+
function truncate(text, maxChars) {
|
|
6606
6149
|
if (text.length <= maxChars) return text;
|
|
6607
6150
|
return text.slice(0, maxChars) + `
|
|
6608
6151
|
... [truncated, ${text.length} chars total]`;
|
|
@@ -7317,8 +6860,8 @@ var resolveEffectiveCompressPermission = (basePermission, hostPermissions, agent
|
|
|
7317
6860
|
agentName ? hostPermissions.agents[agentName] : void 0
|
|
7318
6861
|
) ? "deny" : basePermission;
|
|
7319
6862
|
};
|
|
7320
|
-
var hasExplicitToolPermission = (permissionConfig,
|
|
7321
|
-
return permissionConfig ? Object.prototype.hasOwnProperty.call(permissionConfig,
|
|
6863
|
+
var hasExplicitToolPermission = (permissionConfig, tool7) => {
|
|
6864
|
+
return permissionConfig ? Object.prototype.hasOwnProperty.call(permissionConfig, tool7) : false;
|
|
7322
6865
|
};
|
|
7323
6866
|
|
|
7324
6867
|
// lib/compress-permission.ts
|
|
@@ -7509,7 +7052,7 @@ var dropEmptyMessages = (messages) => {
|
|
|
7509
7052
|
};
|
|
7510
7053
|
|
|
7511
7054
|
// lib/prompts/extensions/nudge.ts
|
|
7512
|
-
function buildCompressedBlockGuidance(state,
|
|
7055
|
+
function buildCompressedBlockGuidance(state, context) {
|
|
7513
7056
|
const activeBlockIds = Array.from(state.prune.messages.activeBlockIds).filter((id) => Number.isInteger(id) && id > 0).sort((a, b) => a - b);
|
|
7514
7057
|
const blockCount = activeBlockIds.length;
|
|
7515
7058
|
const blocksForStats = activeBlockIds.map((id) => state.prune.messages.blocksById.get(id)).filter((b) => b !== void 0 && b.active);
|
|
@@ -7550,32 +7093,6 @@ function buildCompressedBlockGuidance(state, gcConfig, context) {
|
|
|
7550
7093
|
}
|
|
7551
7094
|
}
|
|
7552
7095
|
}
|
|
7553
|
-
const usageRatio = context?.currentTokens && context?.modelContextLimit ? context.currentTokens / context.modelContextLimit : 0;
|
|
7554
|
-
if (gcConfig && usageRatio > 0.9) {
|
|
7555
|
-
const promotionThreshold = gcConfig.promotionThreshold;
|
|
7556
|
-
const agingBlocks = [];
|
|
7557
|
-
for (const blockId of activeBlockIds) {
|
|
7558
|
-
const block = state.prune.messages.blocksById.get(blockId);
|
|
7559
|
-
if (!block) continue;
|
|
7560
|
-
const survived = block.survivedCount ?? 0;
|
|
7561
|
-
const gen = block.generation ?? "young";
|
|
7562
|
-
const sizeK = (block.summary.length / 1e3).toFixed(1);
|
|
7563
|
-
const preview = block.summary.slice(0, 120).replace(/\n/g, " ");
|
|
7564
|
-
if (gen === "old" || survived >= promotionThreshold - 2) {
|
|
7565
|
-
agingBlocks.push(
|
|
7566
|
-
` b${blockId}: age=${survived}/${promotionThreshold}, gen=${gen}, size=${sizeK}K chars \u2014 ${preview}...`
|
|
7567
|
-
);
|
|
7568
|
-
}
|
|
7569
|
-
}
|
|
7570
|
-
if (agingBlocks.length > 0) {
|
|
7571
|
-
lines.push("");
|
|
7572
|
-
lines.push("\u26A0\uFE0F Block aging warning \u2014 context near limit, these blocks may be truncated by last-resort GC:");
|
|
7573
|
-
lines.push(...agingBlocks);
|
|
7574
|
-
lines.push(
|
|
7575
|
-
"Re-summarize these blocks into concise new ones to preserve key facts. At 100% context, oversized blocks are auto-truncated as a last resort."
|
|
7576
|
-
);
|
|
7577
|
-
}
|
|
7578
|
-
}
|
|
7579
7096
|
return lines.join("\n");
|
|
7580
7097
|
}
|
|
7581
7098
|
function renderMessagePriorityGuidance(priorityLabel, refs) {
|
|
@@ -8151,7 +7668,7 @@ function estimateContextComposition(messages, state, protectedTools = [], protec
|
|
|
8151
7668
|
perTool.sort((a, b) => b.tokens - a.tokens);
|
|
8152
7669
|
perCode.sort((a, b) => b.tokens - a.tokens);
|
|
8153
7670
|
perText.sort((a, b) => b.tokens - a.tokens);
|
|
8154
|
-
const toolTypeBreakdown = Array.from(toolTypeMap.entries()).map(([
|
|
7671
|
+
const toolTypeBreakdown = Array.from(toolTypeMap.entries()).map(([tool7, tokens]) => ({ tool: tool7, tokens })).sort((a, b) => b.tokens - a.tokens);
|
|
8155
7672
|
return {
|
|
8156
7673
|
toolTokens,
|
|
8157
7674
|
codeTokens,
|
|
@@ -8508,38 +8025,45 @@ var injectCompressNudges = (state, config, logger, messages, prompts, compressio
|
|
|
8508
8025
|
const currentTurnStart = lastUserIdx >= 0 ? lastUserIdx + 1 : 0;
|
|
8509
8026
|
const currentTurnHasCompress = messages.slice(currentTurnStart).some((m) => m.info.role === "assistant" && messageHasCompressAttempt(m));
|
|
8510
8027
|
if (currentTurnHasCompress) {
|
|
8511
|
-
const
|
|
8512
|
-
|
|
8513
|
-
state.nudges.
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
const
|
|
8524
|
-
if (
|
|
8525
|
-
const
|
|
8526
|
-
const
|
|
8527
|
-
|
|
8528
|
-
|
|
8529
|
-
const
|
|
8530
|
-
const
|
|
8531
|
-
|
|
8028
|
+
const lastCompressMsg = messages.slice(currentTurnStart).findLast((m) => m.info.role === "assistant" && messageHasCompressAttempt(m));
|
|
8029
|
+
const lastCompressMsgId = lastCompressMsg?.info?.id;
|
|
8030
|
+
if (lastCompressMsgId !== state.nudges.lastProcessedCompressMessageId) {
|
|
8031
|
+
state.nudges.lastProcessedCompressMessageId = lastCompressMsgId;
|
|
8032
|
+
const wasNudgeTriggered = state.nudges.lastNudgeShownTokens !== void 0;
|
|
8033
|
+
state.nudges.contextLimitAnchors.clear();
|
|
8034
|
+
state.nudges.turnNudgeAnchors.clear();
|
|
8035
|
+
state.nudges.iterationNudgeAnchors.clear();
|
|
8036
|
+
state.nudges.lastNudgeShownTokens = void 0;
|
|
8037
|
+
state.nudges.lastToolOutputNudgeTokens = void 0;
|
|
8038
|
+
state.nudges.lastTier2NudgeTokens = void 0;
|
|
8039
|
+
state.nudges.lastTier3NudgeTokens = void 0;
|
|
8040
|
+
const currentTurnHasSuccessfulCompress = messages.slice(currentTurnStart).some((m) => m.info.role === "assistant" && messageHasCompress(m));
|
|
8041
|
+
if (currentTurnHasSuccessfulCompress && wasNudgeTriggered && !state.nudges.compressBaselineSet) {
|
|
8042
|
+
const baseline = state.nudges.lastPerMessageNudgeTokens;
|
|
8043
|
+
const postCompress = currentTokens;
|
|
8044
|
+
const preCompress = preCompressTokens;
|
|
8045
|
+
if (baseline !== void 0 && postCompress !== void 0 && preCompress !== void 0 && preCompress > postCompress) {
|
|
8046
|
+
const growth = preCompress - baseline;
|
|
8047
|
+
const compressed = preCompress - postCompress;
|
|
8048
|
+
if (growth > 0 && compressed > 0) {
|
|
8049
|
+
const ratio = Math.min(1, compressed / growth);
|
|
8050
|
+
const adjustment = Math.min(1, ratio * 2);
|
|
8051
|
+
state.nudges.lastPerMessageNudgeTokens = baseline + Math.round((postCompress - baseline) * adjustment);
|
|
8052
|
+
} else {
|
|
8053
|
+
state.nudges.lastPerMessageNudgeTokens = postCompress;
|
|
8054
|
+
}
|
|
8532
8055
|
} else {
|
|
8533
8056
|
state.nudges.lastPerMessageNudgeTokens = postCompress;
|
|
8534
8057
|
}
|
|
8535
|
-
|
|
8536
|
-
state.nudges.lastPerMessageNudgeTokens = postCompress;
|
|
8058
|
+
state.nudges.compressBaselineSet = true;
|
|
8537
8059
|
}
|
|
8538
|
-
state.nudges.
|
|
8060
|
+
state.nudges.shouldInjectThisTurn = false;
|
|
8061
|
+
saveSessionState(state, logger).catch(() => {
|
|
8062
|
+
});
|
|
8063
|
+
return;
|
|
8539
8064
|
}
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
return;
|
|
8065
|
+
} else {
|
|
8066
|
+
state.nudges.lastProcessedCompressMessageId = void 0;
|
|
8543
8067
|
}
|
|
8544
8068
|
state.nudges.compressBaselineSet = false;
|
|
8545
8069
|
let anchorsChanged = false;
|
|
@@ -8822,7 +8346,7 @@ ${HOW_TO_COMPRESS_RULES}`;
|
|
|
8822
8346
|
const visibleMessageIds = new Set(
|
|
8823
8347
|
messages.map((message) => message.info.id)
|
|
8824
8348
|
);
|
|
8825
|
-
const blockGuidance = buildCompressedBlockGuidance(state,
|
|
8349
|
+
const blockGuidance = buildCompressedBlockGuidance(state, {
|
|
8826
8350
|
currentTokens,
|
|
8827
8351
|
modelContextLimit,
|
|
8828
8352
|
includeHint: tipsText !== null,
|
|
@@ -9642,7 +9166,7 @@ function renderOverview(visibleMessages, summaryTokens, blocks, fetchFailed, raw
|
|
|
9642
9166
|
lines.push(
|
|
9643
9167
|
` ${formatTokens(total)} total | ${formatTokens(totalTool)} tool (${toolPct}%) | ${formatTokens(totalText)} text (${textPct}%) | ${formatTokens(summaryTokens)} summaries (${summaryPct}%)`
|
|
9644
9168
|
);
|
|
9645
|
-
const topTypes = Array.from(toolTypeMap.entries()).map(([
|
|
9169
|
+
const topTypes = Array.from(toolTypeMap.entries()).map(([tool7, tokens]) => ({ tool: tool7, tokens })).sort((a, b) => b.tokens - a.tokens).slice(0, 3);
|
|
9646
9170
|
if (topTypes.length > 0) {
|
|
9647
9171
|
lines.push(
|
|
9648
9172
|
` Top tools: ${topTypes.map((t) => `${t.tool} (${pct(t.tokens, total)}%)`).join(", ")}`
|
|
@@ -9967,69 +9491,6 @@ Call with blockId to get the full summary: acp_context_recap({ blockId: N })`);
|
|
|
9967
9491
|
});
|
|
9968
9492
|
}
|
|
9969
9493
|
|
|
9970
|
-
// lib/compress/prune-tool.ts
|
|
9971
|
-
import { tool as tool7 } from "@opencode-ai/plugin";
|
|
9972
|
-
var PRUNE_TOOL_DESCRIPTION = `Remove old tool outputs by tool type \u2014 frees context without compression.
|
|
9973
|
-
|
|
9974
|
-
Unlike compress (which creates summaries), prune directly strips tool call outputs from context. Use for disposable tool outputs where the content is no longer needed: old todowrite states, edit success echoes, repeated status checks.
|
|
9975
|
-
|
|
9976
|
-
Args:
|
|
9977
|
-
- toolType: tool name to prune (e.g., "todowrite", "bash", "edit")
|
|
9978
|
-
- keepLatest: how many recent calls to keep visible (default 3)`;
|
|
9979
|
-
function createPruneTool(factoryCtx) {
|
|
9980
|
-
factoryCtx.prompts.reload();
|
|
9981
|
-
return tool7({
|
|
9982
|
-
description: PRUNE_TOOL_DESCRIPTION,
|
|
9983
|
-
args: {
|
|
9984
|
-
toolType: tool7.schema.string().describe('Tool name to prune (e.g., "todowrite", "bash", "edit")'),
|
|
9985
|
-
keepLatest: tool7.schema.number().optional().describe("How many recent calls to keep visible (default 3)")
|
|
9986
|
-
},
|
|
9987
|
-
async execute(args, toolCtx) {
|
|
9988
|
-
const ctx = resolveToolContext(factoryCtx, toolCtx.sessionID);
|
|
9989
|
-
const keepLatest = args.keepLatest ?? 3;
|
|
9990
|
-
const { rawMessages } = await prepareSession(
|
|
9991
|
-
ctx,
|
|
9992
|
-
toolCtx,
|
|
9993
|
-
`Prune: ${args.toolType}`
|
|
9994
|
-
);
|
|
9995
|
-
const matchingCalls = [];
|
|
9996
|
-
for (let i = 0; i < rawMessages.length; i++) {
|
|
9997
|
-
const msg = rawMessages[i];
|
|
9998
|
-
if (!msg) continue;
|
|
9999
|
-
for (const part of msg.parts || []) {
|
|
10000
|
-
if (part.type !== "tool") continue;
|
|
10001
|
-
const partTool = part?.tool || "";
|
|
10002
|
-
if (partTool !== args.toolType) continue;
|
|
10003
|
-
const callId = part?.callID;
|
|
10004
|
-
if (!callId || typeof callId !== "string") continue;
|
|
10005
|
-
if (ctx.state.prune.tools.has(callId)) continue;
|
|
10006
|
-
const tokens = Math.round(JSON.stringify(part).length / 4);
|
|
10007
|
-
matchingCalls.push({ callId, index: i, tokens });
|
|
10008
|
-
}
|
|
10009
|
-
}
|
|
10010
|
-
if (matchingCalls.length <= keepLatest) {
|
|
10011
|
-
return `Nothing to prune \u2014 only ${matchingCalls.length} ${args.toolType} calls visible (keepLatest=${keepLatest}).`;
|
|
10012
|
-
}
|
|
10013
|
-
matchingCalls.sort((a, b) => a.index - b.index);
|
|
10014
|
-
const toPrune = matchingCalls.slice(0, matchingCalls.length - keepLatest);
|
|
10015
|
-
let totalTokens = 0;
|
|
10016
|
-
for (const item of toPrune) {
|
|
10017
|
-
ctx.state.prune.tools.set(item.callId, item.tokens);
|
|
10018
|
-
totalTokens += item.tokens;
|
|
10019
|
-
}
|
|
10020
|
-
await finalizeSession(
|
|
10021
|
-
ctx,
|
|
10022
|
-
toolCtx,
|
|
10023
|
-
rawMessages,
|
|
10024
|
-
[],
|
|
10025
|
-
`Prune ${args.toolType}`
|
|
10026
|
-
);
|
|
10027
|
-
return `Pruned ${toPrune.length} ${args.toolType} calls (~${totalTokens} tokens). Kept latest ${keepLatest}. Outputs will be stripped on next context refresh.
|
|
10028
|
-
IMPORTANT: This was an automatic context pruning. You MUST continue your previous task exactly where you left off. Do NOT ask the user what to do next.`;
|
|
10029
|
-
}
|
|
10030
|
-
});
|
|
10031
|
-
}
|
|
10032
|
-
|
|
10033
9494
|
// lib/compress/hide-consumed.ts
|
|
10034
9495
|
function hideConsumedCompressCalls(state, messages) {
|
|
10035
9496
|
if (state.prune.messages.blocksById.size === 0) {
|
|
@@ -10082,7 +9543,7 @@ import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
|
10082
9543
|
import { join as join3 } from "path";
|
|
10083
9544
|
import { existsSync as existsSync3 } from "fs";
|
|
10084
9545
|
import { homedir as homedir3 } from "os";
|
|
10085
|
-
var LOG_VERSION = true ? "1.14.
|
|
9546
|
+
var LOG_VERSION = true ? "1.14.5" : "dev";
|
|
10086
9547
|
var Logger = class {
|
|
10087
9548
|
logDir;
|
|
10088
9549
|
enabled;
|
|
@@ -10312,7 +9773,6 @@ You have five context-management tools:
|
|
|
10312
9773
|
- \`compress\` \u2014 Replace a contiguous range of older conversation with a single detailed summary you write. Use when content is genuinely consumed (no longer needed for the current task step). Single range: \`compress({ topic: "API exploration", content: [{ startId: "m00150", endId: "m00220", summary: "..." }] })\`. Batch (multiple unrelated ranges, each with its own topic): \`compress({ content: [{ topic: "Auth", startId: "m00150", endId: "m00220", summary: "..." }, { topic: "Deploy", startId: "m00300", endId: "m00350", summary: "..." }] })\`.
|
|
10313
9774
|
- \`decompress\` \u2014 Restore a previously compressed block's content. By default restores one tier up (T2\u2192T1 summaries, not raw messages). Use \`full: true\` to restore all the way to original messages. Use \`toFile\` to write to file instead of inflating context. Example: \`decompress({ blockId: "b5" })\` or \`decompress({ blockId: "b5", toFile: "path" })\` or \`decompress({ blockId: "b5", full: true })\`.
|
|
10314
9775
|
- \`search_context\` \u2014 Search compressed block summaries (and optionally visible messages) by keyword. Use BEFORE decompressing to find the right block. Example: \`search_context({ query: "auth token refresh" })\`.
|
|
10315
|
-
- \`prune\` \u2014 Remove old tool outputs by tool type, keeping only recent calls. Unlike compress (which creates summaries), prune directly strips outputs. Use for disposable outputs like old todowrite states or edit echoes. Example: \`prune({ toolType: "todowrite", keepLatest: 3 })\`.
|
|
10316
9776
|
- \`acp_status\` \u2014 Context status with compressible ranges. No args = overview + ranges. \`scope:"uncompressed"\` for range view; add \`view:"messages"\` for per-message listing with \`tool\`/\`sort\` filters. \`scope:"compressed"\` for block details.
|
|
10317
9777
|
|
|
10318
9778
|
COMPRESSION PHILOSOPHY
|
|
@@ -10967,6 +10427,73 @@ function renderSystemPrompt(prompts, protectedToolsExtension, manual, subagent)
|
|
|
10967
10427
|
return [prompts.system.trim(), ...extensions].filter(Boolean).join("\n\n").replace(/\n([ \t]*\n)+/g, "\n\n").trim();
|
|
10968
10428
|
}
|
|
10969
10429
|
|
|
10430
|
+
// lib/messages/truncate-tools.ts
|
|
10431
|
+
var TRUNCATION_MARKER = "[truncated for context space";
|
|
10432
|
+
var MIN_OUTPUT_TOKENS = 1e3;
|
|
10433
|
+
var KEEP_PREFIX_CHARS = 2e3;
|
|
10434
|
+
var KEEP_SUFFIX_CHARS = 2e3;
|
|
10435
|
+
var PROTECT_RECENT_MESSAGES = 3;
|
|
10436
|
+
function parseGcThreshold(threshold, modelContextLimit) {
|
|
10437
|
+
if (typeof threshold === "number") return threshold;
|
|
10438
|
+
const str = threshold ?? "100%";
|
|
10439
|
+
const match = /^(\d+(?:\.\d+)?)%$/.exec(str);
|
|
10440
|
+
if (match) return Math.round(Number(match[1]) / 100 * modelContextLimit);
|
|
10441
|
+
return modelContextLimit;
|
|
10442
|
+
}
|
|
10443
|
+
function truncateLargeToolOutputs(state, config, logger, messages) {
|
|
10444
|
+
if (!state.modelContextLimit) return;
|
|
10445
|
+
const currentTokens = getCurrentTokenUsage(state, messages);
|
|
10446
|
+
if (currentTokens === 0) return;
|
|
10447
|
+
const threshold = parseGcThreshold(config.gc?.majorGcThresholdPercent, state.modelContextLimit);
|
|
10448
|
+
if (currentTokens < threshold) return;
|
|
10449
|
+
const protectedIndex = messages.length - PROTECT_RECENT_MESSAGES;
|
|
10450
|
+
const candidates = [];
|
|
10451
|
+
for (let mi = 0; mi < messages.length; mi++) {
|
|
10452
|
+
if (mi >= protectedIndex) break;
|
|
10453
|
+
const msg = messages[mi];
|
|
10454
|
+
const parts = Array.isArray(msg.parts) ? msg.parts : [];
|
|
10455
|
+
for (let pi = 0; pi < parts.length; pi++) {
|
|
10456
|
+
const part = parts[pi];
|
|
10457
|
+
if (part?.type !== "tool") continue;
|
|
10458
|
+
if (part.state?.status !== "completed") continue;
|
|
10459
|
+
const content = extractCompletedToolOutput(part);
|
|
10460
|
+
if (content === void 0) continue;
|
|
10461
|
+
if (content === "[Old tool result content cleared]") continue;
|
|
10462
|
+
if (content.includes(TRUNCATION_MARKER)) continue;
|
|
10463
|
+
const tokens = countTokens2(content);
|
|
10464
|
+
if (tokens < MIN_OUTPUT_TOKENS) continue;
|
|
10465
|
+
candidates.push({ part, content, tokens });
|
|
10466
|
+
}
|
|
10467
|
+
}
|
|
10468
|
+
if (candidates.length === 0) return;
|
|
10469
|
+
candidates.sort((a, b) => b.tokens - a.tokens);
|
|
10470
|
+
const targetTokens = threshold * 0.9;
|
|
10471
|
+
let savedTokens = 0;
|
|
10472
|
+
let truncatedCount = 0;
|
|
10473
|
+
for (const { part, content, tokens } of candidates) {
|
|
10474
|
+
if (currentTokens - savedTokens <= targetTokens) break;
|
|
10475
|
+
if (content.length <= KEEP_PREFIX_CHARS + KEEP_SUFFIX_CHARS) continue;
|
|
10476
|
+
const prefix = content.slice(0, KEEP_PREFIX_CHARS);
|
|
10477
|
+
const suffix = content.slice(-KEEP_SUFFIX_CHARS);
|
|
10478
|
+
const truncated = prefix + `
|
|
10479
|
+
|
|
10480
|
+
...${TRUNCATION_MARKER} \u2014 original ~${tokens} tokens]...
|
|
10481
|
+
|
|
10482
|
+
` + suffix;
|
|
10483
|
+
part.state.output = truncated;
|
|
10484
|
+
savedTokens += tokens - countTokens2(truncated);
|
|
10485
|
+
truncatedCount++;
|
|
10486
|
+
}
|
|
10487
|
+
if (truncatedCount > 0) {
|
|
10488
|
+
logger.info("Emergency tool output truncation", {
|
|
10489
|
+
truncatedCount,
|
|
10490
|
+
estimatedSavedTokens: Math.round(savedTokens),
|
|
10491
|
+
currentTokens,
|
|
10492
|
+
threshold
|
|
10493
|
+
});
|
|
10494
|
+
}
|
|
10495
|
+
}
|
|
10496
|
+
|
|
10970
10497
|
// lib/commands/context.ts
|
|
10971
10498
|
function analyzeTokens(state, messages) {
|
|
10972
10499
|
const breakdown = {
|
|
@@ -11015,7 +10542,7 @@ function analyzeTokens(state, messages) {
|
|
|
11015
10542
|
let foundFirstUser = false;
|
|
11016
10543
|
const allToolIds = /* @__PURE__ */ new Set();
|
|
11017
10544
|
const activeToolIds = /* @__PURE__ */ new Set();
|
|
11018
|
-
const
|
|
10545
|
+
const prunedToolIds = /* @__PURE__ */ new Set();
|
|
11019
10546
|
const allMessageIds = /* @__PURE__ */ new Set();
|
|
11020
10547
|
for (const msg of messages) {
|
|
11021
10548
|
allMessageIds.add(msg.info.id);
|
|
@@ -11033,11 +10560,10 @@ function analyzeTokens(state, messages) {
|
|
|
11033
10560
|
activeToolIds.add(toolPart.callID);
|
|
11034
10561
|
}
|
|
11035
10562
|
if (isMessagePruned) {
|
|
11036
|
-
|
|
10563
|
+
prunedToolIds.add(toolPart.callID);
|
|
11037
10564
|
}
|
|
11038
10565
|
}
|
|
11039
|
-
|
|
11040
|
-
if (!isCompacted && !isPruned) {
|
|
10566
|
+
if (!isCompacted) {
|
|
11041
10567
|
if (toolPart.state?.input) {
|
|
11042
10568
|
const inputStr = typeof toolPart.state.input === "string" ? toolPart.state.input : JSON.stringify(toolPart.state.input);
|
|
11043
10569
|
toolInputParts.push(inputStr);
|
|
@@ -11060,14 +10586,7 @@ function analyzeTokens(state, messages) {
|
|
|
11060
10586
|
foundFirstUser = true;
|
|
11061
10587
|
}
|
|
11062
10588
|
}
|
|
11063
|
-
const
|
|
11064
|
-
for (const id of allToolIds) {
|
|
11065
|
-
if (state.prune.tools.has(id)) {
|
|
11066
|
-
prunedByToolIds.add(id);
|
|
11067
|
-
}
|
|
11068
|
-
}
|
|
11069
|
-
const prunedToolIds = /* @__PURE__ */ new Set([...prunedByToolIds, ...prunedByMessageToolIds]);
|
|
11070
|
-
const toolsInContextCount = [...activeToolIds].filter((id) => !prunedByToolIds.has(id)).length;
|
|
10589
|
+
const toolsInContextCount = [...activeToolIds].filter((id) => !prunedToolIds.has(id)).length;
|
|
11071
10590
|
let prunedMessageCount = 0;
|
|
11072
10591
|
for (const [id, entry] of state.prune.messages.byMessageId) {
|
|
11073
10592
|
if (allMessageIds.has(id) && entry.activeBlockIds.length > 0) {
|
|
@@ -11291,7 +10810,6 @@ async function handleDecompressCommand(ctx) {
|
|
|
11291
10810
|
var BASE_COMMANDS = [
|
|
11292
10811
|
["/acp context", "Show token usage breakdown for current session"],
|
|
11293
10812
|
["/acp stats", "Show ACP pruning statistics"],
|
|
11294
|
-
["/acp sweep [n]", "Prune tools since last user message, or last n tools"],
|
|
11295
10813
|
["/acp manual [on|off]", "Toggle manual mode or set explicit state"]
|
|
11296
10814
|
];
|
|
11297
10815
|
var TOOL_COMMANDS = {
|
|
@@ -11343,9 +10861,9 @@ var COMPRESS_TRIGGER_PROMPT = [
|
|
|
11343
10861
|
"Follow the active compress mode, preserve all critical implementation details, and choose safe targets.",
|
|
11344
10862
|
"Return after compress with a brief explanation of what content was compressed."
|
|
11345
10863
|
].join("\n\n");
|
|
11346
|
-
function getTriggerPrompt(
|
|
10864
|
+
function getTriggerPrompt(tool7, state, config, userFocus) {
|
|
11347
10865
|
const base = COMPRESS_TRIGGER_PROMPT;
|
|
11348
|
-
const compressedBlockGuidance = config.compress.mode === "message" ? "" : buildCompressedBlockGuidance(state
|
|
10866
|
+
const compressedBlockGuidance = config.compress.mode === "message" ? "" : buildCompressedBlockGuidance(state);
|
|
11349
10867
|
const sections = [base, compressedBlockGuidance];
|
|
11350
10868
|
if (userFocus && userFocus.trim().length > 0) {
|
|
11351
10869
|
sections.push(`Additional user focus:
|
|
@@ -11372,8 +10890,8 @@ async function handleManualToggleCommand(ctx, modeArg) {
|
|
|
11372
10890
|
);
|
|
11373
10891
|
logger.info("Manual mode toggled", { manualMode: state.manualMode });
|
|
11374
10892
|
}
|
|
11375
|
-
async function handleManualTriggerCommand(ctx,
|
|
11376
|
-
return getTriggerPrompt(
|
|
10893
|
+
async function handleManualTriggerCommand(ctx, tool7, userFocus) {
|
|
10894
|
+
return getTriggerPrompt(tool7, ctx.state, ctx.config, userFocus);
|
|
11377
10895
|
}
|
|
11378
10896
|
function applyPendingManualTrigger(state, messages, logger) {
|
|
11379
10897
|
const pending = state.pendingManualTrigger;
|
|
@@ -11641,7 +11159,7 @@ async function handleStatsCommand(ctx) {
|
|
|
11641
11159
|
(total, target) => total + target.durationMs,
|
|
11642
11160
|
0
|
|
11643
11161
|
);
|
|
11644
|
-
const prunedToolIds = new Set(
|
|
11162
|
+
const prunedToolIds = /* @__PURE__ */ new Set();
|
|
11645
11163
|
for (const block of state.prune.messages.blocksById.values()) {
|
|
11646
11164
|
if (block.active) {
|
|
11647
11165
|
for (const toolId of block.effectiveToolIds) {
|
|
@@ -11679,243 +11197,6 @@ async function handleStatsCommand(ctx) {
|
|
|
11679
11197
|
});
|
|
11680
11198
|
}
|
|
11681
11199
|
|
|
11682
|
-
// lib/commands/sweep.ts
|
|
11683
|
-
function findLastUserMessageIndex(messages) {
|
|
11684
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
11685
|
-
const msg = messages[i];
|
|
11686
|
-
if (msg.info.role === "user" && !isIgnoredUserMessage(msg)) {
|
|
11687
|
-
return i;
|
|
11688
|
-
}
|
|
11689
|
-
}
|
|
11690
|
-
return -1;
|
|
11691
|
-
}
|
|
11692
|
-
function collectToolIdsAfterIndex(state, messages, afterIndex) {
|
|
11693
|
-
const toolIds = [];
|
|
11694
|
-
for (let i = afterIndex + 1; i < messages.length; i++) {
|
|
11695
|
-
const msg = messages[i];
|
|
11696
|
-
if (isMessageCompacted(state, msg)) {
|
|
11697
|
-
continue;
|
|
11698
|
-
}
|
|
11699
|
-
const parts = Array.isArray(msg.parts) ? msg.parts : [];
|
|
11700
|
-
if (parts.length > 0) {
|
|
11701
|
-
for (const part of parts) {
|
|
11702
|
-
if (part.type === "tool" && part.callID && part.tool) {
|
|
11703
|
-
toolIds.push(part.callID);
|
|
11704
|
-
}
|
|
11705
|
-
}
|
|
11706
|
-
}
|
|
11707
|
-
}
|
|
11708
|
-
return toolIds;
|
|
11709
|
-
}
|
|
11710
|
-
function formatNoUserMessage() {
|
|
11711
|
-
const lines = [];
|
|
11712
|
-
lines.push("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E");
|
|
11713
|
-
lines.push("\u2502 ACP Sweep \u2502");
|
|
11714
|
-
lines.push("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F");
|
|
11715
|
-
lines.push("");
|
|
11716
|
-
lines.push("Nothing swept: no user message found.");
|
|
11717
|
-
return lines.join("\n");
|
|
11718
|
-
}
|
|
11719
|
-
function formatSweepMessage(toolCount, tokensSaved, mode, toolIds, toolMetadata, workingDirectory, skippedProtected) {
|
|
11720
|
-
const lines = [];
|
|
11721
|
-
lines.push("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E");
|
|
11722
|
-
lines.push("\u2502 ACP Sweep \u2502");
|
|
11723
|
-
lines.push("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F");
|
|
11724
|
-
lines.push("");
|
|
11725
|
-
if (toolCount === 0) {
|
|
11726
|
-
if (mode === "since-user") {
|
|
11727
|
-
lines.push("No tools found since the previous user message.");
|
|
11728
|
-
} else {
|
|
11729
|
-
lines.push(`No tools found to sweep.`);
|
|
11730
|
-
}
|
|
11731
|
-
if (skippedProtected && skippedProtected > 0) {
|
|
11732
|
-
lines.push(`(${skippedProtected} protected tool(s) skipped)`);
|
|
11733
|
-
}
|
|
11734
|
-
} else {
|
|
11735
|
-
if (mode === "since-user") {
|
|
11736
|
-
lines.push(`Swept ${toolCount} tool(s) since the previous user message.`);
|
|
11737
|
-
} else {
|
|
11738
|
-
lines.push(`Swept the last ${toolCount} tool(s).`);
|
|
11739
|
-
}
|
|
11740
|
-
lines.push(`Tokens saved: ~${tokensSaved.toLocaleString()}`);
|
|
11741
|
-
if (skippedProtected && skippedProtected > 0) {
|
|
11742
|
-
lines.push(`(${skippedProtected} protected tool(s) skipped)`);
|
|
11743
|
-
}
|
|
11744
|
-
lines.push("");
|
|
11745
|
-
const itemLines = formatPrunedItemsList(toolIds, toolMetadata, workingDirectory);
|
|
11746
|
-
lines.push(...itemLines);
|
|
11747
|
-
}
|
|
11748
|
-
return lines.join("\n");
|
|
11749
|
-
}
|
|
11750
|
-
async function handleSweepCommand(ctx) {
|
|
11751
|
-
const { client, state, config, logger, sessionId, messages, args, workingDirectory } = ctx;
|
|
11752
|
-
const params = getCurrentParams(state, messages, logger);
|
|
11753
|
-
const protectedTools = config.commands.protectedTools;
|
|
11754
|
-
syncToolCache(state, config, logger, messages);
|
|
11755
|
-
buildToolIdList(state, messages);
|
|
11756
|
-
const numArg = args[0] ? parseInt(args[0], 10) : null;
|
|
11757
|
-
const isLastNMode = numArg !== null && !isNaN(numArg) && numArg > 0;
|
|
11758
|
-
let toolIdsToSweep;
|
|
11759
|
-
let mode;
|
|
11760
|
-
if (isLastNMode) {
|
|
11761
|
-
mode = "last-n";
|
|
11762
|
-
const startIndex = Math.max(0, state.toolIdList.length - numArg);
|
|
11763
|
-
toolIdsToSweep = state.toolIdList.slice(startIndex);
|
|
11764
|
-
logger.info(`Sweep command: last ${numArg} mode, found ${toolIdsToSweep.length} tools`);
|
|
11765
|
-
} else {
|
|
11766
|
-
mode = "since-user";
|
|
11767
|
-
const lastUserMsgIndex = findLastUserMessageIndex(messages);
|
|
11768
|
-
if (lastUserMsgIndex === -1) {
|
|
11769
|
-
const message2 = formatNoUserMessage();
|
|
11770
|
-
await sendIgnoredMessage(client, sessionId, message2, params, logger);
|
|
11771
|
-
logger.info("Sweep command: no user message found");
|
|
11772
|
-
return;
|
|
11773
|
-
} else {
|
|
11774
|
-
toolIdsToSweep = collectToolIdsAfterIndex(state, messages, lastUserMsgIndex);
|
|
11775
|
-
logger.info(
|
|
11776
|
-
`Sweep command: found last user at index ${lastUserMsgIndex}, sweeping ${toolIdsToSweep.length} tools`
|
|
11777
|
-
);
|
|
11778
|
-
}
|
|
11779
|
-
}
|
|
11780
|
-
const newToolIds = toolIdsToSweep.filter((id) => {
|
|
11781
|
-
if (state.prune.tools.has(id)) {
|
|
11782
|
-
return false;
|
|
11783
|
-
}
|
|
11784
|
-
const entry = state.toolParameters.get(id);
|
|
11785
|
-
if (!entry) {
|
|
11786
|
-
return true;
|
|
11787
|
-
}
|
|
11788
|
-
if (isToolNameProtected(entry.tool, protectedTools)) {
|
|
11789
|
-
logger.debug(`Sweep: skipping protected tool ${entry.tool} (${id})`);
|
|
11790
|
-
return false;
|
|
11791
|
-
}
|
|
11792
|
-
const filePaths = getFilePathsFromParameters(entry.tool, entry.parameters);
|
|
11793
|
-
if (isFilePathProtected(filePaths, config.protectedFilePatterns)) {
|
|
11794
|
-
logger.debug(`Sweep: skipping protected file path(s) ${filePaths.join(", ")} (${id})`);
|
|
11795
|
-
return false;
|
|
11796
|
-
}
|
|
11797
|
-
return true;
|
|
11798
|
-
});
|
|
11799
|
-
const skippedProtected = toolIdsToSweep.filter((id) => {
|
|
11800
|
-
const entry = state.toolParameters.get(id);
|
|
11801
|
-
if (!entry) {
|
|
11802
|
-
return false;
|
|
11803
|
-
}
|
|
11804
|
-
if (isToolNameProtected(entry.tool, protectedTools)) {
|
|
11805
|
-
return true;
|
|
11806
|
-
}
|
|
11807
|
-
const filePaths = getFilePathsFromParameters(entry.tool, entry.parameters);
|
|
11808
|
-
if (isFilePathProtected(filePaths, config.protectedFilePatterns)) {
|
|
11809
|
-
return true;
|
|
11810
|
-
}
|
|
11811
|
-
return false;
|
|
11812
|
-
}).length;
|
|
11813
|
-
if (newToolIds.length === 0) {
|
|
11814
|
-
const message2 = formatSweepMessage(
|
|
11815
|
-
0,
|
|
11816
|
-
0,
|
|
11817
|
-
mode,
|
|
11818
|
-
[],
|
|
11819
|
-
/* @__PURE__ */ new Map(),
|
|
11820
|
-
workingDirectory,
|
|
11821
|
-
skippedProtected
|
|
11822
|
-
);
|
|
11823
|
-
await sendIgnoredMessage(client, sessionId, message2, params, logger);
|
|
11824
|
-
logger.info("Sweep command: no new tools to sweep", { skippedProtected });
|
|
11825
|
-
return;
|
|
11826
|
-
}
|
|
11827
|
-
const tokensSaved = getTotalToolTokens(state, newToolIds);
|
|
11828
|
-
for (const id of newToolIds) {
|
|
11829
|
-
const entry = state.toolParameters.get(id);
|
|
11830
|
-
state.prune.tools.set(id, entry?.tokenCount ?? 0);
|
|
11831
|
-
}
|
|
11832
|
-
state.stats.pruneTokenCounter += tokensSaved;
|
|
11833
|
-
state.stats.totalPruneTokens += state.stats.pruneTokenCounter;
|
|
11834
|
-
state.stats.pruneTokenCounter = 0;
|
|
11835
|
-
const toolMetadata = /* @__PURE__ */ new Map();
|
|
11836
|
-
for (const id of newToolIds) {
|
|
11837
|
-
const entry = state.toolParameters.get(id);
|
|
11838
|
-
if (entry) {
|
|
11839
|
-
toolMetadata.set(id, entry);
|
|
11840
|
-
}
|
|
11841
|
-
}
|
|
11842
|
-
saveSessionState(state, logger).catch(
|
|
11843
|
-
(err) => logger.error("Failed to persist state after sweep", { error: err.message })
|
|
11844
|
-
);
|
|
11845
|
-
const message = formatSweepMessage(
|
|
11846
|
-
newToolIds.length,
|
|
11847
|
-
tokensSaved,
|
|
11848
|
-
mode,
|
|
11849
|
-
newToolIds,
|
|
11850
|
-
toolMetadata,
|
|
11851
|
-
workingDirectory,
|
|
11852
|
-
skippedProtected
|
|
11853
|
-
);
|
|
11854
|
-
await sendIgnoredMessage(client, sessionId, message, params, logger);
|
|
11855
|
-
logger.info("Sweep command completed", {
|
|
11856
|
-
toolsSwept: newToolIds.length,
|
|
11857
|
-
tokensSaved,
|
|
11858
|
-
skippedProtected,
|
|
11859
|
-
mode,
|
|
11860
|
-
tools: Array.from(toolMetadata.entries()).map(([id, entry]) => ({
|
|
11861
|
-
id,
|
|
11862
|
-
tool: entry.tool
|
|
11863
|
-
}))
|
|
11864
|
-
});
|
|
11865
|
-
}
|
|
11866
|
-
|
|
11867
|
-
// lib/gc/truncate.ts
|
|
11868
|
-
function runTruncateGC(blocks, params) {
|
|
11869
|
-
let compactedBlocks = 0;
|
|
11870
|
-
let savedTokens = 0;
|
|
11871
|
-
for (const block of blocks) {
|
|
11872
|
-
if (!block.active) continue;
|
|
11873
|
-
if (block.summary.length <= params.maxOldGenSummaryLength) continue;
|
|
11874
|
-
const originalLength = block.summary.length;
|
|
11875
|
-
const truncated = truncateSummary(block.summary, params.maxOldGenSummaryLength, block.blockId);
|
|
11876
|
-
const savedChars = originalLength - truncated.length;
|
|
11877
|
-
if (savedChars > 0) {
|
|
11878
|
-
block.summary = truncated;
|
|
11879
|
-
block.summaryTokens = Math.round(truncated.length / 4);
|
|
11880
|
-
compactedBlocks++;
|
|
11881
|
-
savedTokens += Math.round(savedChars / 4);
|
|
11882
|
-
}
|
|
11883
|
-
}
|
|
11884
|
-
return { compactedBlocks, savedTokens };
|
|
11885
|
-
}
|
|
11886
|
-
function truncateSummary(summary, maxLength, _blockId) {
|
|
11887
|
-
if (summary.length <= maxLength) return summary;
|
|
11888
|
-
const headerEnd = summary.indexOf("\n");
|
|
11889
|
-
if (headerEnd === -1) return summary.slice(0, maxLength) + "\n...\n[GC truncated]";
|
|
11890
|
-
const header = summary.slice(0, headerEnd + 1);
|
|
11891
|
-
const footerStart = summary.lastIndexOf("\n\n");
|
|
11892
|
-
const footer = footerStart > headerEnd ? summary.slice(footerStart) : "";
|
|
11893
|
-
const availableForContent = maxLength - header.length - footer.length - 20;
|
|
11894
|
-
if (availableForContent < 100) {
|
|
11895
|
-
return header + "...\n[GC truncated]" + footer;
|
|
11896
|
-
}
|
|
11897
|
-
const content = summary.slice(headerEnd + 1, headerEnd + 1 + availableForContent);
|
|
11898
|
-
return header + content + "\n...\n[GC truncated]" + footer;
|
|
11899
|
-
}
|
|
11900
|
-
function shouldRunMajorGC(currentTokens, modelContextLimit, gcConfig) {
|
|
11901
|
-
if (!modelContextLimit || modelContextLimit === 0) return false;
|
|
11902
|
-
const threshold = parseGcThreshold(gcConfig.majorGcThresholdPercent, modelContextLimit);
|
|
11903
|
-
return currentTokens >= threshold;
|
|
11904
|
-
}
|
|
11905
|
-
function getGCParams(gcConfig, modelContextLimit, currentTokens) {
|
|
11906
|
-
return {
|
|
11907
|
-
maxOldGenSummaryLength: gcConfig.maxOldGenSummaryLength,
|
|
11908
|
-
modelContextLimit,
|
|
11909
|
-
currentTokens
|
|
11910
|
-
};
|
|
11911
|
-
}
|
|
11912
|
-
function parseGcThreshold(limit, modelContextLimit) {
|
|
11913
|
-
if (typeof limit === "number") return limit;
|
|
11914
|
-
const percent = parseFloat(limit.slice(0, -1));
|
|
11915
|
-
if (isNaN(percent)) return modelContextLimit;
|
|
11916
|
-
return Math.round(Math.max(0, Math.min(100, Math.round(percent))) / 100 * modelContextLimit);
|
|
11917
|
-
}
|
|
11918
|
-
|
|
11919
11200
|
// lib/gc/merge.ts
|
|
11920
11201
|
function collectActiveOldGenBlocks(state, maxOldGenSummaryLength) {
|
|
11921
11202
|
const blocks = [];
|
|
@@ -12136,31 +11417,6 @@ function createSystemPromptHandler(registry3, logger, config, prompts) {
|
|
|
12136
11417
|
}
|
|
12137
11418
|
};
|
|
12138
11419
|
}
|
|
12139
|
-
function runMajorGC(state, config, logger, messages) {
|
|
12140
|
-
if (!state.modelContextLimit) return;
|
|
12141
|
-
const currentTokens = getCurrentTokenUsage(state, messages);
|
|
12142
|
-
if (!shouldRunMajorGC(currentTokens, state.modelContextLimit, config.gc)) return;
|
|
12143
|
-
const oldBlocks = [];
|
|
12144
|
-
for (const [blockId, block] of state.prune.messages.blocksById) {
|
|
12145
|
-
if (!block.active) continue;
|
|
12146
|
-
if (block.generation === "old" || block.generation === void 0 || block.summary.length > config.gc.maxOldGenSummaryLength) {
|
|
12147
|
-
oldBlocks.push(block);
|
|
12148
|
-
}
|
|
12149
|
-
}
|
|
12150
|
-
if (oldBlocks.length === 0) return;
|
|
12151
|
-
const params = getGCParams(config.gc, state.modelContextLimit, currentTokens);
|
|
12152
|
-
const result = runTruncateGC(oldBlocks, params);
|
|
12153
|
-
if (result.compactedBlocks > 0) {
|
|
12154
|
-
logger.info("Major GC: truncated old-gen blocks", {
|
|
12155
|
-
compactedBlocks: result.compactedBlocks,
|
|
12156
|
-
savedTokens: result.savedTokens,
|
|
12157
|
-
currentTokens,
|
|
12158
|
-
threshold: config.gc.majorGcThresholdPercent
|
|
12159
|
-
});
|
|
12160
|
-
saveSessionState(state, logger).catch(() => {
|
|
12161
|
-
});
|
|
12162
|
-
}
|
|
12163
|
-
}
|
|
12164
11420
|
function createChatMessageTransformHandler(client, registry3, logger, config, prompts, hostPermissions) {
|
|
12165
11421
|
return async (input, output) => {
|
|
12166
11422
|
const receivedMessages = Array.isArray(output.messages) ? output.messages.length : 0;
|
|
@@ -12204,7 +11460,6 @@ function createChatMessageTransformHandler(client, registry3, logger, config, pr
|
|
|
12204
11460
|
}
|
|
12205
11461
|
syncToolCache(state, config, logger, output.messages);
|
|
12206
11462
|
buildToolIdList(state, output.messages);
|
|
12207
|
-
runMajorGC(state, config, logger, output.messages);
|
|
12208
11463
|
const batchResult = runBatchCleanup(state, config, logger, output.messages);
|
|
12209
11464
|
if (batchResult.mergedCount > 0) {
|
|
12210
11465
|
saveSessionState(state, logger).catch(() => {
|
|
@@ -12212,6 +11467,7 @@ function createChatMessageTransformHandler(client, registry3, logger, config, pr
|
|
|
12212
11467
|
}
|
|
12213
11468
|
const prePruneTokens = getCurrentTokenUsage(state, output.messages);
|
|
12214
11469
|
prune(state, logger, config, output.messages);
|
|
11470
|
+
truncateLargeToolOutputs(state, config, logger, output.messages);
|
|
12215
11471
|
hideConsumedCompressCalls(state, output.messages);
|
|
12216
11472
|
assignMessageRefs(state, output.messages);
|
|
12217
11473
|
const compressionPriorities = buildPriorityMap(config, state, output.messages);
|
|
@@ -12288,14 +11544,6 @@ function createCommandExecuteHandler(client, registry3, logger, config, workingD
|
|
|
12288
11544
|
await handleStatsCommand(commandCtx);
|
|
12289
11545
|
throw new Error("__DCP_STATS_HANDLED__");
|
|
12290
11546
|
}
|
|
12291
|
-
if (subcommand === "sweep") {
|
|
12292
|
-
await handleSweepCommand({
|
|
12293
|
-
...commandCtx,
|
|
12294
|
-
args: subArgs,
|
|
12295
|
-
workingDirectory
|
|
12296
|
-
});
|
|
12297
|
-
throw new Error("__DCP_SWEEP_HANDLED__");
|
|
12298
|
-
}
|
|
12299
11547
|
if (subcommand === "manual") {
|
|
12300
11548
|
await handleManualToggleCommand(commandCtx, subArgs[0]?.toLowerCase());
|
|
12301
11549
|
throw new Error("__DCP_MANUAL_HANDLED__");
|
|
@@ -12601,9 +11849,7 @@ var server = (async (ctx) => {
|
|
|
12601
11849
|
if (isSecureMode()) {
|
|
12602
11850
|
configureClientAuth(ctx.client);
|
|
12603
11851
|
}
|
|
12604
|
-
logger.info("DCP initialized"
|
|
12605
|
-
strategies: config.strategies
|
|
12606
|
-
});
|
|
11852
|
+
logger.info("DCP initialized");
|
|
12607
11853
|
startAutoUpdate(ctx, config.autoUpdate);
|
|
12608
11854
|
const compressToolContext = {
|
|
12609
11855
|
client: ctx.client,
|
|
@@ -12641,7 +11887,6 @@ var server = (async (ctx) => {
|
|
|
12641
11887
|
...config.compress.permission !== "deny" && {
|
|
12642
11888
|
compress: config.compress.mode === "message" ? createCompressMessageTool(compressToolContext) : createCompressRangeTool(compressToolContext),
|
|
12643
11889
|
decompress: createDecompressTool(compressToolContext),
|
|
12644
|
-
prune: createPruneTool(compressToolContext),
|
|
12645
11890
|
search_context: createSearchContextTool(compressToolContext),
|
|
12646
11891
|
acp_status: createAcpStatusTool(compressToolContext),
|
|
12647
11892
|
acp_context_recap: createAcpContextRecapTool(compressToolContext)
|