@lazyingart/agintiflow 0.20.321 → 0.20.322
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-truthful-completion.js +103 -0
- package/src/agent-runner.js +270 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.322",
|
|
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",
|
|
@@ -7,6 +7,7 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
import {
|
|
8
8
|
completionRequirementCoverageInstruction,
|
|
9
9
|
continuationExecutionContractDirective,
|
|
10
|
+
evaluateAuthoritativeStructuredCompletionCoverage,
|
|
10
11
|
removeSupersededCompletionRepairInstructions,
|
|
11
12
|
repositorySourcePrecedenceInstruction,
|
|
12
13
|
runAgent,
|
|
@@ -26,6 +27,51 @@ assert.match(completionCoverageInstruction, /authoritative structured routine/i)
|
|
|
26
27
|
assert.match(completionCoverageInstruction, /every relevant section/i);
|
|
27
28
|
assert.match(completionCoverageInstruction, /instead of summarizing only failures or only successes/i);
|
|
28
29
|
|
|
30
|
+
const structuredHealthOutput = JSON.stringify({
|
|
31
|
+
ok: true,
|
|
32
|
+
degraded: true,
|
|
33
|
+
issues: ["wechat_login_required", "android_poll_stalled"],
|
|
34
|
+
queues: {
|
|
35
|
+
wechat: { pending: 0, active: 0, stale_count: 0, recent_failure_count: 0 },
|
|
36
|
+
wecom: { pending: 0, active: 0, stale_count: 0, recent_failure_count: 0 },
|
|
37
|
+
},
|
|
38
|
+
schedules: {
|
|
39
|
+
career_daily: { status: "waiting", running: true },
|
|
40
|
+
memo_daily: { status: "waiting", running: true },
|
|
41
|
+
echomind_daily_pdf: { status: "current", running: true },
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
const structuredHealthRecord = [{ output: structuredHealthOutput, authoritative: true }];
|
|
45
|
+
const badStructuredCoverage = evaluateAuthoritativeStructuredCompletionCoverage({
|
|
46
|
+
goal: "Report queue health, schedule state, and authentication blockers concisely.",
|
|
47
|
+
candidateResult: "The system is degraded because WeChat login is required. Schedule state is not visible in the retained output.",
|
|
48
|
+
commandOutputs: structuredHealthRecord,
|
|
49
|
+
});
|
|
50
|
+
assert.equal(badStructuredCoverage.checked, true);
|
|
51
|
+
assert.equal(badStructuredCoverage.ok, false);
|
|
52
|
+
assert(badStructuredCoverage.missingSections.includes("queues"));
|
|
53
|
+
assert(badStructuredCoverage.missingSections.includes("schedules"));
|
|
54
|
+
assert(badStructuredCoverage.contradictedSections.includes("schedules"));
|
|
55
|
+
assert.match(badStructuredCoverage.expectedSummary, /Queues: .*wechat pending 0 active 0.*wecom pending 0 active 0/i);
|
|
56
|
+
assert.match(badStructuredCoverage.expectedSummary, /Other schedules: .*career_daily.*memo_daily.*echomind_daily_pdf/i);
|
|
57
|
+
|
|
58
|
+
const goodStructuredCoverage = evaluateAuthoritativeStructuredCompletionCoverage({
|
|
59
|
+
goal: "Report queue health, schedule state, and authentication blockers concisely.",
|
|
60
|
+
candidateResult: "Both queues are clear: WeChat and WeCom have pending 0, active 0, stale 0, and failures 0. Schedules are running: career_daily and memo_daily are waiting, while echomind_daily_pdf is current. Authentication blockers are wechat_login_required and android_poll_stalled.",
|
|
61
|
+
commandOutputs: structuredHealthRecord,
|
|
62
|
+
});
|
|
63
|
+
assert.equal(goodStructuredCoverage.checked, true);
|
|
64
|
+
assert.equal(goodStructuredCoverage.ok, true);
|
|
65
|
+
assert.deepEqual(goodStructuredCoverage.missingSections, []);
|
|
66
|
+
|
|
67
|
+
const unstructuredCoverage = evaluateAuthoritativeStructuredCompletionCoverage({
|
|
68
|
+
goal: "Explain the architecture.",
|
|
69
|
+
candidateResult: "The architecture is complete.",
|
|
70
|
+
commandOutputs: [{ output: "ordinary prose", authoritative: true }],
|
|
71
|
+
});
|
|
72
|
+
assert.equal(unstructuredCoverage.checked, false);
|
|
73
|
+
assert.equal(unstructuredCoverage.ok, true);
|
|
74
|
+
|
|
29
75
|
const sourcePrecedenceInstruction = repositorySourcePrecedenceInstruction();
|
|
30
76
|
assert.match(sourcePrecedenceInstruction, /current direct user request/i);
|
|
31
77
|
assert.match(sourcePrecedenceInstruction, /closest project instructions/i);
|
|
@@ -968,6 +1014,63 @@ try {
|
|
|
968
1014
|
"finish-only reasoning repair still spent a separate empty-response repair turn"
|
|
969
1015
|
);
|
|
970
1016
|
|
|
1017
|
+
const structuredCoverageFallback = await runCase({
|
|
1018
|
+
id: "authoritative-structured-completion-coverage",
|
|
1019
|
+
goal: [
|
|
1020
|
+
"User request:",
|
|
1021
|
+
"Report queue health, schedule state, and authentication blockers concisely. Read-only inspection; send nothing.",
|
|
1022
|
+
"",
|
|
1023
|
+
"Matched established routines",
|
|
1024
|
+
`- \`wechat-chatops\` ready=true; commands=[${JSON.stringify(compactHealthCommand)}, "python agentic_tools/wechat_gui_agent/scripts/wechat_android_ingress.py --status"]; outputs=["messages", "files", "task records"]; guidance=For a read-only phone, message-intake, queue, or schedule question, run the canonical compact health command first; it already includes both Android lanes. Treat that current snapshot as authoritative and stop once it answers the request. Do not inspect raw chat text or private message ledgers or artifact directories, and do not send or mutate anything, unless the current request explicitly needs it.`,
|
|
1025
|
+
].join("\n"),
|
|
1026
|
+
taskProfile: "chatops",
|
|
1027
|
+
allowShellTool: true,
|
|
1028
|
+
allowDestructive: true,
|
|
1029
|
+
setup: async (workspace) => {
|
|
1030
|
+
await fs.mkdir(path.join(workspace, "src", "agenticapp"), { recursive: true });
|
|
1031
|
+
await fs.writeFile(path.join(workspace, "src", "agenticapp", "__init__.py"), "", "utf8");
|
|
1032
|
+
await fs.writeFile(
|
|
1033
|
+
path.join(workspace, "src", "agenticapp", "__main__.py"),
|
|
1034
|
+
`print(${JSON.stringify(structuredHealthOutput)})\n`,
|
|
1035
|
+
"utf8"
|
|
1036
|
+
);
|
|
1037
|
+
},
|
|
1038
|
+
responses: [
|
|
1039
|
+
assistant("", [toolCall("structured-health-command", "run_command", { command: compactHealthCommand })]),
|
|
1040
|
+
assistant("", [toolCall("structured-health-bad-finish-1", "finish", {
|
|
1041
|
+
result: "The system is degraded because WeChat login is required. Schedule state is not visible in the retained output.",
|
|
1042
|
+
})]),
|
|
1043
|
+
assistant("", [toolCall("structured-health-bad-finish-2", "finish", {
|
|
1044
|
+
result: "WeChat authentication remains blocked. The schedule section was not returned.",
|
|
1045
|
+
})]),
|
|
1046
|
+
],
|
|
1047
|
+
});
|
|
1048
|
+
assert.equal(structuredCoverageFallback.calls.length, 3);
|
|
1049
|
+
assert.match(structuredCoverageFallback.result.result, /Queues: .*wechat pending 0 active 0.*wecom pending 0 active 0/i);
|
|
1050
|
+
assert.match(structuredCoverageFallback.result.result, /Other schedules: .*career_daily.*memo_daily.*echomind_daily_pdf/i);
|
|
1051
|
+
assert.match(structuredCoverageFallback.result.result, /issues=wechat_login_required,android_poll_stalled/i);
|
|
1052
|
+
assert.equal(
|
|
1053
|
+
structuredCoverageFallback.events.filter(
|
|
1054
|
+
(event) => event.type === "tool.started" && event.data?.toolName === "run_command"
|
|
1055
|
+
).length,
|
|
1056
|
+
1,
|
|
1057
|
+
"structured summary repair reran the authoritative command"
|
|
1058
|
+
);
|
|
1059
|
+
assert.equal(
|
|
1060
|
+
structuredCoverageFallback.events.filter(
|
|
1061
|
+
(event) => event.type === "completion.structured_output_repair_requested"
|
|
1062
|
+
).length,
|
|
1063
|
+
1,
|
|
1064
|
+
"structured summary defect did not request exactly one finish-only repair"
|
|
1065
|
+
);
|
|
1066
|
+
assert.equal(
|
|
1067
|
+
structuredCoverageFallback.events.filter(
|
|
1068
|
+
(event) => event.type === "completion.structured_output_fallback"
|
|
1069
|
+
).length,
|
|
1070
|
+
1,
|
|
1071
|
+
"repeated bad structured summary did not use the deterministic verified fallback"
|
|
1072
|
+
);
|
|
1073
|
+
|
|
971
1074
|
const wordCompletionWithoutArtifact = await runCase({
|
|
972
1075
|
id: "word-completion-without-artifact",
|
|
973
1076
|
goal: "Create an editable, phone-friendly project handoff from this folder.",
|
package/src/agent-runner.js
CHANGED
|
@@ -4157,6 +4157,7 @@ export function resetGoalScopedRuntimeState(state = {}) {
|
|
|
4157
4157
|
const keys = [
|
|
4158
4158
|
"artifactProgress",
|
|
4159
4159
|
"completionEvidenceRepair",
|
|
4160
|
+
"structuredCompletionRepair",
|
|
4160
4161
|
"dataProjectWorkflow",
|
|
4161
4162
|
"durableEvidenceCategories",
|
|
4162
4163
|
"durableGitActions",
|
|
@@ -4243,6 +4244,7 @@ export function resetSameTaskExecutionContract(state = {}, revision = 0) {
|
|
|
4243
4244
|
const keys = [
|
|
4244
4245
|
"artifactProgress",
|
|
4245
4246
|
"completionEvidenceRepair",
|
|
4247
|
+
"structuredCompletionRepair",
|
|
4246
4248
|
"failedTestRecoveryPacket",
|
|
4247
4249
|
"scs",
|
|
4248
4250
|
"stepBudget",
|
|
@@ -22538,6 +22540,93 @@ async function completionEvidenceDecision({ config, state, store, observers, ste
|
|
|
22538
22540
|
},
|
|
22539
22541
|
};
|
|
22540
22542
|
}
|
|
22543
|
+
const structuredCoverage = String(candidateResult || "").trim()
|
|
22544
|
+
? evaluateAuthoritativeStructuredCompletionCoverage({
|
|
22545
|
+
goal: completionContractGoal(config, state),
|
|
22546
|
+
candidateResult,
|
|
22547
|
+
commandOutputs: assessment.commandOutputs,
|
|
22548
|
+
})
|
|
22549
|
+
: {
|
|
22550
|
+
checked: false,
|
|
22551
|
+
ok: true,
|
|
22552
|
+
requestedSections: [],
|
|
22553
|
+
missingSections: [],
|
|
22554
|
+
contradictedSections: [],
|
|
22555
|
+
expectedSummary: "",
|
|
22556
|
+
key: "",
|
|
22557
|
+
};
|
|
22558
|
+
if (structuredCoverage.checked) {
|
|
22559
|
+
const coverageDetail = {
|
|
22560
|
+
step,
|
|
22561
|
+
mode,
|
|
22562
|
+
ok: structuredCoverage.ok,
|
|
22563
|
+
requestedSections: structuredCoverage.requestedSections,
|
|
22564
|
+
missingSections: structuredCoverage.missingSections,
|
|
22565
|
+
contradictedSections: structuredCoverage.contradictedSections,
|
|
22566
|
+
};
|
|
22567
|
+
await store.appendEvent("completion.structured_output_assessed", coverageDetail);
|
|
22568
|
+
observers.event("completion.structured_output_assessed", coverageDetail);
|
|
22569
|
+
}
|
|
22570
|
+
if (assessment.ok && !claimsIncompleteWork && structuredCoverage.checked && !structuredCoverage.ok) {
|
|
22571
|
+
state.meta = state.meta || {};
|
|
22572
|
+
const prior = state.meta.structuredCompletionRepair || {};
|
|
22573
|
+
const attempts = prior.key === structuredCoverage.key
|
|
22574
|
+
? Math.max(0, Number(prior.attempts || 0))
|
|
22575
|
+
: 0;
|
|
22576
|
+
const detail = {
|
|
22577
|
+
step,
|
|
22578
|
+
mode,
|
|
22579
|
+
key: structuredCoverage.key,
|
|
22580
|
+
repairAttempt: attempts + 1,
|
|
22581
|
+
requestedSections: structuredCoverage.requestedSections,
|
|
22582
|
+
missingSections: structuredCoverage.missingSections,
|
|
22583
|
+
contradictedSections: structuredCoverage.contradictedSections,
|
|
22584
|
+
expectedSummary: structuredCoverage.expectedSummary,
|
|
22585
|
+
};
|
|
22586
|
+
await store.appendEvent("completion.structured_output_rejected", detail);
|
|
22587
|
+
observers.event("completion.structured_output_rejected", detail);
|
|
22588
|
+
if (attempts < 1) {
|
|
22589
|
+
state.meta.structuredCompletionRepair = {
|
|
22590
|
+
key: structuredCoverage.key,
|
|
22591
|
+
attempts: attempts + 1,
|
|
22592
|
+
step,
|
|
22593
|
+
goalRevision: Math.max(0, Number(state.meta?.goalContract?.revision || 0)),
|
|
22594
|
+
at: new Date().toISOString(),
|
|
22595
|
+
};
|
|
22596
|
+
const affectedSections = [
|
|
22597
|
+
...structuredCoverage.missingSections,
|
|
22598
|
+
...structuredCoverage.contradictedSections,
|
|
22599
|
+
];
|
|
22600
|
+
const instruction = [
|
|
22601
|
+
"Your proposed final answer omitted or contradicted requested sections that are present in the retained authoritative structured result.",
|
|
22602
|
+
affectedSections.length
|
|
22603
|
+
? `Correct these sections: ${[...new Set(affectedSections)].join(", ")}.`
|
|
22604
|
+
: "Correct the structured status summary.",
|
|
22605
|
+
"Do not rerun the command, call another tool, or claim that a visible section is unavailable.",
|
|
22606
|
+
structuredCoverage.expectedSummary
|
|
22607
|
+
? `Authoritative evidence summary: ${structuredCoverage.expectedSummary}`
|
|
22608
|
+
: "Use the retained authoritative output already in this session.",
|
|
22609
|
+
"Return one concise natural answer that covers every requested section, then finish.",
|
|
22610
|
+
].filter(Boolean).join(" ");
|
|
22611
|
+
state.messages.push({ role: "user", content: instruction });
|
|
22612
|
+
await store.appendEvent("completion.structured_output_repair_requested", {
|
|
22613
|
+
...detail,
|
|
22614
|
+
instruction,
|
|
22615
|
+
});
|
|
22616
|
+
observers.event("completion.structured_output_repair_requested", detail);
|
|
22617
|
+
return { action: "retry", assessment, detail };
|
|
22618
|
+
}
|
|
22619
|
+
const result = verifiedCompletionFallback(assessment, state);
|
|
22620
|
+
await store.appendEvent("completion.structured_output_fallback", {
|
|
22621
|
+
...detail,
|
|
22622
|
+
result,
|
|
22623
|
+
});
|
|
22624
|
+
observers.event("completion.structured_output_fallback", detail);
|
|
22625
|
+
return { action: "accept", assessment, detail, resultOverride: result };
|
|
22626
|
+
}
|
|
22627
|
+
if (structuredCoverage.ok && state.meta?.structuredCompletionRepair) {
|
|
22628
|
+
delete state.meta.structuredCompletionRepair;
|
|
22629
|
+
}
|
|
22541
22630
|
const hasRealBlocker = completionExternalBlockerCanClose({
|
|
22542
22631
|
candidateResult,
|
|
22543
22632
|
evidenceLedger: assessment.ledger,
|
|
@@ -22882,6 +22971,180 @@ function summarizeJsonCommandOutput(output = "") {
|
|
|
22882
22971
|
return pairs.length ? `Observed JSON status: ${pairs.join(", ")}.` : "";
|
|
22883
22972
|
}
|
|
22884
22973
|
|
|
22974
|
+
const AUTHORITATIVE_STRUCTURED_SECTION_ALIASES = Object.freeze({
|
|
22975
|
+
queues: ["queue", "queues", "backlog", "队列", "佇列"],
|
|
22976
|
+
schedules: ["schedule", "schedules", "scheduler", "schedulers", "日程", "定时", "定時", "排程"],
|
|
22977
|
+
issues: ["issue", "issues", "problem", "problems", "error", "errors", "blocker", "blockers", "auth", "authentication", "login", "问题", "問題", "错误", "錯誤", "阻塞", "登录", "登入", "授权", "授權"],
|
|
22978
|
+
ingress: ["ingress", "receiver", "receivers", "inbound", "intake", "message intake", "入口", "接收", "收件"],
|
|
22979
|
+
});
|
|
22980
|
+
|
|
22981
|
+
function structuredSectionAliases(key = "") {
|
|
22982
|
+
const normalized = String(key || "").trim().toLowerCase();
|
|
22983
|
+
const aliases = new Set(AUTHORITATIVE_STRUCTURED_SECTION_ALIASES[normalized] || []);
|
|
22984
|
+
if (normalized) {
|
|
22985
|
+
aliases.add(normalized);
|
|
22986
|
+
aliases.add(normalized.replace(/_/g, " "));
|
|
22987
|
+
if (normalized.endsWith("s") && normalized.length > 3) aliases.add(normalized.slice(0, -1));
|
|
22988
|
+
}
|
|
22989
|
+
return [...aliases].filter(Boolean);
|
|
22990
|
+
}
|
|
22991
|
+
|
|
22992
|
+
function completionTextHasAny(value = "", terms = []) {
|
|
22993
|
+
const normalized = String(value || "").toLowerCase();
|
|
22994
|
+
return terms.some((rawTerm) => {
|
|
22995
|
+
const term = String(rawTerm || "").trim().toLowerCase();
|
|
22996
|
+
if (!term) return false;
|
|
22997
|
+
if (!/^[a-z0-9_\- ]+$/u.test(term)) return normalized.includes(term);
|
|
22998
|
+
const escaped = term
|
|
22999
|
+
.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
23000
|
+
.replace(/[ _-]+/g, "[ _-]+");
|
|
23001
|
+
return new RegExp(`(?:^|[^a-z0-9])${escaped}(?:$|[^a-z0-9])`, "iu").test(normalized);
|
|
23002
|
+
});
|
|
23003
|
+
}
|
|
23004
|
+
|
|
23005
|
+
function structuredSectionHasFalseAbsence(candidateResult = "", aliases = []) {
|
|
23006
|
+
const sentences = String(candidateResult || "")
|
|
23007
|
+
.split(/(?<=[.!?。!?;;\n])/u)
|
|
23008
|
+
.map((item) => item.trim())
|
|
23009
|
+
.filter(Boolean);
|
|
23010
|
+
const absence = /(?:\b(?:not|isn['’]?t|wasn['’]?t|no)\b.{0,70}\b(?:visible|available|present|returned|shown|included|provided|reported|exposed|found)\b|\b(?:missing|unavailable|unknown|absent)\b|未(?:显示|返回|提供|包含|找到|看到)|不可见|不存在|没有(?:显示|返回|提供|包含))/iu;
|
|
23011
|
+
return sentences.some((sentence) => completionTextHasAny(sentence, aliases) && absence.test(sentence));
|
|
23012
|
+
}
|
|
23013
|
+
|
|
23014
|
+
function structuredChildTerms(value) {
|
|
23015
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return [];
|
|
23016
|
+
return Object.keys(value)
|
|
23017
|
+
.flatMap((key) => [key, ...String(key).split(/[_\-\s]+/u)])
|
|
23018
|
+
.map((item) => String(item || "").trim().toLowerCase())
|
|
23019
|
+
.filter((item) => item.length >= 3 && !["daily", "status", "state", "count"].includes(item));
|
|
23020
|
+
}
|
|
23021
|
+
|
|
23022
|
+
function issueValueTerms(value) {
|
|
23023
|
+
if (!Array.isArray(value)) return [];
|
|
23024
|
+
return value
|
|
23025
|
+
.flatMap((item) => [String(item || ""), ...String(item || "").split(/[_\-\s]+/u)])
|
|
23026
|
+
.map((item) => item.trim().toLowerCase())
|
|
23027
|
+
.filter((item) => item.length >= 4 && !["required", "issue", "error"].includes(item));
|
|
23028
|
+
}
|
|
23029
|
+
|
|
23030
|
+
function authoritativeStructuredRequestText(goal = "") {
|
|
23031
|
+
const text = String(goal || "");
|
|
23032
|
+
const evidenceLine = text.match(/^AGINTI_EVIDENCE_SCOPE_JSON:\s*(\{[^\n]+\})/mu);
|
|
23033
|
+
if (evidenceLine) {
|
|
23034
|
+
try {
|
|
23035
|
+
const parsed = JSON.parse(evidenceLine[1]);
|
|
23036
|
+
if (String(parsed?.request || "").trim()) return String(parsed.request).trim();
|
|
23037
|
+
} catch {
|
|
23038
|
+
// Fall through to the visible user-request packet or the direct goal.
|
|
23039
|
+
}
|
|
23040
|
+
}
|
|
23041
|
+
const marker = text.match(/(?:^|\n)User request:\s*\n/iu);
|
|
23042
|
+
if (!marker || marker.index === undefined) return text;
|
|
23043
|
+
const start = marker.index + marker[0].length;
|
|
23044
|
+
const tail = text.slice(start);
|
|
23045
|
+
const boundary = tail.search(/\n(?:Matched established routines|Operating contract|Execution contract|Agent context|Task packet)\b/iu);
|
|
23046
|
+
return (boundary >= 0 ? tail.slice(0, boundary) : tail).trim();
|
|
23047
|
+
}
|
|
23048
|
+
|
|
23049
|
+
function requestedAuthoritativeStructuredSections(goal = "", data = {}) {
|
|
23050
|
+
const request = authoritativeStructuredRequestText(goal);
|
|
23051
|
+
const requested = [];
|
|
23052
|
+
for (const key of Object.keys(data || {})) {
|
|
23053
|
+
const normalized = String(key || "").trim().toLowerCase();
|
|
23054
|
+
const aliasKey = /ingress/i.test(normalized) ? "ingress" : normalized;
|
|
23055
|
+
const aliases = structuredSectionAliases(aliasKey);
|
|
23056
|
+
if (completionTextHasAny(request, aliases)) requested.push(normalized);
|
|
23057
|
+
}
|
|
23058
|
+
if (
|
|
23059
|
+
Object.prototype.hasOwnProperty.call(data || {}, "issues") &&
|
|
23060
|
+
completionTextHasAny(request, AUTHORITATIVE_STRUCTURED_SECTION_ALIASES.issues)
|
|
23061
|
+
) {
|
|
23062
|
+
requested.push("issues");
|
|
23063
|
+
}
|
|
23064
|
+
return [...new Set(requested)];
|
|
23065
|
+
}
|
|
23066
|
+
|
|
23067
|
+
function authoritativeStructuredSectionCovered(key = "", value, candidateResult = "") {
|
|
23068
|
+
const normalized = String(key || "").toLowerCase();
|
|
23069
|
+
const aliasKey = /ingress/i.test(normalized) ? "ingress" : normalized;
|
|
23070
|
+
const aliases = structuredSectionAliases(aliasKey);
|
|
23071
|
+
if (structuredSectionHasFalseAbsence(candidateResult, aliases)) {
|
|
23072
|
+
return { covered: false, contradicted: true };
|
|
23073
|
+
}
|
|
23074
|
+
const sectionMentioned = completionTextHasAny(candidateResult, aliases);
|
|
23075
|
+
const childMentioned = completionTextHasAny(candidateResult, structuredChildTerms(value));
|
|
23076
|
+
if (normalized === "queues") {
|
|
23077
|
+
const queueState = /\b(?:pending|active|stale|failures?|failed|running|clear|healthy|idle|empty|backlog)\b|待处理|活动|运行|陈旧|失效|失败|健康|空闲|清空/iu.test(candidateResult);
|
|
23078
|
+
return { covered: (sectionMentioned || childMentioned) && queueState, contradicted: false };
|
|
23079
|
+
}
|
|
23080
|
+
if (normalized === "schedules") {
|
|
23081
|
+
const scheduleState = /\b(?:waiting|pending|running|delivered|current|due|retrying|retry|healthy|idle|enabled|disabled|paused|complete|completed)\b|等待|待处理|运行|已送达|已发送|重试|健康|启用|停用|暂停|完成/iu.test(candidateResult);
|
|
23082
|
+
return { covered: (sectionMentioned || childMentioned) && scheduleState && childMentioned, contradicted: false };
|
|
23083
|
+
}
|
|
23084
|
+
if (normalized === "issues") {
|
|
23085
|
+
const issueTerms = issueValueTerms(value);
|
|
23086
|
+
const noIssues = Array.isArray(value) && value.length === 0 && /\b(?:no|zero)\s+(?:issues?|errors?|blockers?)\b|没有(?:问题|错误|阻塞)/iu.test(candidateResult);
|
|
23087
|
+
return {
|
|
23088
|
+
covered: noIssues || ((sectionMentioned || completionTextHasAny(candidateResult, issueTerms)) && completionTextHasAny(candidateResult, issueTerms)),
|
|
23089
|
+
contradicted: false,
|
|
23090
|
+
};
|
|
23091
|
+
}
|
|
23092
|
+
if (/ingress/i.test(normalized)) {
|
|
23093
|
+
const ingressState = /\b(?:reach|reaches|reachable|received|receives|working|healthy|blocked|stale|unknown|ok)\b|可达|收到|接收|正常|健康|阻塞|未知/iu.test(candidateResult);
|
|
23094
|
+
return { covered: (sectionMentioned || childMentioned) && ingressState, contradicted: false };
|
|
23095
|
+
}
|
|
23096
|
+
if (value && typeof value === "object") {
|
|
23097
|
+
return { covered: sectionMentioned && childMentioned, contradicted: false };
|
|
23098
|
+
}
|
|
23099
|
+
const scalar = String(value ?? "").trim().toLowerCase();
|
|
23100
|
+
const scalarTerms = scalar
|
|
23101
|
+
.split(/[_\-\s]+/u)
|
|
23102
|
+
.map((item) => item.trim())
|
|
23103
|
+
.filter((item) => item.length >= 2);
|
|
23104
|
+
const scalarCovered = !scalar ||
|
|
23105
|
+
completionTextHasAny(candidateResult, [scalar]) ||
|
|
23106
|
+
(scalarTerms.length > 1 && scalarTerms.every((term) => completionTextHasAny(candidateResult, [term])));
|
|
23107
|
+
return {
|
|
23108
|
+
covered: sectionMentioned && scalarCovered,
|
|
23109
|
+
contradicted: false,
|
|
23110
|
+
};
|
|
23111
|
+
}
|
|
23112
|
+
|
|
23113
|
+
export function evaluateAuthoritativeStructuredCompletionCoverage({
|
|
23114
|
+
goal = "",
|
|
23115
|
+
candidateResult = "",
|
|
23116
|
+
commandOutputs = [],
|
|
23117
|
+
} = {}) {
|
|
23118
|
+
const authoritative = [...(Array.isArray(commandOutputs) ? commandOutputs : [])]
|
|
23119
|
+
.reverse()
|
|
23120
|
+
.find((item) => item?.authoritative === true && parseCommandJsonOutput(item.output));
|
|
23121
|
+
if (!authoritative) {
|
|
23122
|
+
return { checked: false, ok: true, requestedSections: [], missingSections: [], contradictedSections: [], expectedSummary: "", key: "" };
|
|
23123
|
+
}
|
|
23124
|
+
const data = parseCommandJsonOutput(authoritative.output);
|
|
23125
|
+
const requestedSections = requestedAuthoritativeStructuredSections(goal, data);
|
|
23126
|
+
if (!requestedSections.length) {
|
|
23127
|
+
return { checked: false, ok: true, requestedSections: [], missingSections: [], contradictedSections: [], expectedSummary: summarizeJsonCommandOutput(authoritative.output), key: "" };
|
|
23128
|
+
}
|
|
23129
|
+
const missingSections = [];
|
|
23130
|
+
const contradictedSections = [];
|
|
23131
|
+
for (const key of requestedSections) {
|
|
23132
|
+
const coverage = authoritativeStructuredSectionCovered(key, data[key], candidateResult);
|
|
23133
|
+
if (!coverage.covered) missingSections.push(key);
|
|
23134
|
+
if (coverage.contradicted) contradictedSections.push(key);
|
|
23135
|
+
}
|
|
23136
|
+
const expectedSummary = summarizeJsonCommandOutput(authoritative.output);
|
|
23137
|
+
return {
|
|
23138
|
+
checked: true,
|
|
23139
|
+
ok: missingSections.length === 0 && contradictedSections.length === 0,
|
|
23140
|
+
requestedSections,
|
|
23141
|
+
missingSections,
|
|
23142
|
+
contradictedSections,
|
|
23143
|
+
expectedSummary,
|
|
23144
|
+
key: hashForLog(`${String(goal || "")}\0${String(authoritative.output || "")}\0${requestedSections.join(",")}`),
|
|
23145
|
+
};
|
|
23146
|
+
}
|
|
23147
|
+
|
|
22885
23148
|
function completionCommandOutputRecords(scoped = {}) {
|
|
22886
23149
|
const events = Array.isArray(scoped.events) ? scoped.events : [];
|
|
22887
23150
|
const state = scoped.state && typeof scoped.state === "object" ? scoped.state : {};
|
|
@@ -27689,7 +27952,9 @@ async function runAgentOnceUnlocked(config) {
|
|
|
27689
27952
|
toolResult: completionDecision.artifactBlock,
|
|
27690
27953
|
});
|
|
27691
27954
|
}
|
|
27692
|
-
let fallback = redactSensitiveText(
|
|
27955
|
+
let fallback = redactSensitiveText(
|
|
27956
|
+
completionDecision.resultOverride || assistantMessage.content?.trim() || ""
|
|
27957
|
+
);
|
|
27693
27958
|
if (!fallback) {
|
|
27694
27959
|
const emptyDecision = await repairEmptyCompletion({
|
|
27695
27960
|
config,
|
|
@@ -27936,7 +28201,10 @@ async function runAgentOnceUnlocked(config) {
|
|
|
27936
28201
|
toolResult: completionDecision.artifactBlock,
|
|
27937
28202
|
});
|
|
27938
28203
|
}
|
|
27939
|
-
const completionResult = canonicalizeVerifiedArtifactCompletion(
|
|
28204
|
+
const completionResult = canonicalizeVerifiedArtifactCompletion(
|
|
28205
|
+
state,
|
|
28206
|
+
completionDecision.resultOverride || toolResult.result || ""
|
|
28207
|
+
);
|
|
27940
28208
|
if (config.scsActive) {
|
|
27941
28209
|
const decision = await reviewScsFinish(client, config, state, completionResult, {
|
|
27942
28210
|
events: await store.loadEvents(),
|