fix(acp): restore IteratorResult return type to nextSdkMessageOrAbort
The simplified SDKMessage | undefined return type collapsed two distinct states: generator truly done vs generator yielding undefined. This broke forwardSessionUpdates which needs to distinguish the two — when the generator yields null/undefined it should continue (calling next() again), not break out of the loop. Restored the original IteratorResult<SDKMessage, void> return type so done and yielded-null are distinct again.
This commit is contained in:
parent
3009a58991
commit
3a2f358d27
|
|
@ -698,7 +698,7 @@ describe('toDisplayPath', () => {
|
||||||
// ── forwardSessionUpdates ─────────────────────────────────────────
|
// ── forwardSessionUpdates ─────────────────────────────────────────
|
||||||
|
|
||||||
describe('nextSdkMessageOrAbort', () => {
|
describe('nextSdkMessageOrAbort', () => {
|
||||||
test('returns undefined when aborted while waiting for next message', async () => {
|
test('returns done:true when aborted while waiting for next message', async () => {
|
||||||
const ac = new AbortController()
|
const ac = new AbortController()
|
||||||
const pending = nextSdkMessageOrAbort(makeWaitingStream(), ac.signal)
|
const pending = nextSdkMessageOrAbort(makeWaitingStream(), ac.signal)
|
||||||
ac.abort()
|
ac.abort()
|
||||||
|
|
@ -708,19 +708,19 @@ describe('nextSdkMessageOrAbort', () => {
|
||||||
new Promise<'timeout'>(resolve => setTimeout(resolve, 100, 'timeout')),
|
new Promise<'timeout'>(resolve => setTimeout(resolve, 100, 'timeout')),
|
||||||
])
|
])
|
||||||
|
|
||||||
expect(result).toBeUndefined()
|
expect(result).toEqual({ done: true, value: undefined })
|
||||||
})
|
})
|
||||||
|
|
||||||
test('returns undefined when stream is done', async () => {
|
test('returns done:true when stream is done', async () => {
|
||||||
const result = await nextSdkMessageOrAbort(
|
const result = await nextSdkMessageOrAbort(
|
||||||
makeStream([]),
|
makeStream([]),
|
||||||
new AbortController().signal,
|
new AbortController().signal,
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(result).toBeUndefined()
|
expect(result).toEqual({ done: true, value: undefined })
|
||||||
})
|
})
|
||||||
|
|
||||||
test('returns a valid SDKMessage', async () => {
|
test('returns a valid SDKMessage via IteratorResult', async () => {
|
||||||
const msg = {
|
const msg = {
|
||||||
type: 'assistant',
|
type: 'assistant',
|
||||||
message: {
|
message: {
|
||||||
|
|
@ -734,7 +734,7 @@ describe('nextSdkMessageOrAbort', () => {
|
||||||
new AbortController().signal,
|
new AbortController().signal,
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(result).toBe(msg)
|
expect(result).toEqual({ done: false, value: msg })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -719,28 +719,22 @@ export function toolUpdateFromEditToolResponse(toolResponse: unknown): {
|
||||||
export function nextSdkMessageOrAbort(
|
export function nextSdkMessageOrAbort(
|
||||||
sdkMessages: AsyncGenerator<SDKMessage, void, unknown>,
|
sdkMessages: AsyncGenerator<SDKMessage, void, unknown>,
|
||||||
abortSignal: AbortSignal,
|
abortSignal: AbortSignal,
|
||||||
): Promise<SDKMessage | undefined> {
|
): Promise<IteratorResult<SDKMessage, void>> {
|
||||||
if (abortSignal.aborted) {
|
if (abortSignal.aborted) {
|
||||||
return Promise.resolve(undefined)
|
return Promise.resolve({ done: true, value: undefined })
|
||||||
}
|
}
|
||||||
let abortHandler: (() => void) | undefined
|
let abortHandler: (() => void) | undefined
|
||||||
const abortPromise = new Promise<undefined>(resolve => {
|
const abortPromise = new Promise<IteratorResult<SDKMessage, void>>(
|
||||||
abortHandler = () => resolve(undefined)
|
resolve => {
|
||||||
abortSignal.addEventListener('abort', abortHandler, { once: true })
|
abortHandler = () => resolve({ done: true, value: undefined })
|
||||||
|
abortSignal.addEventListener('abort', abortHandler, { once: true })
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return Promise.race([sdkMessages.next(), abortPromise]).finally(() => {
|
||||||
|
if (abortHandler) {
|
||||||
|
abortSignal.removeEventListener('abort', abortHandler)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
const nextPromise = sdkMessages.next()
|
|
||||||
return Promise.race([nextPromise, abortPromise])
|
|
||||||
.then(result => {
|
|
||||||
if (result === undefined) {
|
|
||||||
void nextPromise.catch(() => {})
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
if (result.done === true) return undefined
|
|
||||||
return result.value
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
if (abortHandler) abortSignal.removeEventListener('abort', abortHandler)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Main forwarding function ──────────────────────────────────────
|
// ── Main forwarding function ──────────────────────────────────────
|
||||||
|
|
@ -779,8 +773,10 @@ export async function forwardSessionUpdates(
|
||||||
// Race the next message against the abort signal so we unblock
|
// Race the next message against the abort signal so we unblock
|
||||||
// immediately when cancelled, even if the generator is waiting for
|
// immediately when cancelled, even if the generator is waiting for
|
||||||
// a slow API response.
|
// a slow API response.
|
||||||
const rawMsg = await nextSdkMessageOrAbort(sdkMessages, abortSignal)
|
const nextResult = await nextSdkMessageOrAbort(sdkMessages, abortSignal)
|
||||||
if (rawMsg === undefined || abortSignal.aborted) break
|
if (nextResult.done || abortSignal.aborted) break
|
||||||
|
const rawMsg = nextResult.value
|
||||||
|
if (rawMsg == null) continue
|
||||||
const msg = rawMsg as BridgeSDKMessage
|
const msg = rawMsg as BridgeSDKMessage
|
||||||
|
|
||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user