@lazyingart/agintiflow 0.20.211 → 0.20.212
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.
|
@@ -75,3 +75,24 @@ The incident established two general contracts:
|
|
|
75
75
|
canvas/download filename derived from the task title and source purpose.
|
|
76
76
|
Internal collision identifiers are short suffixes, never the leading or only
|
|
77
77
|
visible filename information.
|
|
78
|
+
|
|
79
|
+
### QA repair continuity and evidence intent
|
|
80
|
+
|
|
81
|
+
`qa-incident-metrics-001` passed after two reusable runtime fixes. A normal,
|
|
82
|
+
underspecified QA prompt led the DeepSeek-backed agent to reproduce and diagnose
|
|
83
|
+
compound-duration parsing, percentile interpolation/mutation, and deterministic
|
|
84
|
+
summary-order defects. The first partial patch advanced the mutation revision,
|
|
85
|
+
but the runtime then forgot the retained failing test and prematurely reduced
|
|
86
|
+
the tool surface to test-only mode. Source-next restored the failed-test repair
|
|
87
|
+
state until a fresh current-revision test passed, allowing the same durable
|
|
88
|
+
session to finish the coherent patch, add regressions, run 15 tests at 100%
|
|
89
|
+
statement coverage, clean debris, and commit `667891f`.
|
|
90
|
+
|
|
91
|
+
Independent `pytest` and the hidden `qa_incident_metrics_contract.py` checker
|
|
92
|
+
both passed. The run also exposed an evidence-intent false positive: `figure
|
|
93
|
+
out` and `clean up generated test debris` were interpreted as a request for a
|
|
94
|
+
canvas artifact. Evidence inference now excludes those non-production phrases
|
|
95
|
+
while retaining the artifact gate for real generated figures. Exact session
|
|
96
|
+
evidence remains in
|
|
97
|
+
`~/.agintiflow/sessions/aginti-qa-incident-metrics-001/events.jsonl` and the
|
|
98
|
+
machine ledger records the run as `passed_after_fix`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.212",
|
|
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",
|
|
@@ -74,6 +74,12 @@ function cellWidth(value = "") {
|
|
|
74
74
|
return [...String(value || "").replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "")].reduce((sum, char) => sum + charCellWidth(char), 0);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
function stripTerminalControls(value = "") {
|
|
78
|
+
return String(value || "")
|
|
79
|
+
.replace(/\x1b\][\s\S]*?(?:\x07|\x1b\\)/g, "")
|
|
80
|
+
.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "");
|
|
81
|
+
}
|
|
82
|
+
|
|
77
83
|
function runChat(inputText) {
|
|
78
84
|
return runCli(
|
|
79
85
|
["chat", "--provider", "mock", "--routing", "manual", "--profile", "code", "--headless", "--sandbox-mode", "host"],
|
|
@@ -596,7 +602,7 @@ try {
|
|
|
596
602
|
animated: false,
|
|
597
603
|
webAppUrl: "http://127.0.0.1:3210",
|
|
598
604
|
}).join("\n");
|
|
599
|
-
if (!launchHeaderWithWeb.includes("webapp: http://127.0.0.1:3210")) {
|
|
605
|
+
if (!stripTerminalControls(launchHeaderWithWeb).includes("webapp: http://127.0.0.1:3210")) {
|
|
600
606
|
throw new Error("launch header did not render the active webapp URL in the tagline row");
|
|
601
607
|
}
|
|
602
608
|
const launchHeaderWithWebError = buildLaunchHeaderLines({
|
|
@@ -749,17 +755,21 @@ try {
|
|
|
749
755
|
throw new Error("terminal prompt layout did not render live input queue and cwd footer");
|
|
750
756
|
}
|
|
751
757
|
const hintPromptLayout = buildPromptLayout("/mo", 3, 90, 24, { suggestions: ["/models", "/model"], suggestionIndex: 1 });
|
|
752
|
-
const
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
758
|
+
const hintRaw = hintPromptLayout.renderedRows.join("\n");
|
|
759
|
+
const hintText = stripTerminalControls(hintRaw);
|
|
760
|
+
const selectedHintRendered =
|
|
761
|
+
hintText.includes("hint /models >/model") ||
|
|
762
|
+
(hintText.includes("hint /models /model") && hintRaw.includes("\x1b[1m/model\x1b[0m"));
|
|
763
|
+
if (!hintText.includes(" user> /mo") || !selectedHintRendered) {
|
|
764
|
+
throw new Error(`terminal prompt layout did not align user and hint text columns: ${JSON.stringify(hintText)}`);
|
|
757
765
|
}
|
|
758
766
|
const exactHintLayout = buildPromptLayout("/model", 6, 90, 24);
|
|
759
|
-
const
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
767
|
+
const exactHintRaw = exactHintLayout.renderedRows.join("\n");
|
|
768
|
+
const exactHintText = stripTerminalControls(exactHintRaw);
|
|
769
|
+
const exactHintSelected =
|
|
770
|
+
exactHintText.includes("hint >/model") ||
|
|
771
|
+
(exactHintText.includes("hint /model") && exactHintRaw.includes("\x1b[1m/model\x1b[0m"));
|
|
772
|
+
if (!exactHintSelected || exactHintText.includes("/models")) {
|
|
763
773
|
throw new Error("exact slash commands should not show broader prefix matches");
|
|
764
774
|
}
|
|
765
775
|
if (classifyEscapeAction({ active: false }) !== "noop") {
|
|
@@ -986,6 +986,14 @@ const generatedReviewContract = deriveScsTaskContract({
|
|
|
986
986
|
].join("\n"),
|
|
987
987
|
taskProfile: "review",
|
|
988
988
|
});
|
|
989
|
+
const qaCleanupContract = deriveScsTaskContract({
|
|
990
|
+
goal: "Inspect the project, figure out what is actually wrong, fix the failing tests, clean up generated test debris, and commit only the intentional fix.",
|
|
991
|
+
taskProfile: "qa",
|
|
992
|
+
});
|
|
993
|
+
const generatedFigureContract = deriveScsTaskContract({
|
|
994
|
+
goal: "Generate a publication-ready figure that compares the two repair strategies.",
|
|
995
|
+
taskProfile: "design",
|
|
996
|
+
});
|
|
989
997
|
assert(
|
|
990
998
|
!explainCodeContract.requiresExternalEvidence,
|
|
991
999
|
"code profile alone should not force external evidence for a pure explanation"
|
|
@@ -1037,6 +1045,16 @@ assert(
|
|
|
1037
1045
|
!generatedReviewContract.requiredEvidence.some((item) => item.category === "artifact"),
|
|
1038
1046
|
"review profile should not turn review-format boilerplate into file/artifact production requirements"
|
|
1039
1047
|
);
|
|
1048
|
+
assert(
|
|
1049
|
+
qaCleanupContract.requiredEvidence.some((item) => item.category === "command") &&
|
|
1050
|
+
qaCleanupContract.requiredEvidence.some((item) => item.category === "git") &&
|
|
1051
|
+
!qaCleanupContract.requiredEvidence.some((item) => item.category === "artifact"),
|
|
1052
|
+
"cleaning generated test debris should not invent an unrelated artifact-delivery requirement"
|
|
1053
|
+
);
|
|
1054
|
+
assert(
|
|
1055
|
+
generatedFigureContract.requiredEvidence.some((item) => item.category === "artifact"),
|
|
1056
|
+
"tightening QA intent phrases removed the real generated-figure artifact gate"
|
|
1057
|
+
);
|
|
1040
1058
|
const fileOnlyLedger = buildScsEvidenceLedger({
|
|
1041
1059
|
context: { events: [{ type: "file.changed", data: { path: "src/app.js" } }] },
|
|
1042
1060
|
});
|
|
@@ -725,6 +725,47 @@ const constrainedInstructionWrite = failedTestRepairWithRequiredInstruction.find
|
|
|
725
725
|
assertStrict.deepEqual(constrainedInstructionWrite.function.parameters.properties.path.enum, ["AGINTI.md"]);
|
|
726
726
|
assertStrict.deepEqual(constrainedInstructionWrite.function.parameters.properties.mode.enum, ["create"]);
|
|
727
727
|
|
|
728
|
+
const continuedFailedTestRepairRuntime = nextStepRuntimeConfig(
|
|
729
|
+
{ provider: "localllm", taskProfile: "qa" },
|
|
730
|
+
{
|
|
731
|
+
meta: {
|
|
732
|
+
projectVerification: {
|
|
733
|
+
mutationRevision: 1,
|
|
734
|
+
discoveredTests: ["python -m pytest -q"],
|
|
735
|
+
requiredOutputs: [],
|
|
736
|
+
testRuns: [
|
|
737
|
+
{
|
|
738
|
+
command: "python -m pytest -q",
|
|
739
|
+
mutationRevision: 0,
|
|
740
|
+
passed: false,
|
|
741
|
+
failureSignature: "baseline-failure",
|
|
742
|
+
},
|
|
743
|
+
],
|
|
744
|
+
},
|
|
745
|
+
},
|
|
746
|
+
messages: [],
|
|
747
|
+
}
|
|
748
|
+
);
|
|
749
|
+
assertStrict.equal(
|
|
750
|
+
continuedFailedTestRepairRuntime.testFailureRepairActive,
|
|
751
|
+
true,
|
|
752
|
+
"a partial repair forgot the retained failed test after the mutation revision advanced"
|
|
753
|
+
);
|
|
754
|
+
assertStrict.equal(
|
|
755
|
+
continuedFailedTestRepairRuntime.testFailureCommand,
|
|
756
|
+
"python -m pytest -q",
|
|
757
|
+
"a partial repair lost the retained failing test command"
|
|
758
|
+
);
|
|
759
|
+
sameNames(
|
|
760
|
+
selectProgressiveTools(allTools, {
|
|
761
|
+
config: continuedFailedTestRepairRuntime,
|
|
762
|
+
goal: "Continue the coherent repair, then retest.",
|
|
763
|
+
profile: "qa",
|
|
764
|
+
}),
|
|
765
|
+
["read_file", "search_files", "apply_patch", "run_command", "finish"],
|
|
766
|
+
"a partial repair was forced into test-only mode before the coherent patch was complete"
|
|
767
|
+
);
|
|
768
|
+
|
|
728
769
|
const pendingTestTools = selectProgressiveTools(allTools, {
|
|
729
770
|
config: {
|
|
730
771
|
provider: "localllm",
|
package/src/agent-runner.js
CHANGED
|
@@ -4239,13 +4239,23 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
|
|
|
4239
4239
|
};
|
|
4240
4240
|
const verification = state.meta?.projectVerification || {};
|
|
4241
4241
|
const mutationRevision = Number(verification.mutationRevision || 0);
|
|
4242
|
-
const
|
|
4242
|
+
const testRuns = Array.isArray(verification.testRuns) ? verification.testRuns : [];
|
|
4243
|
+
const latestCurrentTest = [...testRuns]
|
|
4243
4244
|
.reverse()
|
|
4244
4245
|
.find((run) => Number(run.mutationRevision || 0) === mutationRevision);
|
|
4245
|
-
|
|
4246
|
+
const latestRecordedTest = [...testRuns]
|
|
4247
|
+
.reverse()
|
|
4248
|
+
.find((run) => String(run?.command || "").trim());
|
|
4249
|
+
const retainedFailedTest =
|
|
4250
|
+
latestCurrentTest && latestCurrentTest.passed !== true
|
|
4251
|
+
? latestCurrentTest
|
|
4252
|
+
: !latestCurrentTest && latestRecordedTest?.passed === false
|
|
4253
|
+
? latestRecordedTest
|
|
4254
|
+
: null;
|
|
4255
|
+
if (retainedFailedTest) {
|
|
4246
4256
|
runtimeConfig.testFailureRepairActive = true;
|
|
4247
|
-
runtimeConfig.testFailureCommand = String(
|
|
4248
|
-
runtimeConfig.testFailureSignature = String(
|
|
4257
|
+
runtimeConfig.testFailureCommand = String(retainedFailedTest.command || "");
|
|
4258
|
+
runtimeConfig.testFailureSignature = String(retainedFailedTest.failureSignature || "");
|
|
4249
4259
|
const completedOutputs = new Set(
|
|
4250
4260
|
(state.meta?.artifactProgress?.completed || [])
|
|
4251
4261
|
.map((item) => String(item || "").replace(/\\/g, "/").replace(/^\.\//, ""))
|
|
@@ -4256,10 +4266,7 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
|
|
|
4256
4266
|
.filter((item) => /(?:^|\/)(?:AGINTI|AGENTS)\.md$/i.test(item))
|
|
4257
4267
|
.slice(0, 8);
|
|
4258
4268
|
} else if (!latestCurrentTest && mutationRevision > 0 && (verification.discoveredTests || []).length) {
|
|
4259
|
-
const retainedTestCommand =
|
|
4260
|
-
.reverse()
|
|
4261
|
-
.map((run) => String(run.command || ""))
|
|
4262
|
-
.find(Boolean);
|
|
4269
|
+
const retainedTestCommand = String(latestRecordedTest?.command || "");
|
|
4263
4270
|
if (retainedTestCommand) {
|
|
4264
4271
|
runtimeConfig.testVerificationPending = true;
|
|
4265
4272
|
runtimeConfig.testVerificationCommand = retainedTestCommand;
|
package/src/scs-evidence.js
CHANGED
|
@@ -544,6 +544,12 @@ function requiresSourceGrounding(goal = "") {
|
|
|
544
544
|
function inferRequirementCategories(goal = "", taskProfile = "", acceptanceCriteria = []) {
|
|
545
545
|
const positiveGoal = stripForbiddenLanguage(goal);
|
|
546
546
|
const text = normalizedText(positiveGoal);
|
|
547
|
+
const artifactSignalText = text
|
|
548
|
+
.replace(
|
|
549
|
+
/\b(?:clean(?:\s+up)?|remove|delete|clear|purge)\b[^.\n;]{0,120}\b(?:generated|temporary|stale|test)?\s*(?:test\s+)?(?:debris|caches?|byproducts?)\b/gi,
|
|
550
|
+
""
|
|
551
|
+
)
|
|
552
|
+
.replace(/\bfigure\s+out\b/gi, "");
|
|
547
553
|
const profile = String(taskProfile || "").toLowerCase();
|
|
548
554
|
const categories = new Set(
|
|
549
555
|
goalRequiresEvidence(positiveGoal, "") ? profileRequirementsForGoal(taskProfile, positiveGoal) : []
|
|
@@ -571,7 +577,7 @@ function inferRequirementCategories(goal = "", taskProfile = "", acceptanceCrite
|
|
|
571
577
|
if (directCommandSignal || (validationSignal && codeProfileRequiresCommand(positiveGoal))) {
|
|
572
578
|
categories.add("command");
|
|
573
579
|
}
|
|
574
|
-
if (textHas(
|
|
580
|
+
if (textHas(artifactSignalText, /\b(artifact|canvas|pdf|image|video|screenshot|cover|plot|chart|figure|docx|archive|copy to|export|generated|generate|draft)\b/) || /输出|产物|图片|视频|截图|封面|生成/.test(artifactSignalText)) {
|
|
575
581
|
categories.add("artifact");
|
|
576
582
|
}
|
|
577
583
|
if (textHas(text, /\b(browser|chrome|chromium|cdp|devtools|playwright|selenium|web[- ]?ui|website|page|tab|composer|click|type|upload|attach|submit|form)\b/) || /浏览器|网页|页面|上传|提交|附件|资产库/.test(text)) {
|