-
-
Notifications
You must be signed in to change notification settings - Fork 7.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
9,975 additions
and
1 deletion.
There are no files selected for viewing
886 changes: 886 additions & 0 deletions
886
src/libs/agent-runtime/togetherai/__snapshots__/index.test.ts.snap
Large diffs are not rendered by default.
Oops, something went wrong.
8,111 changes: 8,111 additions & 0 deletions
8,111
src/libs/agent-runtime/togetherai/fixtures/models.json
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; | ||
|
||
import { debugStream } from './debugStream'; | ||
|
||
describe('debugStream', () => { | ||
let consoleLogSpy: ReturnType<typeof vi.spyOn>; | ||
let consoleErrorSpy: ReturnType<typeof vi.spyOn>; | ||
|
||
beforeEach(() => { | ||
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); | ||
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); | ||
}); | ||
|
||
afterEach(() => { | ||
consoleLogSpy.mockRestore(); | ||
consoleErrorSpy.mockRestore(); | ||
}); | ||
|
||
it('should log stream start and end messages', async () => { | ||
const stream = new ReadableStream({ | ||
start(controller) { | ||
controller.enqueue('test chunk'); | ||
controller.close(); | ||
}, | ||
}); | ||
|
||
await debugStream(stream); | ||
|
||
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringMatching(/^\[stream start\]/)); | ||
}); | ||
|
||
it('should handle and log stream errors', async () => { | ||
const stream = new ReadableStream({ | ||
start(controller) { | ||
controller.enqueue('test chunk'); | ||
}, | ||
}); | ||
|
||
await debugStream(stream); | ||
|
||
expect(consoleErrorSpy).toHaveBeenCalledWith('[debugStream error]', expect.any(Error)); | ||
expect(consoleErrorSpy).toHaveBeenCalledWith('[error chunk value:]', 'test chunk'); | ||
}); | ||
|
||
it('should decode ArrayBuffer chunk values', async () => { | ||
const stream = new ReadableStream({ | ||
start(controller) { | ||
controller.enqueue(new TextEncoder().encode('test chunk')); | ||
controller.close(); | ||
}, | ||
}); | ||
|
||
await debugStream(stream); | ||
|
||
expect(consoleLogSpy).toHaveBeenCalledWith('test chunk'); | ||
}); | ||
|
||
it('should stringify non-string chunk values', async () => { | ||
const stream = new ReadableStream({ | ||
start(controller) { | ||
controller.enqueue({ test: 'chunk' }); | ||
controller.close(); | ||
}, | ||
}); | ||
|
||
await debugStream(stream); | ||
|
||
expect(consoleLogSpy).toHaveBeenCalledWith('{"test":"chunk"}'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import type { Stream } from '@anthropic-ai/sdk/streaming'; | ||
import { describe, expect, it, vi } from 'vitest'; | ||
|
||
import { AnthropicStream } from './anthropic'; | ||
|
||
describe('AnthropicStream', () => { | ||
it('should transform Anthropic stream to protocol stream', async () => { | ||
// @ts-ignore | ||
const mockAnthropicStream: Stream = { | ||
[Symbol.asyncIterator]() { | ||
let count = 0; | ||
return { | ||
next: async () => { | ||
switch (count) { | ||
case 0: | ||
count++; | ||
return { | ||
done: false, | ||
value: { | ||
type: 'message_start', | ||
message: { id: 'message_1', metadata: {} }, | ||
}, | ||
}; | ||
case 1: | ||
count++; | ||
return { | ||
done: false, | ||
value: { | ||
type: 'content_block_delta', | ||
delta: { type: 'text_delta', text: 'Hello' }, | ||
}, | ||
}; | ||
case 2: | ||
count++; | ||
return { | ||
done: false, | ||
value: { | ||
type: 'content_block_delta', | ||
delta: { type: 'text_delta', text: ' world!' }, | ||
}, | ||
}; | ||
case 3: | ||
count++; | ||
return { | ||
done: false, | ||
value: { | ||
type: 'message_delta', | ||
delta: { stop_reason: 'stop' }, | ||
}, | ||
}; | ||
default: | ||
return { done: true, value: undefined }; | ||
} | ||
}, | ||
}; | ||
}, | ||
}; | ||
|
||
const onStartMock = vi.fn(); | ||
const onTextMock = vi.fn(); | ||
const onTokenMock = vi.fn(); | ||
const onCompletionMock = vi.fn(); | ||
|
||
const protocolStream = AnthropicStream(mockAnthropicStream, { | ||
onStart: onStartMock, | ||
onText: onTextMock, | ||
onToken: onTokenMock, | ||
onCompletion: onCompletionMock, | ||
}); | ||
|
||
const decoder = new TextDecoder(); | ||
const chunks = []; | ||
|
||
// @ts-ignore | ||
for await (const chunk of protocolStream) { | ||
chunks.push(decoder.decode(chunk, { stream: true })); | ||
} | ||
|
||
expect(chunks).toEqual([ | ||
'id: message_1\n', | ||
'event: data\n', | ||
`data: {"id":"message_1","metadata":{}}\n\n`, | ||
'id: message_1\n', | ||
'event: text\n', | ||
`data: "Hello"\n\n`, | ||
'id: message_1\n', | ||
'event: text\n', | ||
`data: " world!"\n\n`, | ||
'id: message_1\n', | ||
'event: stop\n', | ||
`data: "stop"\n\n`, | ||
]); | ||
|
||
expect(onStartMock).toHaveBeenCalledTimes(1); | ||
expect(onTextMock).toHaveBeenNthCalledWith(1, '"Hello"'); | ||
expect(onTextMock).toHaveBeenNthCalledWith(2, '" world!"'); | ||
expect(onTokenMock).toHaveBeenCalledTimes(2); | ||
expect(onCompletionMock).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
it('should handle ReadableStream input', async () => { | ||
const mockReadableStream = new ReadableStream({ | ||
start(controller) { | ||
controller.enqueue({ | ||
type: 'message_start', | ||
message: { id: 'message_1', metadata: {} }, | ||
}); | ||
controller.enqueue({ | ||
type: 'content_block_delta', | ||
delta: { type: 'text_delta', text: 'Hello' }, | ||
}); | ||
controller.enqueue({ | ||
type: 'message_stop', | ||
}); | ||
controller.close(); | ||
}, | ||
}); | ||
|
||
const protocolStream = AnthropicStream(mockReadableStream); | ||
|
||
const decoder = new TextDecoder(); | ||
const chunks = []; | ||
|
||
// @ts-ignore | ||
for await (const chunk of protocolStream) { | ||
chunks.push(decoder.decode(chunk, { stream: true })); | ||
} | ||
|
||
expect(chunks).toEqual([ | ||
'id: message_1\n', | ||
'event: data\n', | ||
`data: {"id":"message_1","metadata":{}}\n\n`, | ||
'id: message_1\n', | ||
'event: text\n', | ||
`data: "Hello"\n\n`, | ||
'id: message_1\n', | ||
'event: stop\n', | ||
`data: "message_stop"\n\n`, | ||
]); | ||
}); | ||
}); |
Oops, something went wrong.