Reverts #189 due to reported bugs. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -414,89 +414,4 @@ describe('SSE stream interception — run.completed', () => {
|
||||
|
||||
expect(mockUpdateUsage).toHaveBeenCalledWith('session-split', 200, 50)
|
||||
})
|
||||
|
||||
it('forwards colon-containing SSE deltas around tool events unchanged and disables buffering', async () => {
|
||||
const runId = 'run-colon-tool'
|
||||
const sseData = [
|
||||
`data: ${JSON.stringify({ event: 'message.delta', run_id: runId, delta: '让我直接读文件:A: B' })}\n\n`,
|
||||
`data: ${JSON.stringify({ event: 'tool.started', run_id: runId, tool: 'read_file', preview: 'file:a.md' })}\n\n`,
|
||||
`data: ${JSON.stringify({ event: 'tool.completed', run_id: runId })}\n\n`,
|
||||
`data: ${JSON.stringify({ event: 'message.delta', run_id: runId, delta: '继续:done' })}\n\n`,
|
||||
]
|
||||
|
||||
mockFetch.mockResolvedValue({
|
||||
status: 200,
|
||||
headers: new Headers({ 'content-type': 'text/event-stream' }),
|
||||
body: createSSEBody(sseData),
|
||||
})
|
||||
|
||||
const ctx = createMockCtx({
|
||||
path: `/api/hermes/v1/runs/${runId}/events`,
|
||||
search: '',
|
||||
})
|
||||
|
||||
await proxy(ctx)
|
||||
|
||||
const forwarded = ctx.res.write.mock.calls
|
||||
.map(([chunk]: [Uint8Array]) => new TextDecoder().decode(chunk))
|
||||
.join('')
|
||||
expect(forwarded).toBe(sseData.join(''))
|
||||
expect(ctx.set).toHaveBeenCalledWith('Content-Type', 'text/event-stream')
|
||||
expect(ctx.set).toHaveBeenCalledWith('Cache-Control', 'no-cache, no-transform')
|
||||
expect(ctx.set).toHaveBeenCalledWith('X-Accel-Buffering', 'no')
|
||||
})
|
||||
|
||||
it('intercepts run.completed with CRLF delimiters and data without a space', async () => {
|
||||
const runId = 'run-crlf'
|
||||
setRunSession(runId, 'session-crlf')
|
||||
const completedJson = JSON.stringify({ event: 'run.completed', run_id: runId, usage: { input_tokens: 321, output_tokens: 45, total_tokens: 366 } })
|
||||
const sseData = [`data:${completedJson}\r\n\r\n`]
|
||||
|
||||
mockFetch.mockResolvedValue({
|
||||
status: 200,
|
||||
headers: new Headers({ 'content-type': 'text/event-stream' }),
|
||||
body: createSSEBody(sseData),
|
||||
})
|
||||
|
||||
const ctx = createMockCtx({
|
||||
path: `/api/hermes/v1/runs/${runId}/events`,
|
||||
search: '',
|
||||
})
|
||||
|
||||
await proxy(ctx)
|
||||
|
||||
expect(mockUpdateUsage).toHaveBeenCalledWith('session-crlf', 321, 45)
|
||||
})
|
||||
|
||||
it('does not let usage accounting failures abort the SSE stream', async () => {
|
||||
const runId = 'run-usage-fails'
|
||||
setRunSession(runId, 'session-usage-fails')
|
||||
mockUpdateUsage.mockImplementationOnce(() => {
|
||||
throw new Error('usage db unavailable')
|
||||
})
|
||||
const sseData = [
|
||||
`data: ${JSON.stringify({ event: 'message.delta', run_id: runId, delta: 'before:' })}\n\n`,
|
||||
`data: ${JSON.stringify({ event: 'run.completed', run_id: runId, usage: { input_tokens: 1, output_tokens: 2, total_tokens: 3 } })}\n\n`,
|
||||
]
|
||||
|
||||
mockFetch.mockResolvedValue({
|
||||
status: 200,
|
||||
headers: new Headers({ 'content-type': 'text/event-stream' }),
|
||||
body: createSSEBody(sseData),
|
||||
})
|
||||
|
||||
const ctx = createMockCtx({
|
||||
path: `/api/hermes/v1/runs/${runId}/events`,
|
||||
search: '',
|
||||
})
|
||||
|
||||
await proxy(ctx)
|
||||
|
||||
const forwarded = ctx.res.write.mock.calls
|
||||
.map(([chunk]: [Uint8Array]) => new TextDecoder().decode(chunk))
|
||||
.join('')
|
||||
expect(ctx.status).toBe(200)
|
||||
expect(forwarded).toBe(sseData.join(''))
|
||||
expect(ctx.res.end).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user