@lazyingart/agintiflow 0.20.245 → 0.20.247
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/package.json +1 -1
- package/scripts/smoke-context-budget-recovery.js +150 -0
- package/src/agent-runner.js +126 -37
- package/src/scs-evidence.js +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.247",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -51,6 +51,25 @@ const artifactContract = deriveScsTaskContract({
|
|
|
51
51
|
taskProfile: "chatops",
|
|
52
52
|
});
|
|
53
53
|
assert.equal(artifactContract.requiresExternalEvidence, true, "real chat artifact work lost its evidence gate");
|
|
54
|
+
const retainedReportContract = deriveScsTaskContract({
|
|
55
|
+
goal: [
|
|
56
|
+
"The completed evidence is already saved in tmp/reliability-evidence-pass.md and must remain read-only.",
|
|
57
|
+
"Read only missing bounded ranges of tmp/reliability-evidence-pass.md.",
|
|
58
|
+
"Rewrite agent-reliability-evidence-review.md as a concise decision document.",
|
|
59
|
+
"Rebuild sources.json so it contains only cited sources.",
|
|
60
|
+
].join("\n"),
|
|
61
|
+
taskProfile: "research",
|
|
62
|
+
});
|
|
63
|
+
assert.deepEqual(
|
|
64
|
+
retainedReportContract.exactOutputPaths,
|
|
65
|
+
["agent-reliability-evidence-review.md", "sources.json"],
|
|
66
|
+
"report continuation confused an existing saved input with rewrite/rebuild outputs"
|
|
67
|
+
);
|
|
68
|
+
assert.deepEqual(
|
|
69
|
+
retainedReportContract.exactInputPaths,
|
|
70
|
+
["tmp/reliability-evidence-pass.md"],
|
|
71
|
+
"report continuation lost the read-only evidence input"
|
|
72
|
+
);
|
|
54
73
|
assert.ok(artifactContract.requiredEvidence.some((item) => item.category === "artifact"));
|
|
55
74
|
const scopedArtifactRootContract = deriveScsTaskContract({
|
|
56
75
|
goal:
|
|
@@ -322,4 +341,135 @@ assert.ok(
|
|
|
322
341
|
"DeepSeek runtime compaction exceeded the bounded retry target"
|
|
323
342
|
);
|
|
324
343
|
|
|
344
|
+
function noisyFullReadPair(index, generation) {
|
|
345
|
+
const id = `validator-${generation}-${index}`;
|
|
346
|
+
const file = `tmp/validator-${generation}-${index}.py`;
|
|
347
|
+
return [
|
|
348
|
+
{
|
|
349
|
+
role: "assistant",
|
|
350
|
+
content: "",
|
|
351
|
+
reasoning_content: "Inspect the latest validator.",
|
|
352
|
+
tool_calls: [
|
|
353
|
+
{
|
|
354
|
+
id,
|
|
355
|
+
type: "function",
|
|
356
|
+
function: { name: "read_file", arguments: JSON.stringify({ path: file }) },
|
|
357
|
+
},
|
|
358
|
+
],
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
role: "tool",
|
|
362
|
+
tool_call_id: id,
|
|
363
|
+
content: JSON.stringify({
|
|
364
|
+
ok: true,
|
|
365
|
+
toolName: "read_file",
|
|
366
|
+
path: file,
|
|
367
|
+
bytes: 4096,
|
|
368
|
+
lineCount: 120,
|
|
369
|
+
sha256: `${generation}${String(index).padStart(2, "0")}`.repeat(24).slice(0, 64),
|
|
370
|
+
contentTruncated: false,
|
|
371
|
+
content: `VALIDATOR-${generation}-${index}\n${"broad validator content ".repeat(150)}`,
|
|
372
|
+
}),
|
|
373
|
+
},
|
|
374
|
+
];
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function boundedOutputReadPair(index, generation) {
|
|
378
|
+
const id = `output-${generation}-${index}`;
|
|
379
|
+
return [
|
|
380
|
+
{
|
|
381
|
+
role: "assistant",
|
|
382
|
+
content: "",
|
|
383
|
+
reasoning_content: "Inspect the existing mutable output.",
|
|
384
|
+
tool_calls: [
|
|
385
|
+
{
|
|
386
|
+
id,
|
|
387
|
+
type: "function",
|
|
388
|
+
function: {
|
|
389
|
+
name: "read_file",
|
|
390
|
+
arguments: JSON.stringify({
|
|
391
|
+
path: "agent-reliability-evidence-review.md",
|
|
392
|
+
startLine: 1 + (index - 1) * 40,
|
|
393
|
+
lineLimit: 40,
|
|
394
|
+
}),
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
],
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
role: "tool",
|
|
401
|
+
tool_call_id: id,
|
|
402
|
+
content: JSON.stringify({
|
|
403
|
+
ok: true,
|
|
404
|
+
toolName: "read_file",
|
|
405
|
+
path: "agent-reliability-evidence-review.md",
|
|
406
|
+
startLine: 1 + (index - 1) * 40,
|
|
407
|
+
lineLimit: 40,
|
|
408
|
+
lineCount: 240,
|
|
409
|
+
bytes: 24000,
|
|
410
|
+
sha256: `${generation}${String(index).padStart(2, "0")}`.repeat(24).slice(0, 64),
|
|
411
|
+
contentTruncated: false,
|
|
412
|
+
content: `MUTABLE-OUTPUT-${generation}-${index}\n${"old output content ".repeat(170)}`,
|
|
413
|
+
}),
|
|
414
|
+
},
|
|
415
|
+
];
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const twiceCompactedState = {
|
|
419
|
+
...compactionState,
|
|
420
|
+
meta: {
|
|
421
|
+
scs: {
|
|
422
|
+
taskContract: {
|
|
423
|
+
exactOutputPaths: ["agent-reliability-evidence-review.md", "sources.json"],
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
messages: [
|
|
428
|
+
...deepSeekRuntimeMessages,
|
|
429
|
+
...Array.from({ length: 14 }, (_, index) => noisyFullReadPair(index + 1, 2)).flat(),
|
|
430
|
+
...Array.from({ length: 6 }, (_, index) => boundedOutputReadPair(index + 1, 2)).flat(),
|
|
431
|
+
],
|
|
432
|
+
};
|
|
433
|
+
const twiceCompacted = buildContextBudgetCompactionMessages(
|
|
434
|
+
twiceCompactedState,
|
|
435
|
+
{ ...config, provider: "deepseek", model: "deepseek-chat" },
|
|
436
|
+
{ title: "", url: "" },
|
|
437
|
+
8,
|
|
438
|
+
{ reason: "second DeepSeek compaction" }
|
|
439
|
+
);
|
|
440
|
+
const twiceCompactedText = twiceCompacted.map((message) => message.content || "").join("\n");
|
|
441
|
+
assert.ok(twiceCompactedText.includes("reliability-evidence-v14"));
|
|
442
|
+
assert.ok(twiceCompactedText.includes("EVIDENCE-CHUNK-ONE"));
|
|
443
|
+
assert.ok(twiceCompactedText.includes("EVIDENCE-CHUNK-TWO"));
|
|
444
|
+
assert.equal(
|
|
445
|
+
(twiceCompactedText.match(/Tool: deep_research/g) || []).length,
|
|
446
|
+
1,
|
|
447
|
+
"second DeepSeek compaction duplicated the completed research record"
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
const thriceCompactedState = {
|
|
451
|
+
...compactionState,
|
|
452
|
+
meta: twiceCompactedState.meta,
|
|
453
|
+
messages: [
|
|
454
|
+
...twiceCompacted,
|
|
455
|
+
...Array.from({ length: 14 }, (_, index) => noisyFullReadPair(index + 1, 3)).flat(),
|
|
456
|
+
...Array.from({ length: 6 }, (_, index) => boundedOutputReadPair(index + 1, 3)).flat(),
|
|
457
|
+
],
|
|
458
|
+
};
|
|
459
|
+
const thriceCompacted = buildContextBudgetCompactionMessages(
|
|
460
|
+
thriceCompactedState,
|
|
461
|
+
{ ...config, provider: "deepseek", model: "deepseek-chat" },
|
|
462
|
+
{ title: "", url: "" },
|
|
463
|
+
12,
|
|
464
|
+
{ reason: "third DeepSeek compaction" }
|
|
465
|
+
);
|
|
466
|
+
const thriceCompactedText = thriceCompacted.map((message) => message.content || "").join("\n");
|
|
467
|
+
assert.ok(thriceCompactedText.includes("reliability-evidence-v14"));
|
|
468
|
+
assert.ok(thriceCompactedText.includes("EVIDENCE-CHUNK-ONE"));
|
|
469
|
+
assert.ok(thriceCompactedText.includes("EVIDENCE-CHUNK-TWO"));
|
|
470
|
+
assert.ok(
|
|
471
|
+
estimateMessageTokens(thriceCompacted) <= 12288,
|
|
472
|
+
"cumulative DeepSeek compaction exceeded the bounded retry target"
|
|
473
|
+
);
|
|
474
|
+
|
|
325
475
|
console.log("context budget recovery smoke passed");
|
package/src/agent-runner.js
CHANGED
|
@@ -838,19 +838,38 @@ function retainedReadRange(payload = {}, args = {}) {
|
|
|
838
838
|
};
|
|
839
839
|
}
|
|
840
840
|
|
|
841
|
+
function parseRetainedToolEvidenceMessage(message = {}) {
|
|
842
|
+
if (message?.role !== "user") return null;
|
|
843
|
+
const content = String(message.content || "");
|
|
844
|
+
if (!/^Retained runtime tool evidence\./i.test(content.trim())) return null;
|
|
845
|
+
const match = content.match(
|
|
846
|
+
/^Retained runtime tool evidence\.[^\n]*\nTool:\s*([^\n]+)\nArguments:\s*([^\n]+)\nVerified result:\s*([\s\S]+)$/i
|
|
847
|
+
);
|
|
848
|
+
if (!match) return null;
|
|
849
|
+
const name = String(match[1] || "").trim();
|
|
850
|
+
const args = safeParseToolContent(match[2]) || {};
|
|
851
|
+
const payload = safeParseToolContent(match[3]);
|
|
852
|
+
if (!name || !COMPACTION_STATE_TOOL_NAMES.has(name) || !payload || typeof payload !== "object") {
|
|
853
|
+
return null;
|
|
854
|
+
}
|
|
855
|
+
return { name, args, payload };
|
|
856
|
+
}
|
|
857
|
+
|
|
841
858
|
function summarizeRetainedSourceEvidence(messages = [], limit = 28) {
|
|
842
859
|
const bySource = new Map();
|
|
843
860
|
for (const message of messages) {
|
|
844
|
-
|
|
845
|
-
|
|
861
|
+
const retained = parseRetainedToolEvidenceMessage(message);
|
|
862
|
+
if (message?.role !== "tool" && !retained) continue;
|
|
863
|
+
const payload = retained?.payload || safeParseToolContent(message.content);
|
|
846
864
|
if (!payload || payload.ok === false || payload.blocked || payload.skipped) continue;
|
|
847
|
-
const toolName = String(payload.toolName || payload.name || "");
|
|
865
|
+
const toolName = String(retained?.name || payload.toolName || payload.name || "");
|
|
848
866
|
if (!["read_file", "list_files", "search_files", "inspect_project", "run_command"].includes(toolName)) {
|
|
849
867
|
continue;
|
|
850
868
|
}
|
|
851
|
-
const
|
|
852
|
-
const
|
|
853
|
-
const
|
|
869
|
+
const args = retained?.args || payload.args || {};
|
|
870
|
+
const sourcePath = String(payload.path || args.path || "").trim();
|
|
871
|
+
const command = String(args.command || "").trim();
|
|
872
|
+
const readRange = toolName === "read_file" ? retainedReadRange(payload, args) : null;
|
|
854
873
|
const key = `${toolName}:${sourcePath || command}${readRange ? `:${readRange.key}` : ""}`;
|
|
855
874
|
const parts = [`tool=${toolName}`];
|
|
856
875
|
if (sourcePath) parts.push(`path=${sourcePath}`);
|
|
@@ -976,7 +995,7 @@ function compactRetainedToolPayload(toolName, payload = {}, args = {}) {
|
|
|
976
995
|
result.contentTruncatedByLines = payload.contentTruncatedByLines === true;
|
|
977
996
|
if (payload.sha256) result.sha256 = compactSingleLine(payload.sha256, 96);
|
|
978
997
|
const content = String(payload.content || payload.contentPreview || "");
|
|
979
|
-
if (content) result.content = compactMultiline(content,
|
|
998
|
+
if (content) result.content = compactMultiline(content, 3000);
|
|
980
999
|
if (Array.isArray(payload.pathEvidence)) {
|
|
981
1000
|
result.pathEvidence = compactPathItems(payload.pathEvidence, 12, ["path", "source"]);
|
|
982
1001
|
}
|
|
@@ -986,6 +1005,7 @@ function compactRetainedToolPayload(toolName, payload = {}, args = {}) {
|
|
|
986
1005
|
result.results = compactPathItems(payload.results, 24, ["path", "file", "line", "match"]);
|
|
987
1006
|
} else if (toolName === "run_command") {
|
|
988
1007
|
result.args = { command: compactMultiline(args.command || payload.args?.command || "", 1200) };
|
|
1008
|
+
if (payload.changed !== undefined) result.changed = Boolean(payload.changed);
|
|
989
1009
|
if (Number.isFinite(Number(payload.exitCode))) result.exitCode = Number(payload.exitCode);
|
|
990
1010
|
if (payload.stdout) result.stdout = compactMultiline(payload.stdout, 1800);
|
|
991
1011
|
if (payload.stderr) result.stderr = compactMultiline(payload.stderr, 1200);
|
|
@@ -998,11 +1018,68 @@ function compactRetainedToolPayload(toolName, payload = {}, args = {}) {
|
|
|
998
1018
|
return redactValue(result);
|
|
999
1019
|
}
|
|
1000
1020
|
|
|
1001
|
-
function
|
|
1021
|
+
function retainedPathMatchesOutput(sourcePath = "", outputPaths = []) {
|
|
1022
|
+
const normalize = (value = "") =>
|
|
1023
|
+
String(value || "")
|
|
1024
|
+
.replace(/\\/g, "/")
|
|
1025
|
+
.replace(/^\.\//, "")
|
|
1026
|
+
.replace(/\/{2,}/g, "/")
|
|
1027
|
+
.replace(/\/$/, "");
|
|
1028
|
+
const source = normalize(sourcePath);
|
|
1029
|
+
if (!source) return false;
|
|
1030
|
+
return outputPaths.some((candidate) => {
|
|
1031
|
+
const output = normalize(candidate);
|
|
1032
|
+
return output && (source === output || source.endsWith(`/${output}`) || output.endsWith(`/${source}`));
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
function retainedToolRecordPriority(record = {}, outputPaths = []) {
|
|
1037
|
+
const name = String(record.name || "");
|
|
1038
|
+
const args = record.args || {};
|
|
1039
|
+
const payload = record.payload || {};
|
|
1040
|
+
let priority = 100;
|
|
1041
|
+
if (name === "deep_research") priority = 1000;
|
|
1042
|
+
else if (name === "inspect_project") priority = 900;
|
|
1043
|
+
else if (["apply_patch", "write_file"].includes(name)) priority = 850;
|
|
1044
|
+
else if (name === "run_command") {
|
|
1045
|
+
const exitCode = Number(payload.exitCode);
|
|
1046
|
+
priority = payload.changed === true || (Number.isFinite(exitCode) && exitCode !== 0) ? 800 : 500;
|
|
1047
|
+
} else if (name === "read_file") {
|
|
1048
|
+
const range = retainedReadRange(payload, args);
|
|
1049
|
+
priority = range.lineLimit > 0 ? 750 : 600;
|
|
1050
|
+
const sourcePath = String(payload.path || args.path || "").trim();
|
|
1051
|
+
if (retainedPathMatchesOutput(sourcePath, outputPaths)) priority -= 220;
|
|
1052
|
+
} else if (["search_files", "list_files"].includes(name)) priority = 400;
|
|
1053
|
+
return priority + Math.min(0.999, Math.max(0, Number(record.ordinal) || 0) / 100000);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
function retainedToolStateMessages(messages = [], limit = 12, outputPaths = []) {
|
|
1002
1057
|
const callsById = new Map();
|
|
1003
1058
|
const recordsByKey = new Map();
|
|
1004
1059
|
let ordinal = 0;
|
|
1060
|
+
const retainRecord = (name, args = {}, payload = {}) => {
|
|
1061
|
+
if (!COMPACTION_STATE_TOOL_NAMES.has(name)) return;
|
|
1062
|
+
if (!payload || payload.ok === false || payload.blocked || payload.skipped) return;
|
|
1063
|
+
const sourcePath = String(payload.path || args?.path || "").trim();
|
|
1064
|
+
const command = String(args?.command || payload.args?.command || "").trim();
|
|
1065
|
+
const durableIdentity = String(
|
|
1066
|
+
sourcePath || command || payload.researchId || args?.researchId || args?.query || name
|
|
1067
|
+
).trim();
|
|
1068
|
+
const readRange = name === "read_file" ? retainedReadRange(payload, args) : null;
|
|
1069
|
+
const key = `${name}:${durableIdentity || ordinal}${readRange ? `:${readRange.key}` : ""}`;
|
|
1070
|
+
recordsByKey.set(key, {
|
|
1071
|
+
ordinal: ordinal += 1,
|
|
1072
|
+
name,
|
|
1073
|
+
args: redactValue(args),
|
|
1074
|
+
payload: compactRetainedToolPayload(name, payload, args),
|
|
1075
|
+
});
|
|
1076
|
+
};
|
|
1005
1077
|
for (const message of messages) {
|
|
1078
|
+
const retained = parseRetainedToolEvidenceMessage(message);
|
|
1079
|
+
if (retained) {
|
|
1080
|
+
retainRecord(retained.name, retained.args, retained.payload);
|
|
1081
|
+
continue;
|
|
1082
|
+
}
|
|
1006
1083
|
if (message?.role === "assistant" && Array.isArray(message.tool_calls)) {
|
|
1007
1084
|
for (const call of message.tool_calls) {
|
|
1008
1085
|
const id = String(call?.id || "").trim();
|
|
@@ -1018,27 +1095,19 @@ function retainedToolStateMessages(messages = [], limit = 12) {
|
|
|
1018
1095
|
if (message?.role !== "tool") continue;
|
|
1019
1096
|
const call = callsById.get(String(message.tool_call_id || "").trim());
|
|
1020
1097
|
const payload = safeParseToolContent(message.content);
|
|
1021
|
-
if (!call || !payload
|
|
1022
|
-
|
|
1023
|
-
const command = String(call.args?.command || payload.args?.command || "").trim();
|
|
1024
|
-
const readRange = call.name === "read_file" ? retainedReadRange(payload, call.args) : null;
|
|
1025
|
-
const key = `${call.name}:${sourcePath || command || ordinal}${readRange ? `:${readRange.key}` : ""}`;
|
|
1026
|
-
recordsByKey.set(key, {
|
|
1027
|
-
ordinal: ordinal += 1,
|
|
1028
|
-
name: call.name,
|
|
1029
|
-
args: redactValue(call.args),
|
|
1030
|
-
payload: compactRetainedToolPayload(call.name, payload, call.args),
|
|
1031
|
-
});
|
|
1098
|
+
if (!call || !payload) continue;
|
|
1099
|
+
retainRecord(call.name, call.args, payload);
|
|
1032
1100
|
}
|
|
1033
1101
|
|
|
1034
1102
|
const records = [...recordsByKey.values()];
|
|
1035
|
-
const
|
|
1036
|
-
.
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1103
|
+
const selected = [...records]
|
|
1104
|
+
.sort(
|
|
1105
|
+
(left, right) =>
|
|
1106
|
+
retainedToolRecordPriority(right, outputPaths) - retainedToolRecordPriority(left, outputPaths) ||
|
|
1107
|
+
right.ordinal - left.ordinal
|
|
1108
|
+
)
|
|
1109
|
+
.slice(0, Math.max(1, Number(limit) || 12))
|
|
1110
|
+
.sort((left, right) => left.ordinal - right.ordinal);
|
|
1042
1111
|
|
|
1043
1112
|
return selected.flatMap((record, index) => {
|
|
1044
1113
|
const id = `aginti-compacted-tool-${index + 1}`;
|
|
@@ -1066,8 +1135,8 @@ function retainedToolStateMessages(messages = [], limit = 12) {
|
|
|
1066
1135
|
});
|
|
1067
1136
|
}
|
|
1068
1137
|
|
|
1069
|
-
function retainedToolStateTextMessages(messages = [], limit = 12) {
|
|
1070
|
-
const nativeMessages = retainedToolStateMessages(messages, limit);
|
|
1138
|
+
function retainedToolStateTextMessages(messages = [], limit = 12, outputPaths = []) {
|
|
1139
|
+
const nativeMessages = retainedToolStateMessages(messages, limit, outputPaths);
|
|
1071
1140
|
const retained = [];
|
|
1072
1141
|
for (let index = 0; index < nativeMessages.length; index += 2) {
|
|
1073
1142
|
const assistantMessage = nativeMessages[index];
|
|
@@ -1087,6 +1156,15 @@ function retainedToolStateTextMessages(messages = [], limit = 12) {
|
|
|
1087
1156
|
return retained;
|
|
1088
1157
|
}
|
|
1089
1158
|
|
|
1159
|
+
function retainedToolPairPriority(pair = [], order = 0, outputPaths = []) {
|
|
1160
|
+
const assistantCall = pair[0]?.tool_calls?.[0];
|
|
1161
|
+
const retained = pair.length === 1 ? parseRetainedToolEvidenceMessage(pair[0]) : null;
|
|
1162
|
+
const name = String(retained?.name || assistantCall?.function?.name || "");
|
|
1163
|
+
const args = retained?.args || safeParseToolContent(assistantCall?.function?.arguments) || {};
|
|
1164
|
+
const payload = retained?.payload || safeParseToolContent(pair[1]?.content) || {};
|
|
1165
|
+
return retainedToolRecordPriority({ name, args, payload, ordinal: order }, outputPaths);
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1090
1168
|
function isRuntimeCompactionRequest(content = "") {
|
|
1091
1169
|
return /^(?:The runtime proactively compacted a long agent history|A previous agent-step model request timed out|Continue from this compacted, valid transcript)/i.test(
|
|
1092
1170
|
String(content || "").trim()
|
|
@@ -1107,6 +1185,7 @@ function summarizeOriginalRequests(messages = [], limit = 6) {
|
|
|
1107
1185
|
if (!content.trim()) continue;
|
|
1108
1186
|
if (/^Step \d+\/\d+ .*Latest runtime snapshot:/i.test(content)) continue;
|
|
1109
1187
|
if (/^Previous assistant response retained as compacted history/i.test(content)) continue;
|
|
1188
|
+
if (parseRetainedToolEvidenceMessage(message)) continue;
|
|
1110
1189
|
if (isRuntimeCompactionRequest(content)) continue;
|
|
1111
1190
|
if (isRuntimeRecoveryRequest(content)) continue;
|
|
1112
1191
|
requests.push(compactSingleLine(content, 1200));
|
|
@@ -1265,9 +1344,10 @@ function buildCompactedRuntimeMessages(state, config, snapshot, step, options =
|
|
|
1265
1344
|
// synthetic pairs, so preserve their bounded evidence as explicit runtime
|
|
1266
1345
|
// context instead of fabricating assistant reasoning.
|
|
1267
1346
|
const deepSeekCompaction = normalizeProviderId(config.provider, "") === "deepseek";
|
|
1347
|
+
const exactOutputPaths = exactOutputPathsForState(state);
|
|
1268
1348
|
const retainedToolMessages = deepSeekCompaction
|
|
1269
|
-
? retainedToolStateTextMessages(messages)
|
|
1270
|
-
: retainedToolStateMessages(messages);
|
|
1349
|
+
? retainedToolStateTextMessages(messages, 12, exactOutputPaths)
|
|
1350
|
+
: retainedToolStateMessages(messages, 12, exactOutputPaths);
|
|
1271
1351
|
const snapshotSummary = {
|
|
1272
1352
|
step,
|
|
1273
1353
|
maxSteps: config.maxSteps,
|
|
@@ -1345,7 +1425,7 @@ function buildCompactedRuntimeMessages(state, config, snapshot, step, options =
|
|
|
1345
1425
|
}));
|
|
1346
1426
|
const boundedContent = compactTextForTokenBudget(
|
|
1347
1427
|
compactedContent,
|
|
1348
|
-
Math.max(1024, Math.floor(targetTokens * 0.52)),
|
|
1428
|
+
Math.max(1024, Math.floor(targetTokens * (retainedToolMessages.length ? 0.4 : 0.52))),
|
|
1349
1429
|
{ headFraction: 0.58 }
|
|
1350
1430
|
);
|
|
1351
1431
|
const baseMessages = [
|
|
@@ -1357,20 +1437,29 @@ function buildCompactedRuntimeMessages(state, config, snapshot, step, options =
|
|
|
1357
1437
|
];
|
|
1358
1438
|
const retainedPairs = [];
|
|
1359
1439
|
for (let index = 0; index < retainedToolMessages.length; index += deepSeekCompaction ? 1 : 2) {
|
|
1360
|
-
|
|
1440
|
+
const pair = retainedToolMessages.slice(index, index + (deepSeekCompaction ? 1 : 2));
|
|
1441
|
+
retainedPairs.push({
|
|
1442
|
+
pair,
|
|
1443
|
+
order: retainedPairs.length,
|
|
1444
|
+
priority: retainedToolPairPriority(pair, retainedPairs.length, exactOutputPaths),
|
|
1445
|
+
});
|
|
1361
1446
|
}
|
|
1362
1447
|
const selectedPairs = [];
|
|
1363
|
-
|
|
1448
|
+
const prioritizedPairs = [...retainedPairs].sort(
|
|
1449
|
+
(left, right) => right.priority - left.priority || right.order - left.order
|
|
1450
|
+
);
|
|
1451
|
+
for (const candidatePair of prioritizedPairs) {
|
|
1364
1452
|
const candidate = [
|
|
1365
1453
|
...baseMessages,
|
|
1366
|
-
...pair,
|
|
1367
|
-
...selectedPairs.
|
|
1454
|
+
...candidatePair.pair,
|
|
1455
|
+
...selectedPairs.flatMap((item) => item.pair),
|
|
1368
1456
|
];
|
|
1369
|
-
if (estimateMessageTokens(candidate) <= targetTokens) selectedPairs.
|
|
1457
|
+
if (estimateMessageTokens(candidate) <= targetTokens) selectedPairs.push(candidatePair);
|
|
1370
1458
|
}
|
|
1459
|
+
selectedPairs.sort((left, right) => left.order - right.order);
|
|
1371
1460
|
const compactMessages = [
|
|
1372
1461
|
...baseMessages,
|
|
1373
|
-
...selectedPairs.
|
|
1462
|
+
...selectedPairs.flatMap((item) => item.pair),
|
|
1374
1463
|
];
|
|
1375
1464
|
|
|
1376
1465
|
if (!compactMessages.some((message) => message.role === "system")) {
|
package/src/scs-evidence.js
CHANGED
|
@@ -373,9 +373,9 @@ function inferExactOutputPaths(goal = "") {
|
|
|
373
373
|
"gi"
|
|
374
374
|
);
|
|
375
375
|
const directOutputAction =
|
|
376
|
-
/\b(save|
|
|
376
|
+
/\b(save|write|rewrite|output|create|rebuild|replace|regenerate|generate|store|update|modify|edit)\b|保存|写入|寫入|重写|重寫|输出|輸出|创建|建立|重建|替换|替換|重新生成|生成|更新|修改|编辑|編輯/i;
|
|
377
377
|
const directOutputActionGlobal =
|
|
378
|
-
/\b(save|
|
|
378
|
+
/\b(save|write|rewrite|output|create|rebuild|replace|regenerate|generate|store|update|modify|edit)\b|保存|写入|寫入|重写|重寫|输出|輸出|创建|建立|重建|替换|替換|重新生成|生成|更新|修改|编辑|編輯/gi;
|
|
379
379
|
const outputListHeader =
|
|
380
380
|
/^(?:#+\s*)?(?:(?:required|final|expected|declared|target|pilot|deliverable)\s+)*(?:create|created files?|files? to create|outputs?|output structure|required outputs?|artifacts?|deliverables?|generated files?|writer requirements|renderer requirements|生成文件|输出结构|輸出結構|输出文件|輸出文件|创建文件|建立文件)(?:\s+(?:outputs?|artifacts?|deliverables?))?\s*[::]?\s*$/i;
|
|
381
381
|
const nonOutputToolLine =
|
|
@@ -470,7 +470,7 @@ function inferExactInputPaths(goal = "") {
|
|
|
470
470
|
const inputAction =
|
|
471
471
|
/\b(use|using|read|load|fill|upload|attach|import|select|choose|reference|input|from|fix|repair|patch|correct)\b|使用|读取|讀取|加载|載入|填写|填入|上传|上傳|附加|导入|導入|选择|選擇|选取|選取|参考|參考|素材|图片|圖片|照片|提示词|提示詞|修复|修正|更正|从|從/i;
|
|
472
472
|
const directOutputAction =
|
|
473
|
-
/\b(save|
|
|
473
|
+
/\b(save|write|rewrite|output|create|rebuild|replace|regenerate|generate|store|update|modify|edit)\b|保存|写入|寫入|重写|重寫|输出|輸出|创建|建立|重建|替换|替換|重新生成|生成|更新|修改|编辑|編輯/i;
|
|
474
474
|
const pushPath = (raw = "") => {
|
|
475
475
|
const cleaned = String(raw || "").trim();
|
|
476
476
|
if (!cleaned || /[{}]/.test(cleaned)) return;
|