@tanstack/ai-gemini 0.10.3 → 0.10.4
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.
- package/dist/esm/adapters/summarize.d.ts +23 -48
- package/dist/esm/adapters/summarize.js +9 -159
- package/dist/esm/adapters/summarize.js.map +1 -1
- package/dist/esm/adapters/text.js +93 -95
- package/dist/esm/adapters/text.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -3
- package/package.json +3 -3
- package/src/adapters/summarize.ts +37 -252
- package/src/adapters/text.ts +93 -99
- package/src/index.ts +2 -5
package/src/adapters/text.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FinishReason } from '@google/genai'
|
|
2
|
+
import { EventType } from '@tanstack/ai'
|
|
2
3
|
import { BaseTextAdapter } from '@tanstack/ai/adapters'
|
|
3
4
|
import { convertToolsToProviderFormat } from '../tools/tool-converter'
|
|
4
5
|
import {
|
|
@@ -39,11 +40,6 @@ import type {
|
|
|
39
40
|
} from '../message-types'
|
|
40
41
|
import type { GeminiClientConfig } from '../utils'
|
|
41
42
|
|
|
42
|
-
/** Cast an event object to StreamChunk. Adapters construct events with string
|
|
43
|
-
* literal types which are structurally compatible with the EventType enum. */
|
|
44
|
-
const asChunk = (chunk: Record<string, unknown>) =>
|
|
45
|
-
chunk as unknown as StreamChunk
|
|
46
|
-
|
|
47
43
|
/**
|
|
48
44
|
* Configuration for Gemini text adapter
|
|
49
45
|
*/
|
|
@@ -136,15 +132,14 @@ export class GeminiTextAdapter<
|
|
|
136
132
|
|
|
137
133
|
yield* this.processStreamChunks(result, options, logger)
|
|
138
134
|
} catch (error) {
|
|
139
|
-
const timestamp = Date.now()
|
|
140
135
|
logger.errors('gemini.chatStream fatal', {
|
|
141
136
|
error,
|
|
142
137
|
source: 'gemini.chatStream',
|
|
143
138
|
})
|
|
144
|
-
yield
|
|
145
|
-
type:
|
|
139
|
+
yield {
|
|
140
|
+
type: EventType.RUN_ERROR,
|
|
146
141
|
model: options.model,
|
|
147
|
-
timestamp,
|
|
142
|
+
timestamp: Date.now(),
|
|
148
143
|
message:
|
|
149
144
|
error instanceof Error
|
|
150
145
|
? error.message
|
|
@@ -155,7 +150,7 @@ export class GeminiTextAdapter<
|
|
|
155
150
|
? error.message
|
|
156
151
|
: 'An unknown error occurred during the chat stream.',
|
|
157
152
|
},
|
|
158
|
-
}
|
|
153
|
+
}
|
|
159
154
|
}
|
|
160
155
|
}
|
|
161
156
|
|
|
@@ -240,7 +235,6 @@ export class GeminiTextAdapter<
|
|
|
240
235
|
logger: InternalLogger,
|
|
241
236
|
): AsyncIterable<StreamChunk> {
|
|
242
237
|
const model = options.model
|
|
243
|
-
const timestamp = Date.now()
|
|
244
238
|
let accumulatedContent = ''
|
|
245
239
|
let accumulatedThinking = ''
|
|
246
240
|
const toolCallMap = new Map<
|
|
@@ -271,13 +265,13 @@ export class GeminiTextAdapter<
|
|
|
271
265
|
// Emit RUN_STARTED on first chunk
|
|
272
266
|
if (!hasEmittedRunStarted) {
|
|
273
267
|
hasEmittedRunStarted = true
|
|
274
|
-
yield
|
|
275
|
-
type:
|
|
268
|
+
yield {
|
|
269
|
+
type: EventType.RUN_STARTED,
|
|
276
270
|
runId,
|
|
277
271
|
threadId,
|
|
278
272
|
model,
|
|
279
|
-
timestamp,
|
|
280
|
-
}
|
|
273
|
+
timestamp: Date.now(),
|
|
274
|
+
}
|
|
281
275
|
}
|
|
282
276
|
|
|
283
277
|
if (chunk.candidates?.[0]?.content?.parts) {
|
|
@@ -293,92 +287,92 @@ export class GeminiTextAdapter<
|
|
|
293
287
|
reasoningMessageId = generateId(this.name)
|
|
294
288
|
|
|
295
289
|
// Spec REASONING events
|
|
296
|
-
yield
|
|
297
|
-
type:
|
|
290
|
+
yield {
|
|
291
|
+
type: EventType.REASONING_START,
|
|
298
292
|
messageId: reasoningMessageId,
|
|
299
293
|
model,
|
|
300
|
-
timestamp,
|
|
301
|
-
}
|
|
302
|
-
yield
|
|
303
|
-
type:
|
|
294
|
+
timestamp: Date.now(),
|
|
295
|
+
}
|
|
296
|
+
yield {
|
|
297
|
+
type: EventType.REASONING_MESSAGE_START,
|
|
304
298
|
messageId: reasoningMessageId,
|
|
305
299
|
role: 'reasoning' as const,
|
|
306
300
|
model,
|
|
307
|
-
timestamp,
|
|
308
|
-
}
|
|
301
|
+
timestamp: Date.now(),
|
|
302
|
+
}
|
|
309
303
|
|
|
310
304
|
// Legacy STEP events (kept during transition)
|
|
311
|
-
yield
|
|
312
|
-
type:
|
|
305
|
+
yield {
|
|
306
|
+
type: EventType.STEP_STARTED,
|
|
313
307
|
stepName: stepId,
|
|
314
308
|
stepId,
|
|
315
309
|
model,
|
|
316
|
-
timestamp,
|
|
310
|
+
timestamp: Date.now(),
|
|
317
311
|
stepType: 'thinking',
|
|
318
|
-
}
|
|
312
|
+
}
|
|
319
313
|
}
|
|
320
314
|
|
|
321
315
|
accumulatedThinking += part.text
|
|
322
316
|
|
|
323
317
|
// Spec REASONING content event
|
|
324
|
-
yield
|
|
325
|
-
type:
|
|
318
|
+
yield {
|
|
319
|
+
type: EventType.REASONING_MESSAGE_CONTENT,
|
|
326
320
|
messageId: reasoningMessageId!,
|
|
327
321
|
delta: part.text,
|
|
328
322
|
model,
|
|
329
|
-
timestamp,
|
|
330
|
-
}
|
|
323
|
+
timestamp: Date.now(),
|
|
324
|
+
}
|
|
331
325
|
|
|
332
326
|
// Legacy STEP event
|
|
333
|
-
yield
|
|
334
|
-
type:
|
|
327
|
+
yield {
|
|
328
|
+
type: EventType.STEP_FINISHED,
|
|
335
329
|
stepName: stepId || generateId(this.name),
|
|
336
330
|
stepId: stepId || generateId(this.name),
|
|
337
331
|
model,
|
|
338
|
-
timestamp,
|
|
332
|
+
timestamp: Date.now(),
|
|
339
333
|
delta: part.text,
|
|
340
334
|
content: accumulatedThinking,
|
|
341
|
-
}
|
|
335
|
+
}
|
|
342
336
|
} else if (part.text.trim()) {
|
|
343
337
|
// Close reasoning before text starts
|
|
344
338
|
if (reasoningMessageId && !hasClosedReasoning) {
|
|
345
339
|
hasClosedReasoning = true
|
|
346
|
-
yield
|
|
347
|
-
type:
|
|
340
|
+
yield {
|
|
341
|
+
type: EventType.REASONING_MESSAGE_END,
|
|
348
342
|
messageId: reasoningMessageId,
|
|
349
343
|
model,
|
|
350
|
-
timestamp,
|
|
351
|
-
}
|
|
352
|
-
yield
|
|
353
|
-
type:
|
|
344
|
+
timestamp: Date.now(),
|
|
345
|
+
}
|
|
346
|
+
yield {
|
|
347
|
+
type: EventType.REASONING_END,
|
|
354
348
|
messageId: reasoningMessageId,
|
|
355
349
|
model,
|
|
356
|
-
timestamp,
|
|
357
|
-
}
|
|
350
|
+
timestamp: Date.now(),
|
|
351
|
+
}
|
|
358
352
|
}
|
|
359
353
|
|
|
360
354
|
// Skip whitespace-only text parts (e.g. "\n" during auto-continuation)
|
|
361
355
|
// Emit TEXT_MESSAGE_START on first text content
|
|
362
356
|
if (!hasEmittedTextMessageStart) {
|
|
363
357
|
hasEmittedTextMessageStart = true
|
|
364
|
-
yield
|
|
365
|
-
type:
|
|
358
|
+
yield {
|
|
359
|
+
type: EventType.TEXT_MESSAGE_START,
|
|
366
360
|
messageId,
|
|
367
361
|
model,
|
|
368
|
-
timestamp,
|
|
362
|
+
timestamp: Date.now(),
|
|
369
363
|
role: 'assistant',
|
|
370
|
-
}
|
|
364
|
+
}
|
|
371
365
|
}
|
|
372
366
|
|
|
373
367
|
accumulatedContent += part.text
|
|
374
|
-
yield
|
|
375
|
-
type:
|
|
368
|
+
yield {
|
|
369
|
+
type: EventType.TEXT_MESSAGE_CONTENT,
|
|
376
370
|
messageId,
|
|
377
371
|
model,
|
|
378
|
-
timestamp,
|
|
372
|
+
timestamp: Date.now(),
|
|
379
373
|
delta: part.text,
|
|
380
374
|
content: accumulatedContent,
|
|
381
|
-
}
|
|
375
|
+
}
|
|
382
376
|
}
|
|
383
377
|
}
|
|
384
378
|
|
|
@@ -430,31 +424,31 @@ export class GeminiTextAdapter<
|
|
|
430
424
|
// Emit TOOL_CALL_START if not already started
|
|
431
425
|
if (!toolCallData.started) {
|
|
432
426
|
toolCallData.started = true
|
|
433
|
-
yield
|
|
434
|
-
type:
|
|
427
|
+
yield {
|
|
428
|
+
type: EventType.TOOL_CALL_START,
|
|
435
429
|
toolCallId,
|
|
436
430
|
toolCallName: toolCallData.name,
|
|
437
431
|
toolName: toolCallData.name,
|
|
438
432
|
model,
|
|
439
|
-
timestamp,
|
|
433
|
+
timestamp: Date.now(),
|
|
440
434
|
index: toolCallData.index,
|
|
441
435
|
...(toolCallData.thoughtSignature && {
|
|
442
436
|
metadata: {
|
|
443
437
|
thoughtSignature: toolCallData.thoughtSignature,
|
|
444
438
|
} satisfies GeminiToolCallMetadata,
|
|
445
439
|
}),
|
|
446
|
-
}
|
|
440
|
+
}
|
|
447
441
|
}
|
|
448
442
|
|
|
449
443
|
// Emit TOOL_CALL_ARGS
|
|
450
|
-
yield
|
|
451
|
-
type:
|
|
444
|
+
yield {
|
|
445
|
+
type: EventType.TOOL_CALL_ARGS,
|
|
452
446
|
toolCallId,
|
|
453
447
|
model,
|
|
454
|
-
timestamp,
|
|
448
|
+
timestamp: Date.now(),
|
|
455
449
|
delta: toolCallData.args,
|
|
456
450
|
args: toolCallData.args,
|
|
457
|
-
}
|
|
451
|
+
}
|
|
458
452
|
}
|
|
459
453
|
}
|
|
460
454
|
} else if (chunk.data && chunk.data.trim()) {
|
|
@@ -462,24 +456,24 @@ export class GeminiTextAdapter<
|
|
|
462
456
|
// Emit TEXT_MESSAGE_START on first text content
|
|
463
457
|
if (!hasEmittedTextMessageStart) {
|
|
464
458
|
hasEmittedTextMessageStart = true
|
|
465
|
-
yield
|
|
466
|
-
type:
|
|
459
|
+
yield {
|
|
460
|
+
type: EventType.TEXT_MESSAGE_START,
|
|
467
461
|
messageId,
|
|
468
462
|
model,
|
|
469
|
-
timestamp,
|
|
463
|
+
timestamp: Date.now(),
|
|
470
464
|
role: 'assistant',
|
|
471
|
-
}
|
|
465
|
+
}
|
|
472
466
|
}
|
|
473
467
|
|
|
474
468
|
accumulatedContent += chunk.data
|
|
475
|
-
yield
|
|
476
|
-
type:
|
|
469
|
+
yield {
|
|
470
|
+
type: EventType.TEXT_MESSAGE_CONTENT,
|
|
477
471
|
messageId,
|
|
478
472
|
model,
|
|
479
|
-
timestamp,
|
|
473
|
+
timestamp: Date.now(),
|
|
480
474
|
delta: chunk.data,
|
|
481
475
|
content: accumulatedContent,
|
|
482
|
-
}
|
|
476
|
+
}
|
|
483
477
|
}
|
|
484
478
|
|
|
485
479
|
if (chunk.candidates?.[0]?.finishReason) {
|
|
@@ -508,15 +502,15 @@ export class GeminiTextAdapter<
|
|
|
508
502
|
})
|
|
509
503
|
|
|
510
504
|
// Emit TOOL_CALL_START
|
|
511
|
-
yield
|
|
512
|
-
type:
|
|
505
|
+
yield {
|
|
506
|
+
type: EventType.TOOL_CALL_START,
|
|
513
507
|
toolCallId,
|
|
514
508
|
toolCallName: functionCall.name || '',
|
|
515
509
|
toolName: functionCall.name || '',
|
|
516
510
|
model,
|
|
517
|
-
timestamp,
|
|
511
|
+
timestamp: Date.now(),
|
|
518
512
|
index: nextToolIndex - 1,
|
|
519
|
-
}
|
|
513
|
+
}
|
|
520
514
|
|
|
521
515
|
// Emit TOOL_CALL_END with parsed input
|
|
522
516
|
let parsedInput: unknown = {}
|
|
@@ -531,15 +525,15 @@ export class GeminiTextAdapter<
|
|
|
531
525
|
parsedInput = {}
|
|
532
526
|
}
|
|
533
527
|
|
|
534
|
-
yield
|
|
535
|
-
type:
|
|
528
|
+
yield {
|
|
529
|
+
type: EventType.TOOL_CALL_END,
|
|
536
530
|
toolCallId,
|
|
537
531
|
toolCallName: functionCall.name || '',
|
|
538
532
|
toolName: functionCall.name || '',
|
|
539
533
|
model,
|
|
540
|
-
timestamp,
|
|
534
|
+
timestamp: Date.now(),
|
|
541
535
|
input: parsedInput,
|
|
542
|
-
}
|
|
536
|
+
}
|
|
543
537
|
}
|
|
544
538
|
}
|
|
545
539
|
}
|
|
@@ -555,15 +549,15 @@ export class GeminiTextAdapter<
|
|
|
555
549
|
parsedInput = {}
|
|
556
550
|
}
|
|
557
551
|
|
|
558
|
-
yield
|
|
559
|
-
type:
|
|
552
|
+
yield {
|
|
553
|
+
type: EventType.TOOL_CALL_END,
|
|
560
554
|
toolCallId,
|
|
561
555
|
toolCallName: toolCallData.name,
|
|
562
556
|
toolName: toolCallData.name,
|
|
563
557
|
model,
|
|
564
|
-
timestamp,
|
|
558
|
+
timestamp: Date.now(),
|
|
565
559
|
input: parsedInput,
|
|
566
|
-
}
|
|
560
|
+
}
|
|
567
561
|
}
|
|
568
562
|
|
|
569
563
|
// Reset so a new TEXT_MESSAGE_START is emitted if text follows tool calls
|
|
@@ -572,11 +566,11 @@ export class GeminiTextAdapter<
|
|
|
572
566
|
}
|
|
573
567
|
|
|
574
568
|
if (finishReason === FinishReason.MAX_TOKENS) {
|
|
575
|
-
yield
|
|
576
|
-
type:
|
|
569
|
+
yield {
|
|
570
|
+
type: EventType.RUN_ERROR,
|
|
577
571
|
runId,
|
|
578
572
|
model,
|
|
579
|
-
timestamp,
|
|
573
|
+
timestamp: Date.now(),
|
|
580
574
|
message:
|
|
581
575
|
'The response was cut off because the maximum token limit was reached.',
|
|
582
576
|
code: 'max_tokens',
|
|
@@ -585,42 +579,42 @@ export class GeminiTextAdapter<
|
|
|
585
579
|
'The response was cut off because the maximum token limit was reached.',
|
|
586
580
|
code: 'max_tokens',
|
|
587
581
|
},
|
|
588
|
-
}
|
|
582
|
+
}
|
|
589
583
|
}
|
|
590
584
|
|
|
591
585
|
// Close reasoning events if still open
|
|
592
586
|
if (reasoningMessageId && !hasClosedReasoning) {
|
|
593
587
|
hasClosedReasoning = true
|
|
594
|
-
yield
|
|
595
|
-
type:
|
|
588
|
+
yield {
|
|
589
|
+
type: EventType.REASONING_MESSAGE_END,
|
|
596
590
|
messageId: reasoningMessageId,
|
|
597
591
|
model,
|
|
598
|
-
timestamp,
|
|
599
|
-
}
|
|
600
|
-
yield
|
|
601
|
-
type:
|
|
592
|
+
timestamp: Date.now(),
|
|
593
|
+
}
|
|
594
|
+
yield {
|
|
595
|
+
type: EventType.REASONING_END,
|
|
602
596
|
messageId: reasoningMessageId,
|
|
603
597
|
model,
|
|
604
|
-
timestamp,
|
|
605
|
-
}
|
|
598
|
+
timestamp: Date.now(),
|
|
599
|
+
}
|
|
606
600
|
}
|
|
607
601
|
|
|
608
602
|
// Emit TEXT_MESSAGE_END if we had text content
|
|
609
603
|
if (hasEmittedTextMessageStart) {
|
|
610
|
-
yield
|
|
611
|
-
type:
|
|
604
|
+
yield {
|
|
605
|
+
type: EventType.TEXT_MESSAGE_END,
|
|
612
606
|
messageId,
|
|
613
607
|
model,
|
|
614
|
-
timestamp,
|
|
615
|
-
}
|
|
608
|
+
timestamp: Date.now(),
|
|
609
|
+
}
|
|
616
610
|
}
|
|
617
611
|
|
|
618
|
-
yield
|
|
619
|
-
type:
|
|
612
|
+
yield {
|
|
613
|
+
type: EventType.RUN_FINISHED,
|
|
620
614
|
runId,
|
|
621
615
|
threadId,
|
|
622
616
|
model,
|
|
623
|
-
timestamp,
|
|
617
|
+
timestamp: Date.now(),
|
|
624
618
|
finishReason: toolCallMap.size > 0 ? 'tool_calls' : 'stop',
|
|
625
619
|
usage: chunk.usageMetadata
|
|
626
620
|
? {
|
|
@@ -629,7 +623,7 @@ export class GeminiTextAdapter<
|
|
|
629
623
|
totalTokens: chunk.usageMetadata.totalTokenCount ?? 0,
|
|
630
624
|
}
|
|
631
625
|
: undefined,
|
|
632
|
-
}
|
|
626
|
+
}
|
|
633
627
|
}
|
|
634
628
|
}
|
|
635
629
|
}
|
package/src/index.ts
CHANGED
|
@@ -11,15 +11,12 @@ export {
|
|
|
11
11
|
type GeminiTextProviderOptions,
|
|
12
12
|
} from './adapters/text'
|
|
13
13
|
|
|
14
|
-
// Summarize
|
|
14
|
+
// Summarize - thin factory functions over @tanstack/ai's ChatStreamSummarizeAdapter
|
|
15
15
|
export {
|
|
16
|
-
GeminiSummarizeAdapter,
|
|
17
|
-
GeminiSummarizeModels,
|
|
18
16
|
createGeminiSummarize,
|
|
19
17
|
geminiSummarize,
|
|
20
|
-
type
|
|
18
|
+
type GeminiSummarizeConfig,
|
|
21
19
|
type GeminiSummarizeModel,
|
|
22
|
-
type GeminiSummarizeProviderOptions,
|
|
23
20
|
} from './adapters/summarize'
|
|
24
21
|
|
|
25
22
|
// Image adapter
|