@lazyingart/agintiflow 0.20.322 → 0.20.324
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/scripts/smoke-dynamic-step-budget.js +70 -0
- package/src/agent-runner.js +101 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.324",
|
|
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",
|
|
@@ -11030,6 +11030,62 @@ try {
|
|
|
11030
11030
|
})?.category === "repeated-no-progress-call",
|
|
11031
11031
|
"a third identical unchanged shell probe was not blocked"
|
|
11032
11032
|
);
|
|
11033
|
+
const missingCanvasPath = path.join(workspace, "report.pdf");
|
|
11034
|
+
const repeatedCanvasState = {
|
|
11035
|
+
meta: {
|
|
11036
|
+
toolLoop: {
|
|
11037
|
+
stagnationEpoch: 4,
|
|
11038
|
+
recent: [
|
|
11039
|
+
{
|
|
11040
|
+
toolName: "send_to_canvas",
|
|
11041
|
+
ok: false,
|
|
11042
|
+
blocked: true,
|
|
11043
|
+
stagnationEpoch: 4,
|
|
11044
|
+
error: `Canvas path does not exist or is not a file: ${missingCanvasPath}`,
|
|
11045
|
+
},
|
|
11046
|
+
{
|
|
11047
|
+
toolName: "send_to_canvas",
|
|
11048
|
+
ok: false,
|
|
11049
|
+
blocked: true,
|
|
11050
|
+
stagnationEpoch: 4,
|
|
11051
|
+
error: `Canvas path does not exist or is not a file: ${missingCanvasPath}`,
|
|
11052
|
+
},
|
|
11053
|
+
],
|
|
11054
|
+
},
|
|
11055
|
+
},
|
|
11056
|
+
};
|
|
11057
|
+
assert(
|
|
11058
|
+
repeatedNoProgressToolBlock(
|
|
11059
|
+
repeatedCanvasState,
|
|
11060
|
+
"send_to_canvas",
|
|
11061
|
+
{
|
|
11062
|
+
path: missingCanvasPath,
|
|
11063
|
+
title: "Changed title",
|
|
11064
|
+
note: "A cosmetically different note",
|
|
11065
|
+
},
|
|
11066
|
+
{ commandCwd: workspace }
|
|
11067
|
+
)?.category === "repeated-no-progress-call",
|
|
11068
|
+
"changed canvas metadata allowed the same missing artifact target to loop"
|
|
11069
|
+
);
|
|
11070
|
+
assert(
|
|
11071
|
+
repeatedNoProgressToolBlock(
|
|
11072
|
+
repeatedCanvasState,
|
|
11073
|
+
"send_to_canvas",
|
|
11074
|
+
{ path: path.join(workspace, "different.pdf"), title: "Different artifact" },
|
|
11075
|
+
{ commandCwd: workspace }
|
|
11076
|
+
) === null,
|
|
11077
|
+
"a different canvas artifact was blocked by unrelated missing-path history"
|
|
11078
|
+
);
|
|
11079
|
+
await fs.writeFile(missingCanvasPath, "%PDF-1.4\n", "utf8");
|
|
11080
|
+
assert(
|
|
11081
|
+
repeatedNoProgressToolBlock(
|
|
11082
|
+
repeatedCanvasState,
|
|
11083
|
+
"send_to_canvas",
|
|
11084
|
+
{ path: missingCanvasPath, title: "Now available" },
|
|
11085
|
+
{ commandCwd: workspace }
|
|
11086
|
+
) === null,
|
|
11087
|
+
"a canvas artifact created after prior failures remained blocked"
|
|
11088
|
+
);
|
|
11033
11089
|
assert(
|
|
11034
11090
|
repeatedNoProgressToolBlock(repeatedProbeState, "run_command", repeatedProbeArgs, {
|
|
11035
11091
|
commandCwd: workspace,
|
|
@@ -11089,6 +11145,20 @@ try {
|
|
|
11089
11145
|
})?.category === "repeated-no-progress-call",
|
|
11090
11146
|
"a third identical failed shell command was not blocked"
|
|
11091
11147
|
);
|
|
11148
|
+
const repeatedChangingFailureState = structuredClone(repeatedFailureState);
|
|
11149
|
+
repeatedChangingFailureState.meta.toolLoop.recent[0].outcomeFingerprint =
|
|
11150
|
+
"failure-with-first-dynamic-log";
|
|
11151
|
+
repeatedChangingFailureState.meta.toolLoop.recent[1].outcomeFingerprint =
|
|
11152
|
+
"failure-with-second-dynamic-log";
|
|
11153
|
+
assert(
|
|
11154
|
+
repeatedNoProgressToolBlock(
|
|
11155
|
+
repeatedChangingFailureState,
|
|
11156
|
+
"run_command",
|
|
11157
|
+
repeatedProbeArgs,
|
|
11158
|
+
{ commandCwd: workspace }
|
|
11159
|
+
)?.category === "repeated-no-progress-call",
|
|
11160
|
+
"dynamic failure output allowed an unchanged failing command to loop"
|
|
11161
|
+
);
|
|
11092
11162
|
const newlyAuthoritativeVerificationState = structuredClone(repeatedFailureState);
|
|
11093
11163
|
newlyAuthoritativeVerificationState.meta.projectVerification = {
|
|
11094
11164
|
mutationRevision: 6,
|
package/src/agent-runner.js
CHANGED
|
@@ -11017,13 +11017,83 @@ function noProgressOutcomeFingerprint(toolResult = {}) {
|
|
|
11017
11017
|
}));
|
|
11018
11018
|
}
|
|
11019
11019
|
|
|
11020
|
+
function canvasNoProgressTarget(args = {}, config = {}) {
|
|
11021
|
+
const rawPath = String(args?.path || "").trim();
|
|
11022
|
+
if (rawPath) {
|
|
11023
|
+
const normalized = comparableOutputPath(
|
|
11024
|
+
rawPath,
|
|
11025
|
+
config.commandCwd || process.cwd()
|
|
11026
|
+
);
|
|
11027
|
+
return `path:${normalized}`;
|
|
11028
|
+
}
|
|
11029
|
+
const content = String(args?.content || "");
|
|
11030
|
+
if (content) return `content:${hashForLog(content)}`;
|
|
11031
|
+
return "";
|
|
11032
|
+
}
|
|
11033
|
+
|
|
11034
|
+
function canvasNoProgressTargetFromEntry(entry = {}, config = {}) {
|
|
11035
|
+
if (entry?.semanticSignature) return String(entry.semanticSignature);
|
|
11036
|
+
const error = String(entry?.error || "");
|
|
11037
|
+
const match = error.match(/Canvas path does not exist or is not a file:\s*(.+)$/i);
|
|
11038
|
+
if (!match?.[1]) return "";
|
|
11039
|
+
return `path:${comparableOutputPath(
|
|
11040
|
+
match[1].trim(),
|
|
11041
|
+
config.commandCwd || process.cwd()
|
|
11042
|
+
)}`;
|
|
11043
|
+
}
|
|
11044
|
+
|
|
11045
|
+
function canvasTargetExists(args = {}, config = {}) {
|
|
11046
|
+
const rawPath = String(args?.path || "").trim();
|
|
11047
|
+
if (!rawPath) return false;
|
|
11048
|
+
const candidates = path.isAbsolute(rawPath)
|
|
11049
|
+
? [rawPath]
|
|
11050
|
+
: [path.resolve(config.commandCwd || process.cwd(), rawPath)];
|
|
11051
|
+
return candidates.some((candidate) => {
|
|
11052
|
+
try {
|
|
11053
|
+
return fsSync.statSync(candidate).isFile();
|
|
11054
|
+
} catch {
|
|
11055
|
+
return false;
|
|
11056
|
+
}
|
|
11057
|
+
});
|
|
11058
|
+
}
|
|
11059
|
+
|
|
11020
11060
|
export function repeatedNoProgressToolBlock(state, toolName, args = {}, config = {}) {
|
|
11021
|
-
if (toolName !== "run_command" || expectedRepeatedObservationCommand(args.command)) return null;
|
|
11022
11061
|
const toolLoop = state.meta?.toolLoop || {};
|
|
11062
|
+
const stagnationEpoch = Math.max(0, Number(toolLoop.stagnationEpoch || 0));
|
|
11063
|
+
if (toolName === "send_to_canvas") {
|
|
11064
|
+
if (canvasTargetExists(args, config)) return null;
|
|
11065
|
+
const target = canvasNoProgressTarget(args, config);
|
|
11066
|
+
if (!target) return null;
|
|
11067
|
+
const matches = (Array.isArray(toolLoop.recent) ? toolLoop.recent : []).filter(
|
|
11068
|
+
(entry) =>
|
|
11069
|
+
entry?.toolName === "send_to_canvas" &&
|
|
11070
|
+
entry?.ok === false &&
|
|
11071
|
+
Number(entry?.stagnationEpoch || 0) === stagnationEpoch &&
|
|
11072
|
+
canvasNoProgressTargetFromEntry(entry, config) === target
|
|
11073
|
+
);
|
|
11074
|
+
if (matches.length < 2) return null;
|
|
11075
|
+
return {
|
|
11076
|
+
reason:
|
|
11077
|
+
"The same canvas artifact target already failed twice without an intervening file, artifact, browser, or task-state change.",
|
|
11078
|
+
category: "repeated-no-progress-call",
|
|
11079
|
+
permissionAdvice: {
|
|
11080
|
+
category: "repeated-no-progress-call",
|
|
11081
|
+
autoRecover: true,
|
|
11082
|
+
summary: "This is a missing-artifact convergence guard, not a permission blocker.",
|
|
11083
|
+
instruction:
|
|
11084
|
+
"Do not retry the same missing path with a different title or note. Create or repair the exact artifact with an offered tool, return its durable source path for host processing, or finish with the concrete missing-artifact blocker.",
|
|
11085
|
+
options: [
|
|
11086
|
+
"Create the exact file before sending it to canvas.",
|
|
11087
|
+
"Return a complete editable source so the host can compile the derived artifact.",
|
|
11088
|
+
"Finish with the exact missing path when no enabled tool can create it.",
|
|
11089
|
+
],
|
|
11090
|
+
},
|
|
11091
|
+
};
|
|
11092
|
+
}
|
|
11093
|
+
if (toolName !== "run_command" || expectedRepeatedObservationCommand(args.command)) return null;
|
|
11023
11094
|
const signature = staticToolCallSignature(toolName, args || {}, {
|
|
11024
11095
|
commandCwd: config.commandCwd,
|
|
11025
11096
|
});
|
|
11026
|
-
const stagnationEpoch = Math.max(0, Number(toolLoop.stagnationEpoch || 0));
|
|
11027
11097
|
const requestedCommand = projectTestCommandKey(
|
|
11028
11098
|
normalizeLeadingWorkspaceCd(args.command, config)
|
|
11029
11099
|
);
|
|
@@ -11094,6 +11164,26 @@ export function repeatedNoProgressToolBlock(state, toolName, args = {}, config =
|
|
|
11094
11164
|
Boolean(entry?.outcomeFingerprint)
|
|
11095
11165
|
);
|
|
11096
11166
|
if (matches.length < 2) return null;
|
|
11167
|
+
const repeatedFailures = matches.slice(-2).every((entry) => entry?.ok === false);
|
|
11168
|
+
if (repeatedFailures) {
|
|
11169
|
+
return {
|
|
11170
|
+
reason:
|
|
11171
|
+
"The same command already failed twice without an intervening file, artifact, browser, or task-state change.",
|
|
11172
|
+
category: "repeated-no-progress-call",
|
|
11173
|
+
permissionAdvice: {
|
|
11174
|
+
category: "repeated-no-progress-call",
|
|
11175
|
+
autoRecover: true,
|
|
11176
|
+
summary: "This is a failed-command convergence guard, not a permission blocker.",
|
|
11177
|
+
instruction:
|
|
11178
|
+
"Do not rerun the command or a cosmetically equivalent form. Use the retained failure evidence, change the command or repair the implicated source, then run the smallest relevant validation.",
|
|
11179
|
+
options: [
|
|
11180
|
+
"Choose the correct compiler, interpreter, working directory, or command flags from the observed failure.",
|
|
11181
|
+
"Apply one bounded source repair that addresses the failure, then rerun validation.",
|
|
11182
|
+
"Finish with a concrete external blocker only when no enabled tool can make progress.",
|
|
11183
|
+
],
|
|
11184
|
+
},
|
|
11185
|
+
};
|
|
11186
|
+
}
|
|
11097
11187
|
const recentFingerprints = matches.slice(-2).map((entry) => entry.outcomeFingerprint);
|
|
11098
11188
|
if (new Set(recentFingerprints).size !== 1) return null;
|
|
11099
11189
|
return {
|
|
@@ -19731,6 +19821,11 @@ async function applyToolLoopGuard(state, toolResult, store, observers, config =
|
|
|
19731
19821
|
staticDiscovery: isStaticDiscoveryToolResult(toolResult),
|
|
19732
19822
|
successfulMutation: successfulToolStateProgress(toolResult),
|
|
19733
19823
|
noProgressProbe: Boolean(outcomeFingerprint),
|
|
19824
|
+
semanticSignature:
|
|
19825
|
+
toolResult.toolName === "send_to_canvas"
|
|
19826
|
+
? canvasNoProgressTarget(toolResult.args || {}, config) ||
|
|
19827
|
+
canvasNoProgressTargetFromEntry(toolResult, config)
|
|
19828
|
+
: "",
|
|
19734
19829
|
generatedArtifactProducerAttempt: Boolean(
|
|
19735
19830
|
toolResult.toolName === "run_command" &&
|
|
19736
19831
|
config.generatedArtifactProducerPending === true &&
|
|
@@ -21408,6 +21503,8 @@ async function executeTool(browserState, toolCall, snapshot, config, store, obse
|
|
|
21408
21503
|
blocked: true,
|
|
21409
21504
|
reason: normalized.reason,
|
|
21410
21505
|
toolName: "send_to_canvas",
|
|
21506
|
+
args: safeArgs,
|
|
21507
|
+
category: "canvas",
|
|
21411
21508
|
};
|
|
21412
21509
|
}
|
|
21413
21510
|
|
|
@@ -21430,6 +21527,8 @@ async function executeTool(browserState, toolCall, snapshot, config, store, obse
|
|
|
21430
21527
|
blocked: true,
|
|
21431
21528
|
reason: persisted.reason,
|
|
21432
21529
|
toolName: "send_to_canvas",
|
|
21530
|
+
args: safeArgs,
|
|
21531
|
+
category: "canvas",
|
|
21433
21532
|
};
|
|
21434
21533
|
}
|
|
21435
21534
|
|