@ai-sdk/google 3.0.66 → 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,245 @@
1
+ import type { LanguageModelV3Source } from '@ai-sdk/provider';
2
+ import type {
3
+ GoogleInteractionsAnnotation,
4
+ GoogleInteractionsBuiltinToolResultContent,
5
+ GoogleInteractionsFileCitation,
6
+ GoogleInteractionsGoogleMapsResultContent,
7
+ GoogleInteractionsGoogleSearchResultContent,
8
+ GoogleInteractionsPlaceCitation,
9
+ GoogleInteractionsURLCitation,
10
+ GoogleInteractionsURLContextResultContent,
11
+ } from './google-interactions-prompt';
12
+
13
+ const KNOWN_DOC_EXTENSIONS: Record<string, string> = {
14
+ pdf: 'application/pdf',
15
+ txt: 'text/plain',
16
+ md: 'text/markdown',
17
+ markdown: 'text/markdown',
18
+ doc: 'application/msword',
19
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
20
+ };
21
+
22
+ function inferDocMediaType(uriOrName: string): string {
23
+ const lower = uriOrName.toLowerCase();
24
+ for (const [ext, media] of Object.entries(KNOWN_DOC_EXTENSIONS)) {
25
+ if (lower.endsWith(`.${ext}`)) return media;
26
+ }
27
+ return 'application/octet-stream';
28
+ }
29
+
30
+ function basename(uriOrName: string): string | undefined {
31
+ const parts = uriOrName.split('/');
32
+ const last = parts[parts.length - 1];
33
+ return last && last.length > 0 ? last : undefined;
34
+ }
35
+
36
+ /**
37
+ * Maps a single text-block annotation (`url_citation` / `file_citation` /
38
+ * `place_citation`) onto a `LanguageModelV3Source`. Returns `undefined` when
39
+ * the annotation lacks the minimum payload to form a source (e.g. a URL
40
+ * citation without a `url`).
41
+ */
42
+ export function annotationToSource({
43
+ annotation,
44
+ generateId,
45
+ }: {
46
+ annotation: GoogleInteractionsAnnotation | { type: string };
47
+ generateId: () => string;
48
+ }): LanguageModelV3Source | undefined {
49
+ switch (annotation.type) {
50
+ case 'url_citation': {
51
+ const a = annotation as GoogleInteractionsURLCitation;
52
+ if (a.url == null || a.url.length === 0) return undefined;
53
+ return {
54
+ type: 'source',
55
+ sourceType: 'url',
56
+ id: generateId(),
57
+ url: a.url,
58
+ ...(a.title != null ? { title: a.title } : {}),
59
+ };
60
+ }
61
+ case 'file_citation': {
62
+ const a = annotation as GoogleInteractionsFileCitation;
63
+ const uri = a.document_uri ?? a.source ?? a.file_name;
64
+ if (uri == null || uri.length === 0) return undefined;
65
+ if (uri.startsWith('http://') || uri.startsWith('https://')) {
66
+ return {
67
+ type: 'source',
68
+ sourceType: 'url',
69
+ id: generateId(),
70
+ url: uri,
71
+ ...(a.file_name != null ? { title: a.file_name } : {}),
72
+ };
73
+ }
74
+ const filename = a.file_name ?? basename(uri);
75
+ const mediaType = inferDocMediaType(uri);
76
+ return {
77
+ type: 'source',
78
+ sourceType: 'document',
79
+ id: generateId(),
80
+ mediaType,
81
+ title: a.file_name ?? filename ?? uri,
82
+ ...(filename != null ? { filename } : {}),
83
+ };
84
+ }
85
+ case 'place_citation': {
86
+ const a = annotation as GoogleInteractionsPlaceCitation;
87
+ if (a.url == null || a.url.length === 0) return undefined;
88
+ return {
89
+ type: 'source',
90
+ sourceType: 'url',
91
+ id: generateId(),
92
+ url: a.url,
93
+ ...(a.name != null ? { title: a.name } : {}),
94
+ };
95
+ }
96
+ default:
97
+ return undefined;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Maps a built-in tool *result* content block to zero or more
103
+ * `LanguageModelV3Source` parts. The Interactions API exposes grounding
104
+ * sources both inline (via `text_annotation` deltas) and via tool-result
105
+ * content blocks; the latter is what this function consumes.
106
+ *
107
+ * Supported result kinds:
108
+ * - `url_context_result` -> URL sources for each fetched URL with `status: 'success'`
109
+ * - `google_search_result` -> URL sources (when `url` is present), search-suggestion
110
+ * entries are skipped (they are HTML widgets, not citations)
111
+ * - `google_maps_result` -> URL sources for each place with a `url`
112
+ * - `file_search_result` -> document sources (best-effort -- `result[]` is loosely typed)
113
+ */
114
+ export function builtinToolResultToSources({
115
+ block,
116
+ generateId,
117
+ }: {
118
+ block: GoogleInteractionsBuiltinToolResultContent;
119
+ generateId: () => string;
120
+ }): Array<LanguageModelV3Source> {
121
+ const sources: Array<LanguageModelV3Source> = [];
122
+
123
+ switch (block.type) {
124
+ case 'url_context_result': {
125
+ const result =
126
+ (block as GoogleInteractionsURLContextResultContent).result ?? [];
127
+ for (const entry of result) {
128
+ if (entry?.url == null || entry.url.length === 0) continue;
129
+ if (entry.status != null && entry.status !== 'success') continue;
130
+ sources.push({
131
+ type: 'source',
132
+ sourceType: 'url',
133
+ id: generateId(),
134
+ url: entry.url,
135
+ });
136
+ }
137
+ break;
138
+ }
139
+ case 'google_search_result': {
140
+ const result =
141
+ (block as GoogleInteractionsGoogleSearchResultContent).result ?? [];
142
+ for (const entry of result) {
143
+ const url = entry?.url;
144
+ if (url == null || url.length === 0) continue;
145
+ sources.push({
146
+ type: 'source',
147
+ sourceType: 'url',
148
+ id: generateId(),
149
+ url,
150
+ ...(entry.title != null ? { title: entry.title } : {}),
151
+ });
152
+ }
153
+ break;
154
+ }
155
+ case 'google_maps_result': {
156
+ const result =
157
+ (block as GoogleInteractionsGoogleMapsResultContent).result ?? [];
158
+ for (const entry of result) {
159
+ for (const place of entry.places ?? []) {
160
+ if (place.url == null || place.url.length === 0) continue;
161
+ sources.push({
162
+ type: 'source',
163
+ sourceType: 'url',
164
+ id: generateId(),
165
+ url: place.url,
166
+ ...(place.name != null ? { title: place.name } : {}),
167
+ });
168
+ }
169
+ }
170
+ break;
171
+ }
172
+ case 'file_search_result': {
173
+ const result = (block as { result?: Array<unknown> }).result ?? [];
174
+ for (const raw of result) {
175
+ if (raw == null || typeof raw !== 'object') continue;
176
+ const entry = raw as {
177
+ file_name?: string;
178
+ document_uri?: string;
179
+ source?: string;
180
+ title?: string;
181
+ };
182
+ const uri = entry.document_uri ?? entry.source ?? entry.file_name;
183
+ if (uri == null || uri.length === 0) continue;
184
+ if (uri.startsWith('http://') || uri.startsWith('https://')) {
185
+ sources.push({
186
+ type: 'source',
187
+ sourceType: 'url',
188
+ id: generateId(),
189
+ url: uri,
190
+ ...(entry.title != null ? { title: entry.title } : {}),
191
+ });
192
+ continue;
193
+ }
194
+ const filename = entry.file_name ?? basename(uri);
195
+ const mediaType = inferDocMediaType(uri);
196
+ sources.push({
197
+ type: 'source',
198
+ sourceType: 'document',
199
+ id: generateId(),
200
+ mediaType,
201
+ title: entry.title ?? entry.file_name ?? filename ?? uri,
202
+ ...(filename != null ? { filename } : {}),
203
+ });
204
+ }
205
+ break;
206
+ }
207
+ default:
208
+ break;
209
+ }
210
+
211
+ return sources;
212
+ }
213
+
214
+ /**
215
+ * Given a list of annotations attached to a single `text` content block,
216
+ * returns the corresponding `LanguageModelV3Source` parts (de-duplicated by
217
+ * URL/filename to avoid double-counting when the same citation reappears
218
+ * across deltas).
219
+ */
220
+ export function annotationsToSources({
221
+ annotations,
222
+ generateId,
223
+ }: {
224
+ annotations:
225
+ | Array<GoogleInteractionsAnnotation | { type: string }>
226
+ | null
227
+ | undefined;
228
+ generateId: () => string;
229
+ }): Array<LanguageModelV3Source> {
230
+ if (annotations == null) return [];
231
+ const seen = new Set<string>();
232
+ const sources: Array<LanguageModelV3Source> = [];
233
+ for (const annotation of annotations) {
234
+ const source = annotationToSource({ annotation, generateId });
235
+ if (source == null) continue;
236
+ const key =
237
+ source.sourceType === 'url'
238
+ ? `url:${source.url}`
239
+ : `doc:${source.filename ?? source.title}`;
240
+ if (seen.has(key)) continue;
241
+ seen.add(key);
242
+ sources.push(source);
243
+ }
244
+ return sources;
245
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Type-only module: declares the union of supported Gemini Interactions agent
3
+ * names. Used by the `google.interactions({ agent })` factory branch.
4
+ *
5
+ * Sourced from `googleapis/js-genai` `src/interactions/resources/interactions.ts`
6
+ * (`Interaction.agent` enum). Subject to expansion as Google adds new agents.
7
+ *
8
+ * This is a strict string-literal union (no `string` escape hatch) so that
9
+ * passing an unknown agent name is a compile-time error. Add new agents here
10
+ * as Google publishes them.
11
+ */
12
+
13
+ export type GoogleInteractionsAgentName =
14
+ | 'deep-research-pro-preview-12-2025'
15
+ | 'deep-research-preview-04-2026'
16
+ | 'deep-research-max-preview-04-2026';