Skip to content

Commit 86ded85

Browse files
committed
Fixing serialization issues
1 parent df5ca1c commit 86ded85

File tree

3 files changed

+33
-7
lines changed

3 files changed

+33
-7
lines changed

temporalio/contrib/openai_agents/_invoke_model_activity.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""
55

66
import enum
7+
import json
78
from dataclasses import dataclass
89
from datetime import timedelta
910
from typing import Any, Optional, Union
@@ -32,6 +33,7 @@
3233
AsyncOpenAI,
3334
)
3435
from openai.types.responses.tool_param import Mcp
36+
from pydantic_core import to_json
3537
from typing_extensions import Required, TypedDict
3638

3739
from temporalio import activity
@@ -170,6 +172,11 @@ async def empty_on_invoke_handoff(
170172
) -> Any:
171173
return None
172174

175+
# workaround for https://github.com/pydantic/pydantic/issues/9541
176+
# ValidatorIterator returned
177+
input_json = to_json(input["input"])
178+
input_input = json.loads(input_json)
179+
173180
def make_tool(tool: ToolInput) -> Tool:
174181
if isinstance(
175182
tool,
@@ -212,7 +219,7 @@ def make_tool(tool: ToolInput) -> Tool:
212219
try:
213220
return await model.get_response(
214221
system_instructions=input.get("system_instructions"),
215-
input=input["input"],
222+
input=input_input,
216223
model_settings=input["model_settings"],
217224
tools=tools,
218225
output_schema=input.get("output_schema"),

temporalio/contrib/openai_agents/_temporal_openai_agents.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,17 @@
3434
from temporalio.contrib.openai_agents._trace_interceptor import (
3535
OpenAIAgentsTracingInterceptor,
3636
)
37-
from temporalio.contrib.pydantic import pydantic_data_converter
37+
from temporalio.converter import DataConverter
38+
from temporalio.contrib.pydantic import PydanticJSONPlainPayloadConverter, PydanticPayloadConverter
3839
from temporalio.worker import Worker, WorkerConfig
3940

41+
from temporalio.converter import (
42+
CompositePayloadConverter,
43+
DataConverter,
44+
DefaultPayloadConverter,
45+
EncodingPayloadConverter,
46+
JSONPlainPayloadConverter,
47+
)
4048

4149
@contextmanager
4250
def set_open_ai_agent_temporal_overrides(
@@ -136,6 +144,9 @@ def stream_response(
136144
"""Get a streamed response from the model. Unimplemented."""
137145
raise NotImplementedError()
138146

147+
class _OpenAIPayloadConverter(PydanticPayloadConverter):
148+
def __init__(self) -> None:
149+
super().__init__(exclude_unset=True)
139150

140151
class OpenAIAgentsPlugin(temporalio.client.Plugin, temporalio.worker.Plugin):
141152
"""Temporal plugin for integrating OpenAI agents with Temporal workflows.
@@ -232,7 +243,9 @@ def configure_client(self, config: ClientConfig) -> ClientConfig:
232243
Returns:
233244
The modified client configuration.
234245
"""
235-
config["data_converter"] = pydantic_data_converter
246+
config["data_converter"] = DataConverter(
247+
payload_converter_class=_OpenAIPayloadConverter
248+
)
236249
return super().configure_client(config)
237250

238251
def configure_worker(self, config: WorkerConfig) -> WorkerConfig:

temporalio/contrib/pydantic.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
from typing import Any, Optional, Type
1717

1818
from pydantic import TypeAdapter
19-
from pydantic_core import to_json
19+
from pydantic_core import to_json, SchemaSerializer
20+
from pydantic_core.core_schema import any_schema
2021

2122
import temporalio.api.common.v1
2223
from temporalio.converter import (
@@ -44,6 +45,10 @@ class PydanticJSONPlainPayloadConverter(EncodingPayloadConverter):
4445
See https://docs.pydantic.dev/latest/api/standard_library_types/
4546
"""
4647

48+
def __init__(self, exclude_unset = False):
49+
self._schema_serializer = SchemaSerializer(any_schema())
50+
self._exclude_unset = exclude_unset
51+
4752
@property
4853
def encoding(self) -> str:
4954
"""See base class."""
@@ -57,8 +62,9 @@ def to_payload(self, value: Any) -> Optional[temporalio.api.common.v1.Payload]:
5762
See
5863
https://docs.pydantic.dev/latest/api/pydantic_core/#pydantic_core.to_json.
5964
"""
65+
data = self._schema_serializer.to_json(value, exclude_unset=self._exclude_unset) if self._exclude_unset else to_json(value)
6066
return temporalio.api.common.v1.Payload(
61-
metadata={"encoding": self.encoding.encode()}, data=to_json(value)
67+
metadata={"encoding": self.encoding.encode()}, data=data
6268
)
6369

6470
def from_payload(
@@ -85,9 +91,9 @@ class PydanticPayloadConverter(CompositePayloadConverter):
8591
:py:class:`PydanticJSONPlainPayloadConverter`.
8692
"""
8793

88-
def __init__(self) -> None:
94+
def __init__(self, exclude_unset=False) -> None:
8995
"""Initialize object"""
90-
json_payload_converter = PydanticJSONPlainPayloadConverter()
96+
json_payload_converter = PydanticJSONPlainPayloadConverter(exclude_unset=exclude_unset)
9197
super().__init__(
9298
*(
9399
c

0 commit comments

Comments
 (0)