fix: recover Workbench terminal outbox projection
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-19-p1-agentrun-incremental-cursor; PJ2026-010205 HWLAB接入 draft-2026-06-17-r0; PJ2026-01060505 Workbench Performance draft-2026-06-17-p0.
|
||||
// SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-19-p1-agentrun-incremental-cursor; draft-2026-06-20-p2-terminal-outbox-recovery; PJ2026-010205 HWLAB接入 draft-2026-06-17-r0; PJ2026-01060505 Workbench Performance draft-2026-06-17-p0.
|
||||
// Responsibility: AgentRun v0.1 adapter, incremental Workbench projection cursor sync, and upstream timing projection for Cloud API observability.
|
||||
|
||||
import { createHash, randomUUID } from "node:crypto";
|
||||
@@ -737,6 +737,33 @@ export async function refreshAgentRunTrace({ traceId, result = null, options = {
|
||||
export async function cancelAgentRunChatTurn({ traceId, currentResult = null, options = {}, traceStore = defaultCodeAgentTraceStore }) {
|
||||
const mapped = currentResult ?? await loadPersistedAgentRunResult(traceId, options);
|
||||
if (!mapped?.agentRun?.commandId) return null;
|
||||
const localTerminal = agentRunCancelTerminalStatus(mapped);
|
||||
if (localTerminal) return agentRunAlreadyTerminalCancelPayload({ traceId, payload: mapped, terminalStatus: localTerminal, options, traceStore });
|
||||
try {
|
||||
const guard = await syncAgentRunChatResult({
|
||||
traceId,
|
||||
currentResult: mapped,
|
||||
options: { ...options, deferAgentRunResultSync: false },
|
||||
traceStore,
|
||||
forceResultSync: true,
|
||||
refreshEvents: true
|
||||
});
|
||||
const guarded = guard?.result ?? null;
|
||||
const guardedTerminal = agentRunCancelTerminalStatus(guarded);
|
||||
if (guardedTerminal) return agentRunAlreadyTerminalCancelPayload({ traceId, payload: guarded, terminalStatus: guardedTerminal, options, traceStore });
|
||||
} catch (error) {
|
||||
traceStore.append(traceId, agentRunTraceEvent({
|
||||
type: "cancel",
|
||||
status: "running",
|
||||
label: "agentrun:cancel:terminal_guard_failed",
|
||||
errorCode: error?.code ?? "agentrun_cancel_terminal_guard_failed",
|
||||
message: "HWLAB could not confirm AgentRun terminal state before forwarding cancel; continuing with cancel because no terminal authority was observed.",
|
||||
runId: mapped.agentRun.runId,
|
||||
commandId: mapped.agentRun.commandId,
|
||||
waitingFor: "cancel-terminal-guard",
|
||||
valuesPrinted: false
|
||||
}, mapped.agentRun));
|
||||
}
|
||||
const env = options.env ?? process.env;
|
||||
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
||||
const managerUrl = resolveAgentRunManagerUrl(env, mapped.agentRun.managerUrl);
|
||||
@@ -783,6 +810,45 @@ export async function cancelAgentRunChatTurn({ traceId, currentResult = null, op
|
||||
return payload;
|
||||
}
|
||||
|
||||
function agentRunCancelTerminalStatus(payload = null) {
|
||||
if (!payload || typeof payload !== "object") return null;
|
||||
for (const value of [payload.status, payload.agentRun?.terminalStatus, payload.agentRun?.commandState, payload.agentRun?.status, payload.agentRun?.runStatus]) {
|
||||
const status = normalizeAgentRunStatus(value);
|
||||
if (isAgentRunTerminalStatus(status)) return status;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function agentRunAlreadyTerminalCancelPayload({ traceId, payload, terminalStatus, options = {}, traceStore = defaultCodeAgentTraceStore } = {}) {
|
||||
const normalizedTerminalStatus = normalizeAgentRunStatus(terminalStatus);
|
||||
const agentRun = payload?.agentRun && typeof payload.agentRun === "object" ? payload.agentRun : {};
|
||||
traceStore.append(traceId, agentRunTraceEvent({
|
||||
type: "cancel",
|
||||
status: normalizedTerminalStatus || "completed",
|
||||
label: "agentrun:cancel:already_terminal",
|
||||
message: "AgentRun command is already terminal; HWLAB did not forward cancel or overwrite the terminal Workbench projection.",
|
||||
runId: agentRun.runId,
|
||||
commandId: agentRun.commandId,
|
||||
terminal: true,
|
||||
valuesPrinted: false
|
||||
}, agentRun));
|
||||
const payloadStatus = normalizeAgentRunStatus(payload?.status);
|
||||
const status = isAgentRunTerminalStatus(payloadStatus) ? payloadStatus : normalizedTerminalStatus || payloadStatus || "completed";
|
||||
const result = {
|
||||
...payload,
|
||||
status,
|
||||
canceled: false,
|
||||
alreadyTerminal: true,
|
||||
cancelStatus: "already_terminal",
|
||||
updatedAt: nowIso(options.now),
|
||||
runnerTrace: traceStore.snapshot(traceId),
|
||||
agentRun: { ...agentRun, terminalStatus: agentRun.terminalStatus ?? normalizedTerminalStatus, valuesPrinted: false },
|
||||
valuesPrinted: false
|
||||
};
|
||||
options.codeAgentChatResults?.set?.(traceId, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function steerAgentRunChatTurn({ traceId, currentResult = null, params = {}, options = {}, traceStore = defaultCodeAgentTraceStore }) {
|
||||
const mapped = currentResult ?? await loadPersistedAgentRunResult(traceId, options);
|
||||
if (!safeTraceId(traceId) || !mapped?.agentRun?.runId || !mapped?.agentRun?.commandId) return null;
|
||||
|
||||
Reference in New Issue
Block a user