@ai-sdk/google 3.0.67 → 3.0.68

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.
@@ -0,0 +1,185 @@
1
+ import type {
2
+ LanguageModelV3FinishReason,
3
+ LanguageModelV3StreamPart,
4
+ SharedV3ProviderMetadata,
5
+ SharedV3Warning,
6
+ } from '@ai-sdk/provider';
7
+ import { convertGoogleInteractionsUsage } from './convert-google-interactions-usage';
8
+ import { type GoogleInteractionsResponse } from './google-interactions-api';
9
+ import { mapGoogleInteractionsFinishReason } from './map-google-interactions-finish-reason';
10
+ import { parseGoogleInteractionsOutputs } from './parse-google-interactions-outputs';
11
+
12
+ /**
13
+ * Synthesizes a `LanguageModelV3StreamPart` stream from a fully-resolved
14
+ * Interaction response (i.e. the `response` returned after polling a
15
+ * `background: true` agent call to a terminal status).
16
+ *
17
+ * Agent calls cannot use SSE (`stream: true` is incompatible with
18
+ * `background: true`), so we deterministically replay the polled outputs as a
19
+ * stream sequence in the same order/shape `buildGoogleInteractionsStreamTransform`
20
+ * would produce. Each text/reasoning block is emitted as a single delta — the
21
+ * server has already produced the whole block by the time we synthesize.
22
+ */
23
+ export function synthesizeGoogleInteractionsAgentStream({
24
+ response,
25
+ warnings,
26
+ generateId,
27
+ includeRawChunks,
28
+ headerServiceTier,
29
+ }: {
30
+ response: GoogleInteractionsResponse;
31
+ warnings: Array<SharedV3Warning>;
32
+ generateId: () => string;
33
+ includeRawChunks?: boolean;
34
+ headerServiceTier?: string;
35
+ }): ReadableStream<LanguageModelV3StreamPart> {
36
+ return new ReadableStream<LanguageModelV3StreamPart>({
37
+ start(controller) {
38
+ controller.enqueue({ type: 'stream-start', warnings });
39
+
40
+ const interactionId =
41
+ typeof response.id === 'string' && response.id.length > 0
42
+ ? response.id
43
+ : undefined;
44
+
45
+ let timestamp: Date | undefined;
46
+ const created = response.created;
47
+ if (typeof created === 'string') {
48
+ const parsed = new Date(created);
49
+ if (!Number.isNaN(parsed.getTime())) {
50
+ timestamp = parsed;
51
+ }
52
+ }
53
+
54
+ controller.enqueue({
55
+ type: 'response-metadata',
56
+ ...(interactionId != null ? { id: interactionId } : {}),
57
+ modelId: response.model ?? undefined,
58
+ ...(timestamp ? { timestamp } : {}),
59
+ });
60
+
61
+ if (includeRawChunks) {
62
+ controller.enqueue({ type: 'raw', rawValue: response });
63
+ }
64
+
65
+ const { content, hasFunctionCall } = parseGoogleInteractionsOutputs({
66
+ outputs: response.outputs ?? null,
67
+ generateId,
68
+ interactionId,
69
+ });
70
+
71
+ let blockCounter = 0;
72
+ const nextBlockId = () => `${interactionId ?? 'agent'}:${blockCounter++}`;
73
+
74
+ for (const part of content) {
75
+ switch (part.type) {
76
+ case 'text': {
77
+ const id = nextBlockId();
78
+ const providerMetadata = part.providerMetadata;
79
+ controller.enqueue({ type: 'text-start', id });
80
+ if (part.text.length > 0) {
81
+ controller.enqueue({ type: 'text-delta', id, delta: part.text });
82
+ }
83
+ controller.enqueue({
84
+ type: 'text-end',
85
+ id,
86
+ ...(providerMetadata ? { providerMetadata } : {}),
87
+ });
88
+ break;
89
+ }
90
+ case 'reasoning': {
91
+ const id = nextBlockId();
92
+ const providerMetadata = part.providerMetadata;
93
+ controller.enqueue({ type: 'reasoning-start', id });
94
+ if (part.text.length > 0) {
95
+ controller.enqueue({
96
+ type: 'reasoning-delta',
97
+ id,
98
+ delta: part.text,
99
+ });
100
+ }
101
+ controller.enqueue({
102
+ type: 'reasoning-end',
103
+ id,
104
+ ...(providerMetadata ? { providerMetadata } : {}),
105
+ });
106
+ break;
107
+ }
108
+ case 'tool-call': {
109
+ const providerMetadata = part.providerMetadata;
110
+ controller.enqueue({
111
+ type: 'tool-input-start',
112
+ id: part.toolCallId,
113
+ toolName: part.toolName,
114
+ ...(part.providerExecuted
115
+ ? { providerExecuted: part.providerExecuted }
116
+ : {}),
117
+ });
118
+ controller.enqueue({
119
+ type: 'tool-input-delta',
120
+ id: part.toolCallId,
121
+ delta: part.input,
122
+ });
123
+ controller.enqueue({
124
+ type: 'tool-input-end',
125
+ id: part.toolCallId,
126
+ });
127
+ controller.enqueue({
128
+ type: 'tool-call',
129
+ toolCallId: part.toolCallId,
130
+ toolName: part.toolName,
131
+ input: part.input,
132
+ ...(part.providerExecuted
133
+ ? { providerExecuted: part.providerExecuted }
134
+ : {}),
135
+ ...(providerMetadata ? { providerMetadata } : {}),
136
+ });
137
+ break;
138
+ }
139
+ case 'tool-result': {
140
+ controller.enqueue({
141
+ type: 'tool-result',
142
+ toolCallId: part.toolCallId,
143
+ toolName: part.toolName,
144
+ result: part.result,
145
+ });
146
+ break;
147
+ }
148
+ case 'source':
149
+ case 'file': {
150
+ controller.enqueue(part);
151
+ break;
152
+ }
153
+ default:
154
+ break;
155
+ }
156
+ }
157
+
158
+ const serviceTier = response.service_tier ?? headerServiceTier;
159
+
160
+ const finishReason: LanguageModelV3FinishReason = {
161
+ unified: mapGoogleInteractionsFinishReason({
162
+ status: response.status,
163
+ hasFunctionCall,
164
+ }),
165
+ raw: response.status,
166
+ };
167
+
168
+ const providerMetadata: SharedV3ProviderMetadata = {
169
+ google: {
170
+ ...(interactionId != null ? { interactionId } : {}),
171
+ ...(serviceTier != null ? { serviceTier } : {}),
172
+ },
173
+ };
174
+
175
+ controller.enqueue({
176
+ type: 'finish',
177
+ finishReason,
178
+ usage: convertGoogleInteractionsUsage(response.usage),
179
+ providerMetadata,
180
+ });
181
+
182
+ controller.close();
183
+ },
184
+ });
185
+ }