@lazyingart/agintiflow 0.20.281 → 0.20.282
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.282",
|
|
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",
|
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
isSubstantiveTestCommand,
|
|
54
54
|
mergeDurableGitEvidence,
|
|
55
55
|
nextStepRuntimeConfig,
|
|
56
|
+
patchContextRefreshDecision,
|
|
56
57
|
patchContextScopeMismatchAttemptCount,
|
|
57
58
|
parseGitPorcelainStatus,
|
|
58
59
|
pythonMainGuardOrderDefects,
|
|
@@ -1216,6 +1217,100 @@ try {
|
|
|
1216
1217
|
Boolean(unrelatedInsertionBinding?.scopeIssue),
|
|
1217
1218
|
"an unrelated missing declaration escaped the active failed-test symbol contract"
|
|
1218
1219
|
);
|
|
1220
|
+
const declarationBoundarySource = [
|
|
1221
|
+
"def build_preview():",
|
|
1222
|
+
" path = 'preview.png'",
|
|
1223
|
+
" return path",
|
|
1224
|
+
"",
|
|
1225
|
+
"def main():",
|
|
1226
|
+
" return build_preview()",
|
|
1227
|
+
"",
|
|
1228
|
+
].join("\n");
|
|
1229
|
+
const declarationBoundaryOffset = declarationBoundarySource.indexOf("def main():");
|
|
1230
|
+
const declarationBoundaryAnchor = declarationBoundarySource.slice(
|
|
1231
|
+
0,
|
|
1232
|
+
declarationBoundaryOffset
|
|
1233
|
+
);
|
|
1234
|
+
const declarationBoundaryState = {
|
|
1235
|
+
meta: {
|
|
1236
|
+
goalContract: { revision: 1 },
|
|
1237
|
+
projectVerification: { mutationRevision: 1, privateMutationRevision: 0 },
|
|
1238
|
+
toolLoop: {
|
|
1239
|
+
patchContextRepair: {
|
|
1240
|
+
version: 1,
|
|
1241
|
+
path: "preview_builder.py",
|
|
1242
|
+
goalRevision: 1,
|
|
1243
|
+
mutationRevision: 1,
|
|
1244
|
+
privateMutationRevision: 0,
|
|
1245
|
+
search: declarationBoundaryAnchor,
|
|
1246
|
+
searchHash: crypto
|
|
1247
|
+
.createHash("sha256")
|
|
1248
|
+
.update(declarationBoundaryAnchor)
|
|
1249
|
+
.digest("hex"),
|
|
1250
|
+
sourceHash: crypto
|
|
1251
|
+
.createHash("sha256")
|
|
1252
|
+
.update(declarationBoundarySource)
|
|
1253
|
+
.digest("hex"),
|
|
1254
|
+
anchorKind: "declaration-identity",
|
|
1255
|
+
anchorIdentity: "build_preview",
|
|
1256
|
+
},
|
|
1257
|
+
},
|
|
1258
|
+
},
|
|
1259
|
+
};
|
|
1260
|
+
const declarationBoundaryBinding = bindPatchContextRepairArguments(
|
|
1261
|
+
declarationBoundaryState,
|
|
1262
|
+
{
|
|
1263
|
+
replace: [
|
|
1264
|
+
"def build_preview():",
|
|
1265
|
+
" path = 'preview-fixed.png'",
|
|
1266
|
+
" return path",
|
|
1267
|
+
].join("\n"),
|
|
1268
|
+
}
|
|
1269
|
+
);
|
|
1270
|
+
assert(
|
|
1271
|
+
declarationBoundaryBinding?.boundaryWhitespacePreserved === true &&
|
|
1272
|
+
declarationBoundaryBinding.args.replace.endsWith("\n") &&
|
|
1273
|
+
/return path\n+def main\(\):/.test(
|
|
1274
|
+
`${declarationBoundaryBinding.args.replace}${declarationBoundarySource.slice(declarationBoundaryOffset)}`
|
|
1275
|
+
),
|
|
1276
|
+
"revision-bound declaration replacement did not preserve its Python declaration boundary"
|
|
1277
|
+
);
|
|
1278
|
+
await fs.writeFile(
|
|
1279
|
+
path.join(workspace, "preview_builder.py"),
|
|
1280
|
+
declarationBoundarySource,
|
|
1281
|
+
"utf8"
|
|
1282
|
+
);
|
|
1283
|
+
assert(
|
|
1284
|
+
(await prospectivePythonExactPatchSyntaxBlock(
|
|
1285
|
+
"apply_patch",
|
|
1286
|
+
declarationBoundaryBinding.args,
|
|
1287
|
+
{ commandCwd: workspace }
|
|
1288
|
+
)) === null,
|
|
1289
|
+
"the boundary-preserved declaration replacement still produced invalid Python"
|
|
1290
|
+
);
|
|
1291
|
+
const syntaxRefreshDecision = patchContextRefreshDecision(
|
|
1292
|
+
{
|
|
1293
|
+
meta: {
|
|
1294
|
+
goalContract: { revision: 1 },
|
|
1295
|
+
projectVerification: { mutationRevision: 1, privateMutationRevision: 0 },
|
|
1296
|
+
toolLoop: { stagnationEpoch: 0, recent: [] },
|
|
1297
|
+
},
|
|
1298
|
+
},
|
|
1299
|
+
{
|
|
1300
|
+
toolName: "apply_patch",
|
|
1301
|
+
ok: false,
|
|
1302
|
+
category: "python-syntax-regression",
|
|
1303
|
+
args: {
|
|
1304
|
+
path: "preview_builder.py",
|
|
1305
|
+
search: declarationBoundaryAnchor,
|
|
1306
|
+
},
|
|
1307
|
+
}
|
|
1308
|
+
);
|
|
1309
|
+
assert(
|
|
1310
|
+
syntaxRefreshDecision?.triggerCategory === "python-syntax-regression" &&
|
|
1311
|
+
syntaxRefreshDecision.path === "preview_builder.py",
|
|
1312
|
+
"a prospective Python syntax regression did not force a fresh exact-source read"
|
|
1313
|
+
);
|
|
1219
1314
|
const semanticScopeMismatchState = {
|
|
1220
1315
|
meta: {
|
|
1221
1316
|
goalContract: { revision: 4 },
|
|
@@ -10364,6 +10459,60 @@ try {
|
|
|
10364
10459
|
assert(resumedBudget?.extensionsUsed === 0, "runAgent retained stale extension usage after an explicit resumed max-steps patch");
|
|
10365
10460
|
assert(resumedBudget?.resetFromExplicitOverride === true, "runAgent did not record the explicit budget reset boundary");
|
|
10366
10461
|
|
|
10462
|
+
const educationWorkspace = path.join(tempRoot, "education-artifact-contract");
|
|
10463
|
+
await fs.mkdir(path.join(educationWorkspace, "workshop"), { recursive: true });
|
|
10464
|
+
await fs.writeFile(path.join(educationWorkspace, "workshop", "lesson-deck.md"), "# Lesson\n");
|
|
10465
|
+
const educationGoal =
|
|
10466
|
+
"Create an editable lesson deck, a separate practice sheet and answer key, printable materials, a helpful preview, and a reproducible build entrypoint. Verify and commit the work.";
|
|
10467
|
+
const educationState = {
|
|
10468
|
+
goal: educationGoal,
|
|
10469
|
+
commandCwd: educationWorkspace,
|
|
10470
|
+
plan: "Create every requested artifact, verify them, and commit the complete set.",
|
|
10471
|
+
messages: [
|
|
10472
|
+
{
|
|
10473
|
+
role: "tool",
|
|
10474
|
+
content: JSON.stringify({
|
|
10475
|
+
ok: true,
|
|
10476
|
+
toolName: "write_file",
|
|
10477
|
+
path: "workshop/lesson-deck.md",
|
|
10478
|
+
goalRevision: 1,
|
|
10479
|
+
projectMutationRevision: 1,
|
|
10480
|
+
}),
|
|
10481
|
+
},
|
|
10482
|
+
],
|
|
10483
|
+
meta: {
|
|
10484
|
+
taskProfile: "education",
|
|
10485
|
+
goalContract: {
|
|
10486
|
+
revision: 1,
|
|
10487
|
+
currentRequest: educationGoal,
|
|
10488
|
+
taskGoal: educationGoal,
|
|
10489
|
+
activeGoalRevision: 1,
|
|
10490
|
+
lifecycle: [{ at: new Date(Date.now() - 2000).toISOString() }],
|
|
10491
|
+
},
|
|
10492
|
+
projectVerification: {
|
|
10493
|
+
mutationRevision: 1,
|
|
10494
|
+
mutationHistory: [
|
|
10495
|
+
{
|
|
10496
|
+
revision: 1,
|
|
10497
|
+
at: new Date().toISOString(),
|
|
10498
|
+
toolName: "write_file",
|
|
10499
|
+
paths: ["workshop/lesson-deck.md"],
|
|
10500
|
+
goalRevision: 1,
|
|
10501
|
+
},
|
|
10502
|
+
],
|
|
10503
|
+
},
|
|
10504
|
+
},
|
|
10505
|
+
};
|
|
10506
|
+
const incompleteEducationRuntime = nextStepRuntimeConfig(
|
|
10507
|
+
{ goal: educationGoal, taskProfile: "education", commandCwd: educationWorkspace },
|
|
10508
|
+
educationState
|
|
10509
|
+
);
|
|
10510
|
+
assert(
|
|
10511
|
+
incompleteEducationRuntime.requestedArtifactRequirementsPending === true &&
|
|
10512
|
+
incompleteEducationRuntime.taskOwnedCommitPending !== true,
|
|
10513
|
+
"a partial multi-artifact task entered task-owned Git completion before its deliverables existed"
|
|
10514
|
+
);
|
|
10515
|
+
|
|
10367
10516
|
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
10368
10517
|
console.log("smoke-dynamic-step-budget ok");
|
|
10369
10518
|
} catch (error) {
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
buildScsEvidenceLedger,
|
|
14
14
|
deriveScsTaskContract,
|
|
15
|
+
evaluateRequestedArtifactRequirements,
|
|
15
16
|
evaluateScsSemanticContract,
|
|
16
17
|
extractMarkdownCommandEvidence,
|
|
17
18
|
extractMarkdownPathEvidence,
|
|
@@ -19,6 +20,73 @@ import {
|
|
|
19
20
|
finishResultClaimsIncompleteWork,
|
|
20
21
|
} from "../src/scs-evidence.js";
|
|
21
22
|
|
|
23
|
+
const educationArtifactGoal =
|
|
24
|
+
"Create an editable lesson deck, a separate practice sheet and answer key, printable materials, a helpful preview, and a reproducible build entrypoint.";
|
|
25
|
+
const educationArtifactContract = deriveScsTaskContract({
|
|
26
|
+
goal: educationArtifactGoal,
|
|
27
|
+
taskProfile: "education",
|
|
28
|
+
});
|
|
29
|
+
assert.deepEqual(
|
|
30
|
+
educationArtifactContract.requiredArtifactKinds.map((item) => item.id).sort(),
|
|
31
|
+
[
|
|
32
|
+
"answer-material",
|
|
33
|
+
"editable-presentation",
|
|
34
|
+
"practice-material",
|
|
35
|
+
"printable-document",
|
|
36
|
+
"reproducible-build-entrypoint",
|
|
37
|
+
"visual-preview",
|
|
38
|
+
],
|
|
39
|
+
"multi-artifact education request did not retain each semantic deliverable"
|
|
40
|
+
);
|
|
41
|
+
assert.deepEqual(
|
|
42
|
+
deriveScsTaskContract({
|
|
43
|
+
goal: "Create a canvas artifact preview for this smoke test.",
|
|
44
|
+
taskProfile: "auto",
|
|
45
|
+
}).requiredArtifactKinds,
|
|
46
|
+
[],
|
|
47
|
+
"a generic frontend canvas preview was incorrectly converted into a required image-file artifact"
|
|
48
|
+
);
|
|
49
|
+
const educationWorkspace = fs.mkdtempSync(path.join(os.tmpdir(), "aginti-education-artifacts-"));
|
|
50
|
+
const educationState = {
|
|
51
|
+
meta: {
|
|
52
|
+
goalContract: {
|
|
53
|
+
lifecycle: [{ at: new Date(Date.now() - 2000).toISOString() }],
|
|
54
|
+
},
|
|
55
|
+
projectVerification: { mutationHistory: [] },
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
fs.mkdirSync(path.join(educationWorkspace, "workshop"), { recursive: true });
|
|
59
|
+
fs.writeFileSync(path.join(educationWorkspace, "workshop", "lesson-deck.md"), "# Lesson deck\n");
|
|
60
|
+
const incompleteEducationArtifacts = evaluateRequestedArtifactRequirements(
|
|
61
|
+
educationArtifactContract,
|
|
62
|
+
{ commandCwd: educationWorkspace, state: educationState }
|
|
63
|
+
);
|
|
64
|
+
assert.equal(incompleteEducationArtifacts.ok, false);
|
|
65
|
+
assert.ok(
|
|
66
|
+
incompleteEducationArtifacts.missing.some((item) => item.id === "editable-presentation"),
|
|
67
|
+
"Markdown-only deck incorrectly satisfied the editable presentation contract"
|
|
68
|
+
);
|
|
69
|
+
for (const [name, content] of [
|
|
70
|
+
["lesson-deck.pptx", "pptx"],
|
|
71
|
+
["practice-sheet.md", "practice"],
|
|
72
|
+
["answer-key.md", "answers"],
|
|
73
|
+
["practice-sheet.pdf", "pdf"],
|
|
74
|
+
["lesson-preview.png", "png"],
|
|
75
|
+
["build_materials.py", "print('build')\n"],
|
|
76
|
+
]) {
|
|
77
|
+
fs.writeFileSync(path.join(educationWorkspace, "workshop", name), content);
|
|
78
|
+
}
|
|
79
|
+
const completeEducationArtifacts = evaluateRequestedArtifactRequirements(
|
|
80
|
+
educationArtifactContract,
|
|
81
|
+
{ commandCwd: educationWorkspace, state: educationState }
|
|
82
|
+
);
|
|
83
|
+
assert.equal(
|
|
84
|
+
completeEducationArtifacts.ok,
|
|
85
|
+
true,
|
|
86
|
+
`complete semantic artifact set was rejected: ${completeEducationArtifacts.reason}`
|
|
87
|
+
);
|
|
88
|
+
fs.rmSync(educationWorkspace, { recursive: true, force: true });
|
|
89
|
+
|
|
22
90
|
function fakeStudentClient(json) {
|
|
23
91
|
return {
|
|
24
92
|
chat: {
|
package/scripts/smoke-web-api.js
CHANGED
|
@@ -68,12 +68,23 @@ async function waitForHealth() {
|
|
|
68
68
|
async function waitForRun(sessionId, terminalStatuses = ["finished", "failed"]) {
|
|
69
69
|
const acceptedStatuses = new Set(terminalStatuses);
|
|
70
70
|
const deadline = Date.now() + 20000;
|
|
71
|
+
let lastRun = null;
|
|
71
72
|
while (Date.now() < deadline) {
|
|
72
73
|
const run = await fetchJson(`/api/runs/${encodeURIComponent(sessionId)}`);
|
|
74
|
+
lastRun = run;
|
|
73
75
|
if (acceptedStatuses.has(run.status)) return run;
|
|
74
76
|
await delay(400);
|
|
75
77
|
}
|
|
76
|
-
throw new Error(
|
|
78
|
+
throw new Error(
|
|
79
|
+
`run ${sessionId} did not finish in time; ` +
|
|
80
|
+
`lastRun=${JSON.stringify(lastRun ? {
|
|
81
|
+
status: lastRun.status,
|
|
82
|
+
error: lastRun.error,
|
|
83
|
+
endedAt: lastRun.endedAt,
|
|
84
|
+
logs: Array.isArray(lastRun.logs) ? lastRun.logs.slice(-12) : [],
|
|
85
|
+
} : null)} ` +
|
|
86
|
+
`stdout=${stdout.slice(-1000)} stderr=${stderr.slice(-1000)}`
|
|
87
|
+
);
|
|
77
88
|
}
|
|
78
89
|
|
|
79
90
|
try {
|
package/src/agent-runner.js
CHANGED
|
@@ -128,6 +128,7 @@ import {
|
|
|
128
128
|
deterministicFinishBlocker,
|
|
129
129
|
evaluateScsEvidence,
|
|
130
130
|
evaluateScsSemanticContract,
|
|
131
|
+
evaluateRequestedArtifactRequirements,
|
|
131
132
|
augmentScsTaskContractWithProjectVerification,
|
|
132
133
|
agintiEvidenceScopeLine,
|
|
133
134
|
filterExplicitlyExcludedOutputPaths,
|
|
@@ -1754,6 +1755,11 @@ function buildCompactedRuntimeMessages(state, config, snapshot, step, options =
|
|
|
1754
1755
|
title: snapshot?.title || "",
|
|
1755
1756
|
url: snapshot?.url || "",
|
|
1756
1757
|
plan: effectivePlan,
|
|
1758
|
+
missingRequestedArtifactRequirements: Array.isArray(
|
|
1759
|
+
config.missingRequestedArtifactRequirements
|
|
1760
|
+
)
|
|
1761
|
+
? config.missingRequestedArtifactRequirements
|
|
1762
|
+
: [],
|
|
1757
1763
|
};
|
|
1758
1764
|
const compactedContent = [
|
|
1759
1765
|
options.heading || "Continue from this compacted, valid transcript.",
|
|
@@ -11507,6 +11513,21 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
|
|
|
11507
11513
|
? state.meta.activeExecutionContract || {}
|
|
11508
11514
|
: {};
|
|
11509
11515
|
const groundingTaskContract = completionTaskContract(config, state);
|
|
11516
|
+
const requestedArtifactEvaluation = evaluateRequestedArtifactRequirements(
|
|
11517
|
+
groundingTaskContract,
|
|
11518
|
+
{
|
|
11519
|
+
commandCwd: config.commandCwd || state.commandCwd || process.cwd(),
|
|
11520
|
+
state,
|
|
11521
|
+
}
|
|
11522
|
+
);
|
|
11523
|
+
if (!requestedArtifactEvaluation.ok) {
|
|
11524
|
+
runtimeConfig.requestedArtifactRequirementsPending = true;
|
|
11525
|
+
runtimeConfig.missingRequestedArtifactRequirements =
|
|
11526
|
+
requestedArtifactEvaluation.missing.map((item) => ({
|
|
11527
|
+
id: String(item?.id || ""),
|
|
11528
|
+
description: String(item?.description || item?.id || ""),
|
|
11529
|
+
}));
|
|
11530
|
+
}
|
|
11510
11531
|
const groundingMutationRevision = Math.max(
|
|
11511
11532
|
0,
|
|
11512
11533
|
Number(state.meta?.projectVerification?.mutationRevision || 0)
|
|
@@ -12263,7 +12284,12 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
|
|
|
12263
12284
|
runtimeConfig.requiredProjectCommand = pendingRequiredProjectCommands[0];
|
|
12264
12285
|
runtimeConfig.pendingRequiredProjectCommands = pendingRequiredProjectCommands;
|
|
12265
12286
|
}
|
|
12266
|
-
if (
|
|
12287
|
+
if (
|
|
12288
|
+
!state.meta?.artifactProgress &&
|
|
12289
|
+
!retainedFailedTest &&
|
|
12290
|
+
!implementationOpen &&
|
|
12291
|
+
requestedArtifactEvaluation.ok
|
|
12292
|
+
) {
|
|
12267
12293
|
const completionContract = completionTaskContract(config, state);
|
|
12268
12294
|
const completionEvaluation = evaluateScsEvidence(
|
|
12269
12295
|
completionContract,
|
|
@@ -13293,6 +13319,25 @@ function comparablePatchContextText(value = "") {
|
|
|
13293
13319
|
.trim();
|
|
13294
13320
|
}
|
|
13295
13321
|
|
|
13322
|
+
function preservePatchContextBoundaryWhitespace(marker = {}, replacement = "") {
|
|
13323
|
+
const value = String(replacement || "");
|
|
13324
|
+
if (String(marker.anchorKind || "") === "complete-file") {
|
|
13325
|
+
return { replacement: value, preserved: false };
|
|
13326
|
+
}
|
|
13327
|
+
const search = String(marker.search || "");
|
|
13328
|
+
const trailingBoundary = search.match(/(?:(?:\r\n|\n|\r)[\t ]*)+$/)?.[0] || "";
|
|
13329
|
+
if (!trailingBoundary) return { replacement: value, preserved: false };
|
|
13330
|
+
const withoutTrailingBoundary = value.replace(
|
|
13331
|
+
/(?:(?:\r\n|\n|\r)[\t ]*)+$/,
|
|
13332
|
+
""
|
|
13333
|
+
);
|
|
13334
|
+
const normalized = `${withoutTrailingBoundary}${trailingBoundary}`;
|
|
13335
|
+
return {
|
|
13336
|
+
replacement: normalized,
|
|
13337
|
+
preserved: normalized !== value,
|
|
13338
|
+
};
|
|
13339
|
+
}
|
|
13340
|
+
|
|
13296
13341
|
function patchContextDeclarationCounts(content = "") {
|
|
13297
13342
|
const counts = new Map();
|
|
13298
13343
|
for (const record of sourceLineRecords(content)) {
|
|
@@ -13520,6 +13565,11 @@ export function bindPatchContextRepairArguments(state = {}, requestedArgs = {})
|
|
|
13520
13565
|
: patchContextReplacementScopeIssue(boundMarker, replace);
|
|
13521
13566
|
}
|
|
13522
13567
|
}
|
|
13568
|
+
const boundaryWhitespace = preservePatchContextBoundaryWhitespace(
|
|
13569
|
+
boundMarker,
|
|
13570
|
+
replace
|
|
13571
|
+
);
|
|
13572
|
+
replace = boundaryWhitespace.replacement;
|
|
13523
13573
|
if (boundedSubrange && state.meta?.toolLoop?.patchContextRepair) {
|
|
13524
13574
|
state.meta.toolLoop.patchContextRepair.lastBoundSearchHash =
|
|
13525
13575
|
boundedSubrange.searchHash;
|
|
@@ -13538,6 +13588,7 @@ export function bindPatchContextRepairArguments(state = {}, requestedArgs = {})
|
|
|
13538
13588
|
: "",
|
|
13539
13589
|
boundedRequestedSubrange: Boolean(boundedSubrange),
|
|
13540
13590
|
incrementalDeclarationRecovery,
|
|
13591
|
+
boundaryWhitespacePreserved: boundaryWhitespace.preserved,
|
|
13541
13592
|
noOp:
|
|
13542
13593
|
comparablePatchContextText(replace) ===
|
|
13543
13594
|
comparablePatchContextText(boundMarker.search),
|
|
@@ -13613,8 +13664,21 @@ export function patchContextRefreshDecision(state = {}, toolResult = {}) {
|
|
|
13613
13664
|
toolResult.ok === false &&
|
|
13614
13665
|
toolResult.category === "patch-context-scope-mismatch"
|
|
13615
13666
|
);
|
|
13667
|
+
const pythonSyntaxRegression = Boolean(
|
|
13668
|
+
String(toolResult.toolName || "") === "apply_patch" &&
|
|
13669
|
+
toolResult.ok === false &&
|
|
13670
|
+
toolResult.category === "python-syntax-regression"
|
|
13671
|
+
);
|
|
13616
13672
|
const missingSearch = patchSearchTextWasNotFound(toolResult);
|
|
13617
|
-
if (
|
|
13673
|
+
if (
|
|
13674
|
+
!missingSearch &&
|
|
13675
|
+
!idempotencyBlock &&
|
|
13676
|
+
!topologyBlock &&
|
|
13677
|
+
!scopeMismatch &&
|
|
13678
|
+
!pythonSyntaxRegression
|
|
13679
|
+
) {
|
|
13680
|
+
return null;
|
|
13681
|
+
}
|
|
13618
13682
|
const targetPath = toolResultWorkspacePath(toolResult);
|
|
13619
13683
|
if (!targetPath) return null;
|
|
13620
13684
|
const toolLoop = state.meta?.toolLoop || {};
|
|
@@ -13642,6 +13706,7 @@ export function patchContextRefreshDecision(state = {}, toolResult = {}) {
|
|
|
13642
13706
|
!idempotencyBlock &&
|
|
13643
13707
|
!topologyBlock &&
|
|
13644
13708
|
!scopeMismatch &&
|
|
13709
|
+
!pythonSyntaxRegression &&
|
|
13645
13710
|
stalePatchFailureCount < 1 &&
|
|
13646
13711
|
!followedIdempotencyBlock
|
|
13647
13712
|
) {
|
|
@@ -13673,6 +13738,8 @@ export function patchContextRefreshDecision(state = {}, toolResult = {}) {
|
|
|
13673
13738
|
? "required-symbol-topology"
|
|
13674
13739
|
: scopeMismatch
|
|
13675
13740
|
? "patch-context-scope-mismatch"
|
|
13741
|
+
: pythonSyntaxRegression
|
|
13742
|
+
? "python-syntax-regression"
|
|
13676
13743
|
: "stale-patch-search",
|
|
13677
13744
|
failedSearchPreview,
|
|
13678
13745
|
failedSearchHash: String(toolResult.args?.searchHash || ""),
|
|
@@ -14654,6 +14721,8 @@ async function executeTool(browserState, toolCall, snapshot, config, store, obse
|
|
|
14654
14721
|
patchContextBinding.boundedRequestedSubrange === true,
|
|
14655
14722
|
incrementalDeclarationRecovery:
|
|
14656
14723
|
Boolean(patchContextBinding.incrementalDeclarationRecovery),
|
|
14724
|
+
boundaryWhitespacePreserved:
|
|
14725
|
+
patchContextBinding.boundaryWhitespacePreserved === true,
|
|
14657
14726
|
};
|
|
14658
14727
|
await store.appendEvent("patch_context.anchor_injected", detail);
|
|
14659
14728
|
observers.event("patch_context.anchor_injected", detail);
|
package/src/scs-controller.js
CHANGED
|
@@ -508,6 +508,11 @@ function formatHardContractForPrompt(contract = {}) {
|
|
|
508
508
|
const requiredExecutableTerms = normalizeStringList(contract.requiredExecutableTerms, []);
|
|
509
509
|
const forbiddenTextTerms = normalizeStringList(contract.forbiddenTextTerms, []);
|
|
510
510
|
const forbiddenActions = normalizeStringList(contract.forbiddenActions, []);
|
|
511
|
+
const requiredArtifactKinds = (Array.isArray(contract.requiredArtifactKinds)
|
|
512
|
+
? contract.requiredArtifactKinds
|
|
513
|
+
: [])
|
|
514
|
+
.map((item) => compact(item?.description || item?.id || "", 160))
|
|
515
|
+
.filter(Boolean);
|
|
511
516
|
if (exactOutputPaths.length) lines.push(`Exact output path(s): ${exactOutputPaths.join(", ")}`);
|
|
512
517
|
if (exactInputPaths.length) lines.push(`Exact input/reference path(s) to use: ${exactInputPaths.join(", ")}`);
|
|
513
518
|
if (requiredTextTerms.length) lines.push(`Required text term(s) in the output: ${requiredTextTerms.join(", ")}`);
|
|
@@ -516,6 +521,9 @@ function formatHardContractForPrompt(contract = {}) {
|
|
|
516
521
|
}
|
|
517
522
|
if (forbiddenTextTerms.length) lines.push(`Forbidden text term(s) in the output: ${forbiddenTextTerms.join(", ")}`);
|
|
518
523
|
if (forbiddenActions.length) lines.push(`Forbidden action(s): ${forbiddenActions.join("; ")}`);
|
|
524
|
+
if (requiredArtifactKinds.length) {
|
|
525
|
+
lines.push(`Required artifact deliverable(s): ${requiredArtifactKinds.join(", ")}`);
|
|
526
|
+
}
|
|
519
527
|
return lines.length
|
|
520
528
|
? [
|
|
521
529
|
"Inferred hard task contract. Preserve these literally; do not replace them with weaker or contradictory criteria:",
|
|
@@ -531,8 +539,19 @@ function deterministicPlanContractIssue(committee = {}, contract = {}) {
|
|
|
531
539
|
const missingRequiredTerms = normalizeStringList(contract.requiredTextTerms, []).filter((item) => !planText.includes(item));
|
|
532
540
|
const missingExecutableTerms = normalizeStringList(contract.requiredExecutableTerms, []).filter((item) => !planText.includes(item));
|
|
533
541
|
const forbiddenTermsInPlan = normalizeStringList(contract.forbiddenTextTerms, []).filter((item) => planText.includes(item));
|
|
542
|
+
const missingArtifactKinds = (Array.isArray(contract.requiredArtifactKinds)
|
|
543
|
+
? contract.requiredArtifactKinds
|
|
544
|
+
: []).filter((item) => {
|
|
545
|
+
const id = String(item?.id || "").replace(/^format:/, "");
|
|
546
|
+
const description = String(item?.description || "");
|
|
547
|
+
const terms = [id, description]
|
|
548
|
+
.flatMap((value) => value.toLocaleLowerCase("en-US").split(/[^a-z0-9.]+/))
|
|
549
|
+
.filter((value) => value.length >= 3);
|
|
550
|
+
const normalizedPlan = planText.toLocaleLowerCase("en-US");
|
|
551
|
+
return terms.length > 0 && !terms.some((term) => normalizedPlan.includes(term));
|
|
552
|
+
});
|
|
534
553
|
const actionContradiction = deterministicPlanActionContradiction(planText, contract);
|
|
535
|
-
if (missingPath.length || missingInputPath.length || missingRequiredTerms.length || missingExecutableTerms.length || forbiddenTermsInPlan.length || actionContradiction) {
|
|
554
|
+
if (missingPath.length || missingInputPath.length || missingRequiredTerms.length || missingExecutableTerms.length || forbiddenTermsInPlan.length || missingArtifactKinds.length || actionContradiction) {
|
|
536
555
|
return {
|
|
537
556
|
decision: "veto_plan",
|
|
538
557
|
confidence: 0.94,
|
|
@@ -542,6 +561,11 @@ function deterministicPlanContractIssue(committee = {}, contract = {}) {
|
|
|
542
561
|
missingRequiredTerms.length ? `Plan omitted required text term(s): ${missingRequiredTerms.join(", ")}` : "",
|
|
543
562
|
missingExecutableTerms.length ? `Plan omitted required executable source expression(s): ${missingExecutableTerms.join(", ")}` : "",
|
|
544
563
|
forbiddenTermsInPlan.length ? `Plan includes forbidden text term(s): ${forbiddenTermsInPlan.join(", ")}` : "",
|
|
564
|
+
missingArtifactKinds.length
|
|
565
|
+
? `Plan omitted requested artifact deliverable(s): ${missingArtifactKinds
|
|
566
|
+
.map((item) => item.description || item.id)
|
|
567
|
+
.join(", ")}`
|
|
568
|
+
: "",
|
|
545
569
|
actionContradiction || "",
|
|
546
570
|
].filter(Boolean),
|
|
547
571
|
reason:
|
package/src/scs-evidence.js
CHANGED
|
@@ -521,6 +521,120 @@ function inferExactOutputPaths(goal = "") {
|
|
|
521
521
|
return uniqueLimited(filterShadowedBasenames(paths), 16);
|
|
522
522
|
}
|
|
523
523
|
|
|
524
|
+
const REQUESTED_ARTIFACT_FORMATS = [
|
|
525
|
+
{ extension: ".pptx", pattern: /\b(?:pptx|powerpoint)\b/i, description: "editable PowerPoint deck" },
|
|
526
|
+
{ extension: ".odp", pattern: /\b(?:odp|open(?:office|document) presentation)\b/i, description: "editable ODP deck" },
|
|
527
|
+
{ extension: ".pdf", pattern: /\bpdf\b/i, description: "PDF document" },
|
|
528
|
+
{ extension: ".docx", pattern: /\b(?:docx|word document)\b/i, description: "editable Word document" },
|
|
529
|
+
{ extension: ".xlsx", pattern: /\b(?:xlsx|excel workbook)\b/i, description: "editable spreadsheet" },
|
|
530
|
+
{ extension: ".png", pattern: /\bpng\b/i, description: "PNG image" },
|
|
531
|
+
{ extension: ".svg", pattern: /\bsvg\b/i, description: "editable SVG image" },
|
|
532
|
+
];
|
|
533
|
+
|
|
534
|
+
function artifactRequestHasOutputIntent(goal = "", taskProfile = "") {
|
|
535
|
+
const source = stripForbiddenLanguage(String(goal || ""));
|
|
536
|
+
return Boolean(
|
|
537
|
+
goalRequestsFileMutation(source, taskProfile) ||
|
|
538
|
+
/\b(?:create|deliver|export|generate|leave|make|output|prepare|produce|save|write)\b/i.test(
|
|
539
|
+
source
|
|
540
|
+
) ||
|
|
541
|
+
/\b(?:i|we)\s+(?:also\s+)?(?:need|want|would like)\b[^.\n;]{0,100}\b(?:answer|artifact|deck|document|handout|material|pdf|presentation|preview|report|sheet|slides?|workbook|worksheet)\b/i.test(
|
|
542
|
+
source
|
|
543
|
+
) ||
|
|
544
|
+
/\b(?:give|provide|return|send)\b[^.\n;]{0,80}\b(?:answer|artifact|deck|document|handout|material|pdf|presentation|preview|report|sheet|slides?|workbook|worksheet)\b/i.test(
|
|
545
|
+
source
|
|
546
|
+
) ||
|
|
547
|
+
/(?:创建|生成|输出|导出|保存|提供|需要|交付)/u.test(source)
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export function inferRequestedArtifactRequirements(goal = "", taskProfile = "") {
|
|
552
|
+
const source = stripForbiddenLanguage(String(goal || ""));
|
|
553
|
+
if (!artifactRequestHasOutputIntent(source, taskProfile)) return [];
|
|
554
|
+
|
|
555
|
+
const requirements = [];
|
|
556
|
+
const add = (requirement) => {
|
|
557
|
+
if (!requirement?.id || requirements.some((item) => item.id === requirement.id)) return;
|
|
558
|
+
requirements.push(requirement);
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
for (const format of REQUESTED_ARTIFACT_FORMATS) {
|
|
562
|
+
if (!format.pattern.test(source)) continue;
|
|
563
|
+
add({
|
|
564
|
+
id: `format:${format.extension}`,
|
|
565
|
+
kind: "format",
|
|
566
|
+
extension: format.extension,
|
|
567
|
+
description: format.description,
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const deckRequested = /\b(?:deck|presentation|slides?|slide deck|lecture deck)\b/i.test(source);
|
|
572
|
+
const editableRequested = /\b(?:editable|edit-friendly|native(?:ly)? editable)\b/i.test(source);
|
|
573
|
+
if (deckRequested && editableRequested) {
|
|
574
|
+
add({
|
|
575
|
+
id: "editable-presentation",
|
|
576
|
+
kind: "editable-presentation",
|
|
577
|
+
extensions: [".pptx", ".odp", ".key"],
|
|
578
|
+
description: "editable presentation deck",
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if (
|
|
583
|
+
/\bprintable\b/i.test(source) &&
|
|
584
|
+
/\b(?:answer|deck|document|handout|material|practice|sheet|slides?|worksheet)\b/i.test(source)
|
|
585
|
+
) {
|
|
586
|
+
add({
|
|
587
|
+
id: "printable-document",
|
|
588
|
+
kind: "printable-document",
|
|
589
|
+
extensions: [".pdf"],
|
|
590
|
+
description: "printable PDF material",
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
if (
|
|
595
|
+
/\b(?:helpful|high[- ]resolution|useful|visual)\s+preview\b|\b(?:image|png|rendered|screenshot)\s+preview\b|\bpreview\s+(?:image|png|render|screenshot)\b/i.test(
|
|
596
|
+
source
|
|
597
|
+
)
|
|
598
|
+
) {
|
|
599
|
+
add({
|
|
600
|
+
id: "visual-preview",
|
|
601
|
+
kind: "visual-preview",
|
|
602
|
+
extensions: [".png", ".jpg", ".jpeg", ".webp"],
|
|
603
|
+
description: "visual preview image",
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
if (/\b(?:practice sheet|worksheet|exercise sheet|learner handout)\b/i.test(source)) {
|
|
608
|
+
add({
|
|
609
|
+
id: "practice-material",
|
|
610
|
+
kind: "practice-material",
|
|
611
|
+
description: "separate practice or worksheet material",
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (/\b(?:answer key|answers?|worked solutions?|solutions? sheet)\b/i.test(source)) {
|
|
616
|
+
add({
|
|
617
|
+
id: "answer-material",
|
|
618
|
+
kind: "answer-material",
|
|
619
|
+
description: "separate answer or solution material",
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (
|
|
624
|
+
/\b(?:reproducible|repeatable)\b[^.\n;]{0,80}\b(?:build|generation|export|render)\b|\b(?:build|generation|export|render)\s+(?:entrypoint|script|command)\b/i.test(
|
|
625
|
+
source
|
|
626
|
+
)
|
|
627
|
+
) {
|
|
628
|
+
add({
|
|
629
|
+
id: "reproducible-build-entrypoint",
|
|
630
|
+
kind: "reproducible-build-entrypoint",
|
|
631
|
+
description: "reproducible build or export entrypoint",
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
return requirements.slice(0, 16);
|
|
636
|
+
}
|
|
637
|
+
|
|
524
638
|
function normalizedContractPath(value = "") {
|
|
525
639
|
return String(value || "")
|
|
526
640
|
.trim()
|
|
@@ -1581,6 +1695,10 @@ export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceC
|
|
|
1581
1695
|
excludedOutputPaths
|
|
1582
1696
|
).filter((item) => !inferredOutputPaths.includes(item) && !exactOutputPaths.includes(item));
|
|
1583
1697
|
const declaredSourceRoots = inferDeclaredSourceRoots(evidenceGoal);
|
|
1698
|
+
const requiredArtifactKinds = inferRequestedArtifactRequirements(
|
|
1699
|
+
positiveEvidenceGoal,
|
|
1700
|
+
taskProfile
|
|
1701
|
+
);
|
|
1584
1702
|
return {
|
|
1585
1703
|
version: 1,
|
|
1586
1704
|
outcome: compact(evidenceGoal || "Complete the requested task.", 500),
|
|
@@ -1589,6 +1707,7 @@ export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceC
|
|
|
1589
1707
|
requiredEvidence,
|
|
1590
1708
|
forbiddenActions: inferForbiddenActions(evidenceGoal),
|
|
1591
1709
|
exactOutputPaths,
|
|
1710
|
+
requiredArtifactKinds,
|
|
1592
1711
|
excludedOutputPaths,
|
|
1593
1712
|
artifactRoot,
|
|
1594
1713
|
exactInputPaths,
|
|
@@ -1817,6 +1936,190 @@ function resolveContractPath(commandCwd = process.cwd(), rawPath = "") {
|
|
|
1817
1936
|
return path.resolve(commandCwd || process.cwd(), text);
|
|
1818
1937
|
}
|
|
1819
1938
|
|
|
1939
|
+
const ARTIFACT_SCAN_IGNORED_DIRECTORIES = new Set([
|
|
1940
|
+
".aginti",
|
|
1941
|
+
".aginti-sessions",
|
|
1942
|
+
".git",
|
|
1943
|
+
".hg",
|
|
1944
|
+
".svn",
|
|
1945
|
+
"__pycache__",
|
|
1946
|
+
"node_modules",
|
|
1947
|
+
"vendor",
|
|
1948
|
+
]);
|
|
1949
|
+
|
|
1950
|
+
function taskArtifactFreshnessBoundary(state = {}) {
|
|
1951
|
+
const lifecycle = Array.isArray(state.meta?.goalContract?.lifecycle)
|
|
1952
|
+
? state.meta.goalContract.lifecycle
|
|
1953
|
+
: [];
|
|
1954
|
+
const lifecycleTimes = lifecycle
|
|
1955
|
+
.map((item) => Date.parse(String(item?.at || "")))
|
|
1956
|
+
.filter(Number.isFinite);
|
|
1957
|
+
if (lifecycleTimes.length) return Math.min(...lifecycleTimes) - 2000;
|
|
1958
|
+
const mutationTimes = (Array.isArray(state.meta?.projectVerification?.mutationHistory)
|
|
1959
|
+
? state.meta.projectVerification.mutationHistory
|
|
1960
|
+
: [])
|
|
1961
|
+
.map((item) => Date.parse(String(item?.at || "")))
|
|
1962
|
+
.filter(Number.isFinite);
|
|
1963
|
+
return mutationTimes.length ? Math.min(...mutationTimes) - 2000 : 0;
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
function taskArtifactMutationPaths(state = {}) {
|
|
1967
|
+
const paths = new Set();
|
|
1968
|
+
for (const mutation of Array.isArray(state.meta?.projectVerification?.mutationHistory)
|
|
1969
|
+
? state.meta.projectVerification.mutationHistory
|
|
1970
|
+
: []) {
|
|
1971
|
+
for (const candidate of Array.isArray(mutation?.paths) ? mutation.paths : []) {
|
|
1972
|
+
const normalized = normalizedContractPath(candidate);
|
|
1973
|
+
if (normalized) paths.add(normalized.toLocaleLowerCase("en-US"));
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
return paths;
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
function collectRequestedArtifactCandidates(commandCwd = process.cwd(), state = {}) {
|
|
1980
|
+
const root = path.resolve(commandCwd || process.cwd());
|
|
1981
|
+
const freshnessBoundary = taskArtifactFreshnessBoundary(state);
|
|
1982
|
+
const mutationPaths = taskArtifactMutationPaths(state);
|
|
1983
|
+
const candidates = [];
|
|
1984
|
+
const queue = [{ absolutePath: root, depth: 0 }];
|
|
1985
|
+
let visited = 0;
|
|
1986
|
+
while (queue.length && candidates.length < 3000 && visited < 6000) {
|
|
1987
|
+
const current = queue.shift();
|
|
1988
|
+
visited += 1;
|
|
1989
|
+
let entries = [];
|
|
1990
|
+
try {
|
|
1991
|
+
entries = fs.readdirSync(current.absolutePath, { withFileTypes: true });
|
|
1992
|
+
} catch {
|
|
1993
|
+
continue;
|
|
1994
|
+
}
|
|
1995
|
+
for (const entry of entries) {
|
|
1996
|
+
if (entry.isSymbolicLink()) continue;
|
|
1997
|
+
const absolutePath = path.join(current.absolutePath, entry.name);
|
|
1998
|
+
if (entry.isDirectory()) {
|
|
1999
|
+
if (
|
|
2000
|
+
current.depth < 7 &&
|
|
2001
|
+
!ARTIFACT_SCAN_IGNORED_DIRECTORIES.has(entry.name) &&
|
|
2002
|
+
!entry.name.startsWith(".cache")
|
|
2003
|
+
) {
|
|
2004
|
+
queue.push({ absolutePath, depth: current.depth + 1 });
|
|
2005
|
+
}
|
|
2006
|
+
continue;
|
|
2007
|
+
}
|
|
2008
|
+
if (!entry.isFile()) continue;
|
|
2009
|
+
let stat;
|
|
2010
|
+
try {
|
|
2011
|
+
stat = fs.statSync(absolutePath);
|
|
2012
|
+
} catch {
|
|
2013
|
+
continue;
|
|
2014
|
+
}
|
|
2015
|
+
if (!stat.size) continue;
|
|
2016
|
+
const relativePath = path.relative(root, absolutePath).replace(/\\/g, "/");
|
|
2017
|
+
const normalized = normalizedContractPath(relativePath).toLocaleLowerCase("en-US");
|
|
2018
|
+
const fresh = Boolean(
|
|
2019
|
+
mutationPaths.has(normalized) ||
|
|
2020
|
+
freshnessBoundary === 0 ||
|
|
2021
|
+
Number(stat.mtimeMs || 0) >= freshnessBoundary
|
|
2022
|
+
);
|
|
2023
|
+
candidates.push({
|
|
2024
|
+
path: relativePath,
|
|
2025
|
+
extension: path.extname(entry.name).toLocaleLowerCase("en-US"),
|
|
2026
|
+
basename: entry.name.toLocaleLowerCase("en-US"),
|
|
2027
|
+
bytes: stat.size,
|
|
2028
|
+
mtimeMs: Number(stat.mtimeMs || 0),
|
|
2029
|
+
fresh,
|
|
2030
|
+
});
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
return candidates;
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
function requestedArtifactRequirementMatches(requirement = {}, candidate = {}) {
|
|
2037
|
+
const extension = String(candidate.extension || "").toLocaleLowerCase("en-US");
|
|
2038
|
+
const basename = String(candidate.basename || "").toLocaleLowerCase("en-US");
|
|
2039
|
+
if (requirement.kind === "format") {
|
|
2040
|
+
return extension === String(requirement.extension || "").toLocaleLowerCase("en-US");
|
|
2041
|
+
}
|
|
2042
|
+
if (["editable-presentation", "printable-document", "visual-preview"].includes(requirement.kind)) {
|
|
2043
|
+
const extensions = new Set(
|
|
2044
|
+
(Array.isArray(requirement.extensions) ? requirement.extensions : [])
|
|
2045
|
+
.map((item) => String(item || "").toLocaleLowerCase("en-US"))
|
|
2046
|
+
);
|
|
2047
|
+
if (!extensions.has(extension)) return false;
|
|
2048
|
+
if (requirement.kind === "visual-preview") {
|
|
2049
|
+
return /(?:preview|contact[-_ ]?sheet|overview|thumbnail|render)/i.test(basename);
|
|
2050
|
+
}
|
|
2051
|
+
return true;
|
|
2052
|
+
}
|
|
2053
|
+
if (requirement.kind === "practice-material") {
|
|
2054
|
+
return /(?:practice|worksheet|exercise|handout|activity)/i.test(basename) &&
|
|
2055
|
+
/\.(?:docx|html?|md|odt|pdf|tex|txt)$/i.test(extension);
|
|
2056
|
+
}
|
|
2057
|
+
if (requirement.kind === "answer-material") {
|
|
2058
|
+
return /(?:answer|solution|worked[-_ ]?answers?)/i.test(basename) &&
|
|
2059
|
+
/\.(?:docx|html?|md|odt|pdf|tex|txt)$/i.test(extension);
|
|
2060
|
+
}
|
|
2061
|
+
if (requirement.kind === "reproducible-build-entrypoint") {
|
|
2062
|
+
return (
|
|
2063
|
+
/^(?:makefile|justfile)$/i.test(basename) ||
|
|
2064
|
+
/(?:^|[-_])(?:build|compile|export|generate|render)(?:[-_.]|$)/i.test(basename)
|
|
2065
|
+
) && /(?:^makefile$|^justfile$|\.(?:cjs|js|mjs|py|sh|ts)$)/i.test(basename);
|
|
2066
|
+
}
|
|
2067
|
+
return false;
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
export function evaluateRequestedArtifactRequirements(
|
|
2071
|
+
contract = {},
|
|
2072
|
+
{ commandCwd = process.cwd(), state = {} } = {}
|
|
2073
|
+
) {
|
|
2074
|
+
const requirements = Array.isArray(contract.requiredArtifactKinds)
|
|
2075
|
+
? contract.requiredArtifactKinds
|
|
2076
|
+
: [];
|
|
2077
|
+
if (!requirements.length) {
|
|
2078
|
+
return {
|
|
2079
|
+
ok: true,
|
|
2080
|
+
checked: false,
|
|
2081
|
+
requirements: [],
|
|
2082
|
+
satisfied: [],
|
|
2083
|
+
missing: [],
|
|
2084
|
+
candidates: [],
|
|
2085
|
+
reason: "No semantic artifact-set contract was inferred.",
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
2088
|
+
const candidates = collectRequestedArtifactCandidates(commandCwd, state);
|
|
2089
|
+
const requireFresh = contract.requiresFileMutation === true;
|
|
2090
|
+
const usableCandidates = requireFresh
|
|
2091
|
+
? candidates.filter((candidate) => candidate.fresh)
|
|
2092
|
+
: candidates;
|
|
2093
|
+
const satisfied = [];
|
|
2094
|
+
const missing = [];
|
|
2095
|
+
for (const requirement of requirements) {
|
|
2096
|
+
const matches = usableCandidates.filter((candidate) =>
|
|
2097
|
+
requestedArtifactRequirementMatches(requirement, candidate)
|
|
2098
|
+
);
|
|
2099
|
+
if (matches.length) {
|
|
2100
|
+
satisfied.push({
|
|
2101
|
+
...requirement,
|
|
2102
|
+
paths: matches.map((candidate) => candidate.path).slice(0, 12),
|
|
2103
|
+
});
|
|
2104
|
+
} else {
|
|
2105
|
+
missing.push(requirement);
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
return {
|
|
2109
|
+
ok: missing.length === 0,
|
|
2110
|
+
checked: true,
|
|
2111
|
+
requirements,
|
|
2112
|
+
satisfied,
|
|
2113
|
+
missing,
|
|
2114
|
+
candidates: usableCandidates.slice(0, 120),
|
|
2115
|
+
reason: missing.length
|
|
2116
|
+
? `Missing requested artifact deliverables: ${missing
|
|
2117
|
+
.map((item) => item.description || item.id)
|
|
2118
|
+
.join(", ")}.`
|
|
2119
|
+
: "Every requested artifact format and role has a fresh workspace deliverable.",
|
|
2120
|
+
};
|
|
2121
|
+
}
|
|
2122
|
+
|
|
1820
2123
|
const PROJECT_SOURCE_PATH_PATTERN =
|
|
1821
2124
|
/\.(?:c|cc|cpp|cxx|h|hh|hpp|cs|go|java|js|jsx|ts|tsx|mjs|cjs|kt|kts|php|py|r|rb|rs|scala|sh|sql|swift|vue|svelte|jl)$/i;
|
|
1822
2125
|
const PROJECT_SOURCE_MANIFEST_PATTERN =
|
|
@@ -2993,11 +3296,16 @@ export function evaluateScsSemanticContract(
|
|
|
2993
3296
|
const forbiddenTextTerms = Array.isArray(contract.forbiddenTextTerms) ? contract.forbiddenTextTerms : [];
|
|
2994
3297
|
const projectTestVerification = evaluateProjectTestVerification(events);
|
|
2995
3298
|
const executable = evaluateRequiredExecutableTerms(contract, { commandCwd, events, state });
|
|
3299
|
+
const requestedArtifacts = evaluateRequestedArtifactRequirements(contract, {
|
|
3300
|
+
commandCwd,
|
|
3301
|
+
state,
|
|
3302
|
+
});
|
|
2996
3303
|
if (
|
|
2997
3304
|
!exactOutputPaths.length &&
|
|
2998
3305
|
!requiredTextTerms.length &&
|
|
2999
3306
|
!requiredExecutableTerms.length &&
|
|
3000
|
-
!forbiddenTextTerms.length
|
|
3307
|
+
!forbiddenTextTerms.length &&
|
|
3308
|
+
!requestedArtifacts.checked
|
|
3001
3309
|
) {
|
|
3002
3310
|
return projectTestVerification.checked
|
|
3003
3311
|
? {
|
|
@@ -3009,18 +3317,23 @@ export function evaluateScsSemanticContract(
|
|
|
3009
3317
|
: { ok: true, checked: false, projectTestVerification, reason: "No semantic file contract was inferred." };
|
|
3010
3318
|
}
|
|
3011
3319
|
if (!exactOutputPaths.length) {
|
|
3012
|
-
const ok = executable.ok && projectTestVerification.ok;
|
|
3320
|
+
const ok = executable.ok && projectTestVerification.ok && requestedArtifacts.ok;
|
|
3013
3321
|
return {
|
|
3014
3322
|
ok,
|
|
3015
|
-
checked: executable.checked || projectTestVerification.checked,
|
|
3016
|
-
reason: !
|
|
3323
|
+
checked: executable.checked || projectTestVerification.checked || requestedArtifacts.checked,
|
|
3324
|
+
reason: !requestedArtifacts.ok
|
|
3325
|
+
? requestedArtifacts.reason
|
|
3326
|
+
: !executable.ok
|
|
3017
3327
|
? executable.reason
|
|
3018
3328
|
: !projectTestVerification.ok
|
|
3019
3329
|
? projectTestVerification.reason
|
|
3020
|
-
:
|
|
3330
|
+
: requestedArtifacts.checked
|
|
3331
|
+
? requestedArtifacts.reason
|
|
3332
|
+
: "Semantic text terms were inferred, but no exact output path was inferred for deterministic file inspection.",
|
|
3021
3333
|
requiredTextTerms,
|
|
3022
3334
|
requiredExecutableTerms,
|
|
3023
3335
|
forbiddenTextTerms,
|
|
3336
|
+
requestedArtifacts,
|
|
3024
3337
|
missingExecutableTerms: executable.missingExecutableTerms,
|
|
3025
3338
|
executableSourcePaths: executable.executableSourcePaths,
|
|
3026
3339
|
executable,
|
|
@@ -3048,7 +3361,8 @@ export function evaluateScsSemanticContract(
|
|
|
3048
3361
|
presentForbiddenText.length === 0 &&
|
|
3049
3362
|
executable.ok &&
|
|
3050
3363
|
sourceGrounding.ok &&
|
|
3051
|
-
projectTestVerification.ok
|
|
3364
|
+
projectTestVerification.ok &&
|
|
3365
|
+
requestedArtifacts.ok;
|
|
3052
3366
|
return {
|
|
3053
3367
|
ok,
|
|
3054
3368
|
checked: true,
|
|
@@ -3056,6 +3370,7 @@ export function evaluateScsSemanticContract(
|
|
|
3056
3370
|
requiredTextTerms,
|
|
3057
3371
|
requiredExecutableTerms,
|
|
3058
3372
|
forbiddenTextTerms,
|
|
3373
|
+
requestedArtifacts,
|
|
3059
3374
|
missingFiles,
|
|
3060
3375
|
missingRequiredText,
|
|
3061
3376
|
missingExecutableTerms: executable.missingExecutableTerms,
|
|
@@ -3085,6 +3400,7 @@ export function evaluateScsSemanticContract(
|
|
|
3085
3400
|
presentForbiddenText.length ? `Forbidden text terms present: ${presentForbiddenText.join(", ")}` : "",
|
|
3086
3401
|
!sourceGrounding.ok ? sourceGrounding.reason : "",
|
|
3087
3402
|
!projectTestVerification.ok ? projectTestVerification.reason : "",
|
|
3403
|
+
!requestedArtifacts.ok ? requestedArtifacts.reason : "",
|
|
3088
3404
|
]
|
|
3089
3405
|
.filter(Boolean)
|
|
3090
3406
|
.join("; "),
|
|
@@ -3619,6 +3935,7 @@ export function summarizeScsContractEvidence({ contract = {}, ledger = {}, evalu
|
|
|
3619
3935
|
})),
|
|
3620
3936
|
forbiddenActions: contract.forbiddenActions || [],
|
|
3621
3937
|
exactOutputPaths: contract.exactOutputPaths || [],
|
|
3938
|
+
requiredArtifactKinds: contract.requiredArtifactKinds || [],
|
|
3622
3939
|
exactInputPaths: contract.exactInputPaths || [],
|
|
3623
3940
|
requiredToolCalls: contract.requiredToolCalls || [],
|
|
3624
3941
|
requiredGitActions: contract.requiredGitActions || [],
|