|
|
@@ -283,6 +283,79 @@ describe("OpenRouterHandler", () => {
|
|
|
const generator = handler.createMessage("test", [])
|
|
|
await expect(generator.next()).rejects.toThrow("OpenRouter API Error 500: API Error")
|
|
|
})
|
|
|
+
|
|
|
+ it("yields tool_call_end events when finish_reason is tool_calls", async () => {
|
|
|
+ // Import NativeToolCallParser to set up state
|
|
|
+ const { NativeToolCallParser } = await import("../../../core/assistant-message/NativeToolCallParser")
|
|
|
+
|
|
|
+ // Clear any previous state
|
|
|
+ NativeToolCallParser.clearRawChunkState()
|
|
|
+
|
|
|
+ const handler = new OpenRouterHandler(mockOptions)
|
|
|
+
|
|
|
+ const mockStream = {
|
|
|
+ async *[Symbol.asyncIterator]() {
|
|
|
+ yield {
|
|
|
+ id: "test-id",
|
|
|
+ choices: [
|
|
|
+ {
|
|
|
+ delta: {
|
|
|
+ tool_calls: [
|
|
|
+ {
|
|
|
+ index: 0,
|
|
|
+ id: "call_openrouter_test",
|
|
|
+ function: { name: "read_file", arguments: '{"path":"test.ts"}' },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ index: 0,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ }
|
|
|
+ yield {
|
|
|
+ id: "test-id",
|
|
|
+ choices: [
|
|
|
+ {
|
|
|
+ delta: {},
|
|
|
+ finish_reason: "tool_calls",
|
|
|
+ index: 0,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
|
|
|
+ }
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ const mockCreate = vitest.fn().mockResolvedValue(mockStream)
|
|
|
+ ;(OpenAI as any).prototype.chat = {
|
|
|
+ completions: { create: mockCreate },
|
|
|
+ } as any
|
|
|
+
|
|
|
+ const generator = handler.createMessage("test", [])
|
|
|
+ const chunks = []
|
|
|
+
|
|
|
+ for await (const chunk of generator) {
|
|
|
+ // Simulate what Task.ts does: when we receive tool_call_partial,
|
|
|
+ // process it through NativeToolCallParser to populate rawChunkTracker
|
|
|
+ if (chunk.type === "tool_call_partial") {
|
|
|
+ NativeToolCallParser.processRawChunk({
|
|
|
+ index: chunk.index,
|
|
|
+ id: chunk.id,
|
|
|
+ name: chunk.name,
|
|
|
+ arguments: chunk.arguments,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ chunks.push(chunk)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Should have tool_call_partial and tool_call_end
|
|
|
+ const partialChunks = chunks.filter((chunk) => chunk.type === "tool_call_partial")
|
|
|
+ const endChunks = chunks.filter((chunk) => chunk.type === "tool_call_end")
|
|
|
+
|
|
|
+ expect(partialChunks).toHaveLength(1)
|
|
|
+ expect(endChunks).toHaveLength(1)
|
|
|
+ expect(endChunks[0].id).toBe("call_openrouter_test")
|
|
|
+ })
|
|
|
})
|
|
|
|
|
|
describe("completePrompt", () => {
|