fix(llm): honor DeepSeek SSE keep-alives

This commit is contained in:
fz
2026-08-04 11:48:34 +08:00
parent 804b724202
commit cd6bd5c188
17 changed files with 134 additions and 35 deletions

View File

@@ -545,6 +545,40 @@ describe('DeepSeekAdapter against a mock server', () => {
fetchSpy.mockRestore()
}
})
it('keeps an idle provider read alive through SSE comments', async () => {
vi.useFakeTimers()
const encoder = new TextEncoder()
const fetchSpy = vi.spyOn(globalThis, 'fetch').mockImplementation(() => {
const body = new ReadableStream<Uint8Array>({
start(controller) {
setTimeout(() => { controller.enqueue(encoder.encode(': keep-alive\n\n')) }, 75)
setTimeout(() => { controller.enqueue(encoder.encode(': keep-alive\n\n')) }, 150)
setTimeout(() => {
controller.enqueue(encoder.encode(textEvents.map(event => `data: ${event}\n\n`).join('')))
controller.close()
}, 225)
},
})
return Promise.resolve(new Response(body, { status: 200 }))
})
const adapter = adapterOf({ baseURL: 'https://example.invalid', streamIdleTimeoutMs: 100 })
try {
const chunks: string[] = []
const drain = (async () => {
for await (const chunk of adapter.stream({ provider: 'deepseek-official', model: 'm', messages: [] })) {
chunks.push(chunk.type)
}
})()
await vi.advanceTimersByTimeAsync(75)
await vi.advanceTimersByTimeAsync(75)
await vi.advanceTimersByTimeAsync(75)
await expect(drain).resolves.toBeUndefined()
expect(chunks).toEqual(['block-start', 'text-delta', 'block-end', 'usage', 'finish'])
} finally {
fetchSpy.mockRestore()
}
})
})
describe('plugin registration and config', () => {

View File

@@ -31,6 +31,16 @@ describe('parseSse', () => {
expect(events).toEqual(['{"a":1}', DONE])
})
it('reports comments out of band without yielding them', async () => {
const comments: string[] = []
const events = await collect(parseSse(
bytes(': keep-alive\n\ndata: {"a":1}\n\ndata: [DONE]\n\n'),
(comment) => { comments.push(comment) },
))
expect(comments).toEqual(['keep-alive'])
expect(events).toEqual(['{"a":1}', DONE])
})
it('stops yielding after DONE even when more data follows', async () => {
const events = await collect(parseSse(bytes('data: [DONE]\n\ndata: {"late":1}\n\n')))
expect(events).toEqual([DONE])