mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-30 04:40:37 +00:00
Merge ACP direct-outcome simplification into DSH SDK layer
This commit is contained in:
@@ -379,16 +379,22 @@ export async function startAcpRun(request: SubagentStartRequest, spec: AcpRunSpe
|
||||
|
||||
const observeProcessOutcome = async (signal?: AbortSignal): Promise<SubprocessOutcome | undefined> => {
|
||||
if (processOutcome !== undefined || child.pid <= 0) return processOutcome
|
||||
const timeout = AbortSignal.timeout(Math.ceil(spec.disposeGraceMs))
|
||||
const bound = signal === undefined ? timeout : AbortSignal.any([signal, timeout])
|
||||
const aborted = Promise.withResolvers<undefined>()
|
||||
const onObservationAbort = (): void => { aborted.resolve(undefined) }
|
||||
bound.addEventListener('abort', onObservationAbort, { once: true })
|
||||
/* v8 ignore next -- closes the event-loop race between listener registration and the preceding derived-signal check. */
|
||||
if (bound.aborted) onObservationAbort()
|
||||
try {
|
||||
const timeout = AbortSignal.timeout(Math.ceil(spec.disposeGraceMs))
|
||||
const exited = await child.waitForExit(
|
||||
signal === undefined ? timeout : AbortSignal.any([signal, timeout]),
|
||||
)
|
||||
if (exited) return await processDone
|
||||
return await Promise.race([processDone, aborted.promise])
|
||||
} catch {
|
||||
// The active protocol failure remains authoritative when exit observation fails.
|
||||
/* v8 ignore next -- a published child.done cannot reject; spawn rejection is consumed before publication. */
|
||||
return processOutcome
|
||||
} finally {
|
||||
bound.removeEventListener('abort', onObservationAbort)
|
||||
}
|
||||
return processOutcome
|
||||
}
|
||||
|
||||
// Startup rollback and the published handle share one process teardown.
|
||||
|
||||
@@ -959,7 +959,8 @@ describe('dsh-subagent-acp', () => {
|
||||
|
||||
it('lets local cancellation interrupt prompt-failure process observation', async () => {
|
||||
const controller = new AbortController()
|
||||
const observing = Promise.withResolvers<undefined>()
|
||||
const protocolEnded = Promise.withResolvers<undefined>()
|
||||
let boundedExitWaits = 0
|
||||
const run = await startAcpRun(request('p', controller.signal), {
|
||||
command: process.execPath,
|
||||
args: [mockServer],
|
||||
@@ -968,9 +969,14 @@ describe('dsh-subagent-acp', () => {
|
||||
env: { MOCK_CLOSE_PROTOCOL_ON_PROMPT: '1' },
|
||||
disposeEofGraceMs: 100,
|
||||
disposeGraceMs: 5000,
|
||||
spawn: spec => tapBoundedExitWait(spawnSubprocess(spec), () => { observing.resolve(undefined) }),
|
||||
spawn: (spec) => {
|
||||
const child = spawnSubprocess(spec)
|
||||
child.stdout?.once('end', () => { protocolEnded.resolve(undefined) })
|
||||
return tapBoundedExitWait(child, () => { boundedExitWaits += 1 })
|
||||
},
|
||||
})
|
||||
await observing.promise
|
||||
await protocolEnded.promise
|
||||
await new Promise<void>((resolve) => { setImmediate(resolve) })
|
||||
controller.abort()
|
||||
await expect(Promise.race([
|
||||
run.result,
|
||||
@@ -978,6 +984,7 @@ describe('dsh-subagent-acp', () => {
|
||||
setTimeout(() => { reject(new Error('cancellation waited for process observation')) }, 500)
|
||||
}),
|
||||
])).resolves.toEqual({ output: [], stopReason: 'aborted' })
|
||||
expect(boundedExitWaits).toBe(0)
|
||||
await run.dispose()
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user