Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/main/runtime/orca-runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6989,6 +6989,30 @@ describe('OrcaRuntimeService', () => {
}
})

it('marks a direct dispatch failed when its worker PTY exits', () => {
const runtime = createRuntime()
const workerHandle = runtime.preAllocateHandleForPty('pty-1')
const failDispatch = vi.fn()
const updateTaskStatus = vi.fn()
const insertMessage = vi.fn()
runtime.setOrchestrationDb({
getActiveDispatchForTerminal: vi.fn((handle: string) =>
handle === workerHandle ? { id: 'ctx-1', task_id: 'task-1' } : undefined
),
failDispatch,
getActiveCoordinatorRun: vi.fn(() => undefined),
updateTaskStatus,
insertMessage
} as never)
syncSinglePty(runtime)

runtime.onPtyExit('pty-1', -1)

expect(failDispatch).toHaveBeenCalledWith('ctx-1', 'Agent exited with code -1')
expect(updateTaskStatus).toHaveBeenCalledWith('task-1', 'failed', 'Agent exited with code -1')
expect(insertMessage).not.toHaveBeenCalled()
})

it('keeps stale-title timers isolated per PTY', async () => {
vi.useFakeTimers()
try {
Expand Down
31 changes: 18 additions & 13 deletions src/main/runtime/orca-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10308,20 +10308,25 @@ export class OrcaRuntimeService {
// the unexpected exit on its next check cycle, even if the circuit breaker
// hasn't tripped yet.
const run = this._orchestrationDb.getActiveCoordinatorRun()
if (run) {
this._orchestrationDb.insertMessage({
from: handle,
to: run.coordinator_handle,
subject: `Agent exited unexpectedly (code ${exitCode})`,
type: 'escalation',
priority: 'high',
payload: JSON.stringify({
taskId: dispatch.task_id,
exitCode,
handle
})
})
if (!run) {
// Why: a direct dispatch has no coordinator loop to consume the ready
// retry. Mark it failed so an exited agent cannot silently lose the task.
this._orchestrationDb.updateTaskStatus(dispatch.task_id, 'failed', errorContext)
return
}

this._orchestrationDb.insertMessage({
from: handle,
to: run.coordinator_handle,
subject: `Agent exited unexpectedly (code ${exitCode})`,
type: 'escalation',
priority: 'high',
payload: JSON.stringify({
taskId: dispatch.task_id,
exitCode,
handle
})
})
}

async listTerminals(
Expand Down
Loading