@lazyingart/agintiflow 0.20.321 → 0.20.323

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.321",
3
+ "version": "0.20.323",
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",
@@ -11089,6 +11089,20 @@ try {
11089
11089
  })?.category === "repeated-no-progress-call",
11090
11090
  "a third identical failed shell command was not blocked"
11091
11091
  );
11092
+ const repeatedChangingFailureState = structuredClone(repeatedFailureState);
11093
+ repeatedChangingFailureState.meta.toolLoop.recent[0].outcomeFingerprint =
11094
+ "failure-with-first-dynamic-log";
11095
+ repeatedChangingFailureState.meta.toolLoop.recent[1].outcomeFingerprint =
11096
+ "failure-with-second-dynamic-log";
11097
+ assert(
11098
+ repeatedNoProgressToolBlock(
11099
+ repeatedChangingFailureState,
11100
+ "run_command",
11101
+ repeatedProbeArgs,
11102
+ { commandCwd: workspace }
11103
+ )?.category === "repeated-no-progress-call",
11104
+ "dynamic failure output allowed an unchanged failing command to loop"
11105
+ );
11092
11106
  const newlyAuthoritativeVerificationState = structuredClone(repeatedFailureState);
11093
11107
  newlyAuthoritativeVerificationState.meta.projectVerification = {
11094
11108
  mutationRevision: 6,
@@ -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.",
@@ -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",
@@ -11092,6 +11094,26 @@ export function repeatedNoProgressToolBlock(state, toolName, args = {}, config =
11092
11094
  Boolean(entry?.outcomeFingerprint)
11093
11095
  );
11094
11096
  if (matches.length < 2) return null;
11097
+ const repeatedFailures = matches.slice(-2).every((entry) => entry?.ok === false);
11098
+ if (repeatedFailures) {
11099
+ return {
11100
+ reason:
11101
+ "The same command already failed twice without an intervening file, artifact, browser, or task-state change.",
11102
+ category: "repeated-no-progress-call",
11103
+ permissionAdvice: {
11104
+ category: "repeated-no-progress-call",
11105
+ autoRecover: true,
11106
+ summary: "This is a failed-command convergence guard, not a permission blocker.",
11107
+ instruction:
11108
+ "Do not rerun the command or a cosmetically equivalent form. Use the retained failure evidence, change the command or repair the implicated source, then run the smallest relevant validation.",
11109
+ options: [
11110
+ "Choose the correct compiler, interpreter, working directory, or command flags from the observed failure.",
11111
+ "Apply one bounded source repair that addresses the failure, then rerun validation.",
11112
+ "Finish with a concrete external blocker only when no enabled tool can make progress.",
11113
+ ],
11114
+ },
11115
+ };
11116
+ }
11095
11117
  const recentFingerprints = matches.slice(-2).map((entry) => entry.outcomeFingerprint);
11096
11118
  if (new Set(recentFingerprints).size !== 1) return null;
11097
11119
  return {
@@ -22538,6 +22560,93 @@ async function completionEvidenceDecision({ config, state, store, observers, ste
22538
22560
  },
22539
22561
  };
22540
22562
  }
22563
+ const structuredCoverage = String(candidateResult || "").trim()
22564
+ ? evaluateAuthoritativeStructuredCompletionCoverage({
22565
+ goal: completionContractGoal(config, state),
22566
+ candidateResult,
22567
+ commandOutputs: assessment.commandOutputs,
22568
+ })
22569
+ : {
22570
+ checked: false,
22571
+ ok: true,
22572
+ requestedSections: [],
22573
+ missingSections: [],
22574
+ contradictedSections: [],
22575
+ expectedSummary: "",
22576
+ key: "",
22577
+ };
22578
+ if (structuredCoverage.checked) {
22579
+ const coverageDetail = {
22580
+ step,
22581
+ mode,
22582
+ ok: structuredCoverage.ok,
22583
+ requestedSections: structuredCoverage.requestedSections,
22584
+ missingSections: structuredCoverage.missingSections,
22585
+ contradictedSections: structuredCoverage.contradictedSections,
22586
+ };
22587
+ await store.appendEvent("completion.structured_output_assessed", coverageDetail);
22588
+ observers.event("completion.structured_output_assessed", coverageDetail);
22589
+ }
22590
+ if (assessment.ok && !claimsIncompleteWork && structuredCoverage.checked && !structuredCoverage.ok) {
22591
+ state.meta = state.meta || {};
22592
+ const prior = state.meta.structuredCompletionRepair || {};
22593
+ const attempts = prior.key === structuredCoverage.key
22594
+ ? Math.max(0, Number(prior.attempts || 0))
22595
+ : 0;
22596
+ const detail = {
22597
+ step,
22598
+ mode,
22599
+ key: structuredCoverage.key,
22600
+ repairAttempt: attempts + 1,
22601
+ requestedSections: structuredCoverage.requestedSections,
22602
+ missingSections: structuredCoverage.missingSections,
22603
+ contradictedSections: structuredCoverage.contradictedSections,
22604
+ expectedSummary: structuredCoverage.expectedSummary,
22605
+ };
22606
+ await store.appendEvent("completion.structured_output_rejected", detail);
22607
+ observers.event("completion.structured_output_rejected", detail);
22608
+ if (attempts < 1) {
22609
+ state.meta.structuredCompletionRepair = {
22610
+ key: structuredCoverage.key,
22611
+ attempts: attempts + 1,
22612
+ step,
22613
+ goalRevision: Math.max(0, Number(state.meta?.goalContract?.revision || 0)),
22614
+ at: new Date().toISOString(),
22615
+ };
22616
+ const affectedSections = [
22617
+ ...structuredCoverage.missingSections,
22618
+ ...structuredCoverage.contradictedSections,
22619
+ ];
22620
+ const instruction = [
22621
+ "Your proposed final answer omitted or contradicted requested sections that are present in the retained authoritative structured result.",
22622
+ affectedSections.length
22623
+ ? `Correct these sections: ${[...new Set(affectedSections)].join(", ")}.`
22624
+ : "Correct the structured status summary.",
22625
+ "Do not rerun the command, call another tool, or claim that a visible section is unavailable.",
22626
+ structuredCoverage.expectedSummary
22627
+ ? `Authoritative evidence summary: ${structuredCoverage.expectedSummary}`
22628
+ : "Use the retained authoritative output already in this session.",
22629
+ "Return one concise natural answer that covers every requested section, then finish.",
22630
+ ].filter(Boolean).join(" ");
22631
+ state.messages.push({ role: "user", content: instruction });
22632
+ await store.appendEvent("completion.structured_output_repair_requested", {
22633
+ ...detail,
22634
+ instruction,
22635
+ });
22636
+ observers.event("completion.structured_output_repair_requested", detail);
22637
+ return { action: "retry", assessment, detail };
22638
+ }
22639
+ const result = verifiedCompletionFallback(assessment, state);
22640
+ await store.appendEvent("completion.structured_output_fallback", {
22641
+ ...detail,
22642
+ result,
22643
+ });
22644
+ observers.event("completion.structured_output_fallback", detail);
22645
+ return { action: "accept", assessment, detail, resultOverride: result };
22646
+ }
22647
+ if (structuredCoverage.ok && state.meta?.structuredCompletionRepair) {
22648
+ delete state.meta.structuredCompletionRepair;
22649
+ }
22541
22650
  const hasRealBlocker = completionExternalBlockerCanClose({
22542
22651
  candidateResult,
22543
22652
  evidenceLedger: assessment.ledger,
@@ -22882,6 +22991,180 @@ function summarizeJsonCommandOutput(output = "") {
22882
22991
  return pairs.length ? `Observed JSON status: ${pairs.join(", ")}.` : "";
22883
22992
  }
22884
22993
 
22994
+ const AUTHORITATIVE_STRUCTURED_SECTION_ALIASES = Object.freeze({
22995
+ queues: ["queue", "queues", "backlog", "队列", "佇列"],
22996
+ schedules: ["schedule", "schedules", "scheduler", "schedulers", "日程", "定时", "定時", "排程"],
22997
+ issues: ["issue", "issues", "problem", "problems", "error", "errors", "blocker", "blockers", "auth", "authentication", "login", "问题", "問題", "错误", "錯誤", "阻塞", "登录", "登入", "授权", "授權"],
22998
+ ingress: ["ingress", "receiver", "receivers", "inbound", "intake", "message intake", "入口", "接收", "收件"],
22999
+ });
23000
+
23001
+ function structuredSectionAliases(key = "") {
23002
+ const normalized = String(key || "").trim().toLowerCase();
23003
+ const aliases = new Set(AUTHORITATIVE_STRUCTURED_SECTION_ALIASES[normalized] || []);
23004
+ if (normalized) {
23005
+ aliases.add(normalized);
23006
+ aliases.add(normalized.replace(/_/g, " "));
23007
+ if (normalized.endsWith("s") && normalized.length > 3) aliases.add(normalized.slice(0, -1));
23008
+ }
23009
+ return [...aliases].filter(Boolean);
23010
+ }
23011
+
23012
+ function completionTextHasAny(value = "", terms = []) {
23013
+ const normalized = String(value || "").toLowerCase();
23014
+ return terms.some((rawTerm) => {
23015
+ const term = String(rawTerm || "").trim().toLowerCase();
23016
+ if (!term) return false;
23017
+ if (!/^[a-z0-9_\- ]+$/u.test(term)) return normalized.includes(term);
23018
+ const escaped = term
23019
+ .replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
23020
+ .replace(/[ _-]+/g, "[ _-]+");
23021
+ return new RegExp(`(?:^|[^a-z0-9])${escaped}(?:$|[^a-z0-9])`, "iu").test(normalized);
23022
+ });
23023
+ }
23024
+
23025
+ function structuredSectionHasFalseAbsence(candidateResult = "", aliases = []) {
23026
+ const sentences = String(candidateResult || "")
23027
+ .split(/(?<=[.!?。!?;;\n])/u)
23028
+ .map((item) => item.trim())
23029
+ .filter(Boolean);
23030
+ 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;
23031
+ return sentences.some((sentence) => completionTextHasAny(sentence, aliases) && absence.test(sentence));
23032
+ }
23033
+
23034
+ function structuredChildTerms(value) {
23035
+ if (!value || typeof value !== "object" || Array.isArray(value)) return [];
23036
+ return Object.keys(value)
23037
+ .flatMap((key) => [key, ...String(key).split(/[_\-\s]+/u)])
23038
+ .map((item) => String(item || "").trim().toLowerCase())
23039
+ .filter((item) => item.length >= 3 && !["daily", "status", "state", "count"].includes(item));
23040
+ }
23041
+
23042
+ function issueValueTerms(value) {
23043
+ if (!Array.isArray(value)) return [];
23044
+ return value
23045
+ .flatMap((item) => [String(item || ""), ...String(item || "").split(/[_\-\s]+/u)])
23046
+ .map((item) => item.trim().toLowerCase())
23047
+ .filter((item) => item.length >= 4 && !["required", "issue", "error"].includes(item));
23048
+ }
23049
+
23050
+ function authoritativeStructuredRequestText(goal = "") {
23051
+ const text = String(goal || "");
23052
+ const evidenceLine = text.match(/^AGINTI_EVIDENCE_SCOPE_JSON:\s*(\{[^\n]+\})/mu);
23053
+ if (evidenceLine) {
23054
+ try {
23055
+ const parsed = JSON.parse(evidenceLine[1]);
23056
+ if (String(parsed?.request || "").trim()) return String(parsed.request).trim();
23057
+ } catch {
23058
+ // Fall through to the visible user-request packet or the direct goal.
23059
+ }
23060
+ }
23061
+ const marker = text.match(/(?:^|\n)User request:\s*\n/iu);
23062
+ if (!marker || marker.index === undefined) return text;
23063
+ const start = marker.index + marker[0].length;
23064
+ const tail = text.slice(start);
23065
+ const boundary = tail.search(/\n(?:Matched established routines|Operating contract|Execution contract|Agent context|Task packet)\b/iu);
23066
+ return (boundary >= 0 ? tail.slice(0, boundary) : tail).trim();
23067
+ }
23068
+
23069
+ function requestedAuthoritativeStructuredSections(goal = "", data = {}) {
23070
+ const request = authoritativeStructuredRequestText(goal);
23071
+ const requested = [];
23072
+ for (const key of Object.keys(data || {})) {
23073
+ const normalized = String(key || "").trim().toLowerCase();
23074
+ const aliasKey = /ingress/i.test(normalized) ? "ingress" : normalized;
23075
+ const aliases = structuredSectionAliases(aliasKey);
23076
+ if (completionTextHasAny(request, aliases)) requested.push(normalized);
23077
+ }
23078
+ if (
23079
+ Object.prototype.hasOwnProperty.call(data || {}, "issues") &&
23080
+ completionTextHasAny(request, AUTHORITATIVE_STRUCTURED_SECTION_ALIASES.issues)
23081
+ ) {
23082
+ requested.push("issues");
23083
+ }
23084
+ return [...new Set(requested)];
23085
+ }
23086
+
23087
+ function authoritativeStructuredSectionCovered(key = "", value, candidateResult = "") {
23088
+ const normalized = String(key || "").toLowerCase();
23089
+ const aliasKey = /ingress/i.test(normalized) ? "ingress" : normalized;
23090
+ const aliases = structuredSectionAliases(aliasKey);
23091
+ if (structuredSectionHasFalseAbsence(candidateResult, aliases)) {
23092
+ return { covered: false, contradicted: true };
23093
+ }
23094
+ const sectionMentioned = completionTextHasAny(candidateResult, aliases);
23095
+ const childMentioned = completionTextHasAny(candidateResult, structuredChildTerms(value));
23096
+ if (normalized === "queues") {
23097
+ const queueState = /\b(?:pending|active|stale|failures?|failed|running|clear|healthy|idle|empty|backlog)\b|待处理|活动|运行|陈旧|失效|失败|健康|空闲|清空/iu.test(candidateResult);
23098
+ return { covered: (sectionMentioned || childMentioned) && queueState, contradicted: false };
23099
+ }
23100
+ if (normalized === "schedules") {
23101
+ const scheduleState = /\b(?:waiting|pending|running|delivered|current|due|retrying|retry|healthy|idle|enabled|disabled|paused|complete|completed)\b|等待|待处理|运行|已送达|已发送|重试|健康|启用|停用|暂停|完成/iu.test(candidateResult);
23102
+ return { covered: (sectionMentioned || childMentioned) && scheduleState && childMentioned, contradicted: false };
23103
+ }
23104
+ if (normalized === "issues") {
23105
+ const issueTerms = issueValueTerms(value);
23106
+ const noIssues = Array.isArray(value) && value.length === 0 && /\b(?:no|zero)\s+(?:issues?|errors?|blockers?)\b|没有(?:问题|错误|阻塞)/iu.test(candidateResult);
23107
+ return {
23108
+ covered: noIssues || ((sectionMentioned || completionTextHasAny(candidateResult, issueTerms)) && completionTextHasAny(candidateResult, issueTerms)),
23109
+ contradicted: false,
23110
+ };
23111
+ }
23112
+ if (/ingress/i.test(normalized)) {
23113
+ const ingressState = /\b(?:reach|reaches|reachable|received|receives|working|healthy|blocked|stale|unknown|ok)\b|可达|收到|接收|正常|健康|阻塞|未知/iu.test(candidateResult);
23114
+ return { covered: (sectionMentioned || childMentioned) && ingressState, contradicted: false };
23115
+ }
23116
+ if (value && typeof value === "object") {
23117
+ return { covered: sectionMentioned && childMentioned, contradicted: false };
23118
+ }
23119
+ const scalar = String(value ?? "").trim().toLowerCase();
23120
+ const scalarTerms = scalar
23121
+ .split(/[_\-\s]+/u)
23122
+ .map((item) => item.trim())
23123
+ .filter((item) => item.length >= 2);
23124
+ const scalarCovered = !scalar ||
23125
+ completionTextHasAny(candidateResult, [scalar]) ||
23126
+ (scalarTerms.length > 1 && scalarTerms.every((term) => completionTextHasAny(candidateResult, [term])));
23127
+ return {
23128
+ covered: sectionMentioned && scalarCovered,
23129
+ contradicted: false,
23130
+ };
23131
+ }
23132
+
23133
+ export function evaluateAuthoritativeStructuredCompletionCoverage({
23134
+ goal = "",
23135
+ candidateResult = "",
23136
+ commandOutputs = [],
23137
+ } = {}) {
23138
+ const authoritative = [...(Array.isArray(commandOutputs) ? commandOutputs : [])]
23139
+ .reverse()
23140
+ .find((item) => item?.authoritative === true && parseCommandJsonOutput(item.output));
23141
+ if (!authoritative) {
23142
+ return { checked: false, ok: true, requestedSections: [], missingSections: [], contradictedSections: [], expectedSummary: "", key: "" };
23143
+ }
23144
+ const data = parseCommandJsonOutput(authoritative.output);
23145
+ const requestedSections = requestedAuthoritativeStructuredSections(goal, data);
23146
+ if (!requestedSections.length) {
23147
+ return { checked: false, ok: true, requestedSections: [], missingSections: [], contradictedSections: [], expectedSummary: summarizeJsonCommandOutput(authoritative.output), key: "" };
23148
+ }
23149
+ const missingSections = [];
23150
+ const contradictedSections = [];
23151
+ for (const key of requestedSections) {
23152
+ const coverage = authoritativeStructuredSectionCovered(key, data[key], candidateResult);
23153
+ if (!coverage.covered) missingSections.push(key);
23154
+ if (coverage.contradicted) contradictedSections.push(key);
23155
+ }
23156
+ const expectedSummary = summarizeJsonCommandOutput(authoritative.output);
23157
+ return {
23158
+ checked: true,
23159
+ ok: missingSections.length === 0 && contradictedSections.length === 0,
23160
+ requestedSections,
23161
+ missingSections,
23162
+ contradictedSections,
23163
+ expectedSummary,
23164
+ key: hashForLog(`${String(goal || "")}\0${String(authoritative.output || "")}\0${requestedSections.join(",")}`),
23165
+ };
23166
+ }
23167
+
22885
23168
  function completionCommandOutputRecords(scoped = {}) {
22886
23169
  const events = Array.isArray(scoped.events) ? scoped.events : [];
22887
23170
  const state = scoped.state && typeof scoped.state === "object" ? scoped.state : {};
@@ -27689,7 +27972,9 @@ async function runAgentOnceUnlocked(config) {
27689
27972
  toolResult: completionDecision.artifactBlock,
27690
27973
  });
27691
27974
  }
27692
- let fallback = redactSensitiveText(assistantMessage.content?.trim() || "");
27975
+ let fallback = redactSensitiveText(
27976
+ completionDecision.resultOverride || assistantMessage.content?.trim() || ""
27977
+ );
27693
27978
  if (!fallback) {
27694
27979
  const emptyDecision = await repairEmptyCompletion({
27695
27980
  config,
@@ -27936,7 +28221,10 @@ async function runAgentOnceUnlocked(config) {
27936
28221
  toolResult: completionDecision.artifactBlock,
27937
28222
  });
27938
28223
  }
27939
- const completionResult = canonicalizeVerifiedArtifactCompletion(state, toolResult.result || "");
28224
+ const completionResult = canonicalizeVerifiedArtifactCompletion(
28225
+ state,
28226
+ completionDecision.resultOverride || toolResult.result || ""
28227
+ );
27940
28228
  if (config.scsActive) {
27941
28229
  const decision = await reviewScsFinish(client, config, state, completionResult, {
27942
28230
  events: await store.loadEvents(),