@lazyingart/agintiflow 0.20.216 → 0.20.217
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/docs/supervision-campaign-ledger.md +32 -0
- package/package.json +1 -1
- package/scripts/smoke-coding-tools.js +153 -0
- package/scripts/smoke-dynamic-step-budget.js +1352 -0
- package/scripts/smoke-local-failure-recovery.js +8 -0
- package/scripts/smoke-progressive-tool-selection.js +824 -7
- package/scripts/smoke-truthful-completion.js +76 -0
- package/src/agent-runner.js +2424 -133
- package/src/command-policy.js +53 -1
- package/src/progressive-tool-selection.js +412 -11
- package/src/scs-evidence.js +15 -5
- package/src/tool-contract.js +13 -1
- package/src/workspace-tools.js +1 -0
|
@@ -235,3 +235,35 @@ provider balance. A separate read-only `localllm-deep` review completed with no
|
|
|
235
235
|
actionable findings. The full `npm test` suite, focused dynamic-step-budget,
|
|
236
236
|
coding-tools, SCS-evidence, and syntax checks all pass before packaging
|
|
237
237
|
AgInTiFlow `0.20.216`.
|
|
238
|
+
|
|
239
|
+
### Same-session interruption convergence and bounded completion
|
|
240
|
+
|
|
241
|
+
The `context-interruption-016` campaign exercised a long retained DeepSeek
|
|
242
|
+
session with multiple concrete interruptions, source corrections, an exact
|
|
243
|
+
external acceptance command, and a final clean-repository requirement. The
|
|
244
|
+
agent owned every target edit and commit. Early recovery turns repeatedly read
|
|
245
|
+
the same already-correct diff, showing that token limits alone do not guarantee
|
|
246
|
+
convergence while the available action surface remains open ended.
|
|
247
|
+
|
|
248
|
+
The reusable repair is driven by runtime state and evidence rather than task
|
|
249
|
+
literals. Mutations invalidate stale tests and prior completion evidence;
|
|
250
|
+
same-task interruptions refresh per-turn acceptance while retaining durable
|
|
251
|
+
evidence; repository-state recovery derives task-owned paths since the latest
|
|
252
|
+
successful commit and offers a bounded `commit_project_changes` action; and
|
|
253
|
+
the runtime constructs the path-scoped Git command. A current-revision exact
|
|
254
|
+
validator creates a one-use completion candidate. The following turn compacts
|
|
255
|
+
the evidence and exposes only `finish`; rejection or mutation invalidates the
|
|
256
|
+
candidate.
|
|
257
|
+
|
|
258
|
+
The final live continuation converged in three turns: bounded commit, exact
|
|
259
|
+
validator, and truthful finish. The target ended clean at commit `bd74bbd`.
|
|
260
|
+
Repository-repair context compacted from 156,716 to 5,788 characters, and the
|
|
261
|
+
verified-completion context compacted from 23,658 to 5,157 characters.
|
|
262
|
+
|
|
263
|
+
An independent read-only DeepSeek review then drove three general fixes: a
|
|
264
|
+
dedicated task-owned commit-path validator that supports binary,
|
|
265
|
+
extensionless, and instruction files while rejecting protected paths;
|
|
266
|
+
platform-aware POSIX and Windows command quoting; and recognition of bounded
|
|
267
|
+
stdin `sed -n` pipelines as read-only inspection. Production code contains no
|
|
268
|
+
campaign scenario IDs, target paths, expected prose, commit IDs, or acceptance
|
|
269
|
+
literals.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.217",
|
|
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",
|
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
buildModelTimeoutRetryMessages,
|
|
8
8
|
genericArtifactFilenameBlock,
|
|
9
9
|
modelTimeoutRetryRoute,
|
|
10
|
+
applyModelTimeoutRetryRoute,
|
|
11
|
+
recoverFocusedTextRewriteWithWritingSpecialist,
|
|
10
12
|
repairModelMessageHistory,
|
|
11
13
|
shouldResetStaticDiscoveryPhase,
|
|
12
14
|
runAgent,
|
|
@@ -16,6 +18,7 @@ import {
|
|
|
16
18
|
shellDiagnosticHint,
|
|
17
19
|
skippedAfterBlockedToolResult,
|
|
18
20
|
} from "../src/agent-runner.js";
|
|
21
|
+
import { createToolContract, resolveDispatchableToolCallBatch } from "../src/tool-contract.js";
|
|
19
22
|
import { formatBehaviorContractForPrompt } from "../src/behavior-contract.js";
|
|
20
23
|
import { resolveRuntimeConfig } from "../src/config.js";
|
|
21
24
|
import { readCodebaseMap } from "../src/codebase-map.js";
|
|
@@ -648,6 +651,14 @@ try {
|
|
|
648
651
|
);
|
|
649
652
|
assert(readonlyVersionPipelinePolicy.allowed, "read-only version probe pipelines should not require package-install-policy=allow");
|
|
650
653
|
assert(readonlyVersionPipelinePolicy.category === "read-only", "read-only version probe pipelines should be classified as read-only");
|
|
654
|
+
const readonlyDiffSlicePolicy = evaluateCommandPolicy(
|
|
655
|
+
"git diff -- src/agent-runner.js | sed -n '1,240p'",
|
|
656
|
+
dockerWorkspaceNoInstallsPolicy
|
|
657
|
+
);
|
|
658
|
+
assert(
|
|
659
|
+
readonlyDiffSlicePolicy.allowed && readonlyDiffSlicePolicy.category === "read-only",
|
|
660
|
+
"a bounded sed print filter made a read-only Git diff pipeline require broad shell access"
|
|
661
|
+
);
|
|
651
662
|
const nodeNpmTestPolicy = evaluateCommandPolicy(
|
|
652
663
|
'cd /workspace && node --version && npm test 2>&1; echo "EXIT:$?"',
|
|
653
664
|
dockerWorkspaceNoInstallsPolicy
|
|
@@ -1308,6 +1319,128 @@ try {
|
|
|
1308
1319
|
localTimeoutRoute.model === "localllm-fast" && localTimeoutRoute.retryTimeoutMs === 90000,
|
|
1309
1320
|
"LocalLLM timeout retry did not switch to its same-boundary fast route"
|
|
1310
1321
|
);
|
|
1322
|
+
const adoptedLocalTimeoutRoute = applyModelTimeoutRetryRoute(
|
|
1323
|
+
{ provider: "localllm", model: "localllm-deep", routingMode: "manual" },
|
|
1324
|
+
localTimeoutRoute
|
|
1325
|
+
);
|
|
1326
|
+
assert(
|
|
1327
|
+
adoptedLocalTimeoutRoute.model === "localllm-fast" &&
|
|
1328
|
+
adoptedLocalTimeoutRoute.modelTimeoutRecoveryActive === true &&
|
|
1329
|
+
/continuing this run/.test(adoptedLocalTimeoutRoute.routeReason),
|
|
1330
|
+
"a successful in-provider timeout retry was not retained for later steps in the same run"
|
|
1331
|
+
);
|
|
1332
|
+
const focusedRewriteDescriptor = {
|
|
1333
|
+
type: "function",
|
|
1334
|
+
function: {
|
|
1335
|
+
name: "rewrite_text_excerpt",
|
|
1336
|
+
description: "Rewrite one evidence-selected excerpt.",
|
|
1337
|
+
parameters: {
|
|
1338
|
+
type: "object",
|
|
1339
|
+
properties: {
|
|
1340
|
+
revisedText: {
|
|
1341
|
+
type: "string",
|
|
1342
|
+
minLength: 1,
|
|
1343
|
+
maxLength: 4000,
|
|
1344
|
+
pattern: "^(?:(?!load)[\\s\\S])+$",
|
|
1345
|
+
description:
|
|
1346
|
+
"Return only the complete revised excerpt. Remove the premature first-match operand while preserving the technical meaning.",
|
|
1347
|
+
},
|
|
1348
|
+
},
|
|
1349
|
+
required: ["revisedText"],
|
|
1350
|
+
additionalProperties: false,
|
|
1351
|
+
},
|
|
1352
|
+
},
|
|
1353
|
+
};
|
|
1354
|
+
const focusedRewriteContract = createToolContract([focusedRewriteDescriptor]);
|
|
1355
|
+
const invalidFocusedRewriteCall = {
|
|
1356
|
+
id: "focused-rewrite-smoke",
|
|
1357
|
+
type: "function",
|
|
1358
|
+
function: {
|
|
1359
|
+
name: "rewrite_text_excerpt",
|
|
1360
|
+
arguments: JSON.stringify({ revisedText: "A carefully preloaded technical summary." }),
|
|
1361
|
+
},
|
|
1362
|
+
};
|
|
1363
|
+
const invalidFocusedRewrite = resolveDispatchableToolCallBatch(
|
|
1364
|
+
[invalidFocusedRewriteCall],
|
|
1365
|
+
focusedRewriteContract
|
|
1366
|
+
);
|
|
1367
|
+
assert(
|
|
1368
|
+
!invalidFocusedRewrite.ok &&
|
|
1369
|
+
invalidFocusedRewrite.errors.some((error) => error.code === "ARGUMENT_PATTERN_MISMATCH"),
|
|
1370
|
+
"focused rewrite smoke input did not exercise the semantic pattern failure"
|
|
1371
|
+
);
|
|
1372
|
+
const focusedWriterCalls = [];
|
|
1373
|
+
const focusedRewriteState = {
|
|
1374
|
+
meta: {
|
|
1375
|
+
failedTestDiagnostic: {
|
|
1376
|
+
mutationRevision: 7,
|
|
1377
|
+
failureSignature: "generic-first-occurrence-relation",
|
|
1378
|
+
},
|
|
1379
|
+
},
|
|
1380
|
+
};
|
|
1381
|
+
const focusedRewriteConfig = {
|
|
1382
|
+
provider: "localllm",
|
|
1383
|
+
model: "localllm-fast",
|
|
1384
|
+
baseURL: "http://127.0.0.1:8008/v1",
|
|
1385
|
+
testFailureSignature: "generic-first-occurrence-relation",
|
|
1386
|
+
testFailureRepairPatchTargets: [{
|
|
1387
|
+
path: "notes/handoff.md",
|
|
1388
|
+
search: "A carefully preloaded technical summary.",
|
|
1389
|
+
}],
|
|
1390
|
+
writingClientFactory: (writingConfig) => {
|
|
1391
|
+
focusedWriterCalls.push(writingConfig);
|
|
1392
|
+
return {
|
|
1393
|
+
chat: {
|
|
1394
|
+
completions: {
|
|
1395
|
+
create: async () => ({
|
|
1396
|
+
choices: [{
|
|
1397
|
+
message: {
|
|
1398
|
+
content: JSON.stringify({
|
|
1399
|
+
draft: "A carefully prepared technical summary.",
|
|
1400
|
+
revision_notes: [],
|
|
1401
|
+
continuity_notes: [],
|
|
1402
|
+
format_handoff: {},
|
|
1403
|
+
quality_checks: ["constraint satisfied"],
|
|
1404
|
+
questions: [],
|
|
1405
|
+
}),
|
|
1406
|
+
},
|
|
1407
|
+
}],
|
|
1408
|
+
}),
|
|
1409
|
+
},
|
|
1410
|
+
},
|
|
1411
|
+
};
|
|
1412
|
+
},
|
|
1413
|
+
};
|
|
1414
|
+
const recoveredFocusedRewrite = await recoverFocusedTextRewriteWithWritingSpecialist(
|
|
1415
|
+
focusedRewriteConfig,
|
|
1416
|
+
focusedRewriteState,
|
|
1417
|
+
[invalidFocusedRewriteCall],
|
|
1418
|
+
focusedRewriteContract,
|
|
1419
|
+
invalidFocusedRewrite
|
|
1420
|
+
);
|
|
1421
|
+
assert(recoveredFocusedRewrite?.ok, "writing specialist did not recover the bounded semantic rewrite");
|
|
1422
|
+
assert(
|
|
1423
|
+
recoveredFocusedRewrite.recoveredFocusedTextRewrite === true &&
|
|
1424
|
+
JSON.parse(recoveredFocusedRewrite.acceptedToolCalls[0].function.arguments).revisedText ===
|
|
1425
|
+
"A carefully prepared technical summary.",
|
|
1426
|
+
"writing specialist recovery did not return a schema-valid focused rewrite call"
|
|
1427
|
+
);
|
|
1428
|
+
assert(
|
|
1429
|
+
focusedWriterCalls.length === 1 &&
|
|
1430
|
+
focusedWriterCalls[0].provider === "localllm" &&
|
|
1431
|
+
focusedWriterCalls[0].model === "localllm-fast",
|
|
1432
|
+
"focused rewrite recovery crossed the active provider/model boundary"
|
|
1433
|
+
);
|
|
1434
|
+
assert(
|
|
1435
|
+
(await recoverFocusedTextRewriteWithWritingSpecialist(
|
|
1436
|
+
focusedRewriteConfig,
|
|
1437
|
+
focusedRewriteState,
|
|
1438
|
+
[invalidFocusedRewriteCall],
|
|
1439
|
+
focusedRewriteContract,
|
|
1440
|
+
invalidFocusedRewrite
|
|
1441
|
+
)) === null && focusedWriterCalls.length === 1,
|
|
1442
|
+
"focused rewrite recovery repeated for the same retained failure state"
|
|
1443
|
+
);
|
|
1311
1444
|
const defaultLocalTimeoutRoute = modelTimeoutRetryRoute({
|
|
1312
1445
|
provider: "localllm",
|
|
1313
1446
|
model: "localllm-fast",
|
|
@@ -1512,6 +1645,25 @@ try {
|
|
|
1512
1645
|
const unifiedText = await fs.readFile(path.join(workspace, "unified-target.txt"), "utf8");
|
|
1513
1646
|
assert(unified.ok && unifiedText === "alpha\nnew\nomega\n", "unified apply_patch did not update expected file");
|
|
1514
1647
|
|
|
1648
|
+
await fs.writeFile(path.join(workspace, "no-op-patch-target.txt"), "already correct\n", "utf8");
|
|
1649
|
+
const noOpPatchError = await executeWorkspaceTool(
|
|
1650
|
+
"apply_patch",
|
|
1651
|
+
{
|
|
1652
|
+
path: "no-op-patch-target.txt",
|
|
1653
|
+
search: "already correct",
|
|
1654
|
+
replace: "already correct",
|
|
1655
|
+
expectedReplacements: 1,
|
|
1656
|
+
},
|
|
1657
|
+
{ commandCwd: workspace, allowFileTools: true }
|
|
1658
|
+
)
|
|
1659
|
+
.then(() => "")
|
|
1660
|
+
.catch((error) => String(error?.message || error));
|
|
1661
|
+
assert(
|
|
1662
|
+
/patch made no changes/i.test(noOpPatchError) &&
|
|
1663
|
+
(await fs.readFile(path.join(workspace, "no-op-patch-target.txt"), "utf8")) === "already correct\n",
|
|
1664
|
+
"an exact byte-identical replacement was reported as a successful mutation"
|
|
1665
|
+
);
|
|
1666
|
+
|
|
1515
1667
|
await fs.writeFile(path.join(workspace, "hybrid-patch-target.txt"), "alpha\nold\nomega\n", "utf8");
|
|
1516
1668
|
const hybridPatch = await executeWorkspaceTool(
|
|
1517
1669
|
"apply_patch",
|
|
@@ -1858,6 +2010,7 @@ try {
|
|
|
1858
2010
|
"node_profile_cli_package_manifest",
|
|
1859
2011
|
"python_profile_helper_test_report",
|
|
1860
2012
|
"model_timeout_compact_retry_messages",
|
|
2013
|
+
"focused_text_rewrite_specialist_recovery",
|
|
1861
2014
|
],
|
|
1862
2015
|
},
|
|
1863
2016
|
null,
|