Skip to content

Commit acc82c5

Browse files
yeesiancopybara-github
authored andcommitted
fix: Handle the streaming of JSON delimited by newlines
PiperOrigin-RevId: 720749340
1 parent c5916fe commit acc82c5

File tree

28 files changed

+61
-87
lines changed

28 files changed

+61
-87
lines changed

.release-please-manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "1.79.0"
2+
".": "1.78.0"
33
}

CHANGELOG.md

-30
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,5 @@
11
# Changelog
22

3-
## [1.79.0](https://github.com/googleapis/python-aiplatform/compare/v1.78.0...v1.79.0) (2025-01-28)
4-
5-
6-
### Features
7-
8-
* Add machine_spec, data_persistent_disk_spec, network_spec, euc_config, shielded_vm_config to `.google.cloud.aiplatform.v1beta1.NotebookRuntime` ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
9-
* Add machine_spec, data_persistent_disk_spec, network_spec, euc_config, shielded_vm_config to message `.google.cloud.aiplatform.v1.NotebookRuntime` ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
10-
* Add per-modality token count break downs for GenAI APIs ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
11-
* Add per-modality token count break downs for GenAI APIs ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
12-
* Add speculative decoding spec to DeployedModel proto ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
13-
* Enable FeatureGroup IAM Methods in v1beta1 API version ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
14-
* Enable FeatureView Service Account in v1 API version ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
15-
* Enable UpdateFeatureMonitor in v1beta1 API version ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
16-
* Expose code execution tool API to v1 ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
17-
* GenAI Evaluation: Release GenAI Evaluation SDK Autorater Config/Tuning/Evaluation to vertexai.preview module. ([4531d08](https://github.com/googleapis/python-aiplatform/commit/4531d08c1c9c4a1949f532be9d2beddc53d154b1))
18-
* Reasoning Engine v1 GAPIC release ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
19-
* Remove autorater config related visibility v1beta1 ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
20-
* Update supported locations ([50a66b7](https://github.com/googleapis/python-aiplatform/commit/50a66b778fec5d5bfc87536888e0b835bd8d9db2))
21-
* Upload aggregate metrics and generative models used in an evaluation to GCS. ([713ffac](https://github.com/googleapis/python-aiplatform/commit/713ffac6f6f19408bf629dedc06450cee493dae2))
22-
23-
24-
### Documentation
25-
26-
* Deprecate `is_default` in message `.google.cloud.aiplatform.v1.NotebookRuntimeTemplate` ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
27-
* Deprecate `is_default` in message `.google.cloud.aiplatform.v1beta1.NotebookRuntimeTemplate` ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
28-
* Deprecate `service_account` in message `.google.cloud.aiplatform.v1.NotebookRuntime` ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
29-
* Deprecate `service_account` in message `.google.cloud.aiplatform.v1.NotebookRuntimeTemplate` ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
30-
* Deprecate `service_account` in message `.google.cloud.aiplatform.v1beta1.NotebookRuntime` ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
31-
* Deprecate `service_account` in message `.google.cloud.aiplatform.v1beta1.NotebookRuntimeTemplate` ([4620e6f](https://github.com/googleapis/python-aiplatform/commit/4620e6f0b0623e18b6e676f4183e972c8ad7e89e))
32-
333
## [1.78.0](https://github.com/googleapis/python-aiplatform/compare/v1.77.0...v1.78.0) (2025-01-21)
344

355

google/cloud/aiplatform/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1/schema/predict/instance/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1/schema/predict/instance_v1/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1/schema/predict/params/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1/schema/predict/params_v1/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1/schema/predict/prediction/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1/schema/predict/prediction_v1/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1/schema/trainingjob/definition/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1/schema/trainingjob/definition_v1/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1beta1/schema/predict/instance/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1beta1/schema/predict/instance_v1beta1/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1beta1/schema/predict/params/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1beta1/schema/predict/params_v1beta1/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1beta1/schema/predict/prediction/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1beta1/schema/predict/prediction_v1beta1/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1beta1/schema/trainingjob/definition/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/v1beta1/schema/trainingjob/definition_v1beta1/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform/version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
# limitations under the License.
1616
#
1717

18-
__version__ = "1.79.0"
18+
__version__ = "1.78.0"

google/cloud/aiplatform_v1/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

google/cloud/aiplatform_v1beta1/gapic_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "1.79.0" # {x-release-please-version}
16+
__version__ = "1.78.0" # {x-release-please-version}

pypi/_vertex_ai_placeholder/version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
# limitations under the License.
1616
#
1717

18-
__version__ = "1.79.0"
18+
__version__ = "1.78.0"

samples/generated_samples/snippet_metadata_google.cloud.aiplatform.v1.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
],
99
"language": "PYTHON",
1010
"name": "google-cloud-aiplatform",
11-
"version": "1.79.0"
11+
"version": "0.1.0"
1212
},
1313
"snippets": [
1414
{

samples/generated_samples/snippet_metadata_google.cloud.aiplatform.v1beta1.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
],
99
"language": "PYTHON",
1010
"name": "google-cloud-aiplatform",
11-
"version": "1.79.0"
11+
"version": "0.1.0"
1212
},
1313
"snippets": [
1414
{

tests/unit/vertex_langchain/test_reasoning_engines.py

+14-16
Original file line numberDiff line numberDiff line change
@@ -2234,60 +2234,58 @@ class ToParsedJsonTest(parameterized.TestCase):
22342234
obj=httpbody_pb2.HttpBody(
22352235
content_type="application/json", data=b'{"a": 1, "b": "hello"}'
22362236
),
2237-
expected={"a": 1, "b": "hello"},
2237+
expected=[{"a": 1, "b": "hello"}],
22382238
),
22392239
dict(
22402240
testcase_name="invalid_json",
22412241
obj=httpbody_pb2.HttpBody(
22422242
content_type="application/json", data=b'{"a": 1, "b": "hello"'
22432243
),
2244-
expected=httpbody_pb2.HttpBody(
2245-
content_type="application/json", data=b'{"a": 1, "b": "hello"'
2246-
),
2244+
expected=['{"a": 1, "b": "hello"'], # returns the unparsed string
22472245
),
22482246
dict(
22492247
testcase_name="missing_content_type",
22502248
obj=httpbody_pb2.HttpBody(data=b'{"a": 1}'),
2251-
expected=httpbody_pb2.HttpBody(data=b'{"a": 1}'),
2249+
expected=[httpbody_pb2.HttpBody(data=b'{"a": 1}')],
22522250
),
22532251
dict(
22542252
testcase_name="missing_data",
22552253
obj=httpbody_pb2.HttpBody(content_type="application/json"),
2256-
expected=None,
2254+
expected=[None],
22572255
),
22582256
dict(
22592257
testcase_name="wrong_content_type",
22602258
obj=httpbody_pb2.HttpBody(content_type="text/plain", data=b"hello"),
2261-
expected=httpbody_pb2.HttpBody(content_type="text/plain", data=b"hello"),
2259+
expected=[httpbody_pb2.HttpBody(content_type="text/plain", data=b"hello")],
22622260
),
22632261
dict(
22642262
testcase_name="empty_data",
22652263
obj=httpbody_pb2.HttpBody(content_type="application/json", data=b""),
2266-
expected=None,
2264+
expected=[None],
22672265
),
22682266
dict(
22692267
testcase_name="unicode_data",
22702268
obj=httpbody_pb2.HttpBody(
22712269
content_type="application/json", data='{"a": "你好"}'.encode("utf-8")
22722270
),
2273-
expected={"a": "你好"},
2271+
expected=[{"a": "你好"}],
22742272
),
22752273
dict(
22762274
testcase_name="nested_json",
22772275
obj=httpbody_pb2.HttpBody(
22782276
content_type="application/json", data=b'{"a": {"b": 1}}'
22792277
),
2280-
expected={"a": {"b": 1}},
2278+
expected=[{"a": {"b": 1}}],
22812279
),
22822280
dict(
2283-
testcase_name="error_handling",
2281+
testcase_name="multiline_json",
22842282
obj=httpbody_pb2.HttpBody(
2285-
content_type="application/json", data=b'{"a": 1, "b": "hello"'
2286-
),
2287-
expected=httpbody_pb2.HttpBody(
2288-
content_type="application/json", data=b'{"a": 1, "b": "hello"'
2283+
content_type="application/json",
2284+
data=b'{"a": {"b": 1}}\n{"a": {"b": 2}}',
22892285
),
2286+
expected=[{"a": {"b": 1}}, {"a": {"b": 2}}],
22902287
),
22912288
)
22922289
def test_to_parsed_json(self, obj, expected):
2293-
self.assertEqual(_utils.to_parsed_json(obj), expected)
2290+
for got, want in zip(_utils.yield_parsed_json(obj), expected):
2291+
self.assertEqual(got, want)

vertexai/reasoning_engines/_reasoning_engines.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -840,9 +840,9 @@ def _method(self, **kwargs) -> Iterable[Any]:
840840
),
841841
)
842842
for chunk in response:
843-
parsed_json = _utils.to_parsed_json(chunk)
844-
if parsed_json is not None:
845-
yield parsed_json
843+
for parsed_json in _utils.yield_parsed_json(chunk):
844+
if parsed_json is not None:
845+
yield parsed_json
846846

847847
_method.__name__ = method_name
848848
_method.__doc__ = doc

vertexai/reasoning_engines/_utils.py

+20-14
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import json
1818
import types
1919
import typing
20-
from typing import Any, Callable, Dict, Mapping, Optional, Sequence, Union
20+
from typing import Any, Callable, Dict, Iterable, Mapping, Optional, Sequence, Union
2121

2222
import proto
2323

@@ -90,36 +90,42 @@ def to_dict(message: proto.Message) -> JsonDict:
9090
return result
9191

9292

93-
def to_parsed_json(body: httpbody_pb2.HttpBody) -> Any:
93+
def yield_parsed_json(body: httpbody_pb2.HttpBody) -> Iterable[Any]:
9494
"""Converts the contents of the httpbody message to JSON format.
9595
9696
Args:
9797
body (httpbody_pb2.HttpBody):
9898
Required. The httpbody body to be converted to a JSON.
9999
100-
Returns:
100+
Yields:
101101
Any: A JSON object or the original body if it is not JSON or None.
102102
"""
103103
content_type = getattr(body, "content_type", None)
104104
data = getattr(body, "data", None)
105105

106106
if content_type is None or data is None or "application/json" not in content_type:
107-
return body
107+
yield body
108+
return
108109

109110
try:
110111
utf8_data = data.decode("utf-8")
111112
except Exception as e:
112113
_LOGGER.warning(f"Failed to decode data: {data}. Exception: {e}")
113-
return body
114+
yield body
115+
return
114116

115117
if not utf8_data:
116-
return None
118+
yield None
119+
return
117120

118-
try:
119-
return json.loads(utf8_data)
120-
except Exception as e:
121-
_LOGGER.warning(f"Failed to parse JSON: {utf8_data}. Exception: {e}")
122-
return body # Return the raw body on error
121+
# Handle the case of multiple dictionaries delimited by newlines.
122+
for line in utf8_data.split("\n"):
123+
if line:
124+
try:
125+
line = json.loads(line)
126+
except Exception as e:
127+
_LOGGER.warning(f"failed to parse json: {line}. Exception: {e}")
128+
yield line
123129

124130

125131
def generate_schema(
@@ -195,9 +201,9 @@ def generate_schema(
195201
# * https://github.com/pydantic/pydantic/issues/1270
196202
# * https://stackoverflow.com/a/58841311
197203
# * https://github.com/pydantic/pydantic/discussions/4872
198-
if typing.get_origin(annotation) is typing.Union and type(
199-
None
200-
) in typing.get_args(annotation):
204+
if typing.get_origin(annotation) is Union and type(None) in typing.get_args(
205+
annotation
206+
):
201207
# for "typing.Optional" arguments, function_arg might be a
202208
# dictionary like
203209
#

0 commit comments

Comments
 (0)