@lazyingart/agintiflow 0.20.327 → 0.20.328

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.327",
3
+ "version": "0.20.328",
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",
@@ -14,7 +14,11 @@ import {
14
14
  } from "../src/agent-runner.js";
15
15
  import { resolveRuntimeConfig } from "../src/config.js";
16
16
  import { SessionStore } from "../src/session-store.js";
17
- import { deriveScsTaskContract, finishResultClaimsIncompleteWork } from "../src/scs-evidence.js";
17
+ import {
18
+ deriveScsTaskContract,
19
+ evaluateSourceFreeResponseClaims,
20
+ finishResultClaimsIncompleteWork,
21
+ } from "../src/scs-evidence.js";
18
22
 
19
23
  const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
20
24
  const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "agintiflow-truthful-completion-"));
@@ -180,6 +184,114 @@ assert.equal(
180
184
  "agent-owned pending validation was accepted as a completed result"
181
185
  );
182
186
 
187
+ const sourceFreeResearchGoal = [
188
+ "Correct the research status from the host-managed response context.",
189
+ `AGINTI_EVIDENCE_SCOPE_JSON: ${JSON.stringify({
190
+ mode: "host-managed-response",
191
+ request: "Correct the research status from the host-managed response context.",
192
+ })}`,
193
+ ].join("\n");
194
+ const unsafeSourceFreeClaim = evaluateSourceFreeResponseClaims({
195
+ goal: sourceFreeResearchGoal,
196
+ candidateResult:
197
+ "The publication appeared in 2025 and was validated on a 12,000-case benchmark with 94.2% accuracy.",
198
+ evidenceLedger: { itemCount: 0, categories: [], items: [] },
199
+ });
200
+ assert.equal(
201
+ unsafeSourceFreeClaim.ok,
202
+ false,
203
+ "source-free response-only output accepted unsupported external factual claims"
204
+ );
205
+ assert(unsafeSourceFreeClaim.categories.includes("publication"));
206
+ assert(unsafeSourceFreeClaim.categories.includes("benchmark_or_metric"));
207
+ const unsafeChineseSourceFreeClaim = evaluateSourceFreeResponseClaims({
208
+ goal: sourceFreeResearchGoal,
209
+ candidateResult:
210
+ "这是未验证的背景说明。2025年Nature子刊预印本未公开,已有初步验证,响应延迟低于100ms,并预测2026年底前上线。",
211
+ evidenceLedger: { itemCount: 0, categories: [], items: [] },
212
+ });
213
+ assert.equal(
214
+ unsafeChineseSourceFreeClaim.ok,
215
+ false,
216
+ "Chinese source-free response-only output accepted publication, validation, metric, or forecast claims"
217
+ );
218
+ assert(unsafeChineseSourceFreeClaim.categories.includes("publication"));
219
+ assert(unsafeChineseSourceFreeClaim.categories.includes("validation"));
220
+ assert(unsafeChineseSourceFreeClaim.categories.includes("benchmark_or_metric"));
221
+ assert(unsafeChineseSourceFreeClaim.categories.includes("forecast"));
222
+ const unsafeJapaneseSourceFreeClaim = evaluateSourceFreeResponseClaims({
223
+ goal: sourceFreeResearchGoal,
224
+ candidateResult:
225
+ "2026年末までに公開される見込みで、査読済み研究によりレイテンシ80ms未満が検証済みです。",
226
+ evidenceLedger: { itemCount: 0, categories: [], items: [] },
227
+ });
228
+ assert.equal(
229
+ unsafeJapaneseSourceFreeClaim.ok,
230
+ false,
231
+ "Japanese source-free response-only output accepted publication, validation, metric, or forecast claims"
232
+ );
233
+ assert(unsafeJapaneseSourceFreeClaim.categories.includes("forecast"));
234
+ assert(unsafeJapaneseSourceFreeClaim.categories.includes("validation"));
235
+ assert(unsafeJapaneseSourceFreeClaim.categories.includes("benchmark_or_metric"));
236
+ const framedHypothesisClaim = evaluateSourceFreeResponseClaims({
237
+ goal: sourceFreeResearchGoal,
238
+ candidateResult:
239
+ "Without fresh evidence, this is an unverified hypothesis only: the result may need a new literature check before any publication or benchmark claim is trusted.",
240
+ evidenceLedger: { itemCount: 0, categories: [], items: [] },
241
+ });
242
+ assert.equal(
243
+ framedHypothesisClaim.ok,
244
+ true,
245
+ "explicit unverified hypothesis framing was rejected for source-free response-only output"
246
+ );
247
+ const locallyDeniedChineseClaim = evaluateSourceFreeResponseClaims({
248
+ goal: sourceFreeResearchGoal,
249
+ candidateResult:
250
+ "没有本次新证据,这只是未验证假设:无法验证Nature子刊、2025年发表、已有验证或100ms延迟等说法。",
251
+ evidenceLedger: { itemCount: 0, categories: [], items: [] },
252
+ });
253
+ assert.equal(
254
+ locallyDeniedChineseClaim.ok,
255
+ true,
256
+ "local Chinese unverifiable/hypothesis framing was rejected"
257
+ );
258
+ const separatedUnverifiedClaim = evaluateSourceFreeResponseClaims({
259
+ goal: sourceFreeResearchGoal,
260
+ candidateResult:
261
+ "This paragraph is unverified. The Nature publication appeared in 2025 and validation reached 94.2% accuracy.",
262
+ evidenceLedger: { itemCount: 0, categories: [], items: [] },
263
+ });
264
+ assert.equal(
265
+ separatedUnverifiedClaim.ok,
266
+ false,
267
+ "a generic unverified phrase in one sentence governed a separate unsupported factual claim"
268
+ );
269
+ const ordinaryPureChat = evaluateSourceFreeResponseClaims({
270
+ goal: sourceFreeResearchGoal,
271
+ candidateResult: "A recursive function needs a base case so it can stop.",
272
+ evidenceLedger: { itemCount: 0, categories: [], items: [] },
273
+ });
274
+ assert.equal(
275
+ ordinaryPureChat.ok,
276
+ true,
277
+ "ordinary source-free pure chat was incorrectly rejected"
278
+ );
279
+ const sourcedResponseOnlyClaim = evaluateSourceFreeResponseClaims({
280
+ goal: sourceFreeResearchGoal,
281
+ candidateResult:
282
+ "The retained manifest says the benchmark accuracy is 94.2%.",
283
+ evidenceLedger: {
284
+ itemCount: 1,
285
+ categories: ["command"],
286
+ items: [{ category: "command", verified: true }],
287
+ },
288
+ });
289
+ assert.equal(
290
+ sourcedResponseOnlyClaim.ok,
291
+ true,
292
+ "response-only output with current scoped evidence was rejected"
293
+ );
294
+
183
295
  const staleCompletionRepair =
184
296
  "The proposed completion was rejected because the requested action is not supported by concrete runtime evidence. Reason: Missing required git action(s): commit.";
185
297
  const repairCleanup = removeSupersededCompletionRepairInstructions([
@@ -140,6 +140,7 @@ import {
140
140
  evaluateScsSemanticContract,
141
141
  evaluateRequestedArtifactRequirements,
142
142
  augmentScsTaskContractWithProjectVerification,
143
+ evaluateSourceFreeResponseClaims,
143
144
  agintiEvidenceScopeLine,
144
145
  filterExplicitlyExcludedOutputPaths,
145
146
  extractMarkdownCommandEvidence,
@@ -4099,6 +4100,60 @@ async function finishWithDirectAnswer({ config, state, store, observers, session
4099
4100
  };
4100
4101
  }
4101
4102
 
4103
+ function responseOnlyResultFromMessage(message = {}) {
4104
+ if (!message) {
4105
+ throw new Error("Response-only model request returned no assistant message.");
4106
+ }
4107
+ if (Array.isArray(message.tool_calls) && message.tool_calls.length) {
4108
+ throw new Error("Response-only model request returned an unexpected tool call.");
4109
+ }
4110
+ const result = redactSensitiveText(message.content || "").trim();
4111
+ if (!result) {
4112
+ throw new Error("Response-only model request returned empty content.");
4113
+ }
4114
+ return result;
4115
+ }
4116
+
4117
+ async function assessResponseOnlySourceFreeClaims({ config, state, store, result }) {
4118
+ const scoped = currentContinuationEvidence(state, await store.loadEvents());
4119
+ const ledger = buildScsEvidenceLedger({
4120
+ state: scoped.state,
4121
+ context: {
4122
+ events: scoped.events,
4123
+ taskProfile: config.taskProfile,
4124
+ goal: config.goal,
4125
+ },
4126
+ });
4127
+ return evaluateSourceFreeResponseClaims({
4128
+ goal: completionContractGoal(config, state),
4129
+ candidateResult: result,
4130
+ evidenceLedger: ledger,
4131
+ });
4132
+ }
4133
+
4134
+ function responseOnlySourceFreeRepairInstruction(assessment = {}) {
4135
+ const categories = Array.isArray(assessment.categories) && assessment.categories.length
4136
+ ? assessment.categories.join(", ")
4137
+ : "external factual claims";
4138
+ return [
4139
+ "No fresh AgInTi evidence manifest or scoped tool evidence is available for this response-only turn.",
4140
+ `Your previous answer asserted unsupported external facts (${categories}).`,
4141
+ "Do not claim publications, years, validation, forecasts, benchmarks, quantitative metrics, citations, or source-backed conclusions.",
4142
+ "This includes multilingual claim wording such as 已有验证, 预测, 検証済み, or 予測.",
4143
+ "Return a concise answer that is explicitly framed as an unverified hypothesis, or state that the requested external claim cannot be verified from this run.",
4144
+ ].join(" ");
4145
+ }
4146
+
4147
+ function responseOnlySourceFreeStopResult(assessment = {}) {
4148
+ const categories = Array.isArray(assessment.categories) && assessment.categories.length
4149
+ ? assessment.categories.join(", ")
4150
+ : "external factual claims";
4151
+ return [
4152
+ "No result: this response-only turn has no fresh AgInTi evidence manifest or scoped tool evidence.",
4153
+ `I cannot verify the requested ${categories} from this run. Resume with an evidence-producing research/tool scope or provide a fresh evidence manifest.`,
4154
+ ].join(" ");
4155
+ }
4156
+
4102
4157
  async function finishWithResponseOnlyModelTurn({ client, config, state, store, observers, sessionId }) {
4103
4158
  await store.appendEvent("model.requested", {
4104
4159
  step: 1,
@@ -4115,15 +4170,108 @@ async function finishWithResponseOnlyModelTurn({ client, config, state, store, o
4115
4170
 
4116
4171
  const response = await requestDirectResponse(client, config, state.messages);
4117
4172
  const rawAssistantMessage = response.choices[0]?.message;
4118
- if (!rawAssistantMessage) {
4119
- throw new Error("Response-only model request returned no assistant message.");
4120
- }
4121
- if (Array.isArray(rawAssistantMessage.tool_calls) && rawAssistantMessage.tool_calls.length) {
4122
- throw new Error("Response-only model request returned an unexpected tool call.");
4123
- }
4124
- const result = redactSensitiveText(rawAssistantMessage.content || "").trim();
4125
- if (!result) {
4126
- throw new Error("Response-only model request returned empty content.");
4173
+ let result = responseOnlyResultFromMessage(rawAssistantMessage);
4174
+ let finalAssistantMessage = rawAssistantMessage;
4175
+ let sourceFreeAssessment = await assessResponseOnlySourceFreeClaims({
4176
+ config,
4177
+ state,
4178
+ store,
4179
+ result,
4180
+ });
4181
+ if (!sourceFreeAssessment.ok) {
4182
+ const detail = {
4183
+ step: 1,
4184
+ mode: "response-only",
4185
+ reason: sourceFreeAssessment.reason,
4186
+ categories: sourceFreeAssessment.categories,
4187
+ hasEvidence: sourceFreeAssessment.hasEvidence,
4188
+ explicitlyUnverified: sourceFreeAssessment.explicitlyUnverified,
4189
+ preview: publicCompletionText(result, 300),
4190
+ unsupportedClaims: sourceFreeAssessment.unsupportedClaims || [],
4191
+ };
4192
+ await store.appendEvent("response_only.source_free_claim_rejected", detail);
4193
+ observers.event("response_only.source_free_claim_rejected", detail);
4194
+ state.messages.push({
4195
+ role: "user",
4196
+ content: responseOnlySourceFreeRepairInstruction(sourceFreeAssessment),
4197
+ });
4198
+ await store.saveState(state);
4199
+ await store.appendEvent("model.requested", {
4200
+ step: 2,
4201
+ provider: config.provider,
4202
+ model: config.model,
4203
+ mode: "response-only-repair",
4204
+ });
4205
+ observers.event("model.requested", {
4206
+ step: 2,
4207
+ provider: config.provider,
4208
+ model: config.model,
4209
+ mode: "response-only-repair",
4210
+ });
4211
+ const repairResponse = await requestDirectResponse(client, config, state.messages);
4212
+ finalAssistantMessage = repairResponse.choices[0]?.message;
4213
+ result = responseOnlyResultFromMessage(finalAssistantMessage);
4214
+ sourceFreeAssessment = await assessResponseOnlySourceFreeClaims({
4215
+ config,
4216
+ state,
4217
+ store,
4218
+ result,
4219
+ });
4220
+ if (sourceFreeAssessment.ok) {
4221
+ const repaired = {
4222
+ step: 2,
4223
+ mode: "response-only-repair",
4224
+ reason: sourceFreeAssessment.reason,
4225
+ categories: sourceFreeAssessment.categories,
4226
+ explicitlyUnverified: sourceFreeAssessment.explicitlyUnverified,
4227
+ unsupportedClaims: sourceFreeAssessment.unsupportedClaims || [],
4228
+ };
4229
+ await store.appendEvent("response_only.source_free_claim_repaired", repaired);
4230
+ observers.event("response_only.source_free_claim_repaired", repaired);
4231
+ } else {
4232
+ result = responseOnlySourceFreeStopResult(sourceFreeAssessment);
4233
+ const fallback = {
4234
+ step: 2,
4235
+ mode: "response-only-fail-closed",
4236
+ reason: sourceFreeAssessment.reason,
4237
+ categories: sourceFreeAssessment.categories,
4238
+ unsupportedClaims: sourceFreeAssessment.unsupportedClaims || [],
4239
+ result: publicCompletionText(result, 500),
4240
+ };
4241
+ state.meta = state.meta || {};
4242
+ state.meta.responseOnly = {
4243
+ stoppedAt: new Date().toISOString(),
4244
+ provider: config.provider,
4245
+ model: config.model,
4246
+ sourceFreeClaimBlocked: true,
4247
+ };
4248
+ state.updatedAt = state.meta.responseOnly.stoppedAt;
4249
+ state.messages.push({ role: "assistant", content: result });
4250
+ appendChatEntry(state, "assistant", result);
4251
+ updateGoalStatus(state, "paused", "source_free_evidence_required", state.updatedAt);
4252
+ await store.saveState(state);
4253
+ await store.appendEvent("response_only.source_free_claim_failed_closed", fallback);
4254
+ await store.appendEvent("session.stopped", {
4255
+ reason: "source_free_evidence_required",
4256
+ result,
4257
+ mode: "response-only",
4258
+ });
4259
+ observers.event("response_only.source_free_claim_failed_closed", fallback);
4260
+ observers.event("session.stopped", {
4261
+ reason: "source_free_evidence_required",
4262
+ result,
4263
+ sessionId,
4264
+ mode: "response-only",
4265
+ });
4266
+ emitConsole(config, result, { kind: "assistant", markdown: true });
4267
+ return {
4268
+ sessionId,
4269
+ stopped: true,
4270
+ reason: "source_free_evidence_required",
4271
+ result,
4272
+ ...goalRunMetadata(state),
4273
+ };
4274
+ }
4127
4275
  }
4128
4276
 
4129
4277
  state.meta = state.meta || {};
@@ -4135,7 +4283,7 @@ async function finishWithResponseOnlyModelTurn({ client, config, state, store, o
4135
4283
  state.stepsCompleted = 1;
4136
4284
  state.updatedAt = state.meta.responseOnly.completedAt;
4137
4285
  state.messages.push(preserveAssistantMessage({
4138
- ...rawAssistantMessage,
4286
+ ...finalAssistantMessage,
4139
4287
  role: "assistant",
4140
4288
  content: result,
4141
4289
  tool_calls: undefined,
@@ -300,6 +300,7 @@ export async function requestDirectResponse(client, config, messages = []) {
300
300
  "Response-only scope: return the requested final content directly as the assistant response.",
301
301
  "Do not produce an execution plan, call tools, mention internal runtime details, or stop at a placeholder.",
302
302
  "Preserve every material requirement and all source-grounded details supplied in the current request.",
303
+ "If no fresh evidence manifest or source text is present, do not claim publications, years, validation, forecasts, benchmarks, quantitative metrics, citations, or source-backed conclusions; in English, Chinese, Japanese, or any other response language, frame such material locally as an unverified hypothesis or say it cannot be verified from this run.",
303
304
  ].join(" "),
304
305
  },
305
306
  ];
@@ -1825,6 +1825,191 @@ export function isResponseOnlyEvidenceScope(goal = "") {
1825
1825
  return ["chat-response", "host-managed-response", "plan-response", "read-only-answer"].includes(mode);
1826
1826
  }
1827
1827
 
1828
+ function responseOnlyScopeHasFreshEvidenceManifest(goal = "") {
1829
+ const payload = parseAgintiEvidenceScope(goal);
1830
+ if (!payload || typeof payload !== "object") return false;
1831
+ const manifestCandidates = [
1832
+ payload.evidenceManifest,
1833
+ payload.evidence_manifest,
1834
+ payload.freshEvidenceManifest,
1835
+ payload.fresh_evidence_manifest,
1836
+ payload.sourceManifest,
1837
+ payload.source_manifest,
1838
+ payload.manifestDigest,
1839
+ payload.manifest_digest,
1840
+ payload.evidenceDigest,
1841
+ payload.evidence_digest,
1842
+ payload.sourceDigest,
1843
+ payload.source_digest,
1844
+ ];
1845
+ return manifestCandidates.some((item) => {
1846
+ if (typeof item === "string") return item.trim().length >= 12;
1847
+ if (item && typeof item === "object") return Object.keys(item).length > 0;
1848
+ return Array.isArray(item) && item.length > 0;
1849
+ });
1850
+ }
1851
+
1852
+ function sourceFreeResponseHasEvidence(ledger = {}) {
1853
+ if (!ledger || typeof ledger !== "object") return false;
1854
+ if (Number(ledger.itemCount || 0) > 0) return true;
1855
+ if (Array.isArray(ledger.items) && ledger.items.some((item) => item?.verified !== false)) return true;
1856
+ if (Array.isArray(ledger.categories) && ledger.categories.length > 0) return true;
1857
+ return false;
1858
+ }
1859
+
1860
+ function sourceFreeClaimSegments(text = "") {
1861
+ return String(text || "")
1862
+ .split(/(?:[\n\r]+|(?<=[.!?。!?;;]))/u)
1863
+ .map((item) => item.trim())
1864
+ .filter(Boolean);
1865
+ }
1866
+
1867
+ function sourceFreeClaimSegmentHasExplicitUnverifiedFraming(text = "") {
1868
+ const value = String(text || "");
1869
+ const admitsNoEvidence =
1870
+ /\b(?:unverified|not\s+verified|cannot\s+verify|can't\s+verify|could\s+not\s+verify|no\s+(?:fresh\s+)?(?:evidence|sources?|manifest)|without\s+(?:fresh\s+)?(?:evidence|sources?|manifest))\b/iu.test(
1871
+ value
1872
+ ) ||
1873
+ /(?:没有|沒有|无|無|缺少|未获得|未取得|未取得到)(?:新鲜|新鮮|当前|當前|本次|新的)?(?:证据|證據|来源|來源|资料|資料|文献|文獻|检索|檢索|材料)/u.test(
1874
+ value
1875
+ ) ||
1876
+ /(?:无法|無法|不能|未能|没法|沒法)(?:在本次|从本次|從本次)?(?:验证|驗證|核实|核實|证实|證實|确认|確認|证明|證明|支持)/u.test(
1877
+ value
1878
+ ) ||
1879
+ /(?:証拠|出典|根拠|資料|ソース)(?:が)?(?:ない|ありません|不足)|(?:検証|確認|裏付け)(?:できない|されていない|できません)|未検証/u.test(
1880
+ value
1881
+ );
1882
+ const framesAsHypothesis =
1883
+ /\b(?:hypothesis|hypotheses|speculative|speculation|not\s+(?:a\s+)?(?:verified|evidence-backed|source-backed)\s+claim)\b/iu.test(
1884
+ value
1885
+ ) ||
1886
+ /(?:假设|假說|推测|推測|猜测|猜測|臆测|臆測|未验证|未經驗證|未经验证|未核实|未核實)/u.test(
1887
+ value
1888
+ ) ||
1889
+ /(?:仮説|推測|憶測|未検証|未確認)/u.test(value);
1890
+ return admitsNoEvidence && framesAsHypothesis;
1891
+ }
1892
+
1893
+ function sourceFreeClaimSegmentDeniesVerification(text = "") {
1894
+ const value = String(text || "");
1895
+ return (
1896
+ /\b(?:cannot|can't|could\s+not|do\s+not|don't|unable\s+to|not\s+able\s+to|no\s+(?:fresh\s+)?(?:evidence|source|manifest)\s+to|without\s+(?:fresh\s+)?(?:evidence|sources?|manifest),?\s+(?:i\s+)?(?:cannot|can't|could\s+not)?)\b[^.!?;。!?;\n]{0,140}\b(?:verify|confirm|substantiate|support|validate|prove|claim)\b/iu.test(
1897
+ value
1898
+ ) ||
1899
+ /(?:无法|無法|不能|未能|没法|沒法|不应|不應|不能够|不能夠|没有证据|沒有證據|无证据|無證據)[^。!?;\n]{0,80}(?:验证|驗證|核实|核實|证实|證實|确认|確認|证明|證明|支持|声称|聲稱|断言|斷言)/u.test(
1900
+ value
1901
+ ) ||
1902
+ /(?:検証|確認|裏付け|断言|主張)(?:できない|できません|されていない)|(?:証拠|出典|根拠)(?:が)?(?:ない|ありません)[^。!?;\n]{0,60}(?:検証|確認|主張|断言)/u.test(
1903
+ value
1904
+ )
1905
+ );
1906
+ }
1907
+
1908
+ function sourceFreeExternalClaimCategoriesForSegment(text = "") {
1909
+ const value = String(text || "");
1910
+ if (!value.trim()) return [];
1911
+ const categories = [];
1912
+ const add = (category, pattern) => {
1913
+ pattern.lastIndex = 0;
1914
+ if (pattern.test(value)) categories.push(category);
1915
+ };
1916
+ add(
1917
+ "publication",
1918
+ /\b(?:paper|study|article|preprint|publication|manuscript|dataset|trial|journal|conference|arxiv|doi|nature|science|cell)\b[^.!?;。!?;\n]{0,140}\b(?:published|appeared|released|accepted|reported|found|showed|demonstrated|validated)\b|\b(?:published|accepted|released)\b[^.!?;。!?;\n]{0,80}\b(?:paper|study|article|preprint|publication|manuscript|dataset|trial|journal|conference|arxiv|doi|nature|science|cell)\b|(?:Nature|Science|Cell|子刊|期刊|论文|論文|预印本|預印本|文章|研究|数据集|資料集|データセット|論文|研究|プレプリント|ジャーナル)[^.!?;。!?;\n]{0,80}(?:发表|發表|刊登|出版|公开|公開|收录|收録|发布|發布|掲載|発表|公開|出版)|(?:发表|發表|刊登|出版|公开|公開|收录|收録|发布|發布|掲載|発表|公開|出版)[^.!?;。!?;\n]{0,80}(?:Nature|Science|Cell|子刊|期刊|论文|論文|预印本|預印本|文章|研究|数据集|資料集|データセット|論文|研究|プレプリント|ジャーナル)/iu
1919
+ );
1920
+ add(
1921
+ "year",
1922
+ /\b(?:published|released|announced|accepted|reported|validated|verified|evaluated|benchmarked|forecast(?:ed)?|projected|predicted)\b[^.!?;。!?;\n]{0,100}\b(?:19|20)\d{2}\b|\b(?:19|20)\d{2}\b[^.!?;。!?;\n]{0,100}\b(?:publication|paper|study|article|benchmark|forecast|projection|dataset|trial|validation|release)\b|(?:19|20)\d{2}\s*年?[^.!?;。!?;\n]{0,80}(?:Nature|Science|Cell|子刊|期刊|论文|論文|预印本|預印本|文章|研究|发表|發表|发布|發布|预测|預測|预计|預計|验证|驗證|基准|基準|指标|指標|論文|研究|発表|公開|掲載|予測|検証|ベンチマーク)|(?:Nature|Science|Cell|子刊|期刊|论文|論文|预印本|預印本|文章|研究|发表|發表|发布|發布|预测|預測|预计|預計|验证|驗證|基准|基準|指标|指標|論文|研究|発表|公開|掲載|予測|検証|ベンチマーク)[^.!?;。!?;\n]{0,80}(?:19|20)\d{2}\s*年?/iu
1923
+ );
1924
+ add(
1925
+ "validation",
1926
+ /\b(?:validated|verified|proven|confirmed|replicated|peer-reviewed|source-backed|evidence-backed|grounded\s+in\s+(?:sources?|evidence)|the\s+evidence\s+(?:shows|confirms|validates|proves))\b|(?:已有|已经|已經|已经有|已經有|已|初步|经过|經過|得到|获得|獲得)[^。!?;\n]{0,20}(?:验证|驗證|核实|核實|证实|證實|确认|確認|证明|證明)|(?:验证|驗證|核实|核實|证实|證實|确认|確認|证明|證明)(?:通过|通過|完成|成功|结果|結果)|(?:検証済み|確認済み|実証済み|裏付けられた|査読済み)/iu
1927
+ );
1928
+ add(
1929
+ "forecast",
1930
+ /\b(?:forecast|forecasted|predict(?:s|ed|ion)?|project(?:s|ed|ion)?|expected\s+to|will\s+(?:reach|increase|decrease|grow|decline|outperform|underperform)|cagr)\b|(?:预测|預測|预计|預計|估计|估計|推算|推測|到\s*(?:19|20)\d{2}\s*年?(?:底|末)?(?:前|之前)?|(?:19|20)\d{2}\s*年?(?:底|末)?(?:前|之前)?[^。!?;\n]{0,40}(?:将|將|会|會|预计|預計|预测|預測))|(?:予測|予想|見込み|推定|年末まで|までに)/iu
1931
+ );
1932
+ add(
1933
+ "benchmark_or_metric",
1934
+ /\b(?:benchmark(?:ed|s)?|metric|score|accuracy|precision|recall|f1|auc|bleu|rouge|latency|throughput|validated\s+on|evaluated\s+on)\b[^.!?;。!?;\n]{0,100}\b\d[\d,.]*(?:\s*(?:%|percent|cases?|subjects?|participants?|patients?|samples?|records?|tokens?\/s|requests?\/s|ms|seconds?|x))?\b|\b\d[\d,.]*(?:\.\d+)?\s*(?:%|percent|cases?|subjects?|participants?|patients?|samples?|records?|benchmarks?|tokens?\/s|requests?\/s|ms|seconds?)\b[^.!?;。!?;\n]{0,100}\b(?:accuracy|validated|verified|benchmark|forecast|prediction|projection|reliable|better|improved|increase|decrease)\b|(?:响应延迟|響應延遲|响应时间|響應時間|延迟|延遲|准确率|準確率|精度|召回|吞吐|基准|基準|指标|指標|分数|分數|反応遅延|レイテンシ|精度|ベンチマーク|指標|スコア)[^。!?;\n]{0,60}\d[\d,.]*(?:\s*(?:%|%|ms|毫秒|秒|例|个|個|件|倍|x))?|\d[\d,.]*(?:\.\d+)?\s*(?:%|%|ms|毫秒|秒|例|个|個|件|倍|x)[^。!?;\n]{0,60}(?:响应延迟|響應延遲|响应时间|響應時間|延迟|延遲|准确率|準確率|精度|召回|吞吐|基准|基準|指标|指標|分数|分數|反応遅延|レイテンシ|精度|ベンチマーク|指標|スコア)/iu
1935
+ );
1936
+ add(
1937
+ "external_evidence",
1938
+ /\b(?:according\s+to|as\s+reported\s+by|sources?\s+(?:show|say|indicate|confirm|report)|cit(?:e|ation|ed)|doi\s*[:/]|arxiv\s*[:/]|the\s+(?:paper|study|source|evidence)\s+(?:shows|states|reports|confirms|validates))\b|(?:根据|根據|据|據|来源|來源|资料|資料|证据|證據|文献|文獻|论文|論文|引用)[^。!?;\n]{0,50}(?:显示|顯示|表明|指出|报道|報道|证明|證明|验证|驗證|确认|確認)|(?:によると|出典|証拠|根拠|引用|論文|研究)[^。!?;\n]{0,50}(?:示す|示した|報告|確認|検証)/iu
1939
+ );
1940
+ return unique(categories);
1941
+ }
1942
+
1943
+ function sourceFreeExternalClaimAssessment(text = "") {
1944
+ const segments = sourceFreeClaimSegments(text);
1945
+ const categories = [];
1946
+ const unsupported = [];
1947
+ for (const segment of segments) {
1948
+ const segmentCategories = sourceFreeExternalClaimCategoriesForSegment(segment);
1949
+ if (!segmentCategories.length) continue;
1950
+ categories.push(...segmentCategories);
1951
+ const deniesVerification = sourceFreeClaimSegmentDeniesVerification(segment);
1952
+ const explicitlyUnverified = sourceFreeClaimSegmentHasExplicitUnverifiedFraming(segment);
1953
+ const assertsEvidence = segmentCategories.some((category) =>
1954
+ ["validation", "external_evidence"].includes(category)
1955
+ );
1956
+ if (!deniesVerification && (assertsEvidence || !explicitlyUnverified)) {
1957
+ unsupported.push({
1958
+ categories: segmentCategories,
1959
+ preview: compact(segment, 240),
1960
+ });
1961
+ }
1962
+ }
1963
+ return {
1964
+ categories: unique(categories),
1965
+ unsupported,
1966
+ explicitlyUnverified:
1967
+ categories.length > 0 &&
1968
+ unsupported.length === 0 &&
1969
+ segments.some((segment) => sourceFreeClaimSegmentHasExplicitUnverifiedFraming(segment)),
1970
+ };
1971
+ }
1972
+
1973
+ export function evaluateSourceFreeResponseClaims({
1974
+ goal = "",
1975
+ candidateResult = "",
1976
+ evidenceLedger = {},
1977
+ } = {}) {
1978
+ if (!isResponseOnlyEvidenceScope(goal)) {
1979
+ return {
1980
+ checked: false,
1981
+ ok: true,
1982
+ reason: "Not a response-only evidence scope.",
1983
+ categories: [],
1984
+ hasEvidence: false,
1985
+ explicitlyUnverified: false,
1986
+ };
1987
+ }
1988
+ const hasEvidence =
1989
+ responseOnlyScopeHasFreshEvidenceManifest(goal) ||
1990
+ sourceFreeResponseHasEvidence(evidenceLedger);
1991
+ const claimAssessment = sourceFreeExternalClaimAssessment(candidateResult);
1992
+ const categories = claimAssessment.categories;
1993
+ const unsupportedClaims = claimAssessment.unsupported;
1994
+ const explicitlyUnverified = claimAssessment.explicitlyUnverified;
1995
+ const ok = hasEvidence || categories.length === 0 || unsupportedClaims.length === 0;
1996
+ return {
1997
+ checked: true,
1998
+ ok,
1999
+ reason: ok
2000
+ ? hasEvidence
2001
+ ? "Current scoped evidence is available for response-only factual claims."
2002
+ : explicitlyUnverified
2003
+ ? "Every source-free external claim is locally framed as unverified hypothesis or unverifiable."
2004
+ : "No source-grounded external claim was detected."
2005
+ : `Source-free response-only output claimed external facts without current evidence: ${categories.join(", ")}.`,
2006
+ categories,
2007
+ unsupportedClaims,
2008
+ hasEvidence,
2009
+ explicitlyUnverified,
2010
+ };
2011
+ }
2012
+
1828
2013
  export function scopedChatopsEvidenceGoal(goal = "", taskProfile = "") {
1829
2014
  const payload = parseAgintiEvidenceScope(goal);
1830
2015
  if (!payload) {