fix(runtime): handle unavailable foreground probes

This commit is contained in:
Brennan Benson
2026-08-05 00:42:10 -07:00
parent a9466f0c18
commit aa5032f727
2 changed files with 49 additions and 6 deletions
+21
View File
@@ -8889,6 +8889,27 @@ describe('OrcaRuntimeService', () => {
)
})
it('treats synchronous foreground read failures as unavailable', async () => {
const { runtime, batches } = createSideEffectRuntime()
syncSinglePty(runtime)
runtime.ingestSyntheticTitleFrame('pty-1', '\x1b]0;Codex ready\x07')
const getForegroundProcess = vi.fn(() => {
throw new TypeError('getForegroundProcess is unavailable')
})
runtime.setPtyController({
write: () => true,
kill: () => true,
getForegroundProcess
})
runtime.onPtyData('pty-1', '\x1b]0;bichir\x07', 100)
await vi.waitFor(() =>
expect(batches.flatMap((batch) => batch.facts)).toContainEqual({ kind: 'agent-exited' })
)
expect(getForegroundProcess).toHaveBeenCalledOnce()
})
it('aligns a restored session and pre-response bytes to the provider sequence', async () => {
const { runtime } = createSideEffectRuntime()
+28 -6
View File
@@ -16610,20 +16610,42 @@ export class OrcaRuntimeService {
}
)
}
const entry: PtyForegroundProcessReadEntry = {
const unavailable: PtyForegroundProcessRead = {
controller,
startedAfterTitleObservation: afterTitleObservation,
promise: Promise.resolve({ controller, process: null, available: false })
process: null,
available: false
}
entry.promise = controller
.getForegroundProcess(ptyId)
let processRead: Promise<string | null>
try {
processRead = Promise.resolve(controller.getForegroundProcess(ptyId))
} catch {
const entry: PtyForegroundProcessReadEntry = {
controller,
startedAfterTitleObservation: afterTitleObservation,
promise: Promise.resolve(unavailable)
}
entry.promise = entry.promise.finally(() => {
if (this.ptyForegroundProcessReads.get(ptyId) === entry) {
this.ptyForegroundProcessReads.delete(ptyId)
}
})
this.ptyForegroundProcessReads.set(ptyId, entry)
return entry.promise
}
let entry: PtyForegroundProcessReadEntry
const promise = processRead
.then((process) => ({ controller, process, available: true }))
.catch(() => ({ controller, process: null, available: false }))
.catch(() => unavailable)
.finally(() => {
if (this.ptyForegroundProcessReads.get(ptyId) === entry) {
this.ptyForegroundProcessReads.delete(ptyId)
}
})
entry = {
controller,
startedAfterTitleObservation: afterTitleObservation,
promise
}
this.ptyForegroundProcessReads.set(ptyId, entry)
return entry.promise
}