|
1 | 1 | import type { ChatStreamEvent, EnhancedResponseStreamEvent } from '../../src/lib/tool-types.js'; |
2 | 2 | import type { ClaudeMessageParam } from '../../src/models/claude-message.js'; |
3 | | -import type { ResponsesOutputMessage } from '../../src/models/responsesoutputmessage.js'; |
4 | 3 | import type { OpenResponsesFunctionCallOutput } from '../../src/models/openresponsesfunctioncalloutput.js'; |
| 4 | +import type { OpenResponsesNonStreamingResponse } from '../../src/models/openresponsesnonstreamingresponse.js'; |
| 5 | +import type { OpenResponsesStreamEvent } from '../../src/models/openresponsesstreamevent.js'; |
| 6 | +import type { ResponsesOutputMessage } from '../../src/models/responsesoutputmessage.js'; |
5 | 7 |
|
6 | 8 | import { beforeAll, describe, expect, it } from 'vitest'; |
7 | 9 | import { z } from 'zod/v4'; |
8 | | -import { OpenRouter, ToolType } from '../../src/sdk/sdk.js'; |
9 | | -import { fromChatMessages, toChatMessage } from '../../src/lib/chat-compat.js'; |
| 10 | +import { OpenRouter, ToolType } from '../../src/index.js'; |
10 | 11 | import { fromClaudeMessages } from '../../src/lib/anthropic-compat.js'; |
11 | | -import { OpenResponsesNonStreamingResponse } from '../../src/models/openresponsesnonstreamingresponse.js'; |
12 | | -import { OpenResponsesStreamEvent } from '../../src/models/openresponsesstreamevent.js'; |
| 12 | +import { fromChatMessages, toChatMessage } from '../../src/lib/chat-compat.js'; |
13 | 13 |
|
14 | 14 | describe('callModel E2E Tests', () => { |
15 | 15 | let client: OpenRouter; |
@@ -233,7 +233,7 @@ describe('callModel E2E Tests', () => { |
233 | 233 | }, |
234 | 234 | { |
235 | 235 | role: 'assistant', |
236 | | - content: "Nice to meet you, Alice! How can I help you today?", |
| 236 | + content: 'Nice to meet you, Alice! How can I help you today?', |
237 | 237 | }, |
238 | 238 | { |
239 | 239 | role: 'user', |
@@ -512,7 +512,14 @@ describe('callModel E2E Tests', () => { |
512 | 512 | // Extract text from content array |
513 | 513 | const getTextFromContent = (msg: ResponsesOutputMessage) => { |
514 | 514 | return msg.content |
515 | | - .filter((c): c is { type: 'output_text'; text: string } => 'type' in c && c.type === 'output_text') |
| 515 | + .filter( |
| 516 | + ( |
| 517 | + c, |
| 518 | + ): c is { |
| 519 | + type: 'output_text'; |
| 520 | + text: string; |
| 521 | + } => 'type' in c && c.type === 'output_text', |
| 522 | + ) |
516 | 523 | .map((c) => c.text) |
517 | 524 | .join(''); |
518 | 525 | }; |
@@ -555,12 +562,19 @@ describe('callModel E2E Tests', () => { |
555 | 562 | expect(item).toHaveProperty('type'); |
556 | 563 | expect(typeof item.type).toBe('string'); |
557 | 564 | // Content items should be output_text or refusal |
558 | | - expect(['output_text', 'refusal']).toContain(item.type); |
| 565 | + expect([ |
| 566 | + 'output_text', |
| 567 | + 'refusal', |
| 568 | + ]).toContain(item.type); |
559 | 569 | } |
560 | 570 |
|
561 | 571 | // Validate optional status field |
562 | 572 | if (outputMessage.status !== undefined) { |
563 | | - expect(['completed', 'incomplete', 'in_progress']).toContain(outputMessage.status); |
| 573 | + expect([ |
| 574 | + 'completed', |
| 575 | + 'incomplete', |
| 576 | + 'in_progress', |
| 577 | + ]).toContain(outputMessage.status); |
564 | 578 | } |
565 | 579 | } |
566 | 580 | } |
@@ -685,7 +699,10 @@ describe('callModel E2E Tests', () => { |
685 | 699 | for await (const message of response.getNewMessagesStream()) { |
686 | 700 | // type must be a string and one of the valid values |
687 | 701 | expect(typeof message.type).toBe('string'); |
688 | | - expect(['message', 'function_call_output']).toContain(message.type); |
| 702 | + expect([ |
| 703 | + 'message', |
| 704 | + 'function_call_output', |
| 705 | + ]).toContain(message.type); |
689 | 706 |
|
690 | 707 | if (message.type === 'message') { |
691 | 708 | const outputMessage = message as ResponsesOutputMessage; |
@@ -853,7 +870,7 @@ describe('callModel E2E Tests', () => { |
853 | 870 |
|
854 | 871 | // Verify delta events have the expected structure |
855 | 872 | const firstDelta = textDeltaEvents[0]; |
856 | | - if(firstDelta.type === 'response.output_text.delta') { |
| 873 | + if (firstDelta.type === 'response.output_text.delta') { |
857 | 874 | expect(firstDelta.delta).toBeDefined(); |
858 | 875 | expect(typeof firstDelta.delta).toBe('string'); |
859 | 876 | } else { |
@@ -914,34 +931,82 @@ describe('callModel E2E Tests', () => { |
914 | 931 | case 'content.delta': |
915 | 932 | hasContentDelta = true; |
916 | 933 | // Must have delta property |
917 | | - expect((event as { delta: string }).delta).toBeDefined(); |
918 | | - expect(typeof (event as { delta: string }).delta).toBe('string'); |
| 934 | + expect( |
| 935 | + ( |
| 936 | + event as { |
| 937 | + delta: string; |
| 938 | + } |
| 939 | + ).delta, |
| 940 | + ).toBeDefined(); |
| 941 | + expect( |
| 942 | + typeof ( |
| 943 | + event as { |
| 944 | + delta: string; |
| 945 | + } |
| 946 | + ).delta, |
| 947 | + ).toBe('string'); |
919 | 948 | // Delta can be empty string but must be string |
920 | 949 | break; |
921 | 950 |
|
922 | 951 | case 'message.complete': |
923 | 952 | _hasMessageComplete = true; |
924 | 953 | // Must have response property |
925 | 954 | expect(event).toHaveProperty('response'); |
926 | | - expect((event as { response: OpenResponsesNonStreamingResponse }).response).toBeDefined(); |
| 955 | + expect( |
| 956 | + ( |
| 957 | + event as { |
| 958 | + response: OpenResponsesNonStreamingResponse; |
| 959 | + } |
| 960 | + ).response, |
| 961 | + ).toBeDefined(); |
927 | 962 | // Response should be an object (the full response) |
928 | | - expect(typeof (event as { response: OpenResponsesNonStreamingResponse }).response).toBe('object'); |
929 | | - expect((event as { response: OpenResponsesNonStreamingResponse }).response).not.toBeNull(); |
| 963 | + expect( |
| 964 | + typeof ( |
| 965 | + event as { |
| 966 | + response: OpenResponsesNonStreamingResponse; |
| 967 | + } |
| 968 | + ).response, |
| 969 | + ).toBe('object'); |
| 970 | + expect( |
| 971 | + ( |
| 972 | + event as { |
| 973 | + response: OpenResponsesNonStreamingResponse; |
| 974 | + } |
| 975 | + ).response, |
| 976 | + ).not.toBeNull(); |
930 | 977 | break; |
931 | 978 |
|
932 | 979 | case 'tool.preliminary_result': |
933 | 980 | // Must have toolCallId and result |
934 | 981 | expect(event).toHaveProperty('toolCallId'); |
935 | 982 | expect(event).toHaveProperty('result'); |
936 | | - expect(typeof (event as { toolCallId: string }).toolCallId).toBe('string'); |
937 | | - expect((event as { toolCallId: string }).toolCallId.length).toBeGreaterThan(0); |
| 983 | + expect( |
| 984 | + typeof ( |
| 985 | + event as { |
| 986 | + toolCallId: string; |
| 987 | + } |
| 988 | + ).toolCallId, |
| 989 | + ).toBe('string'); |
| 990 | + expect( |
| 991 | + ( |
| 992 | + event as { |
| 993 | + toolCallId: string; |
| 994 | + } |
| 995 | + ).toolCallId.length, |
| 996 | + ).toBeGreaterThan(0); |
938 | 997 | // result can be any type |
939 | 998 | break; |
940 | 999 |
|
941 | 1000 | default: |
942 | 1001 | // Pass-through events must have event property |
943 | 1002 | expect(event).toHaveProperty('event'); |
944 | | - expect((event as { event: OpenResponsesStreamEvent }).event).toBeDefined(); |
| 1003 | + expect( |
| 1004 | + ( |
| 1005 | + event as { |
| 1006 | + event: OpenResponsesStreamEvent; |
| 1007 | + } |
| 1008 | + ).event, |
| 1009 | + ).toBeDefined(); |
945 | 1010 | break; |
946 | 1011 | } |
947 | 1012 | } |
@@ -976,14 +1041,29 @@ describe('callModel E2E Tests', () => { |
976 | 1041 | expect(event.type).toBe('content.delta'); |
977 | 1042 |
|
978 | 1043 | // delta must be a string |
979 | | - expect(typeof (event as { delta: string }).delta).toBe('string'); |
| 1044 | + expect( |
| 1045 | + typeof ( |
| 1046 | + event as { |
| 1047 | + delta: string; |
| 1048 | + } |
| 1049 | + ).delta, |
| 1050 | + ).toBe('string'); |
980 | 1051 | } |
981 | 1052 | } |
982 | 1053 |
|
983 | 1054 | expect(contentDeltas.length).toBeGreaterThan(0); |
984 | 1055 |
|
985 | 1056 | // Concatenated deltas should form readable text |
986 | | - const fullText = contentDeltas.map((e) => (e as { delta: string }).delta).join(''); |
| 1057 | + const fullText = contentDeltas |
| 1058 | + .map( |
| 1059 | + (e) => |
| 1060 | + ( |
| 1061 | + e as { |
| 1062 | + delta: string; |
| 1063 | + } |
| 1064 | + ).delta, |
| 1065 | + ) |
| 1066 | + .join(''); |
987 | 1067 | expect(fullText.length).toBeGreaterThan(0); |
988 | 1068 | }, 15000); |
989 | 1069 |
|
@@ -1047,11 +1127,29 @@ describe('callModel E2E Tests', () => { |
1047 | 1127 | expect(event).toHaveProperty('result'); |
1048 | 1128 |
|
1049 | 1129 | // toolCallId must be non-empty string |
1050 | | - expect(typeof (event as { toolCallId: string }).toolCallId).toBe('string'); |
1051 | | - expect((event as { toolCallId: string }).toolCallId.length).toBeGreaterThan(0); |
| 1130 | + expect( |
| 1131 | + typeof ( |
| 1132 | + event as { |
| 1133 | + toolCallId: string; |
| 1134 | + } |
| 1135 | + ).toolCallId, |
| 1136 | + ).toBe('string'); |
| 1137 | + expect( |
| 1138 | + ( |
| 1139 | + event as { |
| 1140 | + toolCallId: string; |
| 1141 | + } |
| 1142 | + ).toolCallId.length, |
| 1143 | + ).toBeGreaterThan(0); |
1052 | 1144 |
|
1053 | 1145 | // result is defined |
1054 | | - expect((event as { result: unknown }).result).toBeDefined(); |
| 1146 | + expect( |
| 1147 | + ( |
| 1148 | + event as { |
| 1149 | + result: unknown; |
| 1150 | + } |
| 1151 | + ).result, |
| 1152 | + ).toBeDefined(); |
1055 | 1153 | } |
1056 | 1154 | } |
1057 | 1155 |
|
@@ -1152,7 +1250,14 @@ describe('callModel E2E Tests', () => { |
1152 | 1250 | const lastMessage = messages[messages.length - 1] as ResponsesOutputMessage; |
1153 | 1251 | // Extract text from ResponsesOutputMessage content array |
1154 | 1252 | const textFromMessage = lastMessage.content |
1155 | | - .filter((c): c is { type: 'output_text'; text: string } => 'type' in c && c.type === 'output_text') |
| 1253 | + .filter( |
| 1254 | + ( |
| 1255 | + c, |
| 1256 | + ): c is { |
| 1257 | + type: 'output_text'; |
| 1258 | + text: string; |
| 1259 | + } => 'type' in c && c.type === 'output_text', |
| 1260 | + ) |
1156 | 1261 | .map((c) => c.text) |
1157 | 1262 | .join(''); |
1158 | 1263 |
|
@@ -1277,7 +1382,13 @@ describe('callModel E2E Tests', () => { |
1277 | 1382 | // Verify output items have correct shape |
1278 | 1383 | for (const item of fullResponse.output) { |
1279 | 1384 | expect(item).toHaveProperty('type'); |
1280 | | - expect(typeof (item as { type: string }).type).toBe('string'); |
| 1385 | + expect( |
| 1386 | + typeof ( |
| 1387 | + item as { |
| 1388 | + type: string; |
| 1389 | + } |
| 1390 | + ).type, |
| 1391 | + ).toBe('string'); |
1281 | 1392 | } |
1282 | 1393 |
|
1283 | 1394 | // Verify temperature and topP are present (can be null) |
|
0 commit comments