fix: enforce workbench terminal seal invariant

This commit is contained in:
UniDesk Codex
2026-07-01 19:41:49 +08:00
parent 9fc4671478
commit 19ea9d0962
15 changed files with 531 additions and 58 deletions
+40 -4
View File
@@ -2598,7 +2598,7 @@ async function getCodeAgentSessionByTraceId(traceId, options = {}) {
return await options.accessController.getAgentSessionByTraceId(safeId);
}
function codeAgentTurnStatusPayload({ traceId, result, snapshot, resultPollError, refreshError, options }) {
export function codeAgentTurnStatusPayload({ traceId, result, snapshot, resultPollError, refreshError, options }) {
const resultObject = result && typeof result === "object" ? result : null;
const snapshotObject = snapshot && typeof snapshot === "object" ? snapshot : null;
const lifecycle = codeAgentTurnLifecycleFields(traceId, resultObject ?? snapshotObject ?? {});
@@ -2606,7 +2606,8 @@ function codeAgentTurnStatusPayload({ traceId, result, snapshot, resultPollError
const lastEvent = events.at(-1) ?? null;
const finalResponse = resultObject?.finalResponse ?? snapshotObject?.finalResponse ?? snapshotObject?.terminalEvidence?.finalResponse ?? codeAgentFinalResponseEvidence(resultObject ?? snapshotObject ?? {}, traceId);
const terminalStatus = codeAgentAuthoritativeTerminalStatus(resultObject, snapshotObject, traceId);
const status = normalizeTurnStatus(
const terminalSealBlocked = terminalStatus === "completed" && !codeAgentCompletedTurnFinalText(finalResponse, resultObject, snapshotObject);
const rawStatus = normalizeTurnStatus(
terminalStatus,
resultObject?.agentRun?.commandState,
resultObject?.agentRun?.status,
@@ -2618,6 +2619,7 @@ function codeAgentTurnStatusPayload({ traceId, result, snapshot, resultPollError
resultObject?.agentRun?.terminalStatus,
snapshotObject?.terminalEvidence?.traceSummary?.terminalStatus
);
const status = terminalSealBlocked ? "running" : rawStatus;
const found = Boolean(resultObject || (snapshotObject && snapshotObject.status !== "missing") || snapshotObject?.persisted === true);
const running = isTurnRunningStatus(status);
const terminal = isTurnTerminalStatus(status);
@@ -2638,7 +2640,10 @@ function codeAgentTurnStatusPayload({ traceId, result, snapshot, resultPollError
updatedAt: textValue(resultObject?.updatedAt ?? resultObject?.agentRun?.updatedAt ?? snapshotObject?.updatedAt ?? timingFields.lastEventAt ?? timingFields.startedAt) || null,
...timingFields,
lastEventLabel: textValue(snapshotObject?.lastEventLabel ?? runnerTrace?.lastEventLabel ?? lastEvent?.label ?? lastEvent?.type) || null,
waitingFor: textValue(snapshotObject?.waitingFor ?? runnerTrace?.waitingFor) || null,
waitingFor: terminalSealBlocked ? "final_response" : textValue(snapshotObject?.waitingFor ?? runnerTrace?.waitingFor) || null,
terminalObserved: Boolean(terminalStatus),
terminalObservedStatus: terminalStatus ?? null,
terminalSealBlocked,
resultUrl: `/v1/agent/chat/result/${encodeURIComponent(traceId)}`,
traceUrl: `/v1/agent/traces/${encodeURIComponent(traceId)}`,
turnUrl: `/v1/agent/turns/${encodeURIComponent(traceId)}`,
@@ -2657,6 +2662,21 @@ function codeAgentTurnStatusPayload({ traceId, result, snapshot, resultPollError
};
}
function codeAgentCompletedTurnFinalText(finalResponse = null, resultObject = null, snapshotObject = null) {
const candidates = [
finalResponse,
resultObject?.finalResponse,
snapshotObject?.finalResponse,
snapshotObject?.terminalEvidence?.finalResponse,
resultObject?.terminalEvidence?.finalResponse
];
for (const value of candidates) {
const text = conversationText(value);
if (text) return text;
}
return codeAgentFinalResponseText(resultObject ?? {}) || codeAgentFinalResponseText(snapshotObject ?? {});
}
function codeAgentAuthoritativeTerminalStatus(resultObject, snapshotObject, traceId) {
const sealedPayload = codeAgentPayloadHasSealedFinalResponse(resultObject ?? {}) ? resultObject : codeAgentPayloadHasSealedFinalResponse(snapshotObject ?? {}) ? snapshotObject : null;
if (sealedPayload) return "completed";
@@ -3971,7 +3991,23 @@ function codeAgentFinalResponseEvidence(payload = {}, traceId = null) {
}
function codeAgentFinalResponseText(payload = {}) {
return conversationText(payload?.finalResponse?.text ?? payload?.finalResponse?.content ?? payload?.reply?.content ?? payload?.message?.content ?? payload?.assistantText);
for (const value of [
payload?.finalResponse?.text,
payload?.finalResponse?.content,
payload?.finalResponse,
payload?.reply?.content,
payload?.reply,
payload?.message?.content,
payload?.message,
payload?.assistantText,
payload?.finalText,
payload?.text,
payload?.content
]) {
const text = conversationText(value);
if (text) return text;
}
return "";
}
function codeAgentTraceSummaryEvidence(payload = {}, traceId = null, finalResponse = null) {