@tanstack/ai-gemini 0.10.3 → 0.10.5
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 +94 -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 +94 -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,14 @@ 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
|
+
parentRunId: options.parentRunId,
|
|
275
|
+
}
|
|
281
276
|
}
|
|
282
277
|
|
|
283
278
|
if (chunk.candidates?.[0]?.content?.parts) {
|
|
@@ -293,92 +288,92 @@ export class GeminiTextAdapter<
|
|
|
293
288
|
reasoningMessageId = generateId(this.name)
|
|
294
289
|
|
|
295
290
|
// Spec REASONING events
|
|
296
|
-
yield
|
|
297
|
-
type:
|
|
291
|
+
yield {
|
|
292
|
+
type: EventType.REASONING_START,
|
|
298
293
|
messageId: reasoningMessageId,
|
|
299
294
|
model,
|
|
300
|
-
timestamp,
|
|
301
|
-
}
|
|
302
|
-
yield
|
|
303
|
-
type:
|
|
295
|
+
timestamp: Date.now(),
|
|
296
|
+
}
|
|
297
|
+
yield {
|
|
298
|
+
type: EventType.REASONING_MESSAGE_START,
|
|
304
299
|
messageId: reasoningMessageId,
|
|
305
300
|
role: 'reasoning' as const,
|
|
306
301
|
model,
|
|
307
|
-
timestamp,
|
|
308
|
-
}
|
|
302
|
+
timestamp: Date.now(),
|
|
303
|
+
}
|
|
309
304
|
|
|
310
305
|
// Legacy STEP events (kept during transition)
|
|
311
|
-
yield
|
|
312
|
-
type:
|
|
306
|
+
yield {
|
|
307
|
+
type: EventType.STEP_STARTED,
|
|
313
308
|
stepName: stepId,
|
|
314
309
|
stepId,
|
|
315
310
|
model,
|
|
316
|
-
timestamp,
|
|
311
|
+
timestamp: Date.now(),
|
|
317
312
|
stepType: 'thinking',
|
|
318
|
-
}
|
|
313
|
+
}
|
|
319
314
|
}
|
|
320
315
|
|
|
321
316
|
accumulatedThinking += part.text
|
|
322
317
|
|
|
323
318
|
// Spec REASONING content event
|
|
324
|
-
yield
|
|
325
|
-
type:
|
|
319
|
+
yield {
|
|
320
|
+
type: EventType.REASONING_MESSAGE_CONTENT,
|
|
326
321
|
messageId: reasoningMessageId!,
|
|
327
322
|
delta: part.text,
|
|
328
323
|
model,
|
|
329
|
-
timestamp,
|
|
330
|
-
}
|
|
324
|
+
timestamp: Date.now(),
|
|
325
|
+
}
|
|
331
326
|
|
|
332
327
|
// Legacy STEP event
|
|
333
|
-
yield
|
|
334
|
-
type:
|
|
328
|
+
yield {
|
|
329
|
+
type: EventType.STEP_FINISHED,
|
|
335
330
|
stepName: stepId || generateId(this.name),
|
|
336
331
|
stepId: stepId || generateId(this.name),
|
|
337
332
|
model,
|
|
338
|
-
timestamp,
|
|
333
|
+
timestamp: Date.now(),
|
|
339
334
|
delta: part.text,
|
|
340
335
|
content: accumulatedThinking,
|
|
341
|
-
}
|
|
336
|
+
}
|
|
342
337
|
} else if (part.text.trim()) {
|
|
343
338
|
// Close reasoning before text starts
|
|
344
339
|
if (reasoningMessageId && !hasClosedReasoning) {
|
|
345
340
|
hasClosedReasoning = true
|
|
346
|
-
yield
|
|
347
|
-
type:
|
|
341
|
+
yield {
|
|
342
|
+
type: EventType.REASONING_MESSAGE_END,
|
|
348
343
|
messageId: reasoningMessageId,
|
|
349
344
|
model,
|
|
350
|
-
timestamp,
|
|
351
|
-
}
|
|
352
|
-
yield
|
|
353
|
-
type:
|
|
345
|
+
timestamp: Date.now(),
|
|
346
|
+
}
|
|
347
|
+
yield {
|
|
348
|
+
type: EventType.REASONING_END,
|
|
354
349
|
messageId: reasoningMessageId,
|
|
355
350
|
model,
|
|
356
|
-
timestamp,
|
|
357
|
-
}
|
|
351
|
+
timestamp: Date.now(),
|
|
352
|
+
}
|
|
358
353
|
}
|
|
359
354
|
|
|
360
355
|
// Skip whitespace-only text parts (e.g. "\n" during auto-continuation)
|
|
361
356
|
// Emit TEXT_MESSAGE_START on first text content
|
|
362
357
|
if (!hasEmittedTextMessageStart) {
|
|
363
358
|
hasEmittedTextMessageStart = true
|
|
364
|
-
yield
|
|
365
|
-
type:
|
|
359
|
+
yield {
|
|
360
|
+
type: EventType.TEXT_MESSAGE_START,
|
|
366
361
|
messageId,
|
|
367
362
|
model,
|
|
368
|
-
timestamp,
|
|
363
|
+
timestamp: Date.now(),
|
|
369
364
|
role: 'assistant',
|
|
370
|
-
}
|
|
365
|
+
}
|
|
371
366
|
}
|
|
372
367
|
|
|
373
368
|
accumulatedContent += part.text
|
|
374
|
-
yield
|
|
375
|
-
type:
|
|
369
|
+
yield {
|
|
370
|
+
type: EventType.TEXT_MESSAGE_CONTENT,
|
|
376
371
|
messageId,
|
|
377
372
|
model,
|
|
378
|
-
timestamp,
|
|
373
|
+
timestamp: Date.now(),
|
|
379
374
|
delta: part.text,
|
|
380
375
|
content: accumulatedContent,
|
|
381
|
-
}
|
|
376
|
+
}
|
|
382
377
|
}
|
|
383
378
|
}
|
|
384
379
|
|
|
@@ -430,31 +425,31 @@ export class GeminiTextAdapter<
|
|
|
430
425
|
// Emit TOOL_CALL_START if not already started
|
|
431
426
|
if (!toolCallData.started) {
|
|
432
427
|
toolCallData.started = true
|
|
433
|
-
yield
|
|
434
|
-
type:
|
|
428
|
+
yield {
|
|
429
|
+
type: EventType.TOOL_CALL_START,
|
|
435
430
|
toolCallId,
|
|
436
431
|
toolCallName: toolCallData.name,
|
|
437
432
|
toolName: toolCallData.name,
|
|
438
433
|
model,
|
|
439
|
-
timestamp,
|
|
434
|
+
timestamp: Date.now(),
|
|
440
435
|
index: toolCallData.index,
|
|
441
436
|
...(toolCallData.thoughtSignature && {
|
|
442
437
|
metadata: {
|
|
443
438
|
thoughtSignature: toolCallData.thoughtSignature,
|
|
444
439
|
} satisfies GeminiToolCallMetadata,
|
|
445
440
|
}),
|
|
446
|
-
}
|
|
441
|
+
}
|
|
447
442
|
}
|
|
448
443
|
|
|
449
444
|
// Emit TOOL_CALL_ARGS
|
|
450
|
-
yield
|
|
451
|
-
type:
|
|
445
|
+
yield {
|
|
446
|
+
type: EventType.TOOL_CALL_ARGS,
|
|
452
447
|
toolCallId,
|
|
453
448
|
model,
|
|
454
|
-
timestamp,
|
|
449
|
+
timestamp: Date.now(),
|
|
455
450
|
delta: toolCallData.args,
|
|
456
451
|
args: toolCallData.args,
|
|
457
|
-
}
|
|
452
|
+
}
|
|
458
453
|
}
|
|
459
454
|
}
|
|
460
455
|
} else if (chunk.data && chunk.data.trim()) {
|
|
@@ -462,24 +457,24 @@ export class GeminiTextAdapter<
|
|
|
462
457
|
// Emit TEXT_MESSAGE_START on first text content
|
|
463
458
|
if (!hasEmittedTextMessageStart) {
|
|
464
459
|
hasEmittedTextMessageStart = true
|
|
465
|
-
yield
|
|
466
|
-
type:
|
|
460
|
+
yield {
|
|
461
|
+
type: EventType.TEXT_MESSAGE_START,
|
|
467
462
|
messageId,
|
|
468
463
|
model,
|
|
469
|
-
timestamp,
|
|
464
|
+
timestamp: Date.now(),
|
|
470
465
|
role: 'assistant',
|
|
471
|
-
}
|
|
466
|
+
}
|
|
472
467
|
}
|
|
473
468
|
|
|
474
469
|
accumulatedContent += chunk.data
|
|
475
|
-
yield
|
|
476
|
-
type:
|
|
470
|
+
yield {
|
|
471
|
+
type: EventType.TEXT_MESSAGE_CONTENT,
|
|
477
472
|
messageId,
|
|
478
473
|
model,
|
|
479
|
-
timestamp,
|
|
474
|
+
timestamp: Date.now(),
|
|
480
475
|
delta: chunk.data,
|
|
481
476
|
content: accumulatedContent,
|
|
482
|
-
}
|
|
477
|
+
}
|
|
483
478
|
}
|
|
484
479
|
|
|
485
480
|
if (chunk.candidates?.[0]?.finishReason) {
|
|
@@ -508,15 +503,15 @@ export class GeminiTextAdapter<
|
|
|
508
503
|
})
|
|
509
504
|
|
|
510
505
|
// Emit TOOL_CALL_START
|
|
511
|
-
yield
|
|
512
|
-
type:
|
|
506
|
+
yield {
|
|
507
|
+
type: EventType.TOOL_CALL_START,
|
|
513
508
|
toolCallId,
|
|
514
509
|
toolCallName: functionCall.name || '',
|
|
515
510
|
toolName: functionCall.name || '',
|
|
516
511
|
model,
|
|
517
|
-
timestamp,
|
|
512
|
+
timestamp: Date.now(),
|
|
518
513
|
index: nextToolIndex - 1,
|
|
519
|
-
}
|
|
514
|
+
}
|
|
520
515
|
|
|
521
516
|
// Emit TOOL_CALL_END with parsed input
|
|
522
517
|
let parsedInput: unknown = {}
|
|
@@ -531,15 +526,15 @@ export class GeminiTextAdapter<
|
|
|
531
526
|
parsedInput = {}
|
|
532
527
|
}
|
|
533
528
|
|
|
534
|
-
yield
|
|
535
|
-
type:
|
|
529
|
+
yield {
|
|
530
|
+
type: EventType.TOOL_CALL_END,
|
|
536
531
|
toolCallId,
|
|
537
532
|
toolCallName: functionCall.name || '',
|
|
538
533
|
toolName: functionCall.name || '',
|
|
539
534
|
model,
|
|
540
|
-
timestamp,
|
|
535
|
+
timestamp: Date.now(),
|
|
541
536
|
input: parsedInput,
|
|
542
|
-
}
|
|
537
|
+
}
|
|
543
538
|
}
|
|
544
539
|
}
|
|
545
540
|
}
|
|
@@ -555,15 +550,15 @@ export class GeminiTextAdapter<
|
|
|
555
550
|
parsedInput = {}
|
|
556
551
|
}
|
|
557
552
|
|
|
558
|
-
yield
|
|
559
|
-
type:
|
|
553
|
+
yield {
|
|
554
|
+
type: EventType.TOOL_CALL_END,
|
|
560
555
|
toolCallId,
|
|
561
556
|
toolCallName: toolCallData.name,
|
|
562
557
|
toolName: toolCallData.name,
|
|
563
558
|
model,
|
|
564
|
-
timestamp,
|
|
559
|
+
timestamp: Date.now(),
|
|
565
560
|
input: parsedInput,
|
|
566
|
-
}
|
|
561
|
+
}
|
|
567
562
|
}
|
|
568
563
|
|
|
569
564
|
// Reset so a new TEXT_MESSAGE_START is emitted if text follows tool calls
|
|
@@ -572,11 +567,11 @@ export class GeminiTextAdapter<
|
|
|
572
567
|
}
|
|
573
568
|
|
|
574
569
|
if (finishReason === FinishReason.MAX_TOKENS) {
|
|
575
|
-
yield
|
|
576
|
-
type:
|
|
570
|
+
yield {
|
|
571
|
+
type: EventType.RUN_ERROR,
|
|
577
572
|
runId,
|
|
578
573
|
model,
|
|
579
|
-
timestamp,
|
|
574
|
+
timestamp: Date.now(),
|
|
580
575
|
message:
|
|
581
576
|
'The response was cut off because the maximum token limit was reached.',
|
|
582
577
|
code: 'max_tokens',
|
|
@@ -585,42 +580,42 @@ export class GeminiTextAdapter<
|
|
|
585
580
|
'The response was cut off because the maximum token limit was reached.',
|
|
586
581
|
code: 'max_tokens',
|
|
587
582
|
},
|
|
588
|
-
}
|
|
583
|
+
}
|
|
589
584
|
}
|
|
590
585
|
|
|
591
586
|
// Close reasoning events if still open
|
|
592
587
|
if (reasoningMessageId && !hasClosedReasoning) {
|
|
593
588
|
hasClosedReasoning = true
|
|
594
|
-
yield
|
|
595
|
-
type:
|
|
589
|
+
yield {
|
|
590
|
+
type: EventType.REASONING_MESSAGE_END,
|
|
596
591
|
messageId: reasoningMessageId,
|
|
597
592
|
model,
|
|
598
|
-
timestamp,
|
|
599
|
-
}
|
|
600
|
-
yield
|
|
601
|
-
type:
|
|
593
|
+
timestamp: Date.now(),
|
|
594
|
+
}
|
|
595
|
+
yield {
|
|
596
|
+
type: EventType.REASONING_END,
|
|
602
597
|
messageId: reasoningMessageId,
|
|
603
598
|
model,
|
|
604
|
-
timestamp,
|
|
605
|
-
}
|
|
599
|
+
timestamp: Date.now(),
|
|
600
|
+
}
|
|
606
601
|
}
|
|
607
602
|
|
|
608
603
|
// Emit TEXT_MESSAGE_END if we had text content
|
|
609
604
|
if (hasEmittedTextMessageStart) {
|
|
610
|
-
yield
|
|
611
|
-
type:
|
|
605
|
+
yield {
|
|
606
|
+
type: EventType.TEXT_MESSAGE_END,
|
|
612
607
|
messageId,
|
|
613
608
|
model,
|
|
614
|
-
timestamp,
|
|
615
|
-
}
|
|
609
|
+
timestamp: Date.now(),
|
|
610
|
+
}
|
|
616
611
|
}
|
|
617
612
|
|
|
618
|
-
yield
|
|
619
|
-
type:
|
|
613
|
+
yield {
|
|
614
|
+
type: EventType.RUN_FINISHED,
|
|
620
615
|
runId,
|
|
621
616
|
threadId,
|
|
622
617
|
model,
|
|
623
|
-
timestamp,
|
|
618
|
+
timestamp: Date.now(),
|
|
624
619
|
finishReason: toolCallMap.size > 0 ? 'tool_calls' : 'stop',
|
|
625
620
|
usage: chunk.usageMetadata
|
|
626
621
|
? {
|
|
@@ -629,7 +624,7 @@ export class GeminiTextAdapter<
|
|
|
629
624
|
totalTokens: chunk.usageMetadata.totalTokenCount ?? 0,
|
|
630
625
|
}
|
|
631
626
|
: undefined,
|
|
632
|
-
}
|
|
627
|
+
}
|
|
633
628
|
}
|
|
634
629
|
}
|
|
635
630
|
}
|
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
|