fix(cli): handle session.error in run command to prevent infinite wait
When session.error occurs with incomplete todos, the run command now: - Captures the error via handleSessionError() - Exits with code 1 instead of waiting indefinitely - Shows clear error message to user Previously, run command ignored session.error events, causing infinite 'Waiting: N todos remaining' loop when agent errors occurred. 🤖 Generated with assistance of OhMyOpenCode https://github.com/code-yeongyu/oh-my-opencode
This commit is contained in:
@@ -74,6 +74,8 @@ describe("event handling", () => {
|
|||||||
const ctx = createMockContext("my-session")
|
const ctx = createMockContext("my-session")
|
||||||
const state: EventState = {
|
const state: EventState = {
|
||||||
mainSessionIdle: true,
|
mainSessionIdle: true,
|
||||||
|
mainSessionError: false,
|
||||||
|
lastError: null,
|
||||||
lastOutput: "",
|
lastOutput: "",
|
||||||
lastPartText: "",
|
lastPartText: "",
|
||||||
currentTool: null,
|
currentTool: null,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type {
|
|||||||
EventPayload,
|
EventPayload,
|
||||||
SessionIdleProps,
|
SessionIdleProps,
|
||||||
SessionStatusProps,
|
SessionStatusProps,
|
||||||
|
SessionErrorProps,
|
||||||
MessageUpdatedProps,
|
MessageUpdatedProps,
|
||||||
MessagePartUpdatedProps,
|
MessagePartUpdatedProps,
|
||||||
ToolExecuteProps,
|
ToolExecuteProps,
|
||||||
@@ -12,6 +13,8 @@ import type {
|
|||||||
|
|
||||||
export interface EventState {
|
export interface EventState {
|
||||||
mainSessionIdle: boolean
|
mainSessionIdle: boolean
|
||||||
|
mainSessionError: boolean
|
||||||
|
lastError: string | null
|
||||||
lastOutput: string
|
lastOutput: string
|
||||||
lastPartText: string
|
lastPartText: string
|
||||||
currentTool: string | null
|
currentTool: string | null
|
||||||
@@ -20,6 +23,8 @@ export interface EventState {
|
|||||||
export function createEventState(): EventState {
|
export function createEventState(): EventState {
|
||||||
return {
|
return {
|
||||||
mainSessionIdle: false,
|
mainSessionIdle: false,
|
||||||
|
mainSessionError: false,
|
||||||
|
lastError: null,
|
||||||
lastOutput: "",
|
lastOutput: "",
|
||||||
lastPartText: "",
|
lastPartText: "",
|
||||||
currentTool: null,
|
currentTool: null,
|
||||||
@@ -43,6 +48,7 @@ export async function processEvents(
|
|||||||
|
|
||||||
logEventVerbose(ctx, payload)
|
logEventVerbose(ctx, payload)
|
||||||
|
|
||||||
|
handleSessionError(ctx, payload, state)
|
||||||
handleSessionIdle(ctx, payload, state)
|
handleSessionIdle(ctx, payload, state)
|
||||||
handleSessionStatus(ctx, payload, state)
|
handleSessionStatus(ctx, payload, state)
|
||||||
handleMessagePartUpdated(ctx, payload, state)
|
handleMessagePartUpdated(ctx, payload, state)
|
||||||
@@ -154,6 +160,23 @@ function handleSessionStatus(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSessionError(
|
||||||
|
ctx: RunContext,
|
||||||
|
payload: EventPayload,
|
||||||
|
state: EventState
|
||||||
|
): void {
|
||||||
|
if (payload.type !== "session.error") return
|
||||||
|
|
||||||
|
const props = payload.properties as SessionErrorProps | undefined
|
||||||
|
if (props?.sessionID === ctx.sessionID) {
|
||||||
|
state.mainSessionError = true
|
||||||
|
state.lastError = props?.error
|
||||||
|
? String(props.error instanceof Error ? props.error.message : props.error)
|
||||||
|
: "Unknown error"
|
||||||
|
console.error(pc.red(`\n[session.error] ${state.lastError}`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleMessagePartUpdated(
|
function handleMessagePartUpdated(
|
||||||
ctx: RunContext,
|
ctx: RunContext,
|
||||||
payload: EventPayload,
|
payload: EventPayload,
|
||||||
|
|||||||
@@ -87,6 +87,16 @@ export async function run(options: RunOptions): Promise<number> {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if session errored - exit with failure if so
|
||||||
|
if (eventState.mainSessionError) {
|
||||||
|
console.error(pc.red(`\n\nSession ended with error: ${eventState.lastError}`))
|
||||||
|
console.error(pc.yellow("Check if todos were completed before the error."))
|
||||||
|
abortController.abort()
|
||||||
|
await eventProcessor.catch(() => {})
|
||||||
|
cleanup()
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
const shouldExit = await checkCompletionConditions(ctx)
|
const shouldExit = await checkCompletionConditions(ctx)
|
||||||
if (shouldExit) {
|
if (shouldExit) {
|
||||||
console.log(pc.green("\n\nAll tasks completed."))
|
console.log(pc.green("\n\nAll tasks completed."))
|
||||||
|
|||||||
@@ -69,3 +69,8 @@ export interface ToolResultProps {
|
|||||||
name?: string
|
name?: string
|
||||||
output?: string
|
output?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SessionErrorProps {
|
||||||
|
sessionID?: string
|
||||||
|
error?: unknown
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user