@lazyingart/agintiflow 0.20.296 → 0.20.298
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 +212 -0
- package/scripts/smoke-execution-policy.js +42 -0
- package/scripts/smoke-model-roles.js +41 -0
- package/src/agent-runner.js +197 -34
- package/src/config.js +5 -4
- package/src/model-client.js +9 -5
- package/src/scs-controller.js +9 -0
- package/src/scs-evidence.js +32 -3
- package/src/skill-library.js +14 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.298",
|
|
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",
|
|
@@ -5800,6 +5800,167 @@ try {
|
|
|
5800
5800
|
evaluateScsEvidence(privateEvidenceContract, privateEvidenceLedger).ok,
|
|
5801
5801
|
"ignored private verification evidence invalidated a successful canonical build"
|
|
5802
5802
|
);
|
|
5803
|
+
const scopedTaskRoot = path.join(workspace, "output", "agent-task-1");
|
|
5804
|
+
const scopedTaskGoal = [
|
|
5805
|
+
"Create and verify output/result.json.",
|
|
5806
|
+
`AGINTI_EVIDENCE_SCOPE_JSON: ${JSON.stringify({
|
|
5807
|
+
mode: "task",
|
|
5808
|
+
request: "Create and verify output/result.json.",
|
|
5809
|
+
artifact_root: scopedTaskRoot,
|
|
5810
|
+
})}`,
|
|
5811
|
+
].join("\n");
|
|
5812
|
+
const scopedTaskState = {
|
|
5813
|
+
goal: scopedTaskGoal,
|
|
5814
|
+
commandCwd: workspace,
|
|
5815
|
+
meta: {
|
|
5816
|
+
goalContract: {
|
|
5817
|
+
revision: 1,
|
|
5818
|
+
taskGoal: scopedTaskGoal,
|
|
5819
|
+
currentRequest: "Create and verify output/result.json.",
|
|
5820
|
+
},
|
|
5821
|
+
},
|
|
5822
|
+
};
|
|
5823
|
+
recordProjectVerificationOutcome(
|
|
5824
|
+
scopedTaskState,
|
|
5825
|
+
{
|
|
5826
|
+
toolName: "write_file",
|
|
5827
|
+
ok: true,
|
|
5828
|
+
path: "output/result.json",
|
|
5829
|
+
changes: [
|
|
5830
|
+
{
|
|
5831
|
+
path: "output/result.json",
|
|
5832
|
+
created: true,
|
|
5833
|
+
beforeHash: "",
|
|
5834
|
+
afterHash: "requested-output",
|
|
5835
|
+
},
|
|
5836
|
+
],
|
|
5837
|
+
},
|
|
5838
|
+
{ commandCwd: workspace, taskProfile: "auto" }
|
|
5839
|
+
);
|
|
5840
|
+
const requestedOutputRevision =
|
|
5841
|
+
scopedTaskState.meta.projectVerification?.mutationRevision;
|
|
5842
|
+
const readOnlyArtifactValidation = {
|
|
5843
|
+
toolName: "run_command",
|
|
5844
|
+
ok: true,
|
|
5845
|
+
exitCode: 0,
|
|
5846
|
+
args: {
|
|
5847
|
+
command:
|
|
5848
|
+
"python3 -c \"import json; d=json.load(open('output/result.json')); assert d; print('PASS valid JSON')\"",
|
|
5849
|
+
},
|
|
5850
|
+
projectMutationPaths: [],
|
|
5851
|
+
stdout: "PASS valid JSON\n",
|
|
5852
|
+
stderr: "",
|
|
5853
|
+
};
|
|
5854
|
+
recordProjectVerificationOutcome(
|
|
5855
|
+
scopedTaskState,
|
|
5856
|
+
readOnlyArtifactValidation,
|
|
5857
|
+
{
|
|
5858
|
+
commandCwd: workspace,
|
|
5859
|
+
taskProfile: "auto",
|
|
5860
|
+
allowShellTool: true,
|
|
5861
|
+
sandboxMode: "host",
|
|
5862
|
+
}
|
|
5863
|
+
);
|
|
5864
|
+
recordProjectVerificationOutcome(
|
|
5865
|
+
scopedTaskState,
|
|
5866
|
+
{
|
|
5867
|
+
toolName: "write_file",
|
|
5868
|
+
ok: true,
|
|
5869
|
+
path: path.join(scopedTaskRoot, "agent-result.json"),
|
|
5870
|
+
changes: [
|
|
5871
|
+
{
|
|
5872
|
+
path: path.join(scopedTaskRoot, "agent-result.json"),
|
|
5873
|
+
created: true,
|
|
5874
|
+
beforeHash: "",
|
|
5875
|
+
afterHash: "delivery-manifest",
|
|
5876
|
+
},
|
|
5877
|
+
],
|
|
5878
|
+
},
|
|
5879
|
+
{ commandCwd: workspace, taskProfile: "auto" }
|
|
5880
|
+
);
|
|
5881
|
+
const scopedManifestCommand = {
|
|
5882
|
+
toolName: "run_command",
|
|
5883
|
+
ok: true,
|
|
5884
|
+
exitCode: 0,
|
|
5885
|
+
args: {
|
|
5886
|
+
command: `printf '%s\\n' '{}' > ${JSON.stringify(
|
|
5887
|
+
path.join(scopedTaskRoot, "agent-result.json")
|
|
5888
|
+
)}`,
|
|
5889
|
+
},
|
|
5890
|
+
stdout: "",
|
|
5891
|
+
stderr: "",
|
|
5892
|
+
};
|
|
5893
|
+
recordProjectVerificationOutcome(
|
|
5894
|
+
scopedTaskState,
|
|
5895
|
+
scopedManifestCommand,
|
|
5896
|
+
{
|
|
5897
|
+
commandCwd: workspace,
|
|
5898
|
+
taskProfile: "auto",
|
|
5899
|
+
allowShellTool: true,
|
|
5900
|
+
sandboxMode: "host",
|
|
5901
|
+
}
|
|
5902
|
+
);
|
|
5903
|
+
const pythonScopedManifestCommand = {
|
|
5904
|
+
toolName: "run_command",
|
|
5905
|
+
ok: true,
|
|
5906
|
+
exitCode: 0,
|
|
5907
|
+
args: {
|
|
5908
|
+
command: [
|
|
5909
|
+
"python3 - <<'PY'",
|
|
5910
|
+
`out = ${JSON.stringify(path.join(scopedTaskRoot, "agent-result.json"))}`,
|
|
5911
|
+
"with open(out, 'w', encoding='utf-8') as handle:",
|
|
5912
|
+
" handle.write('{}')",
|
|
5913
|
+
"PY",
|
|
5914
|
+
].join("\n"),
|
|
5915
|
+
},
|
|
5916
|
+
projectMutationPaths: [],
|
|
5917
|
+
stdout: "",
|
|
5918
|
+
stderr: "",
|
|
5919
|
+
};
|
|
5920
|
+
recordProjectVerificationOutcome(
|
|
5921
|
+
scopedTaskState,
|
|
5922
|
+
pythonScopedManifestCommand,
|
|
5923
|
+
{
|
|
5924
|
+
commandCwd: workspace,
|
|
5925
|
+
taskProfile: "auto",
|
|
5926
|
+
allowShellTool: true,
|
|
5927
|
+
sandboxMode: "host",
|
|
5928
|
+
}
|
|
5929
|
+
);
|
|
5930
|
+
assert(
|
|
5931
|
+
requestedOutputRevision === 1 &&
|
|
5932
|
+
scopedTaskState.meta.projectVerification?.mutationRevision === 1 &&
|
|
5933
|
+
readOnlyArtifactValidation.readOnlyArtifactValidation === true &&
|
|
5934
|
+
scopedManifestCommand.scopedTaskArtifactWrite === true &&
|
|
5935
|
+
pythonScopedManifestCommand.scopedTaskArtifactWrite === true,
|
|
5936
|
+
"task-scoped delivery bookkeeping invalidated requested artifact evidence"
|
|
5937
|
+
);
|
|
5938
|
+
const mutatingInlinePython = {
|
|
5939
|
+
toolName: "run_command",
|
|
5940
|
+
ok: true,
|
|
5941
|
+
exitCode: 0,
|
|
5942
|
+
args: {
|
|
5943
|
+
command: "python3 -c \"open('output/side.txt','w').write('changed')\"",
|
|
5944
|
+
},
|
|
5945
|
+
projectMutationPaths: [],
|
|
5946
|
+
stdout: "",
|
|
5947
|
+
stderr: "",
|
|
5948
|
+
};
|
|
5949
|
+
recordProjectVerificationOutcome(
|
|
5950
|
+
scopedTaskState,
|
|
5951
|
+
mutatingInlinePython,
|
|
5952
|
+
{
|
|
5953
|
+
commandCwd: workspace,
|
|
5954
|
+
taskProfile: "auto",
|
|
5955
|
+
allowShellTool: true,
|
|
5956
|
+
sandboxMode: "host",
|
|
5957
|
+
}
|
|
5958
|
+
);
|
|
5959
|
+
assert(
|
|
5960
|
+
scopedTaskState.meta.projectVerification?.mutationRevision === 2 &&
|
|
5961
|
+
mutatingInlinePython.readOnlyArtifactValidation !== true,
|
|
5962
|
+
"write-capable inline Python was incorrectly classified as read-only validation"
|
|
5963
|
+
);
|
|
5803
5964
|
const privateVerifierCommand =
|
|
5804
5965
|
"python3 .aginti/verification/lifecycle/smoke_test.py";
|
|
5805
5966
|
const privateVerifierState = {
|
|
@@ -8080,6 +8241,34 @@ try {
|
|
|
8080
8241
|
sourceGroundingRefreshState.meta.activeExecutionContract.requiresSourceGrounding === true,
|
|
8081
8242
|
"a concrete file correction did not require current source grounding"
|
|
8082
8243
|
);
|
|
8244
|
+
const scopedStaticArtifactRequest =
|
|
8245
|
+
"Create and verify output/parity/result.json with one JSON object. Read it back and finish.";
|
|
8246
|
+
const scopedStaticArtifactGoal = [
|
|
8247
|
+
"You are the persistent LabCanvas agent.",
|
|
8248
|
+
`AGINTI_EVIDENCE_SCOPE_JSON: ${JSON.stringify({
|
|
8249
|
+
mode: "task",
|
|
8250
|
+
request: scopedStaticArtifactRequest,
|
|
8251
|
+
artifact_root: "/tmp/labcanvas-task-1",
|
|
8252
|
+
})}`,
|
|
8253
|
+
"Read AGENTS.md and inspect implementation before editing.",
|
|
8254
|
+
].join("\n\n");
|
|
8255
|
+
const scopedStaticArtifactState = {
|
|
8256
|
+
goal: scopedStaticArtifactGoal,
|
|
8257
|
+
meta: {
|
|
8258
|
+
taskProfile: "auto",
|
|
8259
|
+
goalContract: {
|
|
8260
|
+
revision: 10,
|
|
8261
|
+
currentRequest: scopedStaticArtifactGoal,
|
|
8262
|
+
},
|
|
8263
|
+
projectVerification: { mutationRevision: 0 },
|
|
8264
|
+
},
|
|
8265
|
+
};
|
|
8266
|
+
resetSameTaskExecutionContract(scopedStaticArtifactState, 10);
|
|
8267
|
+
assert(
|
|
8268
|
+
scopedStaticArtifactState.meta.activeExecutionContract.requiresFileMutation === true &&
|
|
8269
|
+
scopedStaticArtifactState.meta.activeExecutionContract.requiresSourceGrounding === false,
|
|
8270
|
+
"LabCanvas wrapper instructions leaked into the scoped static-artifact execution contract"
|
|
8271
|
+
);
|
|
8083
8272
|
const concreteBudgetConfig = { maxSteps: 81, resetStepBudget: false };
|
|
8084
8273
|
assert(
|
|
8085
8274
|
applyConcreteContinuationStepBudgetBoundary(
|
|
@@ -11426,6 +11615,29 @@ try {
|
|
|
11426
11615
|
);
|
|
11427
11616
|
assert(artifactProgress.justActivated, "exact output mutation did not activate artifact validation");
|
|
11428
11617
|
assert(artifactState.meta.artifactProgress.complete, "exact output progress was not persisted");
|
|
11618
|
+
const commandArtifactState = {
|
|
11619
|
+
meta: {
|
|
11620
|
+
scs: {
|
|
11621
|
+
taskContract: {
|
|
11622
|
+
exactOutputPaths: ["output/generated.json"],
|
|
11623
|
+
},
|
|
11624
|
+
},
|
|
11625
|
+
},
|
|
11626
|
+
};
|
|
11627
|
+
const commandArtifactProgress = recordExactOutputProgress(
|
|
11628
|
+
commandArtifactState,
|
|
11629
|
+
{
|
|
11630
|
+
ok: true,
|
|
11631
|
+
toolName: "run_command",
|
|
11632
|
+
verifiedGeneratedOutputPaths: ["output/generated.json"],
|
|
11633
|
+
},
|
|
11634
|
+
{ commandCwd: workspace }
|
|
11635
|
+
);
|
|
11636
|
+
assert(
|
|
11637
|
+
commandArtifactProgress.justActivated &&
|
|
11638
|
+
commandArtifactState.meta.artifactProgress.complete,
|
|
11639
|
+
"snapshot-verified shell output did not activate exact artifact progress"
|
|
11640
|
+
);
|
|
11429
11641
|
assert(
|
|
11430
11642
|
nextStepRuntimeConfig({ provider: "localllm" }, artifactState).artifactValidationPhase === true,
|
|
11431
11643
|
"next step did not enter artifact validation mode"
|
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
} from "../src/context-budget-controller.js";
|
|
16
16
|
import { maxStepsForExecutionPolicy, selectExecutionPolicy } from "../src/execution-policy.js";
|
|
17
17
|
import { SessionStore } from "../src/session-store.js";
|
|
18
|
+
import { selectSkillsForGoal } from "../src/skill-library.js";
|
|
19
|
+
import { scopedChatopsEvidenceGoal } from "../src/scs-evidence.js";
|
|
18
20
|
|
|
19
21
|
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
20
22
|
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "agintiflow-execution-policy-"));
|
|
@@ -97,6 +99,46 @@ try {
|
|
|
97
99
|
assert(responseOnlyConfig.executionTier === "focused", "response-only runtime did not select focused execution");
|
|
98
100
|
assert(!responseOnlyConfig.executionPolicy.requiresPlan, "response-only runtime still requires a plan");
|
|
99
101
|
|
|
102
|
+
const scopedArtifactGoal = [
|
|
103
|
+
"LabCanvas host wrapper: use browser automation, deep research, source ingestion, and recovery skills when relevant.",
|
|
104
|
+
"General host guidance: inspect complex repositories carefully and create a plan for difficult work.",
|
|
105
|
+
`AGINTI_EVIDENCE_SCOPE_JSON: ${JSON.stringify({
|
|
106
|
+
mode: "task",
|
|
107
|
+
request: "Create and verify output/parity/scoped-artifact.json with one valid JSON object.",
|
|
108
|
+
})}`,
|
|
109
|
+
].join("\n");
|
|
110
|
+
const scopedArtifactConfig = resolveRuntimeConfig(
|
|
111
|
+
{
|
|
112
|
+
provider: "mock",
|
|
113
|
+
routingMode: "smart",
|
|
114
|
+
model: "mock-agent",
|
|
115
|
+
goal: scopedArtifactGoal,
|
|
116
|
+
taskProfile: "auto",
|
|
117
|
+
enableScs: "auto",
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
baseDir: runtimeDir,
|
|
121
|
+
packageDir: repoRoot,
|
|
122
|
+
provider: "mock",
|
|
123
|
+
routingMode: "smart",
|
|
124
|
+
model: "mock-agent",
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
assert(
|
|
128
|
+
scopedArtifactConfig.executionTier === "focused" && !scopedArtifactConfig.executionPolicy.requiresPlan,
|
|
129
|
+
"host wrapper keywords inflated a scoped static-artifact task into planned execution"
|
|
130
|
+
);
|
|
131
|
+
assert(!scopedArtifactConfig.scsActive, "host wrapper keywords incorrectly activated SCS for a scoped static artifact");
|
|
132
|
+
const scopedSkillIds = selectSkillsForGoal(
|
|
133
|
+
scopedChatopsEvidenceGoal(scopedArtifactGoal, "auto"),
|
|
134
|
+
{ taskProfile: "auto", limit: 6, projectRoot: workspace }
|
|
135
|
+
).map((skill) => skill.id);
|
|
136
|
+
assert(scopedSkillIds.includes("structured-json"), "scoped JSON task did not retain its relevant structured-data skill");
|
|
137
|
+
assert(
|
|
138
|
+
!scopedSkillIds.some((id) => ["source-ingestion", "autonomous-artifact-pipeline", "wechat-labcanvas-chatops"].includes(id)),
|
|
139
|
+
`literal paths or payload values selected unrelated skills: ${scopedSkillIds.join(", ")}`
|
|
140
|
+
);
|
|
141
|
+
|
|
100
142
|
const simpleConfig = resolveRuntimeConfig(
|
|
101
143
|
{
|
|
102
144
|
provider: "mock",
|
|
@@ -807,6 +807,17 @@ const readinessOnlyContract = deriveScsTaskContract({
|
|
|
807
807
|
].join("\n"),
|
|
808
808
|
taskProfile: "auto",
|
|
809
809
|
});
|
|
810
|
+
const releaseProofFilenameContract = deriveScsTaskContract({
|
|
811
|
+
goal: [
|
|
812
|
+
'AGINTI_EVIDENCE_SCOPE_JSON: {"mode":"task","request":"Create a task-owned plain-text artifact named scoped-path-release-proof.txt, read it back, and finish without external actions."}',
|
|
813
|
+
"The host writes a final task record after the agent finishes.",
|
|
814
|
+
].join("\n"),
|
|
815
|
+
taskProfile: "auto",
|
|
816
|
+
});
|
|
817
|
+
const explicitPackageReleaseContract = deriveScsTaskContract({
|
|
818
|
+
goal: "Release the package to npm and verify the published version.",
|
|
819
|
+
taskProfile: "auto",
|
|
820
|
+
});
|
|
810
821
|
assert(
|
|
811
822
|
readinessOnlyContract.requiredEvidence.some((item) => item.category === "file") &&
|
|
812
823
|
readinessOnlyContract.requiredEvidence.some((item) => item.category === "command"),
|
|
@@ -816,6 +827,15 @@ assert(
|
|
|
816
827
|
!readinessOnlyContract.requiredEvidence.some((item) => ["publish", "browser", "visual", "artifact"].includes(item.category)),
|
|
817
828
|
"read-only readiness contract required a forbidden external action or target artifact"
|
|
818
829
|
);
|
|
830
|
+
assert(
|
|
831
|
+
releaseProofFilenameContract.requiredEvidence.some((item) => item.category === "file") &&
|
|
832
|
+
!releaseProofFilenameContract.requiredEvidence.some((item) => item.category === "publish"),
|
|
833
|
+
"a release-like artifact filename fabricated an external publication obligation"
|
|
834
|
+
);
|
|
835
|
+
assert(
|
|
836
|
+
explicitPackageReleaseContract.requiredEvidence.some((item) => item.category === "publish"),
|
|
837
|
+
"an explicit package release lost its publication evidence obligation"
|
|
838
|
+
);
|
|
819
839
|
assert(
|
|
820
840
|
uploadContract.exactInputPaths.includes("/tmp/reference-a.png") &&
|
|
821
841
|
uploadContract.exactInputPaths.includes("/tmp/reference-b.png") &&
|
|
@@ -1131,6 +1151,13 @@ const canvasArtifactContract = deriveScsTaskContract({
|
|
|
1131
1151
|
const jsonObjectContract = deriveScsTaskContract({
|
|
1132
1152
|
goal: "Extract a valid JSON object with schema from this text.",
|
|
1133
1153
|
});
|
|
1154
|
+
const scopedStaticJsonContract = deriveScsTaskContract({
|
|
1155
|
+
goal: [
|
|
1156
|
+
"Host wrapper: validate code, run commands, inspect browsers, and perform deep research when the request needs them.",
|
|
1157
|
+
'AGINTI_EVIDENCE_SCOPE_JSON: {"mode":"task","request":"Create and verify output/parity/aginti_verified_artifact.json with one valid JSON object, then read it back."}',
|
|
1158
|
+
].join("\n"),
|
|
1159
|
+
taskProfile: "code",
|
|
1160
|
+
});
|
|
1134
1161
|
const virtualFileContract = deriveScsTaskContract({
|
|
1135
1162
|
goal: "Create file: /workspace/virtual-output.txt with virtual Docker path support.",
|
|
1136
1163
|
});
|
|
@@ -1210,6 +1237,20 @@ assert(
|
|
|
1210
1237
|
!jsonObjectContract.requiredEvidence.some((item) => item.category === "file"),
|
|
1211
1238
|
"JSON object extraction should not be treated as a workspace file requirement without an explicit file/path"
|
|
1212
1239
|
);
|
|
1240
|
+
assert(
|
|
1241
|
+
scopedStaticJsonContract.requiredEvidence.some((item) => item.category === "file") &&
|
|
1242
|
+
!scopedStaticJsonContract.requiredEvidence.some((item) => item.category === "command"),
|
|
1243
|
+
"a scoped standalone JSON artifact should require file evidence without an unrelated shell command"
|
|
1244
|
+
);
|
|
1245
|
+
assert(
|
|
1246
|
+
scopedStaticJsonContract.exactOutputPaths.includes("output/parity/aginti_verified_artifact.json") &&
|
|
1247
|
+
!scopedStaticJsonContract.exactInputPaths.includes("output/parity/aginti_verified_artifact.json"),
|
|
1248
|
+
"create-and-verify should retain the structured-data path as an output rather than an input"
|
|
1249
|
+
);
|
|
1250
|
+
assert(
|
|
1251
|
+
scopedStaticJsonContract.requiredExecutableTerms.length === 0,
|
|
1252
|
+
"a required JSON boolean value was misclassified as executable production-source syntax"
|
|
1253
|
+
);
|
|
1213
1254
|
assert(
|
|
1214
1255
|
virtualFileContract.requiredEvidence.some((item) => item.category === "file") &&
|
|
1215
1256
|
!virtualFileContract.requiredEvidence.some((item) => item.category === "artifact"),
|
package/src/agent-runner.js
CHANGED
|
@@ -364,11 +364,14 @@ function textToolRetryInstruction(response) {
|
|
|
364
364
|
|
|
365
365
|
function buildScsRuntimeContext(config = {}, state = {}, extra = {}) {
|
|
366
366
|
const projectRoot = config.commandCwd || config.baseDir || process.cwd();
|
|
367
|
-
const selectedSkills = isRetainedWorkspaceProfile(config) ? [] : selectSkillsForGoal(
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
367
|
+
const selectedSkills = isRetainedWorkspaceProfile(config) ? [] : selectSkillsForGoal(
|
|
368
|
+
scopedChatopsEvidenceGoal(state.goal || config.goal || "", config.taskProfile),
|
|
369
|
+
{
|
|
370
|
+
taskProfile: config.taskProfile,
|
|
371
|
+
limit: 6,
|
|
372
|
+
projectRoot,
|
|
373
|
+
}
|
|
374
|
+
);
|
|
372
375
|
const verification = state.meta?.projectVerification || {};
|
|
373
376
|
const mutationRevision = Number(verification.mutationRevision || 0);
|
|
374
377
|
const privateMutationRevision = Number(verification.privateMutationRevision || 0);
|
|
@@ -435,11 +438,14 @@ function buildScsRuntimeContext(config = {}, state = {}, extra = {}) {
|
|
|
435
438
|
|
|
436
439
|
function withSelectedSkillReadOnlyRoots(config = {}, state = {}) {
|
|
437
440
|
const projectRoot = config.commandCwd || config.baseDir || process.cwd();
|
|
438
|
-
const selectedSkills = isRetainedWorkspaceProfile(config) ? [] : selectSkillsForGoal(
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
441
|
+
const selectedSkills = isRetainedWorkspaceProfile(config) ? [] : selectSkillsForGoal(
|
|
442
|
+
scopedChatopsEvidenceGoal(state.goal || config.goal || "", config.taskProfile),
|
|
443
|
+
{
|
|
444
|
+
taskProfile: config.taskProfile,
|
|
445
|
+
limit: 6,
|
|
446
|
+
projectRoot,
|
|
447
|
+
}
|
|
448
|
+
);
|
|
443
449
|
const skillReadOnlyRoots = [
|
|
444
450
|
...(Array.isArray(config.skillReadOnlyRoots) ? config.skillReadOnlyRoots : []),
|
|
445
451
|
...selectedSkills.map((skill) => skill.path).filter(Boolean),
|
|
@@ -2891,7 +2897,11 @@ async function createInitialState(config, sessionId) {
|
|
|
2891
2897
|
const projectRoot = config.commandCwd || config.baseDir || process.cwd();
|
|
2892
2898
|
const selectedSkills = isRetainedWorkspaceProfile(config)
|
|
2893
2899
|
? []
|
|
2894
|
-
: selectSkillsForGoal(config.goal,
|
|
2900
|
+
: selectSkillsForGoal(scopedChatopsEvidenceGoal(config.goal, config.taskProfile), {
|
|
2901
|
+
taskProfile: config.taskProfile,
|
|
2902
|
+
limit: 6,
|
|
2903
|
+
projectRoot,
|
|
2904
|
+
});
|
|
2895
2905
|
const skillContext = formatSkillsForPrompt(selectedSkills);
|
|
2896
2906
|
const projectInstructions = await readProjectInstructions(config.baseDir || config.commandCwd || process.cwd());
|
|
2897
2907
|
const projectInstructionContext = formatProjectInstructions(projectInstructions);
|
|
@@ -4050,9 +4060,12 @@ export function resetSameTaskExecutionContract(state = {}, revision = 0) {
|
|
|
4050
4060
|
refreshPersistedProjectAcceptance(state);
|
|
4051
4061
|
const activeRevision = Math.max(0, Number(revision || state.meta?.goalContract?.revision || 0));
|
|
4052
4062
|
const currentRequest = String(state.meta?.goalContract?.currentRequest || state.goal || "").trim();
|
|
4063
|
+
const taskProfile = state.meta?.taskProfile || "auto";
|
|
4064
|
+
const scopedCurrentRequest =
|
|
4065
|
+
scopedChatopsEvidenceGoal(currentRequest, taskProfile) || currentRequest;
|
|
4053
4066
|
const currentTurnContract = deriveScsTaskContract({
|
|
4054
|
-
goal:
|
|
4055
|
-
taskProfile
|
|
4067
|
+
goal: scopedCurrentRequest,
|
|
4068
|
+
taskProfile,
|
|
4056
4069
|
});
|
|
4057
4070
|
const currentTurnCommands = normalizedRequiredProjectCommands(
|
|
4058
4071
|
currentTurnContract.requiredProjectCommands
|
|
@@ -4094,7 +4107,7 @@ export function resetSameTaskExecutionContract(state = {}, revision = 0) {
|
|
|
4094
4107
|
currentTurnContract.requiresSourceGrounding === true ||
|
|
4095
4108
|
(
|
|
4096
4109
|
currentTurnContract.requiresFileMutation === true &&
|
|
4097
|
-
goalClearlyAllowsOverwrite(
|
|
4110
|
+
goalClearlyAllowsOverwrite(scopedCurrentRequest)
|
|
4098
4111
|
)
|
|
4099
4112
|
),
|
|
4100
4113
|
requiredProjectCommands: currentTurnCommands,
|
|
@@ -4208,7 +4221,11 @@ async function applyContinuationPrompt(state, config, observers) {
|
|
|
4208
4221
|
const projectRoot = config.commandCwd || config.baseDir || process.cwd();
|
|
4209
4222
|
const selectedSkills = isRetainedWorkspaceProfile(config)
|
|
4210
4223
|
? []
|
|
4211
|
-
: selectSkillsForGoal(config.goal,
|
|
4224
|
+
: selectSkillsForGoal(scopedChatopsEvidenceGoal(config.goal, config.taskProfile), {
|
|
4225
|
+
taskProfile: config.taskProfile,
|
|
4226
|
+
limit: 6,
|
|
4227
|
+
projectRoot,
|
|
4228
|
+
});
|
|
4212
4229
|
const skillContext = formatSkillsForPrompt(selectedSkills);
|
|
4213
4230
|
const projectInstructions = await readProjectInstructions(config.baseDir || config.commandCwd || process.cwd());
|
|
4214
4231
|
state.meta = state.meta || {};
|
|
@@ -6384,9 +6401,9 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
6384
6401
|
}
|
|
6385
6402
|
}
|
|
6386
6403
|
|
|
6387
|
-
const projectMutationPaths = successfulProjectMutationPaths(toolResult);
|
|
6404
|
+
const projectMutationPaths = successfulProjectMutationPaths(toolResult, state, config);
|
|
6388
6405
|
const privateMutationPaths = successfulPrivateVerificationMutationPaths(toolResult);
|
|
6389
|
-
const materialMutationPaths = materialProjectMutationPaths(toolResult);
|
|
6406
|
+
const materialMutationPaths = materialProjectMutationPaths(toolResult, state, config);
|
|
6390
6407
|
if (["write_file", "apply_patch"].includes(toolName) && privateMutationPaths.length) {
|
|
6391
6408
|
delete state.meta.verifiedCompletionCandidate;
|
|
6392
6409
|
verification.privateMutationRevision += 1;
|
|
@@ -6549,12 +6566,23 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
6549
6566
|
config,
|
|
6550
6567
|
{ verificationCommand }
|
|
6551
6568
|
);
|
|
6569
|
+
const scopedTaskArtifactWrite = commandWritesOnlyScopedTaskArtifacts(
|
|
6570
|
+
mutationCommand,
|
|
6571
|
+
state,
|
|
6572
|
+
config
|
|
6573
|
+
);
|
|
6574
|
+
const readOnlyArtifactValidation = Boolean(
|
|
6575
|
+
commandMutationPaths.length === 0 &&
|
|
6576
|
+
commandIsBoundedReadOnlyArtifactValidation(mutationCommand)
|
|
6577
|
+
);
|
|
6552
6578
|
const projectContentMutation = Boolean(
|
|
6553
6579
|
command &&
|
|
6554
6580
|
toolResult.blocked !== true &&
|
|
6555
6581
|
!retainedExactVerification &&
|
|
6556
6582
|
!disposableGeneratedCleanup &&
|
|
6557
6583
|
!disposableGeneratedVerificationSideEffects &&
|
|
6584
|
+
!scopedTaskArtifactWrite &&
|
|
6585
|
+
!readOnlyArtifactValidation &&
|
|
6558
6586
|
(commandSucceeded || commandMutationPaths.length > 0) &&
|
|
6559
6587
|
(
|
|
6560
6588
|
commandCanMutateProjectContent(mutationCommand, commandPolicy) ||
|
|
@@ -6569,6 +6597,12 @@ export function recordProjectVerificationOutcome(state = {}, toolResult = {}, co
|
|
|
6569
6597
|
toolResult.disposableGeneratedVerificationSideEffects = true;
|
|
6570
6598
|
toolResult.disposableGeneratedVerificationPaths = commandMutationPaths;
|
|
6571
6599
|
}
|
|
6600
|
+
if (scopedTaskArtifactWrite) {
|
|
6601
|
+
toolResult.scopedTaskArtifactWrite = true;
|
|
6602
|
+
}
|
|
6603
|
+
if (readOnlyArtifactValidation) {
|
|
6604
|
+
toolResult.readOnlyArtifactValidation = true;
|
|
6605
|
+
}
|
|
6572
6606
|
let requiredBatch = currentRequiredCommandBatch(verification, requiredCommands);
|
|
6573
6607
|
const activeExecutionContract = state.meta?.activeExecutionContract;
|
|
6574
6608
|
const activeTurnCommands =
|
|
@@ -12084,7 +12118,27 @@ function isPrivateVerificationEvidencePath(value = "") {
|
|
|
12084
12118
|
);
|
|
12085
12119
|
}
|
|
12086
12120
|
|
|
12087
|
-
function
|
|
12121
|
+
function isScopedTaskArtifactEvidencePath(value = "", state = {}, config = {}) {
|
|
12122
|
+
const artifactRoot = scopedArtifactRoot(completionContractGoal(config, state));
|
|
12123
|
+
if (!artifactRoot) return false;
|
|
12124
|
+
const raw = String(value || "")
|
|
12125
|
+
.trim()
|
|
12126
|
+
.replace(/^(["'])|(["'])$/g, "")
|
|
12127
|
+
.replace(/\\/g, "/");
|
|
12128
|
+
if (!raw || raw.includes("\0") || /^https?:\/\//i.test(raw)) return false;
|
|
12129
|
+
const commandCwd = path.resolve(
|
|
12130
|
+
config.commandCwd || state.commandCwd || process.cwd()
|
|
12131
|
+
);
|
|
12132
|
+
const absoluteRoot = path.resolve(commandCwd, artifactRoot);
|
|
12133
|
+
const absoluteCandidate = path.resolve(commandCwd, raw);
|
|
12134
|
+
const relative = path.relative(absoluteRoot, absoluteCandidate);
|
|
12135
|
+
return Boolean(
|
|
12136
|
+
relative === "" ||
|
|
12137
|
+
(!relative.startsWith("..") && !path.isAbsolute(relative))
|
|
12138
|
+
);
|
|
12139
|
+
}
|
|
12140
|
+
|
|
12141
|
+
function commandWritesOnlyEvidenceMatching(command = "", pathMatches = () => false) {
|
|
12088
12142
|
const normalized = String(command || "").trim();
|
|
12089
12143
|
if (!normalized) return false;
|
|
12090
12144
|
const tokens = tokenizeShellWords(normalized);
|
|
@@ -12093,27 +12147,97 @@ function commandWritesOnlyPrivateVerificationEvidence(command = "") {
|
|
|
12093
12147
|
if (["-a", "--append"].includes(tokens[index])) index += 1;
|
|
12094
12148
|
if (tokens[index] === "--") index += 1;
|
|
12095
12149
|
const targets = tokens.slice(index);
|
|
12096
|
-
return targets.length > 0 && targets.every(
|
|
12150
|
+
return targets.length > 0 && targets.every(pathMatches);
|
|
12097
12151
|
}
|
|
12098
12152
|
if (tokens[0] === "mkdir") {
|
|
12099
12153
|
const targets = tokens.slice(1).filter((token) => token !== "-p" && token !== "--");
|
|
12100
|
-
return targets.length > 0 && targets.every(
|
|
12154
|
+
return targets.length > 0 && targets.every(pathMatches);
|
|
12101
12155
|
}
|
|
12102
12156
|
|
|
12103
|
-
let
|
|
12104
|
-
const
|
|
12157
|
+
let strippedEvidenceRedirect = false;
|
|
12158
|
+
const withoutEvidenceRedirects = normalized.replace(
|
|
12105
12159
|
/(^|\s)(?:\d*>>?|&>>?)\s*("[^"]+"|'[^']+'|[^\s;&|]+)/g,
|
|
12106
12160
|
(match, prefix, target) => {
|
|
12107
|
-
if (!
|
|
12108
|
-
|
|
12161
|
+
if (!pathMatches(target)) return match;
|
|
12162
|
+
strippedEvidenceRedirect = true;
|
|
12109
12163
|
return prefix;
|
|
12110
12164
|
}
|
|
12111
12165
|
).trim();
|
|
12112
|
-
if (!
|
|
12113
|
-
const underlyingPolicy = classifyCommand(
|
|
12166
|
+
if (!strippedEvidenceRedirect || !withoutEvidenceRedirects) return false;
|
|
12167
|
+
const underlyingPolicy = classifyCommand(withoutEvidenceRedirects);
|
|
12114
12168
|
return underlyingPolicy.writesWorkspace !== true && underlyingPolicy.mayMutateProject !== true;
|
|
12115
12169
|
}
|
|
12116
12170
|
|
|
12171
|
+
function commandWritesOnlyPrivateVerificationEvidence(command = "") {
|
|
12172
|
+
return commandWritesOnlyEvidenceMatching(
|
|
12173
|
+
command,
|
|
12174
|
+
isPrivateVerificationEvidencePath
|
|
12175
|
+
);
|
|
12176
|
+
}
|
|
12177
|
+
|
|
12178
|
+
function commandWritesOnlyScopedTaskArtifacts(command = "", state = {}, config = {}) {
|
|
12179
|
+
if (commandWritesOnlyEvidenceMatching(
|
|
12180
|
+
command,
|
|
12181
|
+
(candidate) => isScopedTaskArtifactEvidencePath(candidate, state, config)
|
|
12182
|
+
)) {
|
|
12183
|
+
return true;
|
|
12184
|
+
}
|
|
12185
|
+
const normalized = String(command || "").trim();
|
|
12186
|
+
const artifactRoot = scopedArtifactRoot(completionContractGoal(config, state));
|
|
12187
|
+
if (!normalized || !artifactRoot) return false;
|
|
12188
|
+
const assignments = new Map();
|
|
12189
|
+
for (const match of normalized.matchAll(
|
|
12190
|
+
/\b([A-Za-z_]\w*)\s*=\s*("[^"\n]+"|'[^'\n]+')/g
|
|
12191
|
+
)) {
|
|
12192
|
+
assignments.set(match[1], match[2]);
|
|
12193
|
+
}
|
|
12194
|
+
const writeTargets = [];
|
|
12195
|
+
for (const match of normalized.matchAll(
|
|
12196
|
+
/\bopen\s*\(\s*([^,\n]+)\s*,\s*(["'][^"']*[wax+][^"']*["'])/gi
|
|
12197
|
+
)) {
|
|
12198
|
+
const operand = String(match[1] || "").trim();
|
|
12199
|
+
const target = assignments.get(operand) || operand;
|
|
12200
|
+
if (!/^(?:"[^"\n]+"|'[^'\n]+')$/.test(target)) return false;
|
|
12201
|
+
writeTargets.push(target);
|
|
12202
|
+
}
|
|
12203
|
+
return Boolean(
|
|
12204
|
+
writeTargets.length > 0 &&
|
|
12205
|
+
writeTargets.every((candidate) =>
|
|
12206
|
+
isScopedTaskArtifactEvidencePath(candidate, state, config)
|
|
12207
|
+
)
|
|
12208
|
+
);
|
|
12209
|
+
}
|
|
12210
|
+
|
|
12211
|
+
function commandIsBoundedReadOnlyArtifactValidation(command = "") {
|
|
12212
|
+
const normalized = String(command || "").trim();
|
|
12213
|
+
if (!normalized) return false;
|
|
12214
|
+
if (
|
|
12215
|
+
!/\bassert\b|\bjson\.(?:load|loads)\s*\(|\bJSON\.parse\s*\(|\bjq\b|\bsha256sum\b|\bmd5sum\b|\b(?:valid|pass|verified?)\b/i.test(
|
|
12216
|
+
normalized
|
|
12217
|
+
)
|
|
12218
|
+
) {
|
|
12219
|
+
return false;
|
|
12220
|
+
}
|
|
12221
|
+
// Heredoc input (`<<`) is compatible with read-only validation. Any output
|
|
12222
|
+
// redirection or known mutator keeps conservative project revision tracking.
|
|
12223
|
+
if (/(^|[^<])>{1,2}(?!=)/m.test(normalized)) return false;
|
|
12224
|
+
if (
|
|
12225
|
+
/\b(?:cp|install|mkdir|mv|rm|rmdir|tee|touch|truncate)\b|\bsed\s+-i\b|\bperl\s+-pi\b/i.test(
|
|
12226
|
+
normalized
|
|
12227
|
+
)
|
|
12228
|
+
) {
|
|
12229
|
+
return false;
|
|
12230
|
+
}
|
|
12231
|
+
if (
|
|
12232
|
+
/\bopen\s*\([^\n)]*,\s*["'][^"']*[wax+][^"']*["']|\.(?:append|mkdir|rename|replace|rmdir|touch|unlink|write|write_bytes|write_text)\s*\(|\b(?:os\.(?:makedirs|mkdir|remove|rename|replace|rmdir|system|unlink)|shutil\.|subprocess\.)/i.test(
|
|
12233
|
+
normalized
|
|
12234
|
+
)
|
|
12235
|
+
) {
|
|
12236
|
+
return false;
|
|
12237
|
+
}
|
|
12238
|
+
return true;
|
|
12239
|
+
}
|
|
12240
|
+
|
|
12117
12241
|
const DISPOSABLE_GENERATED_PATH_SEGMENTS = new Set([
|
|
12118
12242
|
".build",
|
|
12119
12243
|
".gradle",
|
|
@@ -12974,6 +13098,17 @@ export function canonicalizeVerifiedArtifactCompletion(state = {}, result = "")
|
|
|
12974
13098
|
function successfulMutationPaths(toolResult = {}) {
|
|
12975
13099
|
if (!toolResult || toolResult.ok === false || toolResult.blocked || toolResult.skipped) return [];
|
|
12976
13100
|
if (toolResult.toolName === "deep_research" && toolResult.reportPath) return [toolResult.reportPath];
|
|
13101
|
+
if (toolResult.toolName === "run_command") {
|
|
13102
|
+
return [
|
|
13103
|
+
...new Set(
|
|
13104
|
+
(Array.isArray(toolResult.verifiedGeneratedOutputPaths)
|
|
13105
|
+
? toolResult.verifiedGeneratedOutputPaths
|
|
13106
|
+
: [])
|
|
13107
|
+
.map((item) => String(item || "").trim())
|
|
13108
|
+
.filter(Boolean)
|
|
13109
|
+
),
|
|
13110
|
+
];
|
|
13111
|
+
}
|
|
12977
13112
|
if (!["write_file", "apply_patch"].includes(String(toolResult.toolName || ""))) return [];
|
|
12978
13113
|
const changes = [
|
|
12979
13114
|
...(Array.isArray(toolResult.changes) ? toolResult.changes : []),
|
|
@@ -13026,9 +13161,11 @@ function successfulWorkspaceMutationPaths(toolResult = {}) {
|
|
|
13026
13161
|
];
|
|
13027
13162
|
}
|
|
13028
13163
|
|
|
13029
|
-
function successfulProjectMutationPaths(toolResult = {}) {
|
|
13164
|
+
function successfulProjectMutationPaths(toolResult = {}, state = {}, config = {}) {
|
|
13030
13165
|
return successfulWorkspaceMutationPaths(toolResult).filter(
|
|
13031
|
-
(candidate) =>
|
|
13166
|
+
(candidate) =>
|
|
13167
|
+
!isPrivateVerificationEvidencePath(candidate) &&
|
|
13168
|
+
!isScopedTaskArtifactEvidencePath(candidate, state, config)
|
|
13032
13169
|
);
|
|
13033
13170
|
}
|
|
13034
13171
|
|
|
@@ -13052,7 +13189,7 @@ function diffHasMaterialContentChange(diff = "") {
|
|
|
13052
13189
|
return JSON.stringify(compactRemoved) !== JSON.stringify(compactAdded);
|
|
13053
13190
|
}
|
|
13054
13191
|
|
|
13055
|
-
function materialProjectMutationPaths(toolResult = {}) {
|
|
13192
|
+
function materialProjectMutationPaths(toolResult = {}, state = {}, config = {}) {
|
|
13056
13193
|
if (!toolResult || toolResult.blocked || toolResult.skipped) {
|
|
13057
13194
|
return [];
|
|
13058
13195
|
}
|
|
@@ -13065,7 +13202,13 @@ function materialProjectMutationPaths(toolResult = {}) {
|
|
|
13065
13202
|
];
|
|
13066
13203
|
const paths = [];
|
|
13067
13204
|
for (const change of changes) {
|
|
13068
|
-
if (
|
|
13205
|
+
if (
|
|
13206
|
+
!change ||
|
|
13207
|
+
isPrivateVerificationEvidencePath(change.path) ||
|
|
13208
|
+
isScopedTaskArtifactEvidencePath(change.path, state, config)
|
|
13209
|
+
) {
|
|
13210
|
+
continue;
|
|
13211
|
+
}
|
|
13069
13212
|
if (
|
|
13070
13213
|
change.created === true ||
|
|
13071
13214
|
change.deleted === true ||
|
|
@@ -18472,7 +18615,7 @@ async function executeTool(browserState, toolCall, snapshot, config, store, obse
|
|
|
18472
18615
|
const isRequiredCommand = requiredCommands.some((candidate) =>
|
|
18473
18616
|
projectCommandsEquivalent(candidate, observedInnerCommand, config)
|
|
18474
18617
|
);
|
|
18475
|
-
const exactOutputSnapshotsBefore =
|
|
18618
|
+
const exactOutputSnapshotsBefore = policy.writesWorkspace && exactOutputPathsForState(state).length
|
|
18476
18619
|
? await captureExactOutputSnapshots(state, config)
|
|
18477
18620
|
: [];
|
|
18478
18621
|
const gitWorktreeBefore = captureMutationScope
|
|
@@ -18562,6 +18705,16 @@ async function executeTool(browserState, toolCall, snapshot, config, store, obse
|
|
|
18562
18705
|
const eventResult = sanitizeToolResult(result);
|
|
18563
18706
|
await store.appendEvent("tool.completed", eventResult);
|
|
18564
18707
|
observers.event("tool.completed", eventResult);
|
|
18708
|
+
for (const generatedPath of generatedOutputPaths) {
|
|
18709
|
+
const change = {
|
|
18710
|
+
path: generatedPath,
|
|
18711
|
+
toolName: "run_command",
|
|
18712
|
+
commandCwd: config.commandCwd,
|
|
18713
|
+
generatedByCommand: true,
|
|
18714
|
+
};
|
|
18715
|
+
await store.appendEvent("file.changed", change);
|
|
18716
|
+
observers.event("file.changed", change);
|
|
18717
|
+
}
|
|
18565
18718
|
return result;
|
|
18566
18719
|
}
|
|
18567
18720
|
case "tmux_list_sessions": {
|
|
@@ -19848,6 +20001,11 @@ async function completionEvidenceDecision({ config, state, store, observers, ste
|
|
|
19848
20001
|
const blocker = deterministicFinishBlocker(assessment.contract, assessment.ledger, assessment.evaluation);
|
|
19849
20002
|
const verificationDeficits = projectVerificationDeficits(state, config);
|
|
19850
20003
|
const requiredEvidence = (assessment.contract.requiredEvidence || []).map((item) => item.category);
|
|
20004
|
+
const requiresProjectTestEvidence = Boolean(
|
|
20005
|
+
requiredEvidence.includes("test") ||
|
|
20006
|
+
projectTestBlock ||
|
|
20007
|
+
verificationDeficits.failedTestRun
|
|
20008
|
+
);
|
|
19851
20009
|
const presentEvidence = assessment.ledger.categories || [];
|
|
19852
20010
|
const progressCount = Number(assessment.progressCount || 0);
|
|
19853
20011
|
const semanticFailureReason = assessment.semantic.checked && !assessment.semantic.ok
|
|
@@ -19881,8 +20039,13 @@ async function completionEvidenceDecision({ config, state, store, observers, ste
|
|
|
19881
20039
|
freshMutationRequirement.artifactQualityRepairRequired,
|
|
19882
20040
|
missingToolCalls: assessment.evaluation.missingToolCalls || [],
|
|
19883
20041
|
pendingProjectCommands: verificationDeficits.pendingCommands,
|
|
19884
|
-
pendingProjectTests:
|
|
19885
|
-
|
|
20042
|
+
pendingProjectTests:
|
|
20043
|
+
requiresProjectTestEvidence && !verificationDeficits.testsCurrent
|
|
20044
|
+
? verificationDeficits.discoveredTests
|
|
20045
|
+
: [],
|
|
20046
|
+
suggestedTestCommands: requiresProjectTestEvidence
|
|
20047
|
+
? verificationDeficits.suggestedTestCommands
|
|
20048
|
+
: [],
|
|
19886
20049
|
projectMutationRevision: verificationDeficits.revision,
|
|
19887
20050
|
failedProjectTestCommand: verificationDeficits.failedTestRun?.command || "",
|
|
19888
20051
|
failedProjectTestSignature: verificationDeficits.failedTestRun?.failureSignature || "",
|
|
@@ -23182,7 +23345,7 @@ async function runAgentOnceUnlocked(config) {
|
|
|
23182
23345
|
|
|
23183
23346
|
try {
|
|
23184
23347
|
throwIfAborted(config);
|
|
23185
|
-
const goalIntent = classifyGoalIntent(config.goal);
|
|
23348
|
+
const goalIntent = classifyGoalIntent(scopedChatopsEvidenceGoal(config.goal, config.taskProfile));
|
|
23186
23349
|
const canFinishDirectly =
|
|
23187
23350
|
!config.resume && !state.plan && Number(state.stepsCompleted || 0) === 0 && isDirectAnswerIntent(goalIntent);
|
|
23188
23351
|
if (canFinishDirectly) {
|
package/src/config.js
CHANGED
|
@@ -25,7 +25,7 @@ import { normalizeDynamicStepsMode } from "./step-budget-controller.js";
|
|
|
25
25
|
import { maxStepsForExecutionPolicy, selectExecutionPolicy } from "./execution-policy.js";
|
|
26
26
|
import { normalizeContextBudgetMode } from "./context-budget-controller.js";
|
|
27
27
|
import { BASELINE_PROVIDER, normalizeProviderBaseURL, normalizeProviderId } from "./provider-contract.js";
|
|
28
|
-
import { isResponseOnlyEvidenceScope } from "./scs-evidence.js";
|
|
28
|
+
import { isResponseOnlyEvidenceScope, scopedChatopsEvidenceGoal } from "./scs-evidence.js";
|
|
29
29
|
|
|
30
30
|
function parseBoolean(value, fallback) {
|
|
31
31
|
if (value === undefined) return fallback;
|
|
@@ -101,6 +101,7 @@ export function resolveRuntimeConfig(args, overrides = {}) {
|
|
|
101
101
|
const requestedProvider = resolveRequestedProvider(overrides, args);
|
|
102
102
|
const routingMode = normalizeRoutingMode(overrides.routingMode || args.routingMode || process.env.AGENT_ROUTING_MODE || "smart");
|
|
103
103
|
const taskProfile = normalizeTaskProfile(overrides.taskProfile || args.taskProfile || process.env.AGINTI_TASK_PROFILE || "auto");
|
|
104
|
+
const taskSelectionGoal = scopedChatopsEvidenceGoal(args.goal || "", taskProfile);
|
|
104
105
|
const language = resolveLanguage(overrides.language || args.language || process.env.AGINTI_LANGUAGE || "");
|
|
105
106
|
// Capability/resource snapshots are trusted runtime inputs. They are deliberately
|
|
106
107
|
// not inferred from ambient cloud credentials or optimistic environment flags.
|
|
@@ -141,7 +142,7 @@ export function resolveRuntimeConfig(args, overrides = {}) {
|
|
|
141
142
|
routingMode: sessionModelLocked ? "manual" : routingMode,
|
|
142
143
|
provider: requestedProvider,
|
|
143
144
|
model: requestedModel,
|
|
144
|
-
goal:
|
|
145
|
+
goal: taskSelectionGoal,
|
|
145
146
|
taskProfile,
|
|
146
147
|
routeProvider,
|
|
147
148
|
routeModel: overrides.routeModel || args.routeModel || process.env.AGINTI_ROUTE_MODEL || "",
|
|
@@ -190,7 +191,7 @@ export function resolveRuntimeConfig(args, overrides = {}) {
|
|
|
190
191
|
overrides.scsValidationMode ?? args.scsValidationMode ?? process.env.AGINTI_SCS_VALIDATION_MODE ?? "auto"
|
|
191
192
|
);
|
|
192
193
|
const scsActive = shouldActivateScs(scsMode, {
|
|
193
|
-
goal:
|
|
194
|
+
goal: taskSelectionGoal,
|
|
194
195
|
taskProfile,
|
|
195
196
|
complexityScore: route.complexityScore,
|
|
196
197
|
});
|
|
@@ -226,7 +227,7 @@ export function resolveRuntimeConfig(args, overrides = {}) {
|
|
|
226
227
|
? normalizeProviderBaseURL(activeProvider, overrides.baseURL || defaults.baseURL)
|
|
227
228
|
: overrides.baseURL || defaults.baseURL;
|
|
228
229
|
const defaultMaxSteps = recommendedMaxStepsForTask({
|
|
229
|
-
goal:
|
|
230
|
+
goal: taskSelectionGoal,
|
|
230
231
|
taskProfile,
|
|
231
232
|
complexityScore: route.complexityScore,
|
|
232
233
|
});
|
package/src/model-client.js
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
estimateToolSchemaTokens,
|
|
32
32
|
} from "./context-budget-controller.js";
|
|
33
33
|
import { attachToolContract } from "./tool-contract.js";
|
|
34
|
+
import { scopedChatopsEvidenceGoal } from "./scs-evidence.js";
|
|
34
35
|
|
|
35
36
|
function isRetainedWorkspaceProfile(config = {}) {
|
|
36
37
|
return config.integrationSessionProfile === INTEGRATION_TEXT_WORKSPACE_PROFILE_ID ||
|
|
@@ -1241,11 +1242,14 @@ export async function createPlan(client, config, state) {
|
|
|
1241
1242
|
const engineeringGuidance = isRetainedWorkspaceProfile(config)
|
|
1242
1243
|
? ""
|
|
1243
1244
|
: engineeringGuidanceForTask(state.goal, config.taskProfile);
|
|
1244
|
-
const selectedSkills = isRetainedWorkspaceProfile(config) ? [] : selectSkillsForGoal(
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1245
|
+
const selectedSkills = isRetainedWorkspaceProfile(config) ? [] : selectSkillsForGoal(
|
|
1246
|
+
scopedChatopsEvidenceGoal(state.goal, config.taskProfile),
|
|
1247
|
+
{
|
|
1248
|
+
taskProfile: config.taskProfile,
|
|
1249
|
+
limit: 5,
|
|
1250
|
+
projectRoot: config.commandCwd || config.baseDir || process.cwd(),
|
|
1251
|
+
}
|
|
1252
|
+
);
|
|
1249
1253
|
const skillContext = formatSkillsForPrompt(selectedSkills);
|
|
1250
1254
|
const projectInstructions = state.meta?.projectInstructions;
|
|
1251
1255
|
const platform = platformInfo();
|
package/src/scs-controller.js
CHANGED
|
@@ -277,6 +277,15 @@ export function shouldActivateScs(mode = "off", context = {}) {
|
|
|
277
277
|
const profile = String(context.taskProfile || "").toLowerCase();
|
|
278
278
|
const goal = String(context.goal || "");
|
|
279
279
|
if (SCS_AUTO_PROFILES.has(profile)) return true;
|
|
280
|
+
const staticDataPaths = goal.match(/(?:^|[\s`'"(])[^\s`'"()]+\.(?:csv|json|toml|ya?ml)\b/gi) || [];
|
|
281
|
+
const simpleStaticDataWrite =
|
|
282
|
+
staticDataPaths.length === 1 &&
|
|
283
|
+
/\b(?:create|emit|generate|save|write)\b/i.test(goal) &&
|
|
284
|
+
!/\b(?:app|application|build|cli|code|codebase|compile|database|dataset|deploy|implement|library|migrate|package|publish|refactor|release|repository|script|server|source|test|upload)\b/i.test(
|
|
285
|
+
goal
|
|
286
|
+
) &&
|
|
287
|
+
Number(context.complexityScore || 0) < 3;
|
|
288
|
+
if (simpleStaticDataWrite) return false;
|
|
280
289
|
if (SCS_AUTO_HINTS.some((hint) => hint.test(goal))) return true;
|
|
281
290
|
return Number(context.complexityScore || 0) >= 5;
|
|
282
291
|
}
|
package/src/scs-evidence.js
CHANGED
|
@@ -538,7 +538,10 @@ function inferExactOutputPaths(goal = "") {
|
|
|
538
538
|
if (!isOutputListItem && !hasDirectOutputAction) continue;
|
|
539
539
|
const sourceLine = !isOutputListItem && hasDirectOutputAction ? line.slice(directOutputIndex) : line;
|
|
540
540
|
if (!isOutputListItem && negatedOutputLine.test(sourceLine)) continue;
|
|
541
|
-
|
|
541
|
+
const verifierIndex = line.search(/\b(?:validate|verify|check|compile|run|execute)\b/i);
|
|
542
|
+
if (!isOutputListItem && nonOutputToolLine.test(line) && verifierIndex >= 0 && verifierIndex < directOutputIndex) {
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
542
545
|
if (!isOutputListItem && /\boutput\s+(?:subfolders?|directories|folders?|paths?)\b/i.test(sourceLine)) continue;
|
|
543
546
|
const outputDirMatch = sourceLine.match(/(?:to|at|in|under|到|至|在)\s*([^\s,,、;;。]+\/)/i);
|
|
544
547
|
activeOutputDir = outputDirMatch?.[1] || "";
|
|
@@ -962,6 +965,12 @@ export function inferRequiredExecutableTerms(goal = "") {
|
|
|
962
965
|
if (executableRequirementIsNegated(source, index)) continue;
|
|
963
966
|
if (indexFallsInsideInlineCommand(source, index)) continue;
|
|
964
967
|
const window = source.slice(Math.max(0, index - 180), Math.min(source.length, index + match[0].length + 220));
|
|
968
|
+
const structuredDataLiteral =
|
|
969
|
+
/\b(?:csv|json|toml|ya?ml)\b/i.test(window) &&
|
|
970
|
+
!/\b(?:actual|canonical|executable|implementation|source\s+code|function|call|argument|parameter|repair|fix|replace)\b/i.test(
|
|
971
|
+
window
|
|
972
|
+
);
|
|
973
|
+
if (structuredDataLiteral) continue;
|
|
965
974
|
const implementationRequirement =
|
|
966
975
|
/\b(?:actual|canonical|executable|implementation|source|code|call|argument|keyword|parameter|repair|fix|correct|replace|add|set|pass|use|must|required)\b/iu.test(window) ||
|
|
967
976
|
/实际|實際|实现|實現|源码|源碼|代码|代碼|调用|調用|参数|參數|修复|修復|改正|替换|替換|添加|设置|設定|使用|必须|必須|実装|ソース|コード|呼び出し|引数|修正|置換|追加|設定|使用/.test(window);
|
|
@@ -1229,12 +1238,22 @@ function codeProfileRequiresCommand(goal = "") {
|
|
|
1229
1238
|
/\b(?:note|notes?|markdown|readme|documentation|text file)\b/.test(text) ||
|
|
1230
1239
|
/\bnotes?\/[^\s]+\.(?:md|txt)\b/.test(text) ||
|
|
1231
1240
|
/\.(?:md|txt)\b/.test(text);
|
|
1241
|
+
const structuredDataProse = text.replace(
|
|
1242
|
+
/(?:^|[\s`'"(])[^\s`'"()]+\.(?:csv|json|toml|ya?ml)\b/g,
|
|
1243
|
+
" "
|
|
1244
|
+
);
|
|
1245
|
+
const simpleStructuredDataWrite =
|
|
1246
|
+
/\.(?:csv|json|toml|ya?ml)\b/.test(text) &&
|
|
1247
|
+
/\b(?:create|emit|generate|save|write)\b/.test(text) &&
|
|
1248
|
+
!/\b(?:app|application|build|cli|code|codebase|compile|execute|function|implement|library|lint|package|refactor|run|script|server|source|test|typecheck)\b/.test(
|
|
1249
|
+
structuredDataProse
|
|
1250
|
+
);
|
|
1232
1251
|
const substantiveCodeWork =
|
|
1233
1252
|
/\b(?:fix|repair|bug|implement|feature|refactor|test|run|build|compile|lint|typecheck|verify|validate|package|library|cli|api server|app|application|script|codebase|src\/|source code)\b/.test(
|
|
1234
1253
|
text
|
|
1235
1254
|
) ||
|
|
1236
1255
|
/\.(?:js|jsx|ts|tsx|mjs|cjs|py|rs|go|java|kt|swift|rb|php|cs|cpp|c|h|hpp|sh)\b/.test(text);
|
|
1237
|
-
return substantiveCodeWork && !simpleDocumentWrite;
|
|
1256
|
+
return substantiveCodeWork && !simpleDocumentWrite && !simpleStructuredDataWrite;
|
|
1238
1257
|
}
|
|
1239
1258
|
|
|
1240
1259
|
function goalRequestsExplicitTestMutation(text = "") {
|
|
@@ -1439,7 +1458,17 @@ function inferRequirementCategories(goal = "", taskProfile = "", acceptanceCrite
|
|
|
1439
1458
|
) {
|
|
1440
1459
|
categories.add("visual");
|
|
1441
1460
|
}
|
|
1442
|
-
|
|
1461
|
+
const explicitPublishAction =
|
|
1462
|
+
textHas(
|
|
1463
|
+
text,
|
|
1464
|
+
/\b(?:publish|deploy|submit|upload to|generate video|external service|npm publish)\b/
|
|
1465
|
+
) ||
|
|
1466
|
+
textHas(
|
|
1467
|
+
text,
|
|
1468
|
+
/\b(?:release|ship)\s+(?:(?:the|this|that|a|an)\s+)?(?:package|version|build|app|application|software|library|plugin|extension|product)\b|\b(?:release|ship)\s+(?:to|on|via|through)\b|\bcut\s+(?:a\s+)?release\b/
|
|
1469
|
+
) ||
|
|
1470
|
+
/发布|部署|提交|生成视频|外部服务/.test(text);
|
|
1471
|
+
if (explicitPublishAction) {
|
|
1443
1472
|
categories.add("publish");
|
|
1444
1473
|
}
|
|
1445
1474
|
|
package/src/skill-library.js
CHANGED
|
@@ -482,6 +482,7 @@ const GENERIC_ROUTING_TERMS = new Set([
|
|
|
482
482
|
"analysis",
|
|
483
483
|
"app",
|
|
484
484
|
"application",
|
|
485
|
+
"artifact",
|
|
485
486
|
"code",
|
|
486
487
|
"commit",
|
|
487
488
|
"data",
|
|
@@ -498,6 +499,18 @@ const GENERIC_ROUTING_TERMS = new Set([
|
|
|
498
499
|
"work",
|
|
499
500
|
]);
|
|
500
501
|
|
|
502
|
+
function normalizedSkillRoutingText(goal = "") {
|
|
503
|
+
return String(goal || "")
|
|
504
|
+
.toLowerCase()
|
|
505
|
+
.replace(
|
|
506
|
+
/(?:^|[\s`'"(])(?:~|\.{1,2}|\/|[a-z0-9_-])[a-z0-9_./~-]*\.([a-z0-9]{1,12})\b/gi,
|
|
507
|
+
(_match, extension) => ` file.${String(extension || "").toLowerCase()} `
|
|
508
|
+
)
|
|
509
|
+
.replace(/\b[a-z_][a-z0-9_.-]*\s*=\s*[a-z0-9_.-]+\b/gi, " ")
|
|
510
|
+
.replace(/\s+/g, " ")
|
|
511
|
+
.trim();
|
|
512
|
+
}
|
|
513
|
+
|
|
501
514
|
function descriptionTerms(value = "") {
|
|
502
515
|
return [
|
|
503
516
|
...new Set(
|
|
@@ -564,7 +577,7 @@ function textHasTrigger(text, needle) {
|
|
|
564
577
|
}
|
|
565
578
|
|
|
566
579
|
export function selectSkillsForGoal(goal = "", { taskProfile = "auto", limit = 6, includeBody = true, projectRoot = process.cwd() } = {}) {
|
|
567
|
-
const goalText =
|
|
580
|
+
const goalText = normalizedSkillRoutingText(goal);
|
|
568
581
|
const text = goalText;
|
|
569
582
|
const skills = listSkills({ includeBody, projectRoot });
|
|
570
583
|
const ranked = skills
|