@lazyingart/agintiflow 0.20.327 → 0.20.329
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/docs/supervision-campaign-ledger.md +25 -0
- package/package.json +1 -1
- package/scripts/smoke-truthful-completion.js +113 -1
- package/src/agent-runner.js +231 -11
- package/src/model-client.js +1 -0
- package/src/scs-evidence.js +185 -0
|
@@ -675,3 +675,28 @@ demonstrated evidence from inferred recommendations, and finished normally.
|
|
|
675
675
|
The retained trace contains no completion-evidence rejection or forced
|
|
676
676
|
source-mutation loop. Focused completion, evidence, progressive-tool, runtime,
|
|
677
677
|
and dynamic-budget suites plus the full npm suite pass for `0.20.303`.
|
|
678
|
+
|
|
679
|
+
### Response-only context compaction after provider handoff
|
|
680
|
+
|
|
681
|
+
`response-only-context-handoff-092` exercises a high-risk continuation boundary
|
|
682
|
+
for DeepSeek-first operation with LocalLLM fallback. Recent same-session
|
|
683
|
+
response-only evidence showed DeepSeek quota failures followed by LocalLLM
|
|
684
|
+
resume attempts that failed before inference because the retained transcript
|
|
685
|
+
exceeded the LocalLLM context window. Normal agent-step requests already had a
|
|
686
|
+
local context-budget compaction retry, but the explicit response-only branch
|
|
687
|
+
called the direct-response client without that recovery path.
|
|
688
|
+
|
|
689
|
+
AgInTiFlow now catches only `LOCALLLM_CONTEXT_BUDGET_EXCEEDED` in the
|
|
690
|
+
response-only branch, compacts the authoritative retained goal/evidence once,
|
|
691
|
+
persists `model.local_context_budget_exceeded` and
|
|
692
|
+
`history.compacted_for_local_context_retry`, and retries the same response-only
|
|
693
|
+
request with a bounded output reserve. The source-free evidence guard remains
|
|
694
|
+
active after compaction, so unsupported publication, validation, forecast,
|
|
695
|
+
benchmark, or metric claims still retry once and then fail closed.
|
|
696
|
+
|
|
697
|
+
The focused regression seeds a DeepSeek-owned response-only session, inflates
|
|
698
|
+
retained same-session context, resumes with a normal "answer from the saved
|
|
699
|
+
status" prompt, triggers a DeepSeek quota handoff, and verifies that LocalLLM is
|
|
700
|
+
called only after compaction. The run completes without `session.failed`, keeps
|
|
701
|
+
the provider handoff active on the same session, and records the compaction
|
|
702
|
+
events as durable evidence.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.329",
|
|
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 {
|
|
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([
|
package/src/agent-runner.js
CHANGED
|
@@ -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,7 +4100,127 @@ 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 }) {
|
|
4158
|
+
async function requestWithResponseOnlyLocalContextRecovery({ step, mode }) {
|
|
4159
|
+
try {
|
|
4160
|
+
return await requestDirectResponse(client, config, state.messages);
|
|
4161
|
+
} catch (error) {
|
|
4162
|
+
if (!isLocalContextBudgetError(error)) throw error;
|
|
4163
|
+
state.meta = state.meta || {};
|
|
4164
|
+
const retried = state.meta.localContextBudgetRetries || {};
|
|
4165
|
+
const retryKey = `response-only:${mode}`;
|
|
4166
|
+
if (retried[retryKey]) throw error;
|
|
4167
|
+
|
|
4168
|
+
const requestMessages = Array.isArray(state.messages) ? state.messages : [];
|
|
4169
|
+
const currentOutputTokens = Math.max(0, Number(config.maxOutputTokens || 0));
|
|
4170
|
+
const retryOutputTokens = currentOutputTokens
|
|
4171
|
+
? Math.min(currentOutputTokens, 4096)
|
|
4172
|
+
: 4096;
|
|
4173
|
+
const retryRuntimeConfig = {
|
|
4174
|
+
...config,
|
|
4175
|
+
maxOutputTokens: retryOutputTokens,
|
|
4176
|
+
};
|
|
4177
|
+
const compactMessages = buildContextBudgetCompactionMessages(
|
|
4178
|
+
state,
|
|
4179
|
+
retryRuntimeConfig,
|
|
4180
|
+
null,
|
|
4181
|
+
step,
|
|
4182
|
+
{
|
|
4183
|
+
heading: "A response-only LocalLLM request exceeded the local context window.",
|
|
4184
|
+
detail: redactSensitiveText(error instanceof Error ? error.message : String(error)),
|
|
4185
|
+
recoveryInstruction:
|
|
4186
|
+
"Answer the current response-only request directly from the compacted authoritative context above. Do not claim fresh external evidence unless the compacted context contains a current evidence manifest or scoped tool evidence.",
|
|
4187
|
+
}
|
|
4188
|
+
);
|
|
4189
|
+
const detail = {
|
|
4190
|
+
step,
|
|
4191
|
+
mode,
|
|
4192
|
+
provider: config.provider,
|
|
4193
|
+
model: config.model,
|
|
4194
|
+
messageCharsBefore: countMessageChars(requestMessages),
|
|
4195
|
+
messageCharsAfter: countMessageChars(compactMessages),
|
|
4196
|
+
messageTokensBefore: estimateMessageTokens(requestMessages),
|
|
4197
|
+
messageTokensAfter: estimateMessageTokens(compactMessages),
|
|
4198
|
+
maxOutputTokens: retryOutputTokens,
|
|
4199
|
+
error: redactSensitiveText(error instanceof Error ? error.message : String(error)),
|
|
4200
|
+
};
|
|
4201
|
+
state.messages = compactMessages;
|
|
4202
|
+
resetStaticDiscoveryAfterContextLoss(state, "response-only-local-context-budget-retry", {
|
|
4203
|
+
preserveStaticEvidence: true,
|
|
4204
|
+
});
|
|
4205
|
+
state.meta.localContextBudgetRetries = {
|
|
4206
|
+
...retried,
|
|
4207
|
+
[retryKey]: true,
|
|
4208
|
+
};
|
|
4209
|
+
state.meta.lastResponseOnlyContextBudgetRecovery = detail;
|
|
4210
|
+
await store.appendEvent("model.local_context_budget_exceeded", detail);
|
|
4211
|
+
await store.appendEvent("history.compacted_for_local_context_retry", detail);
|
|
4212
|
+
observers.event("model.local_context_budget_exceeded", detail);
|
|
4213
|
+
observers.event("history.compacted_for_local_context_retry", detail);
|
|
4214
|
+
emitConsole(
|
|
4215
|
+
config,
|
|
4216
|
+
"Local provider context exceeded its configured window for a response-only turn; compacted authoritative context and retrying once.",
|
|
4217
|
+
{ kind: "meta" }
|
|
4218
|
+
);
|
|
4219
|
+
await store.saveState(state);
|
|
4220
|
+
return await requestDirectResponse(client, retryRuntimeConfig, state.messages);
|
|
4221
|
+
}
|
|
4222
|
+
}
|
|
4223
|
+
|
|
4103
4224
|
await store.appendEvent("model.requested", {
|
|
4104
4225
|
step: 1,
|
|
4105
4226
|
provider: config.provider,
|
|
@@ -4113,17 +4234,116 @@ async function finishWithResponseOnlyModelTurn({ client, config, state, store, o
|
|
|
4113
4234
|
mode: "response-only",
|
|
4114
4235
|
});
|
|
4115
4236
|
|
|
4116
|
-
const response = await
|
|
4237
|
+
const response = await requestWithResponseOnlyLocalContextRecovery({
|
|
4238
|
+
step: 1,
|
|
4239
|
+
mode: "response-only",
|
|
4240
|
+
});
|
|
4117
4241
|
const rawAssistantMessage = response.choices[0]?.message;
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4242
|
+
let result = responseOnlyResultFromMessage(rawAssistantMessage);
|
|
4243
|
+
let finalAssistantMessage = rawAssistantMessage;
|
|
4244
|
+
let sourceFreeAssessment = await assessResponseOnlySourceFreeClaims({
|
|
4245
|
+
config,
|
|
4246
|
+
state,
|
|
4247
|
+
store,
|
|
4248
|
+
result,
|
|
4249
|
+
});
|
|
4250
|
+
if (!sourceFreeAssessment.ok) {
|
|
4251
|
+
const detail = {
|
|
4252
|
+
step: 1,
|
|
4253
|
+
mode: "response-only",
|
|
4254
|
+
reason: sourceFreeAssessment.reason,
|
|
4255
|
+
categories: sourceFreeAssessment.categories,
|
|
4256
|
+
hasEvidence: sourceFreeAssessment.hasEvidence,
|
|
4257
|
+
explicitlyUnverified: sourceFreeAssessment.explicitlyUnverified,
|
|
4258
|
+
preview: publicCompletionText(result, 300),
|
|
4259
|
+
unsupportedClaims: sourceFreeAssessment.unsupportedClaims || [],
|
|
4260
|
+
};
|
|
4261
|
+
await store.appendEvent("response_only.source_free_claim_rejected", detail);
|
|
4262
|
+
observers.event("response_only.source_free_claim_rejected", detail);
|
|
4263
|
+
state.messages.push({
|
|
4264
|
+
role: "user",
|
|
4265
|
+
content: responseOnlySourceFreeRepairInstruction(sourceFreeAssessment),
|
|
4266
|
+
});
|
|
4267
|
+
await store.saveState(state);
|
|
4268
|
+
await store.appendEvent("model.requested", {
|
|
4269
|
+
step: 2,
|
|
4270
|
+
provider: config.provider,
|
|
4271
|
+
model: config.model,
|
|
4272
|
+
mode: "response-only-repair",
|
|
4273
|
+
});
|
|
4274
|
+
observers.event("model.requested", {
|
|
4275
|
+
step: 2,
|
|
4276
|
+
provider: config.provider,
|
|
4277
|
+
model: config.model,
|
|
4278
|
+
mode: "response-only-repair",
|
|
4279
|
+
});
|
|
4280
|
+
const repairResponse = await requestWithResponseOnlyLocalContextRecovery({
|
|
4281
|
+
step: 2,
|
|
4282
|
+
mode: "response-only-repair",
|
|
4283
|
+
});
|
|
4284
|
+
finalAssistantMessage = repairResponse.choices[0]?.message;
|
|
4285
|
+
result = responseOnlyResultFromMessage(finalAssistantMessage);
|
|
4286
|
+
sourceFreeAssessment = await assessResponseOnlySourceFreeClaims({
|
|
4287
|
+
config,
|
|
4288
|
+
state,
|
|
4289
|
+
store,
|
|
4290
|
+
result,
|
|
4291
|
+
});
|
|
4292
|
+
if (sourceFreeAssessment.ok) {
|
|
4293
|
+
const repaired = {
|
|
4294
|
+
step: 2,
|
|
4295
|
+
mode: "response-only-repair",
|
|
4296
|
+
reason: sourceFreeAssessment.reason,
|
|
4297
|
+
categories: sourceFreeAssessment.categories,
|
|
4298
|
+
explicitlyUnverified: sourceFreeAssessment.explicitlyUnverified,
|
|
4299
|
+
unsupportedClaims: sourceFreeAssessment.unsupportedClaims || [],
|
|
4300
|
+
};
|
|
4301
|
+
await store.appendEvent("response_only.source_free_claim_repaired", repaired);
|
|
4302
|
+
observers.event("response_only.source_free_claim_repaired", repaired);
|
|
4303
|
+
} else {
|
|
4304
|
+
result = responseOnlySourceFreeStopResult(sourceFreeAssessment);
|
|
4305
|
+
const fallback = {
|
|
4306
|
+
step: 2,
|
|
4307
|
+
mode: "response-only-fail-closed",
|
|
4308
|
+
reason: sourceFreeAssessment.reason,
|
|
4309
|
+
categories: sourceFreeAssessment.categories,
|
|
4310
|
+
unsupportedClaims: sourceFreeAssessment.unsupportedClaims || [],
|
|
4311
|
+
result: publicCompletionText(result, 500),
|
|
4312
|
+
};
|
|
4313
|
+
state.meta = state.meta || {};
|
|
4314
|
+
state.meta.responseOnly = {
|
|
4315
|
+
stoppedAt: new Date().toISOString(),
|
|
4316
|
+
provider: config.provider,
|
|
4317
|
+
model: config.model,
|
|
4318
|
+
sourceFreeClaimBlocked: true,
|
|
4319
|
+
};
|
|
4320
|
+
state.updatedAt = state.meta.responseOnly.stoppedAt;
|
|
4321
|
+
state.messages.push({ role: "assistant", content: result });
|
|
4322
|
+
appendChatEntry(state, "assistant", result);
|
|
4323
|
+
updateGoalStatus(state, "paused", "source_free_evidence_required", state.updatedAt);
|
|
4324
|
+
await store.saveState(state);
|
|
4325
|
+
await store.appendEvent("response_only.source_free_claim_failed_closed", fallback);
|
|
4326
|
+
await store.appendEvent("session.stopped", {
|
|
4327
|
+
reason: "source_free_evidence_required",
|
|
4328
|
+
result,
|
|
4329
|
+
mode: "response-only",
|
|
4330
|
+
});
|
|
4331
|
+
observers.event("response_only.source_free_claim_failed_closed", fallback);
|
|
4332
|
+
observers.event("session.stopped", {
|
|
4333
|
+
reason: "source_free_evidence_required",
|
|
4334
|
+
result,
|
|
4335
|
+
sessionId,
|
|
4336
|
+
mode: "response-only",
|
|
4337
|
+
});
|
|
4338
|
+
emitConsole(config, result, { kind: "assistant", markdown: true });
|
|
4339
|
+
return {
|
|
4340
|
+
sessionId,
|
|
4341
|
+
stopped: true,
|
|
4342
|
+
reason: "source_free_evidence_required",
|
|
4343
|
+
result,
|
|
4344
|
+
...goalRunMetadata(state),
|
|
4345
|
+
};
|
|
4346
|
+
}
|
|
4127
4347
|
}
|
|
4128
4348
|
|
|
4129
4349
|
state.meta = state.meta || {};
|
|
@@ -4135,7 +4355,7 @@ async function finishWithResponseOnlyModelTurn({ client, config, state, store, o
|
|
|
4135
4355
|
state.stepsCompleted = 1;
|
|
4136
4356
|
state.updatedAt = state.meta.responseOnly.completedAt;
|
|
4137
4357
|
state.messages.push(preserveAssistantMessage({
|
|
4138
|
-
...
|
|
4358
|
+
...finalAssistantMessage,
|
|
4139
4359
|
role: "assistant",
|
|
4140
4360
|
content: result,
|
|
4141
4361
|
tool_calls: undefined,
|
package/src/model-client.js
CHANGED
|
@@ -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
|
];
|
package/src/scs-evidence.js
CHANGED
|
@@ -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) {
|