加强Goal原生协议真实验收
强制 Goal 成功计划与格式修复全程使用原生工具目录。 为 Goal 阶段等待增加 Runtime 终态快速失败。 补充正式 Provider 复验证据并关闭过期计划状态。
This commit is contained in:
@@ -7235,6 +7235,25 @@ async function readGoalStatus() {
|
||||
return goal;
|
||||
}
|
||||
|
||||
async function assertGoalRuntimeCanProgress(codePrefix) {
|
||||
const [taskSnapshot, runtime] = await Promise.all([
|
||||
readTaskSnapshot(),
|
||||
readJson(mainRuntimeStatePath()).catch(() => null),
|
||||
]);
|
||||
const current = taskSnapshot.latest.find(
|
||||
(task) => task.agentId === mainAgentId && task.runId === state.initialRunId,
|
||||
);
|
||||
if (current && isFailedTask(current)) {
|
||||
throw codedError(`${codePrefix}-runtime-failed`);
|
||||
}
|
||||
if (
|
||||
runtime?.status === 'needs-reconciliation' ||
|
||||
runtime?.phase === 'needs-reconciliation'
|
||||
) {
|
||||
throw codedError(`${codePrefix}-runtime-needs-reconciliation`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertGoalContextSnapshot(runtime, contextBundle, goal, codePrefix) {
|
||||
const expectedGoalSnapshotFingerprint = goalSnapshotFingerprint(goal);
|
||||
assert(
|
||||
@@ -7497,6 +7516,7 @@ async function waitForGoalOldActionBlocked(initialPending) {
|
||||
const deadline = Date.now() + 120_000;
|
||||
let lastError = null;
|
||||
while (Date.now() < deadline) {
|
||||
await assertGoalRuntimeCanProgress('goal-old-action-block');
|
||||
await assertGoalInitialMarkerAbsent(
|
||||
'goal-old-action-block-poll',
|
||||
initialPending.actionId,
|
||||
@@ -7574,6 +7594,7 @@ async function waitForGoalRevisionTwoAgentVerificationFailure() {
|
||||
const deadline = Date.now() + runTimeoutMs;
|
||||
let lastError = null;
|
||||
while (Date.now() < deadline) {
|
||||
await assertGoalRuntimeCanProgress('goal-revision-two-agent-failure');
|
||||
await assertGoalInitialMarkerAbsent('goal-revision-two-verify-poll');
|
||||
const records = await readOptionalJsonl(
|
||||
path.join(state.projectRoot, '.agent/agent.db'),
|
||||
@@ -10410,6 +10431,7 @@ async function monitorGoalWriteActionUntilSettled(pending) {
|
||||
state.goal.monitoredWriteActionIds.add(pending.actionId);
|
||||
const deadline = Date.now() + 120_000;
|
||||
while (Date.now() < deadline) {
|
||||
await assertGoalRuntimeCanProgress('goal-write-action-settle');
|
||||
await assertGoalInitialMarkerAbsent(
|
||||
'goal-write-after-confirm',
|
||||
pending.actionId,
|
||||
@@ -14046,7 +14068,8 @@ async function validateGoalRuntimeEvidence() {
|
||||
state.lureLeakCount = await countLureLeaks();
|
||||
assert(state.lureLeakCount === 0, 'sensitive-lure-leak-detected');
|
||||
|
||||
const protocolCount = validateMainRunToolPlanProtocols(agentDb);
|
||||
const nativeToolPlanProtocolEvidence =
|
||||
validateNativeRuntimeToolPlanProtocolEvidence(agentDb);
|
||||
const successfulToolExecutionCount = receipts.filter(
|
||||
(record) =>
|
||||
record.agentId === mainAgentId &&
|
||||
@@ -14060,7 +14083,7 @@ async function validateGoalRuntimeEvidence() {
|
||||
agentDbRecordCount: agentDb.length,
|
||||
conversationMessageCount: conversations.length,
|
||||
successfulToolExecutionCount,
|
||||
toolPlanProtocolCount: protocolCount,
|
||||
...nativeToolPlanProtocolEvidence,
|
||||
structuredPlanRevision: plan.revision,
|
||||
structuredPlanCompletedStepCount: plan.completedStepHashes.length,
|
||||
goalInitialCompletedStepCount: state.goal.initialCompletedStepHashes.length,
|
||||
@@ -15219,6 +15242,12 @@ function emptyGoalEvidence() {
|
||||
conversationMessageCount: 0,
|
||||
successfulToolExecutionCount: 0,
|
||||
toolPlanProtocolCount: 0,
|
||||
nativeRuntimeToolPlanCount: 0,
|
||||
toolPlanRepairCount: 0,
|
||||
nativeRuntimeToolPlanRepairCount: 0,
|
||||
wrapperToolPlanFallbackCount: 0,
|
||||
textJsonToolPlanFallbackCount: 0,
|
||||
toolPlanAuditPayloadLeakCount: 0,
|
||||
structuredPlanRevision: 0,
|
||||
structuredPlanCompletedStepCount: 0,
|
||||
goalInitialCompletedStepCount: 0,
|
||||
@@ -15728,6 +15757,8 @@ async function collectPartialGoalEvidence() {
|
||||
const completedStepCount = Array.isArray(runtime?.planSteps)
|
||||
? runtime.planSteps.filter((step) => step.status === 'completed').length
|
||||
: 0;
|
||||
const nativeToolPlanProtocolEvidence =
|
||||
collectNativeRuntimeToolPlanProtocolEvidence(agentDb);
|
||||
return {
|
||||
taskCount: taskSnapshot.all.length,
|
||||
eventCount: events.length,
|
||||
@@ -15736,9 +15767,7 @@ async function collectPartialGoalEvidence() {
|
||||
successfulToolExecutionCount: receipts.filter(
|
||||
(record) => record.status === 'ok',
|
||||
).length,
|
||||
toolPlanProtocolCount: agentDb.filter(
|
||||
(record) => record.recordType === 'agent.runtime.tool_plan.protocol',
|
||||
).length,
|
||||
...nativeToolPlanProtocolEvidence,
|
||||
structuredPlanRevision: runtime?.planRevision ?? 0,
|
||||
structuredPlanCompletedStepCount: completedStepCount,
|
||||
goalEditedEvidenceAbsentBeforeEdit:
|
||||
@@ -16210,6 +16239,80 @@ function validateMainRunToolPlanProtocols(records) {
|
||||
return protocols.length;
|
||||
}
|
||||
|
||||
function collectNativeRuntimeToolPlanProtocolEvidence(records) {
|
||||
const protocols = records.filter(
|
||||
(record) =>
|
||||
record.recordType === 'agent.runtime.tool_plan.protocol' &&
|
||||
record.agentId === mainAgentId &&
|
||||
record.runId === state.initialRunId,
|
||||
);
|
||||
const repairs = records.filter(
|
||||
(record) =>
|
||||
record.recordType === 'agent.runtime.tool_plan.repair' &&
|
||||
record.agentId === mainAgentId &&
|
||||
record.runId === state.initialRunId,
|
||||
);
|
||||
const audits = [...protocols, ...repairs];
|
||||
return {
|
||||
toolPlanProtocolCount: protocols.length,
|
||||
nativeRuntimeToolPlanCount: protocols.filter(
|
||||
(record) => record.protocol === 'native_runtime_tools',
|
||||
).length,
|
||||
toolPlanRepairCount: repairs.length,
|
||||
nativeRuntimeToolPlanRepairCount: repairs.filter(
|
||||
(record) => record.protocol === 'native_runtime_tools',
|
||||
).length,
|
||||
wrapperToolPlanFallbackCount: audits.filter(
|
||||
(record) => record.protocol === 'native_function',
|
||||
).length,
|
||||
textJsonToolPlanFallbackCount: audits.filter(
|
||||
(record) => record.protocol === 'text_json',
|
||||
).length,
|
||||
toolPlanAuditPayloadLeakCount: audits.filter(
|
||||
(record) =>
|
||||
Object.hasOwn(record, 'arguments') ||
|
||||
Object.hasOwn(record, 'response') ||
|
||||
Object.hasOwn(record, 'toolArguments'),
|
||||
).length,
|
||||
};
|
||||
}
|
||||
|
||||
function validateNativeRuntimeToolPlanProtocolEvidence(records) {
|
||||
const protocolCount = validateMainRunToolPlanProtocols(records);
|
||||
const evidence = collectNativeRuntimeToolPlanProtocolEvidence(records);
|
||||
const protocols = records.filter(
|
||||
(record) =>
|
||||
record.recordType === 'agent.runtime.tool_plan.protocol' &&
|
||||
record.agentId === mainAgentId &&
|
||||
record.runId === state.initialRunId,
|
||||
);
|
||||
assert(
|
||||
evidence.toolPlanProtocolCount === protocolCount &&
|
||||
evidence.nativeRuntimeToolPlanCount === protocolCount &&
|
||||
evidence.nativeRuntimeToolPlanRepairCount ===
|
||||
evidence.toolPlanRepairCount &&
|
||||
evidence.wrapperToolPlanFallbackCount === 0 &&
|
||||
evidence.textJsonToolPlanFallbackCount === 0 &&
|
||||
evidence.toolPlanAuditPayloadLeakCount === 0 &&
|
||||
protocols.every(
|
||||
(record) =>
|
||||
Number.isSafeInteger(record.functionCallCount) &&
|
||||
record.functionCallCount > 0 &&
|
||||
Array.isArray(record.callIds) &&
|
||||
record.callIds.length === record.functionCallCount &&
|
||||
new Set(record.callIds).size === record.callIds.length &&
|
||||
Array.isArray(record.functionNames) &&
|
||||
record.functionNames.length === record.functionCallCount &&
|
||||
record.functionNames.every(
|
||||
(name) =>
|
||||
isNonEmptyString(name) && name !== 'submit_agent_tool_plan',
|
||||
),
|
||||
),
|
||||
'goal-native-tool-plan-protocol-required',
|
||||
);
|
||||
return evidence;
|
||||
}
|
||||
|
||||
async function validateSameRunSteerEvidence({
|
||||
agentDb,
|
||||
activity,
|
||||
|
||||
Reference in New Issue
Block a user