@ai-sdk/google 3.0.137 → 3.0.139

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/google",
3
- "version": "3.0.137",
3
+ "version": "3.0.139",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -109,8 +109,18 @@ function convertJSONSchemaDefinition(
109
109
  if (nonNullTypes.length === 0) {
110
110
  // Only null type
111
111
  result.type = 'null';
112
+ } else if (nonNullTypes.length === 1) {
113
+ // A single type stays a plain node so sibling keywords (items,
114
+ // format, ...) remain valid: Gemini rejects fields beside anyOf and
115
+ // items on a non-array node.
116
+ result.type = nonNullTypes[0];
117
+ if (hasNull) {
118
+ result.nullable = true;
119
+ }
112
120
  } else {
113
- // One or more non-null types: always use anyOf
121
+ // Multiple non-null types: use anyOf. Type-specific keywords
122
+ // (items, format, ...) still land beside it, which Gemini rejects;
123
+ // splitting them per branch is not handled yet.
114
124
  result.anyOf = nonNullTypes.map(t => ({ type: t }));
115
125
  if (hasNull) {
116
126
  result.nullable = true;
@@ -51,8 +51,14 @@ export class GoogleJSONAccumulator {
51
51
  let delta = '';
52
52
 
53
53
  for (const arg of partialArgs) {
54
- const rawPath = arg.jsonPath.replace(/^\$\./, '');
55
- if (!rawPath) continue;
54
+ // Vertex terminates an array with a value-less `$.path[]` entry. For an
55
+ // empty array, that terminator is the only entry sent for the path.
56
+ const isArrayTerminator = arg.jsonPath.endsWith('[]');
57
+ const jsonPath = isArrayTerminator
58
+ ? arg.jsonPath.slice(0, -2)
59
+ : arg.jsonPath;
60
+ const rawPath = jsonPath.replace(/^\$\./, '');
61
+ if (!rawPath || rawPath === '$') continue;
56
62
 
57
63
  const segments = parsePath(rawPath);
58
64
 
@@ -72,7 +78,20 @@ export class GoogleJSONAccumulator {
72
78
  }
73
79
 
74
80
  const resolved = resolvePartialArgValue(arg);
75
- if (resolved == null) continue;
81
+ if (resolved == null) {
82
+ // A value-less entry for a path without a value is an empty container
83
+ // (an empty container has no leaves to stream). Value-less entries for
84
+ // existing paths are string or array terminators and are ignored.
85
+ if (existingValue !== undefined || arg.willContinue === true) continue;
86
+
87
+ setNestedValue(
88
+ this.accumulatedArgs,
89
+ segments,
90
+ isArrayTerminator ? [] : {},
91
+ );
92
+ delta += this.emitContainer(segments, isArrayTerminator);
93
+ continue;
94
+ }
76
95
 
77
96
  setNestedValue(this.accumulatedArgs, segments, resolved.value);
78
97
  delta += this.emitNavigationTo(segments, arg, resolved.json);
@@ -141,6 +160,36 @@ export class GoogleJSONAccumulator {
141
160
  return fragment;
142
161
  }
143
162
 
163
+ /**
164
+ * Navigates to `targetSegments` and opens a container there. The container
165
+ * stays open so later entries for its children continue inside it; it is
166
+ * closed by subsequent navigation or by `finalize()`.
167
+ *
168
+ * Input: targetSegments=["nested","tags"], isArray=true
169
+ * Output: '{"nested":{"tags":['
170
+ */
171
+ private emitContainer(
172
+ targetSegments: PathSegment[],
173
+ isArray: boolean,
174
+ ): string {
175
+ let fragment = '';
176
+
177
+ if (this.stringOpen) {
178
+ fragment += '"';
179
+ this.stringOpen = false;
180
+ }
181
+
182
+ fragment += this.ensureRoot();
183
+
184
+ const commonDepth = this.findCommonStackDepth(targetSegments);
185
+
186
+ fragment += this.closeDownTo(commonDepth);
187
+ // openDownTo infers the innermost container type from the leaf segment type
188
+ fragment += this.openDownTo(targetSegments, isArray ? 0 : '');
189
+
190
+ return fragment;
191
+ }
192
+
144
193
  /**
145
194
  * Returns the stack depth to preserve when navigating to a new target
146
195
  * container path. Always >= 1 (the root is never popped).