opencode-acp 1.0.1 → 1.1.1
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 +27 -12
- package/README.zh-CN.md +357 -0
- package/dist/index.js +199 -102
- package/dist/index.js.map +1 -1
- package/dist/lib/config-validation.d.ts +14 -0
- package/dist/lib/config-validation.d.ts.map +1 -0
- package/dist/lib/config.d.ts +1 -9
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/message-ids.d.ts +1 -1
- 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 +1 -1
- package/dist/lib/messages/inject/utils.d.ts.map +1 -1
- package/dist/lib/messages/query.d.ts +1 -0
- package/dist/lib/messages/query.d.ts.map +1 -1
- package/dist/lib/prompts/compress-message.d.ts +1 -1
- package/dist/lib/prompts/compress-message.d.ts.map +1 -1
- package/dist/lib/prompts/compress-range.d.ts +1 -1
- package/dist/lib/prompts/compress-range.d.ts.map +1 -1
- package/dist/lib/prompts/extensions/tool.d.ts +2 -2
- package/dist/lib/prompts/extensions/tool.d.ts.map +1 -1
- package/dist/lib/state/state.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
|
@@ -862,20 +862,7 @@ var ParseErrorCode;
|
|
|
862
862
|
ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
|
|
863
863
|
})(ParseErrorCode || (ParseErrorCode = {}));
|
|
864
864
|
|
|
865
|
-
// lib/config.ts
|
|
866
|
-
var DEFAULT_PROTECTED_TOOLS = [
|
|
867
|
-
"task",
|
|
868
|
-
"skill",
|
|
869
|
-
"todowrite",
|
|
870
|
-
"todoread",
|
|
871
|
-
"compress",
|
|
872
|
-
"batch",
|
|
873
|
-
"plan_enter",
|
|
874
|
-
"plan_exit",
|
|
875
|
-
"write",
|
|
876
|
-
"edit"
|
|
877
|
-
];
|
|
878
|
-
var COMPRESS_DEFAULT_PROTECTED_TOOLS = ["task", "skill", "todowrite", "todoread"];
|
|
865
|
+
// lib/config-validation.ts
|
|
879
866
|
var VALID_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
880
867
|
"$schema",
|
|
881
868
|
"enabled",
|
|
@@ -1267,7 +1254,7 @@ function validateConfigTypes(config) {
|
|
|
1267
1254
|
}
|
|
1268
1255
|
if (gc.majorGcThresholdPercent !== void 0) {
|
|
1269
1256
|
const isValidNumber = typeof gc.majorGcThresholdPercent === "number";
|
|
1270
|
-
const isPercentString = typeof gc.majorGcThresholdPercent === "string" && gc.majorGcThresholdPercent
|
|
1257
|
+
const isPercentString = typeof gc.majorGcThresholdPercent === "string" && /^\d+(?:\.\d+)?%$/.test(gc.majorGcThresholdPercent);
|
|
1271
1258
|
if (!isValidNumber && !isPercentString) {
|
|
1272
1259
|
errors.push({
|
|
1273
1260
|
key: "gc.majorGcThresholdPercent",
|
|
@@ -1279,54 +1266,97 @@ function validateConfigTypes(config) {
|
|
|
1279
1266
|
}
|
|
1280
1267
|
}
|
|
1281
1268
|
const strategies = config.strategies;
|
|
1282
|
-
if (strategies) {
|
|
1283
|
-
if (strategies
|
|
1269
|
+
if (strategies !== void 0) {
|
|
1270
|
+
if (typeof strategies !== "object" || strategies === null || Array.isArray(strategies)) {
|
|
1284
1271
|
errors.push({
|
|
1285
|
-
key: "strategies
|
|
1286
|
-
expected: "
|
|
1287
|
-
actual: typeof strategies
|
|
1288
|
-
});
|
|
1289
|
-
}
|
|
1290
|
-
if (strategies.deduplication?.protectedTools !== void 0 && !Array.isArray(strategies.deduplication.protectedTools)) {
|
|
1291
|
-
errors.push({
|
|
1292
|
-
key: "strategies.deduplication.protectedTools",
|
|
1293
|
-
expected: "string[]",
|
|
1294
|
-
actual: typeof strategies.deduplication.protectedTools
|
|
1272
|
+
key: "strategies",
|
|
1273
|
+
expected: "object",
|
|
1274
|
+
actual: typeof strategies
|
|
1295
1275
|
});
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
if (
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1276
|
+
} else {
|
|
1277
|
+
const dedup = strategies.deduplication;
|
|
1278
|
+
if (dedup !== void 0) {
|
|
1279
|
+
if (typeof dedup !== "object" || dedup === null || Array.isArray(dedup)) {
|
|
1280
|
+
errors.push({
|
|
1281
|
+
key: "strategies.deduplication",
|
|
1282
|
+
expected: "object",
|
|
1283
|
+
actual: typeof dedup
|
|
1284
|
+
});
|
|
1285
|
+
} else {
|
|
1286
|
+
if (dedup.enabled !== void 0 && typeof dedup.enabled !== "boolean") {
|
|
1287
|
+
errors.push({
|
|
1288
|
+
key: "strategies.deduplication.enabled",
|
|
1289
|
+
expected: "boolean",
|
|
1290
|
+
actual: typeof dedup.enabled
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
if (dedup.protectedTools !== void 0 && !Array.isArray(dedup.protectedTools)) {
|
|
1294
|
+
errors.push({
|
|
1295
|
+
key: "strategies.deduplication.protectedTools",
|
|
1296
|
+
expected: "string[]",
|
|
1297
|
+
actual: typeof dedup.protectedTools
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1318
1301
|
}
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1302
|
+
const purge = strategies.purgeErrors;
|
|
1303
|
+
if (purge !== void 0) {
|
|
1304
|
+
if (typeof purge !== "object" || purge === null || Array.isArray(purge)) {
|
|
1305
|
+
errors.push({
|
|
1306
|
+
key: "strategies.purgeErrors",
|
|
1307
|
+
expected: "object",
|
|
1308
|
+
actual: typeof purge
|
|
1309
|
+
});
|
|
1310
|
+
} else {
|
|
1311
|
+
if (purge.enabled !== void 0 && typeof purge.enabled !== "boolean") {
|
|
1312
|
+
errors.push({
|
|
1313
|
+
key: "strategies.purgeErrors.enabled",
|
|
1314
|
+
expected: "boolean",
|
|
1315
|
+
actual: typeof purge.enabled
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
if (purge.turns !== void 0 && typeof purge.turns !== "number") {
|
|
1319
|
+
errors.push({
|
|
1320
|
+
key: "strategies.purgeErrors.turns",
|
|
1321
|
+
expected: "number",
|
|
1322
|
+
actual: typeof purge.turns
|
|
1323
|
+
});
|
|
1324
|
+
}
|
|
1325
|
+
if (typeof purge.turns === "number" && purge.turns < 1) {
|
|
1326
|
+
errors.push({
|
|
1327
|
+
key: "strategies.purgeErrors.turns",
|
|
1328
|
+
expected: "positive number (>= 1)",
|
|
1329
|
+
actual: `${purge.turns} (will be clamped to 1)`
|
|
1330
|
+
});
|
|
1331
|
+
}
|
|
1332
|
+
if (purge.protectedTools !== void 0 && !Array.isArray(purge.protectedTools)) {
|
|
1333
|
+
errors.push({
|
|
1334
|
+
key: "strategies.purgeErrors.protectedTools",
|
|
1335
|
+
expected: "string[]",
|
|
1336
|
+
actual: typeof purge.protectedTools
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1325
1340
|
}
|
|
1326
1341
|
}
|
|
1327
1342
|
}
|
|
1328
1343
|
return errors;
|
|
1329
1344
|
}
|
|
1345
|
+
|
|
1346
|
+
// lib/config.ts
|
|
1347
|
+
var DEFAULT_PROTECTED_TOOLS = [
|
|
1348
|
+
"task",
|
|
1349
|
+
"skill",
|
|
1350
|
+
"todowrite",
|
|
1351
|
+
"todoread",
|
|
1352
|
+
"compress",
|
|
1353
|
+
"batch",
|
|
1354
|
+
"plan_enter",
|
|
1355
|
+
"plan_exit",
|
|
1356
|
+
"write",
|
|
1357
|
+
"edit"
|
|
1358
|
+
];
|
|
1359
|
+
var COMPRESS_DEFAULT_PROTECTED_TOOLS = ["task", "skill", "todowrite", "todoread"];
|
|
1330
1360
|
function showConfigWarnings(ctx, configPath, configData, isProject) {
|
|
1331
1361
|
const invalidKeys = getInvalidConfigKeys(configData);
|
|
1332
1362
|
const typeErrors = validateConfigTypes(configData);
|
|
@@ -1389,10 +1419,10 @@ var defaultConfig = {
|
|
|
1389
1419
|
compress: {
|
|
1390
1420
|
mode: "range",
|
|
1391
1421
|
permission: "allow",
|
|
1392
|
-
showCompression:
|
|
1422
|
+
showCompression: true,
|
|
1393
1423
|
summaryBuffer: true,
|
|
1394
|
-
maxContextLimit:
|
|
1395
|
-
minContextLimit:
|
|
1424
|
+
maxContextLimit: "55%",
|
|
1425
|
+
minContextLimit: "45%",
|
|
1396
1426
|
nudgeFrequency: 5,
|
|
1397
1427
|
iterationNudgeThreshold: 15,
|
|
1398
1428
|
nudgeForce: "soft",
|
|
@@ -1416,7 +1446,7 @@ var defaultConfig = {
|
|
|
1416
1446
|
promotionThreshold: 5,
|
|
1417
1447
|
maxBlockAge: 15,
|
|
1418
1448
|
maxOldGenSummaryLength: 3e3,
|
|
1419
|
-
majorGcThresholdPercent: "
|
|
1449
|
+
majorGcThresholdPercent: "100%"
|
|
1420
1450
|
}
|
|
1421
1451
|
};
|
|
1422
1452
|
var GLOBAL_CONFIG_DIR = process.env.XDG_CONFIG_HOME ? join(process.env.XDG_CONFIG_HOME, "opencode") : join(homedir(), ".config", "opencode");
|
|
@@ -1728,6 +1758,10 @@ function filterMessagesInPlace(messages) {
|
|
|
1728
1758
|
}
|
|
1729
1759
|
|
|
1730
1760
|
// lib/messages/query.ts
|
|
1761
|
+
function isSyntheticMessage(message) {
|
|
1762
|
+
const id = message?.info?.id;
|
|
1763
|
+
return typeof id === "string" && (id.startsWith("msg_dcp_summary_") || id.startsWith("msg_dcp_text_"));
|
|
1764
|
+
}
|
|
1731
1765
|
var getLastUserMessage = (messages, startIndex) => {
|
|
1732
1766
|
const start = startIndex ?? messages.length - 1;
|
|
1733
1767
|
for (let i = start; i >= 0; i--) {
|
|
@@ -1735,7 +1769,7 @@ var getLastUserMessage = (messages, startIndex) => {
|
|
|
1735
1769
|
if (!isMessageWithInfo(msg)) {
|
|
1736
1770
|
continue;
|
|
1737
1771
|
}
|
|
1738
|
-
if (msg.info.role === "user" && !isIgnoredUserMessage(msg)) {
|
|
1772
|
+
if (msg.info.role === "user" && !isIgnoredUserMessage(msg) && !isSyntheticMessage(msg)) {
|
|
1739
1773
|
return msg;
|
|
1740
1774
|
}
|
|
1741
1775
|
}
|
|
@@ -1901,8 +1935,8 @@ THE FORMAT OF COMPRESS
|
|
|
1901
1935
|
topic: string, // Short label (3-5 words) - e.g., "Auth System Exploration"
|
|
1902
1936
|
content: [ // One or more ranges to compress
|
|
1903
1937
|
{
|
|
1904
|
-
startId: string, // Boundary ID at range start:
|
|
1905
|
-
endId: string, // Boundary ID at range end:
|
|
1938
|
+
startId: string, // Boundary ID at range start: mNNNNN or bN
|
|
1939
|
+
endId: string, // Boundary ID at range end: mNNNNN or bN
|
|
1906
1940
|
summary: string // Complete technical summary replacing all content in range
|
|
1907
1941
|
}
|
|
1908
1942
|
]
|
|
@@ -1916,7 +1950,7 @@ THE FORMAT OF COMPRESS
|
|
|
1916
1950
|
topic: string, // Short label (3-5 words) for the overall batch
|
|
1917
1951
|
content: [ // One or more messages to compress independently
|
|
1918
1952
|
{
|
|
1919
|
-
messageId: string, // Raw message ID only:
|
|
1953
|
+
messageId: string, // Raw message ID only: mNNNNN (ignore metadata attributes like priority)
|
|
1920
1954
|
topic: string, // Short label (3-5 words) for this one message summary
|
|
1921
1955
|
summary: string // Complete technical summary replacing that one message
|
|
1922
1956
|
}
|
|
@@ -1925,16 +1959,16 @@ THE FORMAT OF COMPRESS
|
|
|
1925
1959
|
\`\`\``;
|
|
1926
1960
|
|
|
1927
1961
|
// lib/message-ids.ts
|
|
1928
|
-
var MESSAGE_REF_REGEX = /^m(\d{4})$/;
|
|
1962
|
+
var MESSAGE_REF_REGEX = /^m(\d{4,5})$/;
|
|
1929
1963
|
var BLOCK_REF_REGEX = /^b([1-9]\d*)$/;
|
|
1930
1964
|
var MESSAGE_ID_TAG_NAME = "dcp-message-id";
|
|
1931
|
-
var MESSAGE_REF_WIDTH =
|
|
1965
|
+
var MESSAGE_REF_WIDTH = 5;
|
|
1932
1966
|
var MESSAGE_REF_MIN_INDEX = 1;
|
|
1933
|
-
var MESSAGE_REF_MAX_INDEX =
|
|
1967
|
+
var MESSAGE_REF_MAX_INDEX = 99999;
|
|
1934
1968
|
function formatMessageRef(index) {
|
|
1935
1969
|
if (!Number.isInteger(index) || index < MESSAGE_REF_MIN_INDEX || index > MESSAGE_REF_MAX_INDEX) {
|
|
1936
1970
|
throw new Error(
|
|
1937
|
-
`Message ID index out of bounds: ${index}. Supported range is
|
|
1971
|
+
`Message ID index out of bounds: ${index}. Supported range is ${MESSAGE_REF_MIN_INDEX}-${MESSAGE_REF_MAX_INDEX}.`
|
|
1938
1972
|
);
|
|
1939
1973
|
}
|
|
1940
1974
|
return `m${index.toString().padStart(MESSAGE_REF_WIDTH, "0")}`;
|
|
@@ -2089,10 +2123,10 @@ function resolveBoundaryIds(context, state, startId, endId) {
|
|
|
2089
2123
|
const parsedStartId = parseBoundaryId(startId);
|
|
2090
2124
|
const parsedEndId = parseBoundaryId(endId);
|
|
2091
2125
|
if (parsedStartId === null) {
|
|
2092
|
-
issues.push("startId is invalid. Use an injected message ID (
|
|
2126
|
+
issues.push("startId is invalid. Use an injected message ID (mNNNNN) or block ID (bN).");
|
|
2093
2127
|
}
|
|
2094
2128
|
if (parsedEndId === null) {
|
|
2095
|
-
issues.push("endId is invalid. Use an injected message ID (
|
|
2129
|
+
issues.push("endId is invalid. Use an injected message ID (mNNNNN) or block ID (bN).");
|
|
2096
2130
|
}
|
|
2097
2131
|
if (issues.length > 0) {
|
|
2098
2132
|
throw new Error(
|
|
@@ -2547,16 +2581,16 @@ var ISSUE_TEMPLATES = {
|
|
|
2547
2581
|
"refer to protected messages and cannot be compressed."
|
|
2548
2582
|
],
|
|
2549
2583
|
"invalid-format": [
|
|
2550
|
-
"is invalid. Use an injected raw message ID of the form
|
|
2551
|
-
"are invalid. Use injected raw message IDs of the form
|
|
2584
|
+
"is invalid. Use an injected raw message ID of the form mNNNNN.",
|
|
2585
|
+
"are invalid. Use injected raw message IDs of the form mNNNNN."
|
|
2552
2586
|
],
|
|
2553
2587
|
"block-id": [
|
|
2554
|
-
"is invalid here. Block IDs like bN are not allowed; use an
|
|
2555
|
-
"are invalid here. Block IDs like bN are not allowed; use
|
|
2588
|
+
"is invalid here. Block IDs like bN are not allowed; use an mNNNNN message ID instead.",
|
|
2589
|
+
"are invalid here. Block IDs like bN are not allowed; use mNNNNN message IDs instead."
|
|
2556
2590
|
],
|
|
2557
2591
|
"not-in-context": [
|
|
2558
|
-
"is not available in the current conversation context. Choose an injected
|
|
2559
|
-
"are not available in the current conversation context. Choose injected
|
|
2592
|
+
"is not available in the current conversation context. Choose an injected mNNNNN ID visible in context.",
|
|
2593
|
+
"are not available in the current conversation context. Choose injected mNNNNN IDs visible in context."
|
|
2560
2594
|
],
|
|
2561
2595
|
protected: [
|
|
2562
2596
|
"refers to a protected message and cannot be compressed.",
|
|
@@ -2923,6 +2957,11 @@ function resetOnCompaction(state) {
|
|
|
2923
2957
|
turnNudgeAnchors: /* @__PURE__ */ new Set(),
|
|
2924
2958
|
iterationNudgeAnchors: /* @__PURE__ */ new Set()
|
|
2925
2959
|
};
|
|
2960
|
+
state.messageIds = {
|
|
2961
|
+
byRawId: /* @__PURE__ */ new Map(),
|
|
2962
|
+
byRef: /* @__PURE__ */ new Map(),
|
|
2963
|
+
nextRef: 1
|
|
2964
|
+
};
|
|
2926
2965
|
}
|
|
2927
2966
|
|
|
2928
2967
|
// lib/state/persistence.ts
|
|
@@ -3295,6 +3334,17 @@ async function ensureSessionInitialized(client, state, sessionId, logger, messag
|
|
|
3295
3334
|
state.messageIds.byRef.delete(ref);
|
|
3296
3335
|
}
|
|
3297
3336
|
}
|
|
3337
|
+
for (const [rawId, oldRef] of state.messageIds.byRawId) {
|
|
3338
|
+
const parsed = parseMessageRef(oldRef);
|
|
3339
|
+
if (parsed !== null) {
|
|
3340
|
+
const newRef = formatMessageRef(parsed);
|
|
3341
|
+
if (newRef !== oldRef) {
|
|
3342
|
+
state.messageIds.byRawId.set(rawId, newRef);
|
|
3343
|
+
state.messageIds.byRef.delete(oldRef);
|
|
3344
|
+
state.messageIds.byRef.set(newRef, rawId);
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3298
3348
|
}
|
|
3299
3349
|
if (persistedAny._persistedLastCompaction !== void 0) {
|
|
3300
3350
|
state.lastCompaction = Math.max(state.lastCompaction, persistedAny._persistedLastCompaction);
|
|
@@ -4284,7 +4334,7 @@ function buildSchema() {
|
|
|
4284
4334
|
),
|
|
4285
4335
|
content: tool.schema.array(
|
|
4286
4336
|
tool.schema.object({
|
|
4287
|
-
messageId: tool.schema.string().describe("Raw message ID to compress (e.g.
|
|
4337
|
+
messageId: tool.schema.string().describe("Raw message ID to compress (e.g. m00001)"),
|
|
4288
4338
|
topic: tool.schema.string().describe("Short label (3-5 words) for this one message summary"),
|
|
4289
4339
|
summary: tool.schema.string().describe("Complete technical summary replacing that one message")
|
|
4290
4340
|
})
|
|
@@ -4521,9 +4571,9 @@ function buildSchema2() {
|
|
|
4521
4571
|
content: tool2.schema.array(
|
|
4522
4572
|
tool2.schema.object({
|
|
4523
4573
|
startId: tool2.schema.string().describe(
|
|
4524
|
-
"Message or block ID marking the beginning of range (e.g.
|
|
4574
|
+
"Message or block ID marking the beginning of range (e.g. m00001, b2)"
|
|
4525
4575
|
),
|
|
4526
|
-
endId: tool2.schema.string().describe("Message or block ID marking the end of range (e.g.
|
|
4576
|
+
endId: tool2.schema.string().describe("Message or block ID marking the end of range (e.g. m00012, b5)"),
|
|
4527
4577
|
summary: tool2.schema.string().describe("Complete technical summary replacing all content in range")
|
|
4528
4578
|
})
|
|
4529
4579
|
).describe(
|
|
@@ -4978,7 +5028,7 @@ Compressed block sections in context are clearly marked with a header:
|
|
|
4978
5028
|
|
|
4979
5029
|
- \`[Compressed conversation section]\`
|
|
4980
5030
|
|
|
4981
|
-
Compressed block IDs always use the \`bN\` form (never \`
|
|
5031
|
+
Compressed block IDs always use the \`bN\` form (never \`mNNNNN\`) and are represented in the same XML metadata tag format.
|
|
4982
5032
|
|
|
4983
5033
|
Rules:
|
|
4984
5034
|
|
|
@@ -5001,7 +5051,7 @@ When you use compressed block placeholders, write the surrounding summary text s
|
|
|
5001
5051
|
BOUNDARY IDS
|
|
5002
5052
|
You specify boundaries by ID using the injected IDs visible in the conversation:
|
|
5003
5053
|
|
|
5004
|
-
- \`
|
|
5054
|
+
- \`mNNNNN\` IDs identify raw messages
|
|
5005
5055
|
- \`bN\` IDs identify previously compressed blocks
|
|
5006
5056
|
|
|
5007
5057
|
Each message has an ID inside XML metadata tags like \`<dcp-message-id>...</dcp-message-id>\`.
|
|
@@ -5036,11 +5086,11 @@ If a message contains no significant technical decisions, code changes, or user
|
|
|
5036
5086
|
MESSAGE IDS
|
|
5037
5087
|
You specify individual raw messages by ID using the injected IDs visible in the conversation:
|
|
5038
5088
|
|
|
5039
|
-
- \`
|
|
5089
|
+
- \`mNNNNN\` IDs identify raw messages
|
|
5040
5090
|
|
|
5041
5091
|
Each message has an ID inside XML metadata tags like \`<dcp-message-id priority="high">m0007</dcp-message-id>\`.
|
|
5042
5092
|
The same ID tag appears in every tool output of the message it belongs to \u2014 each unique ID identifies one complete message.
|
|
5043
|
-
Treat these tags as message metadata only, not as content to summarize. Use only the inner \`
|
|
5093
|
+
Treat these tags as message metadata only, not as content to summarize. Use only the inner \`mNNNNN\` value as the \`messageId\`.
|
|
5044
5094
|
The \`priority\` attribute indicates relative context cost. You MUST compress high-priority messages when their full text is no longer necessary for the active task.
|
|
5045
5095
|
If prior compress-tool results are present, always compress and summarize them minimally only as part of a broader compression pass. Do not invoke the compress tool solely to re-compress an earlier compression result.
|
|
5046
5096
|
Messages marked as \`<dcp-message-id>BLOCKED</dcp-message-id>\` cannot be compressed.
|
|
@@ -5048,8 +5098,8 @@ Messages marked as \`<dcp-message-id>BLOCKED</dcp-message-id>\` cannot be compre
|
|
|
5048
5098
|
Rules:
|
|
5049
5099
|
|
|
5050
5100
|
- Pick each \`messageId\` directly from injected IDs visible in context.
|
|
5051
|
-
- Only use raw message IDs of the form \`
|
|
5052
|
-
- Ignore XML attributes such as \`priority\` when copying the ID; use only the inner \`
|
|
5101
|
+
- Only use raw message IDs of the form \`mNNNNN\`.
|
|
5102
|
+
- Ignore XML attributes such as \`priority\` when copying the ID; use only the inner \`mNNNNN\` value.
|
|
5053
5103
|
- Do not invent IDs. Use only IDs that are present in context.
|
|
5054
5104
|
|
|
5055
5105
|
BATCHING
|
|
@@ -6052,6 +6102,9 @@ function findLastNonIgnoredMessage(messages) {
|
|
|
6052
6102
|
if (isIgnoredUserMessage(message)) {
|
|
6053
6103
|
continue;
|
|
6054
6104
|
}
|
|
6105
|
+
if (isSyntheticMessage(message)) {
|
|
6106
|
+
continue;
|
|
6107
|
+
}
|
|
6055
6108
|
return { message, index: i };
|
|
6056
6109
|
}
|
|
6057
6110
|
return null;
|
|
@@ -6262,10 +6315,48 @@ function buildContextUsageInfo(currentTokens, modelContextLimit) {
|
|
|
6262
6315
|
|
|
6263
6316
|
Context usage: ${formatK(currentTokens)} / ${formatK(modelContextLimit)} tokens (${percentage}%). ACP (Active Context Pruning) threshold: 55%. You ARE the ACP agent \u2014 use the compress tool proactively to manage context quality.`;
|
|
6264
6317
|
}
|
|
6265
|
-
function applyAnchoredNudges(state, config, messages, prompts, compressionPriorities, currentTokens, modelContextLimit) {
|
|
6318
|
+
function applyAnchoredNudges(state, config, messages, prompts, compressionPriorities, currentTokens, modelContextLimit, suffixMessage) {
|
|
6266
6319
|
const contextUsageInfo = buildContextUsageInfo(currentTokens, modelContextLimit);
|
|
6267
6320
|
const contextLimitNudgeWithUsage = prompts.contextLimitNudge + contextUsageInfo;
|
|
6268
6321
|
const turnNudgeAnchors = collectTurnNudgeAnchors2(state, config, messages);
|
|
6322
|
+
if (suffixMessage) {
|
|
6323
|
+
const nudgeParts = [];
|
|
6324
|
+
if (config.compress.mode === "message") {
|
|
6325
|
+
if (state.nudges.contextLimitAnchors.size > 0) {
|
|
6326
|
+
for (const { index } of collectAnchoredMessages(state.nudges.contextLimitAnchors, messages)) {
|
|
6327
|
+
const guidance = buildMessagePriorityGuidance(messages, compressionPriorities, index, MESSAGE_MODE_NUDGE_PRIORITY);
|
|
6328
|
+
nudgeParts.push(appendGuidanceToDcpTag(contextLimitNudgeWithUsage, guidance));
|
|
6329
|
+
}
|
|
6330
|
+
}
|
|
6331
|
+
if (turnNudgeAnchors.size > 0) {
|
|
6332
|
+
for (const { index } of collectAnchoredMessages(turnNudgeAnchors, messages)) {
|
|
6333
|
+
const guidance = buildMessagePriorityGuidance(messages, compressionPriorities, index, MESSAGE_MODE_NUDGE_PRIORITY);
|
|
6334
|
+
nudgeParts.push(appendGuidanceToDcpTag(prompts.turnNudge, guidance));
|
|
6335
|
+
}
|
|
6336
|
+
}
|
|
6337
|
+
if (state.nudges.iterationNudgeAnchors.size > 0) {
|
|
6338
|
+
for (const { index } of collectAnchoredMessages(state.nudges.iterationNudgeAnchors, messages)) {
|
|
6339
|
+
const guidance = buildMessagePriorityGuidance(messages, compressionPriorities, index, MESSAGE_MODE_NUDGE_PRIORITY);
|
|
6340
|
+
nudgeParts.push(appendGuidanceToDcpTag(prompts.iterationNudge, guidance));
|
|
6341
|
+
}
|
|
6342
|
+
}
|
|
6343
|
+
} else {
|
|
6344
|
+
if (state.nudges.contextLimitAnchors.size > 0) {
|
|
6345
|
+
nudgeParts.push(contextLimitNudgeWithUsage);
|
|
6346
|
+
}
|
|
6347
|
+
if (turnNudgeAnchors.size > 0) {
|
|
6348
|
+
nudgeParts.push(prompts.turnNudge);
|
|
6349
|
+
}
|
|
6350
|
+
if (state.nudges.iterationNudgeAnchors.size > 0) {
|
|
6351
|
+
nudgeParts.push(prompts.iterationNudge);
|
|
6352
|
+
}
|
|
6353
|
+
}
|
|
6354
|
+
const combined = nudgeParts.join("\n\n");
|
|
6355
|
+
if (combined.trim()) {
|
|
6356
|
+
injectAnchoredNudge(suffixMessage, combined);
|
|
6357
|
+
}
|
|
6358
|
+
return;
|
|
6359
|
+
}
|
|
6269
6360
|
if (config.compress.mode === "message") {
|
|
6270
6361
|
applyMessageModeAnchoredNudge(
|
|
6271
6362
|
state.nudges.contextLimitAnchors,
|
|
@@ -6308,6 +6399,14 @@ function applyAnchoredNudges(state, config, messages, prompts, compressionPriori
|
|
|
6308
6399
|
}
|
|
6309
6400
|
|
|
6310
6401
|
// lib/messages/inject/inject.ts
|
|
6402
|
+
var ACP_SUFFIX_SEED = "acp-dynamic-guidance";
|
|
6403
|
+
function createSuffixMessage(messages) {
|
|
6404
|
+
if (messages.length === 0) return null;
|
|
6405
|
+
const base = messages.find((m) => m.info.role === "user") || messages[messages.length - 1];
|
|
6406
|
+
const synthetic = createSyntheticUserMessage(base, "", ACP_SUFFIX_SEED);
|
|
6407
|
+
messages.push(synthetic);
|
|
6408
|
+
return synthetic;
|
|
6409
|
+
}
|
|
6311
6410
|
var injectCompressNudges = (state, config, logger, messages, prompts, compressionPriorities) => {
|
|
6312
6411
|
if (compressPermission(state, config) === "deny") {
|
|
6313
6412
|
return;
|
|
@@ -6390,40 +6489,40 @@ var injectCompressNudges = (state, config, logger, messages, prompts, compressio
|
|
|
6390
6489
|
}
|
|
6391
6490
|
}
|
|
6392
6491
|
}
|
|
6393
|
-
|
|
6394
|
-
|
|
6492
|
+
const suffixMessage = createSuffixMessage(messages);
|
|
6493
|
+
applyAnchoredNudges(state, config, messages, prompts, compressionPriorities, currentTokens, modelContextLimit, suffixMessage);
|
|
6494
|
+
injectContextUsage(suffixMessage, currentTokens, modelContextLimit);
|
|
6395
6495
|
if (config.compress.mode !== "message") {
|
|
6396
6496
|
const blockGuidance = buildCompressedBlockGuidance(state, config.gc, { currentTokens, modelContextLimit });
|
|
6397
|
-
if (blockGuidance.trim()) {
|
|
6398
|
-
|
|
6399
|
-
if (lastUser) appendToLastTextPart(lastUser, "\n\n" + blockGuidance);
|
|
6497
|
+
if (blockGuidance.trim() && suffixMessage) {
|
|
6498
|
+
appendToLastTextPart(suffixMessage, "\n\n" + blockGuidance);
|
|
6400
6499
|
}
|
|
6401
6500
|
}
|
|
6402
|
-
injectVisibleIdRange(state, messages);
|
|
6501
|
+
injectVisibleIdRange(state, messages, suffixMessage);
|
|
6403
6502
|
if (anchorsChanged) {
|
|
6404
6503
|
void saveSessionState(state, logger);
|
|
6405
6504
|
}
|
|
6406
6505
|
};
|
|
6407
|
-
function injectContextUsage(
|
|
6506
|
+
function injectContextUsage(target, currentTokens, modelContextLimit) {
|
|
6507
|
+
if (!target) return;
|
|
6408
6508
|
if (currentTokens === void 0 || modelContextLimit === void 0 || modelContextLimit === 0) {
|
|
6409
6509
|
return;
|
|
6410
6510
|
}
|
|
6411
|
-
const lastUser = getLastUserMessage(messages);
|
|
6412
|
-
if (!lastUser) return;
|
|
6413
6511
|
const percentage = (currentTokens / modelContextLimit * 100).toFixed(1);
|
|
6414
6512
|
const formatK = (n) => n >= 1e3 ? `${(n / 1e3).toFixed(1)}K` : String(n);
|
|
6415
6513
|
const usageTag = `
|
|
6416
6514
|
|
|
6417
6515
|
Context usage: ${formatK(currentTokens)} / ${formatK(modelContextLimit)} tokens (${percentage}%). ACP (Active Context Pruning) threshold: 55%. You ARE the ACP agent \u2014 use the compress tool proactively to manage context quality.`;
|
|
6418
|
-
for (const part of
|
|
6516
|
+
for (const part of target.parts) {
|
|
6419
6517
|
if (part.type === "text") {
|
|
6420
6518
|
appendToTextPart(part, usageTag);
|
|
6421
6519
|
return;
|
|
6422
6520
|
}
|
|
6423
6521
|
}
|
|
6424
|
-
|
|
6522
|
+
target.parts.push(createSyntheticTextPart(target, usageTag));
|
|
6425
6523
|
}
|
|
6426
|
-
function injectVisibleIdRange(state, messages) {
|
|
6524
|
+
function injectVisibleIdRange(state, messages, target) {
|
|
6525
|
+
if (!target) return;
|
|
6427
6526
|
const visibleRefs = [];
|
|
6428
6527
|
for (const message of messages) {
|
|
6429
6528
|
const ref = state.messageIds.byRawId.get(message.info.id);
|
|
@@ -6438,15 +6537,13 @@ function injectVisibleIdRange(state, messages) {
|
|
|
6438
6537
|
const rangeTag = `
|
|
6439
6538
|
|
|
6440
6539
|
[Visible message IDs: ${first} to ${last} (${visibleRefs.length} messages). Only use IDs in this range for compress.]`;
|
|
6441
|
-
const
|
|
6442
|
-
if (!lastUser) return;
|
|
6443
|
-
for (const part of lastUser.parts) {
|
|
6540
|
+
for (const part of target.parts) {
|
|
6444
6541
|
if (part.type === "text") {
|
|
6445
6542
|
appendToTextPart(part, rangeTag);
|
|
6446
6543
|
return;
|
|
6447
6544
|
}
|
|
6448
6545
|
}
|
|
6449
|
-
|
|
6546
|
+
target.parts.push(createSyntheticTextPart(target, rangeTag));
|
|
6450
6547
|
}
|
|
6451
6548
|
var injectMessageIds = (state, config, messages, compressionPriorities) => {
|
|
6452
6549
|
if (compressPermission(state, config) === "deny") {
|
|
@@ -8056,7 +8153,7 @@ function configureClientAuth(client) {
|
|
|
8056
8153
|
import { readFile as readFile2, rm } from "fs/promises";
|
|
8057
8154
|
import { basename, dirname as dirname3, join as join5 } from "path";
|
|
8058
8155
|
import { fileURLToPath } from "url";
|
|
8059
|
-
var PACKAGE_NAME = "
|
|
8156
|
+
var PACKAGE_NAME = "opencode-acp";
|
|
8060
8157
|
function startAutoUpdate(ctx, enabled) {
|
|
8061
8158
|
if (!enabled) return;
|
|
8062
8159
|
const controller = new AbortController();
|