@lazyingart/agintiflow 0.20.239 → 0.20.241
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-deep-research.js +16 -1
- package/scripts/smoke-dynamic-step-budget.js +106 -0
- package/scripts/smoke-progressive-tool-selection.js +15 -0
- package/src/agent-runner.js +45 -1
- package/src/command-policy.js +19 -4
- package/src/progressive-tool-selection.js +11 -1
- package/src/research-routing.js +21 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.241",
|
|
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",
|
|
@@ -8,7 +8,11 @@ import { checkToolUse } from "../src/guardrails.js";
|
|
|
8
8
|
import { flushHousekeeping } from "../src/housekeeping.js";
|
|
9
9
|
import { requestNextStep, toolChoiceForProvider } from "../src/model-client.js";
|
|
10
10
|
import { providerStructuredOutputAttempts } from "../src/provider-contract.js";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
hasExplicitDeepResearchIntent,
|
|
13
|
+
hasLocalResearchWorkspaceIntent,
|
|
14
|
+
shouldStartWithDeepResearch,
|
|
15
|
+
} from "../src/research-routing.js";
|
|
12
16
|
import { SessionStore } from "../src/session-store.js";
|
|
13
17
|
import { canonicalizeWebUrl, isPublicWebUrl, readWebPage, searchWeb } from "../src/web-search.js";
|
|
14
18
|
|
|
@@ -48,6 +52,17 @@ async function main() {
|
|
|
48
52
|
assert(!excessiveResearch.allowed, "deep_research accepted an excessive query/source budget");
|
|
49
53
|
|
|
50
54
|
assert(hasExplicitDeepResearchIntent("literature review with primary papers"), "explicit research intent was not detected");
|
|
55
|
+
const localEvidenceGoal =
|
|
56
|
+
"Turn the messy project notes in this folder into an evidence review, write sources.json, and commit the intentional work.";
|
|
57
|
+
assert(hasLocalResearchWorkspaceIntent(localEvidenceGoal), "local research workspace intent was not detected");
|
|
58
|
+
assert(
|
|
59
|
+
!shouldStartWithDeepResearch(localEvidenceGoal),
|
|
60
|
+
"local-source research incorrectly forced deep_research before workspace inspection"
|
|
61
|
+
);
|
|
62
|
+
assert(
|
|
63
|
+
shouldStartWithDeepResearch("Write a deep web research report comparing three primary papers."),
|
|
64
|
+
"standalone deep research no longer starts with the bounded research workflow"
|
|
65
|
+
);
|
|
51
66
|
assert(
|
|
52
67
|
!hasExplicitDeepResearchIntent("Create a phone-friendly document from this folder.", [
|
|
53
68
|
{
|
|
@@ -2302,6 +2302,112 @@ try {
|
|
|
2302
2302
|
shellMutationState.meta.projectVerification?.mutationRevision === 1,
|
|
2303
2303
|
"metadata-only Git chain with observational output invalidated current verification"
|
|
2304
2304
|
);
|
|
2305
|
+
assert(
|
|
2306
|
+
classifyCommand("md5sum output/report.pdf").writesWorkspace === false &&
|
|
2307
|
+
classifyCommand("md5sum -c .aginti/verification/source-hashes.txt").writesWorkspace === false &&
|
|
2308
|
+
classifyCommand("diff .aginti/verification/run-1.txt .aginti/verification/run-2.txt").writesWorkspace === false,
|
|
2309
|
+
"checksum or diff evidence probes were not classified as read-only"
|
|
2310
|
+
);
|
|
2311
|
+
const privateEvidenceState = {
|
|
2312
|
+
meta: {
|
|
2313
|
+
goalContract: { revision: 1 },
|
|
2314
|
+
projectVerification: { requiredCommands: ["bash build.sh"] },
|
|
2315
|
+
},
|
|
2316
|
+
};
|
|
2317
|
+
const privateEvidenceBuild = {
|
|
2318
|
+
toolName: "run_command",
|
|
2319
|
+
ok: true,
|
|
2320
|
+
exitCode: 0,
|
|
2321
|
+
args: { command: "bash build.sh" },
|
|
2322
|
+
stdout: "build complete\n",
|
|
2323
|
+
stderr: "",
|
|
2324
|
+
};
|
|
2325
|
+
recordProjectVerificationOutcome(privateEvidenceState, privateEvidenceBuild, {
|
|
2326
|
+
commandCwd: workspace,
|
|
2327
|
+
taskProfile: "writing",
|
|
2328
|
+
allowShellTool: true,
|
|
2329
|
+
sandboxMode: "host",
|
|
2330
|
+
});
|
|
2331
|
+
const privateEvidenceRevision =
|
|
2332
|
+
privateEvidenceState.meta.projectVerification?.mutationRevision;
|
|
2333
|
+
const privateEvidenceCommand = {
|
|
2334
|
+
toolName: "run_command",
|
|
2335
|
+
ok: true,
|
|
2336
|
+
exitCode: 0,
|
|
2337
|
+
args: {
|
|
2338
|
+
command:
|
|
2339
|
+
"md5sum output/report.pdf > .aginti/verification/hashes-final.txt && cat .aginti/verification/hashes-final.txt && diff .aginti/verification/hashes-run1.txt .aginti/verification/hashes-final.txt && md5sum -c .aginti/verification/source-hashes.txt && git status --porcelain",
|
|
2340
|
+
},
|
|
2341
|
+
stdout: "MATCH\n",
|
|
2342
|
+
stderr: "",
|
|
2343
|
+
};
|
|
2344
|
+
recordProjectVerificationOutcome(privateEvidenceState, privateEvidenceCommand, {
|
|
2345
|
+
commandCwd: workspace,
|
|
2346
|
+
taskProfile: "writing",
|
|
2347
|
+
allowShellTool: true,
|
|
2348
|
+
sandboxMode: "host",
|
|
2349
|
+
});
|
|
2350
|
+
const privateEvidenceWrite = {
|
|
2351
|
+
toolName: "write_file",
|
|
2352
|
+
ok: true,
|
|
2353
|
+
path: ".aginti/verification/visual-check.txt",
|
|
2354
|
+
changes: [
|
|
2355
|
+
{
|
|
2356
|
+
path: ".aginti/verification/visual-check.txt",
|
|
2357
|
+
created: true,
|
|
2358
|
+
beforeHash: "",
|
|
2359
|
+
afterHash: "private-evidence",
|
|
2360
|
+
},
|
|
2361
|
+
],
|
|
2362
|
+
};
|
|
2363
|
+
recordProjectVerificationOutcome(privateEvidenceState, privateEvidenceWrite, {
|
|
2364
|
+
commandCwd: workspace,
|
|
2365
|
+
taskProfile: "writing",
|
|
2366
|
+
});
|
|
2367
|
+
const privateEvidenceContract = augmentScsTaskContractWithProjectVerification(
|
|
2368
|
+
{
|
|
2369
|
+
requiresExternalEvidence: false,
|
|
2370
|
+
requiredEvidence: [],
|
|
2371
|
+
requiredToolCalls: [],
|
|
2372
|
+
requiredGitActions: [],
|
|
2373
|
+
taskProfile: "writing",
|
|
2374
|
+
},
|
|
2375
|
+
privateEvidenceState,
|
|
2376
|
+
{ taskProfile: "writing" }
|
|
2377
|
+
);
|
|
2378
|
+
const privateEvidenceLedger = buildScsEvidenceLedger({
|
|
2379
|
+
state: {
|
|
2380
|
+
messages: [privateEvidenceBuild, privateEvidenceCommand, privateEvidenceWrite].map((result) =>
|
|
2381
|
+
toolMessage(result)
|
|
2382
|
+
),
|
|
2383
|
+
},
|
|
2384
|
+
});
|
|
2385
|
+
assert(
|
|
2386
|
+
privateEvidenceRevision === 1 &&
|
|
2387
|
+
privateEvidenceState.meta.projectVerification?.mutationRevision === 1 &&
|
|
2388
|
+
privateEvidenceState.meta.projectVerification?.requiredCommandBatch?.complete === true &&
|
|
2389
|
+
evaluateScsEvidence(privateEvidenceContract, privateEvidenceLedger).ok,
|
|
2390
|
+
"ignored private verification evidence invalidated a successful canonical build"
|
|
2391
|
+
);
|
|
2392
|
+
const publicEvidenceMutation = {
|
|
2393
|
+
toolName: "run_command",
|
|
2394
|
+
ok: true,
|
|
2395
|
+
exitCode: 0,
|
|
2396
|
+
args: { command: "md5sum output/report.pdf > output/hashes-final.txt" },
|
|
2397
|
+
stdout: "",
|
|
2398
|
+
stderr: "",
|
|
2399
|
+
};
|
|
2400
|
+
recordProjectVerificationOutcome(privateEvidenceState, publicEvidenceMutation, {
|
|
2401
|
+
commandCwd: workspace,
|
|
2402
|
+
taskProfile: "writing",
|
|
2403
|
+
allowShellTool: true,
|
|
2404
|
+
sandboxMode: "host",
|
|
2405
|
+
});
|
|
2406
|
+
assert(
|
|
2407
|
+
privateEvidenceState.meta.projectVerification?.mutationRevision === 2 &&
|
|
2408
|
+
!privateEvidenceState.meta.projectVerification?.requiredCommandBatch,
|
|
2409
|
+
"a non-private output write was incorrectly exempted from project mutation tracking"
|
|
2410
|
+
);
|
|
2305
2411
|
const gitCheckoutResult = {
|
|
2306
2412
|
toolName: "run_command",
|
|
2307
2413
|
ok: true,
|
|
@@ -1475,6 +1475,21 @@ const explicitDeepResearchFollowup = selectProgressiveTools(allTools, {
|
|
|
1475
1475
|
});
|
|
1476
1476
|
assert(names(explicitDeepResearchFollowup).includes("web_search"), "deep-research follow-up did not restore targeted recovery tools");
|
|
1477
1477
|
|
|
1478
|
+
const localEvidenceResearchStarter = selectProgressiveTools(allTools, {
|
|
1479
|
+
config: { provider: "deepseek" },
|
|
1480
|
+
goal:
|
|
1481
|
+
"Investigate the reliability problem in this folder, correct PROJECT_NOTES.md, write an evidence review and sources.json, then commit the intentional work.",
|
|
1482
|
+
profile: "research",
|
|
1483
|
+
});
|
|
1484
|
+
assert(names(localEvidenceResearchStarter).includes("deep_research"), "local evidence research omitted deep_research");
|
|
1485
|
+
assert(names(localEvidenceResearchStarter).includes("read_file"), "local evidence research omitted read_file");
|
|
1486
|
+
assert(names(localEvidenceResearchStarter).includes("write_file"), "local evidence research omitted write_file");
|
|
1487
|
+
assert(names(localEvidenceResearchStarter).includes("run_command"), "local evidence research omitted shell/git access");
|
|
1488
|
+
assert(
|
|
1489
|
+
!(names(localEvidenceResearchStarter).length === 2 && names(localEvidenceResearchStarter)[0] === "deep_research"),
|
|
1490
|
+
"local evidence research was trapped on deep_research before reading its source material"
|
|
1491
|
+
);
|
|
1492
|
+
|
|
1478
1493
|
const documentRuntimeSnapshot =
|
|
1479
1494
|
'Step 1/30. Latest runtime snapshot:\n{"pageText":"Workspace file tools are ready. Web search and resumable deep research are available when current evidence is required."}';
|
|
1480
1495
|
const localDocumentStarter = selectProgressiveTools(allTools, {
|
package/src/agent-runner.js
CHANGED
|
@@ -5991,6 +5991,49 @@ const WORKTREE_CHANGING_GIT_ACTIONS = new Set([
|
|
|
5991
5991
|
"switch",
|
|
5992
5992
|
]);
|
|
5993
5993
|
|
|
5994
|
+
function isPrivateVerificationEvidencePath(value = "") {
|
|
5995
|
+
const normalized = String(value || "")
|
|
5996
|
+
.trim()
|
|
5997
|
+
.replace(/^["']|["']$/g, "")
|
|
5998
|
+
.replace(/\\/g, "/")
|
|
5999
|
+
.replace(/^\.\//, "");
|
|
6000
|
+
return Boolean(
|
|
6001
|
+
normalized === ".aginti/verification" ||
|
|
6002
|
+
normalized.startsWith(".aginti/verification/") ||
|
|
6003
|
+
normalized.includes("/.aginti/verification/")
|
|
6004
|
+
);
|
|
6005
|
+
}
|
|
6006
|
+
|
|
6007
|
+
function commandWritesOnlyPrivateVerificationEvidence(command = "") {
|
|
6008
|
+
const normalized = String(command || "").trim();
|
|
6009
|
+
if (!normalized) return false;
|
|
6010
|
+
const tokens = tokenizeShellWords(normalized);
|
|
6011
|
+
if (tokens[0] === "tee") {
|
|
6012
|
+
let index = 1;
|
|
6013
|
+
if (["-a", "--append"].includes(tokens[index])) index += 1;
|
|
6014
|
+
if (tokens[index] === "--") index += 1;
|
|
6015
|
+
const targets = tokens.slice(index);
|
|
6016
|
+
return targets.length > 0 && targets.every(isPrivateVerificationEvidencePath);
|
|
6017
|
+
}
|
|
6018
|
+
if (tokens[0] === "mkdir") {
|
|
6019
|
+
const targets = tokens.slice(1).filter((token) => token !== "-p" && token !== "--");
|
|
6020
|
+
return targets.length > 0 && targets.every(isPrivateVerificationEvidencePath);
|
|
6021
|
+
}
|
|
6022
|
+
|
|
6023
|
+
let strippedPrivateRedirect = false;
|
|
6024
|
+
const withoutPrivateRedirects = normalized.replace(
|
|
6025
|
+
/(^|\s)(?:\d*>>?|&>>?)\s*("[^"]+"|'[^']+'|[^\s;&|]+)/g,
|
|
6026
|
+
(match, prefix, target) => {
|
|
6027
|
+
if (!isPrivateVerificationEvidencePath(target)) return match;
|
|
6028
|
+
strippedPrivateRedirect = true;
|
|
6029
|
+
return prefix;
|
|
6030
|
+
}
|
|
6031
|
+
).trim();
|
|
6032
|
+
if (!strippedPrivateRedirect || !withoutPrivateRedirects) return false;
|
|
6033
|
+
const underlyingPolicy = classifyCommand(withoutPrivateRedirects);
|
|
6034
|
+
return underlyingPolicy.writesWorkspace !== true && underlyingPolicy.mayMutateProject !== true;
|
|
6035
|
+
}
|
|
6036
|
+
|
|
5994
6037
|
function commandCanMutateProjectContent(command = "", commandPolicy = {}) {
|
|
5995
6038
|
if (commandPolicy.writesWorkspace !== true && commandPolicy.mayMutateProject !== true) return false;
|
|
5996
6039
|
const sequence = parseTopLevelShellSequence(String(command || ""));
|
|
@@ -6004,6 +6047,7 @@ function commandCanMutateProjectContent(command = "", commandPolicy = {}) {
|
|
|
6004
6047
|
commandCanMutateProjectContent(segment, classifyCommand(segment))
|
|
6005
6048
|
);
|
|
6006
6049
|
}
|
|
6050
|
+
if (commandWritesOnlyPrivateVerificationEvidence(command)) return false;
|
|
6007
6051
|
const category = String(commandPolicy.category || "");
|
|
6008
6052
|
if (!["git-workflow", "git-remote"].includes(category)) return true;
|
|
6009
6053
|
if (/\bgit\s+clone\b/i.test(String(command || ""))) return true;
|
|
@@ -6490,7 +6534,7 @@ function successfulProjectMutationPaths(toolResult = {}) {
|
|
|
6490
6534
|
[
|
|
6491
6535
|
toolResult.path,
|
|
6492
6536
|
...actualChanges.flatMap((change) => [change.path, change.fromPath]),
|
|
6493
|
-
].filter(
|
|
6537
|
+
].filter((candidate) => candidate && !isPrivateVerificationEvidencePath(candidate))
|
|
6494
6538
|
),
|
|
6495
6539
|
];
|
|
6496
6540
|
}
|
package/src/command-policy.js
CHANGED
|
@@ -108,17 +108,31 @@ function isReadOnlyUniqFilter(command = "") {
|
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
function
|
|
111
|
+
function isReadOnlyDigestCommand(command = "") {
|
|
112
112
|
const normalized = stripBenignRedirections(command);
|
|
113
113
|
if (hasActiveShellExpansion(normalized)) return false;
|
|
114
114
|
const tokens = tokenizeShellWords(normalized);
|
|
115
|
-
if (
|
|
116
|
-
|
|
115
|
+
if (!["md5sum", "sha256sum"].includes(tokens[0]) || tokens.length < 2) return false;
|
|
116
|
+
let index = 1;
|
|
117
|
+
if (["-c", "--check"].includes(tokens[index])) index += 1;
|
|
118
|
+
if (tokens[index] === "--") index += 1;
|
|
119
|
+
const paths = tokens.slice(index);
|
|
117
120
|
return paths.length > 0 && paths.every((token) =>
|
|
118
121
|
!token.startsWith("-") && READ_ONLY_FOR_LOOP_LITERAL_PATTERN.test(token)
|
|
119
122
|
);
|
|
120
123
|
}
|
|
121
124
|
|
|
125
|
+
function isReadOnlyDiffCommand(command = "") {
|
|
126
|
+
const normalized = stripBenignRedirections(command);
|
|
127
|
+
if (hasActiveShellExpansion(normalized)) return false;
|
|
128
|
+
const tokens = tokenizeShellWords(normalized);
|
|
129
|
+
if (tokens[0] !== "diff" || tokens.length < 3) return false;
|
|
130
|
+
const operands = tokens.slice(1).filter((token) => token !== "--" && !token.startsWith("-"));
|
|
131
|
+
return operands.length === 2 && operands.every((token) =>
|
|
132
|
+
READ_ONLY_FOR_LOOP_LITERAL_PATTERN.test(token)
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
122
136
|
function isReadOnlyFindCommand(command = "") {
|
|
123
137
|
const normalized = stripBenignRedirections(command);
|
|
124
138
|
if (!/^find\s+/.test(normalized)) return false;
|
|
@@ -1511,7 +1525,8 @@ function classifySimpleCommand(normalized) {
|
|
|
1511
1525
|
isReadOnlyPrintfCommand(commandForPatternMatching) ||
|
|
1512
1526
|
isReadOnlyTrDeleteFilter(commandForPatternMatching) ||
|
|
1513
1527
|
isReadOnlyUniqFilter(commandForPatternMatching) ||
|
|
1514
|
-
|
|
1528
|
+
isReadOnlyDigestCommand(commandForPatternMatching) ||
|
|
1529
|
+
isReadOnlyDiffCommand(commandForPatternMatching) ||
|
|
1515
1530
|
isReadOnlyFindCommand(normalized) ||
|
|
1516
1531
|
(!hasActiveShellExpansion(benignRedirectCommand) && isReadOnlyShellCondition(benignRedirectCommand))
|
|
1517
1532
|
) {
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
hasLocalResearchWorkspaceIntent,
|
|
3
|
+
shouldStartWithDeepResearch,
|
|
4
|
+
} from "./research-routing.js";
|
|
2
5
|
import { hasAgintiEvidenceScope, scopedChatopsEvidenceGoal } from "./scs-evidence.js";
|
|
3
6
|
import {
|
|
4
7
|
INTEGRATION_TEXT_WORKSPACE_PROFILE_ID,
|
|
@@ -1241,6 +1244,13 @@ function compactToolNames({ config, goal, profile, messages }) {
|
|
|
1241
1244
|
for (const bundle of inferred) {
|
|
1242
1245
|
if (!bundleOrder.includes(bundle)) bundleOrder.push(bundle);
|
|
1243
1246
|
}
|
|
1247
|
+
if (
|
|
1248
|
+
bundleOrder.includes("research") &&
|
|
1249
|
+
hasLocalResearchWorkspaceIntent(goal || config.goal, messages) &&
|
|
1250
|
+
!bundleOrder.includes("code")
|
|
1251
|
+
) {
|
|
1252
|
+
bundleOrder.push("code");
|
|
1253
|
+
}
|
|
1244
1254
|
if (bundleOrder.length === 0 && explicitProfileTools.length === 0) bundleOrder.push("general");
|
|
1245
1255
|
|
|
1246
1256
|
const names = [];
|
package/src/research-routing.js
CHANGED
|
@@ -48,6 +48,22 @@ export function hasExplicitDeepResearchIntent(goal = "", messages = []) {
|
|
|
48
48
|
);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
export function hasLocalResearchWorkspaceIntent(goal = "", messages = []) {
|
|
52
|
+
const recent = hasAgintiEvidenceScope(goal)
|
|
53
|
+
? ""
|
|
54
|
+
: genuineUserMessages(messages)
|
|
55
|
+
.slice(-4)
|
|
56
|
+
.map((message) => scopedChatopsEvidenceGoal(messageText(message.content)))
|
|
57
|
+
.join("\n");
|
|
58
|
+
const text = `${scopedChatopsEvidenceGoal(goal)}\n${recent}`;
|
|
59
|
+
return (
|
|
60
|
+
/\b(?:this|current|existing|project|workspace|local)\s+(?:folder|directory|repo(?:sitory)?|files?|notes?|sources?|artifacts?)\b/i.test(text) ||
|
|
61
|
+
/\b(?:task|project|source|research|evidence|notes?|manifest|readme)[-_A-Za-z0-9]*\.(?:md|json|ya?ml|txt|csv|bib|tex)\b/i.test(text) ||
|
|
62
|
+
/\b(?:inspect|read|reconcile|correct|rewrite|update)\b.{0,120}\b(?:workspace|folder|directory|repo(?:sitory)?|local files?|project notes?|existing notes?)\b/i.test(text) ||
|
|
63
|
+
/\b(?:git\s+)?commit\b/i.test(text)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
51
67
|
export function toolWasRequested(messages = [], toolName = "") {
|
|
52
68
|
return messages.some((message) => {
|
|
53
69
|
if (
|
|
@@ -65,5 +81,9 @@ export function toolWasRequested(messages = [], toolName = "") {
|
|
|
65
81
|
}
|
|
66
82
|
|
|
67
83
|
export function shouldStartWithDeepResearch(goal = "", messages = []) {
|
|
68
|
-
return
|
|
84
|
+
return (
|
|
85
|
+
hasExplicitDeepResearchIntent(goal, messages) &&
|
|
86
|
+
!hasLocalResearchWorkspaceIntent(goal, messages) &&
|
|
87
|
+
!toolWasRequested(messages, "deep_research")
|
|
88
|
+
);
|
|
69
89
|
}
|