opencode-acp 1.18.1-pr.439.185 → 1.18.2-pr.440.187
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/index.js +391 -42
- package/dist/index.js.map +1 -1
- package/dist/lib/compress/range.d.ts +4 -0
- package/dist/lib/compress/range.d.ts.map +1 -1
- package/dist/lib/compress/smart-plan.d.ts +28 -0
- package/dist/lib/compress/smart-plan.d.ts.map +1 -0
- package/dist/lib/compress/status.d.ts.map +1 -1
- package/dist/lib/config-validation.d.ts.map +1 -1
- package/dist/lib/config.d.ts +2 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/hooks.d.ts.map +1 -1
- package/dist/lib/message-ids.d.ts +7 -0
- package/dist/lib/message-ids.d.ts.map +1 -1
- package/dist/lib/messages/inject/inject.d.ts.map +1 -1
- package/dist/lib/messages/inject/utils.d.ts.map +1 -1
- package/dist/lib/prompts/context-limit-nudge.d.ts +1 -1
- package/dist/lib/prompts/context-limit-nudge.d.ts.map +1 -1
- package/dist/lib/prompts/system.d.ts.map +1 -1
- package/dist/lib/state/utils.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -903,6 +903,7 @@ var VALID_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
903
903
|
"compress.protectUserMessages",
|
|
904
904
|
"compress.maxSummaryLengthHard",
|
|
905
905
|
"compress.minCompressRange",
|
|
906
|
+
"compress.smartPlanRequired",
|
|
906
907
|
"compress.minNudgeGrowthRatio",
|
|
907
908
|
"compress.minNudgeGrowthFloor",
|
|
908
909
|
"compress.emergencyThresholdPercent",
|
|
@@ -1151,6 +1152,13 @@ function validateConfigTypes(config) {
|
|
|
1151
1152
|
actual: `${compress.minCompressRange}`
|
|
1152
1153
|
});
|
|
1153
1154
|
}
|
|
1155
|
+
if (compress.smartPlanRequired !== void 0 && typeof compress.smartPlanRequired !== "boolean") {
|
|
1156
|
+
errors.push({
|
|
1157
|
+
key: "compress.smartPlanRequired",
|
|
1158
|
+
expected: "boolean",
|
|
1159
|
+
actual: typeof compress.smartPlanRequired
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1154
1162
|
if (compress.minNudgeGrowthRatio !== void 0 && typeof compress.minNudgeGrowthRatio !== "number") {
|
|
1155
1163
|
errors.push({
|
|
1156
1164
|
key: "compress.minNudgeGrowthRatio",
|
|
@@ -1396,6 +1404,7 @@ function validateConfigTypes(config) {
|
|
|
1396
1404
|
protectedTools: "stringArray",
|
|
1397
1405
|
maxSummaryLengthHard: "positiveNumber",
|
|
1398
1406
|
minCompressRange: "nonNegativeNumber",
|
|
1407
|
+
smartPlanRequired: "boolean",
|
|
1399
1408
|
maxVisibleSegments: "positiveNumber",
|
|
1400
1409
|
keepEmbedMaxChars: "nonNegativeNumber",
|
|
1401
1410
|
preserveRecentMessages: "nonNegativeNumber",
|
|
@@ -1773,6 +1782,7 @@ var defaultConfig = {
|
|
|
1773
1782
|
protectUserMessages: false,
|
|
1774
1783
|
maxSummaryLengthHard: 2e4,
|
|
1775
1784
|
minCompressRange: 5e3,
|
|
1785
|
+
smartPlanRequired: false,
|
|
1776
1786
|
minNudgeGrowthRatio: 0.45,
|
|
1777
1787
|
minNudgeGrowthFloor: 5e3,
|
|
1778
1788
|
nudgeGrowthTokens: 5e4,
|
|
@@ -1947,6 +1957,7 @@ function mergeCompress(base, override) {
|
|
|
1947
1957
|
protectUserMessages: override.protectUserMessages ?? base.protectUserMessages,
|
|
1948
1958
|
maxSummaryLengthHard: override.maxSummaryLengthHard ?? base.maxSummaryLengthHard,
|
|
1949
1959
|
minCompressRange: override.minCompressRange ?? base.minCompressRange,
|
|
1960
|
+
smartPlanRequired: override.smartPlanRequired ?? base.smartPlanRequired,
|
|
1950
1961
|
minNudgeGrowthRatio: override.minNudgeGrowthRatio ?? base.minNudgeGrowthRatio,
|
|
1951
1962
|
minNudgeGrowthFloor: override.minNudgeGrowthFloor ?? base.minNudgeGrowthFloor,
|
|
1952
1963
|
emergencyThresholdPercent: override.emergencyThresholdPercent ?? base.emergencyThresholdPercent,
|
|
@@ -2756,11 +2767,6 @@ function resetOnCompaction(state) {
|
|
|
2756
2767
|
compressBaselineSet: false,
|
|
2757
2768
|
lastProcessedCompressMessageId: void 0
|
|
2758
2769
|
};
|
|
2759
|
-
state.messageIds = {
|
|
2760
|
-
byRawId: /* @__PURE__ */ new Map(),
|
|
2761
|
-
byRef: /* @__PURE__ */ new Map(),
|
|
2762
|
-
nextRef: 1
|
|
2763
|
-
};
|
|
2764
2770
|
}
|
|
2765
2771
|
function resolveEffectiveContextLimit(state, config) {
|
|
2766
2772
|
if (typeof state.modelContextLimit === "number" && state.modelContextLimit > 0) {
|
|
@@ -3124,6 +3130,52 @@ function assignMessageRefs(state, messages) {
|
|
|
3124
3130
|
}
|
|
3125
3131
|
return assigned;
|
|
3126
3132
|
}
|
|
3133
|
+
function repairNonMonotonicMessageRefs(state, messages) {
|
|
3134
|
+
const eligible = messages.filter((message) => {
|
|
3135
|
+
if (isIgnoredUserMessage(message)) return false;
|
|
3136
|
+
const id = message.info.id;
|
|
3137
|
+
return typeof id === "string" && id.length > 0 && !id.startsWith("msg_dcp_summary_") && !id.startsWith("msg_dcp_text_");
|
|
3138
|
+
});
|
|
3139
|
+
let previous = 0;
|
|
3140
|
+
let corrupted = false;
|
|
3141
|
+
for (const message of eligible) {
|
|
3142
|
+
const ref = state.messageIds.byRawId.get(message.info.id);
|
|
3143
|
+
const parsed = ref ? parseMessageRef(ref) : null;
|
|
3144
|
+
if (parsed === null) continue;
|
|
3145
|
+
if (parsed <= previous) {
|
|
3146
|
+
corrupted = true;
|
|
3147
|
+
break;
|
|
3148
|
+
}
|
|
3149
|
+
previous = parsed;
|
|
3150
|
+
}
|
|
3151
|
+
if (!corrupted) return false;
|
|
3152
|
+
const oldRawIds = [...state.messageIds.byRawId.keys()];
|
|
3153
|
+
state.messageIds.byRawId.clear();
|
|
3154
|
+
state.messageIds.byRef.clear();
|
|
3155
|
+
state.messageIds.nextRef = 1;
|
|
3156
|
+
for (const message of eligible) {
|
|
3157
|
+
const rawId = message.info.id;
|
|
3158
|
+
const ref = allocateNextMessageRef(state);
|
|
3159
|
+
state.messageIds.byRawId.set(rawId, ref);
|
|
3160
|
+
state.messageIds.byRef.set(ref, rawId);
|
|
3161
|
+
}
|
|
3162
|
+
for (const rawId of oldRawIds) {
|
|
3163
|
+
if (state.messageIds.byRawId.has(rawId)) continue;
|
|
3164
|
+
const ref = allocateNextMessageRef(state);
|
|
3165
|
+
state.messageIds.byRawId.set(rawId, ref);
|
|
3166
|
+
state.messageIds.byRef.set(ref, rawId);
|
|
3167
|
+
}
|
|
3168
|
+
for (const block of state.prune.messages.blocksById.values()) {
|
|
3169
|
+
const ids = [.../* @__PURE__ */ new Set([...block.effectiveMessageIds, ...block.directMessageIds])].filter((id) => state.messageIds.byRawId.has(id)).sort(
|
|
3170
|
+
(left, right) => (parseMessageRef(state.messageIds.byRawId.get(left)) ?? 0) - (parseMessageRef(state.messageIds.byRawId.get(right)) ?? 0)
|
|
3171
|
+
);
|
|
3172
|
+
if (ids.length === 0) continue;
|
|
3173
|
+
block.startId = state.messageIds.byRawId.get(ids[0]);
|
|
3174
|
+
block.endId = state.messageIds.byRawId.get(ids[ids.length - 1]);
|
|
3175
|
+
}
|
|
3176
|
+
state.prune.messages.structureVersion = (state.prune.messages.structureVersion ?? 0) + 1;
|
|
3177
|
+
return true;
|
|
3178
|
+
}
|
|
3127
3179
|
function allocateNextMessageRef(state) {
|
|
3128
3180
|
let candidate = Number.isInteger(state.messageIds.nextRef) ? Math.max(MESSAGE_REF_MIN_INDEX, state.messageIds.nextRef) : MESSAGE_REF_MIN_INDEX;
|
|
3129
3181
|
while (candidate <= MESSAGE_REF_MAX_INDEX) {
|
|
@@ -4661,21 +4713,21 @@ function rebuildRangeInvocation(state, input, searchContext, invocation, protect
|
|
|
4661
4713
|
const runId = allocateRunId(state);
|
|
4662
4714
|
let created = 0;
|
|
4663
4715
|
for (const plan of plans) {
|
|
4664
|
-
const
|
|
4716
|
+
const filteredSelection2 = filterProtectedToolMessages(
|
|
4665
4717
|
plan.selection,
|
|
4666
4718
|
searchContext,
|
|
4667
4719
|
protectedTools,
|
|
4668
4720
|
protectedFilePatterns
|
|
4669
4721
|
);
|
|
4670
|
-
if (
|
|
4722
|
+
if (filteredSelection2.messageIds.length === 0) {
|
|
4671
4723
|
continue;
|
|
4672
4724
|
}
|
|
4673
4725
|
const boundaryConsumed = extractBoundaryConsumedBlocks(
|
|
4674
|
-
|
|
4675
|
-
|
|
4726
|
+
filteredSelection2.startReference,
|
|
4727
|
+
filteredSelection2.endReference
|
|
4676
4728
|
);
|
|
4677
4729
|
const consumedBlockIds = dedupeBlockIds([
|
|
4678
|
-
...
|
|
4730
|
+
...filteredSelection2.requiredBlockIds,
|
|
4679
4731
|
...boundaryConsumed
|
|
4680
4732
|
]);
|
|
4681
4733
|
const blockId = allocateBlockId(state);
|
|
@@ -4694,7 +4746,7 @@ function rebuildRangeInvocation(state, input, searchContext, invocation, protect
|
|
|
4694
4746
|
compressCallId: invocation.callId,
|
|
4695
4747
|
summaryTokens
|
|
4696
4748
|
},
|
|
4697
|
-
|
|
4749
|
+
filteredSelection2,
|
|
4698
4750
|
plan.anchorMessageId,
|
|
4699
4751
|
blockId,
|
|
4700
4752
|
storedSummary,
|
|
@@ -7015,10 +7067,7 @@ function resolveContextTokenLimit(config, state, providerId, modelId, threshold)
|
|
|
7015
7067
|
return parseLimitValue(globalLimit);
|
|
7016
7068
|
}
|
|
7017
7069
|
function isContextOverLimits(config, state, providerId, modelId, messages) {
|
|
7018
|
-
const summaryTokenExtension = config.compress.summaryBuffer ? getActiveSummaryTokenUsage(
|
|
7019
|
-
state,
|
|
7020
|
-
new Set(messages.map((m) => m.info.id))
|
|
7021
|
-
) : 0;
|
|
7070
|
+
const summaryTokenExtension = config.compress.summaryBuffer ? getActiveSummaryTokenUsage(state, new Set(messages.map((m) => m.info.id))) : 0;
|
|
7022
7071
|
const resolvedMaxContextLimit = resolveContextTokenLimit(
|
|
7023
7072
|
config,
|
|
7024
7073
|
state,
|
|
@@ -7402,7 +7451,15 @@ function buildCompressibleRanges(messages, state, protectedTools = [], protected
|
|
|
7402
7451
|
lastUserRefIdx.length = 0;
|
|
7403
7452
|
lastUserRefIdx.push(msgInfo.length);
|
|
7404
7453
|
}
|
|
7405
|
-
msgInfo.push({
|
|
7454
|
+
msgInfo.push({
|
|
7455
|
+
ref,
|
|
7456
|
+
refNum: rn,
|
|
7457
|
+
tokens,
|
|
7458
|
+
effectiveTokens: 0,
|
|
7459
|
+
meaningful: hasMeaningfulPart,
|
|
7460
|
+
isTool,
|
|
7461
|
+
isUser: msg.info.role === "user"
|
|
7462
|
+
});
|
|
7406
7463
|
}
|
|
7407
7464
|
const lastUserIdx = lastUserRefIdx.length > 0 ? lastUserRefIdx[0] : -1;
|
|
7408
7465
|
for (let i = 0; i < msgInfo.length; i++) {
|
|
@@ -7421,7 +7478,7 @@ function buildCompressibleRanges(messages, state, protectedTools = [], protected
|
|
|
7421
7478
|
prevRefNum = info.refNum;
|
|
7422
7479
|
continue;
|
|
7423
7480
|
}
|
|
7424
|
-
const hasGap = info.refNum
|
|
7481
|
+
const hasGap = info.refNum !== prevRefNum + 1;
|
|
7425
7482
|
if (cur && (info.isUser && cur.count >= 3 || hasGap)) {
|
|
7426
7483
|
groups.push(cur);
|
|
7427
7484
|
cur = null;
|
|
@@ -7501,9 +7558,7 @@ function filterRecommendedRanges(compressible, _protectedRanges, options) {
|
|
|
7501
7558
|
const effective = r.effectiveTokens ?? r.tokens;
|
|
7502
7559
|
return effective > 0 && effective >= floor;
|
|
7503
7560
|
});
|
|
7504
|
-
const result = kept.map(
|
|
7505
|
-
(r, i) => i === kept.length - 1 ? { ...r, dangerous: true } : r
|
|
7506
|
-
);
|
|
7561
|
+
const result = kept.map((r, i) => i === kept.length - 1 ? { ...r, dangerous: true } : r);
|
|
7507
7562
|
log?.("filterRecommendedRanges: effective-token floor applied", {
|
|
7508
7563
|
inputRanges: compressible.length,
|
|
7509
7564
|
outputRanges: result.length,
|
|
@@ -7637,12 +7692,160 @@ function computeProtectedRefs(messages, state, compress) {
|
|
|
7637
7692
|
}
|
|
7638
7693
|
function excludeProtectedRanges(ranges, protectedRefs) {
|
|
7639
7694
|
if (protectedRefs.size === 0) return ranges;
|
|
7640
|
-
return ranges.filter(
|
|
7641
|
-
|
|
7695
|
+
return ranges.filter((r) => !protectedRefs.has(r.startRef) && !protectedRefs.has(r.endRef));
|
|
7696
|
+
}
|
|
7697
|
+
|
|
7698
|
+
// lib/compress/smart-plan.ts
|
|
7699
|
+
var SMART_PLAN_TTL_MS = 10 * 60 * 1e3;
|
|
7700
|
+
var armedPlans = /* @__PURE__ */ new Map();
|
|
7701
|
+
var visibleMessageIdsBySession = /* @__PURE__ */ new Map();
|
|
7702
|
+
function refNumber(ref) {
|
|
7703
|
+
const value = Number.parseInt(ref.slice(1), 10);
|
|
7704
|
+
return Number.isFinite(value) ? value : -1;
|
|
7705
|
+
}
|
|
7706
|
+
function mergeAdjacentSafeRanges(ranges) {
|
|
7707
|
+
const merged = [];
|
|
7708
|
+
for (const range of ranges.filter((candidate) => !candidate.dangerous)) {
|
|
7709
|
+
const previous = merged.at(-1);
|
|
7710
|
+
if (previous && refNumber(range.startRef) === refNumber(previous.endRef) + 1) {
|
|
7711
|
+
const previousEffective = previous.effectiveTokens ?? previous.tokens;
|
|
7712
|
+
previous.endRef = range.endRef;
|
|
7713
|
+
previous.count += range.count;
|
|
7714
|
+
previous.tokens += range.tokens;
|
|
7715
|
+
previous.effectiveTokens = previousEffective + (range.effectiveTokens ?? range.tokens);
|
|
7716
|
+
continue;
|
|
7717
|
+
}
|
|
7718
|
+
merged.push({ ...range });
|
|
7719
|
+
}
|
|
7720
|
+
return merged;
|
|
7721
|
+
}
|
|
7722
|
+
function recordVisibleMessages(sessionID, messages) {
|
|
7723
|
+
visibleMessageIdsBySession.set(sessionID, new Set(messages.map((message) => message.info.id)));
|
|
7724
|
+
}
|
|
7725
|
+
function getVisibleMessageIds(sessionID) {
|
|
7726
|
+
return visibleMessageIdsBySession.get(sessionID);
|
|
7727
|
+
}
|
|
7728
|
+
function clearSmartPlan(sessionID) {
|
|
7729
|
+
armedPlans.delete(sessionID);
|
|
7730
|
+
}
|
|
7731
|
+
function clearSmartPlanSession(sessionID) {
|
|
7732
|
+
armedPlans.delete(sessionID);
|
|
7733
|
+
visibleMessageIdsBySession.delete(sessionID);
|
|
7734
|
+
}
|
|
7735
|
+
function consumeSmartPlan(sessionID) {
|
|
7736
|
+
armedPlans.delete(sessionID);
|
|
7737
|
+
}
|
|
7738
|
+
function filteredSelection(startId, endId, searchContext, ctx) {
|
|
7739
|
+
const [resolved] = resolveRanges(
|
|
7740
|
+
{
|
|
7741
|
+
topic: "ACP smart plan",
|
|
7742
|
+
content: [{ startId, endId, summary: "Pending model-authored summary." }]
|
|
7743
|
+
},
|
|
7744
|
+
searchContext,
|
|
7745
|
+
ctx.state,
|
|
7746
|
+
ctx.logger
|
|
7747
|
+
);
|
|
7748
|
+
if (!resolved) return void 0;
|
|
7749
|
+
let selection = filterProtectedToolMessages(
|
|
7750
|
+
resolved.selection,
|
|
7751
|
+
searchContext,
|
|
7752
|
+
ctx.config.compress.protectedTools,
|
|
7753
|
+
ctx.config.protectedFilePatterns
|
|
7754
|
+
);
|
|
7755
|
+
selection = filterLastUserMessage(selection, searchContext, ctx.state, ctx.config.compress);
|
|
7756
|
+
selection = filterProtectedRecentMessages(
|
|
7757
|
+
selection,
|
|
7758
|
+
searchContext,
|
|
7759
|
+
ctx.state,
|
|
7760
|
+
ctx.config.compress
|
|
7761
|
+
);
|
|
7762
|
+
return selection;
|
|
7763
|
+
}
|
|
7764
|
+
function armBestSmartPlan(sessionID, ranges, searchContext, ctx, visibleMessageIds, now = Date.now(), targetChars = ctx.config.compress.minCompressRange) {
|
|
7765
|
+
const candidates = [];
|
|
7766
|
+
for (const range of mergeAdjacentSafeRanges(ranges)) {
|
|
7767
|
+
const selection = filteredSelection(range.startRef, range.endRef, searchContext, ctx);
|
|
7768
|
+
if (!selection || selection.messageIds.length === 0) continue;
|
|
7769
|
+
if (visibleMessageIds && !selection.messageIds.every((id) => visibleMessageIds.has(id)))
|
|
7770
|
+
continue;
|
|
7771
|
+
let exactChars = 0;
|
|
7772
|
+
for (const messageId of selection.messageIds) {
|
|
7773
|
+
const message = searchContext.rawMessagesById.get(messageId);
|
|
7774
|
+
if (message) exactChars += countMessageCharacters(message);
|
|
7775
|
+
}
|
|
7776
|
+
if (ctx.config.compress.minCompressRange > 0 && exactChars < ctx.config.compress.minCompressRange) {
|
|
7777
|
+
continue;
|
|
7778
|
+
}
|
|
7779
|
+
candidates.push({
|
|
7780
|
+
sessionID,
|
|
7781
|
+
createdAt: now,
|
|
7782
|
+
structureVersion: ctx.state.prune.messages.structureVersion ?? 0,
|
|
7783
|
+
startId: range.startRef,
|
|
7784
|
+
endId: range.endRef,
|
|
7785
|
+
exactChars,
|
|
7786
|
+
messageIds: [...selection.messageIds],
|
|
7787
|
+
rawStart: selection.startReference.rawIndex
|
|
7788
|
+
});
|
|
7789
|
+
}
|
|
7790
|
+
const sufficient = candidates.filter((candidate) => candidate.exactChars >= targetChars);
|
|
7791
|
+
const pool = sufficient.length > 0 ? sufficient : candidates;
|
|
7792
|
+
pool.sort(
|
|
7793
|
+
(a, b) => sufficient.length > 0 ? a.rawStart - b.rawStart || b.exactChars - a.exactChars : b.exactChars - a.exactChars || a.rawStart - b.rawStart
|
|
7642
7794
|
);
|
|
7795
|
+
const best = pool[0];
|
|
7796
|
+
if (!best) {
|
|
7797
|
+
clearSmartPlan(sessionID);
|
|
7798
|
+
return void 0;
|
|
7799
|
+
}
|
|
7800
|
+
const { rawStart: _rawStart, ...plan } = best;
|
|
7801
|
+
armedPlans.set(sessionID, plan);
|
|
7802
|
+
return plan;
|
|
7803
|
+
}
|
|
7804
|
+
function validateSmartPlan(sessionID, startId, endId, messageIds, exactChars, structureVersion, now = Date.now()) {
|
|
7805
|
+
const plan = armedPlans.get(sessionID);
|
|
7806
|
+
const preflight = 'Use the exact SMART PLAN range from the latest ACP nudge, or call acp_status({scope:"uncompressed"}) to refresh it.';
|
|
7807
|
+
if (!plan) throw new Error(`No smart compression plan is armed. ${preflight}`);
|
|
7808
|
+
if (now - plan.createdAt > SMART_PLAN_TTL_MS) {
|
|
7809
|
+
clearSmartPlan(sessionID);
|
|
7810
|
+
throw new Error(`Smart compression plan expired. ${preflight}`);
|
|
7811
|
+
}
|
|
7812
|
+
if (plan.structureVersion !== structureVersion) {
|
|
7813
|
+
clearSmartPlan(sessionID);
|
|
7814
|
+
throw new Error(
|
|
7815
|
+
`Smart compression plan is stale because compression state changed. ${preflight}`
|
|
7816
|
+
);
|
|
7817
|
+
}
|
|
7818
|
+
if (plan.startId !== startId || plan.endId !== endId) {
|
|
7819
|
+
throw new Error(
|
|
7820
|
+
`Range does not match the armed smart plan (${plan.startId}-${plan.endId}). Do not sort, merge, or batch ranges.`
|
|
7821
|
+
);
|
|
7822
|
+
}
|
|
7823
|
+
const idsMatch = plan.messageIds.length === messageIds.length && plan.messageIds.every((id, i) => id === messageIds[i]);
|
|
7824
|
+
const charsDiff = Math.abs(plan.exactChars - exactChars);
|
|
7825
|
+
const charsMatch = charsDiff === 0 || charsDiff <= 300 || charsDiff / Math.max(plan.exactChars, 1) < 0.02;
|
|
7826
|
+
if (!idsMatch || !charsMatch) {
|
|
7827
|
+
clearSmartPlan(sessionID);
|
|
7828
|
+
throw new Error(
|
|
7829
|
+
`Smart compression plan no longer resolves to the armed messages. ${preflight}`
|
|
7830
|
+
);
|
|
7831
|
+
}
|
|
7832
|
+
const visibleMessageIds = getVisibleMessageIds(sessionID);
|
|
7833
|
+
if (visibleMessageIds && !plan.messageIds.every((id) => visibleMessageIds.has(id))) {
|
|
7834
|
+
clearSmartPlan(sessionID);
|
|
7835
|
+
throw new Error(
|
|
7836
|
+
`Smart compression plan moved outside the model's visible context. ${preflight}`
|
|
7837
|
+
);
|
|
7838
|
+
}
|
|
7839
|
+
return plan;
|
|
7643
7840
|
}
|
|
7644
7841
|
|
|
7645
7842
|
// lib/compress/range.ts
|
|
7843
|
+
function requiresSmartPlan(smartPlanRequired, content) {
|
|
7844
|
+
const isBlockCompression = content.every(
|
|
7845
|
+
(entry) => entry.startId.startsWith("b") && entry.endId.startsWith("b")
|
|
7846
|
+
);
|
|
7847
|
+
return smartPlanRequired && !isBlockCompression;
|
|
7848
|
+
}
|
|
7646
7849
|
function buildSchema(maxSummaryLengthHard) {
|
|
7647
7850
|
return {
|
|
7648
7851
|
topic: tool2.schema.string().optional().describe(
|
|
@@ -7705,13 +7908,32 @@ function createCompressRangeTool(factoryCtx) {
|
|
|
7705
7908
|
...ctx0,
|
|
7706
7909
|
config: applyCompressOverrides(ctx0.config, providerId, modelId)
|
|
7707
7910
|
};
|
|
7708
|
-
const
|
|
7911
|
+
const needsSmartPlan = requiresSmartPlan(
|
|
7912
|
+
ctx.config.compress.smartPlanRequired === true,
|
|
7913
|
+
input.content
|
|
7914
|
+
);
|
|
7915
|
+
if (needsSmartPlan && input.content.length !== 1) {
|
|
7916
|
+
throw new Error(
|
|
7917
|
+
'Raw-message compression accepts exactly one canonical SMART PLAN range per call. Use the latest ACP nudge, or call acp_status({scope:"uncompressed"}) to refresh it.'
|
|
7918
|
+
);
|
|
7919
|
+
}
|
|
7920
|
+
const { plans: filteredPlans, totalChars } = prepareExecutableRangePlans(
|
|
7709
7921
|
input,
|
|
7710
7922
|
searchContext,
|
|
7711
7923
|
ctx.state,
|
|
7712
7924
|
ctx.config,
|
|
7713
7925
|
ctx.logger
|
|
7714
7926
|
);
|
|
7927
|
+
if (needsSmartPlan) {
|
|
7928
|
+
validateSmartPlan(
|
|
7929
|
+
toolCtx.sessionID,
|
|
7930
|
+
filteredPlans[0].entry.startId,
|
|
7931
|
+
filteredPlans[0].entry.endId,
|
|
7932
|
+
filteredPlans[0].selection.messageIds,
|
|
7933
|
+
totalChars,
|
|
7934
|
+
ctx.state.prune.messages.structureVersion ?? 0
|
|
7935
|
+
);
|
|
7936
|
+
}
|
|
7715
7937
|
const notifications = [];
|
|
7716
7938
|
let preparedPlans = [];
|
|
7717
7939
|
let totalCompressedMessages = 0;
|
|
@@ -7889,6 +8111,7 @@ function createCompressRangeTool(factoryCtx) {
|
|
|
7889
8111
|
});
|
|
7890
8112
|
}
|
|
7891
8113
|
await finalizeSession(ctx, toolCtx, rawMessages, notifications, input.topic);
|
|
8114
|
+
if (needsSmartPlan) consumeSmartPlan(toolCtx.sessionID);
|
|
7892
8115
|
} catch (error) {
|
|
7893
8116
|
restoreCompressionState(ctx.state, snapshot);
|
|
7894
8117
|
ctx.state.qualityGateRetryPending = qualityGateRetryPendingBefore;
|
|
@@ -8209,7 +8432,7 @@ COMPRESSION CANDIDATES:
|
|
|
8209
8432
|
- EPISODE identifies a contiguous historical segment made from smaller units.
|
|
8210
8433
|
- Candidate entries are independent and non-overlapping, so they can be batched in one \`content[]\` array.
|
|
8211
8434
|
- Candidates are suggestions, not mandatory targets. Choose only content no longer needed for the current task and do not invent a target when none is listed.
|
|
8212
|
-
-
|
|
8435
|
+
- Use \`acp_status\` for a fresh candidate view if the list is stale or missing.
|
|
8213
8436
|
- When the context limit is reached and candidates are listed, select at least one clearly stale candidate and call the \`compress\` tool in your next reply. Batch only additional candidates that are also clearly stale. Do not merely recommend compression.
|
|
8214
8437
|
</system-reminder>
|
|
8215
8438
|
`;
|
|
@@ -8985,9 +9208,40 @@ var injectCompressNudges = (state, config, logger, messages, prompts, compressio
|
|
|
8985
9208
|
const nothingToCompress = candidatesEnabled && candidateMessages !== void 0 ? noExecutableCandidates : allProtected || allInProtectedZone || allBelowMin;
|
|
8986
9209
|
const emergencyNoTargets = emergencyOverride && nothingToCompress;
|
|
8987
9210
|
const noticeCadenceMet = state.nudges.lastNudgeShownTokens === void 0 || growthSinceBaseline !== void 0 && growthSinceBaseline >= growthFloor;
|
|
8988
|
-
|
|
8989
|
-
|
|
9211
|
+
let shouldInjectNudge = nudgeAllowed && !nothingToCompress;
|
|
9212
|
+
let shouldInjectNotice = emergencyNoTargets && noticeCadenceMet;
|
|
8990
9213
|
let shouldInject = shouldInjectNudge || shouldInjectNotice;
|
|
9214
|
+
let armedSmartPlan;
|
|
9215
|
+
if (shouldInjectNudge && config.compress.smartPlanRequired === true && state.sessionId) {
|
|
9216
|
+
const planningRanges = candidatesEnabled ? candidatePlan.candidates.map((candidate) => ({
|
|
9217
|
+
startRef: candidate.startRef,
|
|
9218
|
+
endRef: candidate.endRef,
|
|
9219
|
+
count: candidate.messageCount,
|
|
9220
|
+
tokens: candidate.estimatedTokens,
|
|
9221
|
+
effectiveTokens: candidate.estimatedTokens,
|
|
9222
|
+
toolPct: candidate.toolPct,
|
|
9223
|
+
textPct: candidate.textPct
|
|
9224
|
+
})) : recommendedRanges;
|
|
9225
|
+
const maxLimit = resolveContextTokenLimit(config, state, providerId, modelId, "max");
|
|
9226
|
+
const reclaimTargetChars = Math.max(
|
|
9227
|
+
config.compress.minCompressRange,
|
|
9228
|
+
maxLimit === void 0 || currentTokens === void 0 ? 0 : Math.max(0, currentTokens - maxLimit + 8192) * 4
|
|
9229
|
+
);
|
|
9230
|
+
armedSmartPlan = armBestSmartPlan(
|
|
9231
|
+
state.sessionId,
|
|
9232
|
+
planningRanges,
|
|
9233
|
+
buildSearchContext(state, messages),
|
|
9234
|
+
{ state, config, logger },
|
|
9235
|
+
new Set(messages.map((message) => message.info.id)),
|
|
9236
|
+
Date.now(),
|
|
9237
|
+
reclaimTargetChars
|
|
9238
|
+
);
|
|
9239
|
+
if (!armedSmartPlan) {
|
|
9240
|
+
shouldInjectNudge = false;
|
|
9241
|
+
shouldInjectNotice = emergencyOverride && noticeCadenceMet;
|
|
9242
|
+
shouldInject = shouldInjectNotice;
|
|
9243
|
+
}
|
|
9244
|
+
}
|
|
8991
9245
|
if (shouldInjectNudge) {
|
|
8992
9246
|
const effectivePrompts = candidatesEnabled ? {
|
|
8993
9247
|
...prompts,
|
|
@@ -9195,13 +9449,22 @@ Breakdown: ${sysPart}${fmt(composition.toolTokens)} tool (${pct2(composition.too
|
|
|
9195
9449
|
${HOW_TO_COMPRESS_RULES}
|
|
9196
9450
|
|
|
9197
9451
|
${candidateText}`;
|
|
9198
|
-
|
|
9452
|
+
if (armedSmartPlan) {
|
|
9453
|
+
breakdown += `
|
|
9454
|
+
|
|
9455
|
+
SMART PLAN ARMED: ${armedSmartPlan.startId}-${armedSmartPlan.endId} | ${armedSmartPlan.exactChars} effective chars`;
|
|
9456
|
+
breakdown += `
|
|
9457
|
+
Next: compress exactly this one range now. acp_status is optional; use it only to inspect or refresh a stale plan.`;
|
|
9458
|
+
} else {
|
|
9459
|
+
breakdown += candidatesEnabled ? "\n\u{1F4A1} You may batch selected independent candidates in one call (pass multiple content entries: `content: [{...}, {...}]`); omit any candidate whose content is still needed." : "\n\u{1F4A1} Compress all ranges in one call (pass multiple content entries: `content: [{...}, {...}]`).";
|
|
9460
|
+
}
|
|
9199
9461
|
}
|
|
9200
|
-
breakdown += `
|
|
9462
|
+
breakdown += armedSmartPlan ? `
|
|
9463
|
+
Use \`acp_status({scope:"uncompressed"})\` only to inspect or refresh a stale plan, or \`acp_status\` for compressed block details.` : `
|
|
9201
9464
|
Use \`acp_status({scope:"uncompressed"})\` to re-fetch compressible ranges after compressing, or \`acp_status\` for compressed block details.`;
|
|
9202
9465
|
appendToLastTextPart(suffixMessage, breakdown);
|
|
9203
9466
|
}
|
|
9204
|
-
if (effectiveTipsVariant === "maxLimit" &&
|
|
9467
|
+
if (effectiveTipsVariant === "maxLimit" && shouldInjectNudge) {
|
|
9205
9468
|
tipsText = candidatesEnabled ? "\n\n\u26A0\uFE0F Context limit reached \u2014 compress now. Select at least one listed candidate whose content is no longer needed and call the `compress` tool in your next reply. Do not merely recommend compression. Candidates are advisory about selection: preserve current intent and active work, and never compress content still needed for the current task.\n\n" + HOW_TO_COMPRESS_RULES + '\n\n{ "topic": "...", "content": [{ "startId": "<ID>", "endId": "<ID>", "summary": "..." }] }\n\nOnly use IDs from visible messages above. If several selected candidates are stale, older work may be preferable; never override semantic judgment or compress content still needed for the current task.' : "\n\n\u26A0\uFE0F Context limit reached \u2014 compress now. Prioritize consumed tool outputs.\n\n" + HOW_TO_COMPRESS_RULES + '\n\n{ "topic": "...", "content": [{ "startId": "<ID>", "endId": "<ID>", "summary": "..." }] }\n\nOnly use IDs from visible messages above. Compress older work first.';
|
|
9206
9469
|
} else if (shouldInjectNotice) {
|
|
9207
9470
|
const emergencyPct = currentTokens !== void 0 && modelContextLimit !== void 0 && modelContextLimit > 0 ? Math.round(currentTokens / modelContextLimit * 100) : void 0;
|
|
@@ -10457,13 +10720,85 @@ function createAcpStatusTool(factoryCtx) {
|
|
|
10457
10720
|
rawMessages = [];
|
|
10458
10721
|
}
|
|
10459
10722
|
hideConsumedCompressCalls(ctx.state, rawMessages);
|
|
10460
|
-
|
|
10461
|
-
|
|
10462
|
-
|
|
10463
|
-
|
|
10464
|
-
|
|
10465
|
-
|
|
10466
|
-
|
|
10723
|
+
assignMessageRefs(ctx.state, rawMessages);
|
|
10724
|
+
if (repairNonMonotonicMessageRefs(ctx.state, rawMessages)) {
|
|
10725
|
+
ctx.logger.warn("Repaired non-monotonic message aliases after native compaction", {
|
|
10726
|
+
session: toolCtx.sessionID,
|
|
10727
|
+
messages: rawMessages.length
|
|
10728
|
+
});
|
|
10729
|
+
await saveSessionState(ctx.state, ctx.logger);
|
|
10730
|
+
}
|
|
10731
|
+
const { providerId, modelId } = getModelInfo(rawMessages);
|
|
10732
|
+
const effectiveCtx = {
|
|
10733
|
+
...ctx,
|
|
10734
|
+
config: applyCompressOverrides(ctx.config, providerId, modelId)
|
|
10735
|
+
};
|
|
10736
|
+
let smartPlanSuffix = "";
|
|
10737
|
+
if (effectiveCtx.config.compress?.smartPlanRequired === true && scope === "uncompressed" && view !== "messages") {
|
|
10738
|
+
const lastModelView = getVisibleMessageIds(toolCtx.sessionID);
|
|
10739
|
+
const visibleRaw = rawMessages.filter((message) => {
|
|
10740
|
+
const entry = effectiveCtx.state.prune.messages.byMessageId.get(message.info.id);
|
|
10741
|
+
return (!entry || entry.activeBlockIds.length === 0) && (!lastModelView || lastModelView.has(message.info.id));
|
|
10742
|
+
});
|
|
10743
|
+
const protectedRefs = computeProtectedRefs(
|
|
10744
|
+
visibleRaw,
|
|
10745
|
+
effectiveCtx.state,
|
|
10746
|
+
effectiveCtx.config.compress
|
|
10747
|
+
);
|
|
10748
|
+
const contextRanges = buildCompressibleRanges(
|
|
10749
|
+
visibleRaw,
|
|
10750
|
+
effectiveCtx.state,
|
|
10751
|
+
effectiveCtx.config.compress.protectedTools,
|
|
10752
|
+
effectiveCtx.config.protectedFilePatterns,
|
|
10753
|
+
protectedRefs
|
|
10754
|
+
);
|
|
10755
|
+
const ranges = filterRecommendedRanges(
|
|
10756
|
+
contextRanges.compressible,
|
|
10757
|
+
contextRanges.protected,
|
|
10758
|
+
{
|
|
10759
|
+
logger: effectiveCtx.logger,
|
|
10760
|
+
minEffectiveTokens: resolveEffectiveFloor(effectiveCtx.config)
|
|
10761
|
+
}
|
|
10762
|
+
);
|
|
10763
|
+
const composition = estimateContextComposition(
|
|
10764
|
+
visibleRaw,
|
|
10765
|
+
effectiveCtx.state,
|
|
10766
|
+
effectiveCtx.config.compress.protectedTools,
|
|
10767
|
+
effectiveCtx.config.protectedFilePatterns
|
|
10768
|
+
);
|
|
10769
|
+
const targetLimit = resolveContextTokenLimit(
|
|
10770
|
+
effectiveCtx.config,
|
|
10771
|
+
effectiveCtx.state,
|
|
10772
|
+
providerId,
|
|
10773
|
+
modelId,
|
|
10774
|
+
"max"
|
|
10775
|
+
);
|
|
10776
|
+
const targetChars = Math.max(
|
|
10777
|
+
effectiveCtx.config.compress.minCompressRange,
|
|
10778
|
+
targetLimit === void 0 ? 0 : Math.max(0, composition.total - targetLimit + 8192) * 4
|
|
10779
|
+
);
|
|
10780
|
+
const plan = lastModelView ? armBestSmartPlan(
|
|
10781
|
+
toolCtx.sessionID,
|
|
10782
|
+
ranges,
|
|
10783
|
+
buildSearchContext(effectiveCtx.state, rawMessages),
|
|
10784
|
+
effectiveCtx,
|
|
10785
|
+
lastModelView,
|
|
10786
|
+
Date.now(),
|
|
10787
|
+
targetChars
|
|
10788
|
+
) : void 0;
|
|
10789
|
+
smartPlanSuffix = plan ? `
|
|
10790
|
+
|
|
10791
|
+
SMART PLAN ARMED: ${plan.startId}-${plan.endId} | ${plan.exactChars} effective chars | reclaim target ${targetChars} chars
|
|
10792
|
+
Next: compress exactly this one range. acp_status is optional unless this plan becomes stale.` : `
|
|
10793
|
+
|
|
10794
|
+
SMART PLAN: none. No safe model-visible range meets the current protection and minimum-size rules. Do not call compress.`;
|
|
10795
|
+
if (!plan) clearSmartPlan(toolCtx.sessionID);
|
|
10796
|
+
}
|
|
10797
|
+
return buildStatusReport(
|
|
10798
|
+
{ state: effectiveCtx.state, config: effectiveCtx.config },
|
|
10799
|
+
rawMessages,
|
|
10800
|
+
{ scope, view, tool: toolFilter, sort, limit }
|
|
10801
|
+
) + smartPlanSuffix;
|
|
10467
10802
|
}
|
|
10468
10803
|
});
|
|
10469
10804
|
}
|
|
@@ -10571,7 +10906,7 @@ import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
|
10571
10906
|
import { join as join4 } from "path";
|
|
10572
10907
|
import { existsSync as existsSync4 } from "fs";
|
|
10573
10908
|
import { homedir as homedir3 } from "os";
|
|
10574
|
-
var LOG_VERSION = true ? "1.18.
|
|
10909
|
+
var LOG_VERSION = true ? "1.18.2-pr.440.187" : "dev";
|
|
10575
10910
|
var LEVEL_RANK = {
|
|
10576
10911
|
debug: 10,
|
|
10577
10912
|
info: 20,
|
|
@@ -10805,7 +11140,7 @@ ACP may append a bounded list headed \`COMPRESSION CANDIDATES\` below a nudge or
|
|
|
10805
11140
|
- \`MICRO\` is one large plain message or one complete tool transaction, including every message needed to keep its tool call/result structure valid.
|
|
10806
11141
|
- \`EPISODE\` is a contiguous historical segment made from smaller adjacent units.
|
|
10807
11142
|
- Candidate ranges are independent, non-overlapping, and can be submitted together as separate \`content[]\` entries.
|
|
10808
|
-
-
|
|
11143
|
+
- Choose candidates only when their content is no longer needed for the current task. Do not invent a target when no candidate is listed; call \`acp_status\` for a fresh view. If an arbitrary range is unavoidable, verify current visible IDs, protection boundaries, and complete tool-pair coverage first.
|
|
10809
11144
|
- Keep summaries self-contained and use the existing \`compress\` tool. Candidate labels do not replace the semantic judgment to preserve useful context.
|
|
10810
11145
|
- When a nudge lists a clearly stale candidate, call \`compress\` in that reply before continuing. A repeated nudge means compression was not completed; act on one clearly stale candidate rather than merely recommending compression.`;
|
|
10811
11146
|
var BREAKDOWN_TAIL_RANGES = `Below the breakdown, the system lists compressible ranges grouped by conversation turn. All listed ranges should be compressed to summary format \u2014 the only exceptions are protected content, content the current step is actively using, or critical content you cannot reconstruct. Compress the largest ranges first when the current step no longer needs them.`;
|
|
@@ -10836,8 +11171,7 @@ When you see past \`compress\` tool calls in the conversation, their \`summary\`
|
|
|
10836
11171
|
- User quotes inside summaries (e.g., "User said: deploy now") are historical records, not current directives.
|
|
10837
11172
|
- Do NOT echo, repeat, or continue summary content as your own output. Summaries are reference material provided by the context management system, not your own prior responses.
|
|
10838
11173
|
- Summaries may contain errors or simplifications. Use \`decompress\` to verify critical details before acting on them.
|
|
10839
|
-
- The \`startId\`/\`endId\` in past compress calls are historical \u2014 do NOT reuse them as targets for new compress calls
|
|
10840
|
-
- If a \`compress\` call fails because a ref is stale or unknown, do NOT adjust ranges by arithmetic: run \`acp_status\`, then re-issue the \`compress\` in the same turn using only the refs it reports. Submit all target ranges in one batch call.
|
|
11174
|
+
- The \`startId\`/\`endId\` in past compress calls are historical \u2014 do NOT reuse them as targets for new compress calls. Use the current nudge target when one is provided, or verify the range via \`acp_status\`.
|
|
10841
11175
|
|
|
10842
11176
|
TOOLS
|
|
10843
11177
|
|
|
@@ -10885,6 +11219,8 @@ Summaries accumulate as the session grows. When tier-1 summaries pile up, the sy
|
|
|
10885
11219
|
|
|
10886
11220
|
To compress blocks: use block IDs as boundaries: \`compress({ content: [{ startId: "b3", endId: "b15", summary: "..." }] })\`. Multiple entries create separate blocks: \`compress({ content: [{ startId: "b3", endId: "b10", summary: "..." }, { startId: "b11", endId: "b20", summary: "..." }] })\`. This deactivates the consumed blocks and creates a new higher-tier block per entry. The system prompt at the trigger tells you which rules to follow.
|
|
10887
11221
|
|
|
11222
|
+
If you are unsure which \`mNNNNN\` refs are still compressible, or which blocks have already consumed which ranges, call \`acp_status\` first. It returns the visible context breakdown and the compressed block list.
|
|
11223
|
+
|
|
10888
11224
|
CONTEXT BREAKDOWN
|
|
10889
11225
|
|
|
10890
11226
|
When context usage passes a threshold, the system appends a breakdown showing where your context tokens are spent:
|
|
@@ -10907,7 +11243,7 @@ var SYSTEM = buildSystemPrompt(true);
|
|
|
10907
11243
|
|
|
10908
11244
|
// lib/prompts/compress-range.ts
|
|
10909
11245
|
var CANDIDATE_GUIDANCE_SECTION = `CANDIDATE GUIDANCE
|
|
10910
|
-
ACP may display a \`COMPRESSION CANDIDATES\` list in a nudge or \`acp_status\` report. A \`MICRO\` entry targets one large message or complete tool transaction; an \`EPISODE\` entry targets a contiguous historical segment. Displayed candidates are independent and non-overlapping, so they may be batched, but they are advisory: compress only entries whose content is no longer needed. When a nudge lists a clearly stale candidate, use its exact IDs and call \`compress\` before continuing. Keep current intent and active work visible
|
|
11246
|
+
ACP may display a \`COMPRESSION CANDIDATES\` list in a nudge or \`acp_status\` report. A \`MICRO\` entry targets one large message or complete tool transaction; an \`EPISODE\` entry targets a contiguous historical segment. Displayed candidates are independent and non-overlapping, so they may be batched, but they are advisory: compress only entries whose content is no longer needed. When a nudge lists a clearly stale candidate, use its exact IDs and call \`compress\` before continuing. Keep current intent and active work visible, and use \`acp_status\` when the candidate list is stale.`;
|
|
10911
11247
|
function buildCompressRangePrompt(candidatesEnabled) {
|
|
10912
11248
|
const candidateGuidanceBlock = candidatesEnabled ? `${CANDIDATE_GUIDANCE_SECTION}
|
|
10913
11249
|
|
|
@@ -12823,6 +13159,14 @@ ${text}`);
|
|
|
12823
13159
|
hideFailedCompressCalls(output.messages);
|
|
12824
13160
|
stripStaleMetadata(output.messages);
|
|
12825
13161
|
dropEmptyMessages(output.messages);
|
|
13162
|
+
const smartPlanEnabled = applyCompressOverrides(
|
|
13163
|
+
config,
|
|
13164
|
+
state.modelProviderID,
|
|
13165
|
+
state.modelID
|
|
13166
|
+
).compress.smartPlanRequired;
|
|
13167
|
+
if (state.sessionId && smartPlanEnabled === true) {
|
|
13168
|
+
recordVisibleMessages(state.sessionId, output.messages);
|
|
13169
|
+
}
|
|
12826
13170
|
const postTokens = getCurrentTokenUsage(state, output.messages);
|
|
12827
13171
|
if (postTokens !== void 0 && effectiveLimit) {
|
|
12828
13172
|
const budget = effectiveLimit.limit - (state.systemPromptTokens ?? 0) - OUTPUT_RESERVE_TOKENS;
|
|
@@ -12938,6 +13282,11 @@ function createTextCompleteHandler(registry4, logger) {
|
|
|
12938
13282
|
}
|
|
12939
13283
|
function createEventHandler(registry4, logger) {
|
|
12940
13284
|
return async (input) => {
|
|
13285
|
+
if (input.event?.type === "session.idle" || input.event?.type === "session.deleted") {
|
|
13286
|
+
const sessionID = input.event?.properties?.sessionID ?? input.event?.properties?.info?.id;
|
|
13287
|
+
if (typeof sessionID === "string") clearSmartPlanSession(sessionID);
|
|
13288
|
+
return;
|
|
13289
|
+
}
|
|
12941
13290
|
const eventTime = typeof input.event?.time === "number" && Number.isFinite(input.event.time) ? input.event.time : typeof input.event?.properties?.time === "number" && Number.isFinite(input.event.properties.time) ? input.event.properties.time : void 0;
|
|
12942
13291
|
if (input.event.type !== "message.part.updated") {
|
|
12943
13292
|
return;
|
|
@@ -13275,7 +13624,7 @@ var server = (async (ctx) => {
|
|
|
13275
13624
|
}
|
|
13276
13625
|
const logger = new Logger(config.debug, config.debug ? "debug" : config.logLevel);
|
|
13277
13626
|
logger.info("ACP plugin initialized", {
|
|
13278
|
-
version: true ? "1.18.
|
|
13627
|
+
version: true ? "1.18.2-pr.440.187" : "dev",
|
|
13279
13628
|
workspace: ctx.directory,
|
|
13280
13629
|
logLevel: logger.level,
|
|
13281
13630
|
debug: config.debug,
|