@ai-sdk/groq 3.0.14 → 3.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2028 +0,0 @@
1
- import { LanguageModelV3Prompt } from '@ai-sdk/provider';
2
- import { createTestServer } from '@ai-sdk/test-server/with-vitest';
3
- import {
4
- convertReadableStreamToArray,
5
- isNodeVersion,
6
- } from '@ai-sdk/provider-utils/test';
7
- import { createGroq } from './groq-provider';
8
- import { describe, it, expect, vi } from 'vitest';
9
-
10
- vi.mock('./version', () => ({
11
- VERSION: '0.0.0-test',
12
- }));
13
-
14
- const TEST_PROMPT: LanguageModelV3Prompt = [
15
- { role: 'user', content: [{ type: 'text', text: 'Hello' }] },
16
- ];
17
-
18
- const provider = createGroq({ apiKey: 'test-api-key' });
19
- const model = provider('gemma2-9b-it');
20
-
21
- const server = createTestServer({
22
- 'https://api.groq.com/openai/v1/chat/completions': {},
23
- });
24
-
25
- describe('doGenerate', () => {
26
- function prepareJsonResponse({
27
- content = '',
28
- reasoning,
29
- tool_calls,
30
- function_call,
31
- usage = {
32
- prompt_tokens: 4,
33
- total_tokens: 34,
34
- completion_tokens: 30,
35
- },
36
- finish_reason = 'stop',
37
- id = 'chatcmpl-95ZTZkhr0mHNKqerQfiwkuox3PHAd',
38
- created = 1711115037,
39
- model = 'gemma2-9b-it',
40
- headers,
41
- }: {
42
- content?: string;
43
- reasoning?: string;
44
- tool_calls?: Array<{
45
- id: string;
46
- type: 'function';
47
- function: {
48
- name: string;
49
- arguments: string;
50
- };
51
- }>;
52
- function_call?: {
53
- name: string;
54
- arguments: string;
55
- };
56
- usage?: {
57
- prompt_tokens?: number;
58
- total_tokens?: number;
59
- completion_tokens?: number;
60
- prompt_tokens_details?: {
61
- cached_tokens?: number;
62
- };
63
- completion_tokens_details?: {
64
- reasoning_tokens?: number;
65
- };
66
- };
67
- finish_reason?: string;
68
- created?: number;
69
- id?: string;
70
- model?: string;
71
- headers?: Record<string, string>;
72
- } = {}) {
73
- server.urls['https://api.groq.com/openai/v1/chat/completions'].response = {
74
- type: 'json-value',
75
- headers,
76
- body: {
77
- id,
78
- object: 'chat.completion',
79
- created,
80
- model,
81
- choices: [
82
- {
83
- index: 0,
84
- message: {
85
- role: 'assistant',
86
- content,
87
- reasoning,
88
- tool_calls,
89
- function_call,
90
- },
91
- finish_reason,
92
- },
93
- ],
94
- usage,
95
- system_fingerprint: 'fp_3bc1b5746c',
96
- },
97
- };
98
- }
99
-
100
- it('should extract text', async () => {
101
- prepareJsonResponse({ content: 'Hello, World!' });
102
-
103
- const { content } = await model.doGenerate({
104
- prompt: TEST_PROMPT,
105
- });
106
-
107
- expect(content).toMatchInlineSnapshot(`
108
- [
109
- {
110
- "text": "Hello, World!",
111
- "type": "text",
112
- },
113
- ]
114
- `);
115
- });
116
-
117
- it('should extract reasoning', async () => {
118
- prepareJsonResponse({
119
- reasoning: 'This is a test reasoning',
120
- });
121
-
122
- const { content } = await model.doGenerate({
123
- prompt: TEST_PROMPT,
124
- });
125
-
126
- expect(content).toMatchInlineSnapshot(`
127
- [
128
- {
129
- "text": "This is a test reasoning",
130
- "type": "reasoning",
131
- },
132
- ]
133
- `);
134
- });
135
-
136
- it('should extract usage', async () => {
137
- prepareJsonResponse({
138
- usage: { prompt_tokens: 20, total_tokens: 25, completion_tokens: 5 },
139
- });
140
-
141
- const { usage } = await model.doGenerate({
142
- prompt: TEST_PROMPT,
143
- });
144
-
145
- expect(usage).toMatchInlineSnapshot(`
146
- {
147
- "inputTokens": {
148
- "cacheRead": undefined,
149
- "cacheWrite": undefined,
150
- "noCache": 20,
151
- "total": 20,
152
- },
153
- "outputTokens": {
154
- "reasoning": undefined,
155
- "text": 5,
156
- "total": 5,
157
- },
158
- "raw": {
159
- "completion_tokens": 5,
160
- "prompt_tokens": 20,
161
- "total_tokens": 25,
162
- },
163
- }
164
- `);
165
- });
166
- it('should send additional response information', async () => {
167
- prepareJsonResponse({
168
- id: 'test-id',
169
- created: 123,
170
- model: 'test-model',
171
- });
172
-
173
- const { response } = await model.doGenerate({
174
- prompt: TEST_PROMPT,
175
- });
176
-
177
- expect({
178
- id: response?.id,
179
- timestamp: response?.timestamp,
180
- modelId: response?.modelId,
181
- }).toStrictEqual({
182
- id: 'test-id',
183
- timestamp: new Date(123 * 1000),
184
- modelId: 'test-model',
185
- });
186
- });
187
-
188
- it('should support partial usage', async () => {
189
- prepareJsonResponse({
190
- usage: { prompt_tokens: 20, total_tokens: 20 },
191
- });
192
-
193
- const { usage } = await model.doGenerate({
194
- prompt: TEST_PROMPT,
195
- });
196
-
197
- expect(usage).toMatchInlineSnapshot(`
198
- {
199
- "inputTokens": {
200
- "cacheRead": undefined,
201
- "cacheWrite": undefined,
202
- "noCache": 20,
203
- "total": 20,
204
- },
205
- "outputTokens": {
206
- "reasoning": undefined,
207
- "text": 0,
208
- "total": 0,
209
- },
210
- "raw": {
211
- "prompt_tokens": 20,
212
- "total_tokens": 20,
213
- },
214
- }
215
- `);
216
- });
217
-
218
- it('should extract cached input tokens', async () => {
219
- prepareJsonResponse({
220
- usage: {
221
- prompt_tokens: 20,
222
- total_tokens: 25,
223
- completion_tokens: 5,
224
- prompt_tokens_details: {
225
- cached_tokens: 15,
226
- },
227
- },
228
- });
229
-
230
- const { usage } = await model.doGenerate({
231
- prompt: TEST_PROMPT,
232
- });
233
-
234
- expect(usage).toMatchInlineSnapshot(`
235
- {
236
- "inputTokens": {
237
- "cacheRead": undefined,
238
- "cacheWrite": undefined,
239
- "noCache": 20,
240
- "total": 20,
241
- },
242
- "outputTokens": {
243
- "reasoning": undefined,
244
- "text": 5,
245
- "total": 5,
246
- },
247
- "raw": {
248
- "completion_tokens": 5,
249
- "prompt_tokens": 20,
250
- "prompt_tokens_details": {
251
- "cached_tokens": 15,
252
- },
253
- "total_tokens": 25,
254
- },
255
- }
256
- `);
257
- });
258
-
259
- it('should extract reasoning tokens from completion_tokens_details', async () => {
260
- prepareJsonResponse({
261
- usage: {
262
- prompt_tokens: 79,
263
- total_tokens: 119,
264
- completion_tokens: 40,
265
- completion_tokens_details: {
266
- reasoning_tokens: 21,
267
- },
268
- },
269
- });
270
-
271
- const { usage } = await model.doGenerate({
272
- prompt: TEST_PROMPT,
273
- });
274
-
275
- expect(usage).toMatchInlineSnapshot(`
276
- {
277
- "inputTokens": {
278
- "cacheRead": undefined,
279
- "cacheWrite": undefined,
280
- "noCache": 79,
281
- "total": 79,
282
- },
283
- "outputTokens": {
284
- "reasoning": 21,
285
- "text": 19,
286
- "total": 40,
287
- },
288
- "raw": {
289
- "completion_tokens": 40,
290
- "completion_tokens_details": {
291
- "reasoning_tokens": 21,
292
- },
293
- "prompt_tokens": 79,
294
- "total_tokens": 119,
295
- },
296
- }
297
- `);
298
- });
299
-
300
- it('should extract finish reason', async () => {
301
- prepareJsonResponse({
302
- finish_reason: 'stop',
303
- });
304
-
305
- const response = await model.doGenerate({
306
- prompt: TEST_PROMPT,
307
- });
308
-
309
- expect(response.finishReason).toMatchInlineSnapshot(`
310
- {
311
- "raw": "stop",
312
- "unified": "stop",
313
- }
314
- `);
315
- });
316
-
317
- it('should support unknown finish reason', async () => {
318
- prepareJsonResponse({
319
- finish_reason: 'eos',
320
- });
321
-
322
- const response = await model.doGenerate({
323
- prompt: TEST_PROMPT,
324
- });
325
-
326
- expect(response.finishReason).toMatchInlineSnapshot(`
327
- {
328
- "raw": "eos",
329
- "unified": "other",
330
- }
331
- `);
332
- });
333
-
334
- it('should expose the raw response headers', async () => {
335
- prepareJsonResponse({
336
- headers: {
337
- 'test-header': 'test-value',
338
- },
339
- });
340
-
341
- const { response } = await model.doGenerate({
342
- prompt: TEST_PROMPT,
343
- });
344
-
345
- expect(response?.headers).toStrictEqual({
346
- // default headers:
347
- 'content-length': '315',
348
- 'content-type': 'application/json',
349
-
350
- // custom header
351
- 'test-header': 'test-value',
352
- });
353
- });
354
-
355
- it('should pass the model and the messages', async () => {
356
- prepareJsonResponse({ content: '' });
357
-
358
- await model.doGenerate({
359
- prompt: TEST_PROMPT,
360
- });
361
-
362
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
363
- model: 'gemma2-9b-it',
364
- messages: [{ role: 'user', content: 'Hello' }],
365
- });
366
- });
367
-
368
- it('should pass provider options', async () => {
369
- prepareJsonResponse();
370
-
371
- await provider('gemma2-9b-it').doGenerate({
372
- prompt: TEST_PROMPT,
373
- providerOptions: {
374
- groq: {
375
- reasoningFormat: 'hidden',
376
- user: 'test-user-id',
377
- parallelToolCalls: false,
378
- },
379
- },
380
- });
381
-
382
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
383
- model: 'gemma2-9b-it',
384
- messages: [{ role: 'user', content: 'Hello' }],
385
- parallel_tool_calls: false,
386
- user: 'test-user-id',
387
- reasoning_format: 'hidden',
388
- });
389
- });
390
-
391
- it('should pass serviceTier provider option', async () => {
392
- prepareJsonResponse();
393
-
394
- await provider('gemma2-9b-it').doGenerate({
395
- prompt: TEST_PROMPT,
396
- providerOptions: {
397
- groq: {
398
- serviceTier: 'flex',
399
- },
400
- },
401
- });
402
-
403
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
404
- model: 'gemma2-9b-it',
405
- messages: [{ role: 'user', content: 'Hello' }],
406
- service_tier: 'flex',
407
- });
408
- });
409
-
410
- it('should pass tools and toolChoice', async () => {
411
- prepareJsonResponse({ content: '' });
412
-
413
- await model.doGenerate({
414
- tools: [
415
- {
416
- type: 'function',
417
- name: 'test-tool',
418
- inputSchema: {
419
- type: 'object',
420
- properties: { value: { type: 'string' } },
421
- required: ['value'],
422
- additionalProperties: false,
423
- $schema: 'http://json-schema.org/draft-07/schema#',
424
- },
425
- },
426
- ],
427
- toolChoice: {
428
- type: 'tool',
429
- toolName: 'test-tool',
430
- },
431
- prompt: TEST_PROMPT,
432
- });
433
-
434
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
435
- model: 'gemma2-9b-it',
436
- messages: [{ role: 'user', content: 'Hello' }],
437
- tools: [
438
- {
439
- type: 'function',
440
- function: {
441
- name: 'test-tool',
442
- parameters: {
443
- type: 'object',
444
- properties: { value: { type: 'string' } },
445
- required: ['value'],
446
- additionalProperties: false,
447
- $schema: 'http://json-schema.org/draft-07/schema#',
448
- },
449
- },
450
- },
451
- ],
452
- tool_choice: {
453
- type: 'function',
454
- function: { name: 'test-tool' },
455
- },
456
- });
457
- });
458
-
459
- it('should pass headers', async () => {
460
- prepareJsonResponse({ content: '' });
461
-
462
- const provider = createGroq({
463
- apiKey: 'test-api-key',
464
- headers: {
465
- 'Custom-Provider-Header': 'provider-header-value',
466
- },
467
- });
468
-
469
- await provider('gemma2-9b-it').doGenerate({
470
- prompt: TEST_PROMPT,
471
- headers: {
472
- 'Custom-Request-Header': 'request-header-value',
473
- },
474
- });
475
-
476
- expect(server.calls[0].requestHeaders).toStrictEqual({
477
- authorization: 'Bearer test-api-key',
478
- 'content-type': 'application/json',
479
- 'custom-provider-header': 'provider-header-value',
480
- 'custom-request-header': 'request-header-value',
481
- });
482
- expect(server.calls[0].requestUserAgent).toContain(
483
- `ai-sdk/groq/0.0.0-test`,
484
- );
485
- });
486
-
487
- it('should parse tool results', async () => {
488
- prepareJsonResponse({
489
- tool_calls: [
490
- {
491
- id: 'call_O17Uplv4lJvD6DVdIvFFeRMw',
492
- type: 'function',
493
- function: {
494
- name: 'test-tool',
495
- arguments: '{"value":"Spark"}',
496
- },
497
- },
498
- ],
499
- });
500
-
501
- const result = await model.doGenerate({
502
- tools: [
503
- {
504
- type: 'function',
505
- name: 'test-tool',
506
- inputSchema: {
507
- type: 'object',
508
- properties: { value: { type: 'string' } },
509
- required: ['value'],
510
- additionalProperties: false,
511
- $schema: 'http://json-schema.org/draft-07/schema#',
512
- },
513
- },
514
- ],
515
- toolChoice: {
516
- type: 'tool',
517
- toolName: 'test-tool',
518
- },
519
- prompt: TEST_PROMPT,
520
- });
521
-
522
- expect(result.content).toMatchInlineSnapshot(`
523
- [
524
- {
525
- "input": "{"value":"Spark"}",
526
- "toolCallId": "call_O17Uplv4lJvD6DVdIvFFeRMw",
527
- "toolName": "test-tool",
528
- "type": "tool-call",
529
- },
530
- ]
531
- `);
532
- });
533
-
534
- it('should pass response format information as json_schema when structuredOutputs enabled by default', async () => {
535
- prepareJsonResponse({ content: '{"value":"Spark"}' });
536
-
537
- const model = provider('gemma2-9b-it');
538
-
539
- await model.doGenerate({
540
- responseFormat: {
541
- type: 'json',
542
- name: 'test-name',
543
- description: 'test description',
544
- schema: {
545
- type: 'object',
546
- properties: { value: { type: 'string' } },
547
- required: ['value'],
548
- additionalProperties: false,
549
- $schema: 'http://json-schema.org/draft-07/schema#',
550
- },
551
- },
552
- prompt: TEST_PROMPT,
553
- });
554
-
555
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
556
- model: 'gemma2-9b-it',
557
- messages: [{ role: 'user', content: 'Hello' }],
558
- response_format: {
559
- type: 'json_schema',
560
- json_schema: {
561
- strict: true,
562
- name: 'test-name',
563
- description: 'test description',
564
- schema: {
565
- type: 'object',
566
- properties: { value: { type: 'string' } },
567
- required: ['value'],
568
- additionalProperties: false,
569
- $schema: 'http://json-schema.org/draft-07/schema#',
570
- },
571
- },
572
- },
573
- });
574
- });
575
-
576
- it('should pass response format information as json_object when structuredOutputs explicitly disabled', async () => {
577
- prepareJsonResponse({ content: '{"value":"Spark"}' });
578
-
579
- const model = provider('gemma2-9b-it');
580
-
581
- const { warnings } = await model.doGenerate({
582
- providerOptions: {
583
- groq: {
584
- structuredOutputs: false,
585
- },
586
- },
587
- responseFormat: {
588
- type: 'json',
589
- name: 'test-name',
590
- description: 'test description',
591
- schema: {
592
- type: 'object',
593
- properties: { value: { type: 'string' } },
594
- required: ['value'],
595
- additionalProperties: false,
596
- $schema: 'http://json-schema.org/draft-07/schema#',
597
- },
598
- },
599
- prompt: TEST_PROMPT,
600
- });
601
-
602
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
603
- model: 'gemma2-9b-it',
604
- messages: [{ role: 'user', content: 'Hello' }],
605
- response_format: {
606
- type: 'json_object',
607
- },
608
- });
609
-
610
- expect(warnings).toMatchInlineSnapshot(`
611
- [
612
- {
613
- "details": "JSON response format schema is only supported with structuredOutputs",
614
- "feature": "responseFormat",
615
- "type": "unsupported",
616
- },
617
- ]
618
- `);
619
- });
620
-
621
- it('should use json_schema format when structuredOutputs explicitly enabled', async () => {
622
- prepareJsonResponse({ content: '{"value":"Spark"}' });
623
-
624
- const model = provider('gemma2-9b-it');
625
-
626
- await model.doGenerate({
627
- providerOptions: {
628
- groq: {
629
- structuredOutputs: true,
630
- },
631
- },
632
- responseFormat: {
633
- type: 'json',
634
- name: 'test-name',
635
- description: 'test description',
636
- schema: {
637
- type: 'object',
638
- properties: { value: { type: 'string' } },
639
- required: ['value'],
640
- additionalProperties: false,
641
- $schema: 'http://json-schema.org/draft-07/schema#',
642
- },
643
- },
644
- prompt: TEST_PROMPT,
645
- });
646
-
647
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
648
- model: 'gemma2-9b-it',
649
- messages: [{ role: 'user', content: 'Hello' }],
650
- response_format: {
651
- type: 'json_schema',
652
- json_schema: {
653
- strict: true,
654
- name: 'test-name',
655
- description: 'test description',
656
- schema: {
657
- type: 'object',
658
- properties: { value: { type: 'string' } },
659
- required: ['value'],
660
- additionalProperties: false,
661
- $schema: 'http://json-schema.org/draft-07/schema#',
662
- },
663
- },
664
- },
665
- });
666
- });
667
-
668
- it('should allow explicit structuredOutputs override', async () => {
669
- prepareJsonResponse({ content: '{"value":"Spark"}' });
670
-
671
- const model = provider('gemma2-9b-it');
672
-
673
- await model.doGenerate({
674
- providerOptions: {
675
- groq: {
676
- structuredOutputs: true,
677
- },
678
- },
679
- responseFormat: {
680
- type: 'json',
681
- schema: {
682
- type: 'object',
683
- properties: { value: { type: 'string' } },
684
- required: ['value'],
685
- additionalProperties: false,
686
- $schema: 'http://json-schema.org/draft-07/schema#',
687
- },
688
- },
689
- prompt: TEST_PROMPT,
690
- });
691
-
692
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
693
- model: 'gemma2-9b-it',
694
- messages: [{ role: 'user', content: 'Hello' }],
695
- response_format: {
696
- type: 'json_schema',
697
- json_schema: {
698
- strict: true,
699
- name: 'response',
700
- schema: {
701
- type: 'object',
702
- properties: { value: { type: 'string' } },
703
- required: ['value'],
704
- additionalProperties: false,
705
- $schema: 'http://json-schema.org/draft-07/schema#',
706
- },
707
- },
708
- },
709
- });
710
- });
711
-
712
- it('should send strict: false when strictJsonSchema is explicitly disabled', async () => {
713
- prepareJsonResponse({ content: '{"value":"Spark"}' });
714
-
715
- const model = provider('gemma2-9b-it');
716
-
717
- await model.doGenerate({
718
- providerOptions: {
719
- groq: {
720
- strictJsonSchema: false,
721
- },
722
- },
723
- responseFormat: {
724
- type: 'json',
725
- name: 'test-name',
726
- description: 'test description',
727
- schema: {
728
- type: 'object',
729
- properties: { value: { type: 'string' } },
730
- required: ['value'],
731
- additionalProperties: false,
732
- $schema: 'http://json-schema.org/draft-07/schema#',
733
- },
734
- },
735
- prompt: TEST_PROMPT,
736
- });
737
-
738
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
739
- model: 'gemma2-9b-it',
740
- messages: [{ role: 'user', content: 'Hello' }],
741
- response_format: {
742
- type: 'json_schema',
743
- json_schema: {
744
- strict: false,
745
- name: 'test-name',
746
- description: 'test description',
747
- schema: {
748
- type: 'object',
749
- properties: { value: { type: 'string' } },
750
- required: ['value'],
751
- additionalProperties: false,
752
- $schema: 'http://json-schema.org/draft-07/schema#',
753
- },
754
- },
755
- },
756
- });
757
- });
758
-
759
- it('should handle structured outputs with Kimi K2 model', async () => {
760
- prepareJsonResponse({
761
- content:
762
- '{"recipe":{"name":"Spaghetti Aglio e Olio","ingredients":["spaghetti","garlic","olive oil","parmesan"],"instructions":["Boil pasta","Sauté garlic","Combine"]}}',
763
- });
764
-
765
- const kimiModel = provider('moonshotai/kimi-k2-instruct-0905');
766
-
767
- const result = await kimiModel.doGenerate({
768
- providerOptions: {
769
- groq: {
770
- structuredOutputs: true,
771
- },
772
- },
773
- responseFormat: {
774
- type: 'json',
775
- name: 'recipe_response',
776
- description: 'A recipe with ingredients and instructions',
777
- schema: {
778
- type: 'object',
779
- properties: {
780
- recipe: {
781
- type: 'object',
782
- properties: {
783
- name: { type: 'string' },
784
- ingredients: { type: 'array', items: { type: 'string' } },
785
- instructions: { type: 'array', items: { type: 'string' } },
786
- },
787
- required: ['name', 'ingredients', 'instructions'],
788
- },
789
- },
790
- required: ['recipe'],
791
- additionalProperties: false,
792
- $schema: 'http://json-schema.org/draft-07/schema#',
793
- },
794
- },
795
- prompt: [
796
- {
797
- role: 'user',
798
- content: [{ type: 'text', text: 'Generate a simple pasta recipe' }],
799
- },
800
- ],
801
- });
802
-
803
- expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(`
804
- {
805
- "messages": [
806
- {
807
- "content": "Generate a simple pasta recipe",
808
- "role": "user",
809
- },
810
- ],
811
- "model": "moonshotai/kimi-k2-instruct-0905",
812
- "response_format": {
813
- "json_schema": {
814
- "description": "A recipe with ingredients and instructions",
815
- "name": "recipe_response",
816
- "schema": {
817
- "$schema": "http://json-schema.org/draft-07/schema#",
818
- "additionalProperties": false,
819
- "properties": {
820
- "recipe": {
821
- "properties": {
822
- "ingredients": {
823
- "items": {
824
- "type": "string",
825
- },
826
- "type": "array",
827
- },
828
- "instructions": {
829
- "items": {
830
- "type": "string",
831
- },
832
- "type": "array",
833
- },
834
- "name": {
835
- "type": "string",
836
- },
837
- },
838
- "required": [
839
- "name",
840
- "ingredients",
841
- "instructions",
842
- ],
843
- "type": "object",
844
- },
845
- },
846
- "required": [
847
- "recipe",
848
- ],
849
- "type": "object",
850
- },
851
- "strict": true,
852
- },
853
- "type": "json_schema",
854
- },
855
- }
856
- `);
857
-
858
- expect(result.content).toMatchInlineSnapshot(`
859
- [
860
- {
861
- "text": "{"recipe":{"name":"Spaghetti Aglio e Olio","ingredients":["spaghetti","garlic","olive oil","parmesan"],"instructions":["Boil pasta","Sauté garlic","Combine"]}}",
862
- "type": "text",
863
- },
864
- ]
865
- `);
866
- });
867
-
868
- it('should include warnings when structured outputs explicitly disabled but schema provided', async () => {
869
- prepareJsonResponse({ content: '{"value":"test"}' });
870
-
871
- const { warnings } = await model.doGenerate({
872
- providerOptions: {
873
- groq: {
874
- structuredOutputs: false,
875
- },
876
- },
877
- responseFormat: {
878
- type: 'json',
879
- schema: {
880
- type: 'object',
881
- properties: { value: { type: 'string' } },
882
- required: ['value'],
883
- additionalProperties: false,
884
- $schema: 'http://json-schema.org/draft-07/schema#',
885
- },
886
- },
887
- prompt: TEST_PROMPT,
888
- });
889
-
890
- expect(warnings).toMatchInlineSnapshot(`
891
- [
892
- {
893
- "details": "JSON response format schema is only supported with structuredOutputs",
894
- "feature": "responseFormat",
895
- "type": "unsupported",
896
- },
897
- ]
898
- `);
899
- });
900
-
901
- it('should send request body', async () => {
902
- prepareJsonResponse({ content: '' });
903
-
904
- const { request } = await model.doGenerate({
905
- prompt: TEST_PROMPT,
906
- });
907
-
908
- expect(request).toStrictEqual({
909
- body: '{"model":"gemma2-9b-it","messages":[{"role":"user","content":"Hello"}]}',
910
- });
911
- });
912
- });
913
-
914
- describe('doStream', () => {
915
- function prepareStreamResponse({
916
- content = [],
917
- finish_reason = 'stop',
918
- headers,
919
- }: {
920
- content?: string[];
921
- finish_reason?: string;
922
- headers?: Record<string, string>;
923
- }) {
924
- server.urls['https://api.groq.com/openai/v1/chat/completions'].response = {
925
- type: 'stream-chunks',
926
- headers,
927
- chunks: [
928
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1702657020,"model":"gemma2-9b-it",` +
929
- `"system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}\n\n`,
930
- ...content.map(text => {
931
- return (
932
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1702657020,"model":"gemma2-9b-it",` +
933
- `"system_fingerprint":null,"choices":[{"index":1,"delta":{"content":"${text}"},"finish_reason":null}]}\n\n`
934
- );
935
- }),
936
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1702657020,"model":"gemma2-9b-it",` +
937
- `"system_fingerprint":null,"choices":[{"index":0,"delta":{},"finish_reason":"${finish_reason}"}]}\n\n`,
938
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1729171479,"model":"gemma2-9b-it",` +
939
- `"system_fingerprint":"fp_10c08bf97d","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"${finish_reason}"}],` +
940
- `"x_groq":{"id":"req_01jadadp0femyae9kav1gpkhe8","usage":{"queue_time":0.061348671,"prompt_tokens":18,"prompt_time":0.000211569,` +
941
- `"completion_tokens":439,"completion_time":0.798181818,"total_tokens":457,"total_time":0.798393387}}}\n\n`,
942
- 'data: [DONE]\n\n',
943
- ],
944
- };
945
- }
946
-
947
- it('should stream text deltas', async () => {
948
- prepareStreamResponse({
949
- content: ['Hello', ', ', 'World!'],
950
- finish_reason: 'stop',
951
- });
952
-
953
- const { stream } = await model.doStream({
954
- prompt: TEST_PROMPT,
955
- includeRawChunks: false,
956
- });
957
-
958
- // note: space moved to last chunk bc of trimming
959
- expect(await convertReadableStreamToArray(stream)).toMatchInlineSnapshot(`
960
- [
961
- {
962
- "type": "stream-start",
963
- "warnings": [],
964
- },
965
- {
966
- "id": "chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798",
967
- "modelId": "gemma2-9b-it",
968
- "timestamp": 2023-12-15T16:17:00.000Z,
969
- "type": "response-metadata",
970
- },
971
- {
972
- "id": "txt-0",
973
- "type": "text-start",
974
- },
975
- {
976
- "delta": "Hello",
977
- "id": "txt-0",
978
- "type": "text-delta",
979
- },
980
- {
981
- "delta": ", ",
982
- "id": "txt-0",
983
- "type": "text-delta",
984
- },
985
- {
986
- "delta": "World!",
987
- "id": "txt-0",
988
- "type": "text-delta",
989
- },
990
- {
991
- "id": "txt-0",
992
- "type": "text-end",
993
- },
994
- {
995
- "finishReason": {
996
- "raw": "stop",
997
- "unified": "stop",
998
- },
999
- "type": "finish",
1000
- "usage": {
1001
- "inputTokens": {
1002
- "cacheRead": undefined,
1003
- "cacheWrite": undefined,
1004
- "noCache": 18,
1005
- "total": 18,
1006
- },
1007
- "outputTokens": {
1008
- "reasoning": undefined,
1009
- "text": 439,
1010
- "total": 439,
1011
- },
1012
- "raw": {
1013
- "completion_tokens": 439,
1014
- "prompt_tokens": 18,
1015
- "total_tokens": 457,
1016
- },
1017
- },
1018
- },
1019
- ]
1020
- `);
1021
- });
1022
-
1023
- it('should stream reasoning deltas', async () => {
1024
- server.urls['https://api.groq.com/openai/v1/chat/completions'].response = {
1025
- type: 'stream-chunks',
1026
- chunks: [
1027
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1702657020,"model":"gemma2-9b-it",` +
1028
- `"system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}\n\n`,
1029
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1702657020,"model":"gemma2-9b-it",` +
1030
- `"system_fingerprint":null,"choices":[{"index":1,"delta":{"reasoning":"I think,"},"finish_reason":null}]}\n\n`,
1031
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1702657020,"model":"gemma2-9b-it",` +
1032
- `"system_fingerprint":null,"choices":[{"index":1,"delta":{"reasoning":"therefore I am."},"finish_reason":null}]}\n\n`,
1033
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1702657020,"model":"gemma2-9b-it",` +
1034
- `"system_fingerprint":null,"choices":[{"index":1,"delta":{"content":"Hello"},"finish_reason":null}]}\n\n`,
1035
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1702657020,"model":"gemma2-9b-it",` +
1036
- `"system_fingerprint":null,"choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}\n\n`,
1037
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1729171479,"model":"gemma2-9b-it",` +
1038
- `"system_fingerprint":"fp_10c08bf97d","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],` +
1039
- `"x_groq":{"id":"req_01jadadp0femyae9kav1gpkhe8","usage":{"queue_time":0.061348671,"prompt_tokens":18,"prompt_time":0.000211569,` +
1040
- `"completion_tokens":439,"completion_time":0.798181818,"total_tokens":457,"total_time":0.798393387}}}\n\n`,
1041
- 'data: [DONE]\n\n',
1042
- ],
1043
- };
1044
-
1045
- const { stream } = await model.doStream({
1046
- prompt: TEST_PROMPT,
1047
- includeRawChunks: false,
1048
- });
1049
-
1050
- expect(await convertReadableStreamToArray(stream)).toMatchInlineSnapshot(`
1051
- [
1052
- {
1053
- "type": "stream-start",
1054
- "warnings": [],
1055
- },
1056
- {
1057
- "id": "chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798",
1058
- "modelId": "gemma2-9b-it",
1059
- "timestamp": 2023-12-15T16:17:00.000Z,
1060
- "type": "response-metadata",
1061
- },
1062
- {
1063
- "id": "reasoning-0",
1064
- "type": "reasoning-start",
1065
- },
1066
- {
1067
- "delta": "I think,",
1068
- "id": "reasoning-0",
1069
- "type": "reasoning-delta",
1070
- },
1071
- {
1072
- "delta": "therefore I am.",
1073
- "id": "reasoning-0",
1074
- "type": "reasoning-delta",
1075
- },
1076
- {
1077
- "id": "reasoning-0",
1078
- "type": "reasoning-end",
1079
- },
1080
- {
1081
- "id": "txt-0",
1082
- "type": "text-start",
1083
- },
1084
- {
1085
- "delta": "Hello",
1086
- "id": "txt-0",
1087
- "type": "text-delta",
1088
- },
1089
- {
1090
- "id": "txt-0",
1091
- "type": "text-end",
1092
- },
1093
- {
1094
- "finishReason": {
1095
- "raw": "stop",
1096
- "unified": "stop",
1097
- },
1098
- "type": "finish",
1099
- "usage": {
1100
- "inputTokens": {
1101
- "cacheRead": undefined,
1102
- "cacheWrite": undefined,
1103
- "noCache": 18,
1104
- "total": 18,
1105
- },
1106
- "outputTokens": {
1107
- "reasoning": undefined,
1108
- "text": 439,
1109
- "total": 439,
1110
- },
1111
- "raw": {
1112
- "completion_tokens": 439,
1113
- "prompt_tokens": 18,
1114
- "total_tokens": 457,
1115
- },
1116
- },
1117
- },
1118
- ]
1119
- `);
1120
- });
1121
-
1122
- it('should stream reasoning tokens from completion_tokens_details', async () => {
1123
- server.urls['https://api.groq.com/openai/v1/chat/completions'].response = {
1124
- type: 'stream-chunks',
1125
- chunks: [
1126
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1702657020,"model":"openai/gpt-oss-120b",` +
1127
- `"system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}\n\n`,
1128
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1702657020,"model":"openai/gpt-oss-120b",` +
1129
- `"system_fingerprint":null,"choices":[{"index":1,"delta":{"content":"42"},"finish_reason":null}]}\n\n`,
1130
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1702657020,"model":"openai/gpt-oss-120b",` +
1131
- `"system_fingerprint":null,"choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}\n\n`,
1132
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1729171479,"model":"openai/gpt-oss-120b",` +
1133
- `"system_fingerprint":"fp_10c08bf97d","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],` +
1134
- `"x_groq":{"id":"req_01jadadp0femyae9kav1gpkhe8","usage":{"queue_time":0.061348671,"prompt_tokens":79,"prompt_time":0.000211569,` +
1135
- `"completion_tokens":40,"completion_time":0.798181818,"total_tokens":119,"total_time":0.798393387,` +
1136
- `"completion_tokens_details":{"reasoning_tokens":21}}}}\n\n`,
1137
- 'data: [DONE]\n\n',
1138
- ],
1139
- };
1140
-
1141
- const { stream } = await model.doStream({
1142
- prompt: TEST_PROMPT,
1143
- includeRawChunks: false,
1144
- });
1145
-
1146
- const chunks = await convertReadableStreamToArray(stream);
1147
- const finishChunk = chunks.find(chunk => chunk.type === 'finish');
1148
-
1149
- expect(finishChunk).toMatchInlineSnapshot(`
1150
- {
1151
- "finishReason": {
1152
- "raw": "stop",
1153
- "unified": "stop",
1154
- },
1155
- "type": "finish",
1156
- "usage": {
1157
- "inputTokens": {
1158
- "cacheRead": undefined,
1159
- "cacheWrite": undefined,
1160
- "noCache": 79,
1161
- "total": 79,
1162
- },
1163
- "outputTokens": {
1164
- "reasoning": 21,
1165
- "text": 19,
1166
- "total": 40,
1167
- },
1168
- "raw": {
1169
- "completion_tokens": 40,
1170
- "completion_tokens_details": {
1171
- "reasoning_tokens": 21,
1172
- },
1173
- "prompt_tokens": 79,
1174
- "total_tokens": 119,
1175
- },
1176
- },
1177
- }
1178
- `);
1179
- });
1180
-
1181
- it('should stream tool deltas', async () => {
1182
- server.urls['https://api.groq.com/openai/v1/chat/completions'].response = {
1183
- type: 'stream-chunks',
1184
- chunks: [
1185
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1186
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"role":"assistant","content":null,` +
1187
- `"tool_calls":[{"index":0,"id":"call_O17Uplv4lJvD6DVdIvFFeRMw","type":"function","function":{"name":"test-tool","arguments":""}}]},` +
1188
- `"finish_reason":null}]}\n\n`,
1189
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1190
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\\""}}]},` +
1191
- `"finish_reason":null}]}\n\n`,
1192
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1193
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"value"}}]},` +
1194
- `"finish_reason":null}]}\n\n`,
1195
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1196
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\\":\\""}}]},` +
1197
- `"finish_reason":null}]}\n\n`,
1198
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1199
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Spark"}}]},` +
1200
- `"finish_reason":null}]}\n\n`,
1201
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1202
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"le"}}]},` +
1203
- `"finish_reason":null}]}\n\n`,
1204
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1205
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" Day"}}]},` +
1206
- `"finish_reason":null}]}\n\n`,
1207
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1208
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\\"}"}}]},` +
1209
- `"finish_reason":null}]}\n\n`,
1210
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1729171479,"model":"gemma2-9b-it",` +
1211
- `"system_fingerprint":"fp_10c08bf97d","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"tool_calls"}],` +
1212
- `"x_groq":{"id":"req_01jadadp0femyae9kav1gpkhe8","usage":{"queue_time":0.061348671,"prompt_tokens":18,"prompt_time":0.000211569,` +
1213
- `"completion_tokens":439,"completion_time":0.798181818,"total_tokens":457,"total_time":0.798393387}}}\n\n`,
1214
- 'data: [DONE]\n\n',
1215
- ],
1216
- };
1217
-
1218
- const { stream } = await model.doStream({
1219
- tools: [
1220
- {
1221
- type: 'function',
1222
- name: 'test-tool',
1223
- inputSchema: {
1224
- type: 'object',
1225
- properties: { value: { type: 'string' } },
1226
- required: ['value'],
1227
- additionalProperties: false,
1228
- $schema: 'http://json-schema.org/draft-07/schema#',
1229
- },
1230
- },
1231
- ],
1232
- prompt: TEST_PROMPT,
1233
- includeRawChunks: false,
1234
- });
1235
-
1236
- expect(await convertReadableStreamToArray(stream)).toMatchInlineSnapshot(`
1237
- [
1238
- {
1239
- "type": "stream-start",
1240
- "warnings": [],
1241
- },
1242
- {
1243
- "id": "chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798",
1244
- "modelId": "gemma2-9b-it",
1245
- "timestamp": 2024-03-25T09:06:38.000Z,
1246
- "type": "response-metadata",
1247
- },
1248
- {
1249
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1250
- "toolName": "test-tool",
1251
- "type": "tool-input-start",
1252
- },
1253
- {
1254
- "delta": "{"",
1255
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1256
- "type": "tool-input-delta",
1257
- },
1258
- {
1259
- "delta": "value",
1260
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1261
- "type": "tool-input-delta",
1262
- },
1263
- {
1264
- "delta": "":"",
1265
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1266
- "type": "tool-input-delta",
1267
- },
1268
- {
1269
- "delta": "Spark",
1270
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1271
- "type": "tool-input-delta",
1272
- },
1273
- {
1274
- "delta": "le",
1275
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1276
- "type": "tool-input-delta",
1277
- },
1278
- {
1279
- "delta": " Day",
1280
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1281
- "type": "tool-input-delta",
1282
- },
1283
- {
1284
- "delta": ""}",
1285
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1286
- "type": "tool-input-delta",
1287
- },
1288
- {
1289
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1290
- "type": "tool-input-end",
1291
- },
1292
- {
1293
- "input": "{"value":"Sparkle Day"}",
1294
- "toolCallId": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1295
- "toolName": "test-tool",
1296
- "type": "tool-call",
1297
- },
1298
- {
1299
- "finishReason": {
1300
- "raw": "tool_calls",
1301
- "unified": "tool-calls",
1302
- },
1303
- "type": "finish",
1304
- "usage": {
1305
- "inputTokens": {
1306
- "cacheRead": undefined,
1307
- "cacheWrite": undefined,
1308
- "noCache": 18,
1309
- "total": 18,
1310
- },
1311
- "outputTokens": {
1312
- "reasoning": undefined,
1313
- "text": 439,
1314
- "total": 439,
1315
- },
1316
- "raw": {
1317
- "completion_tokens": 439,
1318
- "prompt_tokens": 18,
1319
- "total_tokens": 457,
1320
- },
1321
- },
1322
- },
1323
- ]
1324
- `);
1325
- });
1326
-
1327
- it('should stream tool call deltas when tool call arguments are passed in the first chunk', async () => {
1328
- server.urls['https://api.groq.com/openai/v1/chat/completions'].response = {
1329
- type: 'stream-chunks',
1330
- chunks: [
1331
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1332
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"role":"assistant","content":null,` +
1333
- `"tool_calls":[{"index":0,"id":"call_O17Uplv4lJvD6DVdIvFFeRMw","type":"function","function":{"name":"test-tool","arguments":"{\\""}}]},` +
1334
- `"finish_reason":null}]}\n\n`,
1335
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1336
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"va"}}]},` +
1337
- `"finish_reason":null}]}\n\n`,
1338
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1339
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"lue"}}]},` +
1340
- `"finish_reason":null}]}\n\n`,
1341
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1342
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\\":\\""}}]},` +
1343
- `"finish_reason":null}]}\n\n`,
1344
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1345
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Spark"}}]},` +
1346
- `"finish_reason":null}]}\n\n`,
1347
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1348
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"le"}}]},` +
1349
- `"finish_reason":null}]}\n\n`,
1350
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1351
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" Day"}}]},` +
1352
- `"finish_reason":null}]}\n\n`,
1353
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1354
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\\"}"}}]},` +
1355
- `"finish_reason":null}]}\n\n`,
1356
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1729171479,"model":"gemma2-9b-it",` +
1357
- `"system_fingerprint":"fp_10c08bf97d","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"tool_calls"}],` +
1358
- `"x_groq":{"id":"req_01jadadp0femyae9kav1gpkhe8","usage":{"queue_time":0.061348671,"prompt_tokens":18,"prompt_time":0.000211569,` +
1359
- `"completion_tokens":439,"completion_time":0.798181818,"total_tokens":457,"total_time":0.798393387}}}\n\n`,
1360
- 'data: [DONE]\n\n',
1361
- ],
1362
- };
1363
-
1364
- const { stream } = await model.doStream({
1365
- tools: [
1366
- {
1367
- type: 'function',
1368
- name: 'test-tool',
1369
- inputSchema: {
1370
- type: 'object',
1371
- properties: { value: { type: 'string' } },
1372
- required: ['value'],
1373
- additionalProperties: false,
1374
- $schema: 'http://json-schema.org/draft-07/schema#',
1375
- },
1376
- },
1377
- ],
1378
- prompt: TEST_PROMPT,
1379
- includeRawChunks: false,
1380
- });
1381
-
1382
- expect(await convertReadableStreamToArray(stream)).toMatchInlineSnapshot(`
1383
- [
1384
- {
1385
- "type": "stream-start",
1386
- "warnings": [],
1387
- },
1388
- {
1389
- "id": "chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798",
1390
- "modelId": "gemma2-9b-it",
1391
- "timestamp": 2024-03-25T09:06:38.000Z,
1392
- "type": "response-metadata",
1393
- },
1394
- {
1395
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1396
- "toolName": "test-tool",
1397
- "type": "tool-input-start",
1398
- },
1399
- {
1400
- "delta": "{"",
1401
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1402
- "type": "tool-input-delta",
1403
- },
1404
- {
1405
- "delta": "va",
1406
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1407
- "type": "tool-input-delta",
1408
- },
1409
- {
1410
- "delta": "lue",
1411
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1412
- "type": "tool-input-delta",
1413
- },
1414
- {
1415
- "delta": "":"",
1416
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1417
- "type": "tool-input-delta",
1418
- },
1419
- {
1420
- "delta": "Spark",
1421
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1422
- "type": "tool-input-delta",
1423
- },
1424
- {
1425
- "delta": "le",
1426
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1427
- "type": "tool-input-delta",
1428
- },
1429
- {
1430
- "delta": " Day",
1431
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1432
- "type": "tool-input-delta",
1433
- },
1434
- {
1435
- "delta": ""}",
1436
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1437
- "type": "tool-input-delta",
1438
- },
1439
- {
1440
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1441
- "type": "tool-input-end",
1442
- },
1443
- {
1444
- "input": "{"value":"Sparkle Day"}",
1445
- "toolCallId": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1446
- "toolName": "test-tool",
1447
- "type": "tool-call",
1448
- },
1449
- {
1450
- "finishReason": {
1451
- "raw": "tool_calls",
1452
- "unified": "tool-calls",
1453
- },
1454
- "type": "finish",
1455
- "usage": {
1456
- "inputTokens": {
1457
- "cacheRead": undefined,
1458
- "cacheWrite": undefined,
1459
- "noCache": 18,
1460
- "total": 18,
1461
- },
1462
- "outputTokens": {
1463
- "reasoning": undefined,
1464
- "text": 439,
1465
- "total": 439,
1466
- },
1467
- "raw": {
1468
- "completion_tokens": 439,
1469
- "prompt_tokens": 18,
1470
- "total_tokens": 457,
1471
- },
1472
- },
1473
- },
1474
- ]
1475
- `);
1476
- });
1477
-
1478
- it('should not duplicate tool calls when there is an additional empty chunk after the tool call has been completed', async () => {
1479
- server.urls['https://api.groq.com/openai/v1/chat/completions'].response = {
1480
- type: 'stream-chunks',
1481
- chunks: [
1482
- `data: {"id":"chat-2267f7e2910a4254bac0650ba74cfc1c","object":"chat.completion.chunk","created":1733162241,` +
1483
- `"model":"meta/llama-3.1-8b-instruct:fp8","choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}],` +
1484
- `"usage":{"prompt_tokens":226,"total_tokens":226,"completion_tokens":0}}\n\n`,
1485
- `data: {"id":"chat-2267f7e2910a4254bac0650ba74cfc1c","object":"chat.completion.chunk","created":1733162241,` +
1486
- `"model":"meta/llama-3.1-8b-instruct:fp8","choices":[{"index":0,"delta":{"tool_calls":[{"id":"chatcmpl-tool-b3b307239370432d9910d4b79b4dbbaa",` +
1487
- `"type":"function","index":0,"function":{"name":"searchGoogle"}}]},"logprobs":null,"finish_reason":null}],` +
1488
- `"usage":{"prompt_tokens":226,"total_tokens":233,"completion_tokens":7}}\n\n`,
1489
- `data: {"id":"chat-2267f7e2910a4254bac0650ba74cfc1c","object":"chat.completion.chunk","created":1733162241,` +
1490
- `"model":"meta/llama-3.1-8b-instruct:fp8","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,` +
1491
- `"function":{"arguments":"{\\"query\\": \\""}}]},"logprobs":null,"finish_reason":null}],` +
1492
- `"usage":{"prompt_tokens":226,"total_tokens":241,"completion_tokens":15}}\n\n`,
1493
- `data: {"id":"chat-2267f7e2910a4254bac0650ba74cfc1c","object":"chat.completion.chunk","created":1733162241,` +
1494
- `"model":"meta/llama-3.1-8b-instruct:fp8","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,` +
1495
- `"function":{"arguments":"latest"}}]},"logprobs":null,"finish_reason":null}],` +
1496
- `"usage":{"prompt_tokens":226,"total_tokens":242,"completion_tokens":16}}\n\n`,
1497
- `data: {"id":"chat-2267f7e2910a4254bac0650ba74cfc1c","object":"chat.completion.chunk","created":1733162241,` +
1498
- `"model":"meta/llama-3.1-8b-instruct:fp8","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,` +
1499
- `"function":{"arguments":" news"}}]},"logprobs":null,"finish_reason":null}],` +
1500
- `"usage":{"prompt_tokens":226,"total_tokens":243,"completion_tokens":17}}\n\n`,
1501
- `data: {"id":"chat-2267f7e2910a4254bac0650ba74cfc1c","object":"chat.completion.chunk","created":1733162241,` +
1502
- `"model":"meta/llama-3.1-8b-instruct:fp8","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,` +
1503
- `"function":{"arguments":" on"}}]},"logprobs":null,"finish_reason":null}],` +
1504
- `"usage":{"prompt_tokens":226,"total_tokens":244,"completion_tokens":18}}\n\n`,
1505
- `data: {"id":"chat-2267f7e2910a4254bac0650ba74cfc1c","object":"chat.completion.chunk","created":1733162241,` +
1506
- `"model":"meta/llama-3.1-8b-instruct:fp8","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,` +
1507
- `"function":{"arguments":" ai\\"}"}}]},"logprobs":null,"finish_reason":null}],` +
1508
- `"usage":{"prompt_tokens":226,"total_tokens":245,"completion_tokens":19}}\n\n`,
1509
- // empty arguments chunk after the tool call has already been finished:
1510
- `data: {"id":"chat-2267f7e2910a4254bac0650ba74cfc1c","object":"chat.completion.chunk","created":1733162241,` +
1511
- `"model":"meta/llama-3.1-8b-instruct:fp8","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,` +
1512
- `"function":{"arguments":""}}]},"logprobs":null,"finish_reason":"tool_calls","stop_reason":128008}],` +
1513
- `"usage":{"prompt_tokens":226,"total_tokens":246,"completion_tokens":20}}\n\n`,
1514
- `data: {"id":"chat-2267f7e2910a4254bac0650ba74cfc1c","object":"chat.completion.chunk","created":1733162241,` +
1515
- `"model":"meta/llama-3.1-8b-instruct:fp8","choices":[],` +
1516
- `"usage":{"prompt_tokens":226,"total_tokens":246,"completion_tokens":20}}\n\n`,
1517
- `data: [DONE]\n\n`,
1518
- ],
1519
- };
1520
-
1521
- const { stream } = await model.doStream({
1522
- tools: [
1523
- {
1524
- type: 'function',
1525
- name: 'searchGoogle',
1526
- inputSchema: {
1527
- type: 'object',
1528
- properties: { query: { type: 'string' } },
1529
- required: ['query'],
1530
- additionalProperties: false,
1531
- $schema: 'http://json-schema.org/draft-07/schema#',
1532
- },
1533
- },
1534
- ],
1535
- prompt: TEST_PROMPT,
1536
- includeRawChunks: false,
1537
- });
1538
-
1539
- expect(await convertReadableStreamToArray(stream)).toMatchInlineSnapshot(`
1540
- [
1541
- {
1542
- "type": "stream-start",
1543
- "warnings": [],
1544
- },
1545
- {
1546
- "id": "chat-2267f7e2910a4254bac0650ba74cfc1c",
1547
- "modelId": "meta/llama-3.1-8b-instruct:fp8",
1548
- "timestamp": 2024-12-02T17:57:21.000Z,
1549
- "type": "response-metadata",
1550
- },
1551
- {
1552
- "id": "chatcmpl-tool-b3b307239370432d9910d4b79b4dbbaa",
1553
- "toolName": "searchGoogle",
1554
- "type": "tool-input-start",
1555
- },
1556
- {
1557
- "delta": "{"query": "",
1558
- "id": "chatcmpl-tool-b3b307239370432d9910d4b79b4dbbaa",
1559
- "type": "tool-input-delta",
1560
- },
1561
- {
1562
- "delta": "latest",
1563
- "id": "chatcmpl-tool-b3b307239370432d9910d4b79b4dbbaa",
1564
- "type": "tool-input-delta",
1565
- },
1566
- {
1567
- "delta": " news",
1568
- "id": "chatcmpl-tool-b3b307239370432d9910d4b79b4dbbaa",
1569
- "type": "tool-input-delta",
1570
- },
1571
- {
1572
- "delta": " on",
1573
- "id": "chatcmpl-tool-b3b307239370432d9910d4b79b4dbbaa",
1574
- "type": "tool-input-delta",
1575
- },
1576
- {
1577
- "delta": " ai"}",
1578
- "id": "chatcmpl-tool-b3b307239370432d9910d4b79b4dbbaa",
1579
- "type": "tool-input-delta",
1580
- },
1581
- {
1582
- "id": "chatcmpl-tool-b3b307239370432d9910d4b79b4dbbaa",
1583
- "type": "tool-input-end",
1584
- },
1585
- {
1586
- "input": "{"query": "latest news on ai"}",
1587
- "toolCallId": "chatcmpl-tool-b3b307239370432d9910d4b79b4dbbaa",
1588
- "toolName": "searchGoogle",
1589
- "type": "tool-call",
1590
- },
1591
- {
1592
- "finishReason": {
1593
- "raw": "tool_calls",
1594
- "unified": "tool-calls",
1595
- },
1596
- "type": "finish",
1597
- "usage": {
1598
- "inputTokens": {
1599
- "cacheRead": undefined,
1600
- "cacheWrite": undefined,
1601
- "noCache": undefined,
1602
- "total": undefined,
1603
- },
1604
- "outputTokens": {
1605
- "reasoning": undefined,
1606
- "text": undefined,
1607
- "total": undefined,
1608
- },
1609
- "raw": undefined,
1610
- },
1611
- },
1612
- ]
1613
- `);
1614
- });
1615
-
1616
- it('should stream tool call that is sent in one chunk', async () => {
1617
- server.urls['https://api.groq.com/openai/v1/chat/completions'].response = {
1618
- type: 'stream-chunks',
1619
- chunks: [
1620
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1711357598,"model":"gemma2-9b-it",` +
1621
- `"system_fingerprint":"fp_3bc1b5746c","choices":[{"index":0,"delta":{"role":"assistant","content":null,` +
1622
- `"tool_calls":[{"index":0,"id":"call_O17Uplv4lJvD6DVdIvFFeRMw","type":"function","function":{"name":"test-tool","arguments":"{\\"value\\":\\"Sparkle Day\\"}"}}]},` +
1623
- `"finish_reason":null}]}\n\n`,
1624
- `data: {"id":"chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798","object":"chat.completion.chunk","created":1729171479,"model":"gemma2-9b-it",` +
1625
- `"system_fingerprint":"fp_10c08bf97d","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"tool_calls"}],` +
1626
- `"x_groq":{"id":"req_01jadadp0femyae9kav1gpkhe8","usage":{"queue_time":0.061348671,"prompt_tokens":18,"prompt_time":0.000211569,` +
1627
- `"completion_tokens":439,"completion_time":0.798181818,"total_tokens":457,"total_time":0.798393387}}}\n\n`,
1628
- 'data: [DONE]\n\n',
1629
- ],
1630
- };
1631
-
1632
- const { stream } = await model.doStream({
1633
- tools: [
1634
- {
1635
- type: 'function',
1636
- name: 'test-tool',
1637
- inputSchema: {
1638
- type: 'object',
1639
- properties: { value: { type: 'string' } },
1640
- required: ['value'],
1641
- additionalProperties: false,
1642
- $schema: 'http://json-schema.org/draft-07/schema#',
1643
- },
1644
- },
1645
- ],
1646
- prompt: TEST_PROMPT,
1647
- includeRawChunks: false,
1648
- });
1649
-
1650
- expect(await convertReadableStreamToArray(stream)).toMatchInlineSnapshot(`
1651
- [
1652
- {
1653
- "type": "stream-start",
1654
- "warnings": [],
1655
- },
1656
- {
1657
- "id": "chatcmpl-e7f8e220-656c-4455-a132-dacfc1370798",
1658
- "modelId": "gemma2-9b-it",
1659
- "timestamp": 2024-03-25T09:06:38.000Z,
1660
- "type": "response-metadata",
1661
- },
1662
- {
1663
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1664
- "toolName": "test-tool",
1665
- "type": "tool-input-start",
1666
- },
1667
- {
1668
- "delta": "{"value":"Sparkle Day"}",
1669
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1670
- "type": "tool-input-delta",
1671
- },
1672
- {
1673
- "id": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1674
- "type": "tool-input-end",
1675
- },
1676
- {
1677
- "input": "{"value":"Sparkle Day"}",
1678
- "toolCallId": "call_O17Uplv4lJvD6DVdIvFFeRMw",
1679
- "toolName": "test-tool",
1680
- "type": "tool-call",
1681
- },
1682
- {
1683
- "finishReason": {
1684
- "raw": "tool_calls",
1685
- "unified": "tool-calls",
1686
- },
1687
- "type": "finish",
1688
- "usage": {
1689
- "inputTokens": {
1690
- "cacheRead": undefined,
1691
- "cacheWrite": undefined,
1692
- "noCache": 18,
1693
- "total": 18,
1694
- },
1695
- "outputTokens": {
1696
- "reasoning": undefined,
1697
- "text": 439,
1698
- "total": 439,
1699
- },
1700
- "raw": {
1701
- "completion_tokens": 439,
1702
- "prompt_tokens": 18,
1703
- "total_tokens": 457,
1704
- },
1705
- },
1706
- },
1707
- ]
1708
- `);
1709
- });
1710
-
1711
- it('should handle error stream parts', async () => {
1712
- server.urls['https://api.groq.com/openai/v1/chat/completions'].response = {
1713
- type: 'stream-chunks',
1714
- chunks: [
1715
- `data: {"error":{"message": "The server had an error processing your request. Sorry about that!","type":"invalid_request_error"}}\n\n`,
1716
- 'data: [DONE]\n\n',
1717
- ],
1718
- };
1719
-
1720
- const { stream } = await model.doStream({
1721
- prompt: TEST_PROMPT,
1722
- includeRawChunks: false,
1723
- });
1724
-
1725
- expect(await convertReadableStreamToArray(stream)).toMatchInlineSnapshot(`
1726
- [
1727
- {
1728
- "type": "stream-start",
1729
- "warnings": [],
1730
- },
1731
- {
1732
- "error": {
1733
- "message": "The server had an error processing your request. Sorry about that!",
1734
- "type": "invalid_request_error",
1735
- },
1736
- "type": "error",
1737
- },
1738
- {
1739
- "finishReason": {
1740
- "raw": undefined,
1741
- "unified": "error",
1742
- },
1743
- "type": "finish",
1744
- "usage": {
1745
- "inputTokens": {
1746
- "cacheRead": undefined,
1747
- "cacheWrite": undefined,
1748
- "noCache": undefined,
1749
- "total": undefined,
1750
- },
1751
- "outputTokens": {
1752
- "reasoning": undefined,
1753
- "text": undefined,
1754
- "total": undefined,
1755
- },
1756
- "raw": undefined,
1757
- },
1758
- },
1759
- ]
1760
- `);
1761
- });
1762
-
1763
- it.skipIf(isNodeVersion(20))(
1764
- 'should handle unparsable stream parts',
1765
- async () => {
1766
- server.urls['https://api.groq.com/openai/v1/chat/completions'].response =
1767
- {
1768
- type: 'stream-chunks',
1769
- chunks: [`data: {unparsable}\n\n`, 'data: [DONE]\n\n'],
1770
- };
1771
-
1772
- const { stream } = await model.doStream({
1773
- prompt: TEST_PROMPT,
1774
- includeRawChunks: false,
1775
- });
1776
-
1777
- expect(await convertReadableStreamToArray(stream)).toMatchInlineSnapshot(`
1778
- [
1779
- {
1780
- "type": "stream-start",
1781
- "warnings": [],
1782
- },
1783
- {
1784
- "error": [AI_JSONParseError: JSON parsing failed: Text: {unparsable}.
1785
- Error message: Expected property name or '}' in JSON at position 1 (line 1 column 2)],
1786
- "type": "error",
1787
- },
1788
- {
1789
- "finishReason": {
1790
- "raw": undefined,
1791
- "unified": "error",
1792
- },
1793
- "type": "finish",
1794
- "usage": {
1795
- "inputTokens": {
1796
- "cacheRead": undefined,
1797
- "cacheWrite": undefined,
1798
- "noCache": undefined,
1799
- "total": undefined,
1800
- },
1801
- "outputTokens": {
1802
- "reasoning": undefined,
1803
- "text": undefined,
1804
- "total": undefined,
1805
- },
1806
- "raw": undefined,
1807
- },
1808
- },
1809
- ]
1810
- `);
1811
- },
1812
- );
1813
-
1814
- it('should expose the raw response headers', async () => {
1815
- prepareStreamResponse({
1816
- headers: {
1817
- 'test-header': 'test-value',
1818
- },
1819
- });
1820
-
1821
- const { response } = await model.doStream({
1822
- prompt: TEST_PROMPT,
1823
- includeRawChunks: false,
1824
- });
1825
-
1826
- expect(response?.headers).toStrictEqual({
1827
- // default headers:
1828
- 'content-type': 'text/event-stream',
1829
- 'cache-control': 'no-cache',
1830
- connection: 'keep-alive',
1831
-
1832
- // custom header
1833
- 'test-header': 'test-value',
1834
- });
1835
- });
1836
-
1837
- it('should pass the messages and the model', async () => {
1838
- prepareStreamResponse({ content: [] });
1839
-
1840
- await model.doStream({
1841
- prompt: TEST_PROMPT,
1842
- includeRawChunks: false,
1843
- });
1844
-
1845
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
1846
- stream: true,
1847
- model: 'gemma2-9b-it',
1848
- messages: [{ role: 'user', content: 'Hello' }],
1849
- });
1850
- });
1851
-
1852
- it('should pass headers', async () => {
1853
- prepareStreamResponse({ content: [] });
1854
-
1855
- const provider = createGroq({
1856
- apiKey: 'test-api-key',
1857
- headers: {
1858
- 'Custom-Provider-Header': 'provider-header-value',
1859
- },
1860
- });
1861
-
1862
- await provider('gemma2-9b-it').doStream({
1863
- prompt: TEST_PROMPT,
1864
- includeRawChunks: false,
1865
- headers: {
1866
- 'Custom-Request-Header': 'request-header-value',
1867
- },
1868
- });
1869
-
1870
- expect(server.calls[0].requestHeaders).toStrictEqual({
1871
- authorization: 'Bearer test-api-key',
1872
- 'content-type': 'application/json',
1873
- 'custom-provider-header': 'provider-header-value',
1874
- 'custom-request-header': 'request-header-value',
1875
- });
1876
- });
1877
-
1878
- it('should send request body', async () => {
1879
- prepareStreamResponse({ content: [] });
1880
-
1881
- const { request } = await model.doStream({
1882
- prompt: TEST_PROMPT,
1883
- includeRawChunks: false,
1884
- });
1885
-
1886
- expect(request).toStrictEqual({
1887
- body: '{"model":"gemma2-9b-it","messages":[{"role":"user","content":"Hello"}],"stream":true}',
1888
- });
1889
- });
1890
- });
1891
-
1892
- describe('doStream with raw chunks', () => {
1893
- it('should stream raw chunks when includeRawChunks is true', async () => {
1894
- server.urls['https://api.groq.com/openai/v1/chat/completions'].response = {
1895
- type: 'stream-chunks',
1896
- chunks: [
1897
- `data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1234567890,"model":"gemma2-9b-it","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}\n\n`,
1898
- `data: {"id":"chatcmpl-456","object":"chat.completion.chunk","created":1234567890,"model":"gemma2-9b-it","choices":[{"index":0,"delta":{"content":" world"},"finish_reason":null}]}\n\n`,
1899
- `data: {"id":"chatcmpl-789","object":"chat.completion.chunk","created":1234567890,"model":"gemma2-9b-it","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"x_groq":{"usage":{"prompt_tokens":10,"completion_tokens":5,"total_tokens":15}}}\n\n`,
1900
- 'data: [DONE]\n\n',
1901
- ],
1902
- };
1903
-
1904
- const { stream } = await model.doStream({
1905
- prompt: TEST_PROMPT,
1906
- includeRawChunks: true,
1907
- });
1908
-
1909
- const chunks = await convertReadableStreamToArray(stream);
1910
-
1911
- expect(chunks).toMatchInlineSnapshot(`
1912
- [
1913
- {
1914
- "type": "stream-start",
1915
- "warnings": [],
1916
- },
1917
- {
1918
- "rawValue": {
1919
- "choices": [
1920
- {
1921
- "delta": {
1922
- "content": "Hello",
1923
- },
1924
- "finish_reason": null,
1925
- "index": 0,
1926
- },
1927
- ],
1928
- "created": 1234567890,
1929
- "id": "chatcmpl-123",
1930
- "model": "gemma2-9b-it",
1931
- "object": "chat.completion.chunk",
1932
- },
1933
- "type": "raw",
1934
- },
1935
- {
1936
- "id": "chatcmpl-123",
1937
- "modelId": "gemma2-9b-it",
1938
- "timestamp": 2009-02-13T23:31:30.000Z,
1939
- "type": "response-metadata",
1940
- },
1941
- {
1942
- "id": "txt-0",
1943
- "type": "text-start",
1944
- },
1945
- {
1946
- "delta": "Hello",
1947
- "id": "txt-0",
1948
- "type": "text-delta",
1949
- },
1950
- {
1951
- "rawValue": {
1952
- "choices": [
1953
- {
1954
- "delta": {
1955
- "content": " world",
1956
- },
1957
- "finish_reason": null,
1958
- "index": 0,
1959
- },
1960
- ],
1961
- "created": 1234567890,
1962
- "id": "chatcmpl-456",
1963
- "model": "gemma2-9b-it",
1964
- "object": "chat.completion.chunk",
1965
- },
1966
- "type": "raw",
1967
- },
1968
- {
1969
- "delta": " world",
1970
- "id": "txt-0",
1971
- "type": "text-delta",
1972
- },
1973
- {
1974
- "rawValue": {
1975
- "choices": [
1976
- {
1977
- "delta": {},
1978
- "finish_reason": "stop",
1979
- "index": 0,
1980
- },
1981
- ],
1982
- "created": 1234567890,
1983
- "id": "chatcmpl-789",
1984
- "model": "gemma2-9b-it",
1985
- "object": "chat.completion.chunk",
1986
- "x_groq": {
1987
- "usage": {
1988
- "completion_tokens": 5,
1989
- "prompt_tokens": 10,
1990
- "total_tokens": 15,
1991
- },
1992
- },
1993
- },
1994
- "type": "raw",
1995
- },
1996
- {
1997
- "id": "txt-0",
1998
- "type": "text-end",
1999
- },
2000
- {
2001
- "finishReason": {
2002
- "raw": "stop",
2003
- "unified": "stop",
2004
- },
2005
- "type": "finish",
2006
- "usage": {
2007
- "inputTokens": {
2008
- "cacheRead": undefined,
2009
- "cacheWrite": undefined,
2010
- "noCache": 10,
2011
- "total": 10,
2012
- },
2013
- "outputTokens": {
2014
- "reasoning": undefined,
2015
- "text": 5,
2016
- "total": 5,
2017
- },
2018
- "raw": {
2019
- "completion_tokens": 5,
2020
- "prompt_tokens": 10,
2021
- "total_tokens": 15,
2022
- },
2023
- },
2024
- },
2025
- ]
2026
- `);
2027
- });
2028
- });