fix: preserve transport cause diagnostics

This commit is contained in:
Tianyi Cui
2026-07-20 21:03:31 +08:00
parent 8c12f8945e
commit ad021067e0
2 changed files with 10 additions and 8 deletions

View File

@@ -57,10 +57,6 @@ function requestId(headers: Headers): ReturnType<typeof ProviderRequestId> | und
return value === null || value.length === 0 ? undefined : ProviderRequestId(value)
}
function errorMessage(value: unknown): string {
return value instanceof Error ? value.message : String(value)
}
/**
* Map an HTTP status to a stable LlmError code.
* @param status - status of a non-2xx provider response.
@@ -144,7 +140,7 @@ export class DeepSeekAdapter extends LlmAdapter {
throw new LlmError('DeepSeek request aborted by caller', 'ABORTED', { cause: error })
}
if (error instanceof LlmError) throw error
throw new LlmError(`DeepSeek transport failed: ${errorMessage(error)}`, 'TRANSPORT', { cause: error })
throw new LlmError(`DeepSeek API stream from ${this.options.baseURL} failed`, 'TRANSPORT', { cause: error })
} finally {
consumer.abort('DeepSeek stream consumer stopped')
if (!exhausted && iterator.return !== undefined) {

View File

@@ -373,14 +373,20 @@ describe('DeepSeekAdapter against a mock server', () => {
}
})
it('rejects with STREAM_CLOSED when the server drops mid-stream', async () => {
it('classifies an abrupt body close as TRANSPORT and retains its cause', async () => {
const server = await mockServer([{
kind: 'close-early',
events: ['{"choices":[{"delta":{"content":"par"}}]}'],
}])
const ctx = await harness(server.url)
await expect(assemble(ctx,{ model: 'deepseek-v4-flash', messages: [] }))
.rejects.toThrow(/terminated|socket|without \[DONE\]/)
let caught: unknown
try {
await assemble(ctx,{ model: 'deepseek-v4-flash', messages: [] })
} catch (error: unknown) {
caught = error
}
expect(caught).toMatchObject({ code: 'TRANSPORT' })
expect(errorChain(caught)).toMatch(/terminated|socket|without \[DONE\]/)
})
it('aborts mid-stream via the request signal', async () => {