opencode-acp 1.18.1-pr.408.164 → 1.18.1-pr.409.165
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 +470 -503
- package/dist/index.js.map +1 -1
- package/dist/lib/compress/decompress.d.ts.map +1 -1
- package/dist/lib/compress/range.d.ts.map +1 -1
- package/dist/lib/hooks.d.ts.map +1 -1
- package/dist/lib/state/rebuild.d.ts.map +1 -1
- package/dist/lib/state/state.d.ts +0 -17
- package/dist/lib/state/state.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4555,8 +4555,29 @@ function fingerprintMessage(message) {
|
|
|
4555
4555
|
});
|
|
4556
4556
|
return createHash("sha256").update(JSON.stringify({ role: message.info.role, parts })).digest("hex");
|
|
4557
4557
|
}
|
|
4558
|
+
function normalizeParentMessageIds(messageIds) {
|
|
4559
|
+
if (!messageIds) return void 0;
|
|
4560
|
+
const migrate = (ref) => {
|
|
4561
|
+
const parsed = parseMessageRef(ref);
|
|
4562
|
+
return parsed !== null ? formatMessageRef(parsed) : ref;
|
|
4563
|
+
};
|
|
4564
|
+
const byRawId = {};
|
|
4565
|
+
const byRef = {};
|
|
4566
|
+
for (const [rawId, ref] of Object.entries(messageIds.byRawId || {})) {
|
|
4567
|
+
const normalized = migrate(ref);
|
|
4568
|
+
byRawId[rawId] = normalized;
|
|
4569
|
+
byRef[normalized] = rawId;
|
|
4570
|
+
}
|
|
4571
|
+
for (const [ref, rawId] of Object.entries(messageIds.byRef || {})) {
|
|
4572
|
+
const normalized = migrate(ref);
|
|
4573
|
+
if (byRef[normalized] === void 0) {
|
|
4574
|
+
byRef[normalized] = rawId;
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4577
|
+
return { byRef, byRawId, nextRef: messageIds.nextRef || 1 };
|
|
4578
|
+
}
|
|
4558
4579
|
function mapForkIds(state, parent, parentMessages, forkMessages) {
|
|
4559
|
-
const parentRefs = parent.messageIds?.byRef;
|
|
4580
|
+
const parentRefs = normalizeParentMessageIds(parent.messageIds)?.byRef;
|
|
4560
4581
|
if (!parentRefs) return null;
|
|
4561
4582
|
const parentById = new Map(parentMessages.map((message) => [message.info.id, message]));
|
|
4562
4583
|
const forkById = new Map(forkMessages.map((message) => [message.info.id, message]));
|
|
@@ -4830,30 +4851,6 @@ async function updatePerTurnState(state, logger, messages) {
|
|
|
4830
4851
|
state.currentTurn = countTurns(state, messages);
|
|
4831
4852
|
}
|
|
4832
4853
|
var REGISTRY_SOFT_CAP = 32;
|
|
4833
|
-
function createSessionGuard() {
|
|
4834
|
-
const locks = /* @__PURE__ */ new Map();
|
|
4835
|
-
return async (sessionId, fn) => {
|
|
4836
|
-
const previous = locks.get(sessionId) ?? Promise.resolve();
|
|
4837
|
-
let release;
|
|
4838
|
-
const released = new Promise((resolve2) => {
|
|
4839
|
-
release = resolve2;
|
|
4840
|
-
});
|
|
4841
|
-
const chain = previous.then(() => released);
|
|
4842
|
-
locks.set(sessionId, chain);
|
|
4843
|
-
try {
|
|
4844
|
-
await previous;
|
|
4845
|
-
} catch {
|
|
4846
|
-
}
|
|
4847
|
-
try {
|
|
4848
|
-
return await fn();
|
|
4849
|
-
} finally {
|
|
4850
|
-
release();
|
|
4851
|
-
if (locks.get(sessionId) === chain) {
|
|
4852
|
-
locks.delete(sessionId);
|
|
4853
|
-
}
|
|
4854
|
-
}
|
|
4855
|
-
};
|
|
4856
|
-
}
|
|
4857
4854
|
var SessionStateRegistry = class {
|
|
4858
4855
|
constructor(logger, projectDir) {
|
|
4859
4856
|
this.logger = logger;
|
|
@@ -4913,15 +4910,9 @@ var SessionStateRegistry = class {
|
|
|
4913
4910
|
get size() {
|
|
4914
4911
|
return this.states.size;
|
|
4915
4912
|
}
|
|
4916
|
-
// [Issue #404] Per-session FIFO mutex serializing same-session mutations
|
|
4917
|
-
// (message transforms, compress/decompress tools, event-hook saves,
|
|
4918
|
-
// system-hook limit writes). Shared factory so test stubs compose the
|
|
4919
|
-
// exact same implementation instead of drifting.
|
|
4920
|
-
withSessionGuard = createSessionGuard();
|
|
4921
4913
|
// Idempotent: ensureSessionInitialized returns immediately once
|
|
4922
|
-
// state.sessionId === sessionId
|
|
4923
|
-
//
|
|
4924
|
-
// re-reset or observe partially initialized state.
|
|
4914
|
+
// state.sessionId === sessionId (assigned synchronously before any await),
|
|
4915
|
+
// so repeat calls for the same session never re-reset.
|
|
4925
4916
|
async getOrCreate(client, sessionId, messages, config) {
|
|
4926
4917
|
let state = this.states.get(sessionId);
|
|
4927
4918
|
if (!state) {
|
|
@@ -5049,25 +5040,10 @@ function resetSessionState(state) {
|
|
|
5049
5040
|
state.qualityGateRetryPending = false;
|
|
5050
5041
|
state.noContextLimitWarned = false;
|
|
5051
5042
|
}
|
|
5052
|
-
var inflightInits = /* @__PURE__ */ new WeakMap();
|
|
5053
5043
|
async function ensureSessionInitialized(client, state, sessionId, logger, messages, config, projectDir) {
|
|
5054
|
-
const inflight = inflightInits.get(state);
|
|
5055
|
-
if (inflight) {
|
|
5056
|
-
await inflight;
|
|
5057
|
-
return;
|
|
5058
|
-
}
|
|
5059
5044
|
if (state.sessionId === sessionId) {
|
|
5060
5045
|
return;
|
|
5061
5046
|
}
|
|
5062
|
-
const run = runSessionInitialization(client, state, sessionId, logger, messages, config, projectDir);
|
|
5063
|
-
inflightInits.set(state, run);
|
|
5064
|
-
try {
|
|
5065
|
-
await run;
|
|
5066
|
-
} finally {
|
|
5067
|
-
inflightInits.delete(state);
|
|
5068
|
-
}
|
|
5069
|
-
}
|
|
5070
|
-
async function runSessionInitialization(client, state, sessionId, logger, messages, config, projectDir) {
|
|
5071
5047
|
resetSessionState(state);
|
|
5072
5048
|
state.sessionId = sessionId;
|
|
5073
5049
|
state.storageDir = config?.storagePath ? resolveStorageDir(config.storagePath, projectDir ?? cwd()) : void 0;
|
|
@@ -5090,7 +5066,7 @@ async function runSessionInitialization(client, state, sessionId, logger, messag
|
|
|
5090
5066
|
let restored = 0;
|
|
5091
5067
|
if (parentSessionId) {
|
|
5092
5068
|
try {
|
|
5093
|
-
const parent = await loadSessionState(parentSessionId, logger);
|
|
5069
|
+
const parent = await loadSessionState(parentSessionId, logger, state.storageDir);
|
|
5094
5070
|
const response = parent ? await client.session.messages({ path: { id: parentSessionId } }) : void 0;
|
|
5095
5071
|
const parentMessages = Array.isArray(response?.data) ? response.data : Array.isArray(response) ? response : [];
|
|
5096
5072
|
if (parent && parentMessages.length > 0) {
|
|
@@ -5171,6 +5147,14 @@ async function runSessionInitialization(client, state, sessionId, logger, messag
|
|
|
5171
5147
|
if (persistedAny._persistedLastCompaction !== void 0) {
|
|
5172
5148
|
state.lastCompaction = Math.max(state.lastCompaction, persistedAny._persistedLastCompaction);
|
|
5173
5149
|
}
|
|
5150
|
+
const persistedBoundary = typeof persistedAny._persistedLastCompaction === "number" ? persistedAny._persistedLastCompaction : 0;
|
|
5151
|
+
if (state.lastCompaction > persistedBoundary) {
|
|
5152
|
+
resetOnCompaction(state);
|
|
5153
|
+
logger.info("Restarted after native compaction - reset stale transient state", {
|
|
5154
|
+
timestamp: state.lastCompaction,
|
|
5155
|
+
persistedBoundary
|
|
5156
|
+
});
|
|
5157
|
+
}
|
|
5174
5158
|
if (typeof persisted.modelContextLimit === "number" && persisted.modelContextLimit > 0) {
|
|
5175
5159
|
state.modelContextLimit = persisted.modelContextLimit;
|
|
5176
5160
|
state.modelProviderID = persisted.modelProviderID;
|
|
@@ -7713,217 +7697,214 @@ function createCompressRangeTool(factoryCtx) {
|
|
|
7713
7697
|
}
|
|
7714
7698
|
}
|
|
7715
7699
|
const callId = typeof toolCtx.callID === "string" ? toolCtx.callID : void 0;
|
|
7716
|
-
const
|
|
7717
|
-
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
|
|
7700
|
+
const { rawMessages, searchContext } = await prepareSession(
|
|
7701
|
+
ctx0,
|
|
7702
|
+
toolCtx,
|
|
7703
|
+
`Compress Range: ${input.topic ?? "(batch)"}`
|
|
7704
|
+
);
|
|
7705
|
+
const { providerId, modelId } = getModelInfo(rawMessages);
|
|
7706
|
+
const ctx = {
|
|
7707
|
+
...ctx0,
|
|
7708
|
+
config: applyCompressOverrides(ctx0.config, providerId, modelId)
|
|
7709
|
+
};
|
|
7710
|
+
const { plans: filteredPlans } = prepareExecutableRangePlans(
|
|
7711
|
+
input,
|
|
7712
|
+
searchContext,
|
|
7713
|
+
ctx.state,
|
|
7714
|
+
ctx.config,
|
|
7715
|
+
ctx.logger
|
|
7716
|
+
);
|
|
7717
|
+
const notifications = [];
|
|
7718
|
+
let preparedPlans = [];
|
|
7719
|
+
let totalCompressedMessages = 0;
|
|
7720
|
+
for (const plan of filteredPlans) {
|
|
7721
|
+
const parsedPlaceholders = parseBlockPlaceholders(plan.entry.summary);
|
|
7722
|
+
validateSummaryPlaceholders(
|
|
7723
|
+
parsedPlaceholders,
|
|
7724
|
+
plan.selection.requiredBlockIds,
|
|
7725
|
+
plan.selection.startReference,
|
|
7726
|
+
plan.selection.endReference,
|
|
7727
|
+
searchContext.summaryByBlockId,
|
|
7728
|
+
ctx.logger
|
|
7721
7729
|
);
|
|
7722
|
-
const
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7730
|
+
const injected = injectBlockPlaceholders(
|
|
7731
|
+
plan.entry.summary,
|
|
7732
|
+
parsedPlaceholders,
|
|
7733
|
+
searchContext.summaryByBlockId,
|
|
7734
|
+
plan.selection.startReference,
|
|
7735
|
+
plan.selection.endReference
|
|
7736
|
+
);
|
|
7737
|
+
const summaryWithUsers = appendProtectedUserMessages(
|
|
7738
|
+
injected.expandedSummary,
|
|
7739
|
+
plan.selection,
|
|
7729
7740
|
searchContext,
|
|
7730
7741
|
ctx.state,
|
|
7731
|
-
ctx.config
|
|
7732
|
-
ctx.logger
|
|
7742
|
+
ctx.config.compress.protectUserMessages
|
|
7733
7743
|
);
|
|
7734
|
-
const
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
parsedPlaceholders,
|
|
7741
|
-
plan.selection.requiredBlockIds,
|
|
7742
|
-
plan.selection.startReference,
|
|
7743
|
-
plan.selection.endReference,
|
|
7744
|
-
searchContext.summaryByBlockId,
|
|
7745
|
-
ctx.logger
|
|
7746
|
-
);
|
|
7747
|
-
const injected = injectBlockPlaceholders(
|
|
7748
|
-
plan.entry.summary,
|
|
7749
|
-
parsedPlaceholders,
|
|
7750
|
-
searchContext.summaryByBlockId,
|
|
7751
|
-
plan.selection.startReference,
|
|
7752
|
-
plan.selection.endReference
|
|
7753
|
-
);
|
|
7754
|
-
const summaryWithUsers = appendProtectedUserMessages(
|
|
7755
|
-
injected.expandedSummary,
|
|
7756
|
-
plan.selection,
|
|
7757
|
-
searchContext,
|
|
7758
|
-
ctx.state,
|
|
7759
|
-
ctx.config.compress.protectUserMessages
|
|
7760
|
-
);
|
|
7761
|
-
const summaryWithPromptInfo = appendProtectedPromptInfo(
|
|
7762
|
-
summaryWithUsers,
|
|
7763
|
-
plan.selection,
|
|
7764
|
-
searchContext,
|
|
7765
|
-
ctx.state,
|
|
7766
|
-
ctx.config.compress.protectTags
|
|
7767
|
-
);
|
|
7768
|
-
const summaryWithTools = await appendProtectedTools(
|
|
7769
|
-
ctx.client,
|
|
7770
|
-
ctx.state,
|
|
7771
|
-
summaryWithPromptInfo,
|
|
7772
|
-
plan.selection,
|
|
7773
|
-
searchContext,
|
|
7774
|
-
ctx.config.compress.protectedTools,
|
|
7775
|
-
ctx.config.protectedFilePatterns
|
|
7776
|
-
);
|
|
7777
|
-
const completedSummary = appendMissingBlockSummaries(
|
|
7778
|
-
summaryWithTools,
|
|
7779
|
-
[],
|
|
7780
|
-
searchContext.summaryByBlockId,
|
|
7781
|
-
injected.consumedBlockIds
|
|
7782
|
-
);
|
|
7783
|
-
const boundaryConsumed = extractBoundaryConsumedBlocks2(
|
|
7784
|
-
plan.selection.startReference,
|
|
7785
|
-
plan.selection.endReference
|
|
7786
|
-
);
|
|
7787
|
-
const seenConsumed = /* @__PURE__ */ new Set();
|
|
7788
|
-
const mergeConsumedBlockIds = [
|
|
7789
|
-
...plan.selection.requiredBlockIds,
|
|
7790
|
-
...boundaryConsumed
|
|
7791
|
-
].filter((id) => {
|
|
7792
|
-
if (seenConsumed.has(id)) return false;
|
|
7793
|
-
seenConsumed.add(id);
|
|
7794
|
-
return true;
|
|
7795
|
-
});
|
|
7796
|
-
preparedPlans.push({
|
|
7797
|
-
entry: plan.entry,
|
|
7798
|
-
selection: plan.selection,
|
|
7799
|
-
anchorMessageId: plan.anchorMessageId,
|
|
7800
|
-
finalSummary: completedSummary.expandedSummary,
|
|
7801
|
-
consumedBlockIds: mergeConsumedBlockIds
|
|
7802
|
-
});
|
|
7803
|
-
}
|
|
7804
|
-
const partition = partitionPhantomPlans(
|
|
7805
|
-
identifyPhantomPlans(
|
|
7806
|
-
ctx.state,
|
|
7807
|
-
preparedPlans.map((p) => ({
|
|
7808
|
-
messageIds: p.selection.messageIds,
|
|
7809
|
-
consumedBlockIds: p.consumedBlockIds
|
|
7810
|
-
}))
|
|
7811
|
-
),
|
|
7812
|
-
preparedPlans.length
|
|
7744
|
+
const summaryWithPromptInfo = appendProtectedPromptInfo(
|
|
7745
|
+
summaryWithUsers,
|
|
7746
|
+
plan.selection,
|
|
7747
|
+
searchContext,
|
|
7748
|
+
ctx.state,
|
|
7749
|
+
ctx.config.compress.protectTags
|
|
7813
7750
|
);
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
ctx.
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
const
|
|
7834
|
-
const
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7751
|
+
const summaryWithTools = await appendProtectedTools(
|
|
7752
|
+
ctx.client,
|
|
7753
|
+
ctx.state,
|
|
7754
|
+
summaryWithPromptInfo,
|
|
7755
|
+
plan.selection,
|
|
7756
|
+
searchContext,
|
|
7757
|
+
ctx.config.compress.protectedTools,
|
|
7758
|
+
ctx.config.protectedFilePatterns
|
|
7759
|
+
);
|
|
7760
|
+
const completedSummary = appendMissingBlockSummaries(
|
|
7761
|
+
summaryWithTools,
|
|
7762
|
+
[],
|
|
7763
|
+
searchContext.summaryByBlockId,
|
|
7764
|
+
injected.consumedBlockIds
|
|
7765
|
+
);
|
|
7766
|
+
const boundaryConsumed = extractBoundaryConsumedBlocks2(
|
|
7767
|
+
plan.selection.startReference,
|
|
7768
|
+
plan.selection.endReference
|
|
7769
|
+
);
|
|
7770
|
+
const seenConsumed = /* @__PURE__ */ new Set();
|
|
7771
|
+
const mergeConsumedBlockIds = [
|
|
7772
|
+
...plan.selection.requiredBlockIds,
|
|
7773
|
+
...boundaryConsumed
|
|
7774
|
+
].filter((id) => {
|
|
7775
|
+
if (seenConsumed.has(id)) return false;
|
|
7776
|
+
seenConsumed.add(id);
|
|
7777
|
+
return true;
|
|
7778
|
+
});
|
|
7779
|
+
preparedPlans.push({
|
|
7780
|
+
entry: plan.entry,
|
|
7781
|
+
selection: plan.selection,
|
|
7782
|
+
anchorMessageId: plan.anchorMessageId,
|
|
7783
|
+
finalSummary: completedSummary.expandedSummary,
|
|
7784
|
+
consumedBlockIds: mergeConsumedBlockIds
|
|
7785
|
+
});
|
|
7786
|
+
}
|
|
7787
|
+
const partition = partitionPhantomPlans(
|
|
7788
|
+
identifyPhantomPlans(
|
|
7789
|
+
ctx.state,
|
|
7790
|
+
preparedPlans.map((p) => ({
|
|
7791
|
+
messageIds: p.selection.messageIds,
|
|
7792
|
+
consumedBlockIds: p.consumedBlockIds
|
|
7793
|
+
}))
|
|
7794
|
+
),
|
|
7795
|
+
preparedPlans.length
|
|
7796
|
+
);
|
|
7797
|
+
let phantomSkipNotice = null;
|
|
7798
|
+
if (partition.kind === "all-phantom") {
|
|
7799
|
+
ctx.logger.warn("Batch compress: ALL entries phantom", {
|
|
7800
|
+
totalCount: preparedPlans.length,
|
|
7801
|
+
details: partition.details
|
|
7802
|
+
});
|
|
7803
|
+
throw new Error(buildPhantomErrorMessage(partition.details));
|
|
7804
|
+
}
|
|
7805
|
+
if (partition.kind === "partial") {
|
|
7806
|
+
ctx.logger.warn("Batch compress: phantom entries detected", {
|
|
7807
|
+
phantomCount: partition.dropIndices.length,
|
|
7808
|
+
totalCount: preparedPlans.length,
|
|
7809
|
+
phantomIndices: partition.dropIndices,
|
|
7810
|
+
details: partition.details
|
|
7811
|
+
});
|
|
7812
|
+
const dropSet = new Set(partition.dropIndices);
|
|
7813
|
+
preparedPlans = preparedPlans.filter((_, i) => !dropSet.has(i));
|
|
7814
|
+
phantomSkipNotice = partition.notice;
|
|
7815
|
+
}
|
|
7816
|
+
const acknowledgeRisk = args.acknowledgeRisk === true;
|
|
7817
|
+
const qualityGateRetryPendingBefore = ctx.state.qualityGateRetryPending;
|
|
7818
|
+
const bypassQuality = acknowledgeRisk && ctx.state.qualityGateRetryPending;
|
|
7819
|
+
const ignoredAcknowledgeRisk = acknowledgeRisk && !ctx.state.qualityGateRetryPending;
|
|
7820
|
+
if (ignoredAcknowledgeRisk) {
|
|
7821
|
+
ctx.logger.warn(
|
|
7822
|
+
"compress: acknowledgeRisk ignored \u2014 no quality gate rejection pending"
|
|
7823
|
+
);
|
|
7824
|
+
}
|
|
7825
|
+
ctx.state.qualityGateRetryPending = false;
|
|
7826
|
+
if (!bypassQuality) {
|
|
7827
|
+
for (const plan of preparedPlans) {
|
|
7828
|
+
const result = evaluatePreCommitQuality(
|
|
7829
|
+
rawMessages,
|
|
7830
|
+
plan.selection.messageIds,
|
|
7831
|
+
plan.selection.messageTokenById,
|
|
7832
|
+
plan.finalSummary,
|
|
7833
|
+
ctx.config,
|
|
7834
|
+
ctx.logger
|
|
7840
7835
|
);
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
for (const plan of preparedPlans) {
|
|
7845
|
-
const result = evaluatePreCommitQuality(
|
|
7846
|
-
rawMessages,
|
|
7847
|
-
plan.selection.messageIds,
|
|
7848
|
-
plan.selection.messageTokenById,
|
|
7849
|
-
plan.finalSummary,
|
|
7850
|
-
ctx.config,
|
|
7851
|
-
ctx.logger
|
|
7852
|
-
);
|
|
7853
|
-
if (result && !result.passed) {
|
|
7854
|
-
ctx.state.qualityGateRetryPending = true;
|
|
7855
|
-
throw buildQualityRejectionError(
|
|
7856
|
-
{
|
|
7857
|
-
startId: plan.entry.startId,
|
|
7858
|
-
endId: plan.entry.endId,
|
|
7859
|
-
summary: plan.finalSummary,
|
|
7860
|
-
messageIds: plan.selection.messageIds,
|
|
7861
|
-
messageTokenById: plan.selection.messageTokenById
|
|
7862
|
-
},
|
|
7863
|
-
result
|
|
7864
|
-
);
|
|
7865
|
-
}
|
|
7866
|
-
}
|
|
7867
|
-
}
|
|
7868
|
-
const snapshot = snapshotCompressionState(ctx.state);
|
|
7869
|
-
const runId = allocateRunId(ctx.state);
|
|
7870
|
-
try {
|
|
7871
|
-
for (const preparedPlan of preparedPlans) {
|
|
7872
|
-
const blockId = allocateBlockId(ctx.state);
|
|
7873
|
-
const keepResult = resolveKeepMarkers(
|
|
7874
|
-
preparedPlan.finalSummary,
|
|
7875
|
-
rawMessages,
|
|
7876
|
-
ctx.state,
|
|
7877
|
-
ctx.config
|
|
7878
|
-
);
|
|
7879
|
-
preparedPlan.finalSummary = keepResult.summary;
|
|
7880
|
-
const storedSummary = wrapCompressedSummary(blockId, preparedPlan.finalSummary);
|
|
7881
|
-
const summaryTokens = countTokens2(storedSummary);
|
|
7882
|
-
const applied = applyCompressionState(
|
|
7883
|
-
ctx.state,
|
|
7836
|
+
if (result && !result.passed) {
|
|
7837
|
+
ctx.state.qualityGateRetryPending = true;
|
|
7838
|
+
throw buildQualityRejectionError(
|
|
7884
7839
|
{
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
runId,
|
|
7891
|
-
compressMessageId: toolCtx.messageID,
|
|
7892
|
-
compressCallId: callId,
|
|
7893
|
-
summaryTokens
|
|
7840
|
+
startId: plan.entry.startId,
|
|
7841
|
+
endId: plan.entry.endId,
|
|
7842
|
+
summary: plan.finalSummary,
|
|
7843
|
+
messageIds: plan.selection.messageIds,
|
|
7844
|
+
messageTokenById: plan.selection.messageTokenById
|
|
7894
7845
|
},
|
|
7895
|
-
|
|
7896
|
-
preparedPlan.anchorMessageId,
|
|
7897
|
-
blockId,
|
|
7898
|
-
storedSummary,
|
|
7899
|
-
preparedPlan.consumedBlockIds,
|
|
7900
|
-
ctx.config.gc
|
|
7846
|
+
result
|
|
7901
7847
|
);
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
7848
|
+
}
|
|
7849
|
+
}
|
|
7850
|
+
}
|
|
7851
|
+
const snapshot = snapshotCompressionState(ctx.state);
|
|
7852
|
+
const runId = allocateRunId(ctx.state);
|
|
7853
|
+
try {
|
|
7854
|
+
for (const preparedPlan of preparedPlans) {
|
|
7855
|
+
const blockId = allocateBlockId(ctx.state);
|
|
7856
|
+
const keepResult = resolveKeepMarkers(
|
|
7857
|
+
preparedPlan.finalSummary,
|
|
7858
|
+
rawMessages,
|
|
7859
|
+
ctx.state,
|
|
7860
|
+
ctx.config
|
|
7861
|
+
);
|
|
7862
|
+
preparedPlan.finalSummary = keepResult.summary;
|
|
7863
|
+
const storedSummary = wrapCompressedSummary(blockId, preparedPlan.finalSummary);
|
|
7864
|
+
const summaryTokens = countTokens2(storedSummary);
|
|
7865
|
+
const applied = applyCompressionState(
|
|
7866
|
+
ctx.state,
|
|
7867
|
+
{
|
|
7868
|
+
topic: preparedPlan.entry.topic ?? input.topic ?? "",
|
|
7869
|
+
batchTopic: input.topic,
|
|
7870
|
+
startId: preparedPlan.entry.startId,
|
|
7871
|
+
endId: preparedPlan.entry.endId,
|
|
7872
|
+
mode: "range",
|
|
7905
7873
|
runId,
|
|
7906
|
-
|
|
7874
|
+
compressMessageId: toolCtx.messageID,
|
|
7875
|
+
compressCallId: callId,
|
|
7907
7876
|
summaryTokens
|
|
7908
|
-
}
|
|
7909
|
-
|
|
7910
|
-
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7877
|
+
},
|
|
7878
|
+
preparedPlan.selection,
|
|
7879
|
+
preparedPlan.anchorMessageId,
|
|
7880
|
+
blockId,
|
|
7881
|
+
storedSummary,
|
|
7882
|
+
preparedPlan.consumedBlockIds,
|
|
7883
|
+
ctx.config.gc
|
|
7884
|
+
);
|
|
7885
|
+
totalCompressedMessages += applied.messageIds.length;
|
|
7886
|
+
notifications.push({
|
|
7887
|
+
blockId,
|
|
7888
|
+
runId,
|
|
7889
|
+
summary: preparedPlan.finalSummary,
|
|
7890
|
+
summaryTokens
|
|
7891
|
+
});
|
|
7915
7892
|
}
|
|
7916
|
-
|
|
7893
|
+
await finalizeSession(ctx, toolCtx, rawMessages, notifications, input.topic);
|
|
7894
|
+
} catch (error) {
|
|
7895
|
+
restoreCompressionState(ctx.state, snapshot);
|
|
7896
|
+
ctx.state.qualityGateRetryPending = qualityGateRetryPendingBefore;
|
|
7897
|
+
throw error;
|
|
7898
|
+
}
|
|
7899
|
+
const skippedNote = phantomSkipNotice !== null ? `
|
|
7917
7900
|
\u26A0\uFE0F ${phantomSkipNotice}
|
|
7918
7901
|
` : "";
|
|
7919
|
-
|
|
7902
|
+
const ackNote = ignoredAcknowledgeRisk ? `
|
|
7920
7903
|
\u26A0\uFE0F acknowledgeRisk was ignored: no quality gate rejection was pending, so quality checks ran normally. Only pass it when retrying immediately after a quality gate rejection.
|
|
7921
7904
|
` : "";
|
|
7922
|
-
|
|
7905
|
+
return `Compressed ${totalCompressedMessages} messages into ${COMPRESSED_BLOCK_HEADER}.${skippedNote}${ackNote}
|
|
7923
7906
|
IMPORTANT: This was an automatic context compression. You MUST continue your previous task exactly where you left off. Do NOT ask the user what to do next.
|
|
7924
7907
|
\u{1F4A1} Tip: Use search_context('keyword') to find compressed content when you need it later.`;
|
|
7925
|
-
};
|
|
7926
|
-
return factoryCtx.registry.withSessionGuard(toolCtx.sessionID, () => run());
|
|
7927
7908
|
}
|
|
7928
7909
|
});
|
|
7929
7910
|
}
|
|
@@ -9804,112 +9785,109 @@ function createDecompressTool(factoryCtx) {
|
|
|
9804
9785
|
args: buildSchema2(),
|
|
9805
9786
|
async execute(args, toolCtx) {
|
|
9806
9787
|
const ctx = resolveToolContext(factoryCtx, toolCtx.sessionID);
|
|
9807
|
-
const
|
|
9808
|
-
|
|
9809
|
-
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
|
-
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
for (const
|
|
9821
|
-
|
|
9822
|
-
|
|
9823
|
-
activeBlocks.push(block);
|
|
9824
|
-
}
|
|
9825
|
-
}
|
|
9826
|
-
}
|
|
9827
|
-
if (args.toFile) {
|
|
9828
|
-
const targetPath = args.toFile;
|
|
9829
|
-
const os = await import("os");
|
|
9830
|
-
const path = await import("path");
|
|
9831
|
-
const allowedDirs = [
|
|
9832
|
-
os.tmpdir() + "/",
|
|
9833
|
-
path.join(os.homedir(), ".cache", "opencode") + "/"
|
|
9834
|
-
];
|
|
9835
|
-
const resolvedPath = path.resolve(targetPath);
|
|
9836
|
-
const isAllowed = allowedDirs.some((dir) => {
|
|
9837
|
-
const rel = path.relative(dir, resolvedPath);
|
|
9838
|
-
return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
9839
|
-
});
|
|
9840
|
-
if (!isAllowed) {
|
|
9841
|
-
return `Error: toFile path must be under ${os.tmpdir()} or ~/.cache/opencode/. Got: ${targetPath}`;
|
|
9842
|
-
}
|
|
9843
|
-
const msgIdSet = /* @__PURE__ */ new Set();
|
|
9844
|
-
for (const block of activeBlocks) {
|
|
9845
|
-
for (const id of block.effectiveMessageIds ?? []) {
|
|
9846
|
-
msgIdSet.add(id);
|
|
9847
|
-
}
|
|
9788
|
+
const { rawMessages } = await prepareDecompressSession(ctx, toolCtx);
|
|
9789
|
+
const effectiveLimitBefore = resolveEffectiveContextLimit(ctx.state, ctx.config);
|
|
9790
|
+
const contextUsageBefore = effectiveLimitBefore ? Math.round(
|
|
9791
|
+
getCurrentTokenUsage(ctx.state, rawMessages) / effectiveLimitBefore.limit * 100
|
|
9792
|
+
) : void 0;
|
|
9793
|
+
const resolved = resolveTargets(args, ctx.state, rawMessages, ctx.logger);
|
|
9794
|
+
if (!resolved.ok) {
|
|
9795
|
+
return resolved.error;
|
|
9796
|
+
}
|
|
9797
|
+
const targets = resolved.targets;
|
|
9798
|
+
const messagesState = ctx.state.prune.messages;
|
|
9799
|
+
const activeBlocks = [];
|
|
9800
|
+
for (const target of targets) {
|
|
9801
|
+
for (const block of target.blocks) {
|
|
9802
|
+
if (block.active) {
|
|
9803
|
+
activeBlocks.push(block);
|
|
9848
9804
|
}
|
|
9849
|
-
const blockMessages = rawMessages.filter((m) => msgIdSet.has(extractMessageId(m)));
|
|
9850
|
-
const lines2 = blockMessages.map(extractMessageText2);
|
|
9851
|
-
const { writeFile: writeFile4 } = await import("fs/promises");
|
|
9852
|
-
const fileContent = lines2.length > 0 ? lines2.join("\n\n---\n\n") : targets[0]?.blocks[0]?.summary ?? "(no content available)";
|
|
9853
|
-
await writeFile4(targetPath, fileContent, "utf-8");
|
|
9854
|
-
const displayIds2 = targets.map((t) => `b${t.displayId}`).join(", ");
|
|
9855
|
-
return `Block(s) ${displayIds2} content (${blockMessages.length} messages, ${fileContent.length} chars) written to ${targetPath}. Block(s) stay compressed \u2014 context unchanged. Use read tool to access specific parts.`;
|
|
9856
9805
|
}
|
|
9857
|
-
|
|
9858
|
-
|
|
9859
|
-
|
|
9860
|
-
|
|
9861
|
-
|
|
9862
|
-
|
|
9863
|
-
|
|
9864
|
-
|
|
9865
|
-
|
|
9866
|
-
);
|
|
9867
|
-
const
|
|
9868
|
-
|
|
9869
|
-
|
|
9870
|
-
);
|
|
9871
|
-
|
|
9872
|
-
|
|
9873
|
-
ctx.state.stats.totalPruneTokens - restoredTokens
|
|
9874
|
-
);
|
|
9875
|
-
const effectiveLimitAfter = resolveEffectiveContextLimit(ctx.state, ctx.config);
|
|
9876
|
-
const contextUsageAfter = effectiveLimitAfter ? Math.round(
|
|
9877
|
-
getCurrentTokenUsage(ctx.state, rawMessages) / effectiveLimitAfter.limit * 100
|
|
9878
|
-
) : void 0;
|
|
9879
|
-
await finalizeDecompressSession(ctx);
|
|
9880
|
-
const restoredContentPreview = buildRestoredContentPreview(
|
|
9881
|
-
rawMessages,
|
|
9882
|
-
activeMessagesBefore,
|
|
9883
|
-
messagesState
|
|
9884
|
-
);
|
|
9885
|
-
const displayIds = targets.map((t) => `b${t.displayId}`).join(", ");
|
|
9886
|
-
const lines = [];
|
|
9887
|
-
const headerNoun = targets.length === 1 ? "block" : "blocks";
|
|
9888
|
-
lines.push(
|
|
9889
|
-
`Decompressed ${headerNoun} ${displayIds}. Restored ${restoredMessageCount} message(s) (~${formatTokenCount(restoredTokens)}).`
|
|
9890
|
-
);
|
|
9891
|
-
if (contextUsageBefore !== void 0 && contextUsageAfter !== void 0) {
|
|
9892
|
-
lines.push(`Context usage: ${contextUsageBefore}% \u2192 ${contextUsageAfter}%.`);
|
|
9893
|
-
}
|
|
9894
|
-
if (reactivatedBlockIds.length > 0) {
|
|
9895
|
-
const refs = reactivatedBlockIds.map((id) => `b${id}`).join(", ");
|
|
9896
|
-
lines.push(`Also restored nested block(s): ${refs}.`);
|
|
9806
|
+
}
|
|
9807
|
+
if (args.toFile) {
|
|
9808
|
+
const targetPath = args.toFile;
|
|
9809
|
+
const os = await import("os");
|
|
9810
|
+
const path = await import("path");
|
|
9811
|
+
const allowedDirs = [
|
|
9812
|
+
os.tmpdir() + "/",
|
|
9813
|
+
path.join(os.homedir(), ".cache", "opencode") + "/"
|
|
9814
|
+
];
|
|
9815
|
+
const resolvedPath = path.resolve(targetPath);
|
|
9816
|
+
const isAllowed = allowedDirs.some((dir) => {
|
|
9817
|
+
const rel = path.relative(dir, resolvedPath);
|
|
9818
|
+
return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
9819
|
+
});
|
|
9820
|
+
if (!isAllowed) {
|
|
9821
|
+
return `Error: toFile path must be under ${os.tmpdir()} or ~/.cache/opencode/. Got: ${targetPath}`;
|
|
9897
9822
|
}
|
|
9898
|
-
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
|
|
9823
|
+
const msgIdSet = /* @__PURE__ */ new Set();
|
|
9824
|
+
for (const block of activeBlocks) {
|
|
9825
|
+
for (const id of block.effectiveMessageIds ?? []) {
|
|
9826
|
+
msgIdSet.add(id);
|
|
9827
|
+
}
|
|
9902
9828
|
}
|
|
9903
|
-
|
|
9904
|
-
|
|
9905
|
-
|
|
9906
|
-
|
|
9907
|
-
|
|
9908
|
-
|
|
9909
|
-
})
|
|
9910
|
-
|
|
9911
|
-
|
|
9912
|
-
|
|
9829
|
+
const blockMessages = rawMessages.filter((m) => msgIdSet.has(extractMessageId(m)));
|
|
9830
|
+
const lines2 = blockMessages.map(extractMessageText2);
|
|
9831
|
+
const { writeFile: writeFile4 } = await import("fs/promises");
|
|
9832
|
+
const fileContent = lines2.length > 0 ? lines2.join("\n\n---\n\n") : targets[0]?.blocks[0]?.summary ?? "(no content available)";
|
|
9833
|
+
await writeFile4(targetPath, fileContent, "utf-8");
|
|
9834
|
+
const displayIds2 = targets.map((t) => `b${t.displayId}`).join(", ");
|
|
9835
|
+
return `Block(s) ${displayIds2} content (${blockMessages.length} messages, ${fileContent.length} chars) written to ${targetPath}. Block(s) stay compressed \u2014 context unchanged. Use read tool to access specific parts.`;
|
|
9836
|
+
}
|
|
9837
|
+
const activeMessagesBefore = snapshotActiveMessages(messagesState);
|
|
9838
|
+
const activeBlockIdsBefore = new Set(messagesState.activeBlockIds);
|
|
9839
|
+
for (const target of targets) {
|
|
9840
|
+
deactivateCompressionTarget(messagesState, target, { full: args.full === true });
|
|
9841
|
+
}
|
|
9842
|
+
syncCompressionBlocks(ctx.state, ctx.logger, rawMessages);
|
|
9843
|
+
const { restoredMessageCount, restoredTokens } = computeRestoredMessages(
|
|
9844
|
+
messagesState,
|
|
9845
|
+
activeMessagesBefore
|
|
9846
|
+
);
|
|
9847
|
+
const reactivatedBlockIds = computeReactivatedBlockIds(
|
|
9848
|
+
messagesState,
|
|
9849
|
+
activeBlockIdsBefore
|
|
9850
|
+
);
|
|
9851
|
+
ctx.state.stats.totalPruneTokens = Math.max(
|
|
9852
|
+
0,
|
|
9853
|
+
ctx.state.stats.totalPruneTokens - restoredTokens
|
|
9854
|
+
);
|
|
9855
|
+
const effectiveLimitAfter = resolveEffectiveContextLimit(ctx.state, ctx.config);
|
|
9856
|
+
const contextUsageAfter = effectiveLimitAfter ? Math.round(
|
|
9857
|
+
getCurrentTokenUsage(ctx.state, rawMessages) / effectiveLimitAfter.limit * 100
|
|
9858
|
+
) : void 0;
|
|
9859
|
+
await finalizeDecompressSession(ctx);
|
|
9860
|
+
const restoredContentPreview = buildRestoredContentPreview(
|
|
9861
|
+
rawMessages,
|
|
9862
|
+
activeMessagesBefore,
|
|
9863
|
+
messagesState
|
|
9864
|
+
);
|
|
9865
|
+
const displayIds = targets.map((t) => `b${t.displayId}`).join(", ");
|
|
9866
|
+
const lines = [];
|
|
9867
|
+
const headerNoun = targets.length === 1 ? "block" : "blocks";
|
|
9868
|
+
lines.push(
|
|
9869
|
+
`Decompressed ${headerNoun} ${displayIds}. Restored ${restoredMessageCount} message(s) (~${formatTokenCount(restoredTokens)}).`
|
|
9870
|
+
);
|
|
9871
|
+
if (contextUsageBefore !== void 0 && contextUsageAfter !== void 0) {
|
|
9872
|
+
lines.push(`Context usage: ${contextUsageBefore}% \u2192 ${contextUsageAfter}%.`);
|
|
9873
|
+
}
|
|
9874
|
+
if (reactivatedBlockIds.length > 0) {
|
|
9875
|
+
const refs = reactivatedBlockIds.map((id) => `b${id}`).join(", ");
|
|
9876
|
+
lines.push(`Also restored nested block(s): ${refs}.`);
|
|
9877
|
+
}
|
|
9878
|
+
if (restoredContentPreview) {
|
|
9879
|
+
lines.push("");
|
|
9880
|
+
lines.push("RESTORED CONTENT (condensed):");
|
|
9881
|
+
lines.push(restoredContentPreview);
|
|
9882
|
+
}
|
|
9883
|
+
ctx.logger.info("Decompress tool completed", {
|
|
9884
|
+
mode: typeof args.startId === "string" ? "range" : "block",
|
|
9885
|
+
targetBlockIds: targets.map((t) => t.displayId),
|
|
9886
|
+
restoredMessageCount,
|
|
9887
|
+
restoredTokens,
|
|
9888
|
+
reactivatedBlockIds
|
|
9889
|
+
});
|
|
9890
|
+
return lines.join("\n");
|
|
9913
9891
|
}
|
|
9914
9892
|
});
|
|
9915
9893
|
}
|
|
@@ -10595,7 +10573,7 @@ import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
|
10595
10573
|
import { join as join4 } from "path";
|
|
10596
10574
|
import { existsSync as existsSync4 } from "fs";
|
|
10597
10575
|
import { homedir as homedir3 } from "os";
|
|
10598
|
-
var LOG_VERSION = true ? "1.18.1-pr.
|
|
10576
|
+
var LOG_VERSION = true ? "1.18.1-pr.409.165" : "dev";
|
|
10599
10577
|
var LEVEL_RANK = {
|
|
10600
10578
|
debug: 10,
|
|
10601
10579
|
info: 20,
|
|
@@ -12650,24 +12628,22 @@ function createSystemPromptHandler(registry4, logger, config, prompts) {
|
|
|
12650
12628
|
logger.info("Skipping DCP system prompt injection for internal agent");
|
|
12651
12629
|
return;
|
|
12652
12630
|
}
|
|
12653
|
-
if (input.model?.limit?.context
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
}
|
|
12670
|
-
});
|
|
12631
|
+
if (input.model?.limit?.context) {
|
|
12632
|
+
const limit = input.model.limit.context;
|
|
12633
|
+
const providerID = input.model?.providerID;
|
|
12634
|
+
const modelID = input.model?.id;
|
|
12635
|
+
const changed = state.modelContextLimit !== limit || providerID !== void 0 && state.modelProviderID !== providerID || modelID !== void 0 && state.modelID !== modelID;
|
|
12636
|
+
state.modelContextLimit = limit;
|
|
12637
|
+
if (providerID !== void 0) {
|
|
12638
|
+
state.modelProviderID = providerID;
|
|
12639
|
+
}
|
|
12640
|
+
if (modelID !== void 0) {
|
|
12641
|
+
state.modelID = modelID;
|
|
12642
|
+
}
|
|
12643
|
+
if (changed) {
|
|
12644
|
+
saveSessionState(state, logger).catch(() => {
|
|
12645
|
+
});
|
|
12646
|
+
}
|
|
12671
12647
|
}
|
|
12672
12648
|
const effectivePermission = compressPermission(state, config);
|
|
12673
12649
|
if (effectivePermission === "deny") {
|
|
@@ -12702,131 +12678,11 @@ function createChatMessageTransformHandler(client, registry4, logger, config, pr
|
|
|
12702
12678
|
return;
|
|
12703
12679
|
}
|
|
12704
12680
|
const lastUserMessage = getLastUserMessage(messages);
|
|
12705
|
-
|
|
12706
|
-
syncCompressPermissionState(state, config, hostPermissions, output.messages);
|
|
12707
|
-
if (state.isSubAgent && !config.allowSubAgents) {
|
|
12708
|
-
return;
|
|
12709
|
-
}
|
|
12710
|
-
stripHallucinations(output.messages);
|
|
12711
|
-
const dropReasoningModel = lastUserMessage?.info?.model;
|
|
12712
|
-
const reasoningConfig = applyCompressOverrides(
|
|
12713
|
-
config,
|
|
12714
|
-
dropReasoningModel?.providerID ?? state.modelProviderID,
|
|
12715
|
-
dropReasoningModel?.modelID ?? state.modelID
|
|
12716
|
-
).compress.reasoning;
|
|
12717
|
-
if (reasoningConfig?.drop !== false) {
|
|
12718
|
-
const droppedReasoning = dropCompressReasoning(
|
|
12719
|
-
output.messages,
|
|
12720
|
-
reasoningConfig?.threshold ?? DEFAULT_COMPRESS_REASONING.threshold
|
|
12721
|
-
);
|
|
12722
|
-
if (droppedReasoning > 0) {
|
|
12723
|
-
logger.debug("compress.reasoning: dropped oversized reasoning parts", {
|
|
12724
|
-
dropped: droppedReasoning,
|
|
12725
|
-
threshold: reasoningConfig?.threshold ?? DEFAULT_COMPRESS_REASONING.threshold
|
|
12726
|
-
});
|
|
12727
|
-
}
|
|
12728
|
-
}
|
|
12729
|
-
ensureBuiltinFiltersRegistered();
|
|
12730
|
-
const effectiveLimit = resolveEffectiveContextLimit(state, config);
|
|
12731
|
-
applyMessageFilters(output.messages, config.messageFilters, logger, {
|
|
12732
|
-
sessionId: state.sessionId ?? "",
|
|
12733
|
-
isSubAgent: state.isSubAgent,
|
|
12734
|
-
modelContextLimit: effectiveLimit?.limit
|
|
12735
|
-
});
|
|
12736
|
-
cacheSystemPromptTokens(state, output.messages);
|
|
12737
|
-
assignMessageRefs(state, output.messages);
|
|
12738
|
-
const activeBlockCountBefore = state.prune.messages.activeBlockIds.size;
|
|
12739
|
-
const compressionStateChanged = syncCompressionBlocks(state, logger, output.messages);
|
|
12740
|
-
if (compressionStateChanged || state.prune.messages.activeBlockIds.size !== activeBlockCountBefore) {
|
|
12741
|
-
saveSessionState(state, logger).catch(() => {
|
|
12742
|
-
});
|
|
12743
|
-
}
|
|
12744
|
-
syncToolCache(state, config, logger, output.messages);
|
|
12745
|
-
buildToolIdList(state, output.messages);
|
|
12746
|
-
const batchResult = runBatchCleanup(state, config, logger, output.messages);
|
|
12747
|
-
if (batchResult.mergedCount > 0) {
|
|
12748
|
-
saveSessionState(state, logger).catch(() => {
|
|
12749
|
-
});
|
|
12750
|
-
}
|
|
12751
|
-
const prePruneTokens = getCurrentTokenUsage(state, output.messages);
|
|
12752
|
-
const candidateMessages = config.compress.candidates === true ? output.messages.slice() : void 0;
|
|
12753
|
-
prune(state, logger, config, output.messages);
|
|
12754
|
-
hideConsumedCompressCalls(state, output.messages);
|
|
12755
|
-
assignMessageRefs(state, output.messages);
|
|
12756
|
-
const compressionPriorities = buildPriorityMap(config, state, output.messages);
|
|
12757
|
-
prompts.reload();
|
|
12758
|
-
injectCompressNudges(
|
|
12759
|
-
state,
|
|
12760
|
-
config,
|
|
12761
|
-
logger,
|
|
12762
|
-
output.messages,
|
|
12763
|
-
prompts.getRuntimePrompts(),
|
|
12764
|
-
compressionPriorities,
|
|
12765
|
-
config.debug ? (text) => {
|
|
12766
|
-
logger.debug(`[ACP Debug] Nudge injected:
|
|
12767
|
-
${text}`);
|
|
12768
|
-
client.tui.showToast({
|
|
12769
|
-
body: {
|
|
12770
|
-
title: "ACP: Nudge Injected",
|
|
12771
|
-
message: text.slice(0, 500),
|
|
12772
|
-
variant: "info",
|
|
12773
|
-
duration: 5e3
|
|
12774
|
-
}
|
|
12775
|
-
}).catch(() => {
|
|
12776
|
-
});
|
|
12777
|
-
} : void 0,
|
|
12778
|
-
prePruneTokens,
|
|
12779
|
-
candidateMessages
|
|
12780
|
-
);
|
|
12781
|
-
truncateLargeToolOutputs(
|
|
12782
|
-
state,
|
|
12783
|
-
config,
|
|
12784
|
-
logger,
|
|
12785
|
-
output.messages.filter((message) => !isSyntheticMessage(message))
|
|
12786
|
-
);
|
|
12787
|
-
enforceContextBudget(state, config, logger, output.messages);
|
|
12788
|
-
injectMessageIds(state, config, output.messages, compressionPriorities);
|
|
12789
|
-
hideFailedCompressCalls(output.messages);
|
|
12790
|
-
stripStaleMetadata(output.messages);
|
|
12791
|
-
dropEmptyMessages(output.messages);
|
|
12792
|
-
const postTokens = getCurrentTokenUsage(state, output.messages);
|
|
12793
|
-
if (postTokens !== void 0 && effectiveLimit) {
|
|
12794
|
-
const budget = effectiveLimit.limit - (state.systemPromptTokens ?? 0) - OUTPUT_RESERVE_TOKENS;
|
|
12795
|
-
if (postTokens > budget) {
|
|
12796
|
-
logger.error(
|
|
12797
|
-
"ACP hard guard: context exceeds model budget after in-flight reduction",
|
|
12798
|
-
{
|
|
12799
|
-
session: state.sessionId,
|
|
12800
|
-
postTokens,
|
|
12801
|
-
budget,
|
|
12802
|
-
contextLimit: effectiveLimit.limit,
|
|
12803
|
-
contextLimitSource: effectiveLimit.source,
|
|
12804
|
-
hint: "request will likely be rejected; run /compact or start a new session"
|
|
12805
|
-
}
|
|
12806
|
-
);
|
|
12807
|
-
}
|
|
12808
|
-
}
|
|
12809
|
-
logger.info("Chat transform complete", {
|
|
12810
|
-
session: state.sessionId,
|
|
12811
|
-
model: state.modelID,
|
|
12812
|
-
messages: output.messages.length,
|
|
12813
|
-
prePruneTokens,
|
|
12814
|
-
postTokens,
|
|
12815
|
-
contextLimit: effectiveLimit?.limit,
|
|
12816
|
-
contextLimitSource: effectiveLimit?.source,
|
|
12817
|
-
usagePct: postTokens !== void 0 && effectiveLimit ? `${(postTokens / effectiveLimit.limit * 100).toFixed(1)}%` : void 0,
|
|
12818
|
-
nudged: state.nudges.shouldInjectThisTurn
|
|
12819
|
-
});
|
|
12820
|
-
if (state.sessionId) {
|
|
12821
|
-
await logger.saveContext(state.sessionId, output.messages);
|
|
12822
|
-
}
|
|
12823
|
-
};
|
|
12681
|
+
let state;
|
|
12824
12682
|
if (!lastUserMessage) {
|
|
12825
|
-
|
|
12826
|
-
|
|
12827
|
-
|
|
12828
|
-
await registry4.withSessionGuard(lastUserMessage.info.sessionID, async () => {
|
|
12829
|
-
const state = await registry4.getOrCreate(
|
|
12683
|
+
state = createSessionState();
|
|
12684
|
+
} else {
|
|
12685
|
+
state = await registry4.getOrCreate(
|
|
12830
12686
|
client,
|
|
12831
12687
|
lastUserMessage.info.sessionID,
|
|
12832
12688
|
messages,
|
|
@@ -12883,8 +12739,124 @@ ${text}`);
|
|
|
12883
12739
|
}
|
|
12884
12740
|
);
|
|
12885
12741
|
}
|
|
12886
|
-
|
|
12742
|
+
}
|
|
12743
|
+
syncCompressPermissionState(state, config, hostPermissions, output.messages);
|
|
12744
|
+
if (state.isSubAgent && !config.allowSubAgents) {
|
|
12745
|
+
return;
|
|
12746
|
+
}
|
|
12747
|
+
stripHallucinations(output.messages);
|
|
12748
|
+
const dropReasoningModel = lastUserMessage?.info?.model;
|
|
12749
|
+
const reasoningConfig = applyCompressOverrides(
|
|
12750
|
+
config,
|
|
12751
|
+
dropReasoningModel?.providerID ?? state.modelProviderID,
|
|
12752
|
+
dropReasoningModel?.modelID ?? state.modelID
|
|
12753
|
+
).compress.reasoning;
|
|
12754
|
+
if (reasoningConfig?.drop !== false) {
|
|
12755
|
+
const droppedReasoning = dropCompressReasoning(
|
|
12756
|
+
output.messages,
|
|
12757
|
+
reasoningConfig?.threshold ?? DEFAULT_COMPRESS_REASONING.threshold
|
|
12758
|
+
);
|
|
12759
|
+
if (droppedReasoning > 0) {
|
|
12760
|
+
logger.debug("compress.reasoning: dropped oversized reasoning parts", {
|
|
12761
|
+
dropped: droppedReasoning,
|
|
12762
|
+
threshold: reasoningConfig?.threshold ?? DEFAULT_COMPRESS_REASONING.threshold
|
|
12763
|
+
});
|
|
12764
|
+
}
|
|
12765
|
+
}
|
|
12766
|
+
ensureBuiltinFiltersRegistered();
|
|
12767
|
+
const effectiveLimit = resolveEffectiveContextLimit(state, config);
|
|
12768
|
+
applyMessageFilters(output.messages, config.messageFilters, logger, {
|
|
12769
|
+
sessionId: state.sessionId ?? "",
|
|
12770
|
+
isSubAgent: state.isSubAgent,
|
|
12771
|
+
modelContextLimit: effectiveLimit?.limit
|
|
12887
12772
|
});
|
|
12773
|
+
cacheSystemPromptTokens(state, output.messages);
|
|
12774
|
+
assignMessageRefs(state, output.messages);
|
|
12775
|
+
const activeBlockCountBefore = state.prune.messages.activeBlockIds.size;
|
|
12776
|
+
const compressionStateChanged = syncCompressionBlocks(state, logger, output.messages);
|
|
12777
|
+
if (compressionStateChanged || state.prune.messages.activeBlockIds.size !== activeBlockCountBefore) {
|
|
12778
|
+
saveSessionState(state, logger).catch(() => {
|
|
12779
|
+
});
|
|
12780
|
+
}
|
|
12781
|
+
syncToolCache(state, config, logger, output.messages);
|
|
12782
|
+
buildToolIdList(state, output.messages);
|
|
12783
|
+
const batchResult = runBatchCleanup(state, config, logger, output.messages);
|
|
12784
|
+
if (batchResult.mergedCount > 0) {
|
|
12785
|
+
saveSessionState(state, logger).catch(() => {
|
|
12786
|
+
});
|
|
12787
|
+
}
|
|
12788
|
+
const prePruneTokens = getCurrentTokenUsage(state, output.messages);
|
|
12789
|
+
const candidateMessages = config.compress.candidates === true ? output.messages.slice() : void 0;
|
|
12790
|
+
prune(state, logger, config, output.messages);
|
|
12791
|
+
hideConsumedCompressCalls(state, output.messages);
|
|
12792
|
+
assignMessageRefs(state, output.messages);
|
|
12793
|
+
const compressionPriorities = buildPriorityMap(config, state, output.messages);
|
|
12794
|
+
prompts.reload();
|
|
12795
|
+
injectCompressNudges(
|
|
12796
|
+
state,
|
|
12797
|
+
config,
|
|
12798
|
+
logger,
|
|
12799
|
+
output.messages,
|
|
12800
|
+
prompts.getRuntimePrompts(),
|
|
12801
|
+
compressionPriorities,
|
|
12802
|
+
config.debug ? (text) => {
|
|
12803
|
+
logger.debug(`[ACP Debug] Nudge injected:
|
|
12804
|
+
${text}`);
|
|
12805
|
+
client.tui.showToast({
|
|
12806
|
+
body: {
|
|
12807
|
+
title: "ACP: Nudge Injected",
|
|
12808
|
+
message: text.slice(0, 500),
|
|
12809
|
+
variant: "info",
|
|
12810
|
+
duration: 5e3
|
|
12811
|
+
}
|
|
12812
|
+
}).catch(() => {
|
|
12813
|
+
});
|
|
12814
|
+
} : void 0,
|
|
12815
|
+
prePruneTokens,
|
|
12816
|
+
candidateMessages
|
|
12817
|
+
);
|
|
12818
|
+
truncateLargeToolOutputs(
|
|
12819
|
+
state,
|
|
12820
|
+
config,
|
|
12821
|
+
logger,
|
|
12822
|
+
output.messages.filter((message) => !isSyntheticMessage(message))
|
|
12823
|
+
);
|
|
12824
|
+
enforceContextBudget(state, config, logger, output.messages);
|
|
12825
|
+
injectMessageIds(state, config, output.messages, compressionPriorities);
|
|
12826
|
+
hideFailedCompressCalls(output.messages);
|
|
12827
|
+
stripStaleMetadata(output.messages);
|
|
12828
|
+
dropEmptyMessages(output.messages);
|
|
12829
|
+
const postTokens = getCurrentTokenUsage(state, output.messages);
|
|
12830
|
+
if (postTokens !== void 0 && effectiveLimit) {
|
|
12831
|
+
const budget = effectiveLimit.limit - (state.systemPromptTokens ?? 0) - OUTPUT_RESERVE_TOKENS;
|
|
12832
|
+
if (postTokens > budget) {
|
|
12833
|
+
logger.error(
|
|
12834
|
+
"ACP hard guard: context exceeds model budget after in-flight reduction",
|
|
12835
|
+
{
|
|
12836
|
+
session: state.sessionId,
|
|
12837
|
+
postTokens,
|
|
12838
|
+
budget,
|
|
12839
|
+
contextLimit: effectiveLimit.limit,
|
|
12840
|
+
contextLimitSource: effectiveLimit.source,
|
|
12841
|
+
hint: "request will likely be rejected; run /compact or start a new session"
|
|
12842
|
+
}
|
|
12843
|
+
);
|
|
12844
|
+
}
|
|
12845
|
+
}
|
|
12846
|
+
logger.info("Chat transform complete", {
|
|
12847
|
+
session: state.sessionId,
|
|
12848
|
+
model: state.modelID,
|
|
12849
|
+
messages: output.messages.length,
|
|
12850
|
+
prePruneTokens,
|
|
12851
|
+
postTokens,
|
|
12852
|
+
contextLimit: effectiveLimit?.limit,
|
|
12853
|
+
contextLimitSource: effectiveLimit?.source,
|
|
12854
|
+
usagePct: postTokens !== void 0 && effectiveLimit ? `${(postTokens / effectiveLimit.limit * 100).toFixed(1)}%` : void 0,
|
|
12855
|
+
nudged: state.nudges.shouldInjectThisTurn
|
|
12856
|
+
});
|
|
12857
|
+
if (state.sessionId) {
|
|
12858
|
+
await logger.saveContext(state.sessionId, output.messages);
|
|
12859
|
+
}
|
|
12888
12860
|
};
|
|
12889
12861
|
}
|
|
12890
12862
|
function buildHelpText() {
|
|
@@ -12991,21 +12963,16 @@ function createEventHandler(registry4, logger) {
|
|
|
12991
12963
|
durationMs
|
|
12992
12964
|
});
|
|
12993
12965
|
for (const state of registry4.all()) {
|
|
12994
|
-
|
|
12995
|
-
|
|
12966
|
+
const updates = applyPendingCompressionDurations(state);
|
|
12967
|
+
if (updates > 0) {
|
|
12968
|
+
await saveSessionState(state, logger);
|
|
12969
|
+
logger.info("Attached compression time to blocks", {
|
|
12970
|
+
messageID: part.messageID,
|
|
12971
|
+
callID: part.callID,
|
|
12972
|
+
blocks: updates,
|
|
12973
|
+
durationMs
|
|
12974
|
+
});
|
|
12996
12975
|
}
|
|
12997
|
-
await registry4.withSessionGuard(state.sessionId, async () => {
|
|
12998
|
-
const updates = applyPendingCompressionDurations(state);
|
|
12999
|
-
if (updates > 0) {
|
|
13000
|
-
await saveSessionState(state, logger);
|
|
13001
|
-
logger.info("Attached compression time to blocks", {
|
|
13002
|
-
messageID: part.messageID,
|
|
13003
|
-
callID: part.callID,
|
|
13004
|
-
blocks: updates,
|
|
13005
|
-
durationMs
|
|
13006
|
-
});
|
|
13007
|
-
}
|
|
13008
|
-
});
|
|
13009
12976
|
}
|
|
13010
12977
|
return;
|
|
13011
12978
|
}
|
|
@@ -13290,7 +13257,7 @@ var server = (async (ctx) => {
|
|
|
13290
13257
|
}
|
|
13291
13258
|
const logger = new Logger(config.debug, config.debug ? "debug" : config.logLevel);
|
|
13292
13259
|
logger.info("ACP plugin initialized", {
|
|
13293
|
-
version: true ? "1.18.1-pr.
|
|
13260
|
+
version: true ? "1.18.1-pr.409.165" : "dev",
|
|
13294
13261
|
workspace: ctx.directory,
|
|
13295
13262
|
logLevel: logger.level,
|
|
13296
13263
|
debug: config.debug,
|