fix: preserve sealed AgentRun cancel result (#2095)
This commit is contained in:
@@ -706,7 +706,15 @@ function isAgentRunCommandAlreadyClaimed(error) {
|
||||
|
||||
export async function syncAgentRunChatResult({ traceId, currentResult = null, options = {}, traceStore = defaultCodeAgentTraceStore, appendResultEvent = true, refreshEvents = true, forceResultSync = false }) {
|
||||
const initial = currentResult ?? await loadPersistedAgentRunResult(traceId, options);
|
||||
if (isAgentRunUserCancelSealed(initial)) {
|
||||
const runnerTrace = initial.runnerTrace ?? traceStore.snapshot(traceId);
|
||||
return { result: initial, runnerTrace, found: true, eventsRefreshed: false, resultSynced: false, terminalRefreshSkipped: true, localCancelSealed: true };
|
||||
}
|
||||
const mapped = initial ? await resolveAgentRunTraceCommandMapping({ traceId, mapped: initial, options }) : initial;
|
||||
if (isAgentRunUserCancelSealed(mapped)) {
|
||||
const runnerTrace = mapped.runnerTrace ?? traceStore.snapshot(traceId);
|
||||
return { result: mapped, runnerTrace, found: true, eventsRefreshed: false, resultSynced: false, terminalRefreshSkipped: true, localCancelSealed: true };
|
||||
}
|
||||
const performanceStore = options.backendPerformanceStore ?? currentBackendPerformanceContext();
|
||||
if (!forceResultSync && options.skipAgentRunTerminalRefreshIfComplete === true && agentRunTerminalResultRefreshSatisfied(mapped, traceId)) {
|
||||
const runnerTrace = mapped.runnerTrace ?? traceStore.snapshot(traceId);
|
||||
@@ -882,6 +890,14 @@ function normalizeAgentRunStatus(value) {
|
||||
return status === "cancelled" ? "canceled" : status;
|
||||
}
|
||||
|
||||
function isAgentRunUserCancelSealed(payload = null) {
|
||||
if (!payload || typeof payload !== "object") return false;
|
||||
const status = normalizeAgentRunStatus(payload.status);
|
||||
const cancelStatus = normalizeAgentRunStatus(payload.cancelStatus ?? payload.cancelDisposition?.status);
|
||||
const terminalStatus = normalizeAgentRunStatus(payload.agentRun?.terminalStatus ?? payload.agentRun?.commandState ?? payload.agentRun?.status);
|
||||
return payload.canceled === true || status === "canceled" || cancelStatus === "canceled" || terminalStatus === "canceled";
|
||||
}
|
||||
|
||||
async function resolveAgentRunTraceCommandMapping({ traceId, mapped, options = {} }) {
|
||||
const safeId = safeTraceId(traceId);
|
||||
const agentRun = mapped?.agentRun && typeof mapped.agentRun === "object" ? mapped.agentRun : null;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "bun:test";
|
||||
|
||||
import { cancelAgentRunChatTurn } from "./code-agent-agentrun-adapter.ts";
|
||||
import { cancelAgentRunChatTurn, syncAgentRunChatResult } from "./code-agent-agentrun-adapter.ts";
|
||||
import { createCodeAgentTraceStore } from "./code-agent-trace-store.ts";
|
||||
|
||||
test("AgentRun cancel downstream failure returns visible blocked disposition instead of throwing", async () => {
|
||||
@@ -54,3 +54,44 @@ test("AgentRun cancel downstream failure returns visible blocked disposition ins
|
||||
assert.equal(codeAgentChatResults.get(traceId)?.cancelDisposition?.code, "command_not_cancelable");
|
||||
assert.ok(traceStore.snapshot(traceId).events.some((event) => event.label === "agentrun:cancel:blocked" && event.status === "blocked"));
|
||||
});
|
||||
|
||||
test("AgentRun result sync preserves a user-canceled payload instead of accepting late completed result", async () => {
|
||||
const traceId = "trc_cancel_sealed_result";
|
||||
const traceStore = createCodeAgentTraceStore();
|
||||
const currentResult = {
|
||||
traceId,
|
||||
status: "canceled",
|
||||
canceled: true,
|
||||
cancelStatus: "canceled",
|
||||
cancelDisposition: { status: "canceled", forwarded: true, terminal: true, traceId, valuesPrinted: false },
|
||||
finalResponse: { text: "hwlab-user-cancel", status: "canceled", traceId, valuesPrinted: false },
|
||||
agentRun: {
|
||||
runId: "run_cancel_sealed_result",
|
||||
commandId: "cmd_cancel_sealed_result",
|
||||
managerUrl: "http://127.0.0.1:65535",
|
||||
status: "cancelled",
|
||||
commandState: "cancelled",
|
||||
terminalStatus: "cancelled",
|
||||
traceId,
|
||||
valuesPrinted: false
|
||||
},
|
||||
valuesPrinted: false
|
||||
};
|
||||
|
||||
const synced = await syncAgentRunChatResult({
|
||||
traceId,
|
||||
currentResult,
|
||||
traceStore,
|
||||
options: {
|
||||
env: { HWLAB_CODE_AGENT_AGENTRUN_ALLOW_NON_K3S_URL: "1" },
|
||||
fetchImpl() {
|
||||
throw new Error("late AgentRun result must not be fetched after HWLAB user cancel is sealed");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
assert.equal(synced.localCancelSealed, true);
|
||||
assert.equal(synced.resultSynced, false);
|
||||
assert.equal(synced.result.status, "canceled");
|
||||
assert.equal(synced.result.finalResponse.text, "hwlab-user-cancel");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user