Treat OpenCode abort as cancellation, not error (#1169)
OpenCode emits session.error with MessageAbortedError when the user interrupts a running turn. Paseo was mapping every session.error to turn_failed, which set the agent lifecycle to error and appended a raw JSON system error message to the timeline. Now MessageAbortedError translates to turn_canceled (same as an explicit cancel), so the agent returns to idle with no error state. Real errors still produce turn_failed.
This commit is contained in:
@@ -1691,14 +1691,7 @@ export function translateOpenCodeEvent(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "session.error":
|
case "session.error":
|
||||||
if (event.properties.sessionID === state.sessionId) {
|
appendOpenCodeSessionError(event, state, events);
|
||||||
resetOpenCodeTurnTrackingState(state);
|
|
||||||
events.push({
|
|
||||||
type: "turn_failed",
|
|
||||||
provider: "opencode",
|
|
||||||
error: toDiagnosticErrorMessage(event.properties.error),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "session.status":
|
case "session.status":
|
||||||
appendOpenCodeSessionStatus(event, state, events);
|
appendOpenCodeSessionStatus(event, state, events);
|
||||||
@@ -2294,6 +2287,36 @@ function appendOpenCodeQuestionAsked(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function appendOpenCodeSessionError(
|
||||||
|
event: Extract<OpenCodeEvent, { type: "session.error" }>,
|
||||||
|
state: OpenCodeEventTranslationState,
|
||||||
|
events: AgentStreamEvent[],
|
||||||
|
): void {
|
||||||
|
if (event.properties.sessionID !== state.sessionId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resetOpenCodeTurnTrackingState(state);
|
||||||
|
const error = event.properties.error;
|
||||||
|
if (
|
||||||
|
typeof error === "object" &&
|
||||||
|
error !== null &&
|
||||||
|
"name" in error &&
|
||||||
|
error.name === "MessageAbortedError"
|
||||||
|
) {
|
||||||
|
events.push({
|
||||||
|
type: "turn_canceled",
|
||||||
|
provider: "opencode",
|
||||||
|
reason: "interrupted",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
events.push({
|
||||||
|
type: "turn_failed",
|
||||||
|
provider: "opencode",
|
||||||
|
error: toDiagnosticErrorMessage(error),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function appendOpenCodeSessionStatus(
|
function appendOpenCodeSessionStatus(
|
||||||
event: Extract<OpenCodeEvent, { type: "session.status" }>,
|
event: Extract<OpenCodeEvent, { type: "session.status" }>,
|
||||||
state: OpenCodeEventTranslationState,
|
state: OpenCodeEventTranslationState,
|
||||||
|
|||||||
@@ -924,4 +924,52 @@ describe("translateOpenCodeEvent", () => {
|
|||||||
]);
|
]);
|
||||||
expect(second).toEqual([]);
|
expect(second).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("translates session.error with MessageAbortedError as turn_canceled, not turn_failed", () => {
|
||||||
|
const state = createState();
|
||||||
|
|
||||||
|
const events = translateOpenCodeEvent(
|
||||||
|
{
|
||||||
|
type: "session.error",
|
||||||
|
properties: {
|
||||||
|
sessionID: "session-1",
|
||||||
|
error: {
|
||||||
|
name: "MessageAbortedError",
|
||||||
|
data: { message: "aborted" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
state,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(events).toEqual([
|
||||||
|
{ type: "turn_canceled", provider: "opencode", reason: "interrupted" },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("translates session.error with a real error as turn_failed", () => {
|
||||||
|
const state = createState();
|
||||||
|
|
||||||
|
const events = translateOpenCodeEvent(
|
||||||
|
{
|
||||||
|
type: "session.error",
|
||||||
|
properties: {
|
||||||
|
sessionID: "session-1",
|
||||||
|
error: {
|
||||||
|
name: "UnknownError",
|
||||||
|
data: { message: "something broke" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
state,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(events).toEqual([
|
||||||
|
{
|
||||||
|
type: "turn_failed",
|
||||||
|
provider: "opencode",
|
||||||
|
error: '{"name":"UnknownError","data":{"message":"something broke"}}',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user