@lazyingart/agintiflow 0.20.306 → 0.20.308
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.308",
|
|
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",
|
|
@@ -7471,6 +7471,212 @@ try {
|
|
|
7471
7471
|
precommitDocumentQualityState.meta.completionEvidenceRepair === undefined,
|
|
7472
7472
|
"a passing pre-commit document check did not clear its bounded repair marker"
|
|
7473
7473
|
);
|
|
7474
|
+
const currentGoalGeneratedDocumentState = {
|
|
7475
|
+
goal:
|
|
7476
|
+
"Read TASK.md, produce a verified PDF memo for the current task, and commit only the intentional work.",
|
|
7477
|
+
messages: [],
|
|
7478
|
+
meta: {
|
|
7479
|
+
taskProfile: "writing",
|
|
7480
|
+
goalContract: {
|
|
7481
|
+
revision: 5,
|
|
7482
|
+
activeGoalRevision: 5,
|
|
7483
|
+
activeGoal:
|
|
7484
|
+
"Read TASK.md, produce a verified PDF memo for the current task, and commit only the intentional work.",
|
|
7485
|
+
},
|
|
7486
|
+
projectVerification: {
|
|
7487
|
+
mutationRevision: 12,
|
|
7488
|
+
privateMutationRevision: 0,
|
|
7489
|
+
mutationHistory: [
|
|
7490
|
+
{
|
|
7491
|
+
revision: 8,
|
|
7492
|
+
at: "2026-09-01T09:00:00.000Z",
|
|
7493
|
+
toolName: "run_command",
|
|
7494
|
+
paths: ["stale-root.pdf"],
|
|
7495
|
+
goalRevision: 4,
|
|
7496
|
+
},
|
|
7497
|
+
{
|
|
7498
|
+
revision: 11,
|
|
7499
|
+
at: "2026-09-01T09:05:00.000Z",
|
|
7500
|
+
toolName: "write_file",
|
|
7501
|
+
paths: ["daily_memo.tex"],
|
|
7502
|
+
goalRevision: 5,
|
|
7503
|
+
},
|
|
7504
|
+
{
|
|
7505
|
+
revision: 12,
|
|
7506
|
+
at: "2026-09-01T09:06:00.000Z",
|
|
7507
|
+
toolName: "run_command",
|
|
7508
|
+
paths: [
|
|
7509
|
+
"daily_memo.pdf",
|
|
7510
|
+
"daily_memo.aux",
|
|
7511
|
+
"/tmp/escape.pdf",
|
|
7512
|
+
".env.pdf",
|
|
7513
|
+
"secrets/hidden.pdf",
|
|
7514
|
+
],
|
|
7515
|
+
goalRevision: 5,
|
|
7516
|
+
},
|
|
7517
|
+
],
|
|
7518
|
+
},
|
|
7519
|
+
},
|
|
7520
|
+
};
|
|
7521
|
+
let currentGoalDocumentValidatorInput = null;
|
|
7522
|
+
const currentGoalDocumentAssessment = await documentQualityCommitAssessment(
|
|
7523
|
+
currentGoalGeneratedDocumentState,
|
|
7524
|
+
"run_command",
|
|
7525
|
+
{ command: "git add -- daily_memo.tex daily_memo.pdf && git commit -m memo" },
|
|
7526
|
+
{
|
|
7527
|
+
commandCwd: missingArtifactCommitWorkspace,
|
|
7528
|
+
taskProfile: "writing",
|
|
7529
|
+
documentArtifactValidator: async (input) => {
|
|
7530
|
+
currentGoalDocumentValidatorInput = input;
|
|
7531
|
+
return {
|
|
7532
|
+
ok: true,
|
|
7533
|
+
checked: true,
|
|
7534
|
+
artifacts: [{ path: "daily_memo.pdf" }],
|
|
7535
|
+
defects: [],
|
|
7536
|
+
reason: "Independent document checks passed for daily_memo.pdf.",
|
|
7537
|
+
};
|
|
7538
|
+
},
|
|
7539
|
+
}
|
|
7540
|
+
);
|
|
7541
|
+
assert(
|
|
7542
|
+
currentGoalDocumentAssessment?.ok === true &&
|
|
7543
|
+
currentGoalDocumentValidatorInput?.exactOutputPaths?.includes(
|
|
7544
|
+
"daily_memo.pdf"
|
|
7545
|
+
) &&
|
|
7546
|
+
!currentGoalDocumentValidatorInput.exactOutputPaths.includes(
|
|
7547
|
+
"stale-root.pdf"
|
|
7548
|
+
) &&
|
|
7549
|
+
!currentGoalDocumentValidatorInput.exactOutputPaths.includes(
|
|
7550
|
+
"daily_memo.aux"
|
|
7551
|
+
) &&
|
|
7552
|
+
!currentGoalDocumentValidatorInput.exactOutputPaths.includes(
|
|
7553
|
+
"secrets/hidden.pdf"
|
|
7554
|
+
),
|
|
7555
|
+
`a current-goal generated root PDF was not discovered safely for pre-commit validation: ${JSON.stringify(
|
|
7556
|
+
currentGoalDocumentValidatorInput
|
|
7557
|
+
)}`
|
|
7558
|
+
);
|
|
7559
|
+
const unrelatedRootWorkspace = path.join(
|
|
7560
|
+
tempRoot,
|
|
7561
|
+
"unrelated-root-document"
|
|
7562
|
+
);
|
|
7563
|
+
await fs.mkdir(unrelatedRootWorkspace, { recursive: true });
|
|
7564
|
+
await fs.writeFile(
|
|
7565
|
+
path.join(unrelatedRootWorkspace, "unrelated.pdf"),
|
|
7566
|
+
"pre-existing root PDF that the current goal did not create",
|
|
7567
|
+
"utf8"
|
|
7568
|
+
);
|
|
7569
|
+
const unrelatedRootDocumentState = {
|
|
7570
|
+
goal:
|
|
7571
|
+
"Produce a verified PDF artifact for this task and commit the intentional work.",
|
|
7572
|
+
messages: [],
|
|
7573
|
+
meta: {
|
|
7574
|
+
taskProfile: "writing",
|
|
7575
|
+
goalContract: {
|
|
7576
|
+
revision: 6,
|
|
7577
|
+
activeGoalRevision: 6,
|
|
7578
|
+
activeGoal:
|
|
7579
|
+
"Produce a verified PDF artifact for this task and commit the intentional work.",
|
|
7580
|
+
},
|
|
7581
|
+
projectVerification: {
|
|
7582
|
+
mutationRevision: 4,
|
|
7583
|
+
privateMutationRevision: 0,
|
|
7584
|
+
mutationHistory: [
|
|
7585
|
+
{
|
|
7586
|
+
revision: 3,
|
|
7587
|
+
at: "2026-09-01T09:10:00.000Z",
|
|
7588
|
+
toolName: "run_command",
|
|
7589
|
+
paths: ["unrelated.pdf"],
|
|
7590
|
+
goalRevision: 5,
|
|
7591
|
+
},
|
|
7592
|
+
{
|
|
7593
|
+
revision: 4,
|
|
7594
|
+
at: "2026-09-01T09:12:00.000Z",
|
|
7595
|
+
toolName: "write_file",
|
|
7596
|
+
paths: ["notes.tex"],
|
|
7597
|
+
goalRevision: 6,
|
|
7598
|
+
},
|
|
7599
|
+
],
|
|
7600
|
+
},
|
|
7601
|
+
},
|
|
7602
|
+
};
|
|
7603
|
+
let unrelatedRootValidatorInput = null;
|
|
7604
|
+
const unrelatedRootAssessment = await documentQualityCommitAssessment(
|
|
7605
|
+
unrelatedRootDocumentState,
|
|
7606
|
+
"run_command",
|
|
7607
|
+
{ command: "git add -- notes.tex && git commit -m notes" },
|
|
7608
|
+
{
|
|
7609
|
+
commandCwd: unrelatedRootWorkspace,
|
|
7610
|
+
taskProfile: "writing",
|
|
7611
|
+
documentArtifactValidator: async (input) => {
|
|
7612
|
+
unrelatedRootValidatorInput = input;
|
|
7613
|
+
return {
|
|
7614
|
+
ok: false,
|
|
7615
|
+
checked: true,
|
|
7616
|
+
artifacts: [],
|
|
7617
|
+
defects: [{ code: "missing-document-artifact" }],
|
|
7618
|
+
reason: "No readable DOCX or PDF artifact was found for the completed document task.",
|
|
7619
|
+
};
|
|
7620
|
+
},
|
|
7621
|
+
}
|
|
7622
|
+
);
|
|
7623
|
+
assert(
|
|
7624
|
+
unrelatedRootAssessment?.ok === false &&
|
|
7625
|
+
unrelatedRootAssessment.category === "document-quality-incomplete" &&
|
|
7626
|
+
!unrelatedRootValidatorInput?.exactOutputPaths?.includes(
|
|
7627
|
+
"unrelated.pdf"
|
|
7628
|
+
),
|
|
7629
|
+
`an unrelated pre-existing root PDF was accepted as current-goal evidence: ${JSON.stringify(
|
|
7630
|
+
unrelatedRootValidatorInput
|
|
7631
|
+
)}`
|
|
7632
|
+
);
|
|
7633
|
+
const semanticGateDocumentState = structuredClone(
|
|
7634
|
+
currentGoalGeneratedDocumentState
|
|
7635
|
+
);
|
|
7636
|
+
semanticGateDocumentState.meta.scs = {
|
|
7637
|
+
taskContract: { exactInputPaths: ["TASK.md"] },
|
|
7638
|
+
};
|
|
7639
|
+
let semanticGateValidatorInput = null;
|
|
7640
|
+
const semanticGateAssessment = await documentQualityCommitAssessment(
|
|
7641
|
+
semanticGateDocumentState,
|
|
7642
|
+
"run_command",
|
|
7643
|
+
{ command: "git add -- daily_memo.tex daily_memo.pdf && git commit -m memo" },
|
|
7644
|
+
{
|
|
7645
|
+
commandCwd: missingArtifactCommitWorkspace,
|
|
7646
|
+
taskProfile: "writing",
|
|
7647
|
+
documentArtifactValidator: async (input) => {
|
|
7648
|
+
semanticGateValidatorInput = input;
|
|
7649
|
+
return {
|
|
7650
|
+
ok: false,
|
|
7651
|
+
checked: true,
|
|
7652
|
+
artifacts: [{ path: "daily_memo.pdf" }],
|
|
7653
|
+
defects: [{
|
|
7654
|
+
code: "source-topic-coverage-incomplete",
|
|
7655
|
+
path: "daily_memo.pdf",
|
|
7656
|
+
message: "The memo omitted current source-status facts.",
|
|
7657
|
+
}],
|
|
7658
|
+
reason: "daily_memo.pdf: The memo omitted current source-status facts.",
|
|
7659
|
+
};
|
|
7660
|
+
},
|
|
7661
|
+
}
|
|
7662
|
+
);
|
|
7663
|
+
assert(
|
|
7664
|
+
semanticGateAssessment?.ok === false &&
|
|
7665
|
+
semanticGateAssessment.category === "document-quality-incomplete" &&
|
|
7666
|
+
semanticGateDocumentState.meta.completionEvidenceRepair
|
|
7667
|
+
?.artifactQualityRepairRequired === true &&
|
|
7668
|
+
semanticGateDocumentState.meta.completionEvidenceRepair
|
|
7669
|
+
?.documentArtifactGenerationRequired !== true &&
|
|
7670
|
+
semanticGateValidatorInput?.exactOutputPaths?.includes(
|
|
7671
|
+
"daily_memo.pdf"
|
|
7672
|
+
) &&
|
|
7673
|
+
semanticGateValidatorInput?.exactInputPaths?.includes("TASK.md"),
|
|
7674
|
+
`current-goal artifact discovery bypassed source/status quality gates or reopened the missing-artifact loop: ${JSON.stringify({
|
|
7675
|
+
assessment: semanticGateAssessment,
|
|
7676
|
+
input: semanticGateValidatorInput,
|
|
7677
|
+
repair: semanticGateDocumentState.meta.completionEvidenceRepair,
|
|
7678
|
+
})}`
|
|
7679
|
+
);
|
|
7474
7680
|
await fs.writeFile(
|
|
7475
7681
|
path.join(missingArtifactCommitWorkspace, "TASK.md"),
|
|
7476
7682
|
[
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from "../src/agent-runner.js";
|
|
12
12
|
import { resolveRuntimeConfig } from "../src/config.js";
|
|
13
13
|
import { SessionStore } from "../src/session-store.js";
|
|
14
|
-
import { finishResultClaimsIncompleteWork } from "../src/scs-evidence.js";
|
|
14
|
+
import { deriveScsTaskContract, finishResultClaimsIncompleteWork } from "../src/scs-evidence.js";
|
|
15
15
|
|
|
16
16
|
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
17
17
|
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "agintiflow-truthful-completion-"));
|
|
@@ -198,6 +198,9 @@ async function runCase({
|
|
|
198
198
|
id,
|
|
199
199
|
goal,
|
|
200
200
|
taskProfile = "auto",
|
|
201
|
+
provider = "openai",
|
|
202
|
+
model = "scripted-model",
|
|
203
|
+
routingMode = "manual",
|
|
201
204
|
responses,
|
|
202
205
|
allowShellTool = false,
|
|
203
206
|
allowFileTools = false,
|
|
@@ -205,6 +208,9 @@ async function runCase({
|
|
|
205
208
|
executionTier = "",
|
|
206
209
|
maxOutputTokens = undefined,
|
|
207
210
|
resume = false,
|
|
211
|
+
runtimePatch = undefined,
|
|
212
|
+
expectedRuntimeRevision = undefined,
|
|
213
|
+
providerReadinessMode = undefined,
|
|
208
214
|
setup = null,
|
|
209
215
|
scsActive = false,
|
|
210
216
|
}) {
|
|
@@ -215,11 +221,20 @@ async function runCase({
|
|
|
215
221
|
if (typeof setup === "function") await setup(workspace);
|
|
216
222
|
const calls = [];
|
|
217
223
|
const client = scriptedClient([...responses], calls);
|
|
224
|
+
const factoryConfigs = [];
|
|
225
|
+
const clientFactory = async (runtimeConfig = {}) => {
|
|
226
|
+
factoryConfigs.push({
|
|
227
|
+
provider: runtimeConfig.provider,
|
|
228
|
+
model: runtimeConfig.model,
|
|
229
|
+
});
|
|
230
|
+
return client;
|
|
231
|
+
};
|
|
232
|
+
clientFactory.agintiDeterministicTest = true;
|
|
218
233
|
const config = resolveRuntimeConfig(
|
|
219
234
|
{
|
|
220
|
-
provider
|
|
221
|
-
routingMode
|
|
222
|
-
model
|
|
235
|
+
provider,
|
|
236
|
+
routingMode,
|
|
237
|
+
model,
|
|
223
238
|
goal,
|
|
224
239
|
taskProfile,
|
|
225
240
|
executionTier,
|
|
@@ -236,9 +251,9 @@ async function runCase({
|
|
|
236
251
|
{
|
|
237
252
|
baseDir: workspace,
|
|
238
253
|
packageDir: repoRoot,
|
|
239
|
-
provider
|
|
240
|
-
routingMode
|
|
241
|
-
model
|
|
254
|
+
provider,
|
|
255
|
+
routingMode,
|
|
256
|
+
model,
|
|
242
257
|
executionTier,
|
|
243
258
|
sessionId: id,
|
|
244
259
|
resume: resume ? id : "",
|
|
@@ -255,13 +270,13 @@ async function runCase({
|
|
|
255
270
|
allowMcpTools: false,
|
|
256
271
|
allowParallelScouts: false,
|
|
257
272
|
enableScs: scsActive ? "auto" : "off",
|
|
258
|
-
clientFactory
|
|
273
|
+
clientFactory,
|
|
259
274
|
}
|
|
260
275
|
);
|
|
261
276
|
Object.assign(config, {
|
|
262
277
|
apiKey: "scripted-test-only",
|
|
263
278
|
resume: resume ? id : "",
|
|
264
|
-
clientFactory
|
|
279
|
+
clientFactory,
|
|
265
280
|
sessionsDir,
|
|
266
281
|
projectSessionsDir,
|
|
267
282
|
useDockerSandbox: false,
|
|
@@ -283,17 +298,51 @@ async function runCase({
|
|
|
283
298
|
: undefined,
|
|
284
299
|
modelTimeoutMs: 1_000,
|
|
285
300
|
...(executionTier ? { executionTier, executionPolicy: { tier: executionTier, requiresPlan: false, reason: "Scripted completion smoke." } } : {}),
|
|
301
|
+
...(providerReadinessMode ? { providerReadinessMode } : {}),
|
|
302
|
+
...(runtimePatch ? { runtimePatch } : {}),
|
|
303
|
+
...(expectedRuntimeRevision !== undefined ? { expectedRuntimeRevision } : {}),
|
|
286
304
|
});
|
|
287
305
|
const result = await runAgent(config);
|
|
288
306
|
const store = new SessionStore(sessionsDir, id, { projectRoot: workspace, commandCwd: workspace, projectSessionsDir });
|
|
289
307
|
return {
|
|
290
308
|
result,
|
|
291
309
|
calls,
|
|
310
|
+
factoryConfigs,
|
|
292
311
|
events: await store.loadEvents(),
|
|
293
312
|
state: await store.loadState(),
|
|
294
313
|
};
|
|
295
314
|
}
|
|
296
315
|
|
|
316
|
+
function providerRuntimePatch(provider, model) {
|
|
317
|
+
return {
|
|
318
|
+
provider,
|
|
319
|
+
model,
|
|
320
|
+
routingMode: "manual",
|
|
321
|
+
routeProvider: provider,
|
|
322
|
+
routeModel: model,
|
|
323
|
+
mainProvider: provider,
|
|
324
|
+
mainModel: model,
|
|
325
|
+
spareProvider: provider,
|
|
326
|
+
spareModel: model,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function scopedTaskGoal(request, artifactRoot) {
|
|
331
|
+
return [
|
|
332
|
+
"User request:",
|
|
333
|
+
request,
|
|
334
|
+
"",
|
|
335
|
+
`AGINTI_EVIDENCE_SCOPE_JSON: ${JSON.stringify({
|
|
336
|
+
mode: "task",
|
|
337
|
+
request,
|
|
338
|
+
artifact_root: artifactRoot,
|
|
339
|
+
})}`,
|
|
340
|
+
"",
|
|
341
|
+
"Artifact contract:",
|
|
342
|
+
"- If no file is produced, use an empty artifacts list.",
|
|
343
|
+
].join("\n");
|
|
344
|
+
}
|
|
345
|
+
|
|
297
346
|
try {
|
|
298
347
|
const explanation = await runCase({
|
|
299
348
|
id: "ordinary-explanation",
|
|
@@ -410,6 +459,125 @@ try {
|
|
|
410
459
|
assert.equal(quotedChatClassification.result.result, '{"intent":"generation_only","publish":false}');
|
|
411
460
|
assert(!quotedChatClassification.events.some((event) => event.type === "completion.evidence_rejected"));
|
|
412
461
|
|
|
462
|
+
const providerSwitchSessionId = "provider-switch-resume-contract";
|
|
463
|
+
const providerSwitchFirstTurn = await runCase({
|
|
464
|
+
id: providerSwitchSessionId,
|
|
465
|
+
goal: "Create provider-switch-proof.md with the exact text provider switch proof.",
|
|
466
|
+
taskProfile: "auto",
|
|
467
|
+
provider: "localllm",
|
|
468
|
+
model: "localllm-fast",
|
|
469
|
+
providerReadinessMode: "deterministic-test",
|
|
470
|
+
allowFileTools: true,
|
|
471
|
+
responses: [
|
|
472
|
+
assistant("", [
|
|
473
|
+
toolCall("write-provider-switch-proof", "write_file", {
|
|
474
|
+
path: "provider-switch-proof.md",
|
|
475
|
+
mode: "create",
|
|
476
|
+
content: "provider switch proof\n",
|
|
477
|
+
}),
|
|
478
|
+
]),
|
|
479
|
+
assistant("", [
|
|
480
|
+
toolCall("finish-provider-switch-proof", "finish", {
|
|
481
|
+
result: "Created provider-switch-proof.md.",
|
|
482
|
+
}),
|
|
483
|
+
]),
|
|
484
|
+
],
|
|
485
|
+
});
|
|
486
|
+
assert.equal(providerSwitchFirstTurn.result.stopped, undefined);
|
|
487
|
+
assert.equal(providerSwitchFirstTurn.state.meta?.runtimeConfig?.provider, "localllm");
|
|
488
|
+
assert.equal(providerSwitchFirstTurn.state.meta?.runtimeConfig?.model, "localllm-fast");
|
|
489
|
+
|
|
490
|
+
const providerSwitchSecondTurn = await runCase({
|
|
491
|
+
id: providerSwitchSessionId,
|
|
492
|
+
goal: "Resume this exact session with the default provider and return exactly: DEEPSEEK_RESUME_OK",
|
|
493
|
+
taskProfile: "auto",
|
|
494
|
+
provider: "deepseek",
|
|
495
|
+
model: "deepseek-v4-flash",
|
|
496
|
+
resume: true,
|
|
497
|
+
runtimePatch: providerRuntimePatch("deepseek", "deepseek-v4-flash"),
|
|
498
|
+
expectedRuntimeRevision: providerSwitchFirstTurn.state.meta.runtimeConfig.revision,
|
|
499
|
+
responses: [
|
|
500
|
+
assistant("", [
|
|
501
|
+
toolCall("finish-provider-switch-deepseek", "finish", {
|
|
502
|
+
result: "DEEPSEEK_RESUME_OK",
|
|
503
|
+
}),
|
|
504
|
+
]),
|
|
505
|
+
],
|
|
506
|
+
});
|
|
507
|
+
assert.equal(providerSwitchSecondTurn.result.stopped, undefined);
|
|
508
|
+
assert.equal(providerSwitchSecondTurn.result.result, "DEEPSEEK_RESUME_OK");
|
|
509
|
+
assert.equal(providerSwitchSecondTurn.state.meta?.runtimeConfig?.provider, "deepseek");
|
|
510
|
+
assert.equal(providerSwitchSecondTurn.state.meta?.runtimeConfig?.model, "deepseek-v4-flash");
|
|
511
|
+
assert.equal(
|
|
512
|
+
providerSwitchSecondTurn.events.filter(
|
|
513
|
+
(event) => event.type === "session.runtime_resolved" && event.data?.provider === "deepseek"
|
|
514
|
+
).length,
|
|
515
|
+
1,
|
|
516
|
+
"explicit DeepSeek resume did not persist a provider switch"
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
const forcedLocalRequest =
|
|
520
|
+
"Resume this exact session and return exactly: LOCALLLM_FORCED_RESUME_OK Do not create or modify any file.";
|
|
521
|
+
const forcedLocalGoal = scopedTaskGoal(
|
|
522
|
+
forcedLocalRequest,
|
|
523
|
+
path.join(tempRoot, "artifacts", "provider-switch-resume-contract")
|
|
524
|
+
);
|
|
525
|
+
const forcedLocalContract = deriveScsTaskContract({ goal: forcedLocalGoal, taskProfile: "auto" });
|
|
526
|
+
assert.equal(
|
|
527
|
+
forcedLocalContract.requiresExternalEvidence,
|
|
528
|
+
false,
|
|
529
|
+
"a forbidden file-mutation clause made a pure response-only resume require external evidence"
|
|
530
|
+
);
|
|
531
|
+
assert.deepEqual(forcedLocalContract.requiredEvidence, []);
|
|
532
|
+
assert.deepEqual(forcedLocalContract.exactOutputPaths, []);
|
|
533
|
+
assert(
|
|
534
|
+
forcedLocalContract.forbiddenActions.some((item) => /create or modify any file/i.test(item)),
|
|
535
|
+
"forbidden file mutation was not retained as a guardrail"
|
|
536
|
+
);
|
|
537
|
+
|
|
538
|
+
const forcedLocalResume = await runCase({
|
|
539
|
+
id: providerSwitchSessionId,
|
|
540
|
+
goal: forcedLocalGoal,
|
|
541
|
+
taskProfile: "auto",
|
|
542
|
+
provider: "localllm",
|
|
543
|
+
model: "localllm-fast",
|
|
544
|
+
providerReadinessMode: "deterministic-test",
|
|
545
|
+
resume: true,
|
|
546
|
+
runtimePatch: providerRuntimePatch("localllm", "localllm-fast"),
|
|
547
|
+
expectedRuntimeRevision: providerSwitchSecondTurn.state.meta.runtimeConfig.revision,
|
|
548
|
+
responses: [
|
|
549
|
+
assistant("", [
|
|
550
|
+
toolCall("finish-provider-switch-localllm", "finish", {
|
|
551
|
+
result: "LOCALLLM_FORCED_RESUME_OK",
|
|
552
|
+
}),
|
|
553
|
+
]),
|
|
554
|
+
],
|
|
555
|
+
});
|
|
556
|
+
assert.equal(forcedLocalResume.result.stopped, undefined);
|
|
557
|
+
assert.equal(forcedLocalResume.result.result, "LOCALLLM_FORCED_RESUME_OK");
|
|
558
|
+
assert.equal(forcedLocalResume.calls.length, 1);
|
|
559
|
+
assert.deepEqual(forcedLocalResume.factoryConfigs, [{ provider: "localllm", model: "localllm-fast" }]);
|
|
560
|
+
assert.equal(forcedLocalResume.state.meta?.runtimeConfig?.provider, "localllm");
|
|
561
|
+
assert.equal(forcedLocalResume.state.meta?.runtimeConfig?.model, "localllm-fast");
|
|
562
|
+
assert.equal(
|
|
563
|
+
forcedLocalResume.events.filter(
|
|
564
|
+
(event) =>
|
|
565
|
+
event.type === "session.runtime_resolved" &&
|
|
566
|
+
event.data?.provider === "localllm" &&
|
|
567
|
+
event.data?.model === "localllm-fast"
|
|
568
|
+
).length,
|
|
569
|
+
1,
|
|
570
|
+
"explicit LocalLLM resume did not persist the forced provider/model switch"
|
|
571
|
+
);
|
|
572
|
+
assert(
|
|
573
|
+
!forcedLocalResume.events.some(
|
|
574
|
+
(event) =>
|
|
575
|
+
event.type === "completion.evidence_rejected" &&
|
|
576
|
+
/ledger is empty/i.test(String(event.data?.reason || ""))
|
|
577
|
+
),
|
|
578
|
+
"pure LocalLLM resume was rejected for missing external evidence"
|
|
579
|
+
);
|
|
580
|
+
|
|
413
581
|
const proseOnlyAction = await runCase({
|
|
414
582
|
id: "prose-only-action",
|
|
415
583
|
goal: "Run pwd and report the output.",
|
package/src/agent-runner.js
CHANGED
|
@@ -10257,6 +10257,7 @@ export async function documentQualityCommitAssessment(
|
|
|
10257
10257
|
? contract.exactOutputPaths
|
|
10258
10258
|
: []),
|
|
10259
10259
|
...exactOutputPathsForState(state),
|
|
10260
|
+
...currentGoalDocumentArtifactPathsForState(state),
|
|
10260
10261
|
...(Array.isArray(config.taskOwnedCommitPaths)
|
|
10261
10262
|
? config.taskOwnedCommitPaths
|
|
10262
10263
|
: []),
|
|
@@ -14185,6 +14186,46 @@ function exactOutputPathsForState(state = {}) {
|
|
|
14185
14186
|
], exclusions).slice(0, 32);
|
|
14186
14187
|
}
|
|
14187
14188
|
|
|
14189
|
+
function currentGoalDocumentArtifactPathsForState(state = {}) {
|
|
14190
|
+
const verification = state.meta?.projectVerification || {};
|
|
14191
|
+
const history = Array.isArray(verification.mutationHistory)
|
|
14192
|
+
? verification.mutationHistory
|
|
14193
|
+
: [];
|
|
14194
|
+
const currentGoalRevision = Math.max(
|
|
14195
|
+
0,
|
|
14196
|
+
Number(state.meta?.goalContract?.revision || 0)
|
|
14197
|
+
);
|
|
14198
|
+
if (currentGoalRevision <= 0) return [];
|
|
14199
|
+
const candidates = [];
|
|
14200
|
+
const seen = new Set();
|
|
14201
|
+
for (const mutation of history) {
|
|
14202
|
+
if (Number(mutation?.goalRevision || 0) !== currentGoalRevision) continue;
|
|
14203
|
+
const paths = [
|
|
14204
|
+
...(Array.isArray(mutation?.paths) ? mutation.paths : []),
|
|
14205
|
+
...(Array.isArray(mutation?.projectMutationPaths)
|
|
14206
|
+
? mutation.projectMutationPaths
|
|
14207
|
+
: []),
|
|
14208
|
+
...(Array.isArray(mutation?.verifiedGeneratedOutputPaths)
|
|
14209
|
+
? mutation.verifiedGeneratedOutputPaths
|
|
14210
|
+
: []),
|
|
14211
|
+
];
|
|
14212
|
+
for (const value of paths) {
|
|
14213
|
+
const candidate = safeTaskOwnedCommitPath(value);
|
|
14214
|
+
if (
|
|
14215
|
+
!candidate ||
|
|
14216
|
+
!/\.(?:docx|pdf)$/iu.test(candidate) ||
|
|
14217
|
+
seen.has(candidate)
|
|
14218
|
+
) {
|
|
14219
|
+
continue;
|
|
14220
|
+
}
|
|
14221
|
+
seen.add(candidate);
|
|
14222
|
+
candidates.push(candidate);
|
|
14223
|
+
if (candidates.length >= 16) return candidates;
|
|
14224
|
+
}
|
|
14225
|
+
}
|
|
14226
|
+
return candidates;
|
|
14227
|
+
}
|
|
14228
|
+
|
|
14188
14229
|
function exactInputPathsForState(state = {}) {
|
|
14189
14230
|
const scsInputPaths = Array.isArray(state.meta?.scs?.taskContract?.exactInputPaths)
|
|
14190
14231
|
? state.meta.scs.taskContract.exactInputPaths.filter(Boolean)
|
|
@@ -21389,6 +21430,7 @@ async function completionEvidenceDecision({ config, state, store, observers, ste
|
|
|
21389
21430
|
const documentExactOutputPaths = [
|
|
21390
21431
|
...(assessment.contract?.exactOutputPaths || []),
|
|
21391
21432
|
...exactOutputPathsForState(state),
|
|
21433
|
+
...currentGoalDocumentArtifactPathsForState(state),
|
|
21392
21434
|
];
|
|
21393
21435
|
const documentContractText = `${completionContractGoal(config, state)}\n${candidateResult}`;
|
|
21394
21436
|
const documentDeliverableRequested =
|
package/src/scs-evidence.js
CHANGED
|
@@ -2059,7 +2059,8 @@ export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceC
|
|
|
2059
2059
|
if (requiredGitActions.length && !requirementCategories.includes("git")) {
|
|
2060
2060
|
requirementCategories.push("git");
|
|
2061
2061
|
}
|
|
2062
|
-
const requiresExternalEvidence =
|
|
2062
|
+
const requiresExternalEvidence =
|
|
2063
|
+
requirementCategories.length > 0 || requiredToolCalls.length > 0 || goalRequiresEvidence(positiveEvidenceGoal, taskProfile);
|
|
2063
2064
|
const requiredEvidence = requirementCategories.map((category) => ({
|
|
2064
2065
|
id: category,
|
|
2065
2066
|
category,
|