cloudassist-ai-provider 0.0.1

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.
Files changed (117) hide show
  1. package/CHANGELOG.md +1901 -0
  2. package/README.md +35 -0
  3. package/dist/convert-json-schema-to-openapi-schema.d.ts +6 -0
  4. package/dist/convert-json-schema-to-openapi-schema.d.ts.map +1 -0
  5. package/dist/convert-json-schema-to-openapi-schema.js +108 -0
  6. package/dist/convert-json-schema-to-openapi-schema.test.d.ts +2 -0
  7. package/dist/convert-json-schema-to-openapi-schema.test.d.ts.map +1 -0
  8. package/dist/convert-json-schema-to-openapi-schema.test.js +630 -0
  9. package/dist/convert-to-google-generative-ai-messages.d.ts +7 -0
  10. package/dist/convert-to-google-generative-ai-messages.d.ts.map +1 -0
  11. package/dist/convert-to-google-generative-ai-messages.js +195 -0
  12. package/dist/convert-to-google-generative-ai-messages.test.d.ts +2 -0
  13. package/dist/convert-to-google-generative-ai-messages.test.d.ts.map +1 -0
  14. package/dist/convert-to-google-generative-ai-messages.test.js +456 -0
  15. package/dist/get-model-path.d.ts +2 -0
  16. package/dist/get-model-path.d.ts.map +1 -0
  17. package/dist/get-model-path.js +3 -0
  18. package/dist/get-model-path.test.d.ts +2 -0
  19. package/dist/get-model-path.test.d.ts.map +1 -0
  20. package/dist/get-model-path.test.js +11 -0
  21. package/dist/google-error.d.ts +12 -0
  22. package/dist/google-error.d.ts.map +1 -0
  23. package/dist/google-error.js +13 -0
  24. package/dist/google-generative-ai-embedding-model.d.ts +21 -0
  25. package/dist/google-generative-ai-embedding-model.d.ts.map +1 -0
  26. package/dist/google-generative-ai-embedding-model.js +88 -0
  27. package/dist/google-generative-ai-embedding-model.test.d.ts +2 -0
  28. package/dist/google-generative-ai-embedding-model.test.d.ts.map +1 -0
  29. package/dist/google-generative-ai-embedding-model.test.js +148 -0
  30. package/dist/google-generative-ai-embedding-options.d.ts +8 -0
  31. package/dist/google-generative-ai-embedding-options.d.ts.map +1 -0
  32. package/dist/google-generative-ai-embedding-options.js +33 -0
  33. package/dist/google-generative-ai-image-model.d.ts +31 -0
  34. package/dist/google-generative-ai-image-model.d.ts.map +1 -0
  35. package/dist/google-generative-ai-image-model.js +96 -0
  36. package/dist/google-generative-ai-image-model.test.d.ts +2 -0
  37. package/dist/google-generative-ai-image-model.test.d.ts.map +1 -0
  38. package/dist/google-generative-ai-image-model.test.js +252 -0
  39. package/dist/google-generative-ai-image-settings.d.ts +8 -0
  40. package/dist/google-generative-ai-image-settings.d.ts.map +1 -0
  41. package/dist/google-generative-ai-image-settings.js +1 -0
  42. package/dist/google-generative-ai-language-model.d.ts +183 -0
  43. package/dist/google-generative-ai-language-model.d.ts.map +1 -0
  44. package/dist/google-generative-ai-language-model.js +1001 -0
  45. package/dist/google-generative-ai-language-model.test.d.ts +2 -0
  46. package/dist/google-generative-ai-language-model.test.d.ts.map +1 -0
  47. package/dist/google-generative-ai-language-model.test.js +3463 -0
  48. package/dist/google-generative-ai-options.d.ts +37 -0
  49. package/dist/google-generative-ai-options.d.ts.map +1 -0
  50. package/dist/google-generative-ai-options.js +149 -0
  51. package/dist/google-generative-ai-prompt.d.ts +52 -0
  52. package/dist/google-generative-ai-prompt.d.ts.map +1 -0
  53. package/dist/google-generative-ai-prompt.js +1 -0
  54. package/dist/google-prepare-tools.d.ts +27 -0
  55. package/dist/google-prepare-tools.d.ts.map +1 -0
  56. package/dist/google-prepare-tools.js +219 -0
  57. package/dist/google-prepare-tools.test.d.ts +2 -0
  58. package/dist/google-prepare-tools.test.d.ts.map +1 -0
  59. package/dist/google-prepare-tools.test.js +447 -0
  60. package/dist/google-provider.d.ts +65 -0
  61. package/dist/google-provider.d.ts.map +1 -0
  62. package/dist/google-provider.js +74 -0
  63. package/dist/google-provider.test.d.ts +2 -0
  64. package/dist/google-provider.test.d.ts.map +1 -0
  65. package/dist/google-provider.test.js +234 -0
  66. package/dist/google-supported-file-url.d.ts +2 -0
  67. package/dist/google-supported-file-url.d.ts.map +1 -0
  68. package/dist/google-supported-file-url.js +13 -0
  69. package/dist/google-supported-file-url.test.d.ts +2 -0
  70. package/dist/google-supported-file-url.test.d.ts.map +1 -0
  71. package/dist/google-supported-file-url.test.js +45 -0
  72. package/dist/google-tools.d.ts +76 -0
  73. package/dist/google-tools.d.ts.map +1 -0
  74. package/dist/google-tools.js +65 -0
  75. package/dist/index.d.mts +326 -0
  76. package/dist/index.d.ts +9 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +2 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/index.mjs +2172 -0
  81. package/dist/index.mjs.map +1 -0
  82. package/dist/internal/index.d.mts +262 -0
  83. package/dist/internal/index.d.ts +4 -0
  84. package/dist/internal/index.d.ts.map +1 -0
  85. package/dist/internal/index.js +2 -0
  86. package/dist/internal/index.js.map +1 -0
  87. package/dist/internal/index.mjs +1810 -0
  88. package/dist/internal/index.mjs.map +1 -0
  89. package/dist/map-google-generative-ai-finish-reason.d.ts +6 -0
  90. package/dist/map-google-generative-ai-finish-reason.d.ts.map +1 -0
  91. package/dist/map-google-generative-ai-finish-reason.js +22 -0
  92. package/dist/tool/code-execution.d.ts +17 -0
  93. package/dist/tool/code-execution.d.ts.map +1 -0
  94. package/dist/tool/code-execution.js +25 -0
  95. package/dist/tool/enterprise-web-search.d.ts +2 -0
  96. package/dist/tool/enterprise-web-search.d.ts.map +1 -0
  97. package/dist/tool/enterprise-web-search.js +8 -0
  98. package/dist/tool/file-search.d.ts +16 -0
  99. package/dist/tool/file-search.d.ts.map +1 -0
  100. package/dist/tool/file-search.js +33 -0
  101. package/dist/tool/google-maps.d.ts +2 -0
  102. package/dist/tool/google-maps.d.ts.map +1 -0
  103. package/dist/tool/google-maps.js +9 -0
  104. package/dist/tool/google-search.d.ts +14 -0
  105. package/dist/tool/google-search.d.ts.map +1 -0
  106. package/dist/tool/google-search.js +15 -0
  107. package/dist/tool/url-context.d.ts +2 -0
  108. package/dist/tool/url-context.d.ts.map +1 -0
  109. package/dist/tool/url-context.js +7 -0
  110. package/dist/tool/vertex-rag-store.d.ts +16 -0
  111. package/dist/tool/vertex-rag-store.d.ts.map +1 -0
  112. package/dist/tool/vertex-rag-store.js +17 -0
  113. package/dist/version.d.ts +2 -0
  114. package/dist/version.d.ts.map +1 -0
  115. package/dist/version.js +3 -0
  116. package/internal.d.ts +1 -0
  117. package/package.json +73 -0
@@ -0,0 +1,1001 @@
1
+ import { combineHeaders, createEventSourceResponseHandler, generateId, lazySchema, parseProviderOptions, postJsonToApi, resolve, zodSchema, } from '@ai-sdk/provider-utils';
2
+ import { z } from 'zod/v4';
3
+ import { convertJSONSchemaToOpenAPISchema } from './convert-json-schema-to-openapi-schema';
4
+ import { convertToGoogleGenerativeAIMessages } from './convert-to-google-generative-ai-messages';
5
+ import { googleFailedResponseHandler } from './google-error';
6
+ import { googleGenerativeAIProviderOptions, } from './google-generative-ai-options';
7
+ import { prepareTools, isClaudeModel } from './google-prepare-tools';
8
+ import { mapGoogleGenerativeAIFinishReason } from './map-google-generative-ai-finish-reason';
9
+ export class GoogleGenerativeAILanguageModel {
10
+ constructor(modelId, config) {
11
+ var _a;
12
+ this.specificationVersion = 'v2';
13
+ this.modelId = modelId;
14
+ this.config = config;
15
+ this.generateId = (_a = config.generateId) !== null && _a !== void 0 ? _a : generateId;
16
+ }
17
+ get provider() {
18
+ return this.config.provider;
19
+ }
20
+ get supportedUrls() {
21
+ var _a, _b, _c;
22
+ return (_c = (_b = (_a = this.config).supportedUrls) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : {};
23
+ }
24
+ async getArgs({ prompt, maxOutputTokens, temperature, topP, topK, frequencyPenalty, presencePenalty, stopSequences, responseFormat, seed, tools, toolChoice, providerOptions, }) {
25
+ var _a;
26
+ const warnings = [];
27
+ const googleOptions = await parseProviderOptions({
28
+ provider: 'google',
29
+ providerOptions,
30
+ schema: googleGenerativeAIProviderOptions,
31
+ });
32
+ // Add warning if Vertex rag tools are used with a non-Vertex Google provider
33
+ if ((tools === null || tools === void 0 ? void 0 : tools.some(tool => tool.type === 'provider-defined' &&
34
+ tool.id === 'google.vertex_rag_store')) &&
35
+ !this.config.provider.startsWith('google.vertex.')) {
36
+ warnings.push({
37
+ type: 'other',
38
+ message: "The 'vertex_rag_store' tool is only supported with the Google Vertex provider " +
39
+ 'and might not be supported or could behave unexpectedly with the current Google provider ' +
40
+ `(${this.config.provider}).`,
41
+ });
42
+ }
43
+ const isGemmaModel = this.modelId.toLowerCase().startsWith('gemma-');
44
+ const { contents, systemInstruction } = convertToGoogleGenerativeAIMessages(prompt, { isGemmaModel, modelId: this.modelId });
45
+ const { tools: googleTools, toolConfig: googleToolConfig, toolWarnings, } = prepareTools({
46
+ tools,
47
+ toolChoice,
48
+ modelId: this.modelId,
49
+ });
50
+ return {
51
+ args: {
52
+ generationConfig: {
53
+ // standardized settings:
54
+ maxOutputTokens,
55
+ temperature,
56
+ topK,
57
+ topP,
58
+ frequencyPenalty,
59
+ presencePenalty,
60
+ stopSequences,
61
+ seed,
62
+ // response format:
63
+ responseMimeType: (responseFormat === null || responseFormat === void 0 ? void 0 : responseFormat.type) === 'json' ? 'application/json' : undefined,
64
+ responseSchema: (responseFormat === null || responseFormat === void 0 ? void 0 : responseFormat.type) === 'json' &&
65
+ responseFormat.schema != null &&
66
+ // Google GenAI does not support all OpenAPI Schema features,
67
+ // so this is needed as an escape hatch:
68
+ // TODO convert into provider option
69
+ ((_a = googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.structuredOutputs) !== null && _a !== void 0 ? _a : true)
70
+ ? convertJSONSchemaToOpenAPISchema(responseFormat.schema)
71
+ : undefined,
72
+ ...((googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.audioTimestamp) && {
73
+ audioTimestamp: googleOptions.audioTimestamp,
74
+ }),
75
+ // provider options:
76
+ responseModalities: googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.responseModalities,
77
+ thinkingConfig: googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.thinkingConfig,
78
+ ...((googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.imageConfig) && {
79
+ imageConfig: googleOptions.imageConfig,
80
+ }),
81
+ ...((googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.mediaResolution) && {
82
+ mediaResolution: googleOptions.mediaResolution,
83
+ }),
84
+ },
85
+ contents,
86
+ systemInstruction: isGemmaModel ? undefined : systemInstruction,
87
+ safetySettings: googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.safetySettings,
88
+ tools: googleTools,
89
+ toolConfig: (googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.retrievalConfig)
90
+ ? {
91
+ ...googleToolConfig,
92
+ retrievalConfig: googleOptions.retrievalConfig,
93
+ }
94
+ : googleToolConfig,
95
+ cachedContent: googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.cachedContent,
96
+ labels: googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.labels,
97
+ // Cloud Assist: sessionId goes inside the request
98
+ ...((googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.sessionId) && { sessionId: googleOptions.sessionId }),
99
+ },
100
+ warnings: [...warnings, ...toolWarnings],
101
+ // Cloud Assist specific options (used to wrap the request)
102
+ cloudAssistOptions: {
103
+ projectId: googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.projectId,
104
+ requestType: googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.requestType,
105
+ userAgent: googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.userAgent,
106
+ requestId: googleOptions === null || googleOptions === void 0 ? void 0 : googleOptions.requestId,
107
+ },
108
+ };
109
+ }
110
+ async doGenerate(options) {
111
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
112
+ const { args, warnings, cloudAssistOptions } = await this.getArgs(options);
113
+ // Wrap request for Cloud Assist API
114
+ const wrappedRequest = {
115
+ project: cloudAssistOptions.projectId,
116
+ model: this.modelId,
117
+ request: args,
118
+ ...(cloudAssistOptions.requestType && {
119
+ requestType: cloudAssistOptions.requestType,
120
+ }),
121
+ userAgent: (_a = cloudAssistOptions.userAgent) !== null && _a !== void 0 ? _a : 'ai-sdk',
122
+ requestId: (_b = cloudAssistOptions.requestId) !== null && _b !== void 0 ? _b : `ai-sdk-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,
123
+ };
124
+ const body = JSON.stringify(wrappedRequest);
125
+ const mergedHeaders = combineHeaders(await resolve(this.config.headers), options.headers);
126
+ // Use SSE endpoint and collect all chunks
127
+ const { responseHeaders, value: response } = await postJsonToApi({
128
+ url: `${this.config.baseURL}/v1internal:streamGenerateContent?alt=sse`,
129
+ headers: mergedHeaders,
130
+ body: wrappedRequest,
131
+ failedResponseHandler: googleFailedResponseHandler,
132
+ successfulResponseHandler: createEventSourceResponseHandler(chunkSchema),
133
+ abortSignal: options.abortSignal,
134
+ fetch: this.config.fetch,
135
+ });
136
+ // Collect all chunks from the SSE stream
137
+ const content = [];
138
+ let finishReason = 'unknown';
139
+ let usageMetadata;
140
+ let promptFeedback;
141
+ let groundingMetadata;
142
+ let urlContextMetadata;
143
+ let safetyRatings;
144
+ // Track text/reasoning blocks for aggregation
145
+ let currentTextContent = '';
146
+ let currentTextThoughtSignature;
147
+ let currentReasoningContent = '';
148
+ let currentReasoningThoughtSignature;
149
+ let isInReasoning = false;
150
+ let lastCodeExecutionToolCallId;
151
+ const useToolCallId = isClaudeModel(this.modelId);
152
+ const reader = response.getReader();
153
+ try {
154
+ while (true) {
155
+ const { done, value: chunk } = await reader.read();
156
+ if (done)
157
+ break;
158
+ if (!chunk.success)
159
+ continue;
160
+ const value = chunk.value;
161
+ // Unwrap the response from Cloud Assist format
162
+ const responseData = (_c = value.response) !== null && _c !== void 0 ? _c : value;
163
+ if (responseData.usageMetadata) {
164
+ usageMetadata = responseData.usageMetadata;
165
+ }
166
+ if (responseData.promptFeedback) {
167
+ promptFeedback = responseData.promptFeedback;
168
+ }
169
+ const candidate = (_d = responseData.candidates) === null || _d === void 0 ? void 0 : _d[0];
170
+ if (!candidate)
171
+ continue;
172
+ if (candidate.groundingMetadata) {
173
+ groundingMetadata = candidate.groundingMetadata;
174
+ }
175
+ if (candidate.urlContextMetadata) {
176
+ urlContextMetadata = candidate.urlContextMetadata;
177
+ }
178
+ if (candidate.safetyRatings) {
179
+ safetyRatings = candidate.safetyRatings;
180
+ }
181
+ const parts = (_f = (_e = candidate.content) === null || _e === void 0 ? void 0 : _e.parts) !== null && _f !== void 0 ? _f : [];
182
+ for (const part of parts) {
183
+ if ('executableCode' in part && ((_g = part.executableCode) === null || _g === void 0 ? void 0 : _g.code)) {
184
+ // Flush any pending text/reasoning
185
+ if (currentTextContent) {
186
+ content.push({
187
+ type: 'text',
188
+ text: currentTextContent,
189
+ providerMetadata: currentTextThoughtSignature
190
+ ? { google: { thoughtSignature: currentTextThoughtSignature } }
191
+ : undefined,
192
+ });
193
+ currentTextContent = '';
194
+ currentTextThoughtSignature = undefined;
195
+ }
196
+ if (currentReasoningContent) {
197
+ content.push({
198
+ type: 'reasoning',
199
+ text: currentReasoningContent,
200
+ providerMetadata: currentReasoningThoughtSignature
201
+ ? {
202
+ google: {
203
+ thoughtSignature: currentReasoningThoughtSignature,
204
+ },
205
+ }
206
+ : undefined,
207
+ });
208
+ currentReasoningContent = '';
209
+ currentReasoningThoughtSignature = undefined;
210
+ }
211
+ const toolCallId = this.config.generateId();
212
+ lastCodeExecutionToolCallId = toolCallId;
213
+ content.push({
214
+ type: 'tool-call',
215
+ toolCallId,
216
+ toolName: 'code_execution',
217
+ input: JSON.stringify(part.executableCode),
218
+ providerExecuted: true,
219
+ });
220
+ }
221
+ else if ('codeExecutionResult' in part &&
222
+ part.codeExecutionResult) {
223
+ content.push({
224
+ type: 'tool-result',
225
+ toolCallId: lastCodeExecutionToolCallId,
226
+ toolName: 'code_execution',
227
+ result: {
228
+ outcome: part.codeExecutionResult.outcome,
229
+ output: part.codeExecutionResult.output,
230
+ },
231
+ providerExecuted: true,
232
+ });
233
+ lastCodeExecutionToolCallId = undefined;
234
+ }
235
+ else if ('text' in part && part.text != null) {
236
+ const isThinking = part.thought === true;
237
+ if (isThinking) {
238
+ // Flush text if switching to reasoning
239
+ if (!isInReasoning && currentTextContent) {
240
+ content.push({
241
+ type: 'text',
242
+ text: currentTextContent,
243
+ providerMetadata: currentTextThoughtSignature
244
+ ? {
245
+ google: {
246
+ thoughtSignature: currentTextThoughtSignature,
247
+ },
248
+ }
249
+ : undefined,
250
+ });
251
+ currentTextContent = '';
252
+ currentTextThoughtSignature = undefined;
253
+ }
254
+ isInReasoning = true;
255
+ currentReasoningContent += part.text;
256
+ if (part.thoughtSignature) {
257
+ currentReasoningThoughtSignature = part.thoughtSignature;
258
+ }
259
+ }
260
+ else {
261
+ // Flush reasoning if switching to text
262
+ if (isInReasoning && currentReasoningContent) {
263
+ content.push({
264
+ type: 'reasoning',
265
+ text: currentReasoningContent,
266
+ providerMetadata: currentReasoningThoughtSignature
267
+ ? {
268
+ google: {
269
+ thoughtSignature: currentReasoningThoughtSignature,
270
+ },
271
+ }
272
+ : undefined,
273
+ });
274
+ currentReasoningContent = '';
275
+ currentReasoningThoughtSignature = undefined;
276
+ }
277
+ isInReasoning = false;
278
+ currentTextContent += part.text;
279
+ if (part.thoughtSignature) {
280
+ currentTextThoughtSignature = part.thoughtSignature;
281
+ }
282
+ }
283
+ }
284
+ else if ('functionCall' in part) {
285
+ // Flush any pending text/reasoning
286
+ if (currentTextContent) {
287
+ content.push({
288
+ type: 'text',
289
+ text: currentTextContent,
290
+ providerMetadata: currentTextThoughtSignature
291
+ ? { google: { thoughtSignature: currentTextThoughtSignature } }
292
+ : undefined,
293
+ });
294
+ currentTextContent = '';
295
+ currentTextThoughtSignature = undefined;
296
+ }
297
+ if (currentReasoningContent) {
298
+ content.push({
299
+ type: 'reasoning',
300
+ text: currentReasoningContent,
301
+ providerMetadata: currentReasoningThoughtSignature
302
+ ? {
303
+ google: {
304
+ thoughtSignature: currentReasoningThoughtSignature,
305
+ },
306
+ }
307
+ : undefined,
308
+ });
309
+ currentReasoningContent = '';
310
+ currentReasoningThoughtSignature = undefined;
311
+ }
312
+ // Use provided id for Claude models, generate for others
313
+ const toolCallId = useToolCallId && part.functionCall.id
314
+ ? part.functionCall.id
315
+ : this.config.generateId();
316
+ content.push({
317
+ type: 'tool-call',
318
+ toolCallId,
319
+ toolName: part.functionCall.name,
320
+ input: JSON.stringify(part.functionCall.args),
321
+ providerMetadata: part.thoughtSignature
322
+ ? { google: { thoughtSignature: part.thoughtSignature } }
323
+ : undefined,
324
+ });
325
+ }
326
+ else if ('inlineData' in part) {
327
+ // Flush any pending text/reasoning
328
+ if (currentTextContent) {
329
+ content.push({
330
+ type: 'text',
331
+ text: currentTextContent,
332
+ providerMetadata: currentTextThoughtSignature
333
+ ? { google: { thoughtSignature: currentTextThoughtSignature } }
334
+ : undefined,
335
+ });
336
+ currentTextContent = '';
337
+ currentTextThoughtSignature = undefined;
338
+ }
339
+ if (currentReasoningContent) {
340
+ content.push({
341
+ type: 'reasoning',
342
+ text: currentReasoningContent,
343
+ providerMetadata: currentReasoningThoughtSignature
344
+ ? {
345
+ google: {
346
+ thoughtSignature: currentReasoningThoughtSignature,
347
+ },
348
+ }
349
+ : undefined,
350
+ });
351
+ currentReasoningContent = '';
352
+ currentReasoningThoughtSignature = undefined;
353
+ }
354
+ content.push({
355
+ type: 'file',
356
+ data: part.inlineData.data,
357
+ mediaType: part.inlineData.mimeType,
358
+ });
359
+ }
360
+ }
361
+ if (candidate.finishReason) {
362
+ finishReason = mapGoogleGenerativeAIFinishReason({
363
+ finishReason: candidate.finishReason,
364
+ hasToolCalls: content.some(part => part.type === 'tool-call'),
365
+ });
366
+ }
367
+ }
368
+ }
369
+ finally {
370
+ reader.releaseLock();
371
+ }
372
+ // Flush any remaining text/reasoning
373
+ if (currentTextContent) {
374
+ content.push({
375
+ type: 'text',
376
+ text: currentTextContent,
377
+ providerMetadata: currentTextThoughtSignature
378
+ ? { google: { thoughtSignature: currentTextThoughtSignature } }
379
+ : undefined,
380
+ });
381
+ }
382
+ if (currentReasoningContent) {
383
+ content.push({
384
+ type: 'reasoning',
385
+ text: currentReasoningContent,
386
+ providerMetadata: currentReasoningThoughtSignature
387
+ ? { google: { thoughtSignature: currentReasoningThoughtSignature } }
388
+ : undefined,
389
+ });
390
+ }
391
+ // Extract sources from grounding metadata
392
+ const sources = (_h = extractSources({
393
+ groundingMetadata,
394
+ generateId: this.config.generateId,
395
+ })) !== null && _h !== void 0 ? _h : [];
396
+ for (const source of sources) {
397
+ content.push(source);
398
+ }
399
+ return {
400
+ content,
401
+ finishReason,
402
+ usage: {
403
+ inputTokens: (_j = usageMetadata === null || usageMetadata === void 0 ? void 0 : usageMetadata.promptTokenCount) !== null && _j !== void 0 ? _j : undefined,
404
+ outputTokens: (_k = usageMetadata === null || usageMetadata === void 0 ? void 0 : usageMetadata.candidatesTokenCount) !== null && _k !== void 0 ? _k : undefined,
405
+ totalTokens: (_l = usageMetadata === null || usageMetadata === void 0 ? void 0 : usageMetadata.totalTokenCount) !== null && _l !== void 0 ? _l : undefined,
406
+ reasoningTokens: (_m = usageMetadata === null || usageMetadata === void 0 ? void 0 : usageMetadata.thoughtsTokenCount) !== null && _m !== void 0 ? _m : undefined,
407
+ cachedInputTokens: (_o = usageMetadata === null || usageMetadata === void 0 ? void 0 : usageMetadata.cachedContentTokenCount) !== null && _o !== void 0 ? _o : undefined,
408
+ },
409
+ warnings,
410
+ providerMetadata: {
411
+ google: {
412
+ promptFeedback: promptFeedback !== null && promptFeedback !== void 0 ? promptFeedback : null,
413
+ groundingMetadata: groundingMetadata !== null && groundingMetadata !== void 0 ? groundingMetadata : null,
414
+ urlContextMetadata: urlContextMetadata !== null && urlContextMetadata !== void 0 ? urlContextMetadata : null,
415
+ safetyRatings: safetyRatings !== null && safetyRatings !== void 0 ? safetyRatings : null,
416
+ usageMetadata: usageMetadata !== null && usageMetadata !== void 0 ? usageMetadata : null,
417
+ },
418
+ },
419
+ request: { body },
420
+ response: {
421
+ headers: responseHeaders,
422
+ },
423
+ };
424
+ }
425
+ async doStream(options) {
426
+ var _a, _b;
427
+ const { args, warnings, cloudAssistOptions } = await this.getArgs(options);
428
+ // Wrap request for Cloud Assist API
429
+ const wrappedRequest = {
430
+ project: cloudAssistOptions.projectId,
431
+ model: this.modelId,
432
+ request: args,
433
+ ...(cloudAssistOptions.requestType && {
434
+ requestType: cloudAssistOptions.requestType,
435
+ }),
436
+ userAgent: (_a = cloudAssistOptions.userAgent) !== null && _a !== void 0 ? _a : 'ai-sdk',
437
+ requestId: (_b = cloudAssistOptions.requestId) !== null && _b !== void 0 ? _b : `ai-sdk-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,
438
+ };
439
+ const body = JSON.stringify(wrappedRequest);
440
+ const headers = combineHeaders(await resolve(this.config.headers), options.headers);
441
+ const { responseHeaders, value: response } = await postJsonToApi({
442
+ url: `${this.config.baseURL}/v1internal:streamGenerateContent?alt=sse`,
443
+ headers,
444
+ body: wrappedRequest,
445
+ failedResponseHandler: googleFailedResponseHandler,
446
+ successfulResponseHandler: createEventSourceResponseHandler(chunkSchema),
447
+ abortSignal: options.abortSignal,
448
+ fetch: this.config.fetch,
449
+ });
450
+ let finishReason = 'unknown';
451
+ const usage = {
452
+ inputTokens: undefined,
453
+ outputTokens: undefined,
454
+ totalTokens: undefined,
455
+ };
456
+ let providerMetadata = undefined;
457
+ const generateId = this.config.generateId;
458
+ const useToolCallId = isClaudeModel(this.modelId);
459
+ let hasToolCalls = false;
460
+ // Track active blocks to group consecutive parts of same type
461
+ let currentTextBlockId = null;
462
+ let currentReasoningBlockId = null;
463
+ let blockCounter = 0;
464
+ // Track emitted sources to prevent duplicates
465
+ const emittedSourceUrls = new Set();
466
+ // Associates a code execution result with its preceding call.
467
+ let lastCodeExecutionToolCallId;
468
+ return {
469
+ stream: response.pipeThrough(new TransformStream({
470
+ start(controller) {
471
+ controller.enqueue({ type: 'stream-start', warnings });
472
+ },
473
+ transform(chunk, controller) {
474
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
475
+ if (options.includeRawChunks) {
476
+ controller.enqueue({ type: 'raw', rawValue: chunk.rawValue });
477
+ }
478
+ if (!chunk.success) {
479
+ controller.enqueue({ type: 'error', error: chunk.error });
480
+ return;
481
+ }
482
+ const value = chunk.value;
483
+ // Unwrap the response from Cloud Assist format
484
+ const responseData = (_a = value.response) !== null && _a !== void 0 ? _a : value;
485
+ const usageMetadata = responseData.usageMetadata;
486
+ if (usageMetadata != null) {
487
+ usage.inputTokens = (_b = usageMetadata.promptTokenCount) !== null && _b !== void 0 ? _b : undefined;
488
+ usage.outputTokens =
489
+ (_c = usageMetadata.candidatesTokenCount) !== null && _c !== void 0 ? _c : undefined;
490
+ usage.totalTokens = (_d = usageMetadata.totalTokenCount) !== null && _d !== void 0 ? _d : undefined;
491
+ usage.reasoningTokens =
492
+ (_e = usageMetadata.thoughtsTokenCount) !== null && _e !== void 0 ? _e : undefined;
493
+ usage.cachedInputTokens =
494
+ (_f = usageMetadata.cachedContentTokenCount) !== null && _f !== void 0 ? _f : undefined;
495
+ }
496
+ const candidate = (_g = responseData.candidates) === null || _g === void 0 ? void 0 : _g[0];
497
+ // sometimes the API returns an empty candidates array
498
+ if (candidate == null) {
499
+ return;
500
+ }
501
+ const content = candidate.content;
502
+ const sources = extractSources({
503
+ groundingMetadata: candidate.groundingMetadata,
504
+ generateId,
505
+ });
506
+ if (sources != null) {
507
+ for (const source of sources) {
508
+ if (source.sourceType === 'url' &&
509
+ !emittedSourceUrls.has(source.url)) {
510
+ emittedSourceUrls.add(source.url);
511
+ controller.enqueue(source);
512
+ }
513
+ }
514
+ }
515
+ // Process tool call's parts before determining finishReason to ensure hasToolCalls is properly set
516
+ if (content != null) {
517
+ // Process all parts in a single loop to preserve original order
518
+ const parts = (_h = content.parts) !== null && _h !== void 0 ? _h : [];
519
+ for (const part of parts) {
520
+ if ('executableCode' in part && ((_j = part.executableCode) === null || _j === void 0 ? void 0 : _j.code)) {
521
+ const toolCallId = generateId();
522
+ lastCodeExecutionToolCallId = toolCallId;
523
+ controller.enqueue({
524
+ type: 'tool-call',
525
+ toolCallId,
526
+ toolName: 'code_execution',
527
+ input: JSON.stringify(part.executableCode),
528
+ providerExecuted: true,
529
+ });
530
+ hasToolCalls = true;
531
+ }
532
+ else if ('codeExecutionResult' in part &&
533
+ part.codeExecutionResult) {
534
+ // Assumes a result directly follows its corresponding call part.
535
+ const toolCallId = lastCodeExecutionToolCallId;
536
+ if (toolCallId) {
537
+ controller.enqueue({
538
+ type: 'tool-result',
539
+ toolCallId,
540
+ toolName: 'code_execution',
541
+ result: {
542
+ outcome: part.codeExecutionResult.outcome,
543
+ output: part.codeExecutionResult.output,
544
+ },
545
+ providerExecuted: true,
546
+ });
547
+ // Clear the ID after use.
548
+ lastCodeExecutionToolCallId = undefined;
549
+ }
550
+ }
551
+ else if ('text' in part &&
552
+ part.text != null &&
553
+ part.text.length > 0) {
554
+ if (part.thought === true) {
555
+ // End any active text block before starting reasoning
556
+ if (currentTextBlockId !== null) {
557
+ controller.enqueue({
558
+ type: 'text-end',
559
+ id: currentTextBlockId,
560
+ });
561
+ currentTextBlockId = null;
562
+ }
563
+ // Start new reasoning block if not already active
564
+ if (currentReasoningBlockId === null) {
565
+ currentReasoningBlockId = String(blockCounter++);
566
+ controller.enqueue({
567
+ type: 'reasoning-start',
568
+ id: currentReasoningBlockId,
569
+ providerMetadata: part.thoughtSignature
570
+ ? {
571
+ google: {
572
+ thoughtSignature: part.thoughtSignature,
573
+ },
574
+ }
575
+ : undefined,
576
+ });
577
+ }
578
+ controller.enqueue({
579
+ type: 'reasoning-delta',
580
+ id: currentReasoningBlockId,
581
+ delta: part.text,
582
+ providerMetadata: part.thoughtSignature
583
+ ? {
584
+ google: { thoughtSignature: part.thoughtSignature },
585
+ }
586
+ : undefined,
587
+ });
588
+ }
589
+ else {
590
+ // End any active reasoning block before starting text
591
+ if (currentReasoningBlockId !== null) {
592
+ controller.enqueue({
593
+ type: 'reasoning-end',
594
+ id: currentReasoningBlockId,
595
+ });
596
+ currentReasoningBlockId = null;
597
+ }
598
+ // Start new text block if not already active
599
+ if (currentTextBlockId === null) {
600
+ currentTextBlockId = String(blockCounter++);
601
+ controller.enqueue({
602
+ type: 'text-start',
603
+ id: currentTextBlockId,
604
+ providerMetadata: part.thoughtSignature
605
+ ? {
606
+ google: {
607
+ thoughtSignature: part.thoughtSignature,
608
+ },
609
+ }
610
+ : undefined,
611
+ });
612
+ }
613
+ controller.enqueue({
614
+ type: 'text-delta',
615
+ id: currentTextBlockId,
616
+ delta: part.text,
617
+ providerMetadata: part.thoughtSignature
618
+ ? {
619
+ google: { thoughtSignature: part.thoughtSignature },
620
+ }
621
+ : undefined,
622
+ });
623
+ }
624
+ }
625
+ else if ('inlineData' in part) {
626
+ // Process file parts inline to preserve order with text
627
+ controller.enqueue({
628
+ type: 'file',
629
+ mediaType: part.inlineData.mimeType,
630
+ data: part.inlineData.data,
631
+ });
632
+ }
633
+ }
634
+ const toolCallDeltas = getToolCallsFromParts({
635
+ parts: content.parts,
636
+ generateId,
637
+ useToolCallId,
638
+ });
639
+ if (toolCallDeltas != null) {
640
+ for (const toolCall of toolCallDeltas) {
641
+ controller.enqueue({
642
+ type: 'tool-input-start',
643
+ id: toolCall.toolCallId,
644
+ toolName: toolCall.toolName,
645
+ providerMetadata: toolCall.providerMetadata,
646
+ });
647
+ controller.enqueue({
648
+ type: 'tool-input-delta',
649
+ id: toolCall.toolCallId,
650
+ delta: toolCall.args,
651
+ providerMetadata: toolCall.providerMetadata,
652
+ });
653
+ controller.enqueue({
654
+ type: 'tool-input-end',
655
+ id: toolCall.toolCallId,
656
+ providerMetadata: toolCall.providerMetadata,
657
+ });
658
+ controller.enqueue({
659
+ type: 'tool-call',
660
+ toolCallId: toolCall.toolCallId,
661
+ toolName: toolCall.toolName,
662
+ input: toolCall.args,
663
+ providerMetadata: toolCall.providerMetadata,
664
+ });
665
+ hasToolCalls = true;
666
+ }
667
+ }
668
+ }
669
+ if (candidate.finishReason != null) {
670
+ finishReason = mapGoogleGenerativeAIFinishReason({
671
+ finishReason: candidate.finishReason,
672
+ hasToolCalls,
673
+ });
674
+ providerMetadata = {
675
+ google: {
676
+ promptFeedback: (_k = responseData.promptFeedback) !== null && _k !== void 0 ? _k : null,
677
+ groundingMetadata: (_l = candidate.groundingMetadata) !== null && _l !== void 0 ? _l : null,
678
+ urlContextMetadata: (_m = candidate.urlContextMetadata) !== null && _m !== void 0 ? _m : null,
679
+ safetyRatings: (_o = candidate.safetyRatings) !== null && _o !== void 0 ? _o : null,
680
+ },
681
+ };
682
+ if (usageMetadata != null) {
683
+ providerMetadata.google.usageMetadata = usageMetadata;
684
+ }
685
+ }
686
+ },
687
+ flush(controller) {
688
+ // Close any open blocks before finishing
689
+ if (currentTextBlockId !== null) {
690
+ controller.enqueue({
691
+ type: 'text-end',
692
+ id: currentTextBlockId,
693
+ });
694
+ }
695
+ if (currentReasoningBlockId !== null) {
696
+ controller.enqueue({
697
+ type: 'reasoning-end',
698
+ id: currentReasoningBlockId,
699
+ });
700
+ }
701
+ controller.enqueue({
702
+ type: 'finish',
703
+ finishReason,
704
+ usage,
705
+ providerMetadata,
706
+ });
707
+ },
708
+ })),
709
+ response: { headers: responseHeaders },
710
+ request: { body },
711
+ };
712
+ }
713
+ }
714
+ function getToolCallsFromParts({ parts, generateId, useToolCallId = false, }) {
715
+ const functionCallParts = parts === null || parts === void 0 ? void 0 : parts.filter(part => 'functionCall' in part);
716
+ return functionCallParts == null || functionCallParts.length === 0
717
+ ? undefined
718
+ : functionCallParts.map(part => ({
719
+ type: 'tool-call',
720
+ // Use provided id for Claude models, generate for others
721
+ toolCallId: useToolCallId && part.functionCall.id
722
+ ? part.functionCall.id
723
+ : generateId(),
724
+ toolName: part.functionCall.name,
725
+ args: JSON.stringify(part.functionCall.args),
726
+ providerMetadata: part.thoughtSignature
727
+ ? { google: { thoughtSignature: part.thoughtSignature } }
728
+ : undefined,
729
+ }));
730
+ }
731
+ function extractSources({ groundingMetadata, generateId, }) {
732
+ var _a, _b, _c, _d, _e;
733
+ if (!(groundingMetadata === null || groundingMetadata === void 0 ? void 0 : groundingMetadata.groundingChunks)) {
734
+ return undefined;
735
+ }
736
+ const sources = [];
737
+ for (const chunk of groundingMetadata.groundingChunks) {
738
+ if (chunk.web != null) {
739
+ // Handle web chunks as URL sources
740
+ sources.push({
741
+ type: 'source',
742
+ sourceType: 'url',
743
+ id: generateId(),
744
+ url: chunk.web.uri,
745
+ title: (_a = chunk.web.title) !== null && _a !== void 0 ? _a : undefined,
746
+ });
747
+ }
748
+ else if (chunk.retrievedContext != null) {
749
+ // Handle retrievedContext chunks from RAG operations
750
+ const uri = chunk.retrievedContext.uri;
751
+ const fileSearchStore = chunk.retrievedContext.fileSearchStore;
752
+ if (uri && (uri.startsWith('http://') || uri.startsWith('https://'))) {
753
+ // Old format: Google Search with HTTP/HTTPS URL
754
+ sources.push({
755
+ type: 'source',
756
+ sourceType: 'url',
757
+ id: generateId(),
758
+ url: uri,
759
+ title: (_b = chunk.retrievedContext.title) !== null && _b !== void 0 ? _b : undefined,
760
+ });
761
+ }
762
+ else if (uri) {
763
+ // Old format: Document with file path (gs://, etc.)
764
+ const title = (_c = chunk.retrievedContext.title) !== null && _c !== void 0 ? _c : 'Unknown Document';
765
+ let mediaType = 'application/octet-stream';
766
+ let filename = undefined;
767
+ if (uri.endsWith('.pdf')) {
768
+ mediaType = 'application/pdf';
769
+ filename = uri.split('/').pop();
770
+ }
771
+ else if (uri.endsWith('.txt')) {
772
+ mediaType = 'text/plain';
773
+ filename = uri.split('/').pop();
774
+ }
775
+ else if (uri.endsWith('.docx')) {
776
+ mediaType =
777
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
778
+ filename = uri.split('/').pop();
779
+ }
780
+ else if (uri.endsWith('.doc')) {
781
+ mediaType = 'application/msword';
782
+ filename = uri.split('/').pop();
783
+ }
784
+ else if (uri.match(/\.(md|markdown)$/)) {
785
+ mediaType = 'text/markdown';
786
+ filename = uri.split('/').pop();
787
+ }
788
+ else {
789
+ filename = uri.split('/').pop();
790
+ }
791
+ sources.push({
792
+ type: 'source',
793
+ sourceType: 'document',
794
+ id: generateId(),
795
+ mediaType,
796
+ title,
797
+ filename,
798
+ });
799
+ }
800
+ else if (fileSearchStore) {
801
+ // New format: File Search with fileSearchStore (no uri)
802
+ const title = (_d = chunk.retrievedContext.title) !== null && _d !== void 0 ? _d : 'Unknown Document';
803
+ sources.push({
804
+ type: 'source',
805
+ sourceType: 'document',
806
+ id: generateId(),
807
+ mediaType: 'application/octet-stream',
808
+ title,
809
+ filename: fileSearchStore.split('/').pop(),
810
+ });
811
+ }
812
+ }
813
+ else if (chunk.maps != null) {
814
+ if (chunk.maps.uri) {
815
+ sources.push({
816
+ type: 'source',
817
+ sourceType: 'url',
818
+ id: generateId(),
819
+ url: chunk.maps.uri,
820
+ title: (_e = chunk.maps.title) !== null && _e !== void 0 ? _e : undefined,
821
+ });
822
+ }
823
+ }
824
+ }
825
+ return sources.length > 0 ? sources : undefined;
826
+ }
827
+ export const getGroundingMetadataSchema = () => z.object({
828
+ webSearchQueries: z.array(z.string()).nullish(),
829
+ retrievalQueries: z.array(z.string()).nullish(),
830
+ searchEntryPoint: z.object({ renderedContent: z.string() }).nullish(),
831
+ groundingChunks: z
832
+ .array(z.object({
833
+ web: z
834
+ .object({ uri: z.string(), title: z.string().nullish() })
835
+ .nullish(),
836
+ retrievedContext: z
837
+ .object({
838
+ uri: z.string().nullish(),
839
+ title: z.string().nullish(),
840
+ text: z.string().nullish(),
841
+ fileSearchStore: z.string().nullish(),
842
+ })
843
+ .nullish(),
844
+ maps: z
845
+ .object({
846
+ uri: z.string().nullish(),
847
+ title: z.string().nullish(),
848
+ text: z.string().nullish(),
849
+ placeId: z.string().nullish(),
850
+ })
851
+ .nullish(),
852
+ }))
853
+ .nullish(),
854
+ groundingSupports: z
855
+ .array(z.object({
856
+ segment: z.object({
857
+ startIndex: z.number().nullish(),
858
+ endIndex: z.number().nullish(),
859
+ text: z.string().nullish(),
860
+ }),
861
+ segment_text: z.string().nullish(),
862
+ groundingChunkIndices: z.array(z.number()).nullish(),
863
+ supportChunkIndices: z.array(z.number()).nullish(),
864
+ confidenceScores: z.array(z.number()).nullish(),
865
+ confidenceScore: z.array(z.number()).nullish(),
866
+ }))
867
+ .nullish(),
868
+ retrievalMetadata: z
869
+ .union([
870
+ z.object({
871
+ webDynamicRetrievalScore: z.number(),
872
+ }),
873
+ z.object({}),
874
+ ])
875
+ .nullish(),
876
+ });
877
+ const getContentSchema = () => z.object({
878
+ parts: z
879
+ .array(z.union([
880
+ // note: order matters since text can be fully empty
881
+ z.object({
882
+ functionCall: z.object({
883
+ name: z.string(),
884
+ args: z.unknown(),
885
+ id: z.string().nullish(), // Claude models include tool call ID
886
+ }),
887
+ thoughtSignature: z.string().nullish(),
888
+ }),
889
+ z.object({
890
+ inlineData: z.object({
891
+ mimeType: z.string(),
892
+ data: z.string(),
893
+ }),
894
+ }),
895
+ z.object({
896
+ executableCode: z
897
+ .object({
898
+ language: z.string(),
899
+ code: z.string(),
900
+ })
901
+ .nullish(),
902
+ codeExecutionResult: z
903
+ .object({
904
+ outcome: z.string(),
905
+ output: z.string(),
906
+ })
907
+ .nullish(),
908
+ text: z.string().nullish(),
909
+ thought: z.boolean().nullish(),
910
+ thoughtSignature: z.string().nullish(),
911
+ }),
912
+ ]))
913
+ .nullish(),
914
+ });
915
+ // https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/configure-safety-filters
916
+ const getSafetyRatingSchema = () => z.object({
917
+ category: z.string().nullish(),
918
+ probability: z.string().nullish(),
919
+ probabilityScore: z.number().nullish(),
920
+ severity: z.string().nullish(),
921
+ severityScore: z.number().nullish(),
922
+ blocked: z.boolean().nullish(),
923
+ });
924
+ const usageSchema = z.object({
925
+ cachedContentTokenCount: z.number().nullish(),
926
+ thoughtsTokenCount: z.number().nullish(),
927
+ promptTokenCount: z.number().nullish(),
928
+ candidatesTokenCount: z.number().nullish(),
929
+ totalTokenCount: z.number().nullish(),
930
+ // https://cloud.google.com/vertex-ai/generative-ai/docs/reference/rest/v1/GenerateContentResponse#TrafficType
931
+ trafficType: z.string().nullish(),
932
+ });
933
+ // https://ai.google.dev/api/generate-content#UrlRetrievalMetadata
934
+ export const getUrlContextMetadataSchema = () => z.object({
935
+ urlMetadata: z.array(z.object({
936
+ retrievedUrl: z.string(),
937
+ urlRetrievalStatus: z.string(),
938
+ })),
939
+ });
940
+ const responseSchema = lazySchema(() => zodSchema(z.object({
941
+ candidates: z.array(z.object({
942
+ content: getContentSchema().nullish().or(z.object({}).strict()),
943
+ finishReason: z.string().nullish(),
944
+ safetyRatings: z.array(getSafetyRatingSchema()).nullish(),
945
+ groundingMetadata: getGroundingMetadataSchema().nullish(),
946
+ urlContextMetadata: getUrlContextMetadataSchema().nullish(),
947
+ })),
948
+ usageMetadata: usageSchema.nullish(),
949
+ promptFeedback: z
950
+ .object({
951
+ blockReason: z.string().nullish(),
952
+ safetyRatings: z.array(getSafetyRatingSchema()).nullish(),
953
+ })
954
+ .nullish(),
955
+ })));
956
+ // Schema for the inner response content (used by both wrapped and unwrapped formats)
957
+ const getResponseContentSchema = () => z.object({
958
+ candidates: z
959
+ .array(z.object({
960
+ content: getContentSchema().nullish(),
961
+ finishReason: z.string().nullish(),
962
+ safetyRatings: z.array(getSafetyRatingSchema()).nullish(),
963
+ groundingMetadata: getGroundingMetadataSchema().nullish(),
964
+ urlContextMetadata: getUrlContextMetadataSchema().nullish(),
965
+ }))
966
+ .nullish(),
967
+ usageMetadata: usageSchema.nullish(),
968
+ promptFeedback: z
969
+ .object({
970
+ blockReason: z.string().nullish(),
971
+ safetyRatings: z.array(getSafetyRatingSchema()).nullish(),
972
+ })
973
+ .nullish(),
974
+ modelVersion: z.string().nullish(),
975
+ responseId: z.string().nullish(),
976
+ });
977
+ // limited version of the schema, focussed on what is needed for the implementation
978
+ // this approach limits breakages when the API changes and increases efficiency
979
+ // Cloud Assist wraps the response in a "response" field, but we handle both formats
980
+ const chunkSchema = lazySchema(() => zodSchema(z.object({
981
+ // Cloud Assist wrapper fields
982
+ response: getResponseContentSchema().nullish(),
983
+ traceId: z.string().nullish(),
984
+ // Also allow direct fields for compatibility
985
+ candidates: z
986
+ .array(z.object({
987
+ content: getContentSchema().nullish(),
988
+ finishReason: z.string().nullish(),
989
+ safetyRatings: z.array(getSafetyRatingSchema()).nullish(),
990
+ groundingMetadata: getGroundingMetadataSchema().nullish(),
991
+ urlContextMetadata: getUrlContextMetadataSchema().nullish(),
992
+ }))
993
+ .nullish(),
994
+ usageMetadata: usageSchema.nullish(),
995
+ promptFeedback: z
996
+ .object({
997
+ blockReason: z.string().nullish(),
998
+ safetyRatings: z.array(getSafetyRatingSchema()).nullish(),
999
+ })
1000
+ .nullish(),
1001
+ })));