From 4c2009374cc8c51772023b48b88806a197a7de0d Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sat, 29 Nov 2025 19:23:39 -0500 Subject: [PATCH 01/25] add timestamps and update test snapshots --- docs/agents.md | 4 + docs/api/models/function.md | 1 + docs/deferred-tools.md | 6 + docs/message-history.md | 7 + docs/testing.md | 2 + docs/tools.md | 3 + pydantic_ai_slim/pydantic_ai/_agent_graph.py | 4 +- .../pydantic_ai/agent/__init__.py | 1 + .../pydantic_ai/agent/abstract.py | 1 + pydantic_ai_slim/pydantic_ai/agent/wrapper.py | 1 + .../pydantic_ai/durable_exec/dbos/_agent.py | 1 + .../durable_exec/prefect/_agent.py | 1 + .../durable_exec/temporal/_agent.py | 1 + pydantic_ai_slim/pydantic_ai/messages.py | 8 +- pydantic_ai_slim/pydantic_ai/models/google.py | 11 +- pydantic_ai_slim/pydantic_ai/models/groq.py | 15 +- .../pydantic_ai/models/huggingface.py | 20 +- .../pydantic_ai/models/mistral.py | 24 +- pydantic_ai_slim/pydantic_ai/models/openai.py | 44 +- .../pydantic_ai/models/openrouter.py | 11 +- pydantic_ai_slim/pydantic_ai/run.py | 2 + .../pydantic_ai/toolsets/fastmcp.py | 2 +- tests/models/test_anthropic.py | 52 ++- tests/models/test_bedrock.py | 22 +- tests/models/test_cohere.py | 17 +- tests/models/test_deepseek.py | 14 +- tests/models/test_fallback.py | 4 + tests/models/test_gemini.py | 43 +- tests/models/test_google.py | 74 +++- tests/models/test_groq.py | 173 ++++++-- tests/models/test_huggingface.py | 86 +++- tests/models/test_mcp_sampling.py | 5 +- tests/models/test_mistral.py | 238 ++++++++--- tests/models/test_model_function.py | 11 +- tests/models/test_model_test.py | 11 +- tests/models/test_openai.py | 192 +++++++-- tests/models/test_openai_responses.py | 379 +++++++++++++++--- tests/models/test_openrouter.py | 16 +- tests/models/test_outlines.py | 8 + tests/test_a2a.py | 6 +- tests/test_ag_ui.py | 9 +- tests/test_agent.py | 148 ++++++- tests/test_dbos.py | 46 ++- tests/test_history_processor.py | 107 +++-- tests/test_mcp.py | 157 ++++++-- tests/test_messages.py | 3 +- tests/test_streaming.py | 46 ++- tests/test_temporal.py | 17 +- tests/test_tools.py | 21 +- tests/test_usage_limits.py | 2 + tests/test_vercel_ai.py | 33 +- 51 files changed, 1736 insertions(+), 374 deletions(-) diff --git a/docs/agents.md b/docs/agents.md index adbbbefc98..5c07433edf 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -322,6 +322,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ), @@ -386,6 +387,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ), @@ -1050,6 +1052,7 @@ with capture_run_messages() as messages: # (2)! timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -1074,6 +1077,7 @@ with capture_run_messages() as messages: # (2)! timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( diff --git a/docs/api/models/function.md b/docs/api/models/function.md index 4cdceb449f..bfbe35c469 100644 --- a/docs/api/models/function.md +++ b/docs/api/models/function.md @@ -30,6 +30,7 @@ async def model_function( timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ] diff --git a/docs/deferred-tools.md b/docs/deferred-tools.md index 31e14149c0..fc5dc2eaa4 100644 --- a/docs/deferred-tools.md +++ b/docs/deferred-tools.md @@ -118,6 +118,7 @@ print(result.all_messages()) timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -152,6 +153,7 @@ print(result.all_messages()) timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ), ModelRequest( @@ -173,6 +175,7 @@ print(result.all_messages()) timestamp=datetime.datetime(...), ), ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -197,6 +200,7 @@ print(result.all_messages()) timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -324,6 +328,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -350,6 +355,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( diff --git a/docs/message-history.md b/docs/message-history.md index 3363312fed..7045c87c9a 100644 --- a/docs/message-history.md +++ b/docs/message-history.md @@ -51,6 +51,7 @@ print(result.all_messages()) timestamp=datetime.datetime(...), ), ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -95,6 +96,7 @@ async def main(): timestamp=datetime.datetime(...), ), ], + timestamp=datetime.datetime(...), run_id='...', ) ] @@ -122,6 +124,7 @@ async def main(): timestamp=datetime.datetime(...), ), ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -178,6 +181,7 @@ print(result2.all_messages()) timestamp=datetime.datetime(...), ), ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -198,6 +202,7 @@ print(result2.all_messages()) timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -303,6 +308,7 @@ print(result2.all_messages()) timestamp=datetime.datetime(...), ), ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -323,6 +329,7 @@ print(result2.all_messages()) timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( diff --git a/docs/testing.md b/docs/testing.md index 3089585ab0..7178039af0 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -128,6 +128,7 @@ async def test_forecast(): timestamp=IsNow(tz=timezone.utc), # (7)! ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -158,6 +159,7 @@ async def test_forecast(): timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( diff --git a/docs/tools.md b/docs/tools.md index 40dcf5c810..2b8d9247b8 100644 --- a/docs/tools.md +++ b/docs/tools.md @@ -88,6 +88,7 @@ print(dice_result.all_messages()) timestamp=datetime.datetime(...), ), ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -110,6 +111,7 @@ print(dice_result.all_messages()) timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -132,6 +134,7 @@ print(dice_result.all_messages()) timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( diff --git a/pydantic_ai_slim/pydantic_ai/_agent_graph.py b/pydantic_ai_slim/pydantic_ai/_agent_graph.py index 92c45a0c52..821427411e 100644 --- a/pydantic_ai_slim/pydantic_ai/_agent_graph.py +++ b/pydantic_ai_slim/pydantic_ai/_agent_graph.py @@ -19,7 +19,7 @@ from pydantic_ai._function_schema import _takes_ctx as is_takes_ctx # type: ignore from pydantic_ai._instrumentation import DEFAULT_INSTRUMENTATION_VERSION from pydantic_ai._tool_manager import ToolManager -from pydantic_ai._utils import dataclasses_no_defaults_repr, get_union_args, is_async_callable, run_in_executor +from pydantic_ai._utils import dataclasses_no_defaults_repr, get_union_args, is_async_callable, now_utc, run_in_executor from pydantic_ai.builtin_tools import AbstractBuiltinTool from pydantic_graph import BaseNode, GraphRunContext from pydantic_graph.beta import Graph, GraphBuilder @@ -447,6 +447,7 @@ async def stream( assert not self._did_stream, 'stream() should only be called once per node' model_settings, model_request_parameters, message_history, run_context = await self._prepare_request(ctx) + self.request.timestamp = now_utc() async with ctx.deps.model.request_stream( message_history, model_settings, model_request_parameters, run_context ) as streamed_response: @@ -479,6 +480,7 @@ async def _make_request( return self._result # pragma: no cover model_settings, model_request_parameters, message_history, _ = await self._prepare_request(ctx) + self.request.timestamp = now_utc() model_response = await ctx.deps.model.request(message_history, model_settings, model_request_parameters) ctx.state.usage.requests += 1 diff --git a/pydantic_ai_slim/pydantic_ai/agent/__init__.py b/pydantic_ai_slim/pydantic_ai/agent/__init__.py index 85ed332d0b..baa7ac841a 100644 --- a/pydantic_ai_slim/pydantic_ai/agent/__init__.py +++ b/pydantic_ai_slim/pydantic_ai/agent/__init__.py @@ -524,6 +524,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ), diff --git a/pydantic_ai_slim/pydantic_ai/agent/abstract.py b/pydantic_ai_slim/pydantic_ai/agent/abstract.py index cc99f80e74..6c540ede64 100644 --- a/pydantic_ai_slim/pydantic_ai/agent/abstract.py +++ b/pydantic_ai_slim/pydantic_ai/agent/abstract.py @@ -1030,6 +1030,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ), diff --git a/pydantic_ai_slim/pydantic_ai/agent/wrapper.py b/pydantic_ai_slim/pydantic_ai/agent/wrapper.py index f363b5d990..e27e6e054c 100644 --- a/pydantic_ai_slim/pydantic_ai/agent/wrapper.py +++ b/pydantic_ai_slim/pydantic_ai/agent/wrapper.py @@ -169,6 +169,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ), diff --git a/pydantic_ai_slim/pydantic_ai/durable_exec/dbos/_agent.py b/pydantic_ai_slim/pydantic_ai/durable_exec/dbos/_agent.py index c5adf5221d..79465fe8b0 100644 --- a/pydantic_ai_slim/pydantic_ai/durable_exec/dbos/_agent.py +++ b/pydantic_ai_slim/pydantic_ai/durable_exec/dbos/_agent.py @@ -824,6 +824,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ), diff --git a/pydantic_ai_slim/pydantic_ai/durable_exec/prefect/_agent.py b/pydantic_ai_slim/pydantic_ai/durable_exec/prefect/_agent.py index 60c8122686..ba38aa9304 100644 --- a/pydantic_ai_slim/pydantic_ai/durable_exec/prefect/_agent.py +++ b/pydantic_ai_slim/pydantic_ai/durable_exec/prefect/_agent.py @@ -769,6 +769,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ), diff --git a/pydantic_ai_slim/pydantic_ai/durable_exec/temporal/_agent.py b/pydantic_ai_slim/pydantic_ai/durable_exec/temporal/_agent.py index 42fc2a872e..0016d76084 100644 --- a/pydantic_ai_slim/pydantic_ai/durable_exec/temporal/_agent.py +++ b/pydantic_ai_slim/pydantic_ai/durable_exec/temporal/_agent.py @@ -843,6 +843,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ), diff --git a/pydantic_ai_slim/pydantic_ai/messages.py b/pydantic_ai_slim/pydantic_ai/messages.py index 826cf754b2..b0a1cf9361 100644 --- a/pydantic_ai_slim/pydantic_ai/messages.py +++ b/pydantic_ai_slim/pydantic_ai/messages.py @@ -1001,6 +1001,9 @@ class ModelRequest: _: KW_ONLY + timestamp: datetime = field(default_factory=_now_utc) + """The timestamp when the request was sent to the model.""" + instructions: str | None = None """The instructions for the model.""" @@ -1242,9 +1245,10 @@ class ModelResponse: """The name of the model that generated the response.""" timestamp: datetime = field(default_factory=_now_utc) - """The timestamp of the response. + """The timestamp when the response was received locally. - If the model provides a timestamp in the response (as OpenAI does) that will be used. + This is always a high-precision local datetime. Provider-specific timestamps + (if available) are stored in `provider_details['timestamp']`. """ kind: Literal['response'] = 'response' diff --git a/pydantic_ai_slim/pydantic_ai/models/google.py b/pydantic_ai_slim/pydantic_ai/models/google.py index c6f5459f08..248509712f 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -500,6 +500,8 @@ def _process_response(self, response: GenerateContentResponse) -> ModelResponse: raw_finish_reason = candidate.finish_reason if raw_finish_reason: # pragma: no branch vendor_details = {'finish_reason': raw_finish_reason.value} + if response.create_time is not None: + vendor_details['timestamp'] = response.create_time finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) if candidate.content is None or candidate.content.parts is None: @@ -538,9 +540,10 @@ async def _process_streamed_response( model_request_parameters=model_request_parameters, _model_name=first_chunk.model_version or self._model_name, _response=peekable_response, - _timestamp=first_chunk.create_time or _utils.now_utc(), + _timestamp=_utils.now_utc(), _provider_name=self._provider.name, _provider_url=self._provider.base_url, + _provider_timestamp=first_chunk.create_time, ) async def _map_messages( @@ -665,6 +668,7 @@ class GeminiStreamedResponse(StreamedResponse): _timestamp: datetime _provider_name: str _provider_url: str + _provider_timestamp: datetime | None = None async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: # noqa: C901 code_execution_tool_call_id: str | None = None @@ -681,7 +685,10 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: raw_finish_reason = candidate.finish_reason if raw_finish_reason: - self.provider_details = {'finish_reason': raw_finish_reason.value} + provider_details_dict: dict[str, Any] = {'finish_reason': raw_finish_reason.value} + if self._provider_timestamp is not None: + provider_details_dict['timestamp'] = self._provider_timestamp + self.provider_details = provider_details_dict self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) # Google streams the grounding metadata (including the web search queries and results) diff --git a/pydantic_ai_slim/pydantic_ai/models/groq.py b/pydantic_ai_slim/pydantic_ai/models/groq.py index d5f70fa451..b471832c10 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -321,7 +321,7 @@ async def _completions_create( def _process_response(self, response: chat.ChatCompletion) -> ModelResponse: """Process a non-streamed response, and prepare a message to return.""" - timestamp = number_to_datetime(response.created) + timestamp = _utils.now_utc() choice = response.choices[0] items: list[ModelResponsePart] = [] if choice.message.reasoning is not None: @@ -341,7 +341,9 @@ def _process_response(self, response: chat.ChatCompletion) -> ModelResponse: items.append(ToolCallPart(tool_name=c.function.name, args=c.function.arguments, tool_call_id=c.id)) raw_finish_reason = choice.finish_reason - provider_details = {'finish_reason': raw_finish_reason} + provider_details: dict[str, Any] = {'finish_reason': raw_finish_reason} + if response.created: # pragma: no branch + provider_details['timestamp'] = number_to_datetime(response.created) finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) return ModelResponse( parts=items, @@ -371,9 +373,10 @@ async def _process_streamed_response( _response=peekable_response, _model_name=first_chunk.model, _model_profile=self.profile, - _timestamp=number_to_datetime(first_chunk.created), + _timestamp=_utils.now_utc(), _provider_name=self._provider.name, _provider_url=self.base_url, + _provider_timestamp=first_chunk.created, ) def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[chat.ChatCompletionToolParam]: @@ -528,6 +531,7 @@ class GroqStreamedResponse(StreamedResponse): _timestamp: datetime _provider_name: str _provider_url: str + _provider_timestamp: int | None = None async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: # noqa: C901 try: @@ -546,7 +550,10 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: continue if raw_finish_reason := choice.finish_reason: - self.provider_details = {'finish_reason': raw_finish_reason} + provider_details_dict: dict[str, Any] = {'finish_reason': raw_finish_reason} + if self._provider_timestamp is not None: + provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) + self.provider_details = provider_details_dict self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) if choice.delta.reasoning is not None: diff --git a/pydantic_ai_slim/pydantic_ai/models/huggingface.py b/pydantic_ai_slim/pydantic_ai/models/huggingface.py index ab6652dbb4..3c6dad5f7e 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -272,10 +272,7 @@ async def _completions_create( def _process_response(self, response: ChatCompletionOutput) -> ModelResponse: """Process a non-streamed response, and prepare a message to return.""" - if response.created: - timestamp = datetime.fromtimestamp(response.created, tz=timezone.utc) - else: - timestamp = _now_utc() + timestamp = _now_utc() choice = response.choices[0] content = choice.message.content @@ -290,7 +287,9 @@ def _process_response(self, response: ChatCompletionOutput) -> ModelResponse: items.append(ToolCallPart(c.function.name, c.function.arguments, tool_call_id=c.id)) raw_finish_reason = choice.finish_reason - provider_details = {'finish_reason': raw_finish_reason} + provider_details: dict[str, Any] = {'finish_reason': raw_finish_reason} + if response.created: # pragma: no branch + provider_details['timestamp'] = datetime.fromtimestamp(response.created, tz=timezone.utc) finish_reason = _FINISH_REASON_MAP.get(cast(TextGenerationOutputFinishReason, raw_finish_reason), None) return ModelResponse( @@ -321,9 +320,10 @@ async def _process_streamed_response( _model_name=first_chunk.model, _model_profile=self.profile, _response=peekable_response, - _timestamp=datetime.fromtimestamp(first_chunk.created, tz=timezone.utc), + _timestamp=_now_utc(), _provider_name=self._provider.name, _provider_url=self.base_url, + _provider_timestamp=first_chunk.created, ) def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[ChatCompletionInputTool]: @@ -473,6 +473,7 @@ class HuggingFaceStreamedResponse(StreamedResponse): _timestamp: datetime _provider_name: str _provider_url: str + _provider_timestamp: int | None = None async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: async for chunk in self._response: @@ -487,7 +488,12 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: continue if raw_finish_reason := choice.finish_reason: - self.provider_details = {'finish_reason': raw_finish_reason} + provider_details_dict: dict[str, Any] = {'finish_reason': raw_finish_reason} + if self._provider_timestamp is not None: + provider_details_dict['timestamp'] = datetime.fromtimestamp( + self._provider_timestamp, tz=timezone.utc + ) + self.provider_details = provider_details_dict self.finish_reason = _FINISH_REASON_MAP.get( cast(TextGenerationOutputFinishReason, raw_finish_reason), None ) diff --git a/pydantic_ai_slim/pydantic_ai/models/mistral.py b/pydantic_ai_slim/pydantic_ai/models/mistral.py index 01fee32a25..995d76554e 100644 --- a/pydantic_ai_slim/pydantic_ai/models/mistral.py +++ b/pydantic_ai_slim/pydantic_ai/models/mistral.py @@ -348,10 +348,7 @@ def _process_response(self, response: MistralChatCompletionResponse) -> ModelRes """Process a non-streamed response, and prepare a message to return.""" assert response.choices, 'Unexpected empty response choice.' - if response.created: - timestamp = number_to_datetime(response.created) - else: - timestamp = _now_utc() + timestamp = _now_utc() choice = response.choices[0] content = choice.message.content @@ -370,7 +367,9 @@ def _process_response(self, response: MistralChatCompletionResponse) -> ModelRes parts.append(tool) raw_finish_reason = choice.finish_reason - provider_details = {'finish_reason': raw_finish_reason} + provider_details: dict[str, Any] = {'finish_reason': raw_finish_reason} + if response.created: # pragma: no branch + provider_details['timestamp'] = number_to_datetime(response.created) finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) return ModelResponse( @@ -398,18 +397,14 @@ async def _process_streamed_response( 'Streamed response ended without content or tool calls' ) - if first_chunk.data.created: - timestamp = number_to_datetime(first_chunk.data.created) - else: - timestamp = _now_utc() - return MistralStreamedResponse( model_request_parameters=model_request_parameters, _response=peekable_response, _model_name=first_chunk.data.model, - _timestamp=timestamp, + _timestamp=_now_utc(), _provider_name=self._provider.name, _provider_url=self._provider.base_url, + _provider_timestamp=first_chunk.data.created, ) @staticmethod @@ -618,7 +613,7 @@ class MistralStreamedResponse(StreamedResponse): _timestamp: datetime _provider_name: str _provider_url: str - + _provider_timestamp: int | None = None _delta_content: str = field(default='', init=False) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: @@ -635,7 +630,10 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: continue if raw_finish_reason := choice.finish_reason: - self.provider_details = {'finish_reason': raw_finish_reason} + provider_details_dict: dict[str, Any] = {'finish_reason': raw_finish_reason} + if self._provider_timestamp is not None: + provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) + self.provider_details = provider_details_dict self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) # Handle the text part of the response diff --git a/pydantic_ai_slim/pydantic_ai/models/openai.py b/pydantic_ai_slim/pydantic_ai/models/openai.py index efe9629c3a..7a3a89d9b4 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -615,10 +615,8 @@ def _process_response(self, response: chat.ChatCompletion | str) -> ModelRespons f'Invalid response from {self.system} chat completions endpoint, expected JSON data' ) - if response.created: - timestamp = number_to_datetime(response.created) - else: - timestamp = _now_utc() + timestamp = _now_utc() + if not response.created: response.created = int(timestamp.timestamp()) # Workaround for local Ollama which sometimes returns a `None` finish reason. @@ -654,12 +652,16 @@ def _process_response(self, response: chat.ChatCompletion | str) -> ModelRespons part.tool_call_id = _guard_tool_call_id(part) items.append(part) + provider_details = self._process_provider_details(response) + if response.created: # pragma: no branch + provider_details['timestamp'] = number_to_datetime(response.created) + return ModelResponse( parts=items, usage=self._map_usage(response), model_name=response.model, timestamp=timestamp, - provider_details=self._process_provider_details(response), + provider_details=provider_details, provider_response_id=response.id, provider_name=self._provider.name, provider_url=self._provider.base_url, @@ -714,9 +716,10 @@ async def _process_streamed_response( _model_name=model_name, _model_profile=self.profile, _response=peekable_response, - _timestamp=number_to_datetime(first_chunk.created), + _timestamp=_now_utc(), _provider_name=self._provider.name, _provider_url=self._provider.base_url, + _provider_timestamp=first_chunk.created, ) @property @@ -1180,7 +1183,7 @@ def _process_response( # noqa: C901 self, response: responses.Response, model_request_parameters: ModelRequestParameters ) -> ModelResponse: """Process a non-streamed response, and prepare a message to return.""" - timestamp = number_to_datetime(response.created_at) + timestamp = _now_utc() items: list[ModelResponsePart] = [] for item in response.output: if isinstance(item, responses.ResponseReasoningItem): @@ -1271,11 +1274,13 @@ def _process_response( # noqa: C901 pass finish_reason: FinishReason | None = None - provider_details: dict[str, Any] | None = None + provider_details: dict[str, Any] = {} raw_finish_reason = details.reason if (details := response.incomplete_details) else response.status if raw_finish_reason: - provider_details = {'finish_reason': raw_finish_reason} + provider_details['finish_reason'] = raw_finish_reason finish_reason = _RESPONSES_FINISH_REASON_MAP.get(raw_finish_reason) + if response.created_at: # pragma: no branch + provider_details['timestamp'] = number_to_datetime(response.created_at) return ModelResponse( parts=items, @@ -1286,7 +1291,7 @@ def _process_response( # noqa: C901 provider_name=self._provider.name, provider_url=self._provider.base_url, finish_reason=finish_reason, - provider_details=provider_details, + provider_details=provider_details or None, ) async def _process_streamed_response( @@ -1305,9 +1310,11 @@ async def _process_streamed_response( model_request_parameters=model_request_parameters, _model_name=first_chunk.response.model, _response=peekable_response, - _timestamp=number_to_datetime(first_chunk.response.created_at), + _timestamp=_now_utc(), _provider_name=self._provider.name, _provider_url=self._provider.base_url, + # type of created_at is float but it's actually a Unix timestamp in seconds + _provider_timestamp=int(first_chunk.response.created_at), ) @overload @@ -1919,6 +1926,7 @@ class OpenAIStreamedResponse(StreamedResponse): _timestamp: datetime _provider_name: str _provider_url: str + _provider_timestamp: int | None = None async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: async for chunk in self._validate_response(): @@ -1942,7 +1950,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: if raw_finish_reason := choice.finish_reason: self.finish_reason = self._map_finish_reason(raw_finish_reason) - if provider_details := self._map_provider_details(chunk): + if provider_details := self._map_provider_details(chunk): # pragma: no branch self.provider_details = provider_details for event in self._map_part_delta(choice): @@ -2035,7 +2043,10 @@ def _map_provider_details(self, chunk: ChatCompletionChunk) -> dict[str, Any] | This method may be overridden by subclasses of `OpenAIStreamResponse` to customize the provider details. """ - return _map_provider_details(chunk.choices[0]) + provider_details = _map_provider_details(chunk.choices[0]) + if self._provider_timestamp is not None: # pragma: no branch + provider_details['timestamp'] = number_to_datetime(self._provider_timestamp) + return provider_details def _map_usage(self, response: ChatCompletionChunk) -> usage.RequestUsage: return _map_usage(response, self._provider_name, self._provider_url, self.model_name) @@ -2079,6 +2090,7 @@ class OpenAIResponsesStreamedResponse(StreamedResponse): _timestamp: datetime _provider_name: str _provider_url: str + _provider_timestamp: int | None = None async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: # noqa: C901 async for chunk in self._response: @@ -2089,9 +2101,13 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: raw_finish_reason = ( details.reason if (details := chunk.response.incomplete_details) else chunk.response.status ) + provider_details: dict[str, Any] = {} if raw_finish_reason: # pragma: no branch - self.provider_details = {'finish_reason': raw_finish_reason} + provider_details['finish_reason'] = raw_finish_reason self.finish_reason = _RESPONSES_FINISH_REASON_MAP.get(raw_finish_reason) + if self._provider_timestamp is not None: # pragma: no branch + provider_details['timestamp'] = number_to_datetime(self._provider_timestamp) + self.provider_details = provider_details or None elif isinstance(chunk, responses.ResponseContentPartAddedEvent): pass # there's nothing we need to do here diff --git a/pydantic_ai_slim/pydantic_ai/models/openrouter.py b/pydantic_ai_slim/pydantic_ai/models/openrouter.py index 7ac019d43c..721d77a74a 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openrouter.py +++ b/pydantic_ai_slim/pydantic_ai/models/openrouter.py @@ -471,7 +471,8 @@ def _map_openrouter_provider_details( provider_details: dict[str, Any] = {} provider_details['downstream_provider'] = response.provider - provider_details['finish_reason'] = response.choices[0].native_finish_reason + if native_finish_reason := response.choices[0].native_finish_reason: + provider_details['finish_reason'] = native_finish_reason if usage := response.usage: if cost := usage.cost: @@ -688,6 +689,14 @@ def _map_provider_details(self, chunk: chat.ChatCompletionChunk) -> dict[str, An if provider_details := super()._map_provider_details(chunk): provider_details.update(_map_openrouter_provider_details(chunk)) + # Preserve finish_reason from previous chunk if the current chunk doesn't have one. + # After the chunk with native_finish_reason 'completed', OpenRouter sends one more + # chunk with usage data (see cassette test_openrouter_stream_with_native_options.yaml) + # which has native_finish_reason: null. Since provider_details is replaced on each + # chunk, we need to carry forward the finish_reason from the previous chunk. + if 'finish_reason' not in provider_details and self.provider_details: + if previous_finish_reason := self.provider_details.get('finish_reason'): + provider_details['finish_reason'] = previous_finish_reason return provider_details @override diff --git a/pydantic_ai_slim/pydantic_ai/run.py b/pydantic_ai_slim/pydantic_ai/run.py index 0ed3e2455d..81529856f8 100644 --- a/pydantic_ai_slim/pydantic_ai/run.py +++ b/pydantic_ai_slim/pydantic_ai/run.py @@ -64,6 +64,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ), @@ -243,6 +244,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ), diff --git a/pydantic_ai_slim/pydantic_ai/toolsets/fastmcp.py b/pydantic_ai_slim/pydantic_ai/toolsets/fastmcp.py index 2d907266fd..5e8b863e2c 100644 --- a/pydantic_ai_slim/pydantic_ai/toolsets/fastmcp.py +++ b/pydantic_ai_slim/pydantic_ai/toolsets/fastmcp.py @@ -187,7 +187,7 @@ def _map_fastmcp_tool_results(parts: list[ContentBlock]) -> list[FastMCPToolResu def _map_fastmcp_tool_result(part: ContentBlock) -> FastMCPToolResult: if isinstance(part, TextContent): return part.text - elif isinstance(part, ImageContent | AudioContent): + elif isinstance(part, (ImageContent, AudioContent)): return messages.BinaryContent(data=base64.b64decode(part.data), media_type=part.mimeType) elif isinstance(part, EmbeddedResource): if isinstance(part.resource, BlobResourceContents): diff --git a/tests/models/test_anthropic.py b/tests/models/test_anthropic.py index 0e1230a7a5..4d65461667 100644 --- a/tests/models/test_anthropic.py +++ b/tests/models/test_anthropic.py @@ -5,7 +5,7 @@ import re from collections.abc import Callable, Sequence from dataclasses import dataclass, field -from datetime import timezone +from datetime import datetime, timezone from decimal import Decimal from functools import cached_property from typing import Annotated, Any, TypeVar, cast @@ -240,6 +240,7 @@ async def test_sync_request_text_response(allow_model_requests: None): [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -256,6 +257,7 @@ async def test_sync_request_text_response(allow_model_requests: None): ), ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1057,6 +1059,7 @@ async def test_request_structured_response(allow_model_requests: None): [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1086,6 +1089,7 @@ async def test_request_structured_response(allow_model_requests: None): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1128,6 +1132,7 @@ async def get_location(loc_name: str) -> str: SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1157,6 +1162,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1186,6 +1192,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1542,6 +1549,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1584,6 +1592,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1744,6 +1753,7 @@ def simple_instructions(): [ ModelRequest( parts=[UserPromptPart(content='What is the capital of France?', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -1782,6 +1792,7 @@ async def test_anthropic_model_thinking_part(allow_model_requests: None, anthrop [ ModelRequest( parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1840,6 +1851,7 @@ async def test_anthropic_model_thinking_part(allow_model_requests: None, anthrop timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1903,6 +1915,7 @@ async def test_anthropic_model_thinking_part_redacted(allow_model_requests: None timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1950,6 +1963,7 @@ async def test_anthropic_model_thinking_part_redacted(allow_model_requests: None timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2010,6 +2024,7 @@ async def test_anthropic_model_thinking_part_redacted_stream(allow_model_request timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2154,6 +2169,7 @@ async def test_anthropic_model_thinking_part_from_other_model( timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2191,7 +2207,10 @@ async def test_anthropic_model_thinking_part_from_other_model( timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 10, 22, 37, 27, tzinfo=timezone.utc), + }, provider_response_id='resp_68c1fda6f11081a1b9fa80ae9122743506da9901a3d98ab7', finish_reason='stop', run_id=IsStr(), @@ -2217,6 +2236,7 @@ async def test_anthropic_model_thinking_part_from_other_model( timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2274,6 +2294,7 @@ async def test_anthropic_model_thinking_part_stream(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2685,6 +2706,7 @@ async def test_anthropic_web_search_tool(allow_model_requests: None, anthropic_a [ ModelRequest( parts=[UserPromptPart(content='What is the weather in San Francisco today?', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2894,6 +2916,7 @@ async def test_anthropic_web_search_tool(allow_model_requests: None, anthropic_a timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3108,6 +3131,7 @@ async def test_anthropic_model_web_search_tool_stream(allow_model_requests: None timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4155,6 +4179,7 @@ async def test_anthropic_web_fetch_tool(allow_model_requests: None, anthropic_ap timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4237,6 +4262,7 @@ async def test_anthropic_web_fetch_tool(allow_model_requests: None, anthropic_ap timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4307,6 +4333,7 @@ async def test_anthropic_web_fetch_tool(allow_model_requests: None, anthropic_ap timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4404,6 +4431,7 @@ async def test_anthropic_web_fetch_tool_stream( timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5019,6 +5047,7 @@ async def test_anthropic_mcp_servers(allow_model_requests: None, anthropic_api_k timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5106,6 +5135,7 @@ async def test_anthropic_mcp_servers(allow_model_requests: None, anthropic_api_k timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5272,6 +5302,7 @@ async def test_anthropic_mcp_servers_stream(allow_model_requests: None, anthropi timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5535,6 +5566,7 @@ async def test_anthropic_code_execution_tool(allow_model_requests: None, anthrop [ ModelRequest( parts=[UserPromptPart(content='How much is 3 * 12390?', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), instructions='Always use the code execution tool for math.', run_id=IsStr(), ), @@ -5603,6 +5635,7 @@ async def test_anthropic_code_execution_tool(allow_model_requests: None, anthrop timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), instructions='Always use the code execution tool for math.', run_id=IsStr(), ), @@ -5685,6 +5718,7 @@ async def test_anthropic_code_execution_tool_stream(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6270,6 +6304,7 @@ async def test_anthropic_server_tool_pass_history_to_another_provider( [ ModelRequest( parts=[UserPromptPart(content='What day is tomorrow?', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6284,7 +6319,10 @@ async def test_anthropic_server_tool_pass_history_to_another_provider( timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 11, 19, 23, 41, 8, tzinfo=timezone.utc), + }, provider_response_id='resp_0dcd74f01910b54500691e5594957481a0ac36dde76eca939f', finish_reason='stop', run_id=IsStr(), @@ -6385,6 +6423,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6419,6 +6458,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6457,6 +6497,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6491,6 +6532,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6528,6 +6570,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6587,6 +6630,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6621,6 +6665,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6673,6 +6718,7 @@ class CountryLanguage(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( diff --git a/tests/models/test_bedrock.py b/tests/models/test_bedrock.py index 185468021a..91c502b5fa 100644 --- a/tests/models/test_bedrock.py +++ b/tests/models/test_bedrock.py @@ -131,6 +131,7 @@ async def test_bedrock_model(allow_model_requests: None, bedrock_provider: Bedro timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -308,6 +309,7 @@ async def temperature(city: str, date: datetime.date) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -339,6 +341,7 @@ async def temperature(city: str, date: datetime.date) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -370,6 +373,7 @@ async def temperature(city: str, date: datetime.date) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -446,6 +450,7 @@ async def get_capital(country: str) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -477,6 +482,7 @@ async def get_capital(country: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -775,6 +781,7 @@ def instructions() -> str: [ ModelRequest( parts=[UserPromptPart(content='What is the capital of France?', timestamp=IsDatetime())], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -838,6 +845,7 @@ async def test_bedrock_model_thinking_part_deepseek(allow_model_requests: None, [ ModelRequest( parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -867,6 +875,7 @@ async def test_bedrock_model_thinking_part_deepseek(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -901,6 +910,7 @@ async def test_bedrock_model_thinking_part_anthropic(allow_model_requests: None, [ ModelRequest( parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -937,6 +947,7 @@ async def test_bedrock_model_thinking_part_anthropic(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -985,6 +996,7 @@ async def test_bedrock_model_thinking_part_redacted(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1022,6 +1034,7 @@ async def test_bedrock_model_thinking_part_redacted(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1081,6 +1094,7 @@ async def test_bedrock_model_thinking_part_redacted_stream( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1216,6 +1230,7 @@ async def test_bedrock_model_thinking_part_from_other_model( timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1249,7 +1264,10 @@ async def test_bedrock_model_thinking_part_from_other_model( timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 10, 22, 46, 57, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68c1ffe0f9a48191894c46b63c1a4f440003919771fccd27', finish_reason='stop', run_id=IsStr(), @@ -1277,6 +1295,7 @@ async def test_bedrock_model_thinking_part_from_other_model( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1433,6 +1452,7 @@ async def test_bedrock_model_thinking_part_stream(allow_model_requests: None, be timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( diff --git a/tests/models/test_cohere.py b/tests/models/test_cohere.py index a1b7785801..0958d01c67 100644 --- a/tests/models/test_cohere.py +++ b/tests/models/test_cohere.py @@ -3,7 +3,7 @@ import json from collections.abc import Sequence from dataclasses import dataclass -from datetime import timezone +from datetime import datetime, timezone from typing import Any, cast import pytest @@ -128,6 +128,7 @@ async def test_request_simple_success(allow_model_requests: None): [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -142,6 +143,7 @@ async def test_request_simple_success(allow_model_requests: None): ), ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -212,6 +214,7 @@ async def test_request_structured_response(allow_model_requests: None): [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -239,6 +242,7 @@ async def test_request_structured_response(allow_model_requests: None): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -305,6 +309,7 @@ async def get_location(loc_name: str) -> str: SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -332,6 +337,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -360,6 +366,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -452,6 +459,7 @@ def simple_instructions(ctx: RunContext): [ ModelRequest( parts=[UserPromptPart(content='What is the capital of France?', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -501,6 +509,7 @@ async def test_cohere_model_thinking_part(allow_model_requests: None, co_api_key [ ModelRequest( parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -515,7 +524,10 @@ async def test_cohere_model_thinking_part(allow_model_requests: None, co_api_key timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 5, 22, 7, 17, tzinfo=timezone.utc), + }, provider_response_id='resp_68bb5f153efc81a2b3958ddb1f257ff30886f4f20524f3b9', finish_reason='stop', run_id=IsStr(), @@ -537,6 +549,7 @@ async def test_cohere_model_thinking_part(allow_model_requests: None, co_api_key timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( diff --git a/tests/models/test_deepseek.py b/tests/models/test_deepseek.py index 0ecdbbb0bb..204eb69daf 100644 --- a/tests/models/test_deepseek.py +++ b/tests/models/test_deepseek.py @@ -1,6 +1,8 @@ from __future__ import annotations as _annotations + import pytest +from datetime import datetime, timezone from inline_snapshot import snapshot from pydantic_ai import ( @@ -36,6 +38,7 @@ async def test_deepseek_model_thinking_part(allow_model_requests: None, deepseek [ ModelRequest( parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -56,7 +59,10 @@ async def test_deepseek_model_thinking_part(allow_model_requests: None, deepseek timestamp=IsDatetime(), provider_name='deepseek', provider_url='https://api.deepseek.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 4, 22, 14, 9, 11, tzinfo=timezone.utc), + }, provider_response_id='181d9669-2b3a-445e-bd13-2ebff2c378f6', finish_reason='stop', run_id=IsStr(), @@ -84,6 +90,7 @@ async def test_deepseek_model_thinking_stream(allow_model_requests: None, deepse timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -104,7 +111,10 @@ async def test_deepseek_model_thinking_stream(allow_model_requests: None, deepse timestamp=IsDatetime(), provider_name='deepseek', provider_url='https://api.deepseek.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 7, 10, 17, 41, 44, tzinfo=timezone.utc), + }, provider_response_id='33be18fc-3842-486c-8c29-dd8e578f7f20', finish_reason='stop', run_id=IsStr(), diff --git a/tests/models/test_fallback.py b/tests/models/test_fallback.py index 41c20d1e46..3dd0a012a5 100644 --- a/tests/models/test_fallback.py +++ b/tests/models/test_fallback.py @@ -77,6 +77,7 @@ def test_first_successful() -> None: parts=[ UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -104,6 +105,7 @@ def test_first_failed() -> None: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -132,6 +134,7 @@ def test_first_failed_instrumented(capfire: CaptureLogfire) -> None: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -816,6 +819,7 @@ def prompted_output_func(_: list[ModelMessage], info: AgentInfo) -> ModelRespons timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), instructions='Be kind', run_id=IsStr(), ), diff --git a/tests/models/test_gemini.py b/tests/models/test_gemini.py index ee1aa83b15..73056e3fd8 100644 --- a/tests/models/test_gemini.py +++ b/tests/models/test_gemini.py @@ -561,6 +561,7 @@ async def test_text_success(get_gemini_client: GetGeminiClient): [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -582,6 +583,7 @@ async def test_text_success(get_gemini_client: GetGeminiClient): [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -595,6 +597,7 @@ async def test_text_success(get_gemini_client: GetGeminiClient): ), ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -624,6 +627,7 @@ async def test_request_structured_response(get_gemini_client: GetGeminiClient): [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -644,6 +648,7 @@ async def test_request_structured_response(get_gemini_client: GetGeminiClient): tool_call_id=IsStr(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -689,6 +694,7 @@ async def get_location(loc_name: str) -> str: SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -711,6 +717,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -740,6 +747,7 @@ async def get_location(loc_name: str) -> str: tool_call_id=IsStr(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -899,6 +907,7 @@ async def bar(y: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -922,6 +931,7 @@ async def bar(y: str) -> str: tool_name='bar', content='b', timestamp=IsNow(tz=timezone.utc), tool_call_id=IsStr() ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -942,6 +952,7 @@ async def bar(y: str) -> str: tool_call_id=IsStr(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -988,6 +999,7 @@ def get_location(loc_name: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1015,6 +1027,7 @@ def get_location(loc_name: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -1201,6 +1214,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1234,6 +1248,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1391,6 +1406,7 @@ async def test_gemini_model_instructions(allow_model_requests: None, gemini_api_ [ ModelRequest( parts=[UserPromptPart(content='What is the capital of France?', timestamp=IsDatetime())], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -1470,6 +1486,7 @@ async def test_gemini_model_thinking_part(allow_model_requests: None, gemini_api [ ModelRequest( parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1511,7 +1528,10 @@ async def test_gemini_model_thinking_part(allow_model_requests: None, gemini_api timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': IsDatetime(), + }, provider_response_id='resp_680393ff82488191a7d0850bf0dd99a004f0817ea037a07b', finish_reason='stop', run_id=IsStr(), @@ -1531,6 +1551,7 @@ async def test_gemini_model_thinking_part(allow_model_requests: None, gemini_api [ ModelRequest( parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1545,7 +1566,10 @@ async def test_gemini_model_thinking_part(allow_model_requests: None, gemini_api timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': IsDatetime(), + }, provider_response_id='resp_680393ff82488191a7d0850bf0dd99a004f0817ea037a07b', finish_reason='stop', run_id=IsStr(), @@ -1557,6 +1581,7 @@ async def test_gemini_model_thinking_part(allow_model_requests: None, gemini_api timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1630,6 +1655,7 @@ async def test_gemini_youtube_video_url_input(allow_model_requests: None, gemini parts=[ UserPromptPart(content=['What is the main content of this URL?', url], timestamp=IsDatetime()), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1715,6 +1741,7 @@ async def bar() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1738,6 +1765,7 @@ async def bar() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1767,6 +1795,7 @@ async def bar() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -1799,6 +1828,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1822,6 +1852,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1851,6 +1882,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -1882,6 +1914,7 @@ def upcase(text: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1955,6 +1988,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2008,6 +2042,7 @@ class CountryLanguage(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2062,6 +2097,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2112,6 +2148,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2135,6 +2172,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2179,6 +2217,7 @@ class CountryLanguage(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( diff --git a/tests/models/test_google.py b/tests/models/test_google.py index be6d4bd68a..a881f719f5 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -5,6 +5,7 @@ import os import re from collections.abc import AsyncIterator +from datetime import timezone from typing import Any import pytest @@ -64,7 +65,7 @@ from pydantic_ai.settings import ModelSettings from pydantic_ai.usage import RequestUsage, RunUsage, UsageLimits -from ..conftest import IsBytes, IsDatetime, IsInstance, IsStr, try_import +from ..conftest import IsBytes, IsDatetime, IsInstance, IsNow, IsStr, try_import from ..parts_from_messages import part_types_from_messages with try_import() as imports_successful: @@ -137,6 +138,7 @@ async def test_google_model(allow_model_requests: None, google_provider: GoogleP timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -203,6 +205,7 @@ async def temperature(city: str, date: datetime.date) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -231,6 +234,7 @@ async def temperature(city: str, date: datetime.date) -> str: tool_name='temperature', content='30°C', tool_call_id=IsStr(), timestamp=IsDatetime() ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -264,6 +268,7 @@ async def temperature(city: str, date: datetime.date) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -331,6 +336,7 @@ async def test_google_model_builtin_code_execution_stream( timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -572,6 +578,7 @@ async def get_capital(country: str) -> str: SystemPromptPart(content='You are a helpful chatbot.', timestamp=IsDatetime()), UserPromptPart(content='What is the capital of France?', timestamp=IsDatetime()), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -604,6 +611,7 @@ async def get_capital(country: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -636,6 +644,7 @@ async def get_capital(country: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -942,6 +951,7 @@ def instructions() -> str: [ ModelRequest( parts=[UserPromptPart(content='What is the capital of France?', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -1016,6 +1026,7 @@ async def test_google_model_web_search_tool(allow_model_requests: None, google_p timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1096,6 +1107,7 @@ async def test_google_model_web_search_tool(allow_model_requests: None, google_p timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1191,6 +1203,7 @@ async def test_google_model_web_search_tool_stream(allow_model_requests: None, g timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1337,6 +1350,7 @@ async def test_google_model_web_search_tool_stream(allow_model_requests: None, g timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1443,6 +1457,7 @@ async def test_google_model_web_fetch_tool( timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1523,6 +1538,7 @@ async def test_google_model_web_fetch_tool_stream(allow_model_requests: None, go timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1649,6 +1665,7 @@ async def test_google_model_code_execution_tool(allow_model_requests: None, goog SystemPromptPart(content='You are a helpful chatbot.', timestamp=IsDatetime()), UserPromptPart(content='What day is today in Utrecht?', timestamp=IsDatetime()), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1718,6 +1735,7 @@ async def test_google_model_code_execution_tool(allow_model_requests: None, goog [ ModelRequest( parts=[UserPromptPart(content='What day is tomorrow?', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1947,6 +1965,7 @@ def dummy() -> None: ... # pragma: no cover timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1985,6 +2004,7 @@ def dummy() -> None: ... # pragma: no cover timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2037,6 +2057,7 @@ def dummy() -> None: ... # pragma: no cover timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2070,7 +2091,10 @@ def dummy() -> None: ... # pragma: no cover timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 10, 22, 27, 55, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68c1fb6b6a248196a6216e80fc2ace380c14a8a9087e8689', finish_reason='stop', run_id=IsStr(), @@ -2096,6 +2120,7 @@ def dummy() -> None: ... # pragma: no cover timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2153,6 +2178,7 @@ def dummy() -> None: ... # pragma: no cover timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2350,7 +2376,7 @@ async def test_google_url_input( parts=[ UserPromptPart( content=['What is the main content of this URL?', Is(url)], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), ), ], run_id=IsStr(), @@ -2393,7 +2419,7 @@ async def test_google_url_input_force_download( parts=[ UserPromptPart( content=['What is the main content of this URL?', Is(video_url)], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), ), ], run_id=IsStr(), @@ -2447,6 +2473,7 @@ async def bar() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2472,6 +2499,7 @@ async def bar() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2503,6 +2531,7 @@ async def bar() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -2545,6 +2574,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2570,6 +2600,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2601,6 +2632,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -2633,6 +2665,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2658,6 +2691,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2723,6 +2757,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2777,6 +2812,7 @@ class CountryLanguage(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2832,6 +2868,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2879,6 +2916,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2904,6 +2942,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2949,6 +2988,7 @@ class CountryLanguage(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3155,6 +3195,7 @@ async def test_google_image_generation(allow_model_requests: None, google_provid timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3196,6 +3237,7 @@ async def test_google_image_generation(allow_model_requests: None, google_provid timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3272,6 +3314,7 @@ async def test_google_image_generation_stream(allow_model_requests: None, google timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3345,6 +3388,7 @@ async def test_google_image_generation_with_text(allow_model_requests: None, goo timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3462,6 +3506,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3497,6 +3542,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3572,6 +3618,7 @@ async def test_google_image_generation_with_web_search(allow_model_requests: Non timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4147,6 +4194,7 @@ def get_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4169,7 +4217,10 @@ def get_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 11, 21, 21, 57, 19, tzinfo=datetime.timezone.utc), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -4183,6 +4234,7 @@ def get_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4203,7 +4255,10 @@ def get_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 11, 21, 21, 57, 25, tzinfo=datetime.timezone.utc), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -4247,6 +4302,7 @@ def get_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -4325,7 +4381,11 @@ async def test_google_model_retrying_after_empty_response(allow_model_requests: assert result.output == snapshot('Hello! How can I help you today?') assert result.new_messages() == snapshot( [ - ModelRequest(parts=[], run_id=IsStr()), + ModelRequest( + parts=[], + timestamp=IsNow(tz=timezone.utc), + run_id=IsStr(), + ), ModelResponse( parts=[ TextPart( diff --git a/tests/models/test_groq.py b/tests/models/test_groq.py index 0f10b4b7e4..69d67aec63 100644 --- a/tests/models/test_groq.py +++ b/tests/models/test_groq.py @@ -48,7 +48,7 @@ from pydantic_ai.output import NativeOutput, PromptedOutput from pydantic_ai.usage import RequestUsage, RunUsage -from ..conftest import IsDatetime, IsInstance, IsNow, IsStr, raise_if_exception, try_import +from ..conftest import IsDatetime, IsInstance, IsStr, raise_if_exception, try_import from .mock_async_stream import MockAsyncStream with try_import() as imports_successful: @@ -168,31 +168,39 @@ async def test_request_simple_success(allow_model_requests: None): assert result.all_messages() == snapshot( [ ModelRequest( - parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + parts=[UserPromptPart(content='hello', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='world')], model_name='llama-3.3-70b-versatile-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), ), ModelRequest( - parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + parts=[UserPromptPart(content='hello', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='world')], model_name='llama-3.3-70b-versatile-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -237,7 +245,8 @@ async def test_request_structured_response(allow_model_requests: None): assert result.all_messages() == snapshot( [ ModelRequest( - parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + parts=[UserPromptPart(content='Hello', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -249,10 +258,13 @@ async def test_request_structured_response(allow_model_requests: None): ) ], model_name='llama-3.3-70b-versatile-123', - timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc), + timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -263,9 +275,10 @@ async def test_request_structured_response(allow_model_requests: None): tool_name='final_result', content='Final result processed.', tool_call_id='123', - timestamp=IsNow(tz=timezone.utc), + timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -329,9 +342,10 @@ async def get_location(loc_name: str) -> str: [ ModelRequest( parts=[ - SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)), - UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), + SystemPromptPart(content='this is the system prompt', timestamp=IsDatetime()), + UserPromptPart(content='Hello', timestamp=IsDatetime()), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -344,10 +358,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=2, output_tokens=1), model_name='llama-3.3-70b-versatile-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -358,9 +375,10 @@ async def get_location(loc_name: str) -> str: tool_name='get_location', content='Wrong location, please try again', tool_call_id='1', - timestamp=IsNow(tz=timezone.utc), + timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -373,10 +391,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=3, output_tokens=2), model_name='llama-3.3-70b-versatile-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -387,18 +408,22 @@ async def get_location(loc_name: str) -> str: tool_name='get_location', content='{"lat": 51, "lng": 0}', tool_call_id='2', - timestamp=IsNow(tz=timezone.utc), + timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='final response')], model_name='llama-3.3-70b-versatile-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -504,7 +529,8 @@ async def test_stream_structured(allow_model_requests: None): assert result.all_messages() == snapshot( [ ModelRequest( - parts=[UserPromptPart(content='', timestamp=IsNow(tz=timezone.utc))], + parts=[UserPromptPart(content='', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -516,7 +542,7 @@ async def test_stream_structured(allow_model_requests: None): ) ], model_name='llama-3.3-70b-versatile', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', provider_response_id='x', @@ -528,9 +554,10 @@ async def test_stream_structured(allow_model_requests: None): tool_name='final_result', content='Final result processed.', tool_call_id=IsStr(), - timestamp=IsNow(tz=timezone.utc), + timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -615,6 +642,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -624,7 +652,10 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 4, 29, 20, 21, 45, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-3c327c89-e9f5-4aac-a5d5-190e6f6f25c9', finish_reason='tool_call', run_id=IsStr(), @@ -645,6 +676,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -654,7 +686,10 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 4, 29, 20, 21, 47, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-82dfad42-6a28-4089-82c3-c8633f626c0d', finish_reason='stop', run_id=IsStr(), @@ -743,6 +778,7 @@ async def test_groq_model_instructions(allow_model_requests: None, groq_api_key: [ ModelRequest( parts=[UserPromptPart(content='What is the capital of France?', timestamp=IsDatetime())], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -753,7 +789,10 @@ async def test_groq_model_instructions(allow_model_requests: None, groq_api_key: timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 4, 7, 16, 32, 53, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-7586b6a9-fb4b-4ec7-86a0-59f0a77844cf', finish_reason='stop', run_id=IsStr(), @@ -783,6 +822,7 @@ async def test_groq_model_web_search_tool(allow_model_requests: None, groq_api_k timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1022,7 +1062,10 @@ async def test_groq_model_web_search_tool(allow_model_requests: None, groq_api_k timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 9, 17, 21, 14, 13, tzinfo=timezone.utc), + }, provider_response_id='stub', finish_reason='stop', run_id=IsStr(), @@ -1054,6 +1097,7 @@ async def test_groq_model_web_search_tool_stream(allow_model_requests: None, gro timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1190,7 +1234,10 @@ async def test_groq_model_web_search_tool_stream(allow_model_requests: None, gro timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 9, 17, 21, 20, 46, tzinfo=timezone.utc), + }, provider_response_id='stub', finish_reason='stop', run_id=IsStr(), @@ -1946,6 +1993,7 @@ async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key [ ModelRequest( parts=[UserPromptPart(content='I want a recipe to cook Uruguayan alfajores.', timestamp=IsDatetime())], + timestamp=IsDatetime(), instructions='You are a chef.', run_id=IsStr(), ), @@ -1956,7 +2004,10 @@ async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 4, 19, 12, 3, 5, tzinfo=timezone.utc), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -1973,6 +2024,7 @@ async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key [ ModelRequest( parts=[UserPromptPart(content='I want a recipe to cook Uruguayan alfajores.', timestamp=IsDatetime())], + timestamp=IsDatetime(), instructions='You are a chef.', run_id=IsStr(), ), @@ -1983,7 +2035,10 @@ async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 4, 19, 12, 3, 5, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-9748c1af-1065-410a-969a-d7fb48039fbb', finish_reason='stop', run_id=IsStr(), @@ -1995,6 +2050,7 @@ async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='You are a chef.', run_id=IsStr(), ), @@ -2005,7 +2061,10 @@ async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 4, 19, 12, 3, 10, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-994aa228-883a-498c-8b20-9655d770b697', finish_reason='stop', run_id=IsStr(), @@ -2039,6 +2098,7 @@ async def test_groq_model_thinking_part_iter(allow_model_requests: None, groq_ap timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='You are a chef.', run_id=IsStr(), ), @@ -2126,7 +2186,10 @@ async def test_groq_model_thinking_part_iter(allow_model_requests: None, groq_ap timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 9, 17, 21, 29, 56, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-4ef92b12-fb9d-486f-8b98-af9b5ecac736', finish_reason='stop', run_id=IsStr(), @@ -3383,6 +3446,7 @@ async def test_groq_model_thinking_part_iter(allow_model_requests: None, groq_ap timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='You are a chef.', run_id=IsStr(), ), @@ -3489,7 +3553,10 @@ async def test_groq_model_thinking_part_iter(allow_model_requests: None, groq_ap timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 9, 17, 21, 30, 1, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-dd0af56b-f71d-4101-be2f-89efcf3f05ac', finish_reason='stop', run_id=IsStr(), @@ -5330,6 +5397,7 @@ async def get_something_by_name(name: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='Be concise. Never use pretty double quotes, just regular ones.', run_id=IsStr(), ), @@ -5370,6 +5438,7 @@ async def get_something_by_name(name: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='Be concise. Never use pretty double quotes, just regular ones.', run_id=IsStr(), ), @@ -5389,7 +5458,10 @@ async def get_something_by_name(name: str) -> str: timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 9, 2, 21, 3, 54, tzinfo=timezone.utc), + }, provider_response_id=IsStr(), finish_reason='tool_call', run_id=IsStr(), @@ -5403,6 +5475,7 @@ async def get_something_by_name(name: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='Be concise. Never use pretty double quotes, just regular ones.', run_id=IsStr(), ), @@ -5418,7 +5491,10 @@ async def get_something_by_name(name: str) -> str: timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 9, 2, 21, 3, 57, tzinfo=timezone.utc), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -5454,6 +5530,7 @@ async def get_something_by_name(name: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='Be concise. Never use pretty double quotes, just regular ones.', run_id=IsStr(), ), @@ -5501,6 +5578,7 @@ async def get_something_by_name(name: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='Be concise. Never use pretty double quotes, just regular ones.', run_id=IsStr(), ), @@ -5518,7 +5596,10 @@ async def get_something_by_name(name: str) -> str: timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 9, 2, 21, 23, 4, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-fffa1d41-1763-493a-9ced-083bd3f2d98b', finish_reason='tool_call', run_id=IsStr(), @@ -5532,6 +5613,7 @@ async def get_something_by_name(name: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='Be concise. Never use pretty double quotes, just regular ones.', run_id=IsStr(), ), @@ -5542,7 +5624,10 @@ async def get_something_by_name(name: str) -> str: timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 9, 2, 21, 23, 4, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-fe6b5685-166f-4c71-9cd7-3d5a97301bf1', finish_reason='stop', run_id=IsStr(), @@ -5584,6 +5669,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5598,7 +5684,10 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 9, 2, 20, 1, 5, tzinfo=timezone.utc), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -5628,6 +5717,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5642,7 +5732,10 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 9, 2, 20, 1, 6, tzinfo=timezone.utc), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), diff --git a/tests/models/test_huggingface.py b/tests/models/test_huggingface.py index ed99de4e56..bf0ed15986 100644 --- a/tests/models/test_huggingface.py +++ b/tests/models/test_huggingface.py @@ -168,9 +168,12 @@ async def test_simple_completion(allow_model_requests: None, huggingface_api_key ], usage=RequestUsage(input_tokens=30, output_tokens=29), model_name='Qwen/Qwen2.5-72B-Instruct-fast', - timestamp=datetime(2025, 7, 8, 13, 42, 33, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='huggingface', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 7, 8, 13, 42, 33, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-d445c0d473a84791af2acf356cc00df7', run_id=IsStr(), ) @@ -238,10 +241,13 @@ async def test_request_structured_response( ) ], model_name='hf-model', - timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='huggingface', provider_url='https://api-inference.huggingface.co', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', run_id=IsStr(), ) @@ -363,6 +369,7 @@ async def get_location(loc_name: str) -> str: SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -375,10 +382,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=1, output_tokens=1), model_name='hf-model', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='huggingface', provider_url='https://api-inference.huggingface.co', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', run_id=IsStr(), ), @@ -391,6 +401,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -403,10 +414,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=2, output_tokens=1), model_name='hf-model', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='huggingface', provider_url='https://api-inference.huggingface.co', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', run_id=IsStr(), ), @@ -419,15 +433,19 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='final response')], model_name='hf-model', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='huggingface', provider_url='https://api-inference.huggingface.co', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', run_id=IsStr(), ), @@ -645,15 +663,19 @@ async def test_image_url_input(allow_model_requests: None, huggingface_api_key: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='Hello! How can I assist you with this image of a potato?')], usage=RequestUsage(input_tokens=269, output_tokens=15), model_name='Qwen/Qwen2.5-VL-72B-Instruct', - timestamp=datetime(2025, 7, 8, 14, 4, 39, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='huggingface', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 7, 8, 14, 4, 39, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-49aa100effab4ca28514d5ccc00d7944', run_id=IsStr(), ), @@ -714,6 +736,7 @@ def simple_instructions(ctx: RunContext): [ ModelRequest( parts=[UserPromptPart(content='What is the capital of France?', timestamp=IsDatetime())], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -723,7 +746,10 @@ def simple_instructions(ctx: RunContext): model_name='Qwen/Qwen2.5-72B-Instruct-fast', timestamp=IsDatetime(), provider_name='huggingface', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 7, 2, 15, 39, 17, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-b3936940372c481b8d886e596dc75524', run_id=IsStr(), ), @@ -812,15 +838,19 @@ def response_validator(value: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='invalid-response')], model_name='hf-model', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='huggingface', provider_url='https://api-inference.huggingface.co', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', run_id=IsStr(), ), @@ -833,15 +863,19 @@ def response_validator(value: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='final-response')], model_name='hf-model', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='huggingface', provider_url='https://api-inference.huggingface.co', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', run_id=IsStr(), ), @@ -932,6 +966,7 @@ async def test_hf_model_thinking_part(allow_model_requests: None, huggingface_ap [ ModelRequest( parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -943,7 +978,10 @@ async def test_hf_model_thinking_part(allow_model_requests: None, huggingface_ap model_name='Qwen/Qwen3-235B-A22B', timestamp=IsDatetime(), provider_name='huggingface', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 7, 9, 13, 17, 45, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-957db61fe60d4440bcfe1f11f2c5b4b9', run_id=IsStr(), ), @@ -966,6 +1004,7 @@ async def test_hf_model_thinking_part(allow_model_requests: None, huggingface_ap timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -977,7 +1016,10 @@ async def test_hf_model_thinking_part(allow_model_requests: None, huggingface_ap model_name='Qwen/Qwen3-235B-A22B', timestamp=IsDatetime(), provider_name='huggingface', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 7, 9, 13, 18, 14, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-35fdec1307634f94a39f7e26f52e12a7', run_id=IsStr(), ), @@ -1007,6 +1049,7 @@ async def test_hf_model_thinking_part_iter(allow_model_requests: None, huggingfa timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1017,7 +1060,10 @@ async def test_hf_model_thinking_part_iter(allow_model_requests: None, huggingfa model_name='Qwen/Qwen3-235B-A22B', timestamp=IsDatetime(), provider_name='huggingface', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 7, 23, 19, 58, 41, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-357f347a3f5d4897b36a128fb4e4cf7b', run_id=IsStr(), ), diff --git a/tests/models/test_mcp_sampling.py b/tests/models/test_mcp_sampling.py index 1da0851c20..4218d09287 100644 --- a/tests/models/test_mcp_sampling.py +++ b/tests/models/test_mcp_sampling.py @@ -11,7 +11,7 @@ from pydantic_ai.agent import Agent from pydantic_ai.exceptions import UnexpectedModelBehavior -from ..conftest import IsNow, IsStr, try_import +from ..conftest import IsDatetime, IsNow, IsStr, try_import with try_import() as imports_successful: from mcp import CreateMessageResult @@ -55,6 +55,7 @@ def test_assistant_text(): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -92,6 +93,7 @@ def test_assistant_text_history(): [ ModelRequest( parts=[UserPromptPart(content='1', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), instructions='testing', run_id=IsStr(), ), @@ -103,6 +105,7 @@ def test_assistant_text_history(): ), ModelRequest( parts=[UserPromptPart(content='2', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), instructions='testing', run_id=IsStr(), ), diff --git a/tests/models/test_mistral.py b/tests/models/test_mistral.py index 424be8d39b..168d6efdfd 100644 --- a/tests/models/test_mistral.py +++ b/tests/models/test_mistral.py @@ -225,6 +225,7 @@ async def test_multiple_completions(allow_model_requests: None): [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -241,16 +242,20 @@ async def test_multiple_completions(allow_model_requests: None): ), ModelRequest( parts=[UserPromptPart(content='hello again', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='hello again')], usage=RequestUsage(input_tokens=1, output_tokens=1), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -291,48 +296,60 @@ async def test_three_completions(allow_model_requests: None): [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='world')], usage=RequestUsage(input_tokens=1, output_tokens=1), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), ), ModelRequest( parts=[UserPromptPart(content='hello again', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='hello again')], usage=RequestUsage(input_tokens=1, output_tokens=1), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), ), ModelRequest( parts=[UserPromptPart(content='final message', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='final message')], usage=RequestUsage(input_tokens=1, output_tokens=1), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -441,6 +458,7 @@ class CityLocation(BaseModel): [ ModelRequest( parts=[UserPromptPart(content='User prompt value', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -453,10 +471,13 @@ class CityLocation(BaseModel): ], usage=RequestUsage(input_tokens=1, output_tokens=2), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -470,6 +491,7 @@ class CityLocation(BaseModel): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -510,6 +532,7 @@ class CityLocation(BaseModel): [ ModelRequest( parts=[UserPromptPart(content='User prompt value', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -522,10 +545,13 @@ class CityLocation(BaseModel): ], usage=RequestUsage(input_tokens=1, output_tokens=1), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -539,6 +565,7 @@ class CityLocation(BaseModel): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -576,6 +603,7 @@ async def test_request_output_type_with_arguments_str_response(allow_model_reque SystemPromptPart(content='System prompt value', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='User prompt value', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -588,10 +616,13 @@ async def test_request_output_type_with_arguments_str_response(allow_model_reque ], usage=RequestUsage(input_tokens=1, output_tokens=1), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -605,6 +636,7 @@ async def test_request_output_type_with_arguments_str_response(allow_model_reque timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1132,6 +1164,7 @@ async def get_location(loc_name: str) -> str: SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1144,10 +1177,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=2, output_tokens=1), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -1161,6 +1197,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1173,10 +1210,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=3, output_tokens=2), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -1190,16 +1230,20 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='final response')], usage=RequestUsage(input_tokens=1, output_tokens=1), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -1292,6 +1336,7 @@ async def get_location(loc_name: str) -> str: SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1304,10 +1349,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=2, output_tokens=1), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -1321,6 +1369,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1333,10 +1382,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=3, output_tokens=2), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -1350,6 +1402,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1362,10 +1415,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=2, output_tokens=1), model_name='mistral-large-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -1379,6 +1435,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1442,7 +1499,7 @@ async def get_location(loc_name: str) -> str: v = [c async for c in result.stream_output(debounce_by=None)] assert v == snapshot([{'won': True}]) assert result.is_complete - assert result.timestamp() == datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc) + assert result.timestamp() == IsNow(tz=timezone.utc) assert result.usage().input_tokens == 4 assert result.usage().output_tokens == 4 @@ -1456,6 +1513,7 @@ async def get_location(loc_name: str) -> str: SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='User prompt value', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1468,10 +1526,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=2, output_tokens=2), model_name='gpt-4', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='x', finish_reason='tool_call', run_id=IsStr(), @@ -1485,16 +1546,20 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( parts=[ToolCallPart(tool_name='final_result', args='{"won": true}', tool_call_id='1')], usage=RequestUsage(input_tokens=2, output_tokens=2), model_name='gpt-4', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='x', finish_reason='tool_call', run_id=IsStr(), @@ -1508,6 +1573,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1558,7 +1624,7 @@ async def get_location(loc_name: str) -> str: v = [c async for c in result.stream_output(debounce_by=None)] assert v == snapshot(['final ', 'final response']) assert result.is_complete - assert result.timestamp() == datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc) + assert result.timestamp() == IsNow(tz=timezone.utc) assert result.usage().input_tokens == 6 assert result.usage().output_tokens == 6 @@ -1572,6 +1638,7 @@ async def get_location(loc_name: str) -> str: SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='User prompt value', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1584,10 +1651,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=2, output_tokens=2), model_name='gpt-4', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='x', finish_reason='tool_call', run_id=IsStr(), @@ -1601,16 +1671,20 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='final response')], usage=RequestUsage(input_tokens=4, output_tokens=4), model_name='gpt-4', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='x', finish_reason='stop', run_id=IsStr(), @@ -1676,7 +1750,7 @@ async def get_location(loc_name: str) -> str: v = [c async for c in result.stream_text(debounce_by=None)] assert v == snapshot(['final ', 'final response']) assert result.is_complete - assert result.timestamp() == datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc) + assert result.timestamp() == IsNow(tz=timezone.utc) assert result.usage().input_tokens == 7 assert result.usage().output_tokens == 7 @@ -1690,6 +1764,7 @@ async def get_location(loc_name: str) -> str: SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='User prompt value', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1702,10 +1777,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=2, output_tokens=2), model_name='gpt-4', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='x', finish_reason='tool_call', run_id=IsStr(), @@ -1719,6 +1797,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1731,10 +1810,13 @@ async def get_location(loc_name: str) -> str: ], usage=RequestUsage(input_tokens=1, output_tokens=1), model_name='gpt-4', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='x', finish_reason='tool_call', run_id=IsStr(), @@ -1748,16 +1830,20 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='final response')], usage=RequestUsage(input_tokens=4, output_tokens=4), model_name='gpt-4', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='x', finish_reason='stop', run_id=IsStr(), @@ -1929,6 +2015,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1938,8 +2025,11 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'tool_calls'}, - provider_response_id='412174432ea945889703eac58b44ae35', + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 4, 29, 20, 21, 48, tzinfo=timezone.utc), + }, + provider_response_id='fce6d16a4e5940edb24ae16dd0369947', finish_reason='tool_call', run_id=IsStr(), ), @@ -1959,6 +2049,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1972,8 +2063,11 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, - provider_response_id='049b5c7704554d3396e727a95cb6d947', + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 4, 29, 20, 21, 49, tzinfo=timezone.utc), + }, + provider_response_id='26e7de193646460e8904f8e604a60dc1', finish_reason='stop', run_id=IsStr(), ), @@ -2008,6 +2102,7 @@ async def test_image_url_input(allow_model_requests: None): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2017,7 +2112,10 @@ async def test_image_url_input(allow_model_requests: None): timestamp=IsDatetime(), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -2050,6 +2148,7 @@ async def test_image_as_binary_content_input(allow_model_requests: None): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2059,7 +2158,10 @@ async def test_image_as_binary_content_input(allow_model_requests: None): timestamp=IsDatetime(), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -2095,6 +2197,7 @@ async def test_pdf_url_input(allow_model_requests: None): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2104,7 +2207,10 @@ async def test_pdf_url_input(allow_model_requests: None): timestamp=IsDatetime(), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -2134,6 +2240,7 @@ async def test_pdf_as_binary_content_input(allow_model_requests: None): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2143,7 +2250,10 @@ async def test_pdf_as_binary_content_input(allow_model_requests: None): timestamp=IsDatetime(), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -2230,6 +2340,7 @@ async def test_mistral_model_instructions(allow_model_requests: None, mistral_ap [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -2240,7 +2351,10 @@ async def test_mistral_model_instructions(allow_model_requests: None, mistral_ap timestamp=IsDatetime(), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -2260,6 +2374,7 @@ async def test_mistral_model_thinking_part(allow_model_requests: None, openai_ap [ ModelRequest( parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2279,7 +2394,10 @@ async def test_mistral_model_thinking_part(allow_model_requests: None, openai_ap timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 5, 22, 29, 38, tzinfo=timezone.utc), + }, provider_response_id='resp_68bb6452990081968f5aff503a55e3b903498c8aa840cf12', finish_reason='stop', run_id=IsStr(), @@ -2302,6 +2420,7 @@ async def test_mistral_model_thinking_part(allow_model_requests: None, openai_ap timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2314,7 +2433,10 @@ async def test_mistral_model_thinking_part(allow_model_requests: None, openai_ap timestamp=IsDatetime(), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 9, 5, 22, 30, tzinfo=timezone.utc), + }, provider_response_id='9abe8b736bff46af8e979b52334a57cd', finish_reason='stop', run_id=IsStr(), @@ -2345,6 +2467,7 @@ async def test_mistral_model_thinking_part_iter(allow_model_requests: None, mist timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2379,8 +2502,11 @@ async def test_mistral_model_thinking_part_iter(allow_model_requests: None, mist timestamp=IsDatetime(), provider_name='mistral', provider_url='https://api.mistral.ai', - provider_details={'finish_reason': 'stop'}, - provider_response_id='9f9d90210f194076abeee223863eaaf0', + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 9, 9, 23, 7, 43, tzinfo=timezone.utc), + }, + provider_response_id='9faf4309c1d743d189f16b29211d8b45', finish_reason='stop', run_id=IsStr(), ), diff --git a/tests/models/test_model_function.py b/tests/models/test_model_function.py index 196b140454..f774682490 100644 --- a/tests/models/test_model_function.py +++ b/tests/models/test_model_function.py @@ -27,7 +27,7 @@ from pydantic_ai.result import RunUsage from pydantic_ai.usage import RequestUsage -from ..conftest import IsNow, IsStr +from ..conftest import IsDatetime, IsNow, IsStr pytestmark = pytest.mark.anyio @@ -68,6 +68,7 @@ def test_simple(): [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -86,6 +87,7 @@ def test_simple(): [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -97,6 +99,7 @@ def test_simple(): ), ModelRequest( parts=[UserPromptPart(content='World', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -167,6 +170,7 @@ def test_weather(): [ ModelRequest( parts=[UserPromptPart(content='London', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -189,6 +193,7 @@ def test_weather(): tool_call_id=IsStr(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -207,6 +212,7 @@ def test_weather(): tool_call_id=IsStr(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -371,6 +377,7 @@ def test_call_all(): SystemPromptPart(content='foobar', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -404,6 +411,7 @@ def test_call_all(): tool_name='quz', content='a', timestamp=IsNow(tz=timezone.utc), tool_call_id=IsStr() ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -477,6 +485,7 @@ async def test_stream_text(): [ ModelRequest( parts=[UserPromptPart(content='', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( diff --git a/tests/models/test_model_test.py b/tests/models/test_model_test.py index f7a6809a71..ae357f481c 100644 --- a/tests/models/test_model_test.py +++ b/tests/models/test_model_test.py @@ -34,7 +34,7 @@ from pydantic_ai.models.test import TestModel, _chars, _JsonSchemaTestData # pyright: ignore[reportPrivateUsage] from pydantic_ai.usage import RequestUsage, RunUsage -from ..conftest import IsNow, IsStr +from ..conftest import IsDatetime, IsNow, IsStr def test_call_one(): @@ -78,6 +78,7 @@ def test_custom_output_args(): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -102,6 +103,7 @@ def test_custom_output_args(): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -125,6 +127,7 @@ class Foo(BaseModel): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -149,6 +152,7 @@ class Foo(BaseModel): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -168,6 +172,7 @@ def test_output_type(): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -192,6 +197,7 @@ def test_output_type(): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -218,6 +224,7 @@ async def my_ret(x: int) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -236,6 +243,7 @@ async def my_ret(x: int) -> str: tool_call_id=IsStr(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -251,6 +259,7 @@ async def my_ret(x: int) -> str: tool_name='my_ret', content='1', tool_call_id=IsStr(), timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( diff --git a/tests/models/test_openai.py b/tests/models/test_openai.py index 74cb3c1414..5406a165e7 100644 --- a/tests/models/test_openai.py +++ b/tests/models/test_openai.py @@ -125,30 +125,38 @@ async def test_request_simple_success(allow_model_requests: None): [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='world')], model_name='gpt-4o-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='openai', provider_url='https://api.openai.com/v1', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), ), ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='world')], model_name='gpt-4o-123', - timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), provider_name='openai', provider_url='https://api.openai.com/v1', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -240,6 +248,7 @@ async def test_request_structured_response(allow_model_requests: None): [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -251,10 +260,13 @@ async def test_request_structured_response(allow_model_requests: None): ) ], model_name='gpt-4o-123', - timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc), + timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -268,6 +280,7 @@ async def test_request_structured_response(allow_model_requests: None): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -336,6 +349,7 @@ async def get_location(loc_name: str) -> str: SystemPromptPart(content='this is the system prompt', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -352,10 +366,13 @@ async def get_location(loc_name: str) -> str: output_tokens=1, ), model_name='gpt-4o-123', - timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc), + timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -369,6 +386,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -385,10 +403,13 @@ async def get_location(loc_name: str) -> str: output_tokens=2, ), model_name='gpt-4o-123', - timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc), + timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -402,15 +423,19 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( parts=[TextPart(content='final response')], model_name='gpt-4o-123', - timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc), + timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', run_id=IsStr(), @@ -484,7 +509,10 @@ async def test_stream_text_finish_reason(allow_model_requests: None): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, provider_response_id='123', finish_reason='stop', ) @@ -899,6 +927,7 @@ async def get_image() -> ImageUrl: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -917,7 +946,10 @@ async def get_image() -> ImageUrl: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 4, 29, 21, 7, 59, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BRmTHlrARTzAHK1na9s80xDlQGYPX', finish_reason='tool_call', run_id=IsStr(), @@ -941,6 +973,7 @@ async def get_image() -> ImageUrl: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -959,7 +992,10 @@ async def get_image() -> ImageUrl: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 4, 29, 21, 8, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BRmTI0Y2zmkGw27kLarhsmiFQTGxR', finish_reason='stop', run_id=IsStr(), @@ -988,6 +1024,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1006,7 +1043,10 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 4, 29, 20, 21, 33, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BRlkLhPc87BdohVobEJJCGq3rUAG2', finish_reason='tool_call', run_id=IsStr(), @@ -1027,6 +1067,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1045,7 +1086,10 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 4, 29, 20, 21, 36, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BRlkORPA5rXMV3uzcOcgK4eQFKCVW', finish_reason='stop', run_id=IsStr(), @@ -1251,6 +1295,7 @@ async def test_message_history_can_start_with_model_response(allow_model_request timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1269,7 +1314,10 @@ async def test_message_history_can_start_with_model_response(allow_model_request timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 11, 22, 10, 1, 40, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-Ceeiy4ivEE0hcL1EX5ZfLuW5xNUXB', finish_reason='stop', run_id=IsStr(), @@ -2056,6 +2104,7 @@ async def test_openai_instructions(allow_model_requests: None, openai_api_key: s [ ModelRequest( parts=[UserPromptPart(content='What is the capital of France?', timestamp=IsDatetime())], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -2075,7 +2124,10 @@ async def test_openai_instructions(allow_model_requests: None, openai_api_key: s timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 4, 7, 16, 30, 56, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BJjf61mLb9z5H45ClJzbx0UWKwjo1', finish_reason='stop', run_id=IsStr(), @@ -2106,6 +2158,7 @@ async def get_temperature(city: str) -> float: [ ModelRequest( parts=[UserPromptPart(content='What is the temperature in Tokyo?', timestamp=IsDatetime())], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -2125,7 +2178,10 @@ async def get_temperature(city: str) -> float: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 4, 16, 13, 37, 14, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BMxEwRA0p0gJ52oKS7806KAlfMhqq', finish_reason='tool_call', run_id=IsStr(), @@ -2136,6 +2192,7 @@ async def get_temperature(city: str) -> float: tool_name='get_temperature', content=20.0, tool_call_id=IsStr(), timestamp=IsDatetime() ) ], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -2155,7 +2212,10 @@ async def get_temperature(city: str) -> float: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 4, 16, 13, 37, 15, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BMxEx6B8JEj6oDC45MOWKp0phg8UP', finish_reason='stop', run_id=IsStr(), @@ -2175,6 +2235,7 @@ async def test_openai_model_thinking_part(allow_model_requests: None, openai_api [ ModelRequest( parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2193,7 +2254,10 @@ async def test_openai_model_thinking_part(allow_model_requests: None, openai_api timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 10, 22, 21, 57, tzinfo=timezone.utc), + }, provider_response_id='resp_68c1fa0523248197888681b898567bde093f57e27128848a', finish_reason='stop', run_id=IsStr(), @@ -2215,6 +2279,7 @@ async def test_openai_model_thinking_part(allow_model_requests: None, openai_api timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2233,7 +2298,10 @@ async def test_openai_model_thinking_part(allow_model_requests: None, openai_api timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 9, 10, 22, 22, 24, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-CENUmtwDD0HdvTUYL6lUeijDtxrZL', finish_reason='stop', run_id=IsStr(), @@ -2498,7 +2566,10 @@ def test_openai_response_timestamp_milliseconds(allow_model_requests: None): result = agent.run_sync('Hello') response = cast(ModelResponse, result.all_messages()[-1]) - assert response.timestamp == snapshot(datetime(2025, 6, 1, 3, 7, 48, tzinfo=timezone.utc)) + assert response.timestamp == IsNow(tz=timezone.utc) + assert response.provider_details == snapshot( + {'finish_reason': 'stop', 'timestamp': datetime(2025, 6, 1, 3, 7, 48, tzinfo=timezone.utc)} + ) async def test_openai_tool_output(allow_model_requests: None, openai_api_key: str): @@ -2526,6 +2597,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2544,7 +2616,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 5, 1, 23, 36, 24, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BSXk0dWkG4hfPt0lph4oFO35iT73I', finish_reason='tool_call', run_id=IsStr(), @@ -2558,6 +2633,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2582,7 +2658,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 5, 1, 23, 36, 25, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BSXk1xGHYzbhXgUkSutK08bdoNv5s', finish_reason='tool_call', run_id=IsStr(), @@ -2596,6 +2675,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -2626,6 +2706,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2646,7 +2727,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 6, 9, 21, 20, 53, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BgeDFS85bfHosRFEEAvq8reaCPCZ8', finish_reason='tool_call', run_id=IsStr(), @@ -2660,6 +2744,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2678,7 +2763,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 6, 9, 21, 20, 54, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BgeDGX9eDyVrEI56aP2vtIHahBzFH', finish_reason='stop', run_id=IsStr(), @@ -2714,6 +2802,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2734,7 +2823,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 5, 1, 23, 36, 22, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BSXjyBwGuZrtuuSzNCeaWMpGv2MZ3', finish_reason='tool_call', run_id=IsStr(), @@ -2748,6 +2840,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2766,7 +2859,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 5, 1, 23, 36, 23, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-BSXjzYGu67dhTy5r8KmjJvQ4HhDVO', finish_reason='stop', run_id=IsStr(), @@ -2804,6 +2900,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2824,7 +2921,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 6, 9, 23, 21, 26, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-Bgg5utuCSXMQ38j0n2qgfdQKcR9VD', finish_reason='tool_call', run_id=IsStr(), @@ -2838,6 +2938,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2860,7 +2961,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 6, 9, 23, 21, 27, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-Bgg5vrxUtCDlvgMreoxYxPaKxANmd', finish_reason='stop', run_id=IsStr(), @@ -2894,6 +2998,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2914,7 +3019,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 6, 10, 0, 21, 35, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-Bgh27PeOaFW6qmF04qC5uI2H9mviw', finish_reason='tool_call', run_id=IsStr(), @@ -2928,6 +3036,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2946,7 +3055,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 6, 10, 0, 21, 36, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-Bgh28advCSFhGHPnzUevVS6g6Uwg0', finish_reason='stop', run_id=IsStr(), @@ -2984,6 +3096,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -3004,7 +3117,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': datetime(2025, 6, 10, 0, 21, 38, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-Bgh2AW2NXGgMc7iS639MJXNRgtatR', finish_reason='tool_call', run_id=IsStr(), @@ -3018,6 +3134,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -3040,7 +3157,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime(2025, 6, 10, 0, 21, 39, tzinfo=timezone.utc), + }, provider_response_id='chatcmpl-Bgh2BthuopRnSqCuUgMbBnOqgkDHC', finish_reason='stop', run_id=IsStr(), diff --git a/tests/models/test_openai_responses.py b/tests/models/test_openai_responses.py index b03e99bb91..33c2cc00b3 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -4,6 +4,7 @@ from typing import Any, Literal, cast import pytest +from datetime import datetime, timezone from inline_snapshot import snapshot from pydantic import BaseModel from typing_extensions import TypedDict @@ -286,6 +287,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -308,7 +310,10 @@ async def get_location(loc_name: str) -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 3, 27, 12, 42, 44, tzinfo=timezone.utc), + }, provider_response_id='resp_67e547c48c9481918c5c4394464ce0c60ae6111e84dd5c08', finish_reason='stop', run_id=IsStr(), @@ -328,6 +333,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -346,7 +352,10 @@ async def get_location(loc_name: str) -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 3, 27, 12, 42, 45, tzinfo=timezone.utc), + }, provider_response_id='resp_67e547c5a2f08191802a1f43620f348503a2086afed73b47', finish_reason='stop', run_id=IsStr(), @@ -376,6 +385,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -392,7 +402,10 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 4, 29, 20, 21, 39, tzinfo=timezone.utc), + }, provider_response_id='resp_681134d3aa3481919ca581a267db1e510fe7a5a4e2123dc3', finish_reason='stop', run_id=IsStr(), @@ -413,6 +426,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -427,7 +441,10 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 4, 29, 20, 21, 41, tzinfo=timezone.utc), + }, provider_response_id='resp_681134d53c48819198ce7b89db78dffd02cbfeaababb040c', finish_reason='stop', run_id=IsStr(), @@ -530,7 +547,10 @@ async def get_capital(country: str) -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 3, 27, 13, 37, 38, tzinfo=timezone.utc), + }, provider_response_id='resp_67e554a21aa88191b65876ac5e5bbe0406c52f0e511c76ed', finish_reason='stop', ) @@ -564,6 +584,7 @@ async def test_openai_responses_model_builtin_tools_web_search(allow_model_reque timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -709,7 +730,10 @@ async def test_openai_responses_model_builtin_tools_web_search(allow_model_reque timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 12, 23, 19, 54, tzinfo=timezone.utc), + }, provider_response_id='resp_0e3d55e9502941380068c4aa9a62f48195a373978ed720ac63', finish_reason='stop', run_id=IsStr(), @@ -728,6 +752,7 @@ async def test_openai_responses_model_instructions(allow_model_requests: None, o [ ModelRequest( parts=[UserPromptPart(content='What is the capital of France?', timestamp=IsDatetime())], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -743,7 +768,10 @@ async def test_openai_responses_model_instructions(allow_model_requests: None, o timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 4, 7, 16, 31, 57, tzinfo=timezone.utc), + }, provider_response_id='resp_67f3fdfd9fa08191a3d5825db81b8df6003bc73febb56d77', finish_reason='stop', run_id=IsStr(), @@ -766,6 +794,7 @@ async def test_openai_responses_model_web_search_tool(allow_model_requests: None timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -808,7 +837,10 @@ async def test_openai_responses_model_web_search_tool(allow_model_requests: None timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 16, 20, 27, 26, tzinfo=timezone.utc), + }, provider_response_id='resp_028829e50fbcad090068c9c82e1e0081958ddc581008b39428', finish_reason='stop', run_id=IsStr(), @@ -827,6 +859,7 @@ async def test_openai_responses_model_web_search_tool(allow_model_requests: None timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -869,7 +902,10 @@ async def test_openai_responses_model_web_search_tool(allow_model_requests: None timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 16, 20, 27, 39, tzinfo=timezone.utc), + }, provider_response_id='resp_028829e50fbcad090068c9c83b9fb88195b6b84a32e1fc83c0', finish_reason='stop', run_id=IsStr(), @@ -898,6 +934,7 @@ async def test_openai_responses_model_web_search_tool_with_user_location( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -940,7 +977,10 @@ async def test_openai_responses_model_web_search_tool_with_user_location( timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 12, 23, 21, 23, tzinfo=timezone.utc), + }, provider_response_id='resp_0b385a0fdc82fd920068c4aaf3ced88197a88711e356b032c4', finish_reason='stop', run_id=IsStr(), @@ -970,6 +1010,7 @@ async def test_openai_responses_model_web_search_tool_with_invalid_region( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -1012,7 +1053,10 @@ async def test_openai_responses_model_web_search_tool_with_invalid_region( timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 12, 23, 21, 47, tzinfo=timezone.utc), + }, provider_response_id='resp_0b4f29854724a3120068c4ab0b660081919707b95b47552782', finish_reason='stop', run_id=IsStr(), @@ -1049,6 +1093,7 @@ async def test_openai_responses_model_web_search_tool_stream(allow_model_request timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -1097,7 +1142,10 @@ async def test_openai_responses_model_web_search_tool_stream(allow_model_request timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 16, 21, 13, 32, tzinfo=timezone.utc), + }, provider_response_id='resp_00a60507bf41223d0068c9d2fbf93481a0ba2a7796ae2cab4c', finish_reason='stop', run_id=IsStr(), @@ -1269,6 +1317,7 @@ async def test_openai_responses_model_web_search_tool_stream(allow_model_request timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -1317,7 +1366,10 @@ async def test_openai_responses_model_web_search_tool_stream(allow_model_request timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 16, 21, 13, 57, tzinfo=timezone.utc), + }, provider_response_id='resp_00a60507bf41223d0068c9d31574d881a090c232646860a771', finish_reason='stop', run_id=IsStr(), @@ -1410,6 +1462,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1426,7 +1479,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 6, 10, 0, 40, 43, tzinfo=timezone.utc), + }, provider_response_id='resp_68477f0b40a8819cb8d55594bc2c232a001fd29e2d5573f7', finish_reason='stop', run_id=IsStr(), @@ -1440,6 +1496,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1456,7 +1513,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 6, 10, 0, 40, 44, tzinfo=timezone.utc), + }, provider_response_id='resp_68477f0bfda8819ea65458cd7cc389b801dc81d4bc91f560', finish_reason='stop', run_id=IsStr(), @@ -1470,6 +1530,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -1501,6 +1562,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1517,7 +1579,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 6, 10, 0, 40, 45, tzinfo=timezone.utc), + }, provider_response_id='resp_68477f0d9494819ea4f123bba707c9ee0356a60c98816d6a', finish_reason='stop', run_id=IsStr(), @@ -1531,6 +1596,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1545,7 +1611,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 6, 10, 0, 40, 46, tzinfo=timezone.utc), + }, provider_response_id='resp_68477f0e2b28819d9c828ef4ee526d6a03434b607c02582d', finish_reason='stop', run_id=IsStr(), @@ -1582,6 +1651,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1598,7 +1668,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 6, 10, 0, 40, 47, tzinfo=timezone.utc), + }, provider_response_id='resp_68477f0f220081a1a621d6bcdc7f31a50b8591d9001d2329', finish_reason='stop', run_id=IsStr(), @@ -1612,6 +1685,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1626,7 +1700,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 6, 10, 0, 40, 47, tzinfo=timezone.utc), + }, provider_response_id='resp_68477f0fde708192989000a62809c6e5020197534e39cc1f', finish_reason='stop', run_id=IsStr(), @@ -1665,6 +1742,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1681,7 +1759,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 6, 10, 0, 40, 48, tzinfo=timezone.utc), + }, provider_response_id='resp_68477f10f2d081a39b3438f413b3bafc0dd57d732903c563', finish_reason='stop', run_id=IsStr(), @@ -1695,6 +1776,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1709,7 +1791,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 6, 10, 0, 40, 49, tzinfo=timezone.utc), + }, provider_response_id='resp_68477f119830819da162aa6e10552035061ad97e2eef7871', finish_reason='stop', run_id=IsStr(), @@ -1744,6 +1829,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1760,7 +1846,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 6, 10, 13, 11, 46, tzinfo=timezone.utc), + }, provider_response_id='resp_68482f12d63881a1830201ed101ecfbf02f8ef7f2fb42b50', finish_reason='stop', run_id=IsStr(), @@ -1774,6 +1863,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1788,7 +1878,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 6, 10, 13, 11, 55, tzinfo=timezone.utc), + }, provider_response_id='resp_68482f1b556081918d64c9088a470bf0044fdb7d019d4115', finish_reason='stop', run_id=IsStr(), @@ -1827,6 +1920,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1843,7 +1937,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 6, 10, 13, 11, 57, tzinfo=timezone.utc), + }, provider_response_id='resp_68482f1d38e081a1ac828acda978aa6b08e79646fe74d5ee', finish_reason='stop', run_id=IsStr(), @@ -1857,6 +1954,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1871,7 +1969,10 @@ async def get_user_country() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 6, 10, 13, 12, 8, tzinfo=timezone.utc), + }, provider_response_id='resp_68482f28c1b081a1ae73cbbee012ee4906b4ab2d00d03024', finish_reason='stop', run_id=IsStr(), @@ -1980,7 +2081,10 @@ async def test_openai_previous_response_id_mixed_model_history(allow_model_reque assert not previous_response_id assert messages == snapshot( [ - ModelRequest(parts=[UserPromptPart(content='The first secret key is sesame', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='The first secret key is sesame', timestamp=IsDatetime())], + timestamp=IsDatetime(), + ), ModelResponse( parts=[TextPart(content='Open sesame! What would you like to unlock?')], usage=RequestUsage(), @@ -1989,7 +2093,10 @@ async def test_openai_previous_response_id_mixed_model_history(allow_model_reque provider_name='anthropic', provider_response_id='msg_01XUQuedGz9gusk4xZm4gWJj', ), - ModelRequest(parts=[UserPromptPart(content='what is the first secret key?', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='what is the first secret key?', timestamp=IsDatetime())], + timestamp=IsDatetime(), + ), ] ) @@ -2041,7 +2148,10 @@ async def test_openai_previous_response_id_same_model_history(allow_model_reques assert previous_response_id == 'resp_68b9bda81f5c8197a5a51a20a9f4150a000497db2a4c777b' assert messages == snapshot( [ - ModelRequest(parts=[UserPromptPart(content='what is the first secret key?', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='what is the first secret key?', timestamp=IsDatetime())], + timestamp=IsDatetime(), + ), ] ) @@ -2074,6 +2184,7 @@ async def test_openai_responses_usage_without_tokens_details(allow_model_request timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2083,6 +2194,7 @@ async def test_openai_responses_usage_without_tokens_details(allow_model_request timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -2104,6 +2216,7 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, [ ModelRequest( parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2129,7 +2242,10 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 12, 14, 22, 8, tzinfo=timezone.utc), + }, provider_response_id='resp_68c42c902794819cb9335264c342f65407460311b0c8d3de', finish_reason='stop', run_id=IsStr(), @@ -2150,6 +2266,7 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2174,7 +2291,10 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 12, 14, 22, 43, tzinfo=timezone.utc), + }, provider_response_id='resp_68c42cb3d520819c9d28b07036e9059507460311b0c8d3de', finish_reason='stop', run_id=IsStr(), @@ -2203,6 +2323,7 @@ async def test_openai_responses_thinking_part_from_other_model( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2254,6 +2375,7 @@ async def test_openai_responses_thinking_part_from_other_model( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2276,7 +2398,10 @@ async def test_openai_responses_thinking_part_from_other_model( timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 12, 14, 23, 30, tzinfo=timezone.utc), + }, provider_response_id='resp_68c42ce277ac8193ba08881bcefabaf70ad492c7955fc6fc', finish_reason='stop', run_id=IsStr(), @@ -2308,6 +2433,7 @@ async def test_openai_responses_thinking_part_iter(allow_model_requests: None, o timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2340,7 +2466,10 @@ async def test_openai_responses_thinking_part_iter(allow_model_requests: None, o timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 12, 14, 24, 15, tzinfo=timezone.utc), + }, provider_response_id='resp_68c42d0fb418819dbfa579f69406b49508fbf9b1584184ff', finish_reason='stop', run_id=IsStr(), @@ -2386,6 +2515,7 @@ def update_plan(plan: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions="You are a helpful assistant that uses planning. You MUST use the update_plan tool and continually update it as you make progress against the user's prompt", run_id=IsStr(), ), @@ -2413,7 +2543,10 @@ def update_plan(plan: str) -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 12, 14, 24, 40, tzinfo=timezone.utc), + }, provider_response_id='resp_68c42d28772c819684459966ee2201ed0e8bc41441c948f6', finish_reason='stop', run_id=IsStr(), @@ -2427,6 +2560,7 @@ def update_plan(plan: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions="You are a helpful assistant that uses planning. You MUST use the update_plan tool and continually update it as you make progress against the user's prompt", run_id=IsStr(), ), @@ -2439,7 +2573,10 @@ def update_plan(plan: str) -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 12, 14, 25, 3, tzinfo=timezone.utc), + }, provider_response_id='resp_68c42d3fd6a08196bce23d6be960ff8a0e8bc41441c948f6', finish_reason='stop', run_id=IsStr(), @@ -2480,6 +2617,7 @@ async def test_openai_responses_thinking_without_summary(allow_model_requests: N timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2491,6 +2629,7 @@ async def test_openai_responses_thinking_without_summary(allow_model_requests: N timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -2554,6 +2693,7 @@ async def test_openai_responses_thinking_with_multiple_summaries(allow_model_req timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2568,6 +2708,7 @@ async def test_openai_responses_thinking_with_multiple_summaries(allow_model_req timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -2620,6 +2761,7 @@ async def test_openai_responses_thinking_with_modified_history(allow_model_reque timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2637,7 +2779,10 @@ async def test_openai_responses_thinking_with_modified_history(allow_model_reque timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 12, 14, 27, 43, tzinfo=timezone.utc), + }, provider_response_id='resp_68c42ddf9bbc8194aa7b97304dd909cb0202c9ad459e0d23', finish_reason='stop', run_id=IsStr(), @@ -2674,6 +2819,7 @@ async def test_openai_responses_thinking_with_modified_history(allow_model_reque timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2691,7 +2837,10 @@ async def test_openai_responses_thinking_with_modified_history(allow_model_reque timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 12, 14, 27, 48, tzinfo=timezone.utc), + }, provider_response_id='resp_68c42de4afcc819f995a1c59fe87c9d5051f82c608a83beb', finish_reason='stop', run_id=IsStr(), @@ -2723,6 +2872,7 @@ async def test_openai_responses_thinking_with_code_execution_tool(allow_model_re timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2776,7 +2926,10 @@ async def test_openai_responses_thinking_with_code_execution_tool(allow_model_re timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 19, 20, 17, 21, tzinfo=timezone.utc), + }, provider_response_id='resp_68cdba511c7081a389e67b16621029c609b7445677780c8f', finish_reason='stop', run_id=IsStr(), @@ -2795,6 +2948,7 @@ async def test_openai_responses_thinking_with_code_execution_tool(allow_model_re timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2812,7 +2966,10 @@ async def test_openai_responses_thinking_with_code_execution_tool(allow_model_re timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 19, 20, 17, 46, tzinfo=timezone.utc), + }, provider_response_id='resp_68cdba6a610481a3b4533f345bea8a7b09b7445677780c8f', finish_reason='stop', run_id=IsStr(), @@ -2850,6 +3007,7 @@ async def test_openai_responses_thinking_with_code_execution_tool_stream( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2911,7 +3069,10 @@ async def test_openai_responses_thinking_with_code_execution_tool_stream( timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 11, 22, 43, 36, tzinfo=timezone.utc), + }, provider_response_id='resp_68c35098e6fc819e80fb94b25b7d031b0f2d670b80edc507', finish_reason='stop', run_id=IsStr(), @@ -3671,6 +3832,7 @@ def get_meaning_of_life() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -3687,7 +3849,10 @@ def get_meaning_of_life() -> int: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 18, 18, 29, 57, tzinfo=timezone.utc), + }, provider_response_id='resp_68cc4fa5603481958e2143685133fe530548824120ffcf74', finish_reason='stop', run_id=IsStr(), @@ -3701,6 +3866,7 @@ def get_meaning_of_life() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -3719,7 +3885,10 @@ def get_meaning_of_life() -> int: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 18, 18, 29, 58, tzinfo=timezone.utc), + }, provider_response_id='resp_68cc4fa6a8a881a187b0fe1603057bff0307c6d4d2ee5985', finish_reason='stop', run_id=IsStr(), @@ -3782,6 +3951,7 @@ async def test_openai_responses_code_execution_return_image(allow_model_requests timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -3852,7 +4022,10 @@ async def test_openai_responses_code_execution_return_image(allow_model_requests timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 19, 20, 56, 34, tzinfo=timezone.utc), + }, provider_response_id='resp_68cdc382bc98819083a5b47ec92e077b0187028ba77f15f7', finish_reason='stop', run_id=IsStr(), @@ -3878,6 +4051,7 @@ async def test_openai_responses_code_execution_return_image(allow_model_requests timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -4012,7 +4186,10 @@ async def test_openai_responses_code_execution_return_image(allow_model_requests timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 19, 20, 57, 1, tzinfo=timezone.utc), + }, provider_response_id='resp_68cdc39da72481909e0512fef9d646240187028ba77f15f7', finish_reason='stop', run_id=IsStr(), @@ -4056,6 +4233,7 @@ async def test_openai_responses_code_execution_return_image_stream(allow_model_r timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -4098,7 +4276,10 @@ async def test_openai_responses_code_execution_return_image_stream(allow_model_r timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 1, 20, 47, 35, tzinfo=timezone.utc), + }, provider_response_id='resp_06c1a26fd89d07f20068dd9367869c819788cb28e6f19eff9b', finish_reason='stop', run_id=IsStr(), @@ -5545,6 +5726,7 @@ async def test_openai_responses_image_generation(allow_model_requests: None, ope timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5593,7 +5775,10 @@ async def test_openai_responses_image_generation(allow_model_requests: None, ope timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 19, 20, 57, 58, tzinfo=timezone.utc), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -5618,6 +5803,7 @@ async def test_openai_responses_image_generation(allow_model_requests: None, ope timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5666,7 +5852,10 @@ async def test_openai_responses_image_generation(allow_model_requests: None, ope timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 19, 20, 59, 28, tzinfo=timezone.utc), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -5713,6 +5902,7 @@ async def test_openai_responses_image_generation_stream(allow_model_requests: No timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5759,7 +5949,10 @@ async def test_openai_responses_image_generation_stream(allow_model_requests: No timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 1, 20, 40, 2, tzinfo=timezone.utc), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -5894,6 +6087,7 @@ async def test_openai_responses_image_generation_tool_without_image_output( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5939,7 +6133,10 @@ async def test_openai_responses_image_generation_tool_without_image_output( timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 19, 23, 49, 51, tzinfo=timezone.utc), + }, provider_response_id='resp_68cdec1f3290819f99d9caba8703b251079003437d26d0c0', finish_reason='stop', run_id=IsStr(), @@ -5952,6 +6149,7 @@ async def test_openai_responses_image_generation_tool_without_image_output( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5997,7 +6195,10 @@ async def test_openai_responses_image_generation_tool_without_image_output( timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 9, 19, 23, 50, 57, tzinfo=timezone.utc), + }, provider_response_id='resp_68cdec61d0a0819fac14ed057a9946a1079003437d26d0c0', finish_reason='stop', run_id=IsStr(), @@ -6059,6 +6260,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6102,7 +6304,10 @@ class Animal(BaseModel): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 1, 19, 38, 16, tzinfo=timezone.utc), + }, provider_response_id='resp_0360827931d9421b0068dd8328c08c81a0ba854f245883906f', finish_reason='stop', run_id=IsStr(), @@ -6115,6 +6320,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6137,7 +6343,10 @@ class Animal(BaseModel): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 1, 19, 39, 28, tzinfo=timezone.utc), + }, provider_response_id='resp_0360827931d9421b0068dd8370a70081a09d6de822ee43bbc4', finish_reason='stop', run_id=IsStr(), @@ -6151,6 +6360,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -6176,6 +6386,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6222,7 +6433,10 @@ class Animal(BaseModel): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 1, 19, 41, 59, tzinfo=timezone.utc), + }, provider_response_id='resp_09b7ce6df817433c0068dd8407c37881a0ad817ef3cc3a3600', finish_reason='stop', run_id=IsStr(), @@ -6250,6 +6464,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6296,7 +6511,10 @@ class Animal(BaseModel): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 1, 19, 55, 9, tzinfo=timezone.utc), + }, provider_response_id='resp_0d14a5e3c26c21180068dd871d439081908dc36e63fab0cedf', finish_reason='stop', run_id=IsStr(), @@ -6330,6 +6548,7 @@ async def get_animal() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6352,7 +6571,10 @@ async def get_animal() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 1, 20, 2, 36, tzinfo=timezone.utc), + }, provider_response_id='resp_0481074da98340df0068dd88dceb1481918b1d167d99bc51cd', finish_reason='stop', run_id=IsStr(), @@ -6366,6 +6588,7 @@ async def get_animal() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6403,7 +6626,10 @@ async def get_animal() -> str: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 1, 20, 2, 56, tzinfo=timezone.utc), + }, provider_response_id='resp_0481074da98340df0068dd88f0ba04819185a168065ef28040', finish_reason='stop', run_id=IsStr(), @@ -6434,6 +6660,7 @@ async def test_openai_responses_multiple_images(allow_model_requests: None, open timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6507,7 +6734,10 @@ async def test_openai_responses_multiple_images(allow_model_requests: None, open timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 1, 19, 28, 22, tzinfo=timezone.utc), + }, provider_response_id='resp_0b6169df6e16e9690068dd80d64aec81919c65f238307673bb', finish_reason='stop', run_id=IsStr(), @@ -6538,6 +6768,7 @@ async def test_openai_responses_image_generation_jpeg(allow_model_requests: None timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6581,7 +6812,10 @@ async def test_openai_responses_image_generation_jpeg(allow_model_requests: None timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 1, 21, 28, 13, tzinfo=timezone.utc), + }, provider_response_id='resp_08acbdf1ae54befc0068dd9ced226c8197a2e974b29c565407', finish_reason='stop', run_id=IsStr(), @@ -6642,6 +6876,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6664,7 +6899,10 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 13, 11, 30, 47, tzinfo=timezone.utc), + }, provider_response_id='resp_001fd29e2d5573f70068ece2e6dfbc819c96557f0de72802be', finish_reason='stop', run_id=IsStr(), @@ -6678,6 +6916,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -6713,6 +6952,7 @@ async def test_openai_responses_model_mcp_server_tool(allow_model_requests: None timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -6839,7 +7079,10 @@ async def test_openai_responses_model_mcp_server_tool(allow_model_requests: None timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 23, 23, 42, 57, tzinfo=timezone.utc), + }, provider_response_id='resp_0083938b3a28070e0068fabd81970881a0a1195f2cab45bd04', finish_reason='stop', run_id=IsStr(), @@ -6858,6 +7101,7 @@ async def test_openai_responses_model_mcp_server_tool(allow_model_requests: None timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -6887,7 +7131,10 @@ async def test_openai_responses_model_mcp_server_tool(allow_model_requests: None timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 23, 23, 43, 25, tzinfo=timezone.utc), + }, provider_response_id='resp_0083938b3a28070e0068fabd9d414881a089cf24784f80e021', finish_reason='stop', run_id=IsStr(), @@ -6936,6 +7183,7 @@ async def test_openai_responses_model_mcp_server_tool_stream(allow_model_request timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -7108,7 +7356,10 @@ async def test_openai_responses_model_mcp_server_tool_stream(allow_model_request timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 23, 21, 40, 50, tzinfo=timezone.utc), + }, provider_response_id='resp_00b9cc7a23d047270068faa0e25934819f9c3bfdec80065bc4', finish_reason='stop', run_id=IsStr(), @@ -7327,6 +7578,7 @@ async def test_openai_responses_model_mcp_server_tool_with_connector(allow_model parts=[ UserPromptPart(content='What do I have on my Google Calendar for today?', timestamp=IsDatetime()) ], + timestamp=IsDatetime(), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -7487,7 +7739,10 @@ async def test_openai_responses_model_mcp_server_tool_with_connector(allow_model timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 10, 23, 21, 41, 13, tzinfo=timezone.utc), + }, provider_response_id='resp_0558010cf1416a490068faa0f945bc81a0b6a6dfb7391030d5', finish_reason='stop', run_id=IsStr(), diff --git a/tests/models/test_openrouter.py b/tests/models/test_openrouter.py index f3fe1ae095..c5c1bb1d5d 100644 --- a/tests/models/test_openrouter.py +++ b/tests/models/test_openrouter.py @@ -1,3 +1,4 @@ +import datetime from collections.abc import Sequence from typing import Literal, cast @@ -96,7 +97,20 @@ async def test_openrouter_stream_with_native_options(allow_model_requests: None, _ = [chunk async for chunk in stream] - assert stream.provider_details == snapshot({'finish_reason': 'completed', 'downstream_provider': 'xAI'}) + assert stream.provider_details is not None + assert stream.provider_details == snapshot( + { + 'timestamp': datetime.datetime(2025, 11, 2, 6, 14, 57, tzinfo=datetime.timezone.utc), + 'finish_reason': 'completed', + 'cost': 0.00333825, + 'upstream_inference_cost': None, + 'is_byok': False, + 'downstream_provider': 'xAI', + } + ) + # Explicitly verify native_finish_reason is 'completed' and wasn't overwritten by the + # final usage chunk (which has native_finish_reason: null, see cassette for details) + assert stream.provider_details['finish_reason'] == 'completed' assert stream.finish_reason == snapshot('stop') diff --git a/tests/models/test_outlines.py b/tests/models/test_outlines.py index f0af90aa3d..ba78ac6755 100644 --- a/tests/models/test_outlines.py +++ b/tests/models/test_outlines.py @@ -326,6 +326,7 @@ async def test_request_async(llamacpp_model: OutlinesModel) -> None: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='Answer in one word.', run_id=IsStr(), ), @@ -342,6 +343,7 @@ async def test_request_async(llamacpp_model: OutlinesModel) -> None: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='Answer in one word.', run_id=IsStr(), ), @@ -353,6 +355,7 @@ async def test_request_async(llamacpp_model: OutlinesModel) -> None: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='Answer in one word.', run_id=IsStr(), ), @@ -374,6 +377,7 @@ def test_request_sync(llamacpp_model: OutlinesModel) -> None: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse(parts=[TextPart(content=IsStr())], timestamp=IsDatetime(), run_id=IsStr()), @@ -404,6 +408,7 @@ async def test_request_async_model(mock_async_model: OutlinesModel) -> None: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse(parts=[TextPart(content=IsStr())], timestamp=IsDatetime(), run_id=IsStr()), @@ -439,6 +444,7 @@ def test_request_image_binary(transformers_multimodal_model: OutlinesModel, bina timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse(parts=[TextPart(content=IsStr())], timestamp=IsDatetime(), run_id=IsStr()), @@ -470,6 +476,7 @@ def test_request_image_url(transformers_multimodal_model: OutlinesModel) -> None timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse(parts=[TextPart(content=IsStr())], timestamp=IsDatetime(), run_id=IsStr()), @@ -526,6 +533,7 @@ class Box(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse(parts=[TextPart(content=IsStr())], timestamp=IsDatetime(), run_id=IsStr()), diff --git a/tests/test_a2a.py b/tests/test_a2a.py index 4e5f74f476..e19e7e5710 100644 --- a/tests/test_a2a.py +++ b/tests/test_a2a.py @@ -1,4 +1,5 @@ import uuid +from datetime import timezone import anyio import httpx @@ -21,7 +22,7 @@ from pydantic_ai.models.function import AgentInfo, FunctionModel from pydantic_ai.usage import RequestUsage -from .conftest import IsDatetime, IsStr, try_import +from .conftest import IsDatetime, IsNow, IsStr, try_import with try_import() as imports_successful: from fasta2a.client import A2AClient @@ -579,6 +580,7 @@ def track_messages(messages: list[ModelMessage], info: AgentInfo) -> ModelRespon [ ModelRequest( parts=[UserPromptPart(content='First message', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ) ] @@ -618,6 +620,7 @@ def track_messages(messages: list[ModelMessage], info: AgentInfo) -> ModelRespon [ ModelRequest( parts=[UserPromptPart(content='First message', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -641,6 +644,7 @@ def track_messages(messages: list[ModelMessage], info: AgentInfo) -> ModelRespon ), UserPromptPart(content='Second message', timestamp=IsDatetime()), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] diff --git a/tests/test_ag_ui.py b/tests/test_ag_ui.py index 5cbf85fc69..b678029abb 100644 --- a/tests/test_ag_ui.py +++ b/tests/test_ag_ui.py @@ -6,6 +6,7 @@ import uuid from collections.abc import AsyncIterator, MutableMapping from dataclasses import dataclass +from datetime import timezone from http import HTTPStatus from typing import Any @@ -52,7 +53,7 @@ from pydantic_ai.output import OutputDataT from pydantic_ai.tools import AgentDepsT, ToolDefinition -from .conftest import IsDatetime, IsSameStr, try_import +from .conftest import IsDatetime, IsNow, IsSameStr, try_import with try_import() as imports_successful: from ag_ui.core import ( @@ -1525,7 +1526,8 @@ async def test_messages() -> None: content='User message', timestamp=IsDatetime(), ), - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[ @@ -1566,7 +1568,8 @@ async def test_messages() -> None: content='User message', timestamp=IsDatetime(), ), - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[TextPart(content='Assistant message')], diff --git a/tests/test_agent.py b/tests/test_agent.py index 6ce2d91c54..51c5daec93 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -185,6 +185,7 @@ def return_model(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -210,6 +211,7 @@ def return_model(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -228,6 +230,7 @@ def return_model(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -318,6 +321,7 @@ def validate_output(ctx: RunContext[None], o: Foo) -> Foo: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -336,6 +340,7 @@ def validate_output(ctx: RunContext[None], o: Foo) -> Foo: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -354,6 +359,7 @@ def validate_output(ctx: RunContext[None], o: Foo) -> Foo: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -462,6 +468,7 @@ def return_tuple(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -479,6 +486,7 @@ def return_tuple(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: tool_call_id=IsStr(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -499,6 +507,7 @@ def return_tuple(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -511,6 +520,7 @@ def return_tuple(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: tool_name='final_result', content='foobar', tool_call_id=IsStr(), timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ) ) @@ -524,6 +534,7 @@ def return_tuple(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ) ) @@ -1050,6 +1061,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1074,6 +1086,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1098,6 +1111,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1137,6 +1151,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1154,6 +1169,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1329,6 +1345,7 @@ def say_world(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1385,6 +1402,7 @@ def call_handoff_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelRes timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1409,6 +1427,7 @@ def call_handoff_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelRes timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1423,6 +1442,7 @@ def call_handoff_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelRes timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1447,6 +1467,7 @@ def call_handoff_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelRes timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1787,6 +1808,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1823,6 +1845,7 @@ class Foo(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1888,6 +1911,7 @@ def return_foo_bar(_: list[ModelMessage], _info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1935,6 +1959,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1959,6 +1984,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2016,6 +2042,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2033,6 +2060,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2063,6 +2091,7 @@ async def ret_a(x: str) -> str: SystemPromptPart(content='Foobar', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2078,6 +2107,7 @@ async def ret_a(x: str) -> str: tool_name='ret_a', content='a-apple', tool_call_id=IsStr(), timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2099,6 +2129,7 @@ async def ret_a(x: str) -> str: SystemPromptPart(content='Foobar', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2114,6 +2145,7 @@ async def ret_a(x: str) -> str: tool_name='ret_a', content='a-apple', tool_call_id=IsStr(), timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2125,6 +2157,7 @@ async def ret_a(x: str) -> str: ), ModelRequest( parts=[UserPromptPart(content='Hello again', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2164,6 +2197,7 @@ async def ret_a(x: str) -> str: SystemPromptPart(content='Foobar', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2179,6 +2213,7 @@ async def ret_a(x: str) -> str: tool_name='ret_a', content='a-apple', tool_call_id=IsStr(), timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2190,6 +2225,7 @@ async def ret_a(x: str) -> str: ), ModelRequest( parts=[UserPromptPart(content='Hello again', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2228,6 +2264,7 @@ async def ret_a(x: str) -> str: SystemPromptPart(content='Foobar', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2243,6 +2280,7 @@ async def ret_a(x: str) -> str: tool_name='ret_a', content='a-apple', tool_call_id=IsStr(), timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2267,6 +2305,7 @@ async def ret_a(x: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -2280,6 +2319,7 @@ async def ret_a(x: str) -> str: SystemPromptPart(content='Foobar', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2295,6 +2335,7 @@ async def ret_a(x: str) -> str: tool_name='ret_a', content='a-apple', tool_call_id=IsStr(), timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2313,6 +2354,7 @@ async def ret_a(x: str) -> str: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), # second call, notice no repeated system prompt @@ -2320,6 +2362,7 @@ async def ret_a(x: str) -> str: parts=[ UserPromptPart(content='Hello again', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2338,6 +2381,7 @@ async def ret_a(x: str) -> str: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -2405,6 +2449,7 @@ async def instructions(ctx: RunContext) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), instructions='New instructions', run_id=IsStr(), ), @@ -2448,7 +2493,8 @@ def test_tool() -> str: content='Hello', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[ToolCallPart(tool_name='test_tool', args='{}', tool_call_id='call_123')], @@ -2463,6 +2509,7 @@ def test_tool() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2518,7 +2565,8 @@ def simple_response(_messages: list[ModelMessage], _info: AgentInfo) -> ModelRes content='Hello', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[TextPart(content='world')], @@ -2560,6 +2608,7 @@ async def test_message_history_ending_on_model_response_with_instructions(): [ ModelRequest( parts=[], + timestamp=IsNow(tz=timezone.utc), instructions="""\ Summarize this conversation to include all important facts about the user and what their interactions were about.\ @@ -2597,6 +2646,7 @@ def llm(messages: list[ModelMessage], _info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2608,6 +2658,7 @@ def llm(messages: list[ModelMessage], _info: AgentInfo) -> ModelResponse: ), ModelRequest( parts=[], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2640,6 +2691,7 @@ def llm(messages: list[ModelMessage], _info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2651,6 +2703,7 @@ def llm(messages: list[ModelMessage], _info: AgentInfo) -> ModelResponse: ), ModelRequest( parts=[], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2688,6 +2741,7 @@ def empty(_: list[ModelMessage], _info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2706,6 +2760,7 @@ def empty(_: list[ModelMessage], _info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2734,6 +2789,7 @@ def empty(m: list[ModelMessage], _info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2752,6 +2808,7 @@ def empty(m: list[ModelMessage], _info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3149,7 +3206,8 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: assert messages == snapshot( [ ModelRequest( - parts=[UserPromptPart(content='test multiple final results', timestamp=IsNow(tz=timezone.utc))], + parts=[UserPromptPart(content='test exhaustive strategy', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3177,6 +3235,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -3233,6 +3292,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover content='test early strategy with final result in middle', timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3285,6 +3345,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -4117,6 +4178,7 @@ async def get_location(loc_name: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4138,6 +4200,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4166,6 +4229,7 @@ def test_nested_capture_run_messages() -> None: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4193,6 +4257,7 @@ def test_double_capture_run_messages() -> None: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4242,6 +4307,7 @@ async def func() -> str: SystemPromptPart(content=dynamic_value, timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='request', ), @@ -4271,6 +4337,7 @@ async def func() -> str: ), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='request', ), @@ -4283,7 +4350,8 @@ async def func() -> str: kind='response', ), ModelRequest( - parts=[UserPromptPart(content='World', timestamp=IsNow(tz=timezone.utc))], + parts=[UserPromptPart(content='World', timestamp=IsNow(tz=timezone.utc), part_kind='user-prompt')], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='request', ), @@ -4329,6 +4397,7 @@ async def func(): ), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='request', ), @@ -4359,6 +4428,7 @@ async def func(): ), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='request', ), @@ -4371,7 +4441,8 @@ async def func(): kind='response', ), ModelRequest( - parts=[UserPromptPart(content='World', timestamp=IsNow(tz=timezone.utc))], + parts=[UserPromptPart(content='World', timestamp=IsNow(tz=timezone.utc), part_kind='user-prompt')], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='request', ), @@ -4427,6 +4498,7 @@ async def foobar(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='foobar', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4445,6 +4517,7 @@ async def foobar(x: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4521,6 +4594,7 @@ def test_binary_content_serializable(): 'part_kind': 'user-prompt', } ], + 'timestamp': IsStr(), 'instructions': None, 'kind': 'request', 'run_id': IsStr(), @@ -4584,6 +4658,7 @@ def test_image_url_serializable_missing_media_type(): 'part_kind': 'user-prompt', } ], + 'timestamp': IsStr(), 'instructions': None, 'kind': 'request', 'run_id': IsStr(), @@ -4654,6 +4729,7 @@ def test_image_url_serializable(): 'part_kind': 'user-prompt', } ], + 'timestamp': IsStr(), 'instructions': None, 'kind': 'request', 'run_id': IsStr(), @@ -4777,6 +4853,7 @@ def get_image() -> BinaryContent: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ) ) @@ -4829,6 +4906,7 @@ def get_files(): timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ) ) @@ -4848,6 +4926,7 @@ def system_prompt() -> str: SystemPromptPart(content='A system prompt!', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), instructions='An instructions!', run_id=IsStr(), ) @@ -4872,6 +4951,7 @@ def empty_instructions() -> str: SystemPromptPart(content='A system prompt!', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), instructions='An instructions!', run_id=IsStr(), ) @@ -4887,6 +4967,7 @@ def test_instructions_both_instructions_and_system_prompt_are_set(): SystemPromptPart(content='A system prompt!', timestamp=IsNow(tz=timezone.utc)), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc)), ], + timestamp=IsNow(tz=timezone.utc), instructions='An instructions!', run_id=IsStr(), ) @@ -4904,6 +4985,7 @@ def instructions() -> str: assert result.all_messages()[0] == snapshot( ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ) @@ -4921,6 +5003,7 @@ def instructions_2() -> str: assert result.all_messages()[0] == snapshot( ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ) @@ -4936,10 +5019,12 @@ def test_instructions_with_message_history(): assert result.all_messages() == snapshot( [ ModelRequest( - parts=[SystemPromptPart(content='You are a helpful assistant', timestamp=IsNow(tz=timezone.utc))] + parts=[SystemPromptPart(content='You are a helpful assistant', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), ), ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -4968,6 +5053,7 @@ def empty_instructions() -> str: assert result.all_messages()[0] == snapshot( ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), instructions="""\ You are a helpful assistant. @@ -4984,6 +5070,7 @@ def test_instructions_during_run(): assert result.all_messages()[0] == snapshot( ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), instructions="""\ You are a helpful assistant. Your task is to greet people.\ @@ -4996,6 +5083,7 @@ def test_instructions_during_run(): assert result2.all_messages()[0] == snapshot( ModelRequest( parts=[UserPromptPart(content='Hello again!', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), instructions="""\ You are a helpful assistant.\ """, @@ -5024,7 +5112,12 @@ class Output(BaseModel): assert messages == snapshot( [ - ModelRequest(parts=[], instructions='Agent 2 instructions', run_id=IsStr()), + ModelRequest( + parts=[], + timestamp=IsNow(tz=timezone.utc), + instructions='Agent 2 instructions', + run_id=IsStr(), + ), ModelResponse( parts=[ToolCallPart(tool_name='final_result', args={'text': 'a'}, tool_call_id=IsStr())], usage=RequestUsage(input_tokens=51, output_tokens=9), @@ -5041,6 +5134,7 @@ class Output(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -5073,6 +5167,7 @@ def my_tool(x: int) -> int: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5091,6 +5186,7 @@ def my_tool(x: int) -> int: tool_name='my_tool', content=2, tool_call_id=IsStr(), timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5109,6 +5205,7 @@ def my_tool(x: int) -> int: tool_name='my_tool', content=4, tool_call_id=IsStr(), timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5180,6 +5277,7 @@ def foo_tool(foo: Foo) -> int: 'part_kind': 'retry-prompt', } ], + 'timestamp': IsStr(), 'instructions': None, 'kind': 'request', 'run_id': IsStr(), @@ -5252,6 +5350,7 @@ def analyze_data() -> ToolReturn: [ ModelRequest( parts=[UserPromptPart(content='Please analyze the data', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5286,6 +5385,7 @@ def analyze_data() -> ToolReturn: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5333,6 +5433,7 @@ def analyze_data() -> ToolReturn: [ ModelRequest( parts=[UserPromptPart(content='Please analyze the data', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5359,6 +5460,7 @@ def analyze_data() -> ToolReturn: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5637,6 +5739,7 @@ def respond(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5655,6 +5758,7 @@ def respond(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5673,6 +5777,7 @@ def respond(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5728,6 +5833,7 @@ async def only_if_plan_presented( timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5752,6 +5858,7 @@ async def only_if_plan_presented( timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5776,6 +5883,7 @@ async def only_if_plan_presented( timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6049,6 +6157,7 @@ def model_function(messages: list[ModelMessage], info: AgentInfo) -> ModelRespon timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6066,6 +6175,7 @@ def model_function(messages: list[ModelMessage], info: AgentInfo) -> ModelRespon timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6123,6 +6233,7 @@ def create_file(path: str, content: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6153,6 +6264,7 @@ def create_file(path: str, content: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6181,6 +6293,7 @@ def create_file(path: str, content: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6211,6 +6324,7 @@ def create_file(path: str, content: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelRequest( @@ -6228,6 +6342,7 @@ def create_file(path: str, content: str) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6258,6 +6373,7 @@ def create_file(path: str, content: str) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6406,6 +6522,7 @@ def update_file(ctx: RunContext, path: str, content: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Update .env file', timestamp=IsDatetime())], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6443,6 +6560,7 @@ def update_file(ctx: RunContext, path: str, content: str) -> str: ), UserPromptPart(content='continue with the operation', timestamp=IsDatetime()), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6499,7 +6617,8 @@ def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: content='Hello...', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[TextPart(content='...world!'), TextPart(content='Anything else I can help with?')], @@ -6512,6 +6631,7 @@ def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6533,6 +6653,7 @@ def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6553,7 +6674,8 @@ def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: content='Hello...', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[TextPart(content='...world!'), TextPart(content='Anything else I can help with?')], @@ -6566,6 +6688,7 @@ def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6836,6 +6959,7 @@ def roll_dice() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6854,6 +6978,7 @@ def roll_dice() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6878,6 +7003,7 @@ def roll_dice() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6894,6 +7020,7 @@ def roll_dice() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6912,6 +7039,7 @@ def roll_dice() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6936,6 +7064,7 @@ def roll_dice() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -7041,6 +7170,7 @@ def llm(messages: list[ModelMessage], _info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( diff --git a/tests/test_dbos.py b/tests/test_dbos.py index de99f1b1d0..ce000c7ccd 100644 --- a/tests/test_dbos.py +++ b/tests/test_dbos.py @@ -8,7 +8,7 @@ from collections.abc import AsyncIterable, AsyncIterator, Generator, Iterator from contextlib import contextmanager from dataclasses import dataclass, field -from datetime import datetime +from datetime import datetime, timezone from typing import Any, Literal import pytest @@ -44,7 +44,7 @@ from pydantic_ai.run import AgentRunResult from pydantic_ai.usage import RequestUsage -from .conftest import IsDatetime, IsStr +from .conftest import IsDatetime, IsNow, IsStr try: import importlib.metadata @@ -1404,6 +1404,7 @@ async def hitl_main_loop(prompt: str) -> AgentRunResult[str | DeferredToolReques timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), instructions='Just call tools without asking for confirmation.', run_id=IsStr(), ), @@ -1434,7 +1435,10 @@ async def hitl_main_loop(prompt: str) -> AgentRunResult[str | DeferredToolReques timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id=IsStr(), finish_reason='tool_call', run_id=IsStr(), @@ -1454,6 +1458,7 @@ async def hitl_main_loop(prompt: str) -> AgentRunResult[str | DeferredToolReques timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), instructions='Just call tools without asking for confirmation.', run_id=IsStr(), ), @@ -1475,7 +1480,10 @@ async def hitl_main_loop(prompt: str) -> AgentRunResult[str | DeferredToolReques timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -1537,6 +1545,7 @@ def hitl_main_loop_sync(prompt: str) -> AgentRunResult[str | DeferredToolRequest timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), instructions='Just call tools without asking for confirmation.', run_id=IsStr(), ), @@ -1567,7 +1576,10 @@ def hitl_main_loop_sync(prompt: str) -> AgentRunResult[str | DeferredToolRequest timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id=IsStr(), finish_reason='tool_call', run_id=IsStr(), @@ -1587,6 +1599,7 @@ def hitl_main_loop_sync(prompt: str) -> AgentRunResult[str | DeferredToolRequest timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), instructions='Just call tools without asking for confirmation.', run_id=IsStr(), ), @@ -1608,7 +1621,10 @@ def hitl_main_loop_sync(prompt: str) -> AgentRunResult[str | DeferredToolRequest timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -1646,6 +1662,7 @@ async def test_dbos_agent_with_model_retry(allow_model_requests: None, dbos: DBO timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1670,7 +1687,10 @@ async def test_dbos_agent_with_model_retry(allow_model_requests: None, dbos: DBO timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id=IsStr(), finish_reason='tool_call', run_id=IsStr(), @@ -1684,6 +1704,7 @@ async def test_dbos_agent_with_model_retry(allow_model_requests: None, dbos: DBO timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1708,7 +1729,10 @@ async def test_dbos_agent_with_model_retry(allow_model_requests: None, dbos: DBO timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id=IsStr(), finish_reason='tool_call', run_id=IsStr(), @@ -1722,6 +1746,7 @@ async def test_dbos_agent_with_model_retry(allow_model_requests: None, dbos: DBO timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1740,7 +1765,10 @@ async def test_dbos_agent_with_model_retry(allow_model_requests: None, dbos: DBO timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), diff --git a/tests/test_history_processor.py b/tests/test_history_processor.py index 89e487dc8c..0dd573c256 100644 --- a/tests/test_history_processor.py +++ b/tests/test_history_processor.py @@ -62,10 +62,13 @@ def no_op_history_processor(messages: list[ModelMessage]) -> list[ModelMessage]: assert received_messages == snapshot( [ - ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() + ), ModelResponse(parts=[TextPart(content='Previous answer')], timestamp=IsDatetime()), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -73,10 +76,13 @@ def no_op_history_processor(messages: list[ModelMessage]) -> list[ModelMessage]: assert captured_messages == result.all_messages() assert result.all_messages() == snapshot( [ - ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() + ), ModelResponse(parts=[TextPart(content='Previous answer')], timestamp=IsDatetime()), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -124,7 +130,8 @@ def process_previous_answers(messages: list[ModelMessage]) -> list[ModelMessage] content='Processed answer', timestamp=IsDatetime(), ), - ] + ], + timestamp=IsDatetime(), ) ] ) @@ -133,9 +140,12 @@ def process_previous_answers(messages: list[ModelMessage]) -> list[ModelMessage] [ ModelRequest( parts=[UserPromptPart(content='Question 3', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), - ModelRequest(parts=[SystemPromptPart(content='Processed answer', timestamp=IsDatetime())]), + ModelRequest( + parts=[SystemPromptPart(content='Processed answer', timestamp=IsDatetime())], timestamp=IsDatetime() + ), ModelResponse( parts=[TextPart(content='Provider response')], usage=RequestUsage(input_tokens=54, output_tokens=2), @@ -183,7 +193,8 @@ def process_previous_answers(messages: list[ModelMessage]) -> list[ModelMessage] content='Processed answer', timestamp=IsDatetime(), ), - ] + ], + timestamp=IsDatetime(), ) ] ) @@ -192,9 +203,12 @@ def process_previous_answers(messages: list[ModelMessage]) -> list[ModelMessage] [ ModelRequest( parts=[UserPromptPart(content='Question 3', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), - ModelRequest(parts=[SystemPromptPart(content='Processed answer', timestamp=IsDatetime())]), + ModelRequest( + parts=[SystemPromptPart(content='Processed answer', timestamp=IsDatetime())], timestamp=IsDatetime() + ), ModelResponse( parts=[TextPart(content='hello')], usage=RequestUsage(input_tokens=50, output_tokens=1), @@ -238,16 +252,20 @@ def capture_messages_processor(messages: list[ModelMessage]) -> list[ModelMessag content='New question', timestamp=IsDatetime(), ), - ] + ], + timestamp=IsDatetime(), ) ] ) assert captured_messages == result.all_messages() assert result.all_messages() == snapshot( [ - ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() + ), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -304,9 +322,15 @@ def second_processor(messages: list[ModelMessage]) -> list[ModelMessage]: result = await agent.run('New question', message_history=message_history) assert received_messages == snapshot( [ - ModelRequest(parts=[UserPromptPart(content='[SECOND] [FIRST] Question', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='[SECOND] [FIRST] Question', timestamp=IsDatetime())], + timestamp=IsDatetime(), + ), ModelResponse(parts=[TextPart(content='Answer')], timestamp=IsDatetime()), - ModelRequest(parts=[UserPromptPart(content='[SECOND] [FIRST] New question', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='[SECOND] [FIRST] New question', timestamp=IsDatetime())], + timestamp=IsDatetime(), + ), ] ) assert captured_messages == result.all_messages() @@ -318,7 +342,8 @@ def second_processor(messages: list[ModelMessage]) -> list[ModelMessage]: content='[SECOND] [FIRST] Question', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[TextPart(content='Answer')], @@ -330,7 +355,8 @@ def second_processor(messages: list[ModelMessage]) -> list[ModelMessage]: content='[SECOND] [FIRST] New question', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[TextPart(content='Provider response')], @@ -371,7 +397,8 @@ async def async_processor(messages: list[ModelMessage]) -> list[ModelMessage]: content='Question 2', timestamp=IsDatetime(), ), - ] + ], + timestamp=IsDatetime(), ) ] ) @@ -384,7 +411,8 @@ async def async_processor(messages: list[ModelMessage]) -> list[ModelMessage]: content='Question 1', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ), ModelRequest( parts=[ @@ -393,6 +421,7 @@ async def async_processor(messages: list[ModelMessage]) -> list[ModelMessage]: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -441,7 +470,8 @@ async def async_processor(messages: list[ModelMessage]) -> list[ModelMessage]: content='Question 2', timestamp=IsDatetime(), ), - ] + ], + timestamp=IsDatetime(), ) ] ) @@ -454,7 +484,8 @@ async def async_processor(messages: list[ModelMessage]) -> list[ModelMessage]: content='Question 1', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ), ModelRequest( parts=[ @@ -463,6 +494,7 @@ async def async_processor(messages: list[ModelMessage]) -> list[ModelMessage]: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -509,7 +541,8 @@ def context_processor(ctx: RunContext[str], messages: list[ModelMessage]) -> lis content='PREFIX: test', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ) ] ) @@ -522,7 +555,8 @@ def context_processor(ctx: RunContext[str], messages: list[ModelMessage]) -> lis content='PREFIX: test', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[TextPart(content='Provider response')], @@ -564,6 +598,7 @@ async def async_context_processor(ctx: RunContext[Any], messages: list[ModelMess timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ) ] @@ -578,6 +613,7 @@ async def async_context_processor(ctx: RunContext[Any], messages: list[ModelMess timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -642,7 +678,8 @@ class Deps: content='TEST: Question 2', timestamp=IsDatetime(), ), - ] + ], + timestamp=IsDatetime(), ) ] ) @@ -655,7 +692,8 @@ class Deps: content='TEST: Question 1', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ), ModelRequest( parts=[ @@ -663,7 +701,8 @@ class Deps: content='TEST: Question 2', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[TextPart(content='Provider response')], @@ -702,7 +741,8 @@ def return_new_history(messages: list[ModelMessage]) -> list[ModelMessage]: content='Modified message', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ) ] ) @@ -715,7 +755,8 @@ def return_new_history(messages: list[ModelMessage]) -> list[ModelMessage]: content='Modified message', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[TextPart(content='Provider response')], @@ -770,10 +811,13 @@ def __call__(self, messages: list[ModelMessage]) -> list[ModelMessage]: assert received_messages == snapshot( [ - ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() + ), ModelResponse(parts=[TextPart(content='Previous answer')], timestamp=IsDatetime()), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -781,10 +825,13 @@ def __call__(self, messages: list[ModelMessage]) -> list[ModelMessage]: assert captured_messages == result.all_messages() assert result.all_messages() == snapshot( [ - ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() + ), ModelResponse(parts=[TextPart(content='Previous answer')], timestamp=IsDatetime()), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -818,10 +865,13 @@ def __call__(self, _: RunContext, messages: list[ModelMessage]) -> list[ModelMes assert received_messages == snapshot( [ - ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() + ), ModelResponse(parts=[TextPart(content='Previous answer')], timestamp=IsDatetime()), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -829,10 +879,13 @@ def __call__(self, _: RunContext, messages: list[ModelMessage]) -> list[ModelMes assert captured_messages == result.all_messages() assert result.all_messages() == snapshot( [ - ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() + ), ModelResponse(parts=[TextPart(content='Previous answer')], timestamp=IsDatetime()), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( diff --git a/tests/test_mcp.py b/tests/test_mcp.py index 02bab17cc3..d021bb07c2 100644 --- a/tests/test_mcp.py +++ b/tests/test_mcp.py @@ -226,6 +226,7 @@ async def test_agent_with_stdio_server(allow_model_requests: None, agent: Agent) timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -250,7 +251,10 @@ async def test_agent_with_stdio_server(allow_model_requests: None, agent: Agent) timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRlnvvqIPFofAtKqtQKMWZkgXhzlT', finish_reason='tool_call', run_id=IsStr(), @@ -264,6 +268,7 @@ async def test_agent_with_stdio_server(allow_model_requests: None, agent: Agent) timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -282,7 +287,10 @@ async def test_agent_with_stdio_server(allow_model_requests: None, agent: Agent) timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRlnyjUo5wlyqvdNdM5I8vIWjo1qF', finish_reason='stop', run_id=IsStr(), @@ -397,6 +405,7 @@ async def test_tool_returning_str(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -421,7 +430,10 @@ async def test_tool_returning_str(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRlo3e1Ud2lnvkddMilmwC7LAemiy', finish_reason='tool_call', run_id=IsStr(), @@ -435,6 +447,7 @@ async def test_tool_returning_str(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -457,7 +470,10 @@ async def test_tool_returning_str(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRlo41LxqBYgGKWgGrQn67fQacOLp', finish_reason='stop', run_id=IsStr(), @@ -479,6 +495,7 @@ async def test_tool_returning_text_resource(allow_model_requests: None, agent: A timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -503,7 +520,10 @@ async def test_tool_returning_text_resource(allow_model_requests: None, agent: A timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRmhyweJVYonarb7s9ckIMSHf2vHo', finish_reason='tool_call', run_id=IsStr(), @@ -517,6 +537,7 @@ async def test_tool_returning_text_resource(allow_model_requests: None, agent: A timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -535,7 +556,10 @@ async def test_tool_returning_text_resource(allow_model_requests: None, agent: A timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRmhzqXFObpYwSzREMpJvX9kbDikR', finish_reason='stop', run_id=IsStr(), @@ -557,6 +581,7 @@ async def test_tool_returning_text_resource_link(allow_model_requests: None, age timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -581,7 +606,10 @@ async def test_tool_returning_text_resource_link(allow_model_requests: None, age timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BwdHSFe0EykAOpf0LWZzsWAodIQzb', finish_reason='tool_call', run_id=IsStr(), @@ -595,6 +623,7 @@ async def test_tool_returning_text_resource_link(allow_model_requests: None, age timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -613,7 +642,10 @@ async def test_tool_returning_text_resource_link(allow_model_requests: None, age timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BwdHTIlBZWzXJPBR8VTOdC4O57ZQA', finish_reason='stop', run_id=IsStr(), @@ -637,6 +669,7 @@ async def test_tool_returning_image_resource(allow_model_requests: None, agent: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -661,7 +694,10 @@ async def test_tool_returning_image_resource(allow_model_requests: None, agent: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRlo7KYJVXuNZ5lLLdYcKZDsX2CHb', finish_reason='tool_call', run_id=IsStr(), @@ -676,6 +712,7 @@ async def test_tool_returning_image_resource(allow_model_requests: None, agent: ), UserPromptPart(content=['This is file 1c8566:', image_content], timestamp=IsDatetime()), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -698,7 +735,10 @@ async def test_tool_returning_image_resource(allow_model_requests: None, agent: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloBGHh27w3fQKwxq4fX2cPuZJa9', finish_reason='stop', run_id=IsStr(), @@ -724,6 +764,7 @@ async def test_tool_returning_image_resource_link( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -748,7 +789,10 @@ async def test_tool_returning_image_resource_link( timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BwdHygYePH1mZgHo2Xxzib0Y7sId7', finish_reason='tool_call', run_id=IsStr(), @@ -763,6 +807,7 @@ async def test_tool_returning_image_resource_link( ), UserPromptPart(content=['This is file 1c8566:', image_content], timestamp=IsDatetime()), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -785,7 +830,10 @@ async def test_tool_returning_image_resource_link( timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BwdI2D2r9dvqq3pbsA0qgwKDEdTtD', finish_reason='stop', run_id=IsStr(), @@ -805,6 +853,7 @@ async def test_tool_returning_audio_resource( [ ModelRequest( parts=[UserPromptPart(content="What's the content of the audio resource?", timestamp=IsDatetime())], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -831,6 +880,7 @@ async def test_tool_returning_audio_resource( ), UserPromptPart(content=['This is file 2d36ae:', audio_content], timestamp=IsDatetime()), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -870,6 +920,7 @@ async def test_tool_returning_audio_resource_link( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -909,6 +960,7 @@ async def test_tool_returning_audio_resource_link( timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -945,6 +997,7 @@ async def test_tool_returning_image(allow_model_requests: None, agent: Agent, im timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -969,7 +1022,10 @@ async def test_tool_returning_image(allow_model_requests: None, agent: Agent, im timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloGQJWIX0Qk7gtNzF4s2Fez0O29', finish_reason='tool_call', run_id=IsStr(), @@ -990,6 +1046,7 @@ async def test_tool_returning_image(allow_model_requests: None, agent: Agent, im timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1008,7 +1065,10 @@ async def test_tool_returning_image(allow_model_requests: None, agent: Agent, im timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloJHR654fSD0fcvLWZxtKtn0pag', finish_reason='stop', run_id=IsStr(), @@ -1030,6 +1090,7 @@ async def test_tool_returning_dict(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1048,7 +1109,10 @@ async def test_tool_returning_dict(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloOs7Bb2tq8wJyy9Rv7SQ7L65a7', finish_reason='tool_call', run_id=IsStr(), @@ -1062,6 +1126,7 @@ async def test_tool_returning_dict(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1080,7 +1145,10 @@ async def test_tool_returning_dict(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloPczU1HSCWnreyo21DdNtdOM7L', finish_reason='stop', run_id=IsStr(), @@ -1102,6 +1170,7 @@ async def test_tool_returning_unstructured_dict(allow_model_requests: None, agen timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1124,7 +1193,10 @@ async def test_tool_returning_unstructured_dict(allow_model_requests: None, agen timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-CLbP82ODQMEznhobUKdq6Rjn9Aa12', finish_reason='tool_call', run_id=IsStr(), @@ -1138,6 +1210,7 @@ async def test_tool_returning_unstructured_dict(allow_model_requests: None, agen timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1156,7 +1229,10 @@ async def test_tool_returning_unstructured_dict(allow_model_requests: None, agen timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-CLbPAOYN3jPYdvYeD8JNOOXF5N554', finish_reason='stop', run_id=IsStr(), @@ -1180,6 +1256,7 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1204,7 +1281,10 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloSNg7aGSp1rXDkhInjMIUHKd7A', finish_reason='tool_call', run_id=IsStr(), @@ -1218,6 +1298,7 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1242,7 +1323,10 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloTvSkFeX4DZKQLqfH9KbQkWlpt', finish_reason='tool_call', run_id=IsStr(), @@ -1256,6 +1340,7 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1278,7 +1363,10 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloU3MhnqNEqujs28a3ofRbs7VPF', finish_reason='stop', run_id=IsStr(), @@ -1300,6 +1388,7 @@ async def test_tool_returning_none(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1318,7 +1407,10 @@ async def test_tool_returning_none(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloX2RokWc9j9PAXAuNXGR73WNqY', finish_reason='tool_call', run_id=IsStr(), @@ -1332,6 +1424,7 @@ async def test_tool_returning_none(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1350,7 +1443,10 @@ async def test_tool_returning_none(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloYWGujk8yE94gfVSsM1T1Ol2Ej', finish_reason='stop', run_id=IsStr(), @@ -1374,6 +1470,7 @@ async def test_tool_returning_multiple_items(allow_model_requests: None, agent: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1398,7 +1495,10 @@ async def test_tool_returning_multiple_items(allow_model_requests: None, agent: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={ + 'finish_reason': 'tool_calls', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRlobKLgm6vf79c9O8sloZaYx3coC', finish_reason='tool_call', run_id=IsStr(), @@ -1424,6 +1524,7 @@ async def test_tool_returning_multiple_items(allow_model_requests: None, agent: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1446,7 +1547,10 @@ async def test_tool_returning_multiple_items(allow_model_requests: None, agent: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloepWR5NJpTgSqFBGTSPeM1SWm8', finish_reason='stop', run_id=IsStr(), @@ -1531,7 +1635,8 @@ def test_map_from_mcp_params_model_request(): content=[BinaryContent(data=b'img', media_type='image/png', identifier='978ea7')], timestamp=IsNow(tz=timezone.utc), ), - ] + ], + timestamp=IsNow(tz=timezone.utc), ) ] ) diff --git a/tests/test_messages.py b/tests/test_messages.py index f5aaf972d4..e5ae19ab9f 100644 --- a/tests/test_messages.py +++ b/tests/test_messages.py @@ -449,7 +449,8 @@ def test_pre_usage_refactor_messages_deserializable(): content='What is the capital of Mexico?', timestamp=IsNow(tz=timezone.utc), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[TextPart(content='Mexico City.')], diff --git a/tests/test_streaming.py b/tests/test_streaming.py index 9149d19d1b..ef7ee37c04 100644 --- a/tests/test_streaming.py +++ b/tests/test_streaming.py @@ -74,6 +74,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -90,6 +91,7 @@ async def ret_a(x: str) -> str: tool_name='ret_a', content='a-apple', timestamp=IsNow(tz=timezone.utc), tool_call_id=IsStr() ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -110,6 +112,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -126,6 +129,7 @@ async def ret_a(x: str) -> str: tool_name='ret_a', content='a-apple', timestamp=IsNow(tz=timezone.utc), tool_call_id=IsStr() ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -166,6 +170,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -182,6 +187,7 @@ async def ret_a(x: str) -> str: tool_name='ret_a', content='a-apple', timestamp=IsNow(tz=timezone.utc), tool_call_id=IsStr() ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -212,6 +218,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -228,6 +235,7 @@ async def ret_a(x: str) -> str: tool_name='ret_a', content='a-apple', timestamp=IsNow(tz=timezone.utc), tool_call_id=IsStr() ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -590,6 +598,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -608,6 +617,7 @@ async def ret_a(x: str) -> str: tool_call_id=IsStr(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -617,6 +627,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -635,6 +646,7 @@ async def ret_a(x: str) -> str: tool_call_id=IsStr(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -659,6 +671,7 @@ async def ret_a(x: str) -> str: tool_call_id=IsStr(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -690,6 +703,7 @@ async def stream_structured_function( timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -699,7 +713,11 @@ async def stream_structured_function( timestamp=IsDatetime(), run_id=IsStr(), ), - ModelRequest(parts=[], run_id=IsStr()), + ModelRequest( + parts=[], + timestamp=IsNow(tz=timezone.utc), + run_id=IsStr(), + ), ModelResponse( parts=[TextPart(content='ok here is text')], usage=RequestUsage(input_tokens=50, output_tokens=4), @@ -734,6 +752,7 @@ async def ret_a(x: str) -> str: # pragma: no cover [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -805,6 +824,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover [ ModelRequest( parts=[UserPromptPart(content='test early strategy', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -846,6 +866,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover tool_call_id=IsStr(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -899,6 +920,7 @@ async def stream_function(_: list[ModelMessage], info: AgentInfo) -> AsyncIterat [ ModelRequest( parts=[UserPromptPart(content='test early output tools', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -926,6 +948,7 @@ async def stream_function(_: list[ModelMessage], info: AgentInfo) -> AsyncIterat timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -951,6 +974,7 @@ async def sf(_: list[ModelMessage], info: AgentInfo) -> AsyncIterator[str | Delt [ ModelRequest( parts=[UserPromptPart(content='test multiple final results', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -978,6 +1002,7 @@ async def sf(_: list[ModelMessage], info: AgentInfo) -> AsyncIterator[str | Delt tool_call_id=IsStr(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1034,6 +1059,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=datetime.timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1102,6 +1128,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=datetime.timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1171,6 +1198,7 @@ def regular_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=datetime.timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1207,6 +1235,7 @@ def regular_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=datetime.timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1256,6 +1285,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=datetime.timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1281,6 +1311,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=datetime.timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1315,6 +1346,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=datetime.timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1340,6 +1372,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=datetime.timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1365,6 +1398,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=datetime.timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1420,6 +1454,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover [ ModelRequest( parts=[UserPromptPart(content='test exhaustive strategy', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1472,6 +1507,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1525,6 +1561,7 @@ async def stream_function(_: list[ModelMessage], info: AgentInfo) -> AsyncIterat [ ModelRequest( parts=[UserPromptPart(content='test exhaustive output tools', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1552,6 +1589,7 @@ async def stream_function(_: list[ModelMessage], info: AgentInfo) -> AsyncIterat timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1686,6 +1724,7 @@ async def stream_function(_: list[ModelMessage], info: AgentInfo) -> AsyncIterat [ ModelRequest( parts=[UserPromptPart(content='test valid first invalid second', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1713,6 +1752,7 @@ async def stream_function(_: list[ModelMessage], info: AgentInfo) -> AsyncIterat timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1770,6 +1810,7 @@ async def stream_function(_: list[ModelMessage], info: AgentInfo) -> AsyncIterat content='test exhaustive with tool retry', timestamp=IsNow(tz=datetime.timezone.utc) ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1797,6 +1838,7 @@ async def stream_function(_: list[ModelMessage], info: AgentInfo) -> AsyncIterat timestamp=IsNow(tz=datetime.timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -2330,6 +2372,7 @@ def my_tool(ctx: RunContext[None], x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2348,6 +2391,7 @@ def my_tool(ctx: RunContext[None], x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( diff --git a/tests/test_temporal.py b/tests/test_temporal.py index 24ccefb83e..645bdd189f 100644 --- a/tests/test_temporal.py +++ b/tests/test_temporal.py @@ -1833,6 +1833,9 @@ async def test_temporal_agent_with_hitl_tool(allow_model_requests: None, client: timestamp=IsDatetime(), ) ], + # NOTE in other tests we check timestamp=IsNow(tz=timezone.utc) + # but temporal tests fail when we use IsNow + timestamp=IsDatetime(), instructions='Just call tools without asking for confirmation.', run_id=IsStr(), ), @@ -1863,7 +1866,7 @@ async def test_temporal_agent_with_hitl_tool(allow_model_requests: None, client: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={'finish_reason': 'tool_calls', 'timestamp': '2025-08-28T22:11:03Z'}, provider_response_id=IsStr(), finish_reason='tool_call', run_id=IsStr(), @@ -1883,6 +1886,7 @@ async def test_temporal_agent_with_hitl_tool(allow_model_requests: None, client: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), instructions='Just call tools without asking for confirmation.', run_id=IsStr(), ), @@ -1906,7 +1910,7 @@ async def test_temporal_agent_with_hitl_tool(allow_model_requests: None, client: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={'finish_reason': 'stop', 'timestamp': '2025-08-28T22:11:06Z'}, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -1960,6 +1964,7 @@ async def test_temporal_agent_with_model_retry(allow_model_requests: None, clien timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1984,7 +1989,7 @@ async def test_temporal_agent_with_model_retry(allow_model_requests: None, clien timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={'finish_reason': 'tool_calls', 'timestamp': '2025-08-28T23:19:50Z'}, provider_response_id=IsStr(), finish_reason='tool_call', run_id=IsStr(), @@ -1998,6 +2003,7 @@ async def test_temporal_agent_with_model_retry(allow_model_requests: None, clien timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2022,7 +2028,7 @@ async def test_temporal_agent_with_model_retry(allow_model_requests: None, clien timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'tool_calls'}, + provider_details={'finish_reason': 'tool_calls', 'timestamp': '2025-08-28T23:19:51Z'}, provider_response_id=IsStr(), finish_reason='tool_call', run_id=IsStr(), @@ -2036,6 +2042,7 @@ async def test_temporal_agent_with_model_retry(allow_model_requests: None, clien timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2054,7 +2061,7 @@ async def test_temporal_agent_with_model_retry(allow_model_requests: None, clien timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1/', - provider_details={'finish_reason': 'stop'}, + provider_details={'finish_reason': 'stop', 'timestamp': '2025-08-28T23:19:52Z'}, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), diff --git a/tests/test_tools.py b/tests/test_tools.py index 0031f702cd..1e9e6d5ce7 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -1381,6 +1381,7 @@ def my_tool(ctx: RunContext[None], x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1399,6 +1400,7 @@ def my_tool(ctx: RunContext[None], x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1772,6 +1774,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1826,6 +1829,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -1865,6 +1869,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1919,6 +1924,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelRequest( @@ -1947,6 +1953,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1987,6 +1994,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2008,6 +2016,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2084,7 +2093,8 @@ def buy(fruit: str): content='I bought a banana', timestamp=IsDatetime(), ), - ] + ], + timestamp=IsDatetime(), ), ] ) @@ -2165,6 +2175,7 @@ def bar(x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2187,6 +2198,7 @@ def bar(x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -2218,6 +2230,7 @@ def bar(x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2240,6 +2253,7 @@ def bar(x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelRequest( @@ -2257,6 +2271,7 @@ def bar(x: int) -> int: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2404,6 +2419,7 @@ def always_fail(ctx: RunContext[None]) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2422,6 +2438,7 @@ def always_fail(ctx: RunContext[None]) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2440,6 +2457,7 @@ def always_fail(ctx: RunContext[None]) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2458,6 +2476,7 @@ def always_fail(ctx: RunContext[None]) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( diff --git a/tests/test_usage_limits.py b/tests/test_usage_limits.py index ac17fd0be5..5cb4d529be 100644 --- a/tests/test_usage_limits.py +++ b/tests/test_usage_limits.py @@ -100,6 +100,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -125,6 +126,7 @@ async def ret_a(x: str) -> str: tool_call_id=IsStr(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] diff --git a/tests/test_vercel_ai.py b/tests/test_vercel_ai.py index 12a4ea3eaa..75914276db 100644 --- a/tests/test_vercel_ai.py +++ b/tests/test_vercel_ai.py @@ -2,6 +2,7 @@ import json from collections.abc import AsyncIterator, MutableMapping +from datetime import timezone from typing import Any, cast import pytest @@ -59,7 +60,7 @@ ) from pydantic_ai.ui.vercel_ai.response_types import BaseChunk, DataChunk -from .conftest import IsDatetime, IsSameStr, IsStr, try_import +from .conftest import IsDatetime, IsNow, IsSameStr, IsStr, try_import with try_import() as starlette_import_successful: from starlette.requests import Request @@ -184,7 +185,8 @@ async def test_run(allow_model_requests: None, openai_api_key: str): """, timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[ @@ -216,7 +218,8 @@ async def test_run(allow_model_requests: None, openai_api_key: str): content='Give me the ToCs', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[ @@ -237,7 +240,8 @@ async def test_run(allow_model_requests: None, openai_api_key: str): tool_call_id='toolu_01XX3rjFfG77h3KCbVHoYJMQ', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[ @@ -257,7 +261,8 @@ async def test_run(allow_model_requests: None, openai_api_key: str): tool_call_id='toolu_01W2yGpGQcMx7pXV2zZ4sz9g', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[ @@ -273,7 +278,8 @@ async def test_run(allow_model_requests: None, openai_api_key: str): content='How do I get FastAPI instrumentation to include the HTTP request and response', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ] ) @@ -1832,7 +1838,8 @@ async def test_adapter_load_messages(): ], timestamp=IsDatetime(), ), - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[ @@ -1848,7 +1855,8 @@ async def test_adapter_load_messages(): content='Give me the ToCs', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[ @@ -1869,7 +1877,8 @@ async def test_adapter_load_messages(): tool_call_id='toolu_01XX3rjFfG77h3KCbVHoYJMQ', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[ @@ -1889,7 +1898,8 @@ async def test_adapter_load_messages(): tool_call_id='toolu_01XX3rjFfG77h3KCbVHoY', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[ @@ -1909,7 +1919,8 @@ async def test_adapter_load_messages(): tool_call_id='toolu_01W2yGpGQcMx7pXV2zZ4sz9g', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[ From 125d47f436717833b695d00f7927f94b2ff62865 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sat, 29 Nov 2025 21:27:43 -0500 Subject: [PATCH 02/25] fix: add missing timestamp field to ModelRequest test snapshots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ModelRequest snapshots for Google/Vertex URL input tests were missing the timestamp field that was added in the parent commit. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- tests/models/test_gemini_vertex.py | 6 ++++++ tests/models/test_google.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/tests/models/test_gemini_vertex.py b/tests/models/test_gemini_vertex.py index a361f51033..42f5bb65c4 100644 --- a/tests/models/test_gemini_vertex.py +++ b/tests/models/test_gemini_vertex.py @@ -141,6 +141,7 @@ async def test_url_input( timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -148,9 +149,11 @@ async def test_url_input( usage=IsInstance(RequestUsage), model_name='gemini-2.0-flash', timestamp=IsDatetime(), + provider_name='google-vertex', provider_url='https://us-central1-aiplatform.googleapis.com/v1/projects/pydantic-ai/locations/us-central1/publishers/google/models/', provider_details={'finish_reason': 'STOP'}, provider_response_id=IsStr(), + finish_reason='stop', run_id=IsStr(), ), ] @@ -181,6 +184,7 @@ async def test_url_input_force_download(allow_model_requests: None) -> None: # timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -188,9 +192,11 @@ async def test_url_input_force_download(allow_model_requests: None) -> None: # usage=IsInstance(RequestUsage), model_name='gemini-2.0-flash', timestamp=IsDatetime(), + provider_name='google-vertex', provider_url='https://us-central1-aiplatform.googleapis.com/v1/projects/pydantic-ai/locations/us-central1/publishers/google/models/', provider_details={'finish_reason': 'STOP'}, provider_response_id=IsStr(), + finish_reason='stop', run_id=IsStr(), ), ] diff --git a/tests/models/test_google.py b/tests/models/test_google.py index a881f719f5..163b6d0268 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -2379,6 +2379,7 @@ async def test_google_url_input( timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2422,6 +2423,7 @@ async def test_google_url_input_force_download( timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( From 029a58ad06d577be184169a0eb6bfe0abc9b2838 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sat, 29 Nov 2025 21:48:31 -0500 Subject: [PATCH 03/25] fix tests --- tests/models/test_gemini_vertex.py | 2 -- tests/models/test_google.py | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/models/test_gemini_vertex.py b/tests/models/test_gemini_vertex.py index 42f5bb65c4..6471ca37ee 100644 --- a/tests/models/test_gemini_vertex.py +++ b/tests/models/test_gemini_vertex.py @@ -153,7 +153,6 @@ async def test_url_input( provider_url='https://us-central1-aiplatform.googleapis.com/v1/projects/pydantic-ai/locations/us-central1/publishers/google/models/', provider_details={'finish_reason': 'STOP'}, provider_response_id=IsStr(), - finish_reason='stop', run_id=IsStr(), ), ] @@ -196,7 +195,6 @@ async def test_url_input_force_download(allow_model_requests: None) -> None: # provider_url='https://us-central1-aiplatform.googleapis.com/v1/projects/pydantic-ai/locations/us-central1/publishers/google/models/', provider_details={'finish_reason': 'STOP'}, provider_response_id=IsStr(), - finish_reason='stop', run_id=IsStr(), ), ] diff --git a/tests/models/test_google.py b/tests/models/test_google.py index 163b6d0268..b35580bc1d 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -2389,7 +2389,7 @@ async def test_google_url_input( timestamp=IsDatetime(), provider_name='google-vertex', provider_url='https://aiplatform.googleapis.com/', - provider_details={'finish_reason': 'STOP'}, + provider_details={'finish_reason': 'STOP', 'timestamp': IsDatetime()}, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -2433,7 +2433,7 @@ async def test_google_url_input_force_download( timestamp=IsDatetime(), provider_name='google-vertex', provider_url='https://aiplatform.googleapis.com/', - provider_details={'finish_reason': 'STOP'}, + provider_details={'finish_reason': 'STOP', 'timestamp': IsDatetime()}, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), From 40314ea40cebc813247e8ba737f7307225cd7455 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sat, 29 Nov 2025 22:36:44 -0500 Subject: [PATCH 04/25] coverage --- pydantic_ai_slim/pydantic_ai/models/google.py | 2 +- pydantic_ai_slim/pydantic_ai/models/groq.py | 2 +- pydantic_ai_slim/pydantic_ai/models/huggingface.py | 2 +- pydantic_ai_slim/pydantic_ai/models/mistral.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/models/google.py b/pydantic_ai_slim/pydantic_ai/models/google.py index 248509712f..71e2ba97b3 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -686,7 +686,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: raw_finish_reason = candidate.finish_reason if raw_finish_reason: provider_details_dict: dict[str, Any] = {'finish_reason': raw_finish_reason.value} - if self._provider_timestamp is not None: + if self._provider_timestamp is not None: # pragma: no branch provider_details_dict['timestamp'] = self._provider_timestamp self.provider_details = provider_details_dict self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) diff --git a/pydantic_ai_slim/pydantic_ai/models/groq.py b/pydantic_ai_slim/pydantic_ai/models/groq.py index b471832c10..4bef882a32 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -551,7 +551,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: if raw_finish_reason := choice.finish_reason: provider_details_dict: dict[str, Any] = {'finish_reason': raw_finish_reason} - if self._provider_timestamp is not None: + if self._provider_timestamp is not None: # pragma: no branch provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) self.provider_details = provider_details_dict self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) diff --git a/pydantic_ai_slim/pydantic_ai/models/huggingface.py b/pydantic_ai_slim/pydantic_ai/models/huggingface.py index 3c6dad5f7e..05335ecd9a 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -489,7 +489,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: if raw_finish_reason := choice.finish_reason: provider_details_dict: dict[str, Any] = {'finish_reason': raw_finish_reason} - if self._provider_timestamp is not None: + if self._provider_timestamp is not None: # pragma: no branch provider_details_dict['timestamp'] = datetime.fromtimestamp( self._provider_timestamp, tz=timezone.utc ) diff --git a/pydantic_ai_slim/pydantic_ai/models/mistral.py b/pydantic_ai_slim/pydantic_ai/models/mistral.py index 995d76554e..1c6d89b2b8 100644 --- a/pydantic_ai_slim/pydantic_ai/models/mistral.py +++ b/pydantic_ai_slim/pydantic_ai/models/mistral.py @@ -631,7 +631,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: if raw_finish_reason := choice.finish_reason: provider_details_dict: dict[str, Any] = {'finish_reason': raw_finish_reason} - if self._provider_timestamp is not None: + if self._provider_timestamp is not None: # pragma: no branch provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) self.provider_details = provider_details_dict self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) From 40ffc8e8146d07faed98fd664112cb5e899c2945 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sat, 29 Nov 2025 23:00:48 -0500 Subject: [PATCH 05/25] improve code --- pydantic_ai_slim/pydantic_ai/models/google.py | 10 ++++++---- pydantic_ai_slim/pydantic_ai/models/groq.py | 10 ++++++---- pydantic_ai_slim/pydantic_ai/models/huggingface.py | 12 ++++++------ pydantic_ai_slim/pydantic_ai/models/mistral.py | 10 ++++++---- pydantic_ai_slim/pydantic_ai/models/openrouter.py | 2 +- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/models/google.py b/pydantic_ai_slim/pydantic_ai/models/google.py index 71e2ba97b3..797eaf61a6 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -684,12 +684,14 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: self.provider_response_id = chunk.response_id raw_finish_reason = candidate.finish_reason + provider_details_dict: dict[str, Any] = {} if raw_finish_reason: - provider_details_dict: dict[str, Any] = {'finish_reason': raw_finish_reason.value} - if self._provider_timestamp is not None: # pragma: no branch - provider_details_dict['timestamp'] = self._provider_timestamp - self.provider_details = provider_details_dict + provider_details_dict['finish_reason'] = raw_finish_reason.value self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) + if self._provider_timestamp is not None: + provider_details_dict['timestamp'] = self._provider_timestamp + if provider_details_dict: + self.provider_details = provider_details_dict # Google streams the grounding metadata (including the web search queries and results) # _after_ the text that was generated using it, so it would show up out of order in the stream, diff --git a/pydantic_ai_slim/pydantic_ai/models/groq.py b/pydantic_ai_slim/pydantic_ai/models/groq.py index 4bef882a32..ea833744c3 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -549,12 +549,14 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: except IndexError: continue + provider_details_dict: dict[str, Any] = {} if raw_finish_reason := choice.finish_reason: - provider_details_dict: dict[str, Any] = {'finish_reason': raw_finish_reason} - if self._provider_timestamp is not None: # pragma: no branch - provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) - self.provider_details = provider_details_dict + provider_details_dict['finish_reason'] = raw_finish_reason self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) + if self._provider_timestamp is not None: + provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) + if provider_details_dict: + self.provider_details = provider_details_dict if choice.delta.reasoning is not None: if not reasoning: diff --git a/pydantic_ai_slim/pydantic_ai/models/huggingface.py b/pydantic_ai_slim/pydantic_ai/models/huggingface.py index 05335ecd9a..d282edd2a1 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -487,16 +487,16 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: except IndexError: continue + provider_details_dict: dict[str, Any] = {} if raw_finish_reason := choice.finish_reason: - provider_details_dict: dict[str, Any] = {'finish_reason': raw_finish_reason} - if self._provider_timestamp is not None: # pragma: no branch - provider_details_dict['timestamp'] = datetime.fromtimestamp( - self._provider_timestamp, tz=timezone.utc - ) - self.provider_details = provider_details_dict + provider_details_dict['finish_reason'] = raw_finish_reason self.finish_reason = _FINISH_REASON_MAP.get( cast(TextGenerationOutputFinishReason, raw_finish_reason), None ) + if self._provider_timestamp is not None: + provider_details_dict['timestamp'] = datetime.fromtimestamp(self._provider_timestamp, tz=timezone.utc) + if provider_details_dict: + self.provider_details = provider_details_dict # Handle the text part of the response content = choice.delta.content diff --git a/pydantic_ai_slim/pydantic_ai/models/mistral.py b/pydantic_ai_slim/pydantic_ai/models/mistral.py index 1c6d89b2b8..3baba14858 100644 --- a/pydantic_ai_slim/pydantic_ai/models/mistral.py +++ b/pydantic_ai_slim/pydantic_ai/models/mistral.py @@ -629,12 +629,14 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: except IndexError: continue + provider_details_dict: dict[str, Any] = {} if raw_finish_reason := choice.finish_reason: - provider_details_dict: dict[str, Any] = {'finish_reason': raw_finish_reason} - if self._provider_timestamp is not None: # pragma: no branch - provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) - self.provider_details = provider_details_dict + provider_details_dict['finish_reason'] = raw_finish_reason self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) + if self._provider_timestamp is not None: + provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) + if provider_details_dict: + self.provider_details = provider_details_dict # Handle the text part of the response content = choice.delta.content diff --git a/pydantic_ai_slim/pydantic_ai/models/openrouter.py b/pydantic_ai_slim/pydantic_ai/models/openrouter.py index 721d77a74a..a6b12e3800 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openrouter.py +++ b/pydantic_ai_slim/pydantic_ai/models/openrouter.py @@ -694,7 +694,7 @@ def _map_provider_details(self, chunk: chat.ChatCompletionChunk) -> dict[str, An # chunk with usage data (see cassette test_openrouter_stream_with_native_options.yaml) # which has native_finish_reason: null. Since provider_details is replaced on each # chunk, we need to carry forward the finish_reason from the previous chunk. - if 'finish_reason' not in provider_details and self.provider_details: + if 'finish_reason' not in provider_details and self.provider_details: # pragma: no branch if previous_finish_reason := self.provider_details.get('finish_reason'): provider_details['finish_reason'] = previous_finish_reason return provider_details From 6da812decaebdc44951a7fd9993698772e844393 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sat, 29 Nov 2025 23:19:34 -0500 Subject: [PATCH 06/25] fix groq test --- tests/models/test_groq.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/models/test_groq.py b/tests/models/test_groq.py index 69d67aec63..16917934ba 100644 --- a/tests/models/test_groq.py +++ b/tests/models/test_groq.py @@ -545,6 +545,7 @@ async def test_stream_structured(allow_model_requests: None): timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='x', run_id=IsStr(), ), @@ -5553,6 +5554,7 @@ async def get_something_by_name(name: str) -> str: timestamp=IsDatetime(), provider_name='groq', provider_url='https://api.groq.com', + provider_details={'timestamp': datetime(2025, 9, 2, 21, 23, 3, tzinfo=timezone.utc)}, provider_response_id='chatcmpl-4e0ca299-7515-490a-a98a-16d7664d4fba', run_id=IsStr(), ), From 2a7143183ed2eb7f93a763490a38eedf69fbdf74 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sun, 30 Nov 2025 09:01:23 -0500 Subject: [PATCH 07/25] covergae --- pydantic_ai_slim/pydantic_ai/models/google.py | 2 +- pydantic_ai_slim/pydantic_ai/models/groq.py | 2 +- pydantic_ai_slim/pydantic_ai/models/huggingface.py | 2 +- pydantic_ai_slim/pydantic_ai/models/mistral.py | 2 +- pydantic_ai_slim/pydantic_ai/models/openrouter.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/models/google.py b/pydantic_ai_slim/pydantic_ai/models/google.py index 797eaf61a6..3d05882b38 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -688,7 +688,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: if raw_finish_reason: provider_details_dict['finish_reason'] = raw_finish_reason.value self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) - if self._provider_timestamp is not None: + if self._provider_timestamp is not None: # pragma: no branch provider_details_dict['timestamp'] = self._provider_timestamp if provider_details_dict: self.provider_details = provider_details_dict diff --git a/pydantic_ai_slim/pydantic_ai/models/groq.py b/pydantic_ai_slim/pydantic_ai/models/groq.py index ea833744c3..7e17ad99d6 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -553,7 +553,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: if raw_finish_reason := choice.finish_reason: provider_details_dict['finish_reason'] = raw_finish_reason self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) - if self._provider_timestamp is not None: + if self._provider_timestamp is not None: # pragma: no branch provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) if provider_details_dict: self.provider_details = provider_details_dict diff --git a/pydantic_ai_slim/pydantic_ai/models/huggingface.py b/pydantic_ai_slim/pydantic_ai/models/huggingface.py index d282edd2a1..6076bdf905 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -493,7 +493,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: self.finish_reason = _FINISH_REASON_MAP.get( cast(TextGenerationOutputFinishReason, raw_finish_reason), None ) - if self._provider_timestamp is not None: + if self._provider_timestamp is not None: # pragma: no branch provider_details_dict['timestamp'] = datetime.fromtimestamp(self._provider_timestamp, tz=timezone.utc) if provider_details_dict: self.provider_details = provider_details_dict diff --git a/pydantic_ai_slim/pydantic_ai/models/mistral.py b/pydantic_ai_slim/pydantic_ai/models/mistral.py index 3baba14858..302682c8d3 100644 --- a/pydantic_ai_slim/pydantic_ai/models/mistral.py +++ b/pydantic_ai_slim/pydantic_ai/models/mistral.py @@ -633,7 +633,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: if raw_finish_reason := choice.finish_reason: provider_details_dict['finish_reason'] = raw_finish_reason self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) - if self._provider_timestamp is not None: + if self._provider_timestamp is not None: # pragma: no branch provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) if provider_details_dict: self.provider_details = provider_details_dict diff --git a/pydantic_ai_slim/pydantic_ai/models/openrouter.py b/pydantic_ai_slim/pydantic_ai/models/openrouter.py index a6b12e3800..48b25ec163 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openrouter.py +++ b/pydantic_ai_slim/pydantic_ai/models/openrouter.py @@ -687,7 +687,7 @@ def _map_thinking_delta(self, choice: chat_completion_chunk.Choice) -> Iterable[ def _map_provider_details(self, chunk: chat.ChatCompletionChunk) -> dict[str, Any] | None: assert isinstance(chunk, _OpenRouterChatCompletionChunk) - if provider_details := super()._map_provider_details(chunk): + if provider_details := super()._map_provider_details(chunk): # pragma: no branch provider_details.update(_map_openrouter_provider_details(chunk)) # Preserve finish_reason from previous chunk if the current chunk doesn't have one. # After the chunk with native_finish_reason 'completed', OpenRouter sends one more From efcb78b3a8832cdf438bcd33d7366c09b12c239a Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sun, 30 Nov 2025 11:17:39 -0500 Subject: [PATCH 08/25] coverage --- pydantic_ai_slim/pydantic_ai/models/google.py | 4 ++-- pydantic_ai_slim/pydantic_ai/models/groq.py | 2 +- pydantic_ai_slim/pydantic_ai/models/huggingface.py | 2 +- pydantic_ai_slim/pydantic_ai/models/mistral.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/models/google.py b/pydantic_ai_slim/pydantic_ai/models/google.py index 3d05882b38..4de1416230 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -688,8 +688,8 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: if raw_finish_reason: provider_details_dict['finish_reason'] = raw_finish_reason.value self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) - if self._provider_timestamp is not None: # pragma: no branch - provider_details_dict['timestamp'] = self._provider_timestamp + if self._provider_timestamp is not None: + provider_details_dict['timestamp'] = self._provider_timestamp # pragma: no cover if provider_details_dict: self.provider_details = provider_details_dict diff --git a/pydantic_ai_slim/pydantic_ai/models/groq.py b/pydantic_ai_slim/pydantic_ai/models/groq.py index 7e17ad99d6..1e80e32a55 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -555,7 +555,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) if self._provider_timestamp is not None: # pragma: no branch provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) - if provider_details_dict: + if provider_details_dict: # pragma: no branch self.provider_details = provider_details_dict if choice.delta.reasoning is not None: diff --git a/pydantic_ai_slim/pydantic_ai/models/huggingface.py b/pydantic_ai_slim/pydantic_ai/models/huggingface.py index 6076bdf905..b80c3fd53d 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -495,7 +495,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: ) if self._provider_timestamp is not None: # pragma: no branch provider_details_dict['timestamp'] = datetime.fromtimestamp(self._provider_timestamp, tz=timezone.utc) - if provider_details_dict: + if provider_details_dict: # pragma: no branch self.provider_details = provider_details_dict # Handle the text part of the response diff --git a/pydantic_ai_slim/pydantic_ai/models/mistral.py b/pydantic_ai_slim/pydantic_ai/models/mistral.py index 302682c8d3..aed53f3e66 100644 --- a/pydantic_ai_slim/pydantic_ai/models/mistral.py +++ b/pydantic_ai_slim/pydantic_ai/models/mistral.py @@ -635,7 +635,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) if self._provider_timestamp is not None: # pragma: no branch provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) - if provider_details_dict: + if provider_details_dict: # pragma: no branch self.provider_details = provider_details_dict # Handle the text part of the response From 18150d73e44c5d5ba65bb524c033103102bc6b3c Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sun, 30 Nov 2025 11:23:15 -0500 Subject: [PATCH 09/25] add note --- pydantic_ai_slim/pydantic_ai/models/google.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pydantic_ai_slim/pydantic_ai/models/google.py b/pydantic_ai_slim/pydantic_ai/models/google.py index 4de1416230..e604e231c6 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -689,6 +689,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: provider_details_dict['finish_reason'] = raw_finish_reason.value self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) if self._provider_timestamp is not None: + # _provider_timestamp is always None in Google streaming cassettes provider_details_dict['timestamp'] = self._provider_timestamp # pragma: no cover if provider_details_dict: self.provider_details = provider_details_dict From 20f325521dba3be21867fc1916a0eb7e714bf04c Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Tue, 2 Dec 2025 16:15:45 -0500 Subject: [PATCH 10/25] - set default timestamp on StreamResponseModels - remove default timestamp on ModelResponse and set it manually - adjust tests --- pydantic_ai_slim/pydantic_ai/_a2a.py | 5 +- pydantic_ai_slim/pydantic_ai/_agent_graph.py | 15 ++-- pydantic_ai_slim/pydantic_ai/_mcp.py | 6 +- .../pydantic_ai/agent/abstract.py | 6 +- pydantic_ai_slim/pydantic_ai/messages.py | 4 +- .../pydantic_ai/models/anthropic.py | 4 +- pydantic_ai_slim/pydantic_ai/models/google.py | 16 ++-- pydantic_ai_slim/pydantic_ai/models/groq.py | 6 +- .../pydantic_ai/models/huggingface.py | 3 +- .../pydantic_ai/models/mistral.py | 4 +- pydantic_ai_slim/pydantic_ai/models/openai.py | 6 +- .../pydantic_ai/models/outlines.py | 9 +-- .../pydantic_ai/toolsets/fastmcp.py | 2 +- .../pydantic_ai/ui/_messages_builder.py | 4 +- tests/models/test_anthropic.py | 14 ++-- tests/models/test_bedrock.py | 19 +++-- tests/models/test_google.py | 13 +++- tests/models/test_huggingface.py | 2 +- tests/models/test_instrumented.py | 77 ++++++++++++------- tests/models/test_mcp_sampling.py | 3 +- tests/models/test_openai_responses.py | 13 +++- tests/models/test_outlines.py | 14 +++- tests/test_agent.py | 44 ++++++----- tests/test_history_processor.py | 50 ++++++------ tests/test_logfire.py | 8 +- tests/test_messages.py | 1 + tests/test_prefect.py | 14 +++- 27 files changed, 221 insertions(+), 141 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/_a2a.py b/pydantic_ai_slim/pydantic_ai/_a2a.py index eee3832b1b..77a07e935f 100644 --- a/pydantic_ai_slim/pydantic_ai/_a2a.py +++ b/pydantic_ai_slim/pydantic_ai/_a2a.py @@ -25,6 +25,7 @@ ToolCallPart, UserPromptPart, VideoUrl, + _utils, ) from .agent import AbstractAgent, AgentDepsT, OutputDataT @@ -200,7 +201,9 @@ def build_message_history(self, history: list[Message]) -> list[ModelMessage]: model_messages: list[ModelMessage] = [] for message in history: if message['role'] == 'user': - model_messages.append(ModelRequest(parts=self._request_parts_from_a2a(message['parts']))) + model_messages.append( + ModelRequest(parts=self._request_parts_from_a2a(message['parts']), timestamp=_utils.now_utc()) + ) else: model_messages.append(ModelResponse(parts=self._response_parts_from_a2a(message['parts']))) return model_messages diff --git a/pydantic_ai_slim/pydantic_ai/_agent_graph.py b/pydantic_ai_slim/pydantic_ai/_agent_graph.py index 821427411e..b4f1954c68 100644 --- a/pydantic_ai_slim/pydantic_ai/_agent_graph.py +++ b/pydantic_ai_slim/pydantic_ai/_agent_graph.py @@ -225,7 +225,7 @@ async def run( # noqa: C901 if isinstance(last_message, _messages.ModelRequest) and self.user_prompt is None: # Drop last message from history and reuse its parts messages.pop() - next_message = _messages.ModelRequest(parts=last_message.parts) + next_message = _messages.ModelRequest(parts=last_message.parts, timestamp=now_utc()) # Extract `UserPromptPart` content from the popped message and add to `ctx.deps.prompt` user_prompt_parts = [part for part in last_message.parts if isinstance(part, _messages.UserPromptPart)] @@ -269,7 +269,7 @@ async def run( # noqa: C901 if self.user_prompt is not None: parts.append(_messages.UserPromptPart(self.user_prompt)) - next_message = _messages.ModelRequest(parts=parts) + next_message = _messages.ModelRequest(parts=parts, timestamp=now_utc()) next_message.instructions = instructions @@ -637,7 +637,7 @@ async def _run_stream() -> AsyncIterator[_messages.HandleResponseEvent]: # noqa run_context = build_run_context(ctx) instructions = await ctx.deps.get_instructions(run_context) self._next_node = ModelRequestNode[DepsT, NodeRunEndT]( - _messages.ModelRequest(parts=[], instructions=instructions) + _messages.ModelRequest(parts=[], instructions=instructions, timestamp=now_utc()) ) return @@ -705,7 +705,7 @@ async def _run_stream() -> AsyncIterator[_messages.HandleResponseEvent]: # noqa run_context = build_run_context(ctx) instructions = await ctx.deps.get_instructions(run_context) self._next_node = ModelRequestNode[DepsT, NodeRunEndT]( - _messages.ModelRequest(parts=[e.tool_retry], instructions=instructions) + _messages.ModelRequest(parts=[e.tool_retry], instructions=instructions, timestamp=now_utc()) ) self._events_iterator = _run_stream() @@ -747,7 +747,7 @@ async def _handle_tool_calls( instructions = await ctx.deps.get_instructions(run_context) self._next_node = ModelRequestNode[DepsT, NodeRunEndT]( - _messages.ModelRequest(parts=output_parts, instructions=instructions) + _messages.ModelRequest(parts=output_parts, instructions=instructions, timestamp=now_utc()) ) async def _handle_text_response( @@ -782,7 +782,7 @@ def _handle_final_result( # For backwards compatibility, append a new ModelRequest using the tool returns and retries if tool_responses: - messages.append(_messages.ModelRequest(parts=tool_responses, run_id=ctx.state.run_id)) + messages.append(_messages.ModelRequest(parts=tool_responses, run_id=ctx.state.run_id, timestamp=now_utc())) return End(final_result) @@ -1359,8 +1359,7 @@ def _clean_message_history(messages: list[_messages.ModelMessage]) -> list[_mess key=lambda x: 0 if isinstance(x, _messages.ToolReturnPart | _messages.RetryPromptPart) else 1 ) merged_message = _messages.ModelRequest( - parts=parts, - instructions=last_message.instructions or message.instructions, + parts=parts, instructions=last_message.instructions or message.instructions, timestamp=now_utc() ) clean_messages[-1] = merged_message else: diff --git a/pydantic_ai_slim/pydantic_ai/_mcp.py b/pydantic_ai_slim/pydantic_ai/_mcp.py index 1729e4c225..2e2bd69b72 100644 --- a/pydantic_ai_slim/pydantic_ai/_mcp.py +++ b/pydantic_ai_slim/pydantic_ai/_mcp.py @@ -4,7 +4,7 @@ from collections.abc import Sequence from typing import Literal -from . import exceptions, messages +from . import _utils, exceptions, messages try: from mcp import types as mcp_types @@ -44,7 +44,7 @@ def map_from_mcp_params(params: mcp_types.CreateMessageRequestParams) -> list[me # role is assistant # if there are any request parts, add a request message wrapping them if request_parts: - pai_messages.append(messages.ModelRequest(parts=request_parts)) + pai_messages.append(messages.ModelRequest(parts=request_parts, timestamp=_utils.now_utc())) request_parts = [] response_parts.append(map_from_sampling_content(content)) @@ -52,7 +52,7 @@ def map_from_mcp_params(params: mcp_types.CreateMessageRequestParams) -> list[me if response_parts: pai_messages.append(messages.ModelResponse(parts=response_parts)) if request_parts: - pai_messages.append(messages.ModelRequest(parts=request_parts)) + pai_messages.append(messages.ModelRequest(parts=request_parts, timestamp=_utils.now_utc())) return pai_messages diff --git a/pydantic_ai_slim/pydantic_ai/agent/abstract.py b/pydantic_ai_slim/pydantic_ai/agent/abstract.py index 6c540ede64..1211fc8d6d 100644 --- a/pydantic_ai_slim/pydantic_ai/agent/abstract.py +++ b/pydantic_ai_slim/pydantic_ai/agent/abstract.py @@ -585,7 +585,11 @@ async def on_complete() -> None: # For backwards compatibility, append a new ModelRequest using the tool returns and retries if parts: - messages.append(_messages.ModelRequest(parts, run_id=graph_ctx.state.run_id)) + messages.append( + _messages.ModelRequest( + parts, run_id=graph_ctx.state.run_id, timestamp=_utils.now_utc() + ) + ) await agent_run.next(_agent_graph.SetFinalResult(final_result)) diff --git a/pydantic_ai_slim/pydantic_ai/messages.py b/pydantic_ai_slim/pydantic_ai/messages.py index b0a1cf9361..480622446b 100644 --- a/pydantic_ai_slim/pydantic_ai/messages.py +++ b/pydantic_ai_slim/pydantic_ai/messages.py @@ -1001,7 +1001,7 @@ class ModelRequest: _: KW_ONLY - timestamp: datetime = field(default_factory=_now_utc) + timestamp: datetime """The timestamp when the request was sent to the model.""" instructions: str | None = None @@ -1019,7 +1019,7 @@ class ModelRequest: @classmethod def user_text_prompt(cls, user_prompt: str, *, instructions: str | None = None) -> ModelRequest: """Create a `ModelRequest` with a single user prompt as text.""" - return cls(parts=[UserPromptPart(user_prompt)], instructions=instructions) + return cls(parts=[UserPromptPart(user_prompt)], instructions=instructions, timestamp=_now_utc()) __repr__ = _utils.dataclasses_no_defaults_repr diff --git a/pydantic_ai_slim/pydantic_ai/models/anthropic.py b/pydantic_ai_slim/pydantic_ai/models/anthropic.py index 9bc04f7619..0c0aa7e1e1 100644 --- a/pydantic_ai_slim/pydantic_ai/models/anthropic.py +++ b/pydantic_ai_slim/pydantic_ai/models/anthropic.py @@ -559,6 +559,7 @@ def _process_response(self, response: BetaMessage) -> ModelResponse: parts=items, usage=_map_usage(response, self._provider.name, self._provider.base_url, self._model_name), model_name=response.model, + timestamp=_utils.now_utc(), provider_response_id=response.id, provider_name=self._provider.name, provider_url=self._provider.base_url, @@ -580,7 +581,6 @@ async def _process_streamed_response( model_request_parameters=model_request_parameters, _model_name=first_chunk.message.model, _response=peekable_response, - _timestamp=_utils.now_utc(), _provider_name=self._provider.name, _provider_url=self._provider.base_url, ) @@ -1142,9 +1142,9 @@ class AnthropicStreamedResponse(StreamedResponse): _model_name: AnthropicModelName _response: AsyncIterable[BetaRawMessageStreamEvent] - _timestamp: datetime _provider_name: str _provider_url: str + _timestamp: datetime = field(default_factory=_utils.now_utc) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: # noqa: C901 current_block: BetaContentBlock | None = None diff --git a/pydantic_ai_slim/pydantic_ai/models/google.py b/pydantic_ai_slim/pydantic_ai/models/google.py index e604e231c6..3c05cd05f8 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -495,15 +495,17 @@ def _process_response(self, response: GenerateContentResponse) -> ModelResponse: candidate = response.candidates[0] vendor_id = response.response_id - vendor_details: dict[str, Any] | None = None finish_reason: FinishReason | None = None + vendor_details: dict[str, Any] = {} + raw_finish_reason = candidate.finish_reason if raw_finish_reason: # pragma: no branch - vendor_details = {'finish_reason': raw_finish_reason.value} - if response.create_time is not None: - vendor_details['timestamp'] = response.create_time + vendor_details['finish_reason'] = raw_finish_reason.value finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) + if response.create_time is not None: # pragma: no branch + vendor_details['timestamp'] = response.create_time + if candidate.content is None or candidate.content.parts is None: if finish_reason == 'content_filter' and raw_finish_reason: raise UnexpectedModelBehavior( @@ -522,7 +524,7 @@ def _process_response(self, response: GenerateContentResponse) -> ModelResponse: self._provider.base_url, usage, vendor_id=vendor_id, - vendor_details=vendor_details, + vendor_details=vendor_details or None, finish_reason=finish_reason, url_context_metadata=candidate.url_context_metadata, ) @@ -540,7 +542,6 @@ async def _process_streamed_response( model_request_parameters=model_request_parameters, _model_name=first_chunk.model_version or self._model_name, _response=peekable_response, - _timestamp=_utils.now_utc(), _provider_name=self._provider.name, _provider_url=self._provider.base_url, _provider_timestamp=first_chunk.create_time, @@ -665,10 +666,10 @@ class GeminiStreamedResponse(StreamedResponse): _model_name: GoogleModelName _response: AsyncIterator[GenerateContentResponse] - _timestamp: datetime _provider_name: str _provider_url: str _provider_timestamp: datetime | None = None + _timestamp: datetime = field(default_factory=_utils.now_utc) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: # noqa: C901 code_execution_tool_call_id: str | None = None @@ -949,6 +950,7 @@ def _process_response_from_parts( return ModelResponse( parts=items, model_name=model_name, + timestamp=_utils.now_utc(), usage=usage, provider_response_id=vendor_id, provider_details=vendor_details, diff --git a/pydantic_ai_slim/pydantic_ai/models/groq.py b/pydantic_ai_slim/pydantic_ai/models/groq.py index 1e80e32a55..398690126f 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -321,7 +321,6 @@ async def _completions_create( def _process_response(self, response: chat.ChatCompletion) -> ModelResponse: """Process a non-streamed response, and prepare a message to return.""" - timestamp = _utils.now_utc() choice = response.choices[0] items: list[ModelResponsePart] = [] if choice.message.reasoning is not None: @@ -349,7 +348,7 @@ def _process_response(self, response: chat.ChatCompletion) -> ModelResponse: parts=items, usage=_map_usage(response), model_name=response.model, - timestamp=timestamp, + timestamp=_utils.now_utc(), provider_response_id=response.id, provider_name=self._provider.name, provider_url=self.base_url, @@ -373,7 +372,6 @@ async def _process_streamed_response( _response=peekable_response, _model_name=first_chunk.model, _model_profile=self.profile, - _timestamp=_utils.now_utc(), _provider_name=self._provider.name, _provider_url=self.base_url, _provider_timestamp=first_chunk.created, @@ -528,10 +526,10 @@ class GroqStreamedResponse(StreamedResponse): _model_name: GroqModelName _model_profile: ModelProfile _response: AsyncIterable[chat.ChatCompletionChunk] - _timestamp: datetime _provider_name: str _provider_url: str _provider_timestamp: int | None = None + _timestamp: datetime = field(default_factory=_utils.now_utc) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: # noqa: C901 try: diff --git a/pydantic_ai_slim/pydantic_ai/models/huggingface.py b/pydantic_ai_slim/pydantic_ai/models/huggingface.py index b80c3fd53d..a2b6630c3a 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -320,7 +320,6 @@ async def _process_streamed_response( _model_name=first_chunk.model, _model_profile=self.profile, _response=peekable_response, - _timestamp=_now_utc(), _provider_name=self._provider.name, _provider_url=self.base_url, _provider_timestamp=first_chunk.created, @@ -470,10 +469,10 @@ class HuggingFaceStreamedResponse(StreamedResponse): _model_name: str _model_profile: ModelProfile _response: AsyncIterable[ChatCompletionStreamOutput] - _timestamp: datetime _provider_name: str _provider_url: str _provider_timestamp: int | None = None + _timestamp: datetime = field(default_factory=_utils.now_utc) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: async for chunk in self._response: diff --git a/pydantic_ai_slim/pydantic_ai/models/mistral.py b/pydantic_ai_slim/pydantic_ai/models/mistral.py index aed53f3e66..3c5be3f99e 100644 --- a/pydantic_ai_slim/pydantic_ai/models/mistral.py +++ b/pydantic_ai_slim/pydantic_ai/models/mistral.py @@ -401,7 +401,6 @@ async def _process_streamed_response( model_request_parameters=model_request_parameters, _response=peekable_response, _model_name=first_chunk.data.model, - _timestamp=_now_utc(), _provider_name=self._provider.name, _provider_url=self._provider.base_url, _provider_timestamp=first_chunk.data.created, @@ -610,10 +609,11 @@ class MistralStreamedResponse(StreamedResponse): _model_name: MistralModelName _response: AsyncIterable[MistralCompletionEvent] - _timestamp: datetime _provider_name: str _provider_url: str _provider_timestamp: int | None = None + _timestamp: datetime = field(default_factory=_now_utc) + _delta_content: str = field(default='', init=False) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: diff --git a/pydantic_ai_slim/pydantic_ai/models/openai.py b/pydantic_ai_slim/pydantic_ai/models/openai.py index 7a3a89d9b4..6fddc4bd58 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -716,7 +716,6 @@ async def _process_streamed_response( _model_name=model_name, _model_profile=self.profile, _response=peekable_response, - _timestamp=_now_utc(), _provider_name=self._provider.name, _provider_url=self._provider.base_url, _provider_timestamp=first_chunk.created, @@ -1310,7 +1309,6 @@ async def _process_streamed_response( model_request_parameters=model_request_parameters, _model_name=first_chunk.response.model, _response=peekable_response, - _timestamp=_now_utc(), _provider_name=self._provider.name, _provider_url=self._provider.base_url, # type of created_at is float but it's actually a Unix timestamp in seconds @@ -1923,10 +1921,10 @@ class OpenAIStreamedResponse(StreamedResponse): _model_name: OpenAIModelName _model_profile: ModelProfile _response: AsyncIterable[ChatCompletionChunk] - _timestamp: datetime _provider_name: str _provider_url: str _provider_timestamp: int | None = None + _timestamp: datetime = field(default_factory=_now_utc) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: async for chunk in self._validate_response(): @@ -2087,10 +2085,10 @@ class OpenAIResponsesStreamedResponse(StreamedResponse): _model_name: OpenAIModelName _response: AsyncIterable[responses.ResponseStreamEvent] - _timestamp: datetime _provider_name: str _provider_url: str _provider_timestamp: int | None = None + _timestamp: datetime = field(default_factory=_now_utc) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: # noqa: C901 async for chunk in self._response: diff --git a/pydantic_ai_slim/pydantic_ai/models/outlines.py b/pydantic_ai_slim/pydantic_ai/models/outlines.py index d8dc6b2241..9cde3e2f2c 100644 --- a/pydantic_ai_slim/pydantic_ai/models/outlines.py +++ b/pydantic_ai_slim/pydantic_ai/models/outlines.py @@ -8,8 +8,8 @@ import io from collections.abc import AsyncIterable, AsyncIterator, Sequence from contextlib import asynccontextmanager -from dataclasses import dataclass, replace -from datetime import datetime, timezone +from dataclasses import dataclass, field, replace +from datetime import datetime from typing import TYPE_CHECKING, Any, Literal, cast from typing_extensions import assert_never @@ -507,6 +507,7 @@ def _process_response(self, response: str) -> ModelResponse: parts=cast( list[ModelResponsePart], split_content_into_text_and_thinking(response, self.profile.thinking_tags) ), + timestamp=_utils.now_utc(), ) async def _process_streamed_response( @@ -518,13 +519,11 @@ async def _process_streamed_response( if isinstance(first_chunk, _utils.Unset): # pragma: no cover raise UnexpectedModelBehavior('Streamed response ended without content or tool calls') - timestamp = datetime.now(tz=timezone.utc) return OutlinesStreamedResponse( model_request_parameters=model_request_parameters, _model_name=self._model_name, _model_profile=self.profile, _response=peekable_response, - _timestamp=timestamp, _provider_name='outlines', ) @@ -544,9 +543,9 @@ class OutlinesStreamedResponse(StreamedResponse): _model_name: str _model_profile: ModelProfile _response: AsyncIterable[str] - _timestamp: datetime _provider_name: str _provider_url: str | None = None + _timestamp: datetime = field(default_factory=_utils.now_utc) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: async for content in self._response: diff --git a/pydantic_ai_slim/pydantic_ai/toolsets/fastmcp.py b/pydantic_ai_slim/pydantic_ai/toolsets/fastmcp.py index 5e8b863e2c..2d907266fd 100644 --- a/pydantic_ai_slim/pydantic_ai/toolsets/fastmcp.py +++ b/pydantic_ai_slim/pydantic_ai/toolsets/fastmcp.py @@ -187,7 +187,7 @@ def _map_fastmcp_tool_results(parts: list[ContentBlock]) -> list[FastMCPToolResu def _map_fastmcp_tool_result(part: ContentBlock) -> FastMCPToolResult: if isinstance(part, TextContent): return part.text - elif isinstance(part, (ImageContent, AudioContent)): + elif isinstance(part, ImageContent | AudioContent): return messages.BinaryContent(data=base64.b64decode(part.data), media_type=part.mimeType) elif isinstance(part, EmbeddedResource): if isinstance(part.resource, BlobResourceContents): diff --git a/pydantic_ai_slim/pydantic_ai/ui/_messages_builder.py b/pydantic_ai_slim/pydantic_ai/ui/_messages_builder.py index 6a2edf1715..5d9207c318 100644 --- a/pydantic_ai_slim/pydantic_ai/ui/_messages_builder.py +++ b/pydantic_ai_slim/pydantic_ai/ui/_messages_builder.py @@ -1,7 +1,7 @@ from dataclasses import dataclass, field from typing import cast -from pydantic_ai._utils import get_union_args +from pydantic_ai._utils import get_union_args, now_utc as _now_utc from pydantic_ai.messages import ModelMessage, ModelRequest, ModelRequestPart, ModelResponse, ModelResponsePart @@ -19,7 +19,7 @@ def add(self, part: ModelRequestPart | ModelResponsePart) -> None: if isinstance(last_message, ModelRequest): last_message.parts = [*last_message.parts, part] else: - self.messages.append(ModelRequest(parts=[part])) + self.messages.append(ModelRequest(parts=[part], timestamp=_now_utc())) else: part = cast(ModelResponsePart, part) if isinstance(last_message, ModelResponse): diff --git a/tests/models/test_anthropic.py b/tests/models/test_anthropic.py index 4d65461667..93eff8b53a 100644 --- a/tests/models/test_anthropic.py +++ b/tests/models/test_anthropic.py @@ -2680,7 +2680,7 @@ async def test_anthropic_model_empty_message_on_history(allow_model_requests: No result = await agent.run( 'I need a potato!', message_history=[ - ModelRequest(parts=[], instructions='You are a helpful assistant.', kind='request'), + ModelRequest(parts=[], instructions='You are a helpful assistant.', kind='request', timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Hello, how can I help you?')], kind='response'), ], ) @@ -4893,7 +4893,7 @@ async def test_anthropic_web_fetch_tool_message_replay(): # Create message history with BuiltinToolCallPart and BuiltinToolReturnPart messages = [ - ModelRequest(parts=[UserPromptPart(content='Test')]), + ModelRequest(parts=[UserPromptPart(content='Test')], timestamp=IsDatetime()), ModelResponse( parts=[ BuiltinToolCallPart( @@ -6366,14 +6366,16 @@ async def test_anthropic_empty_content_filtering(env: TestEnv): # Test _map_message with empty string in user prompt messages_empty_string: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='')], kind='request'), + ModelRequest(parts=[UserPromptPart(content='')], kind='request', timestamp=IsDatetime()), ] _, anthropic_messages = await model._map_message(messages_empty_string, ModelRequestParameters(), {}) # type: ignore[attr-defined] assert anthropic_messages == snapshot([]) # Empty content should be filtered out # Test _map_message with list containing empty strings in user prompt messages_mixed_content: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content=['', 'Hello', '', 'World'])], kind='request'), + ModelRequest( + parts=[UserPromptPart(content=['', 'Hello', '', 'World'])], kind='request', timestamp=IsDatetime() + ), ] _, anthropic_messages = await model._map_message(messages_mixed_content, ModelRequestParameters(), {}) # type: ignore[attr-defined] assert anthropic_messages == snapshot( @@ -6382,9 +6384,9 @@ async def test_anthropic_empty_content_filtering(env: TestEnv): # Test _map_message with empty assistant response messages: list[ModelMessage] = [ - ModelRequest(parts=[SystemPromptPart(content='You are helpful')], kind='request'), + ModelRequest(parts=[SystemPromptPart(content='You are helpful')], kind='request', timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='')], kind='response'), # Empty response - ModelRequest(parts=[UserPromptPart(content='Hello')], kind='request'), + ModelRequest(parts=[UserPromptPart(content='Hello')], kind='request', timestamp=IsDatetime()), ] _, anthropic_messages = await model._map_message(messages, ModelRequestParameters(), {}) # type: ignore[attr-defined] # The empty assistant message should be filtered out diff --git a/tests/models/test_bedrock.py b/tests/models/test_bedrock.py index 91c502b5fa..7efd3ca492 100644 --- a/tests/models/test_bedrock.py +++ b/tests/models/test_bedrock.py @@ -824,9 +824,14 @@ async def test_bedrock_multiple_documents_in_history( result = await agent.run( 'What is in the documents?', message_history=[ - ModelRequest(parts=[UserPromptPart(content=['Here is a PDF document: ', document_content])]), + ModelRequest( + parts=[UserPromptPart(content=['Here is a PDF document: ', document_content])], timestamp=IsDatetime() + ), ModelResponse(parts=[TextPart(content='foo bar')]), - ModelRequest(parts=[UserPromptPart(content=['Here is another PDF document: ', document_content])]), + ModelRequest( + parts=[UserPromptPart(content=['Here is another PDF document: ', document_content])], + timestamp=IsDatetime(), + ), ModelResponse(parts=[TextPart(content='foo bar 2')]), ], ) @@ -1353,16 +1358,17 @@ async def test_bedrock_group_consecutive_tool_return_parts(bedrock_provider: Bed now = datetime.datetime.now() # Create a ModelRequest with 3 consecutive ToolReturnParts req = [ - ModelRequest(parts=[UserPromptPart(content=['Hello'])]), + ModelRequest(parts=[UserPromptPart(content=['Hello'])], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Hi')]), - ModelRequest(parts=[UserPromptPart(content=['How are you?'])]), + ModelRequest(parts=[UserPromptPart(content=['How are you?'])], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Cloudy')]), ModelRequest( parts=[ ToolReturnPart(tool_name='tool1', content='result1', tool_call_id='id1', timestamp=now), ToolReturnPart(tool_name='tool2', content='result2', tool_call_id='id2', timestamp=now), ToolReturnPart(tool_name='tool3', content='result3', tool_call_id='id3', timestamp=now), - ] + ], + timestamp=IsDatetime(), ), ] @@ -1483,7 +1489,8 @@ async def test_bedrock_mistral_tool_result_format(bedrock_provider: BedrockProvi ModelRequest( parts=[ ToolReturnPart(tool_name='tool1', content={'foo': 'bar'}, tool_call_id='id1', timestamp=now), - ] + ], + timestamp=IsDatetime(), ), ] diff --git a/tests/models/test_google.py b/tests/models/test_google.py index b35580bc1d..a78b9c53ca 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -982,9 +982,14 @@ async def test_google_model_multiple_documents_in_history( result = await agent.run( 'What is in the documents?', message_history=[ - ModelRequest(parts=[UserPromptPart(content=['Here is a PDF document: ', document_content])]), + ModelRequest( + parts=[UserPromptPart(content=['Here is a PDF document: ', document_content])], timestamp=IsDatetime() + ), ModelResponse(parts=[TextPart(content='foo bar')]), - ModelRequest(parts=[UserPromptPart(content=['Here is another PDF document: ', document_content])]), + ModelRequest( + parts=[UserPromptPart(content=['Here is another PDF document: ', document_content])], + timestamp=IsDatetime(), + ), ModelResponse(parts=[TextPart(content='foo bar 2')]), ], ) @@ -1926,7 +1931,7 @@ async def test_google_model_empty_assistant_response(allow_model_requests: None, result = await agent.run( 'Was your previous response empty?', message_history=[ - ModelRequest(parts=[UserPromptPart(content='Hi')]), + ModelRequest(parts=[UserPromptPart(content='Hi')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='')]), ], ) @@ -4371,7 +4376,7 @@ async def test_google_api_non_http_error( async def test_google_model_retrying_after_empty_response(allow_model_requests: None, google_provider: GoogleProvider): message_history = [ - ModelRequest(parts=[UserPromptPart(content='Hi')]), + ModelRequest(parts=[UserPromptPart(content='Hi')], timestamp=IsDatetime()), ModelResponse(parts=[]), ] diff --git a/tests/models/test_huggingface.py b/tests/models/test_huggingface.py index bf0ed15986..3ec552cf0d 100644 --- a/tests/models/test_huggingface.py +++ b/tests/models/test_huggingface.py @@ -899,7 +899,7 @@ async def test_thinking_part_in_history(allow_model_requests: None): model = HuggingFaceModel('hf-model', provider=HuggingFaceProvider(hf_client=mock_client, api_key='x')) agent = Agent(model) messages = [ - ModelRequest(parts=[UserPromptPart(content='request')]), + ModelRequest(parts=[UserPromptPart(content='request')], timestamp=IsDatetime()), ModelResponse( parts=[ TextPart(content='text 1'), diff --git a/tests/models/test_instrumented.py b/tests/models/test_instrumented.py index 47f7a38731..bb176b0bc5 100644 --- a/tests/models/test_instrumented.py +++ b/tests/models/test_instrumented.py @@ -44,7 +44,7 @@ from pydantic_ai.settings import ModelSettings from pydantic_ai.usage import RequestUsage -from ..conftest import IsInt, IsStr, try_import +from ..conftest import IsDatetime, IsInt, IsStr, try_import with try_import() as imports_successful: from logfire.testing import CaptureLogfire @@ -148,7 +148,8 @@ async def test_instrumented_model(capfire: CaptureLogfire): RetryPromptPart('retry_prompt1', tool_name='tool4', tool_call_id='tool_call_4'), RetryPromptPart('retry_prompt2'), {}, # test unexpected parts # type: ignore - ] + ], + timestamp=IsDatetime(), ), ModelResponse(parts=[TextPart('text3')]), ] @@ -359,7 +360,7 @@ async def test_instrumented_model_not_recording(): InstrumentationSettings(tracer_provider=NoOpTracerProvider(), logger_provider=NoOpLoggerProvider()), ) - messages: list[ModelMessage] = [ModelRequest(parts=[SystemPromptPart('system_prompt')])] + messages: list[ModelMessage] = [ModelRequest(parts=[SystemPromptPart('system_prompt')], timestamp=IsDatetime())] await model.request( messages, model_settings=ModelSettings(temperature=1), @@ -380,7 +381,8 @@ async def test_instrumented_model_stream(capfire: CaptureLogfire): ModelRequest( parts=[ UserPromptPart('user_prompt'), - ] + ], + timestamp=IsDatetime(), ), ] async with model.request_stream( @@ -482,7 +484,8 @@ async def test_instrumented_model_stream_break(capfire: CaptureLogfire): ModelRequest( parts=[ UserPromptPart('user_prompt'), - ] + ], + timestamp=IsDatetime(), ), ] @@ -607,6 +610,7 @@ async def test_instrumented_model_attributes_mode(capfire: CaptureLogfire, instr RetryPromptPart('retry_prompt2'), {}, # test unexpected parts # type: ignore ], + timestamp=IsDatetime(), ), ModelResponse(parts=[TextPart('text3')]), ] @@ -987,7 +991,7 @@ def __repr__(self): messages = [ ModelResponse(parts=[ToolCallPart('tool', {'arg': Foo()}, tool_call_id='tool_call_id')]), - ModelRequest(parts=[ToolReturnPart('tool', Bar(), tool_call_id='return_tool_call_id')]), + ModelRequest(parts=[ToolReturnPart('tool', Bar(), tool_call_id='return_tool_call_id')], timestamp=IsDatetime()), ] settings = InstrumentationSettings() @@ -1026,7 +1030,7 @@ def __repr__(self): def test_messages_to_otel_events_instructions(): messages = [ - ModelRequest(instructions='instructions', parts=[UserPromptPart('user_prompt')]), + ModelRequest(instructions='instructions', parts=[UserPromptPart('user_prompt')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart('text1')]), ] settings = InstrumentationSettings() @@ -1052,9 +1056,9 @@ def test_messages_to_otel_events_instructions(): def test_messages_to_otel_events_instructions_multiple_messages(): messages = [ - ModelRequest(instructions='instructions', parts=[UserPromptPart('user_prompt')]), + ModelRequest(instructions='instructions', parts=[UserPromptPart('user_prompt')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart('text1')]), - ModelRequest(instructions='instructions2', parts=[UserPromptPart('user_prompt2')]), + ModelRequest(instructions='instructions2', parts=[UserPromptPart('user_prompt2')], timestamp=IsDatetime()), ] settings = InstrumentationSettings() assert [InstrumentedModel.event_to_dict(e) for e in settings.messages_to_otel_events(messages)] == snapshot( @@ -1081,10 +1085,22 @@ def test_messages_to_otel_events_instructions_multiple_messages(): def test_messages_to_otel_events_image_url(document_content: BinaryContent): messages = [ - ModelRequest(parts=[UserPromptPart(content=['user_prompt', ImageUrl('https://example.com/image.png')])]), - ModelRequest(parts=[UserPromptPart(content=['user_prompt2', AudioUrl('https://example.com/audio.mp3')])]), - ModelRequest(parts=[UserPromptPart(content=['user_prompt3', DocumentUrl('https://example.com/document.pdf')])]), - ModelRequest(parts=[UserPromptPart(content=['user_prompt4', VideoUrl('https://example.com/video.mp4')])]), + ModelRequest( + parts=[UserPromptPart(content=['user_prompt', ImageUrl('https://example.com/image.png')])], + timestamp=IsDatetime(), + ), + ModelRequest( + parts=[UserPromptPart(content=['user_prompt2', AudioUrl('https://example.com/audio.mp3')])], + timestamp=IsDatetime(), + ), + ModelRequest( + parts=[UserPromptPart(content=['user_prompt3', DocumentUrl('https://example.com/document.pdf')])], + timestamp=IsDatetime(), + ), + ModelRequest( + parts=[UserPromptPart(content=['user_prompt4', VideoUrl('https://example.com/video.mp4')])], + timestamp=IsDatetime(), + ), ModelRequest( parts=[ UserPromptPart( @@ -1096,9 +1112,10 @@ def test_messages_to_otel_events_image_url(document_content: BinaryContent): VideoUrl('https://example.com/video2.mp4'), ] ) - ] + ], + timestamp=IsDatetime(), ), - ModelRequest(parts=[UserPromptPart(content=['user_prompt6', document_content])]), + ModelRequest(parts=[UserPromptPart(content=['user_prompt6', document_content])], timestamp=IsDatetime()), ModelResponse(parts=[TextPart('text1')]), ModelResponse(parts=[FilePart(content=document_content)]), ] @@ -1238,7 +1255,7 @@ def test_messages_to_otel_events_image_url(document_content: BinaryContent): def test_messages_to_otel_events_without_binary_content(document_content: BinaryContent): messages: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content=['user_prompt6', document_content])]), + ModelRequest(parts=[UserPromptPart(content=['user_prompt6', document_content])], timestamp=IsDatetime()), ] settings = InstrumentationSettings(include_binary_content=False) assert [InstrumentedModel.event_to_dict(e) for e in settings.messages_to_otel_events(messages)] == snapshot( @@ -1266,7 +1283,7 @@ def test_messages_to_otel_events_without_binary_content(document_content: Binary def test_messages_without_content(document_content: BinaryContent): messages: list[ModelMessage] = [ - ModelRequest(parts=[SystemPromptPart('system_prompt')]), + ModelRequest(parts=[SystemPromptPart('system_prompt')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart('text1')]), ModelRequest( parts=[ @@ -1280,13 +1297,17 @@ def test_messages_without_content(document_content: BinaryContent): document_content, ] ) - ] + ], + timestamp=IsDatetime(), ), ModelResponse(parts=[TextPart('text2'), ToolCallPart(tool_name='my_tool', args={'a': 13, 'b': 4})]), - ModelRequest(parts=[ToolReturnPart('tool', 'tool_return_content', 'tool_call_1')]), - ModelRequest(parts=[RetryPromptPart('retry_prompt', tool_name='tool', tool_call_id='tool_call_2')]), - ModelRequest(parts=[UserPromptPart(content=['user_prompt2', document_content])]), - ModelRequest(parts=[UserPromptPart('simple text prompt')]), + ModelRequest(parts=[ToolReturnPart('tool', 'tool_return_content', 'tool_call_1')], timestamp=IsDatetime()), + ModelRequest( + parts=[RetryPromptPart('retry_prompt', tool_name='tool', tool_call_id='tool_call_2')], + timestamp=IsDatetime(), + ), + ModelRequest(parts=[UserPromptPart(content=['user_prompt2', document_content])], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart('simple text prompt')], timestamp=IsDatetime()), ModelResponse(parts=[FilePart(content=document_content)]), ] settings = InstrumentationSettings(include_content=False) @@ -1460,7 +1481,7 @@ def test_deprecated_event_mode_warning(): async def test_response_cost_error(capfire: CaptureLogfire, monkeypatch: pytest.MonkeyPatch): model = InstrumentedModel(MyModel()) - messages: list[ModelMessage] = [ModelRequest(parts=[UserPromptPart('user_prompt')])] + messages: list[ModelMessage] = [ModelRequest(parts=[UserPromptPart('user_prompt')], timestamp=IsDatetime())] monkeypatch.setattr(ModelResponse, 'cost', None) with warns( @@ -1619,7 +1640,9 @@ def test_cache_point_in_user_prompt(): OpenTelemetry message parts output. """ messages: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content=['text before', CachePoint(), 'text after'])]), + ModelRequest( + parts=[UserPromptPart(content=['text before', CachePoint(), 'text after'])], timestamp=IsDatetime() + ), ] settings = InstrumentationSettings() @@ -1641,7 +1664,8 @@ def test_cache_point_in_user_prompt(): ModelRequest( parts=[ UserPromptPart(content=['first', CachePoint(), 'second', CachePoint(), 'third']), - ] + ], + timestamp=IsDatetime(), ), ] assert settings.messages_to_otel_messages(messages_multi) == snapshot( @@ -1670,7 +1694,8 @@ def test_cache_point_in_user_prompt(): 'question', ] ), - ] + ], + timestamp=IsDatetime(), ), ] assert settings.messages_to_otel_messages(messages_mixed) == snapshot( diff --git a/tests/models/test_mcp_sampling.py b/tests/models/test_mcp_sampling.py index 4218d09287..c4094ce818 100644 --- a/tests/models/test_mcp_sampling.py +++ b/tests/models/test_mcp_sampling.py @@ -128,7 +128,8 @@ def test_assistant_text_history_complex(): content=['a string', BinaryContent(data=base64.b64encode(b'data'), media_type='image/jpeg')] ), SystemPromptPart(content='system content'), - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[TextPart(content='text content')], diff --git a/tests/models/test_openai_responses.py b/tests/models/test_openai_responses.py index 33c2cc00b3..b38426f17a 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -2016,6 +2016,7 @@ async def test_openai_previous_response_id_auto_mode(allow_model_requests: None, content='The first secret key is sesame', ), ], + timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -2031,6 +2032,7 @@ async def test_openai_previous_response_id_auto_mode(allow_model_requests: None, content='The second secret key is olives', ), ], + timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -2058,6 +2060,7 @@ async def test_openai_previous_response_id_mixed_model_history(allow_model_reque content='The first secret key is sesame', ), ], + timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -2073,6 +2076,7 @@ async def test_openai_previous_response_id_mixed_model_history(allow_model_reque content='what is the first secret key?', ), ], + timestamp=IsDatetime(), ), ] @@ -2110,6 +2114,7 @@ async def test_openai_previous_response_id_same_model_history(allow_model_reques content='The first secret key is sesame', ), ], + timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -2125,6 +2130,7 @@ async def test_openai_previous_response_id_same_model_history(allow_model_reques content='The second secret key is olives', ), ], + timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -2140,6 +2146,7 @@ async def test_openai_previous_response_id_same_model_history(allow_model_reques content='what is the first secret key?', ), ], + timestamp=IsDatetime(), ), ] @@ -6839,7 +6846,8 @@ class CityLocation(BaseModel): UserPromptPart( content='What is the largest city in the user country?', ) - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -6861,7 +6869,8 @@ class CityLocation(BaseModel): content='Mexico', tool_call_id='call_ZWkVhdUjupo528U9dqgFeRkH|fc_68477f0bb8e4819cba6d781e174d77f8001fd29e2d5573f7', ) - ] + ], + timestamp=IsDatetime(), ), ] diff --git a/tests/models/test_outlines.py b/tests/models/test_outlines.py index ba78ac6755..c8b3d2cb1c 100644 --- a/tests/models/test_outlines.py +++ b/tests/models/test_outlines.py @@ -552,7 +552,8 @@ def test_input_format(transformers_multimodal_model: OutlinesModel, binary_image SystemPromptPart(content='You are a helpful assistance'), UserPromptPart(content='Hello'), RetryPromptPart(content='Failure'), - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -574,7 +575,8 @@ def test_input_format(transformers_multimodal_model: OutlinesModel, binary_image AudioUrl('https://example.com/audio.mp3'), ] ) - ] + ], + timestamp=IsDatetime(), ) ] with pytest.raises( @@ -585,14 +587,18 @@ def test_input_format(transformers_multimodal_model: OutlinesModel, binary_image # unsupported: tool calls tool_call_message_history: list[ModelMessage] = [ ModelResponse(parts=[ToolCallPart(tool_call_id='1', tool_name='get_location')]), - ModelRequest(parts=[ToolReturnPart(tool_name='get_location', content='London', tool_call_id='1')]), + ModelRequest( + parts=[ToolReturnPart(tool_name='get_location', content='London', tool_call_id='1')], timestamp=IsDatetime() + ), ] with pytest.raises(UserError, match='Tool calls are not supported for Outlines models yet.'): agent.run_sync('How are you doing?', message_history=tool_call_message_history) # unsupported: tool returns tool_return_message_history: list[ModelMessage] = [ - ModelRequest(parts=[ToolReturnPart(tool_name='get_location', content='London', tool_call_id='1')]) + ModelRequest( + parts=[ToolReturnPart(tool_name='get_location', content='London', tool_call_id='1')], timestamp=IsDatetime() + ) ] with pytest.raises(UserError, match='Tool calls are not supported for Outlines models yet.'): agent.run_sync('How are you doing?', message_history=tool_return_message_history) diff --git a/tests/test_agent.py b/tests/test_agent.py index 51c5daec93..427ebfa530 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -2422,6 +2422,7 @@ async def system_prompt(ctx: RunContext) -> str: UserPromptPart(content='How goes it?'), ], instructions='Original instructions', + timestamp=IsDatetime(), ), ] @@ -2479,7 +2480,7 @@ def test_tool() -> str: return 'Test response' message_history = [ - ModelRequest(parts=[UserPromptPart(content='Hello')]), + ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), ModelResponse(parts=[ToolCallPart(tool_name='test_tool', args='{}', tool_call_id='call_123')]), ] @@ -2534,7 +2535,7 @@ def simple_response(_messages: list[ModelMessage], _info: AgentInfo) -> ModelRes agent = Agent(FunctionModel(simple_response)) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Hello')]), + ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), ModelResponse(parts=[ToolCallPart(tool_name='test_tool', args='{}', tool_call_id='call_123')]), ] @@ -2552,7 +2553,7 @@ def simple_response(_messages: list[ModelMessage], _info: AgentInfo) -> ModelRes agent = Agent(FunctionModel(simple_response)) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Hello')]), + ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart('world')]), ] @@ -2589,15 +2590,15 @@ async def test_message_history_ending_on_model_response_with_instructions(): ) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Hi, my name is James')]), + ModelRequest(parts=[UserPromptPart(content='Hi, my name is James')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Nice to meet you, James.')]), - ModelRequest(parts=[UserPromptPart(content='I like cars')]), + ModelRequest(parts=[UserPromptPart(content='I like cars')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='I like them too. Sport cars?')]), - ModelRequest(parts=[UserPromptPart(content='No, cars in general.')]), + ModelRequest(parts=[UserPromptPart(content='No, cars in general.')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Awesome. Which one do you like most?')]), - ModelRequest(parts=[UserPromptPart(content='Fiat 126p')]), + ModelRequest(parts=[UserPromptPart(content='Fiat 126p')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content="That's an old one, isn't it?")]), - ModelRequest(parts=[UserPromptPart(content='Yes, it is. My parents had one.')]), + ModelRequest(parts=[UserPromptPart(content='Yes, it is. My parents had one.')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Cool. Was it fast?')]), ] @@ -4473,7 +4474,9 @@ async def dynamic_func() -> str: result1 = agent.run_sync('Hello') # Create ModelRequest with non-dynamic SystemPromptPart (no dynamic_ref) - manual_request = ModelRequest(parts=[SystemPromptPart(content='Static'), UserPromptPart(content='Manual')]) + manual_request = ModelRequest( + parts=[SystemPromptPart(content='Static'), UserPromptPart(content='Manual')], timestamp=IsDatetime() + ) # Mix dynamic and non-dynamic messages to trigger branch coverage result2 = agent.run_sync('Second call', message_history=result1.all_messages() + [manual_request]) @@ -5014,7 +5017,9 @@ def test_instructions_with_message_history(): agent = Agent('test', instructions='You are a helpful assistant.') result = agent.run_sync( 'Hello', - message_history=[ModelRequest(parts=[SystemPromptPart(content='You are a helpful assistant')])], + message_history=[ + ModelRequest(parts=[SystemPromptPart(content='You are a helpful assistant')], timestamp=IsDatetime()) + ], ) assert result.all_messages() == snapshot( [ @@ -6390,7 +6395,9 @@ def create_file(path: str, content: str) -> str: async def test_run_with_deferred_tool_results_errors(): agent = Agent('test') - message_history: list[ModelMessage] = [ModelRequest(parts=[UserPromptPart(content=['Hello', 'world'])])] + message_history: list[ModelMessage] = [ + ModelRequest(parts=[UserPromptPart(content=['Hello', 'world'])], timestamp=IsDatetime()) + ] with pytest.raises( UserError, @@ -6403,7 +6410,7 @@ async def test_run_with_deferred_tool_results_errors(): ) message_history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='Hello')]), + ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Hello to you too!')]), ] @@ -6418,7 +6425,7 @@ async def test_run_with_deferred_tool_results_errors(): ) message_history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='Hello')]), + ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), ModelResponse(parts=[ToolCallPart(tool_name='say_hello')]), ] @@ -6440,7 +6447,7 @@ async def test_run_with_deferred_tool_results_errors(): ) message_history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='Hello')]), + ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), ModelResponse( parts=[ ToolCallPart(tool_name='run_me', tool_call_id='run_me'), @@ -6452,7 +6459,8 @@ async def test_run_with_deferred_tool_results_errors(): parts=[ ToolReturnPart(tool_name='run_me', tool_call_id='run_me', content='Success'), RetryPromptPart(tool_name='run_me_too', tool_call_id='run_me_too', content='Failure'), - ] + ], + timestamp=IsDatetime(), ), ] @@ -6600,7 +6608,7 @@ def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: ) history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='Hello...')]), + ModelRequest(parts=[UserPromptPart(content='Hello...')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='...world!')]), ModelResponse(parts=[TextPart(content='Anything else I can help with?')]), ] @@ -7124,7 +7132,7 @@ def delete_file() -> None: print('File deleted.') # pragma: no cover messages = [ - ModelRequest(parts=[UserPromptPart(content='Hello')]), + ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), ModelResponse(parts=[ToolCallPart(tool_name='delete_file')]), ] @@ -7144,7 +7152,7 @@ def llm(messages: list[ModelMessage], _info: AgentInfo) -> ModelResponse: async with agent.iter( message_history=[ - ModelRequest(parts=[UserPromptPart(content='Hello')]), + ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), ], ) as run: async for _ in run: diff --git a/tests/test_history_processor.py b/tests/test_history_processor.py index 0dd573c256..c75e53ef26 100644 --- a/tests/test_history_processor.py +++ b/tests/test_history_processor.py @@ -53,7 +53,7 @@ def no_op_history_processor(messages: list[ModelMessage]) -> list[ModelMessage]: agent = Agent(function_model, history_processors=[no_op_history_processor]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Previous question')]), + ModelRequest(parts=[UserPromptPart(content='Previous question')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Previous answer')]), ] @@ -104,14 +104,16 @@ async def test_history_processor_run_replaces_message_history( def process_previous_answers(messages: list[ModelMessage]) -> list[ModelMessage]: # Keep the last message (last question) and add a new system prompt - return messages[-1:] + [ModelRequest(parts=[SystemPromptPart(content='Processed answer')])] + return messages[-1:] + [ + ModelRequest(parts=[SystemPromptPart(content='Processed answer')], timestamp=IsDatetime()) + ] agent = Agent(function_model, history_processors=[process_previous_answers]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Question 1')]), + ModelRequest(parts=[UserPromptPart(content='Question 1')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Answer 1')]), - ModelRequest(parts=[UserPromptPart(content='Question 2')]), + ModelRequest(parts=[UserPromptPart(content='Question 2')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Answer 2')]), ] @@ -165,14 +167,16 @@ async def test_history_processor_streaming_replaces_message_history( def process_previous_answers(messages: list[ModelMessage]) -> list[ModelMessage]: # Keep the last message (last question) and add a new system prompt - return messages[-1:] + [ModelRequest(parts=[SystemPromptPart(content='Processed answer')])] + return messages[-1:] + [ + ModelRequest(parts=[SystemPromptPart(content='Processed answer')], timestamp=IsDatetime()) + ] agent = Agent(function_model, history_processors=[process_previous_answers]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Question 1')]), + ModelRequest(parts=[UserPromptPart(content='Question 1')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Answer 1')]), - ModelRequest(parts=[UserPromptPart(content='Question 2')]), + ModelRequest(parts=[UserPromptPart(content='Question 2')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Answer 2')]), ] @@ -233,7 +237,7 @@ def capture_messages_processor(messages: list[ModelMessage]) -> list[ModelMessag agent = Agent(function_model, history_processors=[capture_messages_processor]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Previous question')]), + ModelRequest(parts=[UserPromptPart(content='Previous question')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Previous answer')]), # This should be filtered out ] @@ -292,7 +296,7 @@ def first_processor(messages: list[ModelMessage]) -> list[ModelMessage]: for part in msg.parts: if isinstance(part, UserPromptPart): # pragma: no branch new_parts.append(UserPromptPart(content=f'[FIRST] {part.content}')) - processed.append(ModelRequest(parts=new_parts)) + processed.append(ModelRequest(parts=new_parts, timestamp=IsDatetime())) else: processed.append(msg) return processed @@ -306,7 +310,7 @@ def second_processor(messages: list[ModelMessage]) -> list[ModelMessage]: for part in msg.parts: if isinstance(part, UserPromptPart): # pragma: no branch new_parts.append(UserPromptPart(content=f'[SECOND] {part.content}')) - processed.append(ModelRequest(parts=new_parts)) + processed.append(ModelRequest(parts=new_parts, timestamp=IsDatetime())) else: processed.append(msg) return processed @@ -314,7 +318,7 @@ def second_processor(messages: list[ModelMessage]) -> list[ModelMessage]: agent = Agent(function_model, history_processors=[first_processor, second_processor]) message_history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='Question')]), + ModelRequest(parts=[UserPromptPart(content='Question')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Answer')]), ] @@ -379,7 +383,7 @@ async def async_processor(messages: list[ModelMessage]) -> list[ModelMessage]: agent = Agent(function_model, history_processors=[async_processor]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Question 1')]), + ModelRequest(parts=[UserPromptPart(content='Question 1')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Answer 1')]), # Should be filtered out ] @@ -443,7 +447,7 @@ async def async_processor(messages: list[ModelMessage]) -> list[ModelMessage]: return [msg for msg in messages if isinstance(msg, ModelRequest)] message_history = [ - ModelRequest(parts=[UserPromptPart(content='Question 1')]), + ModelRequest(parts=[UserPromptPart(content='Question 1')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Answer 1')]), ] @@ -524,7 +528,7 @@ def context_processor(ctx: RunContext[str], messages: list[ModelMessage]) -> lis new_parts.append(UserPromptPart(content=f'{prefix}: {part.content}')) else: new_parts.append(part) # pragma: no cover - processed.append(ModelRequest(parts=new_parts)) + processed.append(ModelRequest(parts=new_parts, timestamp=IsDatetime())) else: processed.append(msg) # pragma: no cover return processed @@ -579,9 +583,9 @@ async def async_context_processor(ctx: RunContext[Any], messages: list[ModelMess return messages[-1:] # Keep only the last message message_history = [ - ModelRequest(parts=[UserPromptPart(content='Question 1')]), + ModelRequest(parts=[UserPromptPart(content='Question 1')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Answer 1')]), - ModelRequest(parts=[UserPromptPart(content='Question 2')]), + ModelRequest(parts=[UserPromptPart(content='Question 2')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Answer 2')]), ] @@ -647,13 +651,13 @@ def context_processor(ctx: RunContext[Any], messages: list[ModelMessage]) -> lis new_parts.append(UserPromptPart(content=f'{prefix}: {part.content}')) else: new_parts.append(part) # pragma: no cover - processed.append(ModelRequest(parts=new_parts)) + processed.append(ModelRequest(parts=new_parts, timestamp=IsDatetime())) else: processed.append(msg) # pragma: no cover return processed message_history = [ - ModelRequest(parts=[UserPromptPart(content='Question 1')]), + ModelRequest(parts=[UserPromptPart(content='Question 1')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Answer 1')]), ] @@ -718,14 +722,14 @@ class Deps: async def test_history_processor_replace_messages(function_model: FunctionModel, received_messages: list[ModelMessage]): history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='Original message')]), + ModelRequest(parts=[UserPromptPart(content='Original message')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Original response')]), - ModelRequest(parts=[UserPromptPart(content='Original followup')]), + ModelRequest(parts=[UserPromptPart(content='Original followup')], timestamp=IsDatetime()), ] def return_new_history(messages: list[ModelMessage]) -> list[ModelMessage]: return [ - ModelRequest(parts=[UserPromptPart(content='Modified message')]), + ModelRequest(parts=[UserPromptPart(content='Modified message')], timestamp=IsDatetime()), ] agent = Agent(function_model, history_processors=[return_new_history]) @@ -802,7 +806,7 @@ def __call__(self, messages: list[ModelMessage]) -> list[ModelMessage]: agent = Agent(function_model, history_processors=[NoOpHistoryProcessor()]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Previous question')]), + ModelRequest(parts=[UserPromptPart(content='Previous question')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Previous answer')]), ] @@ -856,7 +860,7 @@ def __call__(self, _: RunContext, messages: list[ModelMessage]) -> list[ModelMes agent = Agent(function_model, history_processors=[NoOpHistoryProcessorWithCtx()]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Previous question')]), + ModelRequest(parts=[UserPromptPart(content='Previous question')], timestamp=IsDatetime()), ModelResponse(parts=[TextPart(content='Previous answer')]), ] diff --git a/tests/test_logfire.py b/tests/test_logfire.py index b33e8702e0..397cf05d61 100644 --- a/tests/test_logfire.py +++ b/tests/test_logfire.py @@ -22,7 +22,7 @@ from pydantic_ai.toolsets.function import FunctionToolset from pydantic_ai.toolsets.wrapper import WrapperToolset -from .conftest import IsStr +from .conftest import IsDatetime, IsStr try: import logfire @@ -2740,7 +2740,11 @@ def instructions(ctx: RunContext[None]): result = my_agent.run_sync( 'Hello', message_history=[ - ModelRequest(parts=[UserPromptPart(content='Hi')], instructions='Instructions from a previous agent run'), + ModelRequest( + parts=[UserPromptPart(content='Hi')], + instructions='Instructions from a previous agent run', + timestamp=IsDatetime(), + ), ModelResponse(parts=[TextPart(content='Hello')]), ], output_type=MyOutput, diff --git a/tests/test_messages.py b/tests/test_messages.py index e5ae19ab9f..9fac7f83ce 100644 --- a/tests/test_messages.py +++ b/tests/test_messages.py @@ -533,6 +533,7 @@ def test_model_messages_type_adapter_preserves_run_id(): parts=[UserPromptPart(content='Hi there', timestamp=datetime.now(tz=timezone.utc))], run_id='run-123', metadata={'key': 'value'}, + timestamp=IsDatetime(), ), ModelResponse(parts=[TextPart(content='Hello!')], run_id='run-123', metadata={'key': 'value'}), ] diff --git a/tests/test_prefect.py b/tests/test_prefect.py index b1c18b9803..ec27c4a86a 100644 --- a/tests/test_prefect.py +++ b/tests/test_prefect.py @@ -68,7 +68,7 @@ from inline_snapshot import snapshot -from .conftest import IsStr +from .conftest import IsDatetime, IsStr pytestmark = [ pytest.mark.anyio, @@ -1037,7 +1037,9 @@ async def test_cache_policy_custom(): # First set of messages messages1 = [ - ModelRequest(parts=[UserPromptPart(content='What is the capital of France?', timestamp=time1)]), + ModelRequest( + parts=[UserPromptPart(content='What is the capital of France?', timestamp=time1)], timestamp=IsDatetime() + ), ModelResponse( parts=[TextPart(content='The capital of France is Paris.')], usage=RequestUsage(input_tokens=10, output_tokens=10), @@ -1048,7 +1050,9 @@ async def test_cache_policy_custom(): # Second set of messages - same content, different timestamps messages2 = [ - ModelRequest(parts=[UserPromptPart(content='What is the capital of France?', timestamp=time2)]), + ModelRequest( + parts=[UserPromptPart(content='What is the capital of France?', timestamp=time2)], timestamp=IsDatetime() + ), ModelResponse( parts=[TextPart(content='The capital of France is Paris.')], usage=RequestUsage(input_tokens=10, output_tokens=10), @@ -1077,7 +1081,9 @@ async def test_cache_policy_custom(): # Also test that different content produces different hashes messages3 = [ - ModelRequest(parts=[UserPromptPart(content='What is the capital of Spain?', timestamp=time1)]), + ModelRequest( + parts=[UserPromptPart(content='What is the capital of Spain?', timestamp=time1)], timestamp=IsDatetime() + ), ModelResponse( parts=[TextPart(content='The capital of Spain is Madrid.')], usage=RequestUsage(input_tokens=10, output_tokens=10), From a98e48020d95553f11f52b1f5fd82e86aa62f10f Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Tue, 2 Dec 2025 17:05:59 -0500 Subject: [PATCH 11/25] ModelRequest.timestamp=None by default for backwards compat --- pydantic_ai_slim/pydantic_ai/messages.py | 2 +- tests/models/test_openai_responses.py | 160 ++++++++++------------- tests/test_agent.py | 59 ++++----- tests/test_history_processor.py | 126 +++++++----------- tests/test_messages.py | 2 - 5 files changed, 139 insertions(+), 210 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/messages.py b/pydantic_ai_slim/pydantic_ai/messages.py index 480622446b..da63d436fe 100644 --- a/pydantic_ai_slim/pydantic_ai/messages.py +++ b/pydantic_ai_slim/pydantic_ai/messages.py @@ -1001,7 +1001,7 @@ class ModelRequest: _: KW_ONLY - timestamp: datetime + timestamp: datetime | None = None """The timestamp when the request was sent to the model.""" instructions: str | None = None diff --git a/tests/models/test_openai_responses.py b/tests/models/test_openai_responses.py index b38426f17a..c12ea27d01 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -51,7 +51,7 @@ from pydantic_ai.tools import ToolDefinition from pydantic_ai.usage import RequestUsage, RunUsage -from ..conftest import IsBytes, IsDatetime, IsStr, TestEnv, try_import +from ..conftest import IsBytes, IsDatetime, IsNow, IsStr, TestEnv, try_import from .mock_openai import MockOpenAIResponses, get_mock_responses_kwargs, response_message with try_import() as imports_successful: @@ -287,7 +287,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -333,7 +333,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsDatetime(), ), ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -385,7 +385,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -426,7 +426,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -584,7 +584,7 @@ async def test_openai_responses_model_builtin_tools_web_search(allow_model_reque timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -752,7 +752,7 @@ async def test_openai_responses_model_instructions(allow_model_requests: None, o [ ModelRequest( parts=[UserPromptPart(content='What is the capital of France?', timestamp=IsDatetime())], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -794,7 +794,7 @@ async def test_openai_responses_model_web_search_tool(allow_model_requests: None timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -859,7 +859,7 @@ async def test_openai_responses_model_web_search_tool(allow_model_requests: None timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -934,7 +934,7 @@ async def test_openai_responses_model_web_search_tool_with_user_location( timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -1010,7 +1010,7 @@ async def test_openai_responses_model_web_search_tool_with_invalid_region( timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -1093,7 +1093,7 @@ async def test_openai_responses_model_web_search_tool_stream(allow_model_request timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -1317,7 +1317,7 @@ async def test_openai_responses_model_web_search_tool_stream(allow_model_request timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -1462,7 +1462,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1496,7 +1496,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1530,7 +1530,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1562,7 +1562,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1596,7 +1596,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1651,7 +1651,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1685,7 +1685,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1742,7 +1742,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1776,7 +1776,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1829,7 +1829,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1863,7 +1863,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1920,7 +1920,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1954,7 +1954,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2016,7 +2016,6 @@ async def test_openai_previous_response_id_auto_mode(allow_model_requests: None, content='The first secret key is sesame', ), ], - timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -2032,7 +2031,6 @@ async def test_openai_previous_response_id_auto_mode(allow_model_requests: None, content='The second secret key is olives', ), ], - timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -2060,7 +2058,6 @@ async def test_openai_previous_response_id_mixed_model_history(allow_model_reque content='The first secret key is sesame', ), ], - timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -2076,7 +2073,6 @@ async def test_openai_previous_response_id_mixed_model_history(allow_model_reque content='what is the first secret key?', ), ], - timestamp=IsDatetime(), ), ] @@ -2085,10 +2081,7 @@ async def test_openai_previous_response_id_mixed_model_history(allow_model_reque assert not previous_response_id assert messages == snapshot( [ - ModelRequest( - parts=[UserPromptPart(content='The first secret key is sesame', timestamp=IsDatetime())], - timestamp=IsDatetime(), - ), + ModelRequest(parts=[UserPromptPart(content='The first secret key is sesame', timestamp=IsDatetime())]), ModelResponse( parts=[TextPart(content='Open sesame! What would you like to unlock?')], usage=RequestUsage(), @@ -2097,10 +2090,7 @@ async def test_openai_previous_response_id_mixed_model_history(allow_model_reque provider_name='anthropic', provider_response_id='msg_01XUQuedGz9gusk4xZm4gWJj', ), - ModelRequest( - parts=[UserPromptPart(content='what is the first secret key?', timestamp=IsDatetime())], - timestamp=IsDatetime(), - ), + ModelRequest(parts=[UserPromptPart(content='what is the first secret key?', timestamp=IsDatetime())]), ] ) @@ -2114,7 +2104,6 @@ async def test_openai_previous_response_id_same_model_history(allow_model_reques content='The first secret key is sesame', ), ], - timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -2130,7 +2119,6 @@ async def test_openai_previous_response_id_same_model_history(allow_model_reques content='The second secret key is olives', ), ], - timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -2146,7 +2134,6 @@ async def test_openai_previous_response_id_same_model_history(allow_model_reques content='what is the first secret key?', ), ], - timestamp=IsDatetime(), ), ] @@ -2155,10 +2142,7 @@ async def test_openai_previous_response_id_same_model_history(allow_model_reques assert previous_response_id == 'resp_68b9bda81f5c8197a5a51a20a9f4150a000497db2a4c777b' assert messages == snapshot( [ - ModelRequest( - parts=[UserPromptPart(content='what is the first secret key?', timestamp=IsDatetime())], - timestamp=IsDatetime(), - ), + ModelRequest(parts=[UserPromptPart(content='what is the first secret key?', timestamp=IsDatetime())]), ] ) @@ -2191,7 +2175,7 @@ async def test_openai_responses_usage_without_tokens_details(allow_model_request timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2223,7 +2207,7 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, [ ModelRequest( parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2273,7 +2257,7 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2330,7 +2314,7 @@ async def test_openai_responses_thinking_part_from_other_model( timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2382,7 +2366,7 @@ async def test_openai_responses_thinking_part_from_other_model( timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2440,7 +2424,7 @@ async def test_openai_responses_thinking_part_iter(allow_model_requests: None, o timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2522,7 +2506,7 @@ def update_plan(plan: str) -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions="You are a helpful assistant that uses planning. You MUST use the update_plan tool and continually update it as you make progress against the user's prompt", run_id=IsStr(), ), @@ -2567,7 +2551,7 @@ def update_plan(plan: str) -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions="You are a helpful assistant that uses planning. You MUST use the update_plan tool and continually update it as you make progress against the user's prompt", run_id=IsStr(), ), @@ -2624,7 +2608,7 @@ async def test_openai_responses_thinking_without_summary(allow_model_requests: N timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2700,7 +2684,7 @@ async def test_openai_responses_thinking_with_multiple_summaries(allow_model_req timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2768,7 +2752,7 @@ async def test_openai_responses_thinking_with_modified_history(allow_model_reque timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2826,7 +2810,7 @@ async def test_openai_responses_thinking_with_modified_history(allow_model_reque timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2879,7 +2863,7 @@ async def test_openai_responses_thinking_with_code_execution_tool(allow_model_re timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2955,7 +2939,7 @@ async def test_openai_responses_thinking_with_code_execution_tool(allow_model_re timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3014,7 +2998,7 @@ async def test_openai_responses_thinking_with_code_execution_tool_stream( timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3839,7 +3823,7 @@ def get_meaning_of_life() -> int: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3873,7 +3857,7 @@ def get_meaning_of_life() -> int: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3958,7 +3942,7 @@ async def test_openai_responses_code_execution_return_image(allow_model_requests timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4058,7 +4042,7 @@ async def test_openai_responses_code_execution_return_image(allow_model_requests timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4240,7 +4224,7 @@ async def test_openai_responses_code_execution_return_image_stream(allow_model_r timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5733,7 +5717,7 @@ async def test_openai_responses_image_generation(allow_model_requests: None, ope timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5810,7 +5794,7 @@ async def test_openai_responses_image_generation(allow_model_requests: None, ope timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5909,7 +5893,7 @@ async def test_openai_responses_image_generation_stream(allow_model_requests: No timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6094,7 +6078,7 @@ async def test_openai_responses_image_generation_tool_without_image_output( timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6156,7 +6140,7 @@ async def test_openai_responses_image_generation_tool_without_image_output( timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6267,7 +6251,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6327,7 +6311,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6367,7 +6351,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6393,7 +6377,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6471,7 +6455,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6555,7 +6539,7 @@ async def get_animal() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6595,7 +6579,7 @@ async def get_animal() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6667,7 +6651,7 @@ async def test_openai_responses_multiple_images(allow_model_requests: None, open timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6775,7 +6759,7 @@ async def test_openai_responses_image_generation_jpeg(allow_model_requests: None timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6846,8 +6830,7 @@ class CityLocation(BaseModel): UserPromptPart( content='What is the largest city in the user country?', ) - ], - timestamp=IsDatetime(), + ] ), ModelResponse( parts=[ @@ -6869,8 +6852,7 @@ class CityLocation(BaseModel): content='Mexico', tool_call_id='call_ZWkVhdUjupo528U9dqgFeRkH|fc_68477f0bb8e4819cba6d781e174d77f8001fd29e2d5573f7', ) - ], - timestamp=IsDatetime(), + ] ), ] @@ -6885,7 +6867,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6925,7 +6907,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6961,7 +6943,7 @@ async def test_openai_responses_model_mcp_server_tool(allow_model_requests: None timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -7110,7 +7092,7 @@ async def test_openai_responses_model_mcp_server_tool(allow_model_requests: None timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -7192,7 +7174,7 @@ async def test_openai_responses_model_mcp_server_tool_stream(allow_model_request timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), @@ -7587,7 +7569,7 @@ async def test_openai_responses_model_mcp_server_tool_with_connector(allow_model parts=[ UserPromptPart(content='What do I have on my Google Calendar for today?', timestamp=IsDatetime()) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), instructions='You are a helpful assistant.', run_id=IsStr(), ), diff --git a/tests/test_agent.py b/tests/test_agent.py index 427ebfa530..afb8c8a4b5 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -2422,7 +2422,6 @@ async def system_prompt(ctx: RunContext) -> str: UserPromptPart(content='How goes it?'), ], instructions='Original instructions', - timestamp=IsDatetime(), ), ] @@ -2480,7 +2479,7 @@ def test_tool() -> str: return 'Test response' message_history = [ - ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Hello')]), ModelResponse(parts=[ToolCallPart(tool_name='test_tool', args='{}', tool_call_id='call_123')]), ] @@ -2494,8 +2493,7 @@ def test_tool() -> str: content='Hello', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[ToolCallPart(tool_name='test_tool', args='{}', tool_call_id='call_123')], @@ -2535,7 +2533,7 @@ def simple_response(_messages: list[ModelMessage], _info: AgentInfo) -> ModelRes agent = Agent(FunctionModel(simple_response)) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Hello')]), ModelResponse(parts=[ToolCallPart(tool_name='test_tool', args='{}', tool_call_id='call_123')]), ] @@ -2553,7 +2551,7 @@ def simple_response(_messages: list[ModelMessage], _info: AgentInfo) -> ModelRes agent = Agent(FunctionModel(simple_response)) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Hello')]), ModelResponse(parts=[TextPart('world')]), ] @@ -2566,8 +2564,7 @@ def simple_response(_messages: list[ModelMessage], _info: AgentInfo) -> ModelRes content='Hello', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[TextPart(content='world')], @@ -2590,15 +2587,15 @@ async def test_message_history_ending_on_model_response_with_instructions(): ) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Hi, my name is James')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Hi, my name is James')]), ModelResponse(parts=[TextPart(content='Nice to meet you, James.')]), - ModelRequest(parts=[UserPromptPart(content='I like cars')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='I like cars')]), ModelResponse(parts=[TextPart(content='I like them too. Sport cars?')]), - ModelRequest(parts=[UserPromptPart(content='No, cars in general.')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='No, cars in general.')]), ModelResponse(parts=[TextPart(content='Awesome. Which one do you like most?')]), - ModelRequest(parts=[UserPromptPart(content='Fiat 126p')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Fiat 126p')]), ModelResponse(parts=[TextPart(content="That's an old one, isn't it?")]), - ModelRequest(parts=[UserPromptPart(content='Yes, it is. My parents had one.')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Yes, it is. My parents had one.')]), ModelResponse(parts=[TextPart(content='Cool. Was it fast?')]), ] @@ -4474,9 +4471,7 @@ async def dynamic_func() -> str: result1 = agent.run_sync('Hello') # Create ModelRequest with non-dynamic SystemPromptPart (no dynamic_ref) - manual_request = ModelRequest( - parts=[SystemPromptPart(content='Static'), UserPromptPart(content='Manual')], timestamp=IsDatetime() - ) + manual_request = ModelRequest(parts=[SystemPromptPart(content='Static'), UserPromptPart(content='Manual')]) # Mix dynamic and non-dynamic messages to trigger branch coverage result2 = agent.run_sync('Second call', message_history=result1.all_messages() + [manual_request]) @@ -5017,15 +5012,12 @@ def test_instructions_with_message_history(): agent = Agent('test', instructions='You are a helpful assistant.') result = agent.run_sync( 'Hello', - message_history=[ - ModelRequest(parts=[SystemPromptPart(content='You are a helpful assistant')], timestamp=IsDatetime()) - ], + message_history=[ModelRequest(parts=[SystemPromptPart(content='You are a helpful assistant')])], ) assert result.all_messages() == snapshot( [ ModelRequest( - parts=[SystemPromptPart(content='You are a helpful assistant', timestamp=IsNow(tz=timezone.utc))], - timestamp=IsNow(tz=timezone.utc), + parts=[SystemPromptPart(content='You are a helpful assistant', timestamp=IsNow(tz=timezone.utc))] ), ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], @@ -6395,9 +6387,7 @@ def create_file(path: str, content: str) -> str: async def test_run_with_deferred_tool_results_errors(): agent = Agent('test') - message_history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content=['Hello', 'world'])], timestamp=IsDatetime()) - ] + message_history: list[ModelMessage] = [ModelRequest(parts=[UserPromptPart(content=['Hello', 'world'])])] with pytest.raises( UserError, @@ -6410,7 +6400,7 @@ async def test_run_with_deferred_tool_results_errors(): ) message_history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Hello')]), ModelResponse(parts=[TextPart(content='Hello to you too!')]), ] @@ -6425,7 +6415,7 @@ async def test_run_with_deferred_tool_results_errors(): ) message_history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Hello')]), ModelResponse(parts=[ToolCallPart(tool_name='say_hello')]), ] @@ -6447,7 +6437,7 @@ async def test_run_with_deferred_tool_results_errors(): ) message_history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Hello')]), ModelResponse( parts=[ ToolCallPart(tool_name='run_me', tool_call_id='run_me'), @@ -6459,8 +6449,7 @@ async def test_run_with_deferred_tool_results_errors(): parts=[ ToolReturnPart(tool_name='run_me', tool_call_id='run_me', content='Success'), RetryPromptPart(tool_name='run_me_too', tool_call_id='run_me_too', content='Failure'), - ], - timestamp=IsDatetime(), + ] ), ] @@ -6608,7 +6597,7 @@ def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: ) history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='Hello...')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Hello...')]), ModelResponse(parts=[TextPart(content='...world!')]), ModelResponse(parts=[TextPart(content='Anything else I can help with?')]), ] @@ -6625,8 +6614,7 @@ def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: content='Hello...', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[TextPart(content='...world!'), TextPart(content='Anything else I can help with?')], @@ -6682,8 +6670,7 @@ def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: content='Hello...', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[TextPart(content='...world!'), TextPart(content='Anything else I can help with?')], @@ -7132,7 +7119,7 @@ def delete_file() -> None: print('File deleted.') # pragma: no cover messages = [ - ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Hello')]), ModelResponse(parts=[ToolCallPart(tool_name='delete_file')]), ] @@ -7152,7 +7139,7 @@ def llm(messages: list[ModelMessage], _info: AgentInfo) -> ModelResponse: async with agent.iter( message_history=[ - ModelRequest(parts=[UserPromptPart(content='Hello')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Hello')]), ], ) as run: async for _ in run: diff --git a/tests/test_history_processor.py b/tests/test_history_processor.py index c75e53ef26..f0402f3d9b 100644 --- a/tests/test_history_processor.py +++ b/tests/test_history_processor.py @@ -53,7 +53,7 @@ def no_op_history_processor(messages: list[ModelMessage]) -> list[ModelMessage]: agent = Agent(function_model, history_processors=[no_op_history_processor]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Previous question')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Previous question')]), ModelResponse(parts=[TextPart(content='Previous answer')]), ] @@ -62,9 +62,7 @@ def no_op_history_processor(messages: list[ModelMessage]) -> list[ModelMessage]: assert received_messages == snapshot( [ - ModelRequest( - parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() - ), + ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), ModelResponse(parts=[TextPart(content='Previous answer')], timestamp=IsDatetime()), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], @@ -76,9 +74,7 @@ def no_op_history_processor(messages: list[ModelMessage]) -> list[ModelMessage]: assert captured_messages == result.all_messages() assert result.all_messages() == snapshot( [ - ModelRequest( - parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() - ), + ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), ModelResponse(parts=[TextPart(content='Previous answer')], timestamp=IsDatetime()), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], @@ -104,16 +100,14 @@ async def test_history_processor_run_replaces_message_history( def process_previous_answers(messages: list[ModelMessage]) -> list[ModelMessage]: # Keep the last message (last question) and add a new system prompt - return messages[-1:] + [ - ModelRequest(parts=[SystemPromptPart(content='Processed answer')], timestamp=IsDatetime()) - ] + return messages[-1:] + [ModelRequest(parts=[SystemPromptPart(content='Processed answer')])] agent = Agent(function_model, history_processors=[process_previous_answers]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Question 1')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Question 1')]), ModelResponse(parts=[TextPart(content='Answer 1')]), - ModelRequest(parts=[UserPromptPart(content='Question 2')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Question 2')]), ModelResponse(parts=[TextPart(content='Answer 2')]), ] @@ -145,9 +139,7 @@ def process_previous_answers(messages: list[ModelMessage]) -> list[ModelMessage] timestamp=IsDatetime(), run_id=IsStr(), ), - ModelRequest( - parts=[SystemPromptPart(content='Processed answer', timestamp=IsDatetime())], timestamp=IsDatetime() - ), + ModelRequest(parts=[SystemPromptPart(content='Processed answer', timestamp=IsDatetime())]), ModelResponse( parts=[TextPart(content='Provider response')], usage=RequestUsage(input_tokens=54, output_tokens=2), @@ -167,16 +159,14 @@ async def test_history_processor_streaming_replaces_message_history( def process_previous_answers(messages: list[ModelMessage]) -> list[ModelMessage]: # Keep the last message (last question) and add a new system prompt - return messages[-1:] + [ - ModelRequest(parts=[SystemPromptPart(content='Processed answer')], timestamp=IsDatetime()) - ] + return messages[-1:] + [ModelRequest(parts=[SystemPromptPart(content='Processed answer')])] agent = Agent(function_model, history_processors=[process_previous_answers]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Question 1')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Question 1')]), ModelResponse(parts=[TextPart(content='Answer 1')]), - ModelRequest(parts=[UserPromptPart(content='Question 2')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Question 2')]), ModelResponse(parts=[TextPart(content='Answer 2')]), ] @@ -210,9 +200,7 @@ def process_previous_answers(messages: list[ModelMessage]) -> list[ModelMessage] timestamp=IsDatetime(), run_id=IsStr(), ), - ModelRequest( - parts=[SystemPromptPart(content='Processed answer', timestamp=IsDatetime())], timestamp=IsDatetime() - ), + ModelRequest(parts=[SystemPromptPart(content='Processed answer', timestamp=IsDatetime())]), ModelResponse( parts=[TextPart(content='hello')], usage=RequestUsage(input_tokens=50, output_tokens=1), @@ -237,7 +225,7 @@ def capture_messages_processor(messages: list[ModelMessage]) -> list[ModelMessag agent = Agent(function_model, history_processors=[capture_messages_processor]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Previous question')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Previous question')]), ModelResponse(parts=[TextPart(content='Previous answer')]), # This should be filtered out ] @@ -264,9 +252,7 @@ def capture_messages_processor(messages: list[ModelMessage]) -> list[ModelMessag assert captured_messages == result.all_messages() assert result.all_messages() == snapshot( [ - ModelRequest( - parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() - ), + ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], timestamp=IsDatetime(), @@ -296,7 +282,7 @@ def first_processor(messages: list[ModelMessage]) -> list[ModelMessage]: for part in msg.parts: if isinstance(part, UserPromptPart): # pragma: no branch new_parts.append(UserPromptPart(content=f'[FIRST] {part.content}')) - processed.append(ModelRequest(parts=new_parts, timestamp=IsDatetime())) + processed.append(ModelRequest(parts=new_parts)) else: processed.append(msg) return processed @@ -310,7 +296,7 @@ def second_processor(messages: list[ModelMessage]) -> list[ModelMessage]: for part in msg.parts: if isinstance(part, UserPromptPart): # pragma: no branch new_parts.append(UserPromptPart(content=f'[SECOND] {part.content}')) - processed.append(ModelRequest(parts=new_parts, timestamp=IsDatetime())) + processed.append(ModelRequest(parts=new_parts)) else: processed.append(msg) return processed @@ -318,7 +304,7 @@ def second_processor(messages: list[ModelMessage]) -> list[ModelMessage]: agent = Agent(function_model, history_processors=[first_processor, second_processor]) message_history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='Question')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Question')]), ModelResponse(parts=[TextPart(content='Answer')]), ] @@ -326,15 +312,9 @@ def second_processor(messages: list[ModelMessage]) -> list[ModelMessage]: result = await agent.run('New question', message_history=message_history) assert received_messages == snapshot( [ - ModelRequest( - parts=[UserPromptPart(content='[SECOND] [FIRST] Question', timestamp=IsDatetime())], - timestamp=IsDatetime(), - ), + ModelRequest(parts=[UserPromptPart(content='[SECOND] [FIRST] Question', timestamp=IsDatetime())]), ModelResponse(parts=[TextPart(content='Answer')], timestamp=IsDatetime()), - ModelRequest( - parts=[UserPromptPart(content='[SECOND] [FIRST] New question', timestamp=IsDatetime())], - timestamp=IsDatetime(), - ), + ModelRequest(parts=[UserPromptPart(content='[SECOND] [FIRST] New question', timestamp=IsDatetime())]), ] ) assert captured_messages == result.all_messages() @@ -346,8 +326,7 @@ def second_processor(messages: list[ModelMessage]) -> list[ModelMessage]: content='[SECOND] [FIRST] Question', timestamp=IsDatetime(), ) - ], - timestamp=IsDatetime(), + ] ), ModelResponse( parts=[TextPart(content='Answer')], @@ -359,8 +338,7 @@ def second_processor(messages: list[ModelMessage]) -> list[ModelMessage]: content='[SECOND] [FIRST] New question', timestamp=IsDatetime(), ) - ], - timestamp=IsDatetime(), + ] ), ModelResponse( parts=[TextPart(content='Provider response')], @@ -383,7 +361,7 @@ async def async_processor(messages: list[ModelMessage]) -> list[ModelMessage]: agent = Agent(function_model, history_processors=[async_processor]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Question 1')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Question 1')]), ModelResponse(parts=[TextPart(content='Answer 1')]), # Should be filtered out ] @@ -415,8 +393,7 @@ async def async_processor(messages: list[ModelMessage]) -> list[ModelMessage]: content='Question 1', timestamp=IsDatetime(), ) - ], - timestamp=IsDatetime(), + ] ), ModelRequest( parts=[ @@ -447,7 +424,7 @@ async def async_processor(messages: list[ModelMessage]) -> list[ModelMessage]: return [msg for msg in messages if isinstance(msg, ModelRequest)] message_history = [ - ModelRequest(parts=[UserPromptPart(content='Question 1')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Question 1')]), ModelResponse(parts=[TextPart(content='Answer 1')]), ] @@ -488,8 +465,7 @@ async def async_processor(messages: list[ModelMessage]) -> list[ModelMessage]: content='Question 1', timestamp=IsDatetime(), ) - ], - timestamp=IsDatetime(), + ] ), ModelRequest( parts=[ @@ -528,7 +504,7 @@ def context_processor(ctx: RunContext[str], messages: list[ModelMessage]) -> lis new_parts.append(UserPromptPart(content=f'{prefix}: {part.content}')) else: new_parts.append(part) # pragma: no cover - processed.append(ModelRequest(parts=new_parts, timestamp=IsDatetime())) + processed.append(ModelRequest(parts=new_parts)) else: processed.append(msg) # pragma: no cover return processed @@ -545,8 +521,7 @@ def context_processor(ctx: RunContext[str], messages: list[ModelMessage]) -> lis content='PREFIX: test', timestamp=IsDatetime(), ) - ], - timestamp=IsDatetime(), + ] ) ] ) @@ -559,8 +534,7 @@ def context_processor(ctx: RunContext[str], messages: list[ModelMessage]) -> lis content='PREFIX: test', timestamp=IsDatetime(), ) - ], - timestamp=IsDatetime(), + ] ), ModelResponse( parts=[TextPart(content='Provider response')], @@ -583,9 +557,9 @@ async def async_context_processor(ctx: RunContext[Any], messages: list[ModelMess return messages[-1:] # Keep only the last message message_history = [ - ModelRequest(parts=[UserPromptPart(content='Question 1')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Question 1')]), ModelResponse(parts=[TextPart(content='Answer 1')]), - ModelRequest(parts=[UserPromptPart(content='Question 2')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Question 2')]), ModelResponse(parts=[TextPart(content='Answer 2')]), ] @@ -651,13 +625,13 @@ def context_processor(ctx: RunContext[Any], messages: list[ModelMessage]) -> lis new_parts.append(UserPromptPart(content=f'{prefix}: {part.content}')) else: new_parts.append(part) # pragma: no cover - processed.append(ModelRequest(parts=new_parts, timestamp=IsDatetime())) + processed.append(ModelRequest(parts=new_parts)) else: processed.append(msg) # pragma: no cover return processed message_history = [ - ModelRequest(parts=[UserPromptPart(content='Question 1')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Question 1')]), ModelResponse(parts=[TextPart(content='Answer 1')]), ] @@ -696,8 +670,7 @@ class Deps: content='TEST: Question 1', timestamp=IsDatetime(), ) - ], - timestamp=IsDatetime(), + ] ), ModelRequest( parts=[ @@ -705,8 +678,7 @@ class Deps: content='TEST: Question 2', timestamp=IsDatetime(), ) - ], - timestamp=IsDatetime(), + ] ), ModelResponse( parts=[TextPart(content='Provider response')], @@ -722,14 +694,14 @@ class Deps: async def test_history_processor_replace_messages(function_model: FunctionModel, received_messages: list[ModelMessage]): history: list[ModelMessage] = [ - ModelRequest(parts=[UserPromptPart(content='Original message')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Original message')]), ModelResponse(parts=[TextPart(content='Original response')]), - ModelRequest(parts=[UserPromptPart(content='Original followup')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Original followup')]), ] def return_new_history(messages: list[ModelMessage]) -> list[ModelMessage]: return [ - ModelRequest(parts=[UserPromptPart(content='Modified message')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Modified message')]), ] agent = Agent(function_model, history_processors=[return_new_history]) @@ -745,8 +717,7 @@ def return_new_history(messages: list[ModelMessage]) -> list[ModelMessage]: content='Modified message', timestamp=IsDatetime(), ) - ], - timestamp=IsDatetime(), + ] ) ] ) @@ -759,8 +730,7 @@ def return_new_history(messages: list[ModelMessage]) -> list[ModelMessage]: content='Modified message', timestamp=IsDatetime(), ) - ], - timestamp=IsDatetime(), + ] ), ModelResponse( parts=[TextPart(content='Provider response')], @@ -806,7 +776,7 @@ def __call__(self, messages: list[ModelMessage]) -> list[ModelMessage]: agent = Agent(function_model, history_processors=[NoOpHistoryProcessor()]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Previous question')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Previous question')]), ModelResponse(parts=[TextPart(content='Previous answer')]), ] @@ -815,9 +785,7 @@ def __call__(self, messages: list[ModelMessage]) -> list[ModelMessage]: assert received_messages == snapshot( [ - ModelRequest( - parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() - ), + ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), ModelResponse(parts=[TextPart(content='Previous answer')], timestamp=IsDatetime()), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], @@ -829,9 +797,7 @@ def __call__(self, messages: list[ModelMessage]) -> list[ModelMessage]: assert captured_messages == result.all_messages() assert result.all_messages() == snapshot( [ - ModelRequest( - parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() - ), + ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), ModelResponse(parts=[TextPart(content='Previous answer')], timestamp=IsDatetime()), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], @@ -860,7 +826,7 @@ def __call__(self, _: RunContext, messages: list[ModelMessage]) -> list[ModelMes agent = Agent(function_model, history_processors=[NoOpHistoryProcessorWithCtx()]) message_history = [ - ModelRequest(parts=[UserPromptPart(content='Previous question')], timestamp=IsDatetime()), + ModelRequest(parts=[UserPromptPart(content='Previous question')]), ModelResponse(parts=[TextPart(content='Previous answer')]), ] @@ -869,9 +835,7 @@ def __call__(self, _: RunContext, messages: list[ModelMessage]) -> list[ModelMes assert received_messages == snapshot( [ - ModelRequest( - parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() - ), + ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), ModelResponse(parts=[TextPart(content='Previous answer')], timestamp=IsDatetime()), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], @@ -883,9 +847,7 @@ def __call__(self, _: RunContext, messages: list[ModelMessage]) -> list[ModelMes assert captured_messages == result.all_messages() assert result.all_messages() == snapshot( [ - ModelRequest( - parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())], timestamp=IsDatetime() - ), + ModelRequest(parts=[UserPromptPart(content='Previous question', timestamp=IsDatetime())]), ModelResponse(parts=[TextPart(content='Previous answer')], timestamp=IsDatetime()), ModelRequest( parts=[UserPromptPart(content='New question', timestamp=IsDatetime())], diff --git a/tests/test_messages.py b/tests/test_messages.py index 9fac7f83ce..3e0868c2fa 100644 --- a/tests/test_messages.py +++ b/tests/test_messages.py @@ -450,7 +450,6 @@ def test_pre_usage_refactor_messages_deserializable(): timestamp=IsNow(tz=timezone.utc), ) ], - timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[TextPart(content='Mexico City.')], @@ -533,7 +532,6 @@ def test_model_messages_type_adapter_preserves_run_id(): parts=[UserPromptPart(content='Hi there', timestamp=datetime.now(tz=timezone.utc))], run_id='run-123', metadata={'key': 'value'}, - timestamp=IsDatetime(), ), ModelResponse(parts=[TextPart(content='Hello!')], run_id='run-123', metadata={'key': 'value'}), ] From 800a1f6bd8b972c3e4849323f525901b3462f9c0 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Thu, 4 Dec 2025 14:15:52 -0500 Subject: [PATCH 12/25] timestamp's set only in one place --- pydantic_ai_slim/pydantic_ai/_agent_graph.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/_agent_graph.py b/pydantic_ai_slim/pydantic_ai/_agent_graph.py index b4f1954c68..80b9276970 100644 --- a/pydantic_ai_slim/pydantic_ai/_agent_graph.py +++ b/pydantic_ai_slim/pydantic_ai/_agent_graph.py @@ -225,7 +225,7 @@ async def run( # noqa: C901 if isinstance(last_message, _messages.ModelRequest) and self.user_prompt is None: # Drop last message from history and reuse its parts messages.pop() - next_message = _messages.ModelRequest(parts=last_message.parts, timestamp=now_utc()) + next_message = _messages.ModelRequest(parts=last_message.parts) # Extract `UserPromptPart` content from the popped message and add to `ctx.deps.prompt` user_prompt_parts = [part for part in last_message.parts if isinstance(part, _messages.UserPromptPart)] @@ -269,7 +269,7 @@ async def run( # noqa: C901 if self.user_prompt is not None: parts.append(_messages.UserPromptPart(self.user_prompt)) - next_message = _messages.ModelRequest(parts=parts, timestamp=now_utc()) + next_message = _messages.ModelRequest(parts=parts) next_message.instructions = instructions @@ -637,7 +637,7 @@ async def _run_stream() -> AsyncIterator[_messages.HandleResponseEvent]: # noqa run_context = build_run_context(ctx) instructions = await ctx.deps.get_instructions(run_context) self._next_node = ModelRequestNode[DepsT, NodeRunEndT]( - _messages.ModelRequest(parts=[], instructions=instructions, timestamp=now_utc()) + _messages.ModelRequest(parts=[], instructions=instructions) ) return @@ -705,7 +705,7 @@ async def _run_stream() -> AsyncIterator[_messages.HandleResponseEvent]: # noqa run_context = build_run_context(ctx) instructions = await ctx.deps.get_instructions(run_context) self._next_node = ModelRequestNode[DepsT, NodeRunEndT]( - _messages.ModelRequest(parts=[e.tool_retry], instructions=instructions, timestamp=now_utc()) + _messages.ModelRequest(parts=[e.tool_retry], instructions=instructions) ) self._events_iterator = _run_stream() @@ -747,7 +747,7 @@ async def _handle_tool_calls( instructions = await ctx.deps.get_instructions(run_context) self._next_node = ModelRequestNode[DepsT, NodeRunEndT]( - _messages.ModelRequest(parts=output_parts, instructions=instructions, timestamp=now_utc()) + _messages.ModelRequest(parts=output_parts, instructions=instructions) ) async def _handle_text_response( @@ -1359,7 +1359,9 @@ def _clean_message_history(messages: list[_messages.ModelMessage]) -> list[_mess key=lambda x: 0 if isinstance(x, _messages.ToolReturnPart | _messages.RetryPromptPart) else 1 ) merged_message = _messages.ModelRequest( - parts=parts, instructions=last_message.instructions or message.instructions, timestamp=now_utc() + parts=parts, + instructions=last_message.instructions or message.instructions, + timestamp=message.timestamp or last_message.timestamp, ) clean_messages[-1] = merged_message else: From 3c83c06a09fec41e2a43e2258934d185e6b3f5fd Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Thu, 4 Dec 2025 15:05:48 -0500 Subject: [PATCH 13/25] make sure last request always has timestamp --- pydantic_ai_slim/pydantic_ai/_agent_graph.py | 8 +++-- tests/test_history_processor.py | 33 ++++++++++++++------ tests/test_vercel_ai.py | 4 +-- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/_agent_graph.py b/pydantic_ai_slim/pydantic_ai/_agent_graph.py index 80b9276970..5a82570759 100644 --- a/pydantic_ai_slim/pydantic_ai/_agent_graph.py +++ b/pydantic_ai_slim/pydantic_ai/_agent_graph.py @@ -447,7 +447,6 @@ async def stream( assert not self._did_stream, 'stream() should only be called once per node' model_settings, model_request_parameters, message_history, run_context = await self._prepare_request(ctx) - self.request.timestamp = now_utc() async with ctx.deps.model.request_stream( message_history, model_settings, model_request_parameters, run_context ) as streamed_response: @@ -480,7 +479,6 @@ async def _make_request( return self._result # pragma: no cover model_settings, model_request_parameters, message_history, _ = await self._prepare_request(ctx) - self.request.timestamp = now_utc() model_response = await ctx.deps.model.request(message_history, model_settings, model_request_parameters) ctx.state.usage.requests += 1 @@ -489,6 +487,7 @@ async def _make_request( async def _prepare_request( self, ctx: GraphRunContext[GraphAgentState, GraphAgentDeps[DepsT, NodeRunEndT]] ) -> tuple[ModelSettings | None, models.ModelRequestParameters, list[_messages.ModelMessage], RunContext[DepsT]]: + self.request.timestamp = now_utc() self.request.run_id = self.request.run_id or ctx.state.run_id ctx.state.message_history.append(self.request) @@ -506,6 +505,11 @@ async def _prepare_request( # Update the new message index to ensure `result.new_messages()` returns the correct messages ctx.deps.new_message_index -= len(original_history) - len(message_history) + # Ensure the last request has a timestamp (history processors may create new ModelRequest objects without one) + last_request = message_history[-1] + if isinstance(last_request, _messages.ModelRequest) and last_request.timestamp is None: + last_request.timestamp = self.request.timestamp + # Merge possible consecutive trailing `ModelRequest`s into one, with tool call parts before user parts, # but don't store it in the message history on state. This is just for the benefit of model classes that want clear user/assistant boundaries. # See `tests/test_tools.py::test_parallel_tool_return_with_deferred` for an example where this is necessary diff --git a/tests/test_history_processor.py b/tests/test_history_processor.py index f0402f3d9b..09dc6f4689 100644 --- a/tests/test_history_processor.py +++ b/tests/test_history_processor.py @@ -139,7 +139,10 @@ def process_previous_answers(messages: list[ModelMessage]) -> list[ModelMessage] timestamp=IsDatetime(), run_id=IsStr(), ), - ModelRequest(parts=[SystemPromptPart(content='Processed answer', timestamp=IsDatetime())]), + ModelRequest( + parts=[SystemPromptPart(content='Processed answer', timestamp=IsDatetime())], + timestamp=IsDatetime(), + ), ModelResponse( parts=[TextPart(content='Provider response')], usage=RequestUsage(input_tokens=54, output_tokens=2), @@ -200,7 +203,10 @@ def process_previous_answers(messages: list[ModelMessage]) -> list[ModelMessage] timestamp=IsDatetime(), run_id=IsStr(), ), - ModelRequest(parts=[SystemPromptPart(content='Processed answer', timestamp=IsDatetime())]), + ModelRequest( + parts=[SystemPromptPart(content='Processed answer', timestamp=IsDatetime())], + timestamp=IsDatetime(), + ), ModelResponse( parts=[TextPart(content='hello')], usage=RequestUsage(input_tokens=50, output_tokens=1), @@ -314,7 +320,10 @@ def second_processor(messages: list[ModelMessage]) -> list[ModelMessage]: [ ModelRequest(parts=[UserPromptPart(content='[SECOND] [FIRST] Question', timestamp=IsDatetime())]), ModelResponse(parts=[TextPart(content='Answer')], timestamp=IsDatetime()), - ModelRequest(parts=[UserPromptPart(content='[SECOND] [FIRST] New question', timestamp=IsDatetime())]), + ModelRequest( + parts=[UserPromptPart(content='[SECOND] [FIRST] New question', timestamp=IsDatetime())], + timestamp=IsDatetime(), + ), ] ) assert captured_messages == result.all_messages() @@ -338,7 +347,8 @@ def second_processor(messages: list[ModelMessage]) -> list[ModelMessage]: content='[SECOND] [FIRST] New question', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[TextPart(content='Provider response')], @@ -521,7 +531,8 @@ def context_processor(ctx: RunContext[str], messages: list[ModelMessage]) -> lis content='PREFIX: test', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ) ] ) @@ -534,7 +545,8 @@ def context_processor(ctx: RunContext[str], messages: list[ModelMessage]) -> lis content='PREFIX: test', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[TextPart(content='Provider response')], @@ -678,7 +690,8 @@ class Deps: content='TEST: Question 2', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[TextPart(content='Provider response')], @@ -717,7 +730,8 @@ def return_new_history(messages: list[ModelMessage]) -> list[ModelMessage]: content='Modified message', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ) ] ) @@ -730,7 +744,8 @@ def return_new_history(messages: list[ModelMessage]) -> list[ModelMessage]: content='Modified message', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[TextPart(content='Provider response')], diff --git a/tests/test_vercel_ai.py b/tests/test_vercel_ai.py index 75914276db..bec755f188 100644 --- a/tests/test_vercel_ai.py +++ b/tests/test_vercel_ai.py @@ -2517,7 +2517,7 @@ def sync_timestamps(original: list[ModelRequest | ModelResponse], new: list[Mode if hasattr(orig_part, 'timestamp') and hasattr(new_part, 'timestamp'): new_part.timestamp = orig_part.timestamp # pyright: ignore[reportAttributeAccessIssue, reportUnknownMemberType] if hasattr(orig_msg, 'timestamp') and hasattr(new_msg, 'timestamp'): - new_msg.timestamp = orig_msg.timestamp # pyright: ignore[reportAttributeAccessIssue, reportUnknownMemberType] + new_msg.timestamp = orig_msg.timestamp # pyright: ignore[reportAttributeAccessIssue] # Load back to Pydantic AI format reloaded_messages = VercelAIAdapter.load_messages(ui_messages) @@ -2755,7 +2755,7 @@ async def test_adapter_dump_messages_thinking_with_metadata(): # Sync timestamps for comparison (ModelResponse always has timestamp) for orig_msg, new_msg in zip(original_messages, reloaded_messages): - new_msg.timestamp = orig_msg.timestamp # pyright: ignore[reportAttributeAccessIssue] + new_msg.timestamp = orig_msg.timestamp assert reloaded_messages == original_messages From 220995db2d91b73f1e2fb01d94f6a335c83573c6 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Fri, 5 Dec 2025 11:58:23 -0500 Subject: [PATCH 14/25] fix new tests --- pydantic_ai_slim/pydantic_ai/models/openai.py | 9 ++++----- tests/models/test_mistral.py | 12 ++++++------ tests/models/test_openai.py | 7 ++++++- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/models/openai.py b/pydantic_ai_slim/pydantic_ai/models/openai.py index 6fddc4bd58..d7a2712bba 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -1188,8 +1188,10 @@ def _process_response( # noqa: C901 if isinstance(item, responses.ResponseReasoningItem): signature = item.encrypted_content # Handle raw CoT content from gpt-oss models + provider_details: dict[str, Any] = {} raw_content: list[str] | None = [c.text for c in item.content] if item.content else None - provider_details: dict[str, Any] | None = {'raw_content': raw_content} if raw_content else None + if raw_content: + provider_details['raw_content'] = raw_content if item.summary: for summary in item.summary: @@ -1200,12 +1202,9 @@ def _process_response( # noqa: C901 id=item.id, signature=signature, provider_name=self.system if (signature or provider_details) else None, - provider_details=provider_details, + provider_details=provider_details or None, ) ) - # We only need to store the signature and raw_content once. - signature = None - provider_details = None elif signature or provider_details: items.append( ThinkingPart( diff --git a/tests/models/test_mistral.py b/tests/models/test_mistral.py index 168d6efdfd..0d3a653b07 100644 --- a/tests/models/test_mistral.py +++ b/tests/models/test_mistral.py @@ -2027,9 +2027,9 @@ async def get_image() -> BinaryContent: provider_url='https://api.mistral.ai', provider_details={ 'finish_reason': 'tool_calls', - 'timestamp': datetime(2025, 4, 29, 20, 21, 48, tzinfo=timezone.utc), + 'timestamp': datetime(2025, 11, 28, 2, 19, 58, tzinfo=timezone.utc), }, - provider_response_id='fce6d16a4e5940edb24ae16dd0369947', + provider_response_id='412174432ea945889703eac58b44ae35', finish_reason='tool_call', run_id=IsStr(), ), @@ -2065,9 +2065,9 @@ async def get_image() -> BinaryContent: provider_url='https://api.mistral.ai', provider_details={ 'finish_reason': 'stop', - 'timestamp': datetime(2025, 4, 29, 20, 21, 49, tzinfo=timezone.utc), + 'timestamp': datetime(2025, 11, 28, 2, 20, 5, tzinfo=timezone.utc), }, - provider_response_id='26e7de193646460e8904f8e604a60dc1', + provider_response_id='049b5c7704554d3396e727a95cb6d947', finish_reason='stop', run_id=IsStr(), ), @@ -2504,9 +2504,9 @@ async def test_mistral_model_thinking_part_iter(allow_model_requests: None, mist provider_url='https://api.mistral.ai', provider_details={ 'finish_reason': 'stop', - 'timestamp': datetime(2025, 9, 9, 23, 7, 43, tzinfo=timezone.utc), + 'timestamp': datetime(2025, 11, 28, 2, 19, 53, tzinfo=timezone.utc), }, - provider_response_id='9faf4309c1d743d189f16b29211d8b45', + provider_response_id='9f9d90210f194076abeee223863eaaf0', finish_reason='stop', run_id=IsStr(), ), diff --git a/tests/models/test_openai.py b/tests/models/test_openai.py index 5406a165e7..9e41522f98 100644 --- a/tests/models/test_openai.py +++ b/tests/models/test_openai.py @@ -2246,7 +2246,12 @@ async def test_openai_model_thinking_part(allow_model_requests: None, openai_api signature=IsStr(), provider_name='openai', ), - ThinkingPart(content=IsStr(), id='rs_68c1fa166e9c81979ff56b16882744f1093f57e27128848a'), + ThinkingPart( + content=IsStr(), + id='rs_68c1fa166e9c81979ff56b16882744f1093f57e27128848a', + signature='gAAAAABowfofynE_bcBtlQwnphMqkyKvkV8Sr35i7mAX3iK-nK_d2usOyX9bxTqTs2rO9Q-rWy_925tvvxVDftIty6WSJYgydfLk3_2n4aNnc--vX7aUT5db_qTyH_367MTbp_Qr_Wcu_QkOwTuMfF5wU0RxF5PNqKwg1Owpteut0jDGs0haA6SHMMskH0sezDb9VXSTHaIq2EQuaB2n5nAVi6hy5Z6OCScNnC4aBzSnTbPOFi2qMGf4vZwyGpl-mPZn6_kEtuN0ov7K0_vj3MyT02QHrk7ADk1aWu1GFvQHunYJ8LPV1jqZnwP6ovVI080lTTBXEkwvvjJxSmt2UE-0JJ3rlKDXVEC6U-k6_wL95LbXc0MqrFSO_yLNOnytNnTctYSF6i5mwID994MvNhF_L7zRLllV4uf_XrTSBD_oHmcL8R9E5Po=', + provider_name='openai', + ), TextPart(content=IsStr(), id='msg_68c1fa1ec9448197b5c8f78a90999360093f57e27128848a'), ], usage=RequestUsage(input_tokens=13, output_tokens=1915, details={'reasoning_tokens': 1600}), From 11129f4ec209e3dd56d6c2b0212bf8878c36dee4 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Fri, 5 Dec 2025 12:19:47 -0500 Subject: [PATCH 15/25] fix timestamps --- tests/models/test_openai_responses.py | 190 ++++++++++++++++++++++---- 1 file changed, 163 insertions(+), 27 deletions(-) diff --git a/tests/models/test_openai_responses.py b/tests/models/test_openai_responses.py index c12ea27d01..4e0cd0b28a 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -2218,11 +2218,36 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, signature=IsStr(), provider_name='openai', ), - ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), - ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), - ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), - ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), - ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), + ThinkingPart( + content=IsStr(), + id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de', + signature='gAAAAABoxCyzDT6i7ehEoWDBoDGMZmLcOX8TMbvBssJGa0cA0-7Dy6YfH759wsF0Dn5Auzz8Mp2geHtbVJVxKa-SF4Al-z3lq7gQG29dTf2ecfq_6bkg1gS49MbGEmaLo4FnS6_5oekdntomcOVO4mqwC7JKnCTO5Qyq8-Nm3POi0nOZm6KaEfqrmPHiJttupduQBkiqHIc8_CIfQ9LGqSxXZuAFQ0DbNow-6yya7_5oNOoLdgWti5_n9CENxTYyvG_q-2WAmioZM_rR54rWqmMbxUNNsKJls8xx593rb4u2dEpFJztVeifJNmFnDcYDDHMhvqLdSXJU4z3Yrxg8hgH9w2gD7Ygu2UDsMsiUdp5YGXKx_acJeu81-7H8Yf3XY86woskIv2o2XaegpK496fKkeiUAD8OTGWK0hjJb9KPK3hqTBfRfJzafQbIvnNTwOod3ZPyClgSXTYKsN1E_j3S6G8R0uzyA_NBc47Q-VMIUYf3jBTym3NUTMwiA95qdR1_1N-l4Yy7c9-X3UiRrVpNQ53lNuaUzdYuSq7XGHS_4ZNFwKXuG_dM7U2vhn_2dk2fkuEKZjtBYkVofStR8qlkswIAuEw4mrnt-wjG8cxrAwacoXop0R6NShjmWSrAhgqvAqwY3oR4HCPo_zaHSWjnJcRZ41LkVEcBSvtXqNpez2jYYmUkoGHgr_5gGpHpPo2j2lM0pBmPwPQ3OA8RJLEZYiQtabP7AKzZ32Lvsf35uhLRMZ6hkLtwPKgJ4tuR6E2B7xlZ6C0UoUbuI2Spou5dQsqPd6byXwHa22yViPpcpjeZOgHKK41cnK_tpL1kEe1KtodMW43d4OwHZ4LYqm8B769ob3uWnzGOMSGSrTsvci7gm00P0mwKBCh-XC1xdo448iGC7O_bvfYeBJNGsFObB3KqT7WLy04gc0gP7uWH629g151xRPzILeJUHsM_MwrFbNRqo9KbJFtGP0AQiQkO9lE-0VpWQW6ZyQLg6wByI-pPwakXJiCWxpxQF95NRjGOvwYyoU32ipX9mqEjdjQ-vTDn9vte8wPww0aPtAKqK-k0gkeBZAJYALVZNj6Oh0BUdA2t-XcMxs7Qho0V-LLgUjrmyM2ci71LgxeqO8I7LkOuGYMGYj2rFIGrzMeZOgucDhMyury4ELb50ohyYGjf5sOYavsYUwzK3NQwDZ3kjyHFSzCvgkuRgMLKxmME-4aRW8VbGLyC1f2hDuwxzL-cExk4yMh8TijVsf-bnRhHwmQKiR-SGkhrylfn-WnBQQffAdWpjscP9od0UJSPZrLZTaht7Z_15rMw9RO7vXl6PmcFw8vYciH58zUpU5vgq5_QGNvACSnnQxG8Nc9KmIYxGQyMow_ch1PBUP4yGYXR7Xwg0YiB6bwW5p_bxysCJAWBrp4sazb2Al3055Cfnmq9QXTFwFJo0jfbpqwPySuQ28TAiZah0CbCf_zdpJgz9hqM9HeRWHDwIKiR9OpxH2N8rWLqqRZTyfvRX7BfMF6P1bFVVagwhqljKZfcF7QFztlqKdYSGcsA6jdz1RT7B9CItJyKCnHgTYsFtxOr-7z8lkNNlb3xJAYmwYuSQszTR0nFnP4Inc_Ay8XVdmY-ppo6PMJztYQqZXB9wABGkzfKUl9UAIvjMrqHAw76sw28WTA3xxoVS64CM4YDs028hnVsL6euOe6VVBqpVMbrQ6OVi2FOR-vLbNAVBwbelAhbsqoZNMATg8bqlf3UMwacTkr_R1me2gDFv2BjxbjvlZUApzkl9L-CMnVPEsyb187O20chSrJhsy2tLh8SC_6_XCCnNFub3RAvD0BkNzDVZig_oC3ps_EEaPZgEdtbUb_GqaCFcbeo6X4wY7xkr1gZfTP_NHK8XyElajh_HP8T1fPmTZMh46rtXh5-54th6NQ_3jTjCeOfmLjbQKotLNOhJKlB8vXa2CsO575d2zkP2CAMGy9TU_ztUCfaGFOeFPN_xvz1vBZ7QqA-yA10tOdOm8b3oowPfMbZ2n5mvyLNG-DgUkjPGty5gyvJvyMgoqZao66fyzfLvM28eQMpOOcGAcozDFnW_vkffTU5GmPLUaG6rx74V32RVzaQKuC_nGBF8T_NfJ9NfecUw2uj21vCcUyTiIQb3Are8aZLnfsi4DyY-E7WhNnBoLsKZO1CzurCYKCPi4KYGjTr9og_MQM4frL9nez4teQDdUZnu3TkTqF9jRmeFMpZNLaRydPWCmumrCI7HSwb6PuBmsswxPi5Br_NcjszNq-c3t5_Gj8klCceJjDak7wjMuGYSK1GU34iRlNW7iUYUACE4FApDJciqJcRXE31-S_b7IsZ2xcMU4f0Qf1sWHuKKRiwG-Wx-AhXjDSH_tbhauB0P3JEAFg0eNnsRBwUvrYqzPRKkAJz0AUF_biQ-s3czpmmt77NBxh_IjIfVbfOs8QbHM1bgZqUzhS1f-cFLcrEypLHL49Iuy_qXlut79gr2XBsQ05ZIQvOtzCmjZ32b_P-d8oeGzW65rwq0HovxMWxwR7zHqoZD3KJ__a72HMcwK3-fYZBzjMjxOHlBxdzmy4_xsfUBMWxuXREypfY9cb8uuALpRJCebN4pIocB59ShZgTtApb2GVk2jheXHAMx8-7GAUO_W8mzJlaHtrdJd1QYFME1W-_bhfJkYJW70phqUcvVDjoBGHiiL6TxkYAFwCNUhJsvnIG8Ihm09t8TKmcrPx73MVG-euP6T1ZIVL5FFX4kOqSZW2gKg_cUr6xUhuey3sVNd5Qfl_q3PHNHVif93EpJ6iac1VQ6soW9MwuNpKURX_r6WWDx6kyeTXKmbE_6Boe4jSTq_BKYY_SYoZY8AIOrGmKBV6wemc7hR8ko5yfH5_T4V7rwHSPotueN02Xb7qAgizPUxwxuMvwiQoqo6PEI6V96_iRvTCso0mJ2k-EZ7e77Wo3X4A2EjH1ciljhDA2uQAh5QgGUgVI3QfGiaDFrgeQQOatOd-zqvM1j-WB0ZBpjYFR13O8N2ZqXQQ_AlWOmx60LQI79a-BIZb_UBzkpMpR-bsUlFq_CQv9o4cxGU3M9Orwsck_5a_V2Mlsicz8ThvLz2-MaoQvwnU3Zskde4SyRQlqMYSThRxSc1kUBsDDWgBWNrvpeVDxvLAmc8XVR_xMgCiRcyAvrv9kG3RseYoD--fqyx_YpoAGleoG4jA4FFkvZdE-MEN3CSuML2oOJAsMNgAG1mNzkbeJO53oe6qrL4ZnnYHQyayaxSMpi0FonMibsg6pHn8EZ1vKes2W9ljy02W8lfTxnaXewF5qX9uKTnfHM2s9MSdSasJCLagPDjA5ZtsRcwBMpZ6LgJuT6OZsvYyWONDM2y-BdUMN1iiIvJXaRIG-smszpElaZZimJUSPKhO3klT5LH0mZRWL03AnpauWNRdZNZhWJl7sum2bEulbxe7_Ir0LvN1IxUTbDX4TLTDwPc4vEpouKM278KKxo8idZlo0Sd-Azwu6CAvr0uIs0Vs6SqKWWvyC5B5ZmJwxJ_uEFphVW1WKxUxqhSHadoLF95BtwU23ayhu7GV6ZbpgkS9JBETCsYY1xZ0W_A02jv6SsSX45zEg7wJVgKl_EgWBlCw8QCxNirmpxcYvEbikYIBz1NscUBlLnGNIpGONVzrdtmBOkkikw0Goot8ixXePS0_7Jm1LavQIqhklO2SZ8Ve90UZCf0cO4NioF9S58mYFxQ5M4UAErTkbH6LOpmk9I3OhSUUgDwpYN9FWIc__JoAvfUIqvgxvvU13DUyTjdyWvcJyAd2qN_TqSQRreY2fiieLXTEDsZwMRy3qVKQIXVc8wd3hiztuO45EXMqW6ho3OhXFPiVhXUzzt6YJ4SFO5_yPLDOLQj0t4jOnjdvAOnt0gdiC8VSZaugxZTpQFSDPD-skDmj0CAZ9VUJhWNUnkRK_aiclAf2rouiJ1Ot9APUEtXlHR2ImVQSrepMEHDJz1ijCH6QUnkX1aTYt41RBZiEa09207Ow8X1BtTrhofjxAyLzVhEqg76sNiXHhP7J9QAYhxctefmDgk6ZUHqIeveNDeKKfeXrW2UzlLBl6S3xW1xnHBrHxp6wcjngqih1SG0eqfXWgJ_mEg9lOUrbDttiTJbTE7_XhZ2vfJ7Y626u0J6Iz7mGcPa3nCSgzskbBKQflfE0CqS-N-AjTirwU2_7Lb-ofMmbd-rWludoNtNwzh6BAKFVs66rHa-VrWSwoWR-2mMD1GD8WzsjCN4PvgTo5mOGlltDDkWROl5ibhJ-tLyAeZ4mtK5f_oVModXQtapyXA9GEoktjGtoFqE3BkMwk0i_P542lOJ3fNGI-sPyfaWRQXx56wxy470_0dwy_o3aSvJdetOxOi32BfEqfPN-TBNU3MkX_bt0FTMcXjOltnoGh6bgZI8tZ4RGHof9yBLhqVsW9aQ8LN8amNJg4JCsO75vjpW0nDgOk6cKeadSWjP3fBJ_BEmfFkDgLfGeZ_ILTxpzJ9r7yCGPdFoA1C5a1i4DT-3A0UD15W6cpgdfAYRF0Wt3i4UDopGFpASyM1_TpKBzig_iy8j4yM6qUwSShEQiGDdNohlrS2q0fS03Rk7EJEi9wFLB6GPvm4hqJoCes22TvIN14fjz8udTQXNMVEbanKdhMgckZ3sjmAakOe9APmpTbWJ0GNVXwGoErrwLlaptkA5BIk2ZW3OcRWykaHZBnCgf2dNb6II7Mjjguw6H5_J1oMqJFQqIlFnxK5B4nvDzQ-9-lLIub0QvWlPn3jxTkZXBO2rrhBwUUDlZ0NN6dtl79XwliYz0aOc9gnfKptmei73V0WXP8qrv4v4ISgRCjytAC72Uao_QoB86j0jdNNuJ-HUz4BGCB4k6pr9rkOwdwd0PY5OfJbDO6PxqiXNO6unt6IOaIoKEhs0rxpRA6GzyooaoLrVTYQxaSeJTa8I_pwuILBgUSu99DD7HhbQwrloBN7ststbloZhT8cN6SzQ2nBbU_LxnroDH6GTrHFPruSt-5jY-lj9GEm4AFsRwQrXgcL_VMzPThUdbYDOMouzuACn9xdz2bhKcGF20DlLA06ZdtWQfOeYHWwFbmUR1FToyVsUkH8Y_V0vzEDLxzXnVS_0xumFFUXltD9kp4guS4W-MWAFa7hDRBG701kJNQXZqRkzHKqpLNgAdUggl59qrgqLbFtTtco2jaj3dmuPBQFppJL0Jbms5I6lDayWkpqxURphQ7mHtKuodiEmK-srvX2V-X49zV3W_wjAdKQzIZH7qyYNud9QhOO6kBrzhAueZModu_lcYU6SaKZ_s_jPkHauZ6lB04rihZnkpF-vcRVOARctFnxGLOyLQ5zsMxtZ9HIm_s7sRMNQoKAVSaGbgH60Vp9P4yUaHZvwIOfC0cJOynP0PZ4hL-5vjkMwsfYI8rvoyg7woA7gbff9UCQtZG4W5nNzR_06goA9-G9c1DAA__-DxpDpaM68LfopLNJoendZ5jNUEjAmGQBhvPHce4WISmsxtXXonFbZQUlja5KAw1nrlPs7QnkECMPBnwzCC9dj5_8m6ZOieQn0RJPAL2vd-3wSJ5Hdndz1O6wuJVRjdHFAoGFq-azLkSJsRfimKwzPorGlUaaHd1KXZAtKVAjgRKhBVN5iHRgIMB573yZ-gD7syERLNECujzRQnSZydBPLAejqmLcreLecByKa5M0e_vN5cxjNEraw9hCg5UzCCrIQ06Xn2S50s9l6V5g9c3IuAE0u-7OVLh0CSqV0aKXg9UOl5E_9n1kn6FA7bYfEK9oUWP91X690oVqobM1EZlUoBdA3drz4tNAsp0zCgG9SleiPCzzFURdTGlzDPKvzk5V7EWiSZf5Mx4mLTJtABBRH-ovoSHLuj0L_mtlTTpXBfyHXV0KdljQ3XQAl_CRHr98HbliFTonvLQLfal-vWW7KRX7H0TYYhPFl0v12_IVI9eae5QvmLLxElJuMYnTuvauewwMxjLSovOsxnIKvaTTDBGclEKpXOOY2sDHpamRKxm9lJLi1Cpwz-6GLdUM1_v97xFGyrlJBqDjLap_c2UcDTPU8EcPiBakEVQdkmNBhz7d08PUze28JH226GnIS9_poHQfroLnxo8RNnOJqFgvMa3xb3Gd9lmGVMwvZuZVsELFnXshva46Zouz6QZQ8V7O9mRDPI4B1oG2eGocb_E74G9i4hWISG_CrOiWwWFPaChqfIbLqFJbxTWRpv30iqmD7IpLgr4hMBMj8MujxlI1BqhnhotOfvOksRkCtOmwpofL0l4YGiJ6cCtwD7ALgzLN4_nTVXR6ZaETLZTqpAfx7z7INvRDuzeSsMdFcWTlLPCsA5WrSCKMC_jtUUAyPktcEKJ6QdLNmhwZmE4FUNrUcjSYZim-ZNXrYC3U5SF9WbsbeQ4G0Tz31JF5ls08RRzsCBCQGf-TKz2PR_hMD-QUCFwhgJkw3xqqy0MONTtECZDHLUiiL04IyK-MbWtV9BIMa7B3g-q8plZ_Rwroj83CoMQbJWb9Ofe6RM_87NN1kXoc8muhMHGZkUgmq_WQMayrSiq_L0Pm2YsJOaGOyJ4sHHd_R6-OlJ6zR6W4qU9bmJSZvF58Z6oshhPQToUQXObEB0E78alCmrWNYSrcXuMqyhzVToGiAdyJoQlBrpjCAR8Ra8_wYx-8EWMzJaHXYG908knfMALVUE51f8J0AAjB1JmVwZbehBhxJrwzgJo3gmLgWNBPvItPgq8HZX8oXgM4d3PwlNnUF6IsPMsyHIYFfnggIKTHv3Mz1QDTRHJ-SIIGnEHtHiUZojIQJf3CUG_UNZAlVL-qqj05sjZahdueLVH2bVYe3Xa75AuN5v8hoUdbeQfDY1LcNk4yz4SLnss5owSXvK_0DM9V2y510RrHmBVLx0GAo8TtgpVd7Vle2TzNeUksWkmCbYsgMealTceOPQsuDPQ5Ie_1kBss8qiz727fst9SueE5hjHe9vmB99Y9O8W18a7TwRedJv2M5RbxOVhq89bXUBq0bbfVoJ5l9t-1YL4-YKESmj529Bcy71_yNzXs8yRJvSUOPhG9-z5aWonPQI30QhcJqtHG_vtAQE4kT5oDEpujitzwdbQYtntGemNGQKWNYV6CLpi499KfZ10jdeHSkbRTZFjX5J7mffEwBVBRHbptsizL6fGCdY3KkFNKNEKU_FRcYgPSyrzRe4koB_Q-2g2yvHBYqghqLsmTMcahnki8uBB_H-WawnjX0jJwKvP9_azFkvOzrQUBl0yCuklM8npNEFAjVVS_h-jQ6Fseb-lyvehp63MVFac__nIdrYoVnOi1Yihb0w4A7Xt4QFtxyfCHnp1re9zisS4msZm0dfb3s-VRRFQ8VeXWazEIUtDc6QhBiTVaOIZjCOrAOV-BCDhnKPKaJ2gK5R0QspQes0EMt1jpPhgqX6Bvxsj-SMyyKZBr9mkAo1pMb4eJw6sWWchEhXQGQIArBDezuQFEa8KbOFoZ8mohCSLZO3pANGJaE0iEB9Uk-y0ftAkFEbzf_lUi8VHa7hDCqLCOvc56isd9MfVFkMWEhbiSaUhACAac75qp63Y7VVRZAR46EfrrIHvTbFO7yebBTxgetKZc4umvt68EUWDfGqVluVWealK0t63CgYo3dk_bnaQTWxIP8fpIJjgchJjie8luPDR2ZzzanU_TMK8hdE-5iHokVnSHWCnJ8TOI8qrRk9YUPCQof9B3I9pH-KJjBQmgo2SurVLFv230SUdrgs7n4EzBYu9GNq9ryakhwoQRLbQsN40PZJuXL3YSBm4Uprptq5-e_r-FnLIk_OcMUOCv6Vupn9-pqWLCc-mTpJCUdduz5Ht8Ecb-plOc0owN_dzBDgdlzA3d4UpAk_2PNmeXRv6e_futRtKRaKJwY0q1-7XnxHpn8PqmQ1sBYVkLpEOeETh_FlSXwcK1ie10hcnE1H988srGMRCtwgPiU7gAGZPuiXq5aaaGEklYLxEvaSRkASWrIzoP6yqk_FUk65o1Q4hqDCMJhXNSnxaYNgRunsxbv4e3nevbeuuaYHrjyrhPizillKvwwGfckmOv9Y25BZSUXMwSVK9Ad3XA98NajHK8rVoiTRa1fjfBXUwVoce2JcVhuzk1zR_B3KixTZCJl7TUT6ajt70IQA-EsWfNtxdUrINMgm0ZjJVkG3ccM2MVQ0v85VUDwMEqcF3LRFAY1-6Rt0shEK9H2HSvRC-jHBl6xV7DQM0OEuWRvJAECkbRTPDs-XbZhqUQJRRb6XMDZsqeX9tCS1MLyMZ1IUQlRIj3d1auBzc6ICfraQA-cMcAyxofrnaRwhZGr__gns5coe8-DQ3YzNE776gzwLAg5k5M-3WEGJY-BbRtde7opCZnWZWLK9tezTy9ws-qLiIeOlRUu5xSnfwuy6icNYqvWvAN6FwAz2m8F56m7RrtigY8JKwpSk2Jkz2XknkCdv-yaFl4PIZoeRF_pmLSi5jSyP4-ze0owGzmSX0CIRMqZYSsS7D0d88U0DWFFupGK4Kg_I4TPgjByoRH8hZrOcsKvmavJktXN-beunsA06WH8opv2jya9gZkxgAiFIifJBVgEDM5bfFtvfD6N3QJE9TfcUPNGoFqhvEBYzVgQnj1IPrMWBEjBrhc9iCnCattATNc8LVlYbHZ3514DESdjISCctsU-fnKuLN-W9tOdSYEp4xi3phiLD3TLI679uQtifBlAYAPabNDe8ZiwI20jl5REQX10lHjvnPRK7mLHxt7PkOGAcd3hVH_w2KzrWdpf_-DM36G6Lq4HvBUH4BNk8zewp3qybZu_V5zZ2hALyRv7Ibl6pULmyoscJXJoFzBHGDr8rqnazTAwFTWVCwxCskGHkw5DPDGsm1T7ILIgAPEveVdLmmnOP4rXI_o0RGsi-nQxdavHPt67-YWOFYeNWiy1AlNlra5DvL-hfDfxCNgrvG6BbW8c7xEhoFvlR80wgfwPDckjd3U4RjjiiUfVsvgf9bx6x9-cIzlxwiRBzVMnlTPXOwqAsJ2H1e8-_tKTFjFkZuYpVRFCf5Dy4xFcvP2rHtHXE3G_ZGii_M5ZwlrBkfmVVO19lazSqpe67rPuobutmjt1bK_A8B2plrI01cZ_B9yOMzrVoZJebI_cs2Eam46VWfOFGTMoJwzLWmwmF4jt6elLw17Wlrv7yW6RoFzMVROMfRGksuezBufgDDKgpK_aX4jWJpldlI_pNRTycgieG9xHkWPsslTUPFFQ07yNArqB_9ERbiZv_4ljva8O2U4lSmi_CPocI_Gf899EBvd7QmlGl7ZswYlb-VrfcfHuSg-eV0QUH4KwQDvx2qBxL3ng0bxCBgiNsOFv8Kot9afWjUA4YKpvoHajsai91iOUEJ1KBfd-GGv_l3M9OoZtpnXre5twKtdCfllAuLcmH4HMAW6cPX41sFdFf2wwk4aaTic4f5_TX3-dSk6_epKwdmjjucflHtrFp6c9SJwf_aB7y7XYnoq3DvveOtT8LqPb92mIsSwvkxd0E6CVw2D0kpUsD8t3wWz59IeaSuGdqzS_7DCBsk240J2F0L-bAi1UmwtJySyEH6gGcb2wzuekUpoL1lbk8NvOFhqGMskpzAW31X5KlAIB5fMqYIechq2qgUTX0fbFbbK-WOS5BNuZzQHg5u-x7KCsd4M-i0-JQtTNyHDQ9_6GICe3RAa1au6QMk3bbuEeX6p2rkQNIaoaP4X4cayBr_0yu1Txn9PV28js9BnbryxWauTjYYSz02CGE1kN8STnQ-ebpq3WkorL8QcPw7VJFDRytkwSz_AslMaxmoCzvftC8nxZgEveO027csojiijwJ0gpDZYvyhMgNcPhPaLIEJrVSWkyMnkt7Pu3Y2YotbyxyjnySgVgUhvU4rplk9cHykR-1KIdnyrtAmWD1POJhmmtRF0wbMXWPg2zp4LPvH1LRywS1Si6lgMCGOMXRfOzbm8PYJDeM13j6e5PrX78ZsaM_n1Y3cDfew8Oy5guR6ja2TAzstADnEs9-ieIV6xIgARP4tLLi5JSMSDKlaite-kt4Os6cW6ZPm3O3rUthnWq5vHRByyhVEytS-ALARuaoZdc-yl0RvQp08jXqnqueILKWdaRWXJveMAB4XenxSGeCVffEuAm2HdhC0EVcS3rimTX4FSGFLOD2cUNXoB7ywSDnP5VTZ-hQKp-URDXx3YsCj_nXwyIYC4EIUN34i4YUh-DprUnNfJqW9Ev3sfByzjyNS7W1a1htCgXckmy0XBY6X8bNswm7w1ptgpLU76NGOuu1haWJp-LPwxXgDEkpG2tLQQsCKedet_QiBmarepWVN1j9ZIkDDwQE5hwRNrwRgHyGIXk-mNcXXF1gmr3q68XEt2VEur6grCHA0CN3dy4NRxuoS1P-vaRxLl0Dl9Iy7lIGoZaKP_MdGdiotIZdnxe08sBWUvZGdUMg0gpEAn6CegsiuQbLCqT1KuPoMNLKnh-33zrHA7Jo9SqxZ-xrRpwhj-bTeL4v9WgALcRO22E8vhFrVJZICjEBwUv6rpo584dUhoxWlwC3wNo8VRp08Hkbso018pjErTyQ7Is61euKF_OxAvYmHgyZVb_IaldqIHSelpu7EQaaFtvLJSiA3XOIpD4O-rZeimfmS6tOOYQad2TjTbrO15c6AY1OlCWsWAbUGQ_8NGmAijI39Vfcy1z5DJceiok_1_Ao2jh82tEMflNeI6DVEe01zDeZvTHimGVreOj7P7a8Turi7VbzP1VlxrgAxDWZmkPWRxIzfrFjfdMM21KtCE5M1FAqX9buLWcCO-PYmQEjb3_34_g5jOwywcmJXB2LVw5H1d0LpnoBrZSYi52lQaYM0pUombI4jqfrHuZUemB_uYWMdqogdGtyWr23TJeUeQg8BfxtVzjmyw5lbCwH62GSDbpyjzCv3Fn3WDq0qrjR_Xwmj2B9bJR0SgWZhOZm9ZudUOuq3VEZcuaDNvRtmUGysZWzRGRAp3AxolKhk_gTywGIytH25Hj0L28paw0xjmN8YunkxNVbegg8MnXw5l9G8SXNPhZJYKZ5HqI5XRsbwZgvJvSHy5V_G8Ie9YLVrbpoYkmT0j7ErSHXh4BQeS_zbFJosev3fmnxJIEyTz916SACv0s1ocw80aohgzjK8N8eDz5FJ2JQIBZz8TNSYmfFX_Uv93_ZwR0mOAJ2QkKdv5maUC6JU_SSSmDCqcMwp1u4-AA--Z0rSCXGHWWkdZ4vWhRbxFkCQs1IcuSQn2-OxNBImLxvxmhS8XDBKFfm9t8B6ed4TjupnNn6x0BWG2BtJ0yk7Y2ecj8XMQaiaG4MKRdUd6i6xOz7GwmtSA7ckNZef3_B-XA-vw7kYih6vhIf0sRdDX7IK3GVrsN9LbhmMeswEQJteavZGwDWF-piCpBMJ4LWcwsKI534unKNAPhzVPIiczSD1gM8ykZnxVWZYfX4Gd5TC96tdoQq9Z9e-d7uksaInDQr-NSo9rMPPm2quIe_GUEeqzvRHVDmaJkmP-4CeMGghGHQHozDXavc8os__2len8ZFyVAKnyHfhn6D7eo4aHnPL3J4frq7M6SLDjdvunW9OCmROtmSkXjvFwM09w95KEcroXJBkM7bsA-Z6KU-uTwADINUA4TH3K3Y7R0oRmCBtWzT_mQaIE2fgqbwyI5ZhmjelOG8QZYPCK9OtqYwNw1pHDFeHHM9EcXrux-jfccDUJ4IPdOKGOkPurJx7EJv_Ed0sh1IKaYzNRuvsUJGbVU_xyb1nef-Fic6P38JCrC7EYEzLKdtKNCFTacUn9OO3Ygf9b833fcjfG0LYWZeCINxKp1OeGsOTd6am8kwL9Dwx41BbBRHHxb2Fa_w8oneZ5f5yQmHlKvhJ7Rh6hUEYWDCUOG2njMVe0BeI9H8bxzxeWZI4RCXYa0sbEbCqk30ivJI1pdzYuuyk9cc4qUbsPdIScAcSXk7NqBlS82Lz7kDtFjrRtNOVhrjpjlKV-a9W6-rPB0U2savy6xjp-e7yPL_S1Spt10edRjtxHt-AvX3qh56EJdILHPX1MbxFol5LhH9evz_dw2Pe9gxOTYS6S58qxcxX4Nb-KfXngnxaeJ48SsKN-TKi2TWntVLsjDBLPUO1LXrFw8_ZjijdW9j0SxZkOEbnvI3uJ3jvEVxMxUojlfUh7TvKdR209jBuO2ezWcLt3CKfRG6Ak0FjcugJ8ByMucCG5mGMOB7UyWCTurM4FvTeHHAN20C16LRkZ8VyANz-Oe9YfYFO9lrofS1-3jm8UoZ5AbIjCkOCAdOdVEo8RBOh_P8wOTVaYlURHOfeXniL51czYw3UjyIkMftiVXghc5KAWhwrqOkeTPDa3b4zImVqd00u-fsVl9_-c25qR-K1UaiwEEvF0ZJK1TTjMNerCVNezaycd8KZ8ktdaqQD9bvx3okUSpKFZ_WZtgRg4oOlf7ac1ba0PUyigxms9I-9f6snYfzyefP3elvMXL4KpbcDfDcxEWrwFiQ-xDSHjHLrve-irM1DEbgNY85C4XciSOq_fMVut-s6GulegmFjJYOukwLjpLFrEEaenpEKKQlN0upzQcHmdUm1XPUuOFrevg3IMzIpYoYjpsMHtJPXEhViPcpt2uwwRH6gWGtt9wX1KFlYeES1LfdNYBgBA4myFQwz8TR3EeojBxTwtW_pIX5P_A0byfabD2BCEKDZwmgiLfSA25skSB57d2WllO8GkY0pdKBkprewSBb9rqcrRDIk-wd_hSX5NGSnlUGY2-hU0ng1erQeYamS5pYw-BUVTtka3WdDIK4Xg_-RXXg08hfdruAZT-QNBr4KhSVX1l_W-BACPuXirWu1LH12Fu1LQ7X168GjM3ncmfW1abNU6auYfJoxOYTvditijm4SHidFcLNNOYGTOe5WkNNUMKhfjPI03_ofrwmbC0XZvgrUdRPNLM4ocIb4u9W6_LuDRcxd_pnv061OvmBXLYjVQx_O5sscdftVxVj70DaT1Xt1CI51THYtlr0iA_r-xYFTYEMBvNOdz8mzQOblwbeLqnhFWvkcjBj__0K8brz9WTkKJDmq1JPTkG6h-hjPgAcyL-ayVuWJ0iLlvXObqalnNWZ41zyc5XG2uOX2roF2EMOwjZ4Io5eAnhR5ZkhxBJTm9egvFyZ-sU9ibMw4dglZ-_mESgmo6AF7UKR77czR_c6gaTUOdu_U=', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de', + signature='gAAAAABoxCyzDT6i7ehEoWDBoDGMZmLcOX8TMbvBssJGa0cA0-7Dy6YfH759wsF0Dn5Auzz8Mp2geHtbVJVxKa-SF4Al-z3lq7gQG29dTf2ecfq_6bkg1gS49MbGEmaLo4FnS6_5oekdntomcOVO4mqwC7JKnCTO5Qyq8-Nm3POi0nOZm6KaEfqrmPHiJttupduQBkiqHIc8_CIfQ9LGqSxXZuAFQ0DbNow-6yya7_5oNOoLdgWti5_n9CENxTYyvG_q-2WAmioZM_rR54rWqmMbxUNNsKJls8xx593rb4u2dEpFJztVeifJNmFnDcYDDHMhvqLdSXJU4z3Yrxg8hgH9w2gD7Ygu2UDsMsiUdp5YGXKx_acJeu81-7H8Yf3XY86woskIv2o2XaegpK496fKkeiUAD8OTGWK0hjJb9KPK3hqTBfRfJzafQbIvnNTwOod3ZPyClgSXTYKsN1E_j3S6G8R0uzyA_NBc47Q-VMIUYf3jBTym3NUTMwiA95qdR1_1N-l4Yy7c9-X3UiRrVpNQ53lNuaUzdYuSq7XGHS_4ZNFwKXuG_dM7U2vhn_2dk2fkuEKZjtBYkVofStR8qlkswIAuEw4mrnt-wjG8cxrAwacoXop0R6NShjmWSrAhgqvAqwY3oR4HCPo_zaHSWjnJcRZ41LkVEcBSvtXqNpez2jYYmUkoGHgr_5gGpHpPo2j2lM0pBmPwPQ3OA8RJLEZYiQtabP7AKzZ32Lvsf35uhLRMZ6hkLtwPKgJ4tuR6E2B7xlZ6C0UoUbuI2Spou5dQsqPd6byXwHa22yViPpcpjeZOgHKK41cnK_tpL1kEe1KtodMW43d4OwHZ4LYqm8B769ob3uWnzGOMSGSrTsvci7gm00P0mwKBCh-XC1xdo448iGC7O_bvfYeBJNGsFObB3KqT7WLy04gc0gP7uWH629g151xRPzILeJUHsM_MwrFbNRqo9KbJFtGP0AQiQkO9lE-0VpWQW6ZyQLg6wByI-pPwakXJiCWxpxQF95NRjGOvwYyoU32ipX9mqEjdjQ-vTDn9vte8wPww0aPtAKqK-k0gkeBZAJYALVZNj6Oh0BUdA2t-XcMxs7Qho0V-LLgUjrmyM2ci71LgxeqO8I7LkOuGYMGYj2rFIGrzMeZOgucDhMyury4ELb50ohyYGjf5sOYavsYUwzK3NQwDZ3kjyHFSzCvgkuRgMLKxmME-4aRW8VbGLyC1f2hDuwxzL-cExk4yMh8TijVsf-bnRhHwmQKiR-SGkhrylfn-WnBQQffAdWpjscP9od0UJSPZrLZTaht7Z_15rMw9RO7vXl6PmcFw8vYciH58zUpU5vgq5_QGNvACSnnQxG8Nc9KmIYxGQyMow_ch1PBUP4yGYXR7Xwg0YiB6bwW5p_bxysCJAWBrp4sazb2Al3055Cfnmq9QXTFwFJo0jfbpqwPySuQ28TAiZah0CbCf_zdpJgz9hqM9HeRWHDwIKiR9OpxH2N8rWLqqRZTyfvRX7BfMF6P1bFVVagwhqljKZfcF7QFztlqKdYSGcsA6jdz1RT7B9CItJyKCnHgTYsFtxOr-7z8lkNNlb3xJAYmwYuSQszTR0nFnP4Inc_Ay8XVdmY-ppo6PMJztYQqZXB9wABGkzfKUl9UAIvjMrqHAw76sw28WTA3xxoVS64CM4YDs028hnVsL6euOe6VVBqpVMbrQ6OVi2FOR-vLbNAVBwbelAhbsqoZNMATg8bqlf3UMwacTkr_R1me2gDFv2BjxbjvlZUApzkl9L-CMnVPEsyb187O20chSrJhsy2tLh8SC_6_XCCnNFub3RAvD0BkNzDVZig_oC3ps_EEaPZgEdtbUb_GqaCFcbeo6X4wY7xkr1gZfTP_NHK8XyElajh_HP8T1fPmTZMh46rtXh5-54th6NQ_3jTjCeOfmLjbQKotLNOhJKlB8vXa2CsO575d2zkP2CAMGy9TU_ztUCfaGFOeFPN_xvz1vBZ7QqA-yA10tOdOm8b3oowPfMbZ2n5mvyLNG-DgUkjPGty5gyvJvyMgoqZao66fyzfLvM28eQMpOOcGAcozDFnW_vkffTU5GmPLUaG6rx74V32RVzaQKuC_nGBF8T_NfJ9NfecUw2uj21vCcUyTiIQb3Are8aZLnfsi4DyY-E7WhNnBoLsKZO1CzurCYKCPi4KYGjTr9og_MQM4frL9nez4teQDdUZnu3TkTqF9jRmeFMpZNLaRydPWCmumrCI7HSwb6PuBmsswxPi5Br_NcjszNq-c3t5_Gj8klCceJjDak7wjMuGYSK1GU34iRlNW7iUYUACE4FApDJciqJcRXE31-S_b7IsZ2xcMU4f0Qf1sWHuKKRiwG-Wx-AhXjDSH_tbhauB0P3JEAFg0eNnsRBwUvrYqzPRKkAJz0AUF_biQ-s3czpmmt77NBxh_IjIfVbfOs8QbHM1bgZqUzhS1f-cFLcrEypLHL49Iuy_qXlut79gr2XBsQ05ZIQvOtzCmjZ32b_P-d8oeGzW65rwq0HovxMWxwR7zHqoZD3KJ__a72HMcwK3-fYZBzjMjxOHlBxdzmy4_xsfUBMWxuXREypfY9cb8uuALpRJCebN4pIocB59ShZgTtApb2GVk2jheXHAMx8-7GAUO_W8mzJlaHtrdJd1QYFME1W-_bhfJkYJW70phqUcvVDjoBGHiiL6TxkYAFwCNUhJsvnIG8Ihm09t8TKmcrPx73MVG-euP6T1ZIVL5FFX4kOqSZW2gKg_cUr6xUhuey3sVNd5Qfl_q3PHNHVif93EpJ6iac1VQ6soW9MwuNpKURX_r6WWDx6kyeTXKmbE_6Boe4jSTq_BKYY_SYoZY8AIOrGmKBV6wemc7hR8ko5yfH5_T4V7rwHSPotueN02Xb7qAgizPUxwxuMvwiQoqo6PEI6V96_iRvTCso0mJ2k-EZ7e77Wo3X4A2EjH1ciljhDA2uQAh5QgGUgVI3QfGiaDFrgeQQOatOd-zqvM1j-WB0ZBpjYFR13O8N2ZqXQQ_AlWOmx60LQI79a-BIZb_UBzkpMpR-bsUlFq_CQv9o4cxGU3M9Orwsck_5a_V2Mlsicz8ThvLz2-MaoQvwnU3Zskde4SyRQlqMYSThRxSc1kUBsDDWgBWNrvpeVDxvLAmc8XVR_xMgCiRcyAvrv9kG3RseYoD--fqyx_YpoAGleoG4jA4FFkvZdE-MEN3CSuML2oOJAsMNgAG1mNzkbeJO53oe6qrL4ZnnYHQyayaxSMpi0FonMibsg6pHn8EZ1vKes2W9ljy02W8lfTxnaXewF5qX9uKTnfHM2s9MSdSasJCLagPDjA5ZtsRcwBMpZ6LgJuT6OZsvYyWONDM2y-BdUMN1iiIvJXaRIG-smszpElaZZimJUSPKhO3klT5LH0mZRWL03AnpauWNRdZNZhWJl7sum2bEulbxe7_Ir0LvN1IxUTbDX4TLTDwPc4vEpouKM278KKxo8idZlo0Sd-Azwu6CAvr0uIs0Vs6SqKWWvyC5B5ZmJwxJ_uEFphVW1WKxUxqhSHadoLF95BtwU23ayhu7GV6ZbpgkS9JBETCsYY1xZ0W_A02jv6SsSX45zEg7wJVgKl_EgWBlCw8QCxNirmpxcYvEbikYIBz1NscUBlLnGNIpGONVzrdtmBOkkikw0Goot8ixXePS0_7Jm1LavQIqhklO2SZ8Ve90UZCf0cO4NioF9S58mYFxQ5M4UAErTkbH6LOpmk9I3OhSUUgDwpYN9FWIc__JoAvfUIqvgxvvU13DUyTjdyWvcJyAd2qN_TqSQRreY2fiieLXTEDsZwMRy3qVKQIXVc8wd3hiztuO45EXMqW6ho3OhXFPiVhXUzzt6YJ4SFO5_yPLDOLQj0t4jOnjdvAOnt0gdiC8VSZaugxZTpQFSDPD-skDmj0CAZ9VUJhWNUnkRK_aiclAf2rouiJ1Ot9APUEtXlHR2ImVQSrepMEHDJz1ijCH6QUnkX1aTYt41RBZiEa09207Ow8X1BtTrhofjxAyLzVhEqg76sNiXHhP7J9QAYhxctefmDgk6ZUHqIeveNDeKKfeXrW2UzlLBl6S3xW1xnHBrHxp6wcjngqih1SG0eqfXWgJ_mEg9lOUrbDttiTJbTE7_XhZ2vfJ7Y626u0J6Iz7mGcPa3nCSgzskbBKQflfE0CqS-N-AjTirwU2_7Lb-ofMmbd-rWludoNtNwzh6BAKFVs66rHa-VrWSwoWR-2mMD1GD8WzsjCN4PvgTo5mOGlltDDkWROl5ibhJ-tLyAeZ4mtK5f_oVModXQtapyXA9GEoktjGtoFqE3BkMwk0i_P542lOJ3fNGI-sPyfaWRQXx56wxy470_0dwy_o3aSvJdetOxOi32BfEqfPN-TBNU3MkX_bt0FTMcXjOltnoGh6bgZI8tZ4RGHof9yBLhqVsW9aQ8LN8amNJg4JCsO75vjpW0nDgOk6cKeadSWjP3fBJ_BEmfFkDgLfGeZ_ILTxpzJ9r7yCGPdFoA1C5a1i4DT-3A0UD15W6cpgdfAYRF0Wt3i4UDopGFpASyM1_TpKBzig_iy8j4yM6qUwSShEQiGDdNohlrS2q0fS03Rk7EJEi9wFLB6GPvm4hqJoCes22TvIN14fjz8udTQXNMVEbanKdhMgckZ3sjmAakOe9APmpTbWJ0GNVXwGoErrwLlaptkA5BIk2ZW3OcRWykaHZBnCgf2dNb6II7Mjjguw6H5_J1oMqJFQqIlFnxK5B4nvDzQ-9-lLIub0QvWlPn3jxTkZXBO2rrhBwUUDlZ0NN6dtl79XwliYz0aOc9gnfKptmei73V0WXP8qrv4v4ISgRCjytAC72Uao_QoB86j0jdNNuJ-HUz4BGCB4k6pr9rkOwdwd0PY5OfJbDO6PxqiXNO6unt6IOaIoKEhs0rxpRA6GzyooaoLrVTYQxaSeJTa8I_pwuILBgUSu99DD7HhbQwrloBN7ststbloZhT8cN6SzQ2nBbU_LxnroDH6GTrHFPruSt-5jY-lj9GEm4AFsRwQrXgcL_VMzPThUdbYDOMouzuACn9xdz2bhKcGF20DlLA06ZdtWQfOeYHWwFbmUR1FToyVsUkH8Y_V0vzEDLxzXnVS_0xumFFUXltD9kp4guS4W-MWAFa7hDRBG701kJNQXZqRkzHKqpLNgAdUggl59qrgqLbFtTtco2jaj3dmuPBQFppJL0Jbms5I6lDayWkpqxURphQ7mHtKuodiEmK-srvX2V-X49zV3W_wjAdKQzIZH7qyYNud9QhOO6kBrzhAueZModu_lcYU6SaKZ_s_jPkHauZ6lB04rihZnkpF-vcRVOARctFnxGLOyLQ5zsMxtZ9HIm_s7sRMNQoKAVSaGbgH60Vp9P4yUaHZvwIOfC0cJOynP0PZ4hL-5vjkMwsfYI8rvoyg7woA7gbff9UCQtZG4W5nNzR_06goA9-G9c1DAA__-DxpDpaM68LfopLNJoendZ5jNUEjAmGQBhvPHce4WISmsxtXXonFbZQUlja5KAw1nrlPs7QnkECMPBnwzCC9dj5_8m6ZOieQn0RJPAL2vd-3wSJ5Hdndz1O6wuJVRjdHFAoGFq-azLkSJsRfimKwzPorGlUaaHd1KXZAtKVAjgRKhBVN5iHRgIMB573yZ-gD7syERLNECujzRQnSZydBPLAejqmLcreLecByKa5M0e_vN5cxjNEraw9hCg5UzCCrIQ06Xn2S50s9l6V5g9c3IuAE0u-7OVLh0CSqV0aKXg9UOl5E_9n1kn6FA7bYfEK9oUWP91X690oVqobM1EZlUoBdA3drz4tNAsp0zCgG9SleiPCzzFURdTGlzDPKvzk5V7EWiSZf5Mx4mLTJtABBRH-ovoSHLuj0L_mtlTTpXBfyHXV0KdljQ3XQAl_CRHr98HbliFTonvLQLfal-vWW7KRX7H0TYYhPFl0v12_IVI9eae5QvmLLxElJuMYnTuvauewwMxjLSovOsxnIKvaTTDBGclEKpXOOY2sDHpamRKxm9lJLi1Cpwz-6GLdUM1_v97xFGyrlJBqDjLap_c2UcDTPU8EcPiBakEVQdkmNBhz7d08PUze28JH226GnIS9_poHQfroLnxo8RNnOJqFgvMa3xb3Gd9lmGVMwvZuZVsELFnXshva46Zouz6QZQ8V7O9mRDPI4B1oG2eGocb_E74G9i4hWISG_CrOiWwWFPaChqfIbLqFJbxTWRpv30iqmD7IpLgr4hMBMj8MujxlI1BqhnhotOfvOksRkCtOmwpofL0l4YGiJ6cCtwD7ALgzLN4_nTVXR6ZaETLZTqpAfx7z7INvRDuzeSsMdFcWTlLPCsA5WrSCKMC_jtUUAyPktcEKJ6QdLNmhwZmE4FUNrUcjSYZim-ZNXrYC3U5SF9WbsbeQ4G0Tz31JF5ls08RRzsCBCQGf-TKz2PR_hMD-QUCFwhgJkw3xqqy0MONTtECZDHLUiiL04IyK-MbWtV9BIMa7B3g-q8plZ_Rwroj83CoMQbJWb9Ofe6RM_87NN1kXoc8muhMHGZkUgmq_WQMayrSiq_L0Pm2YsJOaGOyJ4sHHd_R6-OlJ6zR6W4qU9bmJSZvF58Z6oshhPQToUQXObEB0E78alCmrWNYSrcXuMqyhzVToGiAdyJoQlBrpjCAR8Ra8_wYx-8EWMzJaHXYG908knfMALVUE51f8J0AAjB1JmVwZbehBhxJrwzgJo3gmLgWNBPvItPgq8HZX8oXgM4d3PwlNnUF6IsPMsyHIYFfnggIKTHv3Mz1QDTRHJ-SIIGnEHtHiUZojIQJf3CUG_UNZAlVL-qqj05sjZahdueLVH2bVYe3Xa75AuN5v8hoUdbeQfDY1LcNk4yz4SLnss5owSXvK_0DM9V2y510RrHmBVLx0GAo8TtgpVd7Vle2TzNeUksWkmCbYsgMealTceOPQsuDPQ5Ie_1kBss8qiz727fst9SueE5hjHe9vmB99Y9O8W18a7TwRedJv2M5RbxOVhq89bXUBq0bbfVoJ5l9t-1YL4-YKESmj529Bcy71_yNzXs8yRJvSUOPhG9-z5aWonPQI30QhcJqtHG_vtAQE4kT5oDEpujitzwdbQYtntGemNGQKWNYV6CLpi499KfZ10jdeHSkbRTZFjX5J7mffEwBVBRHbptsizL6fGCdY3KkFNKNEKU_FRcYgPSyrzRe4koB_Q-2g2yvHBYqghqLsmTMcahnki8uBB_H-WawnjX0jJwKvP9_azFkvOzrQUBl0yCuklM8npNEFAjVVS_h-jQ6Fseb-lyvehp63MVFac__nIdrYoVnOi1Yihb0w4A7Xt4QFtxyfCHnp1re9zisS4msZm0dfb3s-VRRFQ8VeXWazEIUtDc6QhBiTVaOIZjCOrAOV-BCDhnKPKaJ2gK5R0QspQes0EMt1jpPhgqX6Bvxsj-SMyyKZBr9mkAo1pMb4eJw6sWWchEhXQGQIArBDezuQFEa8KbOFoZ8mohCSLZO3pANGJaE0iEB9Uk-y0ftAkFEbzf_lUi8VHa7hDCqLCOvc56isd9MfVFkMWEhbiSaUhACAac75qp63Y7VVRZAR46EfrrIHvTbFO7yebBTxgetKZc4umvt68EUWDfGqVluVWealK0t63CgYo3dk_bnaQTWxIP8fpIJjgchJjie8luPDR2ZzzanU_TMK8hdE-5iHokVnSHWCnJ8TOI8qrRk9YUPCQof9B3I9pH-KJjBQmgo2SurVLFv230SUdrgs7n4EzBYu9GNq9ryakhwoQRLbQsN40PZJuXL3YSBm4Uprptq5-e_r-FnLIk_OcMUOCv6Vupn9-pqWLCc-mTpJCUdduz5Ht8Ecb-plOc0owN_dzBDgdlzA3d4UpAk_2PNmeXRv6e_futRtKRaKJwY0q1-7XnxHpn8PqmQ1sBYVkLpEOeETh_FlSXwcK1ie10hcnE1H988srGMRCtwgPiU7gAGZPuiXq5aaaGEklYLxEvaSRkASWrIzoP6yqk_FUk65o1Q4hqDCMJhXNSnxaYNgRunsxbv4e3nevbeuuaYHrjyrhPizillKvwwGfckmOv9Y25BZSUXMwSVK9Ad3XA98NajHK8rVoiTRa1fjfBXUwVoce2JcVhuzk1zR_B3KixTZCJl7TUT6ajt70IQA-EsWfNtxdUrINMgm0ZjJVkG3ccM2MVQ0v85VUDwMEqcF3LRFAY1-6Rt0shEK9H2HSvRC-jHBl6xV7DQM0OEuWRvJAECkbRTPDs-XbZhqUQJRRb6XMDZsqeX9tCS1MLyMZ1IUQlRIj3d1auBzc6ICfraQA-cMcAyxofrnaRwhZGr__gns5coe8-DQ3YzNE776gzwLAg5k5M-3WEGJY-BbRtde7opCZnWZWLK9tezTy9ws-qLiIeOlRUu5xSnfwuy6icNYqvWvAN6FwAz2m8F56m7RrtigY8JKwpSk2Jkz2XknkCdv-yaFl4PIZoeRF_pmLSi5jSyP4-ze0owGzmSX0CIRMqZYSsS7D0d88U0DWFFupGK4Kg_I4TPgjByoRH8hZrOcsKvmavJktXN-beunsA06WH8opv2jya9gZkxgAiFIifJBVgEDM5bfFtvfD6N3QJE9TfcUPNGoFqhvEBYzVgQnj1IPrMWBEjBrhc9iCnCattATNc8LVlYbHZ3514DESdjISCctsU-fnKuLN-W9tOdSYEp4xi3phiLD3TLI679uQtifBlAYAPabNDe8ZiwI20jl5REQX10lHjvnPRK7mLHxt7PkOGAcd3hVH_w2KzrWdpf_-DM36G6Lq4HvBUH4BNk8zewp3qybZu_V5zZ2hALyRv7Ibl6pULmyoscJXJoFzBHGDr8rqnazTAwFTWVCwxCskGHkw5DPDGsm1T7ILIgAPEveVdLmmnOP4rXI_o0RGsi-nQxdavHPt67-YWOFYeNWiy1AlNlra5DvL-hfDfxCNgrvG6BbW8c7xEhoFvlR80wgfwPDckjd3U4RjjiiUfVsvgf9bx6x9-cIzlxwiRBzVMnlTPXOwqAsJ2H1e8-_tKTFjFkZuYpVRFCf5Dy4xFcvP2rHtHXE3G_ZGii_M5ZwlrBkfmVVO19lazSqpe67rPuobutmjt1bK_A8B2plrI01cZ_B9yOMzrVoZJebI_cs2Eam46VWfOFGTMoJwzLWmwmF4jt6elLw17Wlrv7yW6RoFzMVROMfRGksuezBufgDDKgpK_aX4jWJpldlI_pNRTycgieG9xHkWPsslTUPFFQ07yNArqB_9ERbiZv_4ljva8O2U4lSmi_CPocI_Gf899EBvd7QmlGl7ZswYlb-VrfcfHuSg-eV0QUH4KwQDvx2qBxL3ng0bxCBgiNsOFv8Kot9afWjUA4YKpvoHajsai91iOUEJ1KBfd-GGv_l3M9OoZtpnXre5twKtdCfllAuLcmH4HMAW6cPX41sFdFf2wwk4aaTic4f5_TX3-dSk6_epKwdmjjucflHtrFp6c9SJwf_aB7y7XYnoq3DvveOtT8LqPb92mIsSwvkxd0E6CVw2D0kpUsD8t3wWz59IeaSuGdqzS_7DCBsk240J2F0L-bAi1UmwtJySyEH6gGcb2wzuekUpoL1lbk8NvOFhqGMskpzAW31X5KlAIB5fMqYIechq2qgUTX0fbFbbK-WOS5BNuZzQHg5u-x7KCsd4M-i0-JQtTNyHDQ9_6GICe3RAa1au6QMk3bbuEeX6p2rkQNIaoaP4X4cayBr_0yu1Txn9PV28js9BnbryxWauTjYYSz02CGE1kN8STnQ-ebpq3WkorL8QcPw7VJFDRytkwSz_AslMaxmoCzvftC8nxZgEveO027csojiijwJ0gpDZYvyhMgNcPhPaLIEJrVSWkyMnkt7Pu3Y2YotbyxyjnySgVgUhvU4rplk9cHykR-1KIdnyrtAmWD1POJhmmtRF0wbMXWPg2zp4LPvH1LRywS1Si6lgMCGOMXRfOzbm8PYJDeM13j6e5PrX78ZsaM_n1Y3cDfew8Oy5guR6ja2TAzstADnEs9-ieIV6xIgARP4tLLi5JSMSDKlaite-kt4Os6cW6ZPm3O3rUthnWq5vHRByyhVEytS-ALARuaoZdc-yl0RvQp08jXqnqueILKWdaRWXJveMAB4XenxSGeCVffEuAm2HdhC0EVcS3rimTX4FSGFLOD2cUNXoB7ywSDnP5VTZ-hQKp-URDXx3YsCj_nXwyIYC4EIUN34i4YUh-DprUnNfJqW9Ev3sfByzjyNS7W1a1htCgXckmy0XBY6X8bNswm7w1ptgpLU76NGOuu1haWJp-LPwxXgDEkpG2tLQQsCKedet_QiBmarepWVN1j9ZIkDDwQE5hwRNrwRgHyGIXk-mNcXXF1gmr3q68XEt2VEur6grCHA0CN3dy4NRxuoS1P-vaRxLl0Dl9Iy7lIGoZaKP_MdGdiotIZdnxe08sBWUvZGdUMg0gpEAn6CegsiuQbLCqT1KuPoMNLKnh-33zrHA7Jo9SqxZ-xrRpwhj-bTeL4v9WgALcRO22E8vhFrVJZICjEBwUv6rpo584dUhoxWlwC3wNo8VRp08Hkbso018pjErTyQ7Is61euKF_OxAvYmHgyZVb_IaldqIHSelpu7EQaaFtvLJSiA3XOIpD4O-rZeimfmS6tOOYQad2TjTbrO15c6AY1OlCWsWAbUGQ_8NGmAijI39Vfcy1z5DJceiok_1_Ao2jh82tEMflNeI6DVEe01zDeZvTHimGVreOj7P7a8Turi7VbzP1VlxrgAxDWZmkPWRxIzfrFjfdMM21KtCE5M1FAqX9buLWcCO-PYmQEjb3_34_g5jOwywcmJXB2LVw5H1d0LpnoBrZSYi52lQaYM0pUombI4jqfrHuZUemB_uYWMdqogdGtyWr23TJeUeQg8BfxtVzjmyw5lbCwH62GSDbpyjzCv3Fn3WDq0qrjR_Xwmj2B9bJR0SgWZhOZm9ZudUOuq3VEZcuaDNvRtmUGysZWzRGRAp3AxolKhk_gTywGIytH25Hj0L28paw0xjmN8YunkxNVbegg8MnXw5l9G8SXNPhZJYKZ5HqI5XRsbwZgvJvSHy5V_G8Ie9YLVrbpoYkmT0j7ErSHXh4BQeS_zbFJosev3fmnxJIEyTz916SACv0s1ocw80aohgzjK8N8eDz5FJ2JQIBZz8TNSYmfFX_Uv93_ZwR0mOAJ2QkKdv5maUC6JU_SSSmDCqcMwp1u4-AA--Z0rSCXGHWWkdZ4vWhRbxFkCQs1IcuSQn2-OxNBImLxvxmhS8XDBKFfm9t8B6ed4TjupnNn6x0BWG2BtJ0yk7Y2ecj8XMQaiaG4MKRdUd6i6xOz7GwmtSA7ckNZef3_B-XA-vw7kYih6vhIf0sRdDX7IK3GVrsN9LbhmMeswEQJteavZGwDWF-piCpBMJ4LWcwsKI534unKNAPhzVPIiczSD1gM8ykZnxVWZYfX4Gd5TC96tdoQq9Z9e-d7uksaInDQr-NSo9rMPPm2quIe_GUEeqzvRHVDmaJkmP-4CeMGghGHQHozDXavc8os__2len8ZFyVAKnyHfhn6D7eo4aHnPL3J4frq7M6SLDjdvunW9OCmROtmSkXjvFwM09w95KEcroXJBkM7bsA-Z6KU-uTwADINUA4TH3K3Y7R0oRmCBtWzT_mQaIE2fgqbwyI5ZhmjelOG8QZYPCK9OtqYwNw1pHDFeHHM9EcXrux-jfccDUJ4IPdOKGOkPurJx7EJv_Ed0sh1IKaYzNRuvsUJGbVU_xyb1nef-Fic6P38JCrC7EYEzLKdtKNCFTacUn9OO3Ygf9b833fcjfG0LYWZeCINxKp1OeGsOTd6am8kwL9Dwx41BbBRHHxb2Fa_w8oneZ5f5yQmHlKvhJ7Rh6hUEYWDCUOG2njMVe0BeI9H8bxzxeWZI4RCXYa0sbEbCqk30ivJI1pdzYuuyk9cc4qUbsPdIScAcSXk7NqBlS82Lz7kDtFjrRtNOVhrjpjlKV-a9W6-rPB0U2savy6xjp-e7yPL_S1Spt10edRjtxHt-AvX3qh56EJdILHPX1MbxFol5LhH9evz_dw2Pe9gxOTYS6S58qxcxX4Nb-KfXngnxaeJ48SsKN-TKi2TWntVLsjDBLPUO1LXrFw8_ZjijdW9j0SxZkOEbnvI3uJ3jvEVxMxUojlfUh7TvKdR209jBuO2ezWcLt3CKfRG6Ak0FjcugJ8ByMucCG5mGMOB7UyWCTurM4FvTeHHAN20C16LRkZ8VyANz-Oe9YfYFO9lrofS1-3jm8UoZ5AbIjCkOCAdOdVEo8RBOh_P8wOTVaYlURHOfeXniL51czYw3UjyIkMftiVXghc5KAWhwrqOkeTPDa3b4zImVqd00u-fsVl9_-c25qR-K1UaiwEEvF0ZJK1TTjMNerCVNezaycd8KZ8ktdaqQD9bvx3okUSpKFZ_WZtgRg4oOlf7ac1ba0PUyigxms9I-9f6snYfzyefP3elvMXL4KpbcDfDcxEWrwFiQ-xDSHjHLrve-irM1DEbgNY85C4XciSOq_fMVut-s6GulegmFjJYOukwLjpLFrEEaenpEKKQlN0upzQcHmdUm1XPUuOFrevg3IMzIpYoYjpsMHtJPXEhViPcpt2uwwRH6gWGtt9wX1KFlYeES1LfdNYBgBA4myFQwz8TR3EeojBxTwtW_pIX5P_A0byfabD2BCEKDZwmgiLfSA25skSB57d2WllO8GkY0pdKBkprewSBb9rqcrRDIk-wd_hSX5NGSnlUGY2-hU0ng1erQeYamS5pYw-BUVTtka3WdDIK4Xg_-RXXg08hfdruAZT-QNBr4KhSVX1l_W-BACPuXirWu1LH12Fu1LQ7X168GjM3ncmfW1abNU6auYfJoxOYTvditijm4SHidFcLNNOYGTOe5WkNNUMKhfjPI03_ofrwmbC0XZvgrUdRPNLM4ocIb4u9W6_LuDRcxd_pnv061OvmBXLYjVQx_O5sscdftVxVj70DaT1Xt1CI51THYtlr0iA_r-xYFTYEMBvNOdz8mzQOblwbeLqnhFWvkcjBj__0K8brz9WTkKJDmq1JPTkG6h-hjPgAcyL-ayVuWJ0iLlvXObqalnNWZ41zyc5XG2uOX2roF2EMOwjZ4Io5eAnhR5ZkhxBJTm9egvFyZ-sU9ibMw4dglZ-_mESgmo6AF7UKR77czR_c6gaTUOdu_U=', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de', + signature='gAAAAABoxCyzDT6i7ehEoWDBoDGMZmLcOX8TMbvBssJGa0cA0-7Dy6YfH759wsF0Dn5Auzz8Mp2geHtbVJVxKa-SF4Al-z3lq7gQG29dTf2ecfq_6bkg1gS49MbGEmaLo4FnS6_5oekdntomcOVO4mqwC7JKnCTO5Qyq8-Nm3POi0nOZm6KaEfqrmPHiJttupduQBkiqHIc8_CIfQ9LGqSxXZuAFQ0DbNow-6yya7_5oNOoLdgWti5_n9CENxTYyvG_q-2WAmioZM_rR54rWqmMbxUNNsKJls8xx593rb4u2dEpFJztVeifJNmFnDcYDDHMhvqLdSXJU4z3Yrxg8hgH9w2gD7Ygu2UDsMsiUdp5YGXKx_acJeu81-7H8Yf3XY86woskIv2o2XaegpK496fKkeiUAD8OTGWK0hjJb9KPK3hqTBfRfJzafQbIvnNTwOod3ZPyClgSXTYKsN1E_j3S6G8R0uzyA_NBc47Q-VMIUYf3jBTym3NUTMwiA95qdR1_1N-l4Yy7c9-X3UiRrVpNQ53lNuaUzdYuSq7XGHS_4ZNFwKXuG_dM7U2vhn_2dk2fkuEKZjtBYkVofStR8qlkswIAuEw4mrnt-wjG8cxrAwacoXop0R6NShjmWSrAhgqvAqwY3oR4HCPo_zaHSWjnJcRZ41LkVEcBSvtXqNpez2jYYmUkoGHgr_5gGpHpPo2j2lM0pBmPwPQ3OA8RJLEZYiQtabP7AKzZ32Lvsf35uhLRMZ6hkLtwPKgJ4tuR6E2B7xlZ6C0UoUbuI2Spou5dQsqPd6byXwHa22yViPpcpjeZOgHKK41cnK_tpL1kEe1KtodMW43d4OwHZ4LYqm8B769ob3uWnzGOMSGSrTsvci7gm00P0mwKBCh-XC1xdo448iGC7O_bvfYeBJNGsFObB3KqT7WLy04gc0gP7uWH629g151xRPzILeJUHsM_MwrFbNRqo9KbJFtGP0AQiQkO9lE-0VpWQW6ZyQLg6wByI-pPwakXJiCWxpxQF95NRjGOvwYyoU32ipX9mqEjdjQ-vTDn9vte8wPww0aPtAKqK-k0gkeBZAJYALVZNj6Oh0BUdA2t-XcMxs7Qho0V-LLgUjrmyM2ci71LgxeqO8I7LkOuGYMGYj2rFIGrzMeZOgucDhMyury4ELb50ohyYGjf5sOYavsYUwzK3NQwDZ3kjyHFSzCvgkuRgMLKxmME-4aRW8VbGLyC1f2hDuwxzL-cExk4yMh8TijVsf-bnRhHwmQKiR-SGkhrylfn-WnBQQffAdWpjscP9od0UJSPZrLZTaht7Z_15rMw9RO7vXl6PmcFw8vYciH58zUpU5vgq5_QGNvACSnnQxG8Nc9KmIYxGQyMow_ch1PBUP4yGYXR7Xwg0YiB6bwW5p_bxysCJAWBrp4sazb2Al3055Cfnmq9QXTFwFJo0jfbpqwPySuQ28TAiZah0CbCf_zdpJgz9hqM9HeRWHDwIKiR9OpxH2N8rWLqqRZTyfvRX7BfMF6P1bFVVagwhqljKZfcF7QFztlqKdYSGcsA6jdz1RT7B9CItJyKCnHgTYsFtxOr-7z8lkNNlb3xJAYmwYuSQszTR0nFnP4Inc_Ay8XVdmY-ppo6PMJztYQqZXB9wABGkzfKUl9UAIvjMrqHAw76sw28WTA3xxoVS64CM4YDs028hnVsL6euOe6VVBqpVMbrQ6OVi2FOR-vLbNAVBwbelAhbsqoZNMATg8bqlf3UMwacTkr_R1me2gDFv2BjxbjvlZUApzkl9L-CMnVPEsyb187O20chSrJhsy2tLh8SC_6_XCCnNFub3RAvD0BkNzDVZig_oC3ps_EEaPZgEdtbUb_GqaCFcbeo6X4wY7xkr1gZfTP_NHK8XyElajh_HP8T1fPmTZMh46rtXh5-54th6NQ_3jTjCeOfmLjbQKotLNOhJKlB8vXa2CsO575d2zkP2CAMGy9TU_ztUCfaGFOeFPN_xvz1vBZ7QqA-yA10tOdOm8b3oowPfMbZ2n5mvyLNG-DgUkjPGty5gyvJvyMgoqZao66fyzfLvM28eQMpOOcGAcozDFnW_vkffTU5GmPLUaG6rx74V32RVzaQKuC_nGBF8T_NfJ9NfecUw2uj21vCcUyTiIQb3Are8aZLnfsi4DyY-E7WhNnBoLsKZO1CzurCYKCPi4KYGjTr9og_MQM4frL9nez4teQDdUZnu3TkTqF9jRmeFMpZNLaRydPWCmumrCI7HSwb6PuBmsswxPi5Br_NcjszNq-c3t5_Gj8klCceJjDak7wjMuGYSK1GU34iRlNW7iUYUACE4FApDJciqJcRXE31-S_b7IsZ2xcMU4f0Qf1sWHuKKRiwG-Wx-AhXjDSH_tbhauB0P3JEAFg0eNnsRBwUvrYqzPRKkAJz0AUF_biQ-s3czpmmt77NBxh_IjIfVbfOs8QbHM1bgZqUzhS1f-cFLcrEypLHL49Iuy_qXlut79gr2XBsQ05ZIQvOtzCmjZ32b_P-d8oeGzW65rwq0HovxMWxwR7zHqoZD3KJ__a72HMcwK3-fYZBzjMjxOHlBxdzmy4_xsfUBMWxuXREypfY9cb8uuALpRJCebN4pIocB59ShZgTtApb2GVk2jheXHAMx8-7GAUO_W8mzJlaHtrdJd1QYFME1W-_bhfJkYJW70phqUcvVDjoBGHiiL6TxkYAFwCNUhJsvnIG8Ihm09t8TKmcrPx73MVG-euP6T1ZIVL5FFX4kOqSZW2gKg_cUr6xUhuey3sVNd5Qfl_q3PHNHVif93EpJ6iac1VQ6soW9MwuNpKURX_r6WWDx6kyeTXKmbE_6Boe4jSTq_BKYY_SYoZY8AIOrGmKBV6wemc7hR8ko5yfH5_T4V7rwHSPotueN02Xb7qAgizPUxwxuMvwiQoqo6PEI6V96_iRvTCso0mJ2k-EZ7e77Wo3X4A2EjH1ciljhDA2uQAh5QgGUgVI3QfGiaDFrgeQQOatOd-zqvM1j-WB0ZBpjYFR13O8N2ZqXQQ_AlWOmx60LQI79a-BIZb_UBzkpMpR-bsUlFq_CQv9o4cxGU3M9Orwsck_5a_V2Mlsicz8ThvLz2-MaoQvwnU3Zskde4SyRQlqMYSThRxSc1kUBsDDWgBWNrvpeVDxvLAmc8XVR_xMgCiRcyAvrv9kG3RseYoD--fqyx_YpoAGleoG4jA4FFkvZdE-MEN3CSuML2oOJAsMNgAG1mNzkbeJO53oe6qrL4ZnnYHQyayaxSMpi0FonMibsg6pHn8EZ1vKes2W9ljy02W8lfTxnaXewF5qX9uKTnfHM2s9MSdSasJCLagPDjA5ZtsRcwBMpZ6LgJuT6OZsvYyWONDM2y-BdUMN1iiIvJXaRIG-smszpElaZZimJUSPKhO3klT5LH0mZRWL03AnpauWNRdZNZhWJl7sum2bEulbxe7_Ir0LvN1IxUTbDX4TLTDwPc4vEpouKM278KKxo8idZlo0Sd-Azwu6CAvr0uIs0Vs6SqKWWvyC5B5ZmJwxJ_uEFphVW1WKxUxqhSHadoLF95BtwU23ayhu7GV6ZbpgkS9JBETCsYY1xZ0W_A02jv6SsSX45zEg7wJVgKl_EgWBlCw8QCxNirmpxcYvEbikYIBz1NscUBlLnGNIpGONVzrdtmBOkkikw0Goot8ixXePS0_7Jm1LavQIqhklO2SZ8Ve90UZCf0cO4NioF9S58mYFxQ5M4UAErTkbH6LOpmk9I3OhSUUgDwpYN9FWIc__JoAvfUIqvgxvvU13DUyTjdyWvcJyAd2qN_TqSQRreY2fiieLXTEDsZwMRy3qVKQIXVc8wd3hiztuO45EXMqW6ho3OhXFPiVhXUzzt6YJ4SFO5_yPLDOLQj0t4jOnjdvAOnt0gdiC8VSZaugxZTpQFSDPD-skDmj0CAZ9VUJhWNUnkRK_aiclAf2rouiJ1Ot9APUEtXlHR2ImVQSrepMEHDJz1ijCH6QUnkX1aTYt41RBZiEa09207Ow8X1BtTrhofjxAyLzVhEqg76sNiXHhP7J9QAYhxctefmDgk6ZUHqIeveNDeKKfeXrW2UzlLBl6S3xW1xnHBrHxp6wcjngqih1SG0eqfXWgJ_mEg9lOUrbDttiTJbTE7_XhZ2vfJ7Y626u0J6Iz7mGcPa3nCSgzskbBKQflfE0CqS-N-AjTirwU2_7Lb-ofMmbd-rWludoNtNwzh6BAKFVs66rHa-VrWSwoWR-2mMD1GD8WzsjCN4PvgTo5mOGlltDDkWROl5ibhJ-tLyAeZ4mtK5f_oVModXQtapyXA9GEoktjGtoFqE3BkMwk0i_P542lOJ3fNGI-sPyfaWRQXx56wxy470_0dwy_o3aSvJdetOxOi32BfEqfPN-TBNU3MkX_bt0FTMcXjOltnoGh6bgZI8tZ4RGHof9yBLhqVsW9aQ8LN8amNJg4JCsO75vjpW0nDgOk6cKeadSWjP3fBJ_BEmfFkDgLfGeZ_ILTxpzJ9r7yCGPdFoA1C5a1i4DT-3A0UD15W6cpgdfAYRF0Wt3i4UDopGFpASyM1_TpKBzig_iy8j4yM6qUwSShEQiGDdNohlrS2q0fS03Rk7EJEi9wFLB6GPvm4hqJoCes22TvIN14fjz8udTQXNMVEbanKdhMgckZ3sjmAakOe9APmpTbWJ0GNVXwGoErrwLlaptkA5BIk2ZW3OcRWykaHZBnCgf2dNb6II7Mjjguw6H5_J1oMqJFQqIlFnxK5B4nvDzQ-9-lLIub0QvWlPn3jxTkZXBO2rrhBwUUDlZ0NN6dtl79XwliYz0aOc9gnfKptmei73V0WXP8qrv4v4ISgRCjytAC72Uao_QoB86j0jdNNuJ-HUz4BGCB4k6pr9rkOwdwd0PY5OfJbDO6PxqiXNO6unt6IOaIoKEhs0rxpRA6GzyooaoLrVTYQxaSeJTa8I_pwuILBgUSu99DD7HhbQwrloBN7ststbloZhT8cN6SzQ2nBbU_LxnroDH6GTrHFPruSt-5jY-lj9GEm4AFsRwQrXgcL_VMzPThUdbYDOMouzuACn9xdz2bhKcGF20DlLA06ZdtWQfOeYHWwFbmUR1FToyVsUkH8Y_V0vzEDLxzXnVS_0xumFFUXltD9kp4guS4W-MWAFa7hDRBG701kJNQXZqRkzHKqpLNgAdUggl59qrgqLbFtTtco2jaj3dmuPBQFppJL0Jbms5I6lDayWkpqxURphQ7mHtKuodiEmK-srvX2V-X49zV3W_wjAdKQzIZH7qyYNud9QhOO6kBrzhAueZModu_lcYU6SaKZ_s_jPkHauZ6lB04rihZnkpF-vcRVOARctFnxGLOyLQ5zsMxtZ9HIm_s7sRMNQoKAVSaGbgH60Vp9P4yUaHZvwIOfC0cJOynP0PZ4hL-5vjkMwsfYI8rvoyg7woA7gbff9UCQtZG4W5nNzR_06goA9-G9c1DAA__-DxpDpaM68LfopLNJoendZ5jNUEjAmGQBhvPHce4WISmsxtXXonFbZQUlja5KAw1nrlPs7QnkECMPBnwzCC9dj5_8m6ZOieQn0RJPAL2vd-3wSJ5Hdndz1O6wuJVRjdHFAoGFq-azLkSJsRfimKwzPorGlUaaHd1KXZAtKVAjgRKhBVN5iHRgIMB573yZ-gD7syERLNECujzRQnSZydBPLAejqmLcreLecByKa5M0e_vN5cxjNEraw9hCg5UzCCrIQ06Xn2S50s9l6V5g9c3IuAE0u-7OVLh0CSqV0aKXg9UOl5E_9n1kn6FA7bYfEK9oUWP91X690oVqobM1EZlUoBdA3drz4tNAsp0zCgG9SleiPCzzFURdTGlzDPKvzk5V7EWiSZf5Mx4mLTJtABBRH-ovoSHLuj0L_mtlTTpXBfyHXV0KdljQ3XQAl_CRHr98HbliFTonvLQLfal-vWW7KRX7H0TYYhPFl0v12_IVI9eae5QvmLLxElJuMYnTuvauewwMxjLSovOsxnIKvaTTDBGclEKpXOOY2sDHpamRKxm9lJLi1Cpwz-6GLdUM1_v97xFGyrlJBqDjLap_c2UcDTPU8EcPiBakEVQdkmNBhz7d08PUze28JH226GnIS9_poHQfroLnxo8RNnOJqFgvMa3xb3Gd9lmGVMwvZuZVsELFnXshva46Zouz6QZQ8V7O9mRDPI4B1oG2eGocb_E74G9i4hWISG_CrOiWwWFPaChqfIbLqFJbxTWRpv30iqmD7IpLgr4hMBMj8MujxlI1BqhnhotOfvOksRkCtOmwpofL0l4YGiJ6cCtwD7ALgzLN4_nTVXR6ZaETLZTqpAfx7z7INvRDuzeSsMdFcWTlLPCsA5WrSCKMC_jtUUAyPktcEKJ6QdLNmhwZmE4FUNrUcjSYZim-ZNXrYC3U5SF9WbsbeQ4G0Tz31JF5ls08RRzsCBCQGf-TKz2PR_hMD-QUCFwhgJkw3xqqy0MONTtECZDHLUiiL04IyK-MbWtV9BIMa7B3g-q8plZ_Rwroj83CoMQbJWb9Ofe6RM_87NN1kXoc8muhMHGZkUgmq_WQMayrSiq_L0Pm2YsJOaGOyJ4sHHd_R6-OlJ6zR6W4qU9bmJSZvF58Z6oshhPQToUQXObEB0E78alCmrWNYSrcXuMqyhzVToGiAdyJoQlBrpjCAR8Ra8_wYx-8EWMzJaHXYG908knfMALVUE51f8J0AAjB1JmVwZbehBhxJrwzgJo3gmLgWNBPvItPgq8HZX8oXgM4d3PwlNnUF6IsPMsyHIYFfnggIKTHv3Mz1QDTRHJ-SIIGnEHtHiUZojIQJf3CUG_UNZAlVL-qqj05sjZahdueLVH2bVYe3Xa75AuN5v8hoUdbeQfDY1LcNk4yz4SLnss5owSXvK_0DM9V2y510RrHmBVLx0GAo8TtgpVd7Vle2TzNeUksWkmCbYsgMealTceOPQsuDPQ5Ie_1kBss8qiz727fst9SueE5hjHe9vmB99Y9O8W18a7TwRedJv2M5RbxOVhq89bXUBq0bbfVoJ5l9t-1YL4-YKESmj529Bcy71_yNzXs8yRJvSUOPhG9-z5aWonPQI30QhcJqtHG_vtAQE4kT5oDEpujitzwdbQYtntGemNGQKWNYV6CLpi499KfZ10jdeHSkbRTZFjX5J7mffEwBVBRHbptsizL6fGCdY3KkFNKNEKU_FRcYgPSyrzRe4koB_Q-2g2yvHBYqghqLsmTMcahnki8uBB_H-WawnjX0jJwKvP9_azFkvOzrQUBl0yCuklM8npNEFAjVVS_h-jQ6Fseb-lyvehp63MVFac__nIdrYoVnOi1Yihb0w4A7Xt4QFtxyfCHnp1re9zisS4msZm0dfb3s-VRRFQ8VeXWazEIUtDc6QhBiTVaOIZjCOrAOV-BCDhnKPKaJ2gK5R0QspQes0EMt1jpPhgqX6Bvxsj-SMyyKZBr9mkAo1pMb4eJw6sWWchEhXQGQIArBDezuQFEa8KbOFoZ8mohCSLZO3pANGJaE0iEB9Uk-y0ftAkFEbzf_lUi8VHa7hDCqLCOvc56isd9MfVFkMWEhbiSaUhACAac75qp63Y7VVRZAR46EfrrIHvTbFO7yebBTxgetKZc4umvt68EUWDfGqVluVWealK0t63CgYo3dk_bnaQTWxIP8fpIJjgchJjie8luPDR2ZzzanU_TMK8hdE-5iHokVnSHWCnJ8TOI8qrRk9YUPCQof9B3I9pH-KJjBQmgo2SurVLFv230SUdrgs7n4EzBYu9GNq9ryakhwoQRLbQsN40PZJuXL3YSBm4Uprptq5-e_r-FnLIk_OcMUOCv6Vupn9-pqWLCc-mTpJCUdduz5Ht8Ecb-plOc0owN_dzBDgdlzA3d4UpAk_2PNmeXRv6e_futRtKRaKJwY0q1-7XnxHpn8PqmQ1sBYVkLpEOeETh_FlSXwcK1ie10hcnE1H988srGMRCtwgPiU7gAGZPuiXq5aaaGEklYLxEvaSRkASWrIzoP6yqk_FUk65o1Q4hqDCMJhXNSnxaYNgRunsxbv4e3nevbeuuaYHrjyrhPizillKvwwGfckmOv9Y25BZSUXMwSVK9Ad3XA98NajHK8rVoiTRa1fjfBXUwVoce2JcVhuzk1zR_B3KixTZCJl7TUT6ajt70IQA-EsWfNtxdUrINMgm0ZjJVkG3ccM2MVQ0v85VUDwMEqcF3LRFAY1-6Rt0shEK9H2HSvRC-jHBl6xV7DQM0OEuWRvJAECkbRTPDs-XbZhqUQJRRb6XMDZsqeX9tCS1MLyMZ1IUQlRIj3d1auBzc6ICfraQA-cMcAyxofrnaRwhZGr__gns5coe8-DQ3YzNE776gzwLAg5k5M-3WEGJY-BbRtde7opCZnWZWLK9tezTy9ws-qLiIeOlRUu5xSnfwuy6icNYqvWvAN6FwAz2m8F56m7RrtigY8JKwpSk2Jkz2XknkCdv-yaFl4PIZoeRF_pmLSi5jSyP4-ze0owGzmSX0CIRMqZYSsS7D0d88U0DWFFupGK4Kg_I4TPgjByoRH8hZrOcsKvmavJktXN-beunsA06WH8opv2jya9gZkxgAiFIifJBVgEDM5bfFtvfD6N3QJE9TfcUPNGoFqhvEBYzVgQnj1IPrMWBEjBrhc9iCnCattATNc8LVlYbHZ3514DESdjISCctsU-fnKuLN-W9tOdSYEp4xi3phiLD3TLI679uQtifBlAYAPabNDe8ZiwI20jl5REQX10lHjvnPRK7mLHxt7PkOGAcd3hVH_w2KzrWdpf_-DM36G6Lq4HvBUH4BNk8zewp3qybZu_V5zZ2hALyRv7Ibl6pULmyoscJXJoFzBHGDr8rqnazTAwFTWVCwxCskGHkw5DPDGsm1T7ILIgAPEveVdLmmnOP4rXI_o0RGsi-nQxdavHPt67-YWOFYeNWiy1AlNlra5DvL-hfDfxCNgrvG6BbW8c7xEhoFvlR80wgfwPDckjd3U4RjjiiUfVsvgf9bx6x9-cIzlxwiRBzVMnlTPXOwqAsJ2H1e8-_tKTFjFkZuYpVRFCf5Dy4xFcvP2rHtHXE3G_ZGii_M5ZwlrBkfmVVO19lazSqpe67rPuobutmjt1bK_A8B2plrI01cZ_B9yOMzrVoZJebI_cs2Eam46VWfOFGTMoJwzLWmwmF4jt6elLw17Wlrv7yW6RoFzMVROMfRGksuezBufgDDKgpK_aX4jWJpldlI_pNRTycgieG9xHkWPsslTUPFFQ07yNArqB_9ERbiZv_4ljva8O2U4lSmi_CPocI_Gf899EBvd7QmlGl7ZswYlb-VrfcfHuSg-eV0QUH4KwQDvx2qBxL3ng0bxCBgiNsOFv8Kot9afWjUA4YKpvoHajsai91iOUEJ1KBfd-GGv_l3M9OoZtpnXre5twKtdCfllAuLcmH4HMAW6cPX41sFdFf2wwk4aaTic4f5_TX3-dSk6_epKwdmjjucflHtrFp6c9SJwf_aB7y7XYnoq3DvveOtT8LqPb92mIsSwvkxd0E6CVw2D0kpUsD8t3wWz59IeaSuGdqzS_7DCBsk240J2F0L-bAi1UmwtJySyEH6gGcb2wzuekUpoL1lbk8NvOFhqGMskpzAW31X5KlAIB5fMqYIechq2qgUTX0fbFbbK-WOS5BNuZzQHg5u-x7KCsd4M-i0-JQtTNyHDQ9_6GICe3RAa1au6QMk3bbuEeX6p2rkQNIaoaP4X4cayBr_0yu1Txn9PV28js9BnbryxWauTjYYSz02CGE1kN8STnQ-ebpq3WkorL8QcPw7VJFDRytkwSz_AslMaxmoCzvftC8nxZgEveO027csojiijwJ0gpDZYvyhMgNcPhPaLIEJrVSWkyMnkt7Pu3Y2YotbyxyjnySgVgUhvU4rplk9cHykR-1KIdnyrtAmWD1POJhmmtRF0wbMXWPg2zp4LPvH1LRywS1Si6lgMCGOMXRfOzbm8PYJDeM13j6e5PrX78ZsaM_n1Y3cDfew8Oy5guR6ja2TAzstADnEs9-ieIV6xIgARP4tLLi5JSMSDKlaite-kt4Os6cW6ZPm3O3rUthnWq5vHRByyhVEytS-ALARuaoZdc-yl0RvQp08jXqnqueILKWdaRWXJveMAB4XenxSGeCVffEuAm2HdhC0EVcS3rimTX4FSGFLOD2cUNXoB7ywSDnP5VTZ-hQKp-URDXx3YsCj_nXwyIYC4EIUN34i4YUh-DprUnNfJqW9Ev3sfByzjyNS7W1a1htCgXckmy0XBY6X8bNswm7w1ptgpLU76NGOuu1haWJp-LPwxXgDEkpG2tLQQsCKedet_QiBmarepWVN1j9ZIkDDwQE5hwRNrwRgHyGIXk-mNcXXF1gmr3q68XEt2VEur6grCHA0CN3dy4NRxuoS1P-vaRxLl0Dl9Iy7lIGoZaKP_MdGdiotIZdnxe08sBWUvZGdUMg0gpEAn6CegsiuQbLCqT1KuPoMNLKnh-33zrHA7Jo9SqxZ-xrRpwhj-bTeL4v9WgALcRO22E8vhFrVJZICjEBwUv6rpo584dUhoxWlwC3wNo8VRp08Hkbso018pjErTyQ7Is61euKF_OxAvYmHgyZVb_IaldqIHSelpu7EQaaFtvLJSiA3XOIpD4O-rZeimfmS6tOOYQad2TjTbrO15c6AY1OlCWsWAbUGQ_8NGmAijI39Vfcy1z5DJceiok_1_Ao2jh82tEMflNeI6DVEe01zDeZvTHimGVreOj7P7a8Turi7VbzP1VlxrgAxDWZmkPWRxIzfrFjfdMM21KtCE5M1FAqX9buLWcCO-PYmQEjb3_34_g5jOwywcmJXB2LVw5H1d0LpnoBrZSYi52lQaYM0pUombI4jqfrHuZUemB_uYWMdqogdGtyWr23TJeUeQg8BfxtVzjmyw5lbCwH62GSDbpyjzCv3Fn3WDq0qrjR_Xwmj2B9bJR0SgWZhOZm9ZudUOuq3VEZcuaDNvRtmUGysZWzRGRAp3AxolKhk_gTywGIytH25Hj0L28paw0xjmN8YunkxNVbegg8MnXw5l9G8SXNPhZJYKZ5HqI5XRsbwZgvJvSHy5V_G8Ie9YLVrbpoYkmT0j7ErSHXh4BQeS_zbFJosev3fmnxJIEyTz916SACv0s1ocw80aohgzjK8N8eDz5FJ2JQIBZz8TNSYmfFX_Uv93_ZwR0mOAJ2QkKdv5maUC6JU_SSSmDCqcMwp1u4-AA--Z0rSCXGHWWkdZ4vWhRbxFkCQs1IcuSQn2-OxNBImLxvxmhS8XDBKFfm9t8B6ed4TjupnNn6x0BWG2BtJ0yk7Y2ecj8XMQaiaG4MKRdUd6i6xOz7GwmtSA7ckNZef3_B-XA-vw7kYih6vhIf0sRdDX7IK3GVrsN9LbhmMeswEQJteavZGwDWF-piCpBMJ4LWcwsKI534unKNAPhzVPIiczSD1gM8ykZnxVWZYfX4Gd5TC96tdoQq9Z9e-d7uksaInDQr-NSo9rMPPm2quIe_GUEeqzvRHVDmaJkmP-4CeMGghGHQHozDXavc8os__2len8ZFyVAKnyHfhn6D7eo4aHnPL3J4frq7M6SLDjdvunW9OCmROtmSkXjvFwM09w95KEcroXJBkM7bsA-Z6KU-uTwADINUA4TH3K3Y7R0oRmCBtWzT_mQaIE2fgqbwyI5ZhmjelOG8QZYPCK9OtqYwNw1pHDFeHHM9EcXrux-jfccDUJ4IPdOKGOkPurJx7EJv_Ed0sh1IKaYzNRuvsUJGbVU_xyb1nef-Fic6P38JCrC7EYEzLKdtKNCFTacUn9OO3Ygf9b833fcjfG0LYWZeCINxKp1OeGsOTd6am8kwL9Dwx41BbBRHHxb2Fa_w8oneZ5f5yQmHlKvhJ7Rh6hUEYWDCUOG2njMVe0BeI9H8bxzxeWZI4RCXYa0sbEbCqk30ivJI1pdzYuuyk9cc4qUbsPdIScAcSXk7NqBlS82Lz7kDtFjrRtNOVhrjpjlKV-a9W6-rPB0U2savy6xjp-e7yPL_S1Spt10edRjtxHt-AvX3qh56EJdILHPX1MbxFol5LhH9evz_dw2Pe9gxOTYS6S58qxcxX4Nb-KfXngnxaeJ48SsKN-TKi2TWntVLsjDBLPUO1LXrFw8_ZjijdW9j0SxZkOEbnvI3uJ3jvEVxMxUojlfUh7TvKdR209jBuO2ezWcLt3CKfRG6Ak0FjcugJ8ByMucCG5mGMOB7UyWCTurM4FvTeHHAN20C16LRkZ8VyANz-Oe9YfYFO9lrofS1-3jm8UoZ5AbIjCkOCAdOdVEo8RBOh_P8wOTVaYlURHOfeXniL51czYw3UjyIkMftiVXghc5KAWhwrqOkeTPDa3b4zImVqd00u-fsVl9_-c25qR-K1UaiwEEvF0ZJK1TTjMNerCVNezaycd8KZ8ktdaqQD9bvx3okUSpKFZ_WZtgRg4oOlf7ac1ba0PUyigxms9I-9f6snYfzyefP3elvMXL4KpbcDfDcxEWrwFiQ-xDSHjHLrve-irM1DEbgNY85C4XciSOq_fMVut-s6GulegmFjJYOukwLjpLFrEEaenpEKKQlN0upzQcHmdUm1XPUuOFrevg3IMzIpYoYjpsMHtJPXEhViPcpt2uwwRH6gWGtt9wX1KFlYeES1LfdNYBgBA4myFQwz8TR3EeojBxTwtW_pIX5P_A0byfabD2BCEKDZwmgiLfSA25skSB57d2WllO8GkY0pdKBkprewSBb9rqcrRDIk-wd_hSX5NGSnlUGY2-hU0ng1erQeYamS5pYw-BUVTtka3WdDIK4Xg_-RXXg08hfdruAZT-QNBr4KhSVX1l_W-BACPuXirWu1LH12Fu1LQ7X168GjM3ncmfW1abNU6auYfJoxOYTvditijm4SHidFcLNNOYGTOe5WkNNUMKhfjPI03_ofrwmbC0XZvgrUdRPNLM4ocIb4u9W6_LuDRcxd_pnv061OvmBXLYjVQx_O5sscdftVxVj70DaT1Xt1CI51THYtlr0iA_r-xYFTYEMBvNOdz8mzQOblwbeLqnhFWvkcjBj__0K8brz9WTkKJDmq1JPTkG6h-hjPgAcyL-ayVuWJ0iLlvXObqalnNWZ41zyc5XG2uOX2roF2EMOwjZ4Io5eAnhR5ZkhxBJTm9egvFyZ-sU9ibMw4dglZ-_mESgmo6AF7UKR77czR_c6gaTUOdu_U=', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de', + signature='gAAAAABoxCyzDT6i7ehEoWDBoDGMZmLcOX8TMbvBssJGa0cA0-7Dy6YfH759wsF0Dn5Auzz8Mp2geHtbVJVxKa-SF4Al-z3lq7gQG29dTf2ecfq_6bkg1gS49MbGEmaLo4FnS6_5oekdntomcOVO4mqwC7JKnCTO5Qyq8-Nm3POi0nOZm6KaEfqrmPHiJttupduQBkiqHIc8_CIfQ9LGqSxXZuAFQ0DbNow-6yya7_5oNOoLdgWti5_n9CENxTYyvG_q-2WAmioZM_rR54rWqmMbxUNNsKJls8xx593rb4u2dEpFJztVeifJNmFnDcYDDHMhvqLdSXJU4z3Yrxg8hgH9w2gD7Ygu2UDsMsiUdp5YGXKx_acJeu81-7H8Yf3XY86woskIv2o2XaegpK496fKkeiUAD8OTGWK0hjJb9KPK3hqTBfRfJzafQbIvnNTwOod3ZPyClgSXTYKsN1E_j3S6G8R0uzyA_NBc47Q-VMIUYf3jBTym3NUTMwiA95qdR1_1N-l4Yy7c9-X3UiRrVpNQ53lNuaUzdYuSq7XGHS_4ZNFwKXuG_dM7U2vhn_2dk2fkuEKZjtBYkVofStR8qlkswIAuEw4mrnt-wjG8cxrAwacoXop0R6NShjmWSrAhgqvAqwY3oR4HCPo_zaHSWjnJcRZ41LkVEcBSvtXqNpez2jYYmUkoGHgr_5gGpHpPo2j2lM0pBmPwPQ3OA8RJLEZYiQtabP7AKzZ32Lvsf35uhLRMZ6hkLtwPKgJ4tuR6E2B7xlZ6C0UoUbuI2Spou5dQsqPd6byXwHa22yViPpcpjeZOgHKK41cnK_tpL1kEe1KtodMW43d4OwHZ4LYqm8B769ob3uWnzGOMSGSrTsvci7gm00P0mwKBCh-XC1xdo448iGC7O_bvfYeBJNGsFObB3KqT7WLy04gc0gP7uWH629g151xRPzILeJUHsM_MwrFbNRqo9KbJFtGP0AQiQkO9lE-0VpWQW6ZyQLg6wByI-pPwakXJiCWxpxQF95NRjGOvwYyoU32ipX9mqEjdjQ-vTDn9vte8wPww0aPtAKqK-k0gkeBZAJYALVZNj6Oh0BUdA2t-XcMxs7Qho0V-LLgUjrmyM2ci71LgxeqO8I7LkOuGYMGYj2rFIGrzMeZOgucDhMyury4ELb50ohyYGjf5sOYavsYUwzK3NQwDZ3kjyHFSzCvgkuRgMLKxmME-4aRW8VbGLyC1f2hDuwxzL-cExk4yMh8TijVsf-bnRhHwmQKiR-SGkhrylfn-WnBQQffAdWpjscP9od0UJSPZrLZTaht7Z_15rMw9RO7vXl6PmcFw8vYciH58zUpU5vgq5_QGNvACSnnQxG8Nc9KmIYxGQyMow_ch1PBUP4yGYXR7Xwg0YiB6bwW5p_bxysCJAWBrp4sazb2Al3055Cfnmq9QXTFwFJo0jfbpqwPySuQ28TAiZah0CbCf_zdpJgz9hqM9HeRWHDwIKiR9OpxH2N8rWLqqRZTyfvRX7BfMF6P1bFVVagwhqljKZfcF7QFztlqKdYSGcsA6jdz1RT7B9CItJyKCnHgTYsFtxOr-7z8lkNNlb3xJAYmwYuSQszTR0nFnP4Inc_Ay8XVdmY-ppo6PMJztYQqZXB9wABGkzfKUl9UAIvjMrqHAw76sw28WTA3xxoVS64CM4YDs028hnVsL6euOe6VVBqpVMbrQ6OVi2FOR-vLbNAVBwbelAhbsqoZNMATg8bqlf3UMwacTkr_R1me2gDFv2BjxbjvlZUApzkl9L-CMnVPEsyb187O20chSrJhsy2tLh8SC_6_XCCnNFub3RAvD0BkNzDVZig_oC3ps_EEaPZgEdtbUb_GqaCFcbeo6X4wY7xkr1gZfTP_NHK8XyElajh_HP8T1fPmTZMh46rtXh5-54th6NQ_3jTjCeOfmLjbQKotLNOhJKlB8vXa2CsO575d2zkP2CAMGy9TU_ztUCfaGFOeFPN_xvz1vBZ7QqA-yA10tOdOm8b3oowPfMbZ2n5mvyLNG-DgUkjPGty5gyvJvyMgoqZao66fyzfLvM28eQMpOOcGAcozDFnW_vkffTU5GmPLUaG6rx74V32RVzaQKuC_nGBF8T_NfJ9NfecUw2uj21vCcUyTiIQb3Are8aZLnfsi4DyY-E7WhNnBoLsKZO1CzurCYKCPi4KYGjTr9og_MQM4frL9nez4teQDdUZnu3TkTqF9jRmeFMpZNLaRydPWCmumrCI7HSwb6PuBmsswxPi5Br_NcjszNq-c3t5_Gj8klCceJjDak7wjMuGYSK1GU34iRlNW7iUYUACE4FApDJciqJcRXE31-S_b7IsZ2xcMU4f0Qf1sWHuKKRiwG-Wx-AhXjDSH_tbhauB0P3JEAFg0eNnsRBwUvrYqzPRKkAJz0AUF_biQ-s3czpmmt77NBxh_IjIfVbfOs8QbHM1bgZqUzhS1f-cFLcrEypLHL49Iuy_qXlut79gr2XBsQ05ZIQvOtzCmjZ32b_P-d8oeGzW65rwq0HovxMWxwR7zHqoZD3KJ__a72HMcwK3-fYZBzjMjxOHlBxdzmy4_xsfUBMWxuXREypfY9cb8uuALpRJCebN4pIocB59ShZgTtApb2GVk2jheXHAMx8-7GAUO_W8mzJlaHtrdJd1QYFME1W-_bhfJkYJW70phqUcvVDjoBGHiiL6TxkYAFwCNUhJsvnIG8Ihm09t8TKmcrPx73MVG-euP6T1ZIVL5FFX4kOqSZW2gKg_cUr6xUhuey3sVNd5Qfl_q3PHNHVif93EpJ6iac1VQ6soW9MwuNpKURX_r6WWDx6kyeTXKmbE_6Boe4jSTq_BKYY_SYoZY8AIOrGmKBV6wemc7hR8ko5yfH5_T4V7rwHSPotueN02Xb7qAgizPUxwxuMvwiQoqo6PEI6V96_iRvTCso0mJ2k-EZ7e77Wo3X4A2EjH1ciljhDA2uQAh5QgGUgVI3QfGiaDFrgeQQOatOd-zqvM1j-WB0ZBpjYFR13O8N2ZqXQQ_AlWOmx60LQI79a-BIZb_UBzkpMpR-bsUlFq_CQv9o4cxGU3M9Orwsck_5a_V2Mlsicz8ThvLz2-MaoQvwnU3Zskde4SyRQlqMYSThRxSc1kUBsDDWgBWNrvpeVDxvLAmc8XVR_xMgCiRcyAvrv9kG3RseYoD--fqyx_YpoAGleoG4jA4FFkvZdE-MEN3CSuML2oOJAsMNgAG1mNzkbeJO53oe6qrL4ZnnYHQyayaxSMpi0FonMibsg6pHn8EZ1vKes2W9ljy02W8lfTxnaXewF5qX9uKTnfHM2s9MSdSasJCLagPDjA5ZtsRcwBMpZ6LgJuT6OZsvYyWONDM2y-BdUMN1iiIvJXaRIG-smszpElaZZimJUSPKhO3klT5LH0mZRWL03AnpauWNRdZNZhWJl7sum2bEulbxe7_Ir0LvN1IxUTbDX4TLTDwPc4vEpouKM278KKxo8idZlo0Sd-Azwu6CAvr0uIs0Vs6SqKWWvyC5B5ZmJwxJ_uEFphVW1WKxUxqhSHadoLF95BtwU23ayhu7GV6ZbpgkS9JBETCsYY1xZ0W_A02jv6SsSX45zEg7wJVgKl_EgWBlCw8QCxNirmpxcYvEbikYIBz1NscUBlLnGNIpGONVzrdtmBOkkikw0Goot8ixXePS0_7Jm1LavQIqhklO2SZ8Ve90UZCf0cO4NioF9S58mYFxQ5M4UAErTkbH6LOpmk9I3OhSUUgDwpYN9FWIc__JoAvfUIqvgxvvU13DUyTjdyWvcJyAd2qN_TqSQRreY2fiieLXTEDsZwMRy3qVKQIXVc8wd3hiztuO45EXMqW6ho3OhXFPiVhXUzzt6YJ4SFO5_yPLDOLQj0t4jOnjdvAOnt0gdiC8VSZaugxZTpQFSDPD-skDmj0CAZ9VUJhWNUnkRK_aiclAf2rouiJ1Ot9APUEtXlHR2ImVQSrepMEHDJz1ijCH6QUnkX1aTYt41RBZiEa09207Ow8X1BtTrhofjxAyLzVhEqg76sNiXHhP7J9QAYhxctefmDgk6ZUHqIeveNDeKKfeXrW2UzlLBl6S3xW1xnHBrHxp6wcjngqih1SG0eqfXWgJ_mEg9lOUrbDttiTJbTE7_XhZ2vfJ7Y626u0J6Iz7mGcPa3nCSgzskbBKQflfE0CqS-N-AjTirwU2_7Lb-ofMmbd-rWludoNtNwzh6BAKFVs66rHa-VrWSwoWR-2mMD1GD8WzsjCN4PvgTo5mOGlltDDkWROl5ibhJ-tLyAeZ4mtK5f_oVModXQtapyXA9GEoktjGtoFqE3BkMwk0i_P542lOJ3fNGI-sPyfaWRQXx56wxy470_0dwy_o3aSvJdetOxOi32BfEqfPN-TBNU3MkX_bt0FTMcXjOltnoGh6bgZI8tZ4RGHof9yBLhqVsW9aQ8LN8amNJg4JCsO75vjpW0nDgOk6cKeadSWjP3fBJ_BEmfFkDgLfGeZ_ILTxpzJ9r7yCGPdFoA1C5a1i4DT-3A0UD15W6cpgdfAYRF0Wt3i4UDopGFpASyM1_TpKBzig_iy8j4yM6qUwSShEQiGDdNohlrS2q0fS03Rk7EJEi9wFLB6GPvm4hqJoCes22TvIN14fjz8udTQXNMVEbanKdhMgckZ3sjmAakOe9APmpTbWJ0GNVXwGoErrwLlaptkA5BIk2ZW3OcRWykaHZBnCgf2dNb6II7Mjjguw6H5_J1oMqJFQqIlFnxK5B4nvDzQ-9-lLIub0QvWlPn3jxTkZXBO2rrhBwUUDlZ0NN6dtl79XwliYz0aOc9gnfKptmei73V0WXP8qrv4v4ISgRCjytAC72Uao_QoB86j0jdNNuJ-HUz4BGCB4k6pr9rkOwdwd0PY5OfJbDO6PxqiXNO6unt6IOaIoKEhs0rxpRA6GzyooaoLrVTYQxaSeJTa8I_pwuILBgUSu99DD7HhbQwrloBN7ststbloZhT8cN6SzQ2nBbU_LxnroDH6GTrHFPruSt-5jY-lj9GEm4AFsRwQrXgcL_VMzPThUdbYDOMouzuACn9xdz2bhKcGF20DlLA06ZdtWQfOeYHWwFbmUR1FToyVsUkH8Y_V0vzEDLxzXnVS_0xumFFUXltD9kp4guS4W-MWAFa7hDRBG701kJNQXZqRkzHKqpLNgAdUggl59qrgqLbFtTtco2jaj3dmuPBQFppJL0Jbms5I6lDayWkpqxURphQ7mHtKuodiEmK-srvX2V-X49zV3W_wjAdKQzIZH7qyYNud9QhOO6kBrzhAueZModu_lcYU6SaKZ_s_jPkHauZ6lB04rihZnkpF-vcRVOARctFnxGLOyLQ5zsMxtZ9HIm_s7sRMNQoKAVSaGbgH60Vp9P4yUaHZvwIOfC0cJOynP0PZ4hL-5vjkMwsfYI8rvoyg7woA7gbff9UCQtZG4W5nNzR_06goA9-G9c1DAA__-DxpDpaM68LfopLNJoendZ5jNUEjAmGQBhvPHce4WISmsxtXXonFbZQUlja5KAw1nrlPs7QnkECMPBnwzCC9dj5_8m6ZOieQn0RJPAL2vd-3wSJ5Hdndz1O6wuJVRjdHFAoGFq-azLkSJsRfimKwzPorGlUaaHd1KXZAtKVAjgRKhBVN5iHRgIMB573yZ-gD7syERLNECujzRQnSZydBPLAejqmLcreLecByKa5M0e_vN5cxjNEraw9hCg5UzCCrIQ06Xn2S50s9l6V5g9c3IuAE0u-7OVLh0CSqV0aKXg9UOl5E_9n1kn6FA7bYfEK9oUWP91X690oVqobM1EZlUoBdA3drz4tNAsp0zCgG9SleiPCzzFURdTGlzDPKvzk5V7EWiSZf5Mx4mLTJtABBRH-ovoSHLuj0L_mtlTTpXBfyHXV0KdljQ3XQAl_CRHr98HbliFTonvLQLfal-vWW7KRX7H0TYYhPFl0v12_IVI9eae5QvmLLxElJuMYnTuvauewwMxjLSovOsxnIKvaTTDBGclEKpXOOY2sDHpamRKxm9lJLi1Cpwz-6GLdUM1_v97xFGyrlJBqDjLap_c2UcDTPU8EcPiBakEVQdkmNBhz7d08PUze28JH226GnIS9_poHQfroLnxo8RNnOJqFgvMa3xb3Gd9lmGVMwvZuZVsELFnXshva46Zouz6QZQ8V7O9mRDPI4B1oG2eGocb_E74G9i4hWISG_CrOiWwWFPaChqfIbLqFJbxTWRpv30iqmD7IpLgr4hMBMj8MujxlI1BqhnhotOfvOksRkCtOmwpofL0l4YGiJ6cCtwD7ALgzLN4_nTVXR6ZaETLZTqpAfx7z7INvRDuzeSsMdFcWTlLPCsA5WrSCKMC_jtUUAyPktcEKJ6QdLNmhwZmE4FUNrUcjSYZim-ZNXrYC3U5SF9WbsbeQ4G0Tz31JF5ls08RRzsCBCQGf-TKz2PR_hMD-QUCFwhgJkw3xqqy0MONTtECZDHLUiiL04IyK-MbWtV9BIMa7B3g-q8plZ_Rwroj83CoMQbJWb9Ofe6RM_87NN1kXoc8muhMHGZkUgmq_WQMayrSiq_L0Pm2YsJOaGOyJ4sHHd_R6-OlJ6zR6W4qU9bmJSZvF58Z6oshhPQToUQXObEB0E78alCmrWNYSrcXuMqyhzVToGiAdyJoQlBrpjCAR8Ra8_wYx-8EWMzJaHXYG908knfMALVUE51f8J0AAjB1JmVwZbehBhxJrwzgJo3gmLgWNBPvItPgq8HZX8oXgM4d3PwlNnUF6IsPMsyHIYFfnggIKTHv3Mz1QDTRHJ-SIIGnEHtHiUZojIQJf3CUG_UNZAlVL-qqj05sjZahdueLVH2bVYe3Xa75AuN5v8hoUdbeQfDY1LcNk4yz4SLnss5owSXvK_0DM9V2y510RrHmBVLx0GAo8TtgpVd7Vle2TzNeUksWkmCbYsgMealTceOPQsuDPQ5Ie_1kBss8qiz727fst9SueE5hjHe9vmB99Y9O8W18a7TwRedJv2M5RbxOVhq89bXUBq0bbfVoJ5l9t-1YL4-YKESmj529Bcy71_yNzXs8yRJvSUOPhG9-z5aWonPQI30QhcJqtHG_vtAQE4kT5oDEpujitzwdbQYtntGemNGQKWNYV6CLpi499KfZ10jdeHSkbRTZFjX5J7mffEwBVBRHbptsizL6fGCdY3KkFNKNEKU_FRcYgPSyrzRe4koB_Q-2g2yvHBYqghqLsmTMcahnki8uBB_H-WawnjX0jJwKvP9_azFkvOzrQUBl0yCuklM8npNEFAjVVS_h-jQ6Fseb-lyvehp63MVFac__nIdrYoVnOi1Yihb0w4A7Xt4QFtxyfCHnp1re9zisS4msZm0dfb3s-VRRFQ8VeXWazEIUtDc6QhBiTVaOIZjCOrAOV-BCDhnKPKaJ2gK5R0QspQes0EMt1jpPhgqX6Bvxsj-SMyyKZBr9mkAo1pMb4eJw6sWWchEhXQGQIArBDezuQFEa8KbOFoZ8mohCSLZO3pANGJaE0iEB9Uk-y0ftAkFEbzf_lUi8VHa7hDCqLCOvc56isd9MfVFkMWEhbiSaUhACAac75qp63Y7VVRZAR46EfrrIHvTbFO7yebBTxgetKZc4umvt68EUWDfGqVluVWealK0t63CgYo3dk_bnaQTWxIP8fpIJjgchJjie8luPDR2ZzzanU_TMK8hdE-5iHokVnSHWCnJ8TOI8qrRk9YUPCQof9B3I9pH-KJjBQmgo2SurVLFv230SUdrgs7n4EzBYu9GNq9ryakhwoQRLbQsN40PZJuXL3YSBm4Uprptq5-e_r-FnLIk_OcMUOCv6Vupn9-pqWLCc-mTpJCUdduz5Ht8Ecb-plOc0owN_dzBDgdlzA3d4UpAk_2PNmeXRv6e_futRtKRaKJwY0q1-7XnxHpn8PqmQ1sBYVkLpEOeETh_FlSXwcK1ie10hcnE1H988srGMRCtwgPiU7gAGZPuiXq5aaaGEklYLxEvaSRkASWrIzoP6yqk_FUk65o1Q4hqDCMJhXNSnxaYNgRunsxbv4e3nevbeuuaYHrjyrhPizillKvwwGfckmOv9Y25BZSUXMwSVK9Ad3XA98NajHK8rVoiTRa1fjfBXUwVoce2JcVhuzk1zR_B3KixTZCJl7TUT6ajt70IQA-EsWfNtxdUrINMgm0ZjJVkG3ccM2MVQ0v85VUDwMEqcF3LRFAY1-6Rt0shEK9H2HSvRC-jHBl6xV7DQM0OEuWRvJAECkbRTPDs-XbZhqUQJRRb6XMDZsqeX9tCS1MLyMZ1IUQlRIj3d1auBzc6ICfraQA-cMcAyxofrnaRwhZGr__gns5coe8-DQ3YzNE776gzwLAg5k5M-3WEGJY-BbRtde7opCZnWZWLK9tezTy9ws-qLiIeOlRUu5xSnfwuy6icNYqvWvAN6FwAz2m8F56m7RrtigY8JKwpSk2Jkz2XknkCdv-yaFl4PIZoeRF_pmLSi5jSyP4-ze0owGzmSX0CIRMqZYSsS7D0d88U0DWFFupGK4Kg_I4TPgjByoRH8hZrOcsKvmavJktXN-beunsA06WH8opv2jya9gZkxgAiFIifJBVgEDM5bfFtvfD6N3QJE9TfcUPNGoFqhvEBYzVgQnj1IPrMWBEjBrhc9iCnCattATNc8LVlYbHZ3514DESdjISCctsU-fnKuLN-W9tOdSYEp4xi3phiLD3TLI679uQtifBlAYAPabNDe8ZiwI20jl5REQX10lHjvnPRK7mLHxt7PkOGAcd3hVH_w2KzrWdpf_-DM36G6Lq4HvBUH4BNk8zewp3qybZu_V5zZ2hALyRv7Ibl6pULmyoscJXJoFzBHGDr8rqnazTAwFTWVCwxCskGHkw5DPDGsm1T7ILIgAPEveVdLmmnOP4rXI_o0RGsi-nQxdavHPt67-YWOFYeNWiy1AlNlra5DvL-hfDfxCNgrvG6BbW8c7xEhoFvlR80wgfwPDckjd3U4RjjiiUfVsvgf9bx6x9-cIzlxwiRBzVMnlTPXOwqAsJ2H1e8-_tKTFjFkZuYpVRFCf5Dy4xFcvP2rHtHXE3G_ZGii_M5ZwlrBkfmVVO19lazSqpe67rPuobutmjt1bK_A8B2plrI01cZ_B9yOMzrVoZJebI_cs2Eam46VWfOFGTMoJwzLWmwmF4jt6elLw17Wlrv7yW6RoFzMVROMfRGksuezBufgDDKgpK_aX4jWJpldlI_pNRTycgieG9xHkWPsslTUPFFQ07yNArqB_9ERbiZv_4ljva8O2U4lSmi_CPocI_Gf899EBvd7QmlGl7ZswYlb-VrfcfHuSg-eV0QUH4KwQDvx2qBxL3ng0bxCBgiNsOFv8Kot9afWjUA4YKpvoHajsai91iOUEJ1KBfd-GGv_l3M9OoZtpnXre5twKtdCfllAuLcmH4HMAW6cPX41sFdFf2wwk4aaTic4f5_TX3-dSk6_epKwdmjjucflHtrFp6c9SJwf_aB7y7XYnoq3DvveOtT8LqPb92mIsSwvkxd0E6CVw2D0kpUsD8t3wWz59IeaSuGdqzS_7DCBsk240J2F0L-bAi1UmwtJySyEH6gGcb2wzuekUpoL1lbk8NvOFhqGMskpzAW31X5KlAIB5fMqYIechq2qgUTX0fbFbbK-WOS5BNuZzQHg5u-x7KCsd4M-i0-JQtTNyHDQ9_6GICe3RAa1au6QMk3bbuEeX6p2rkQNIaoaP4X4cayBr_0yu1Txn9PV28js9BnbryxWauTjYYSz02CGE1kN8STnQ-ebpq3WkorL8QcPw7VJFDRytkwSz_AslMaxmoCzvftC8nxZgEveO027csojiijwJ0gpDZYvyhMgNcPhPaLIEJrVSWkyMnkt7Pu3Y2YotbyxyjnySgVgUhvU4rplk9cHykR-1KIdnyrtAmWD1POJhmmtRF0wbMXWPg2zp4LPvH1LRywS1Si6lgMCGOMXRfOzbm8PYJDeM13j6e5PrX78ZsaM_n1Y3cDfew8Oy5guR6ja2TAzstADnEs9-ieIV6xIgARP4tLLi5JSMSDKlaite-kt4Os6cW6ZPm3O3rUthnWq5vHRByyhVEytS-ALARuaoZdc-yl0RvQp08jXqnqueILKWdaRWXJveMAB4XenxSGeCVffEuAm2HdhC0EVcS3rimTX4FSGFLOD2cUNXoB7ywSDnP5VTZ-hQKp-URDXx3YsCj_nXwyIYC4EIUN34i4YUh-DprUnNfJqW9Ev3sfByzjyNS7W1a1htCgXckmy0XBY6X8bNswm7w1ptgpLU76NGOuu1haWJp-LPwxXgDEkpG2tLQQsCKedet_QiBmarepWVN1j9ZIkDDwQE5hwRNrwRgHyGIXk-mNcXXF1gmr3q68XEt2VEur6grCHA0CN3dy4NRxuoS1P-vaRxLl0Dl9Iy7lIGoZaKP_MdGdiotIZdnxe08sBWUvZGdUMg0gpEAn6CegsiuQbLCqT1KuPoMNLKnh-33zrHA7Jo9SqxZ-xrRpwhj-bTeL4v9WgALcRO22E8vhFrVJZICjEBwUv6rpo584dUhoxWlwC3wNo8VRp08Hkbso018pjErTyQ7Is61euKF_OxAvYmHgyZVb_IaldqIHSelpu7EQaaFtvLJSiA3XOIpD4O-rZeimfmS6tOOYQad2TjTbrO15c6AY1OlCWsWAbUGQ_8NGmAijI39Vfcy1z5DJceiok_1_Ao2jh82tEMflNeI6DVEe01zDeZvTHimGVreOj7P7a8Turi7VbzP1VlxrgAxDWZmkPWRxIzfrFjfdMM21KtCE5M1FAqX9buLWcCO-PYmQEjb3_34_g5jOwywcmJXB2LVw5H1d0LpnoBrZSYi52lQaYM0pUombI4jqfrHuZUemB_uYWMdqogdGtyWr23TJeUeQg8BfxtVzjmyw5lbCwH62GSDbpyjzCv3Fn3WDq0qrjR_Xwmj2B9bJR0SgWZhOZm9ZudUOuq3VEZcuaDNvRtmUGysZWzRGRAp3AxolKhk_gTywGIytH25Hj0L28paw0xjmN8YunkxNVbegg8MnXw5l9G8SXNPhZJYKZ5HqI5XRsbwZgvJvSHy5V_G8Ie9YLVrbpoYkmT0j7ErSHXh4BQeS_zbFJosev3fmnxJIEyTz916SACv0s1ocw80aohgzjK8N8eDz5FJ2JQIBZz8TNSYmfFX_Uv93_ZwR0mOAJ2QkKdv5maUC6JU_SSSmDCqcMwp1u4-AA--Z0rSCXGHWWkdZ4vWhRbxFkCQs1IcuSQn2-OxNBImLxvxmhS8XDBKFfm9t8B6ed4TjupnNn6x0BWG2BtJ0yk7Y2ecj8XMQaiaG4MKRdUd6i6xOz7GwmtSA7ckNZef3_B-XA-vw7kYih6vhIf0sRdDX7IK3GVrsN9LbhmMeswEQJteavZGwDWF-piCpBMJ4LWcwsKI534unKNAPhzVPIiczSD1gM8ykZnxVWZYfX4Gd5TC96tdoQq9Z9e-d7uksaInDQr-NSo9rMPPm2quIe_GUEeqzvRHVDmaJkmP-4CeMGghGHQHozDXavc8os__2len8ZFyVAKnyHfhn6D7eo4aHnPL3J4frq7M6SLDjdvunW9OCmROtmSkXjvFwM09w95KEcroXJBkM7bsA-Z6KU-uTwADINUA4TH3K3Y7R0oRmCBtWzT_mQaIE2fgqbwyI5ZhmjelOG8QZYPCK9OtqYwNw1pHDFeHHM9EcXrux-jfccDUJ4IPdOKGOkPurJx7EJv_Ed0sh1IKaYzNRuvsUJGbVU_xyb1nef-Fic6P38JCrC7EYEzLKdtKNCFTacUn9OO3Ygf9b833fcjfG0LYWZeCINxKp1OeGsOTd6am8kwL9Dwx41BbBRHHxb2Fa_w8oneZ5f5yQmHlKvhJ7Rh6hUEYWDCUOG2njMVe0BeI9H8bxzxeWZI4RCXYa0sbEbCqk30ivJI1pdzYuuyk9cc4qUbsPdIScAcSXk7NqBlS82Lz7kDtFjrRtNOVhrjpjlKV-a9W6-rPB0U2savy6xjp-e7yPL_S1Spt10edRjtxHt-AvX3qh56EJdILHPX1MbxFol5LhH9evz_dw2Pe9gxOTYS6S58qxcxX4Nb-KfXngnxaeJ48SsKN-TKi2TWntVLsjDBLPUO1LXrFw8_ZjijdW9j0SxZkOEbnvI3uJ3jvEVxMxUojlfUh7TvKdR209jBuO2ezWcLt3CKfRG6Ak0FjcugJ8ByMucCG5mGMOB7UyWCTurM4FvTeHHAN20C16LRkZ8VyANz-Oe9YfYFO9lrofS1-3jm8UoZ5AbIjCkOCAdOdVEo8RBOh_P8wOTVaYlURHOfeXniL51czYw3UjyIkMftiVXghc5KAWhwrqOkeTPDa3b4zImVqd00u-fsVl9_-c25qR-K1UaiwEEvF0ZJK1TTjMNerCVNezaycd8KZ8ktdaqQD9bvx3okUSpKFZ_WZtgRg4oOlf7ac1ba0PUyigxms9I-9f6snYfzyefP3elvMXL4KpbcDfDcxEWrwFiQ-xDSHjHLrve-irM1DEbgNY85C4XciSOq_fMVut-s6GulegmFjJYOukwLjpLFrEEaenpEKKQlN0upzQcHmdUm1XPUuOFrevg3IMzIpYoYjpsMHtJPXEhViPcpt2uwwRH6gWGtt9wX1KFlYeES1LfdNYBgBA4myFQwz8TR3EeojBxTwtW_pIX5P_A0byfabD2BCEKDZwmgiLfSA25skSB57d2WllO8GkY0pdKBkprewSBb9rqcrRDIk-wd_hSX5NGSnlUGY2-hU0ng1erQeYamS5pYw-BUVTtka3WdDIK4Xg_-RXXg08hfdruAZT-QNBr4KhSVX1l_W-BACPuXirWu1LH12Fu1LQ7X168GjM3ncmfW1abNU6auYfJoxOYTvditijm4SHidFcLNNOYGTOe5WkNNUMKhfjPI03_ofrwmbC0XZvgrUdRPNLM4ocIb4u9W6_LuDRcxd_pnv061OvmBXLYjVQx_O5sscdftVxVj70DaT1Xt1CI51THYtlr0iA_r-xYFTYEMBvNOdz8mzQOblwbeLqnhFWvkcjBj__0K8brz9WTkKJDmq1JPTkG6h-hjPgAcyL-ayVuWJ0iLlvXObqalnNWZ41zyc5XG2uOX2roF2EMOwjZ4Io5eAnhR5ZkhxBJTm9egvFyZ-sU9ibMw4dglZ-_mESgmo6AF7UKR77czR_c6gaTUOdu_U=', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de', + signature='gAAAAABoxCyzDT6i7ehEoWDBoDGMZmLcOX8TMbvBssJGa0cA0-7Dy6YfH759wsF0Dn5Auzz8Mp2geHtbVJVxKa-SF4Al-z3lq7gQG29dTf2ecfq_6bkg1gS49MbGEmaLo4FnS6_5oekdntomcOVO4mqwC7JKnCTO5Qyq8-Nm3POi0nOZm6KaEfqrmPHiJttupduQBkiqHIc8_CIfQ9LGqSxXZuAFQ0DbNow-6yya7_5oNOoLdgWti5_n9CENxTYyvG_q-2WAmioZM_rR54rWqmMbxUNNsKJls8xx593rb4u2dEpFJztVeifJNmFnDcYDDHMhvqLdSXJU4z3Yrxg8hgH9w2gD7Ygu2UDsMsiUdp5YGXKx_acJeu81-7H8Yf3XY86woskIv2o2XaegpK496fKkeiUAD8OTGWK0hjJb9KPK3hqTBfRfJzafQbIvnNTwOod3ZPyClgSXTYKsN1E_j3S6G8R0uzyA_NBc47Q-VMIUYf3jBTym3NUTMwiA95qdR1_1N-l4Yy7c9-X3UiRrVpNQ53lNuaUzdYuSq7XGHS_4ZNFwKXuG_dM7U2vhn_2dk2fkuEKZjtBYkVofStR8qlkswIAuEw4mrnt-wjG8cxrAwacoXop0R6NShjmWSrAhgqvAqwY3oR4HCPo_zaHSWjnJcRZ41LkVEcBSvtXqNpez2jYYmUkoGHgr_5gGpHpPo2j2lM0pBmPwPQ3OA8RJLEZYiQtabP7AKzZ32Lvsf35uhLRMZ6hkLtwPKgJ4tuR6E2B7xlZ6C0UoUbuI2Spou5dQsqPd6byXwHa22yViPpcpjeZOgHKK41cnK_tpL1kEe1KtodMW43d4OwHZ4LYqm8B769ob3uWnzGOMSGSrTsvci7gm00P0mwKBCh-XC1xdo448iGC7O_bvfYeBJNGsFObB3KqT7WLy04gc0gP7uWH629g151xRPzILeJUHsM_MwrFbNRqo9KbJFtGP0AQiQkO9lE-0VpWQW6ZyQLg6wByI-pPwakXJiCWxpxQF95NRjGOvwYyoU32ipX9mqEjdjQ-vTDn9vte8wPww0aPtAKqK-k0gkeBZAJYALVZNj6Oh0BUdA2t-XcMxs7Qho0V-LLgUjrmyM2ci71LgxeqO8I7LkOuGYMGYj2rFIGrzMeZOgucDhMyury4ELb50ohyYGjf5sOYavsYUwzK3NQwDZ3kjyHFSzCvgkuRgMLKxmME-4aRW8VbGLyC1f2hDuwxzL-cExk4yMh8TijVsf-bnRhHwmQKiR-SGkhrylfn-WnBQQffAdWpjscP9od0UJSPZrLZTaht7Z_15rMw9RO7vXl6PmcFw8vYciH58zUpU5vgq5_QGNvACSnnQxG8Nc9KmIYxGQyMow_ch1PBUP4yGYXR7Xwg0YiB6bwW5p_bxysCJAWBrp4sazb2Al3055Cfnmq9QXTFwFJo0jfbpqwPySuQ28TAiZah0CbCf_zdpJgz9hqM9HeRWHDwIKiR9OpxH2N8rWLqqRZTyfvRX7BfMF6P1bFVVagwhqljKZfcF7QFztlqKdYSGcsA6jdz1RT7B9CItJyKCnHgTYsFtxOr-7z8lkNNlb3xJAYmwYuSQszTR0nFnP4Inc_Ay8XVdmY-ppo6PMJztYQqZXB9wABGkzfKUl9UAIvjMrqHAw76sw28WTA3xxoVS64CM4YDs028hnVsL6euOe6VVBqpVMbrQ6OVi2FOR-vLbNAVBwbelAhbsqoZNMATg8bqlf3UMwacTkr_R1me2gDFv2BjxbjvlZUApzkl9L-CMnVPEsyb187O20chSrJhsy2tLh8SC_6_XCCnNFub3RAvD0BkNzDVZig_oC3ps_EEaPZgEdtbUb_GqaCFcbeo6X4wY7xkr1gZfTP_NHK8XyElajh_HP8T1fPmTZMh46rtXh5-54th6NQ_3jTjCeOfmLjbQKotLNOhJKlB8vXa2CsO575d2zkP2CAMGy9TU_ztUCfaGFOeFPN_xvz1vBZ7QqA-yA10tOdOm8b3oowPfMbZ2n5mvyLNG-DgUkjPGty5gyvJvyMgoqZao66fyzfLvM28eQMpOOcGAcozDFnW_vkffTU5GmPLUaG6rx74V32RVzaQKuC_nGBF8T_NfJ9NfecUw2uj21vCcUyTiIQb3Are8aZLnfsi4DyY-E7WhNnBoLsKZO1CzurCYKCPi4KYGjTr9og_MQM4frL9nez4teQDdUZnu3TkTqF9jRmeFMpZNLaRydPWCmumrCI7HSwb6PuBmsswxPi5Br_NcjszNq-c3t5_Gj8klCceJjDak7wjMuGYSK1GU34iRlNW7iUYUACE4FApDJciqJcRXE31-S_b7IsZ2xcMU4f0Qf1sWHuKKRiwG-Wx-AhXjDSH_tbhauB0P3JEAFg0eNnsRBwUvrYqzPRKkAJz0AUF_biQ-s3czpmmt77NBxh_IjIfVbfOs8QbHM1bgZqUzhS1f-cFLcrEypLHL49Iuy_qXlut79gr2XBsQ05ZIQvOtzCmjZ32b_P-d8oeGzW65rwq0HovxMWxwR7zHqoZD3KJ__a72HMcwK3-fYZBzjMjxOHlBxdzmy4_xsfUBMWxuXREypfY9cb8uuALpRJCebN4pIocB59ShZgTtApb2GVk2jheXHAMx8-7GAUO_W8mzJlaHtrdJd1QYFME1W-_bhfJkYJW70phqUcvVDjoBGHiiL6TxkYAFwCNUhJsvnIG8Ihm09t8TKmcrPx73MVG-euP6T1ZIVL5FFX4kOqSZW2gKg_cUr6xUhuey3sVNd5Qfl_q3PHNHVif93EpJ6iac1VQ6soW9MwuNpKURX_r6WWDx6kyeTXKmbE_6Boe4jSTq_BKYY_SYoZY8AIOrGmKBV6wemc7hR8ko5yfH5_T4V7rwHSPotueN02Xb7qAgizPUxwxuMvwiQoqo6PEI6V96_iRvTCso0mJ2k-EZ7e77Wo3X4A2EjH1ciljhDA2uQAh5QgGUgVI3QfGiaDFrgeQQOatOd-zqvM1j-WB0ZBpjYFR13O8N2ZqXQQ_AlWOmx60LQI79a-BIZb_UBzkpMpR-bsUlFq_CQv9o4cxGU3M9Orwsck_5a_V2Mlsicz8ThvLz2-MaoQvwnU3Zskde4SyRQlqMYSThRxSc1kUBsDDWgBWNrvpeVDxvLAmc8XVR_xMgCiRcyAvrv9kG3RseYoD--fqyx_YpoAGleoG4jA4FFkvZdE-MEN3CSuML2oOJAsMNgAG1mNzkbeJO53oe6qrL4ZnnYHQyayaxSMpi0FonMibsg6pHn8EZ1vKes2W9ljy02W8lfTxnaXewF5qX9uKTnfHM2s9MSdSasJCLagPDjA5ZtsRcwBMpZ6LgJuT6OZsvYyWONDM2y-BdUMN1iiIvJXaRIG-smszpElaZZimJUSPKhO3klT5LH0mZRWL03AnpauWNRdZNZhWJl7sum2bEulbxe7_Ir0LvN1IxUTbDX4TLTDwPc4vEpouKM278KKxo8idZlo0Sd-Azwu6CAvr0uIs0Vs6SqKWWvyC5B5ZmJwxJ_uEFphVW1WKxUxqhSHadoLF95BtwU23ayhu7GV6ZbpgkS9JBETCsYY1xZ0W_A02jv6SsSX45zEg7wJVgKl_EgWBlCw8QCxNirmpxcYvEbikYIBz1NscUBlLnGNIpGONVzrdtmBOkkikw0Goot8ixXePS0_7Jm1LavQIqhklO2SZ8Ve90UZCf0cO4NioF9S58mYFxQ5M4UAErTkbH6LOpmk9I3OhSUUgDwpYN9FWIc__JoAvfUIqvgxvvU13DUyTjdyWvcJyAd2qN_TqSQRreY2fiieLXTEDsZwMRy3qVKQIXVc8wd3hiztuO45EXMqW6ho3OhXFPiVhXUzzt6YJ4SFO5_yPLDOLQj0t4jOnjdvAOnt0gdiC8VSZaugxZTpQFSDPD-skDmj0CAZ9VUJhWNUnkRK_aiclAf2rouiJ1Ot9APUEtXlHR2ImVQSrepMEHDJz1ijCH6QUnkX1aTYt41RBZiEa09207Ow8X1BtTrhofjxAyLzVhEqg76sNiXHhP7J9QAYhxctefmDgk6ZUHqIeveNDeKKfeXrW2UzlLBl6S3xW1xnHBrHxp6wcjngqih1SG0eqfXWgJ_mEg9lOUrbDttiTJbTE7_XhZ2vfJ7Y626u0J6Iz7mGcPa3nCSgzskbBKQflfE0CqS-N-AjTirwU2_7Lb-ofMmbd-rWludoNtNwzh6BAKFVs66rHa-VrWSwoWR-2mMD1GD8WzsjCN4PvgTo5mOGlltDDkWROl5ibhJ-tLyAeZ4mtK5f_oVModXQtapyXA9GEoktjGtoFqE3BkMwk0i_P542lOJ3fNGI-sPyfaWRQXx56wxy470_0dwy_o3aSvJdetOxOi32BfEqfPN-TBNU3MkX_bt0FTMcXjOltnoGh6bgZI8tZ4RGHof9yBLhqVsW9aQ8LN8amNJg4JCsO75vjpW0nDgOk6cKeadSWjP3fBJ_BEmfFkDgLfGeZ_ILTxpzJ9r7yCGPdFoA1C5a1i4DT-3A0UD15W6cpgdfAYRF0Wt3i4UDopGFpASyM1_TpKBzig_iy8j4yM6qUwSShEQiGDdNohlrS2q0fS03Rk7EJEi9wFLB6GPvm4hqJoCes22TvIN14fjz8udTQXNMVEbanKdhMgckZ3sjmAakOe9APmpTbWJ0GNVXwGoErrwLlaptkA5BIk2ZW3OcRWykaHZBnCgf2dNb6II7Mjjguw6H5_J1oMqJFQqIlFnxK5B4nvDzQ-9-lLIub0QvWlPn3jxTkZXBO2rrhBwUUDlZ0NN6dtl79XwliYz0aOc9gnfKptmei73V0WXP8qrv4v4ISgRCjytAC72Uao_QoB86j0jdNNuJ-HUz4BGCB4k6pr9rkOwdwd0PY5OfJbDO6PxqiXNO6unt6IOaIoKEhs0rxpRA6GzyooaoLrVTYQxaSeJTa8I_pwuILBgUSu99DD7HhbQwrloBN7ststbloZhT8cN6SzQ2nBbU_LxnroDH6GTrHFPruSt-5jY-lj9GEm4AFsRwQrXgcL_VMzPThUdbYDOMouzuACn9xdz2bhKcGF20DlLA06ZdtWQfOeYHWwFbmUR1FToyVsUkH8Y_V0vzEDLxzXnVS_0xumFFUXltD9kp4guS4W-MWAFa7hDRBG701kJNQXZqRkzHKqpLNgAdUggl59qrgqLbFtTtco2jaj3dmuPBQFppJL0Jbms5I6lDayWkpqxURphQ7mHtKuodiEmK-srvX2V-X49zV3W_wjAdKQzIZH7qyYNud9QhOO6kBrzhAueZModu_lcYU6SaKZ_s_jPkHauZ6lB04rihZnkpF-vcRVOARctFnxGLOyLQ5zsMxtZ9HIm_s7sRMNQoKAVSaGbgH60Vp9P4yUaHZvwIOfC0cJOynP0PZ4hL-5vjkMwsfYI8rvoyg7woA7gbff9UCQtZG4W5nNzR_06goA9-G9c1DAA__-DxpDpaM68LfopLNJoendZ5jNUEjAmGQBhvPHce4WISmsxtXXonFbZQUlja5KAw1nrlPs7QnkECMPBnwzCC9dj5_8m6ZOieQn0RJPAL2vd-3wSJ5Hdndz1O6wuJVRjdHFAoGFq-azLkSJsRfimKwzPorGlUaaHd1KXZAtKVAjgRKhBVN5iHRgIMB573yZ-gD7syERLNECujzRQnSZydBPLAejqmLcreLecByKa5M0e_vN5cxjNEraw9hCg5UzCCrIQ06Xn2S50s9l6V5g9c3IuAE0u-7OVLh0CSqV0aKXg9UOl5E_9n1kn6FA7bYfEK9oUWP91X690oVqobM1EZlUoBdA3drz4tNAsp0zCgG9SleiPCzzFURdTGlzDPKvzk5V7EWiSZf5Mx4mLTJtABBRH-ovoSHLuj0L_mtlTTpXBfyHXV0KdljQ3XQAl_CRHr98HbliFTonvLQLfal-vWW7KRX7H0TYYhPFl0v12_IVI9eae5QvmLLxElJuMYnTuvauewwMxjLSovOsxnIKvaTTDBGclEKpXOOY2sDHpamRKxm9lJLi1Cpwz-6GLdUM1_v97xFGyrlJBqDjLap_c2UcDTPU8EcPiBakEVQdkmNBhz7d08PUze28JH226GnIS9_poHQfroLnxo8RNnOJqFgvMa3xb3Gd9lmGVMwvZuZVsELFnXshva46Zouz6QZQ8V7O9mRDPI4B1oG2eGocb_E74G9i4hWISG_CrOiWwWFPaChqfIbLqFJbxTWRpv30iqmD7IpLgr4hMBMj8MujxlI1BqhnhotOfvOksRkCtOmwpofL0l4YGiJ6cCtwD7ALgzLN4_nTVXR6ZaETLZTqpAfx7z7INvRDuzeSsMdFcWTlLPCsA5WrSCKMC_jtUUAyPktcEKJ6QdLNmhwZmE4FUNrUcjSYZim-ZNXrYC3U5SF9WbsbeQ4G0Tz31JF5ls08RRzsCBCQGf-TKz2PR_hMD-QUCFwhgJkw3xqqy0MONTtECZDHLUiiL04IyK-MbWtV9BIMa7B3g-q8plZ_Rwroj83CoMQbJWb9Ofe6RM_87NN1kXoc8muhMHGZkUgmq_WQMayrSiq_L0Pm2YsJOaGOyJ4sHHd_R6-OlJ6zR6W4qU9bmJSZvF58Z6oshhPQToUQXObEB0E78alCmrWNYSrcXuMqyhzVToGiAdyJoQlBrpjCAR8Ra8_wYx-8EWMzJaHXYG908knfMALVUE51f8J0AAjB1JmVwZbehBhxJrwzgJo3gmLgWNBPvItPgq8HZX8oXgM4d3PwlNnUF6IsPMsyHIYFfnggIKTHv3Mz1QDTRHJ-SIIGnEHtHiUZojIQJf3CUG_UNZAlVL-qqj05sjZahdueLVH2bVYe3Xa75AuN5v8hoUdbeQfDY1LcNk4yz4SLnss5owSXvK_0DM9V2y510RrHmBVLx0GAo8TtgpVd7Vle2TzNeUksWkmCbYsgMealTceOPQsuDPQ5Ie_1kBss8qiz727fst9SueE5hjHe9vmB99Y9O8W18a7TwRedJv2M5RbxOVhq89bXUBq0bbfVoJ5l9t-1YL4-YKESmj529Bcy71_yNzXs8yRJvSUOPhG9-z5aWonPQI30QhcJqtHG_vtAQE4kT5oDEpujitzwdbQYtntGemNGQKWNYV6CLpi499KfZ10jdeHSkbRTZFjX5J7mffEwBVBRHbptsizL6fGCdY3KkFNKNEKU_FRcYgPSyrzRe4koB_Q-2g2yvHBYqghqLsmTMcahnki8uBB_H-WawnjX0jJwKvP9_azFkvOzrQUBl0yCuklM8npNEFAjVVS_h-jQ6Fseb-lyvehp63MVFac__nIdrYoVnOi1Yihb0w4A7Xt4QFtxyfCHnp1re9zisS4msZm0dfb3s-VRRFQ8VeXWazEIUtDc6QhBiTVaOIZjCOrAOV-BCDhnKPKaJ2gK5R0QspQes0EMt1jpPhgqX6Bvxsj-SMyyKZBr9mkAo1pMb4eJw6sWWchEhXQGQIArBDezuQFEa8KbOFoZ8mohCSLZO3pANGJaE0iEB9Uk-y0ftAkFEbzf_lUi8VHa7hDCqLCOvc56isd9MfVFkMWEhbiSaUhACAac75qp63Y7VVRZAR46EfrrIHvTbFO7yebBTxgetKZc4umvt68EUWDfGqVluVWealK0t63CgYo3dk_bnaQTWxIP8fpIJjgchJjie8luPDR2ZzzanU_TMK8hdE-5iHokVnSHWCnJ8TOI8qrRk9YUPCQof9B3I9pH-KJjBQmgo2SurVLFv230SUdrgs7n4EzBYu9GNq9ryakhwoQRLbQsN40PZJuXL3YSBm4Uprptq5-e_r-FnLIk_OcMUOCv6Vupn9-pqWLCc-mTpJCUdduz5Ht8Ecb-plOc0owN_dzBDgdlzA3d4UpAk_2PNmeXRv6e_futRtKRaKJwY0q1-7XnxHpn8PqmQ1sBYVkLpEOeETh_FlSXwcK1ie10hcnE1H988srGMRCtwgPiU7gAGZPuiXq5aaaGEklYLxEvaSRkASWrIzoP6yqk_FUk65o1Q4hqDCMJhXNSnxaYNgRunsxbv4e3nevbeuuaYHrjyrhPizillKvwwGfckmOv9Y25BZSUXMwSVK9Ad3XA98NajHK8rVoiTRa1fjfBXUwVoce2JcVhuzk1zR_B3KixTZCJl7TUT6ajt70IQA-EsWfNtxdUrINMgm0ZjJVkG3ccM2MVQ0v85VUDwMEqcF3LRFAY1-6Rt0shEK9H2HSvRC-jHBl6xV7DQM0OEuWRvJAECkbRTPDs-XbZhqUQJRRb6XMDZsqeX9tCS1MLyMZ1IUQlRIj3d1auBzc6ICfraQA-cMcAyxofrnaRwhZGr__gns5coe8-DQ3YzNE776gzwLAg5k5M-3WEGJY-BbRtde7opCZnWZWLK9tezTy9ws-qLiIeOlRUu5xSnfwuy6icNYqvWvAN6FwAz2m8F56m7RrtigY8JKwpSk2Jkz2XknkCdv-yaFl4PIZoeRF_pmLSi5jSyP4-ze0owGzmSX0CIRMqZYSsS7D0d88U0DWFFupGK4Kg_I4TPgjByoRH8hZrOcsKvmavJktXN-beunsA06WH8opv2jya9gZkxgAiFIifJBVgEDM5bfFtvfD6N3QJE9TfcUPNGoFqhvEBYzVgQnj1IPrMWBEjBrhc9iCnCattATNc8LVlYbHZ3514DESdjISCctsU-fnKuLN-W9tOdSYEp4xi3phiLD3TLI679uQtifBlAYAPabNDe8ZiwI20jl5REQX10lHjvnPRK7mLHxt7PkOGAcd3hVH_w2KzrWdpf_-DM36G6Lq4HvBUH4BNk8zewp3qybZu_V5zZ2hALyRv7Ibl6pULmyoscJXJoFzBHGDr8rqnazTAwFTWVCwxCskGHkw5DPDGsm1T7ILIgAPEveVdLmmnOP4rXI_o0RGsi-nQxdavHPt67-YWOFYeNWiy1AlNlra5DvL-hfDfxCNgrvG6BbW8c7xEhoFvlR80wgfwPDckjd3U4RjjiiUfVsvgf9bx6x9-cIzlxwiRBzVMnlTPXOwqAsJ2H1e8-_tKTFjFkZuYpVRFCf5Dy4xFcvP2rHtHXE3G_ZGii_M5ZwlrBkfmVVO19lazSqpe67rPuobutmjt1bK_A8B2plrI01cZ_B9yOMzrVoZJebI_cs2Eam46VWfOFGTMoJwzLWmwmF4jt6elLw17Wlrv7yW6RoFzMVROMfRGksuezBufgDDKgpK_aX4jWJpldlI_pNRTycgieG9xHkWPsslTUPFFQ07yNArqB_9ERbiZv_4ljva8O2U4lSmi_CPocI_Gf899EBvd7QmlGl7ZswYlb-VrfcfHuSg-eV0QUH4KwQDvx2qBxL3ng0bxCBgiNsOFv8Kot9afWjUA4YKpvoHajsai91iOUEJ1KBfd-GGv_l3M9OoZtpnXre5twKtdCfllAuLcmH4HMAW6cPX41sFdFf2wwk4aaTic4f5_TX3-dSk6_epKwdmjjucflHtrFp6c9SJwf_aB7y7XYnoq3DvveOtT8LqPb92mIsSwvkxd0E6CVw2D0kpUsD8t3wWz59IeaSuGdqzS_7DCBsk240J2F0L-bAi1UmwtJySyEH6gGcb2wzuekUpoL1lbk8NvOFhqGMskpzAW31X5KlAIB5fMqYIechq2qgUTX0fbFbbK-WOS5BNuZzQHg5u-x7KCsd4M-i0-JQtTNyHDQ9_6GICe3RAa1au6QMk3bbuEeX6p2rkQNIaoaP4X4cayBr_0yu1Txn9PV28js9BnbryxWauTjYYSz02CGE1kN8STnQ-ebpq3WkorL8QcPw7VJFDRytkwSz_AslMaxmoCzvftC8nxZgEveO027csojiijwJ0gpDZYvyhMgNcPhPaLIEJrVSWkyMnkt7Pu3Y2YotbyxyjnySgVgUhvU4rplk9cHykR-1KIdnyrtAmWD1POJhmmtRF0wbMXWPg2zp4LPvH1LRywS1Si6lgMCGOMXRfOzbm8PYJDeM13j6e5PrX78ZsaM_n1Y3cDfew8Oy5guR6ja2TAzstADnEs9-ieIV6xIgARP4tLLi5JSMSDKlaite-kt4Os6cW6ZPm3O3rUthnWq5vHRByyhVEytS-ALARuaoZdc-yl0RvQp08jXqnqueILKWdaRWXJveMAB4XenxSGeCVffEuAm2HdhC0EVcS3rimTX4FSGFLOD2cUNXoB7ywSDnP5VTZ-hQKp-URDXx3YsCj_nXwyIYC4EIUN34i4YUh-DprUnNfJqW9Ev3sfByzjyNS7W1a1htCgXckmy0XBY6X8bNswm7w1ptgpLU76NGOuu1haWJp-LPwxXgDEkpG2tLQQsCKedet_QiBmarepWVN1j9ZIkDDwQE5hwRNrwRgHyGIXk-mNcXXF1gmr3q68XEt2VEur6grCHA0CN3dy4NRxuoS1P-vaRxLl0Dl9Iy7lIGoZaKP_MdGdiotIZdnxe08sBWUvZGdUMg0gpEAn6CegsiuQbLCqT1KuPoMNLKnh-33zrHA7Jo9SqxZ-xrRpwhj-bTeL4v9WgALcRO22E8vhFrVJZICjEBwUv6rpo584dUhoxWlwC3wNo8VRp08Hkbso018pjErTyQ7Is61euKF_OxAvYmHgyZVb_IaldqIHSelpu7EQaaFtvLJSiA3XOIpD4O-rZeimfmS6tOOYQad2TjTbrO15c6AY1OlCWsWAbUGQ_8NGmAijI39Vfcy1z5DJceiok_1_Ao2jh82tEMflNeI6DVEe01zDeZvTHimGVreOj7P7a8Turi7VbzP1VlxrgAxDWZmkPWRxIzfrFjfdMM21KtCE5M1FAqX9buLWcCO-PYmQEjb3_34_g5jOwywcmJXB2LVw5H1d0LpnoBrZSYi52lQaYM0pUombI4jqfrHuZUemB_uYWMdqogdGtyWr23TJeUeQg8BfxtVzjmyw5lbCwH62GSDbpyjzCv3Fn3WDq0qrjR_Xwmj2B9bJR0SgWZhOZm9ZudUOuq3VEZcuaDNvRtmUGysZWzRGRAp3AxolKhk_gTywGIytH25Hj0L28paw0xjmN8YunkxNVbegg8MnXw5l9G8SXNPhZJYKZ5HqI5XRsbwZgvJvSHy5V_G8Ie9YLVrbpoYkmT0j7ErSHXh4BQeS_zbFJosev3fmnxJIEyTz916SACv0s1ocw80aohgzjK8N8eDz5FJ2JQIBZz8TNSYmfFX_Uv93_ZwR0mOAJ2QkKdv5maUC6JU_SSSmDCqcMwp1u4-AA--Z0rSCXGHWWkdZ4vWhRbxFkCQs1IcuSQn2-OxNBImLxvxmhS8XDBKFfm9t8B6ed4TjupnNn6x0BWG2BtJ0yk7Y2ecj8XMQaiaG4MKRdUd6i6xOz7GwmtSA7ckNZef3_B-XA-vw7kYih6vhIf0sRdDX7IK3GVrsN9LbhmMeswEQJteavZGwDWF-piCpBMJ4LWcwsKI534unKNAPhzVPIiczSD1gM8ykZnxVWZYfX4Gd5TC96tdoQq9Z9e-d7uksaInDQr-NSo9rMPPm2quIe_GUEeqzvRHVDmaJkmP-4CeMGghGHQHozDXavc8os__2len8ZFyVAKnyHfhn6D7eo4aHnPL3J4frq7M6SLDjdvunW9OCmROtmSkXjvFwM09w95KEcroXJBkM7bsA-Z6KU-uTwADINUA4TH3K3Y7R0oRmCBtWzT_mQaIE2fgqbwyI5ZhmjelOG8QZYPCK9OtqYwNw1pHDFeHHM9EcXrux-jfccDUJ4IPdOKGOkPurJx7EJv_Ed0sh1IKaYzNRuvsUJGbVU_xyb1nef-Fic6P38JCrC7EYEzLKdtKNCFTacUn9OO3Ygf9b833fcjfG0LYWZeCINxKp1OeGsOTd6am8kwL9Dwx41BbBRHHxb2Fa_w8oneZ5f5yQmHlKvhJ7Rh6hUEYWDCUOG2njMVe0BeI9H8bxzxeWZI4RCXYa0sbEbCqk30ivJI1pdzYuuyk9cc4qUbsPdIScAcSXk7NqBlS82Lz7kDtFjrRtNOVhrjpjlKV-a9W6-rPB0U2savy6xjp-e7yPL_S1Spt10edRjtxHt-AvX3qh56EJdILHPX1MbxFol5LhH9evz_dw2Pe9gxOTYS6S58qxcxX4Nb-KfXngnxaeJ48SsKN-TKi2TWntVLsjDBLPUO1LXrFw8_ZjijdW9j0SxZkOEbnvI3uJ3jvEVxMxUojlfUh7TvKdR209jBuO2ezWcLt3CKfRG6Ak0FjcugJ8ByMucCG5mGMOB7UyWCTurM4FvTeHHAN20C16LRkZ8VyANz-Oe9YfYFO9lrofS1-3jm8UoZ5AbIjCkOCAdOdVEo8RBOh_P8wOTVaYlURHOfeXniL51czYw3UjyIkMftiVXghc5KAWhwrqOkeTPDa3b4zImVqd00u-fsVl9_-c25qR-K1UaiwEEvF0ZJK1TTjMNerCVNezaycd8KZ8ktdaqQD9bvx3okUSpKFZ_WZtgRg4oOlf7ac1ba0PUyigxms9I-9f6snYfzyefP3elvMXL4KpbcDfDcxEWrwFiQ-xDSHjHLrve-irM1DEbgNY85C4XciSOq_fMVut-s6GulegmFjJYOukwLjpLFrEEaenpEKKQlN0upzQcHmdUm1XPUuOFrevg3IMzIpYoYjpsMHtJPXEhViPcpt2uwwRH6gWGtt9wX1KFlYeES1LfdNYBgBA4myFQwz8TR3EeojBxTwtW_pIX5P_A0byfabD2BCEKDZwmgiLfSA25skSB57d2WllO8GkY0pdKBkprewSBb9rqcrRDIk-wd_hSX5NGSnlUGY2-hU0ng1erQeYamS5pYw-BUVTtka3WdDIK4Xg_-RXXg08hfdruAZT-QNBr4KhSVX1l_W-BACPuXirWu1LH12Fu1LQ7X168GjM3ncmfW1abNU6auYfJoxOYTvditijm4SHidFcLNNOYGTOe5WkNNUMKhfjPI03_ofrwmbC0XZvgrUdRPNLM4ocIb4u9W6_LuDRcxd_pnv061OvmBXLYjVQx_O5sscdftVxVj70DaT1Xt1CI51THYtlr0iA_r-xYFTYEMBvNOdz8mzQOblwbeLqnhFWvkcjBj__0K8brz9WTkKJDmq1JPTkG6h-hjPgAcyL-ayVuWJ0iLlvXObqalnNWZ41zyc5XG2uOX2roF2EMOwjZ4Io5eAnhR5ZkhxBJTm9egvFyZ-sU9ibMw4dglZ-_mESgmo6AF7UKR77czR_c6gaTUOdu_U=', + provider_name='openai', + ), TextPart( content=IsStr(), id='msg_68c42cb1aaec819cb992bd92a8c7766007460311b0c8d3de', @@ -2268,10 +2293,30 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, signature=IsStr(), provider_name='openai', ), - ThinkingPart(content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de'), - ThinkingPart(content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de'), - ThinkingPart(content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de'), - ThinkingPart(content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de'), + ThinkingPart( + content=IsStr(), + id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de', + signature='gAAAAABoxCzZ6TwL-z6tYv85YPC9CwMFJRrSrWgYUyOhSFYLkdfGwRUIbrgBnmAW0qtzE-shPNPNfbUltLnBS4uU8kMuSMPxotFngVcFFnZ8qmzDUJiEf2CsnqYqH5d2RmuvIXUQTau20SjGte8vOLksGsz0sXRUQnFs7ZoT_2DSy7tKVCCN7fbvkxm2l9D-IibdvGiflbP6lGGgYWczEl3_QyEyJGhDTcL_nUk511C2hjvqI6YkEjujvYjEGMh-BdhFrJeLFL2wCbn6beWaDB2IXYVo7LqhlQUtKksY2PQ4ybBgPhERNvWWf2N-K4NxEQuv6vdB_5ni_BlUKFMabeeeI4wVr5M3HKE6cSgnM8cpi93o_rGu9uSh5fbN5zZcIYumnjkGJ-ULwku7TVtpw_Vha8bJl67qCLvRe90MaCCgJxFKp-IsxakpnNCXVrAlN70cIchPEjOWW3VKrGZ-omyQLgs3EzddhaPmSqDELbmYkxCUuRYdLvZPzhI5VvNiW_j-WGBKEMJLFz0k33oPbH3Q6Fn9HcJSruSsQ8Lc-QWQsibGoABEY_auM7LDLjbvpEYcdsP5BJOBUS8wpyOD7N5jEQL2PYPT3tsP6mvWy7csRIkwEbh1x1sXp6NL3skS6QwpqNiWalP4OQvs8jDi8Gz-NrtNvmX3RR4A0MIuX4q0Tb1VI9PilRUvOvg9hF-fk3bqIh7wW7_iD2eDoXjvI99M-UZ2QZGZlPa1O039QVGLBTi-KwrLuhh-D5q3N-3-DyXY0sjsdFzM5Qf__lVaxtRhZRKyxSONZsTt8mGatlOH4Q-MIPgCXsrLu25gWn6Jr6vt_iQ1eZG30cox98F4aU11Hp-o4tFKuHL8Kbgl9Eetpd4ggfJrTe9QxQfWfgCHAKnhjVRJOepHPEFzSRFKiHrOgATIw_x5xNRacsF_tO1WkpeBdBJhpAUozarHgPQi2A71LCcmd5Zzy7FAL6R_5QtHW-H7NE2PjqqXnf2ZMiMM-oYLHKhfu8tZu9EV7V21xKkovIGH-0OQ-lk44ww8-j3rBNXjWIwp8SO73O85PP7vzE_zJJCF8riB_rOpazJpMCaDP_HUOZq5XhcfHseiS1SownunaXj2wOmgLJ103BowC18-i83n8RVTtRQxLsiCRzMwRH3eEbEClqZ1Fqt4V6NKqICKK3kF3_R_oPtX_-7xYBpl8LGR2Ei_2hXkEIuQ8cCRz1zmuyfjLEWIbm6Rm9wgYafXIXugOqGl4lUc2NSeeJ5T_-ziLEX9-Z6LZafWo9PMvxbxpm86-e5ZqTBlsbukWWIePrKZ6BjElMcxTOUr2XYg-vMAc7QRx11Ld11DwesN_Xj62Kc0TUQRfREPp2AF0gAlYYKLvl7XKwU12Rg6UlWBfJWjX-hUvPY83B7H1saGyAv6V4RR9PODI0p8duptI4mC6u3cYPUk8pOVwFvX1PYCTM3I2yik_XG5ZyI6BIGBNAGL5SoAyMfpqYu0Da4duOIve6tQ3FWkMYnU9sSjxvS00mRJ3JscA-pNm2B_dUXBRATIAD6XVg1m19-pV6OLG58tuDtbjE7nBHUHuS2sm2gbm4PFjpGKFMS07LUSfYax19Ombld0hV_0kwaIjl-4UTcRcqqLK-Tc2E3NPwmdJuzb95-lUoAJG9Jp8UCoyXQRcZk33IGXMYtNquee5K-Oc-ajKjbbevpi6rIEOVjwKrZYwTC5ddl8FBcCBTm0NunKUzo9TkDeEIF6kce9zYdKo9GwYc8Go2S9lxbb6tlizDql2Uv_ZiTz0d5RUvShsMH6RzKiXu8eFzv5sUraMbLUtm3VtZsz9Ld0iztNIqV7q6glrqD2UuLgWxKsa7EbDRvrlBnAOP1iMRtg6ICr2YHYtlwU6R5RzKllG4LGMccZ3x6HsZL6MMaMJc8rLMTtQYqE067kCnXAIBz_-FJS0CzwCwnbh70tc-ytaiTm404Jp3CIBTlGwDwTvXUqzzNAdFRHrilKUPNgtKb6uQAyPhJZwbFIfrFevaMdOGZ9UhJoKtQtsSj1qM-dhXIkn4T_SL0o72wgb08zYSjsemhfJdbNO6jPG_GfWV6FDAhY9vNyTT8XlqgsePnALnV60AIvRZPI7mfh8D7F8SI0yZU4AJVtEHKKgStPvCuixxtjTt9nSWm-cXOItJdKYxMjVtWCmcCI9LbPolXXkewgNhmUx-b0XlY_BN9cX2j0COic5Ml6LS0BZ6ikG65a-7kIl_yofLeat8q9-4OI-lhKYOxwMhQq8yWNCBuJZCGg5n3DM_QgEQt7cqWYuTuTMTgMnRIvSefK_Q-ZSY-ZfzPcNp13-v56KgA_yUqYOHvQDu4ZuZCI3KvlO1WSO17SiqiNZvo3iaM2BrrgzOAJYcSx4TUzl7ZuFE_6LkokGlxguZH82W9dpewDyN83yLLwakOhgLfbTlMCFs8NCLzMr17eBFNX8YqP9bh88f98KtLSYr09naEesCwW3v-M-I1MUdR7oEC64ixrAWEwpSI-Jcc60oUgvLBVbwkeoQWI29NqZCS2JYGsxjXfNmhWWB3kW7_7ik5RHk3oNRWXiEQ_N_K7c97Ui1YkomyAAZv4t3zQYHwsLBmnf2DCEMBViQn2nXXjGwBxEf9KY2dlT1ihIbcPBmyzI17UrKYXvYKkfE25c_R0VjQtRSiXrlEWkBgLwRzWt18_62P00dJRAeJOEq6etGKoSh0PsrmtCGfnOf1EJhksjZPyObdHWm_yrNiX-h3myewuYT4BIanBFdUQxQvpNyvoQJIMtKH3gAh9oCJY8os-vS1Mx7h4Zh0gEdQZhIVn7KoJwqbx09F8hGokOaVXx6H9gMD5kVZkXkX56AFC78ykpMLSsolvyUhAI_qxcpTVGSgDIzfK7BzQsMd4TawOtHObxfvVr9qojhx__eQEipXplbfOVh8vjM8TFY7eb8k5EvxaU_pBuEmSagGoV0fiPUmMTzipVTMQ-cpaF6xQSVYZK3CvmUwxHfcX2r8lPPH_SyeiVFKRdqTmpIGYw8drhwc9GFgFM_N1O_iJuhjSt-8iLt9BExKYJZftIcXPYl4eGgC1yC6oUBurdmvQUOZD2tv_isd28fMNeoiWAy7HCDz57TAkJg9nJsfULk_z5ClBqz7rPP9Qq9CZrYEsz6Lggj19AXh6PmA9Skl9nUSgsqn2GvDI3I5E8YmxhlP58XrZyYKLkYLqqAMDy4tqI2eiQMe4z1OhMGpVxoEt7ACxw8-YaQTKgItzSNNskrXkRsGvWa2m9XcaZNwbZFeqek7OZ0vxLMsQJ3InnvY1lj9aMUUGukolxZEZ0KolEPOsIKhwH4iMg79yNlxeqdM2e-OoxrUyIBvBqC5uNemtqnulwarV_0K4XYtimpR2ONcwjzSO-eY9untVEmJRdw-OYEJiKJoRRNEjmr77UuJLDhPqjtxmcF2LHRTbpQ8b73Vp-mt-1okyP2yOr8Rd6LbsJuntv77VWE6Mt2JBzJpwJZab3mKd-2c6VkTswJX8p8Lf3g6m3uPwBRrvyCuuxztoxG2rDrh-3krcjDFnwU5tZjpZ3G3pq6KXbcmsX3kvJhJc6er38kO6uR9SkJUcRkbQPZ5nUKCtRZ3AkFukiT_YHtUamsUlA0nX5DI0CcrrNtu71HD7jSkwF9-P_QNX3_c9k31cSfHQ8BCMHcy7DO0vPYuzj2BiStEdTymAXfMeTFVO3wUvQf9KyuqVnKFMtFwP2DaospAJCd4TaHeDCm-uczeg1of-R2SB0f5XorCQ5MljHFk1VTHmWG3LHgCTEmAtx2KKbdMO8zXsBop6LAnFj3dNEBv1grO5lMCZRqKRo-csAJKwqXn9kuIa6GXi-NMZWBGLvxWhJpWdCeGnaFjCk-7uzPQ7PN_JhtPjeI3W-9A5bY8RvzYLrKKIEOEMGyHb-77dcYPhhLgn10-HpglS0_uJw5f0STZE60rxVXH-sb7vrpyAyBqMUh-OdoGAqR4r9dflKk-jECG0sggRuzx8jLGGfO-dNZSznD8JbaCsRDdLuHWiFSZKJswXwX5PS9rmVpYRrH-0QniMhPiMOuINwp9GvTtzSvXNIPBWtNMsY_jN_O2gIKxL-KnyoQkyUFWHN0Anuyv5pCHQk1lhfcR0alSvDLVmVVgi1tQdjsdAl19qMdfm43ViBTRLDwzP8iauhipIfCpxFjak0Ka8uFaHfEhKstcmUdxEnzIsN3SQXrPud-p0YJ3O1MsyUDjzMROP43FKMhVCSnM5PsXVvuPZKRmuEFbJyj0dwwBnSH-rk8tuK5SYoX8PIrJXyAySgj2VouGdzvkqa9WPSHU42AxDZNQT2c5pEI3gUS7VzcGCTwoznmFtmHKGOJj8HxKswzB2z0AumI_ht8zx6kehnvKK4cJfKjdJfO--2o_gzVR0DkA1HcenMD4ugxj6rWQDiJvo6cFdfkXpMfLAe4NQRLVLNv4UdIehCxCHMsF1RZJf93Z6sdxW_2PumLLcfdb2XIkouuFN0mECzZlWgM4XLUErlaaqDc8oU_gRrgHEJbjZqF7by2nHtqCjyWOZC9n7vF18iSRJES5DX71nY84a8ydPR2_KEYfHHgqF51Nz9zMo2Gv6ramAFs6lZC5rjOUR1VmpLd2pKs-sPQJpYNncwbDe8dG_NDJI1wIgs2K42eKPE4lEueCtp359ifPU58DpJA0JiB_FW3jBBh_9MphsnQjuso9S-YSaSFt4Llc_Zf0MJ3CbiEsk-IwfgsLysFQg-vJq9hHR48ZoW0kx7CaIAUgkiJg7-7m_dVNsfaUM-OSHtfryYXWrUsotLJ6OTuicPOfb_LfaYz5OoasG0o-4vdtF8e4VX6ZpR_Krje-dZaCph1XjgGLfFlRRkywl7i8IEUirHpQJaoCPmc9q61hjETcuPCEVDy-dJMwPLiNzXY1mkJI1lQQ1LL8Ke5EgtAcC-2K_5Nwh4h4bafWA44XgnisMfYDv66CzsL35i0XtZHibfLqPwdLyHqInlLPtiFyhJZifcJ_GsiQ0U4SZO3WHmvSG9AHy0YnA2jC3O4x7yj73RmroELKFvT-_CSO5LVz3qRRVdlyL0CQr3lkHUXJbFNpOz7Uek4q6MjB8Cn0xAKzt9ztcClLdAA9NkR88Dy3rOP5yPjRJJVVG6SbelsE1SnPDaKQqu2ZN1zdtGUY9AcULc2dGFb4mezcbJsC_eL3DD0LwfwcSAILDfDIrqHACR0XmI7jmF_p_PzmBhMsocLnblzKTho5ufo4htqhTEjVdFywm9WIjw1N_9PWge3i3J8mSdILp0HQ1QvbRlMt13qPyLNwAmY75m4Zw7EIlk4cyxMjcTSY02TRCC3cBKX2e6xl0DIAygChReVOxL16BT21sEgT2ps24Mljsvht-fokU3JPtj3fY8wojksHAWNv2hlF62xKrOv9h9AqM_Q9JlghHHNTrzxvT8SVeLBhEvysbhErrgtTPcgvKfMUCT1JMWolxLZUSFEFKNR9cl2GiSqMIhdTL3JvA0-etZ7ykeIbUEU0jlRZAw4a3vY1R1zW1-c6XRSNiS9VDPAfcN2OD4bXL8Hi2Un7Vc_pRyWn32kWQqQuw7v6J4RB-sr3Bkb4OzUljytF3ixqGkMIpuA-LjJwdBJ-XgR8Fj_DONbguNct7MTkMtQqWU9twa8XF_sot8iEYc1UOkZQVJvTtNclIkklJhP8VNj1aY18Y1Gtnn0fvfaOFfY4wa7HIq0U7paT2Fqb0xtY62bqNM6rRXLsAQex5HvMvHQvL_9JbQngBOD2ehk7zIAJKZWzbAKqKCgH-_v4kaGBVrciIxffYF6WnWq35pQwbsvNqQG4uJR0qhLEXfc5akEon1sL2fjxim_GFcgunyCqL28lMB8yhnzA48QESW0sotVss_GIeeftSYS74zPaHXiuSx0RoAmw90kERXPDGVCRkwTTwaW2BkshCJCx2JOSDEWVRMjxngzaoroybl9A1VzTrDEbodeq2O_kVyZfrZE58BO8DDd6ZH07m4zuiL_NKXLw23NmC4CuAN0ufn7HFtX_ow4ZJILfZI9PczBi16liV0LWrBwvadZ2Lf4o3sV65CLg1VKujttEiOhtpYjmB9zIRLfAHViz5vgTonL6H_9N4D2dXLzUWlaDPNGJNnt7EbHS64f3jSXGG1fb7LGKhNtTHqbfBJnMpmPjFQGb4ae2kKv_V_L8xgXNpQRi5I_QNTzDzfBs4avowydppTpEE1b8WNITLc7qvMa6gwpDxp2N91fIVC9wyd0k2DXaz3VbDn-2v7W72D2UPa0L00NKvIKYecd9FMpYmkEyxJfFFr7b9hKA1ZXdqlejjPJPjVYC9XTEZLEwzdeoG6yrxtYMrl7o72M37uIRNZAj1Jf0B8s0qhPaaBfUVKtKl7bd2Ub2503LZ7ZvJ_1segaIT4S8nt17hjfep3re_4rEKA2rrxMbWoLhM4qkAPZvdjyAFF1YNB7u-Uex7l4STRYSpzl4eQIMSl7N0pGlKk58Z1FxTKHsAZTkZYtj40lptma1AfcwRPViNPceCFA36XfVjaratWPYgDhcjK8nNnAhxvL7t25nPbCXazPK1D16ZkY2SwcX7sMx8QklNQdzukZwGyP51yhU8o0PT-u3xGDaXnP6Wh_o35cCIRnar6Id9h2ovViZXJRUzNa8aXedxiFp7hLScSQfIPrPBcqN45EvLjEmtLvzzxNgHY7zw6gzj5QFgv64u2fI9zAY00B9U37bHIZPQnFAhge0466vyXNENzYO3acUGo5HhyFDlcuiBCbIZ413bmfbtRbj5W1FZMY58l1plTmNljfcwQ7Kd0PUGvGEb_jwKlmyKni1HzyyUmElGHdRkyS5Yk7aja6AJOk6z12WUM5snqG-uRVkByxCXQ2KaFR6Qm-IOHMFqzrPINkjyEJgG6KyKfkF5ScVfQaThHBuMrb7ETWMnlk0L28ZszB-TLt3HfaxINsoD5pndSSqBpHB1z_2kEweik3y_PdxIchV3CyBLnmrlqBPBIarCoM8VwzForh3RzQmgNsOGkJXy3Lk0rIr3t-BE7qgXWsrDolobtH6MMFO96Taa6MYIYYYbYvzQYcDuQwD21yGTLwKAnynBDn99bGYEg65LomsJbTSKCYQRcj2Rh2AaScsq8JiHYJEGAnRkgsXNivZnioTlkI9_5XqXBJt3GKMY37YL6qIU3XJ7HapKELorbX4fH_JlOIZLIOIaU80295GZcFdx1I2La9lp_UvAtALEDJklGNvbcDG51NNn2mj_P85vIfzsVdrfX7N_AftR8t1kQx7bdbVLyP4ls_qKnXXigfNJajWtPVgwGeroQq2jtaQw6Tj2Wsi3Itmo5QNg3N_ja3erlEHEdTo8lm4XZHjbl2bAH3n_wuEdYKTt2B3jhj4ddhO8atc1fryqbRfn61YFKUnR3f5vQ1qUq79uisQi0cvHr6DQ_12FpKzFvFckAkQmbk5fcS5Ri5S4L_JtFAexj8n2f_oYuG_9CYYplOU5i1Q84MyXUZ2fZyDhRPRiyjvPJ07_IAiL2ny1btmIFtVPeQSHVwfun-m5Lba3KgnZIJ6CRFqxR-o6F8e5K78d-bAotgA5vOcfeC_fBQfaom-EX0mJyzf7_Wjgam4IA_W3PO_wGoVULHfr7mwUw2Qc-VzITtjajZvRoT-SkVREyJVnKBxHFj2cNTcTtooSxCu115KmbtePf2OwgJocB2jyPT2GK-kIVZtuGdv4Dns8m7Z7FpT7PvjCVjidQqVsJxFQUs7ZzcTXX4vdChdcVK1_OiUwCJKiYN9ZKGA_OmwQJjhnV6gutHFYanu3Gm0m5PQLIM6Pip7yXCw8-Lhq0sxFTl2f-7DeYlfrWpYJyc2wR3T2u-kHl1g52CxX5XoHCV1LsBIU75L23Igsx5_v9ZNeewK2Qh8yWwlWZ18qnXOh5ZJqJUpYtxy3sUhHMG8fe5RKVGbbJyHltosuW26yJ9eUQXqJOSj4wv0YN6a-BezPdkkCqdiUGDHllrgAi96kkeM4jES6iZV60rTgdmfOS03JL0eqCwLnH0gP9t5Xq7l0-GUKp7mrsUjgN4Utb89AVPyIDFWxfJTuFJK-g6Z1EHexEvDY4iTsuOdq9M49_zV6iL8ChB4p5l0lUOiFzIH1Qj-gNMqpU2p0H73cMd3MNeecFhMsCfRadVCO8D4UN39W2mEXDxLBlTN2f4m6aDKjLHi58zyDiJ4aga_ntZRnv56KJpWob0A-4U6_GRJI3OynwKPfb0wpAzK8Gm6Ak1OpxvD-8TmbKUKVA5m55PMoBgGbmvtrwC9Q9Exg-zdotpZ5-iWM1ssnKLXobFa2SmYJeOcGbEjh_yvRvjBRNHxWmq_sP1ohPCTce4Pt97WVQs0Kc_Peb85RqZEnCyjRfV4C3nFUkTxJhFJbmIBPG-VPJDfKEMVTtUe7xB_w55BKViE87CTrd9AAveBFKkBrL3x4bVba3SK5HLU3tOgUPMDnN6Q-waVbjTXsNPGPwJjvbDAN-xwm1V19e-gYcI9sExy4hH9fCkx7Y93e3EMo_EvPA8ZFO8C-KKKlKttqg66BlOp_WYj4GnTpurNDHjVtBQZI6FN5HGl72n7ZL0me0cbfiDkFh7mIfHJCc3EcRCp__gjeBYQaGaR3hh7hLrNeuJB_oAfW5mz-2mIgUYz7vGxRrTeo9CyNYjr5CNwd-hp06pklYw1Bmce-1ZqG87pwFGjfWaAABwqNElf9Wdhgzll31WmopAxDC12Q8pzpAiFfkWWeHsPgvx_Hfm6B50TiIn_LCi8hjTaVUkvtNxZgiKJdAdL5btiUvPwVD10EkysT4dfAEg6l9Z64sZT6oss0KlH55VrNoLOybfx9-TGJZOCB5Zf7JU0KuA1Dpfp8I8TlCOUBwybFvNbECafzsrKB8XI6cmvDtsG0NqNzifoYUPzZDv4eNQhb4QAxlWx_xjiD_G33rgZ27DfvecgVkhDUc317uWUTrWt0f4WJItv4A8P4fj2CDa4cAjfe9CCWM8oehppoxScG5nBFdeebs1m3efdBi0VlYbJTEFQC92q0Zdr7kdfo0FbR1GQ05x66u5b0qLRqqsgF6n72p8Vo_izkLs1N3HKOz9AvcoTmD_tD70rZC6SVJ0jQcKtOMre7VK7lJQJwkuuUL-TRcVYVFeKln1CDs0zpqwza1iCVw3LcUdh96iPsN3XcHrH9pqUxSEY_T6Bq8aSTHdf-iqucTB2u2zsq5BgU40_zXUqvfvQRhcHbaNl0NkdbWKVr8AA3KkoGHMe-H_FBRmyBFX2KL7F4naGngOz7crLfNoSqvPF6cBudn3Q_PPxutj_F5d3FxcfHSHizhfZ3sC39DiwyKgWMU4rUm4gsyYpnKQ90aXtF9nuLWDyNZEb1hsHiVyIoNkUx4IznUY94rrMNzlobnMyqtaic819_vgKqTo9jYA-i5JgMoTPy2DTtIZIpU_p-TggdpEActJ7qncHdQjM0mCrZGYo78NvZ0697fexOgo-dQjfUmNNKNtLp1UQiMBllHwIDZzRePAgOeisXx-E10lLdPUm6AKQcg6IYbvrPDil1_EaQyV3JXqEgNCZwXvkDIh2cnaBLUzyWsep_iupiypilShz_QWLsa467qw5dJ_Q0vR1ulAzMWokaCmTTiJQ6RL71J4WBiGAnobFDrluwJtRr4BTRNDmzDBh8_G3EKTS5mr6W1EQnFnMAqIrW_TOvKasBlQqlLVcFDlllp7X2akyW6Z23NBe7JCnYi4m1HkM0_gnHqnFbnT3cS4umAd22ugbPbo8gn0KRoFxAZK4_4JPHbz_T2itrnDcl4z6_50F-I0Ynp9nHSKnlG5x5V6IGd47vfF7sIks8Vfpq8LUKgQu2g9XHzwf-q_jmwH-eokmnUlznsJnZWnz_GnHyeEMsdQbBKDGK9rjNuMC_QZGuiaARSlSvP7hMyowcczvtuKrN7sZc5nTWPD31UV-TBzrDnzmmsKZ_3BdPebNj71vt31hatE4Mc6OJJUZ-HPPUieICZJFiYXltJBqApmSrscPjDUy9fUoD0iJudrtDu6UJ31SFMkaapXqHG2FqMOwkEk_T5wGmdZ3Y6I8QKKiI4bXRcjPexjVQUJdHnGLRZ4L7tyKU1mFJHMEIMwAer1LiYsnFLHBt3XoAQbNu7LewtB3Cd1Qzeo16USsORAgO8DYtAiu9T0yfTOMAn6lfMgEIdqdJdY5KiPC2TWro08m4pn3mhDlfIWB4XzyBsaO8JiRlF_7Dfg0UpDEnk2AN7ACqsjeUoMk5478ov9JeTPOnCDw2W3x4-w3VhTndvrAD3OrnDoxsc7OcoQjni96fsh-E72g_FKaHJVqH591bROjD5nAPTj5rseGJYDTJkAlHauG67pXgIpMLSLgTUUeplBgjDDTWPdww6dYp8yW9CJNOXCrqmAunZDJe5d0n2BmzGLiOHxiDLKT4-7XoycRXq9adUn2uWgHUooKJbs4BI9sF_28FhxsbN5E2KT4b51aZsK91802OXcSbLCF1K-HqxFNeELpvrlnYT4Cefr_gQydbzRvzSdpTSpUTLtCspJ8RZzJZzQT6x6DnOT8KVt95Sx2OsaE6zCOEBUf5EX85M3Xw630kFQPAjAXx85FxEos_Fl5NtgSssugztP0Q6dbXJTuQrsSgSb6TWsJWaC6agqNudU2lkI3lWpxcxjnYdlDisZE2CVtPXIbMc0fP81Oz9g-LybenNrYDUdIL_FvJ9FM2ZSAleLrEgMM6IyDUXBC8PXA7QP-DukpVBDGkt6GRaNqiqMFN6ceHu1IcTRy8RBucg2ahZqS9BgLlbj2xGANaeZKjzvNKBbtqawx-RkwsHludZ4I6WaLC6-fCnqE0GuK3kw8mbym6gAbfHouwbWarAdtesd3tjoa620dCNg9QwQ1Hzgs4Fd0pjsSgMFB7ahRSDy78GWbdPXZqPollN22uUgQ1zWEva_VxrPK2C05iQMPE4Cg5X8XQbxGH6GY7wuOnc23Pvh9qe6po8voXKaUAPVb3oUGgYx7lgsWZIW-2c861ip10CSjcfFm6AVrS5Iaf7m0OZvUvL52q2r5Py_LWxLbgf0ubrDXMtHbhEGXYmiRaHcmuOxoFUtaqCB6kr6970im-84hk-SiCoL_96yg6Bna4isurYJb2JQgGktUX_SjcB4TshvDDx-G4H-lUYId4AaqP1zNJ0ryUPOlQQXlKtc6s0tUfEZu5SagAE6h6iTUkCr4hJ9hLanj_mMSMJiCjBCFUYMeZ4LCxzQagyR5qWxq90n2HlHhmPy5eCj16DTBIL49ScuUqyN5x8fWt23H-B0VjTUdFEVk8FFaPsSFv0SddM9LEvrlUcA-RcMpyZ1a2ifF7N_HwvRlMslVSzW2BUZRibnB0xpeZlUbqy2CDkr10azuxJYajE6giMCnSHfiKM2EPMuFl5-sX6FiyfsTIA3CmcdoHvd83KNQbMuDRp_nDCAl6LNcj8CXPyenI56CAX5owOddnszaI3C7fEfW7MavfzLE4KlNBPYeFmQLL7w0Rw6uZfqjBKLFLNtXNDBnJW3GSWYKFB0QiAMjf_9_nfOU0w3cwgnfsdmUU0BG_9bXy-qvzYvnWs1eLfoCfruH7gt5Bvb4iGPr37EFMI8yv-df__xbRHgDxVtAd-A5kL8N8DR4U6eSsw5UH8--p3ZpLyrh9vklTf4LDr0xt62qvZjUKzcuMZjQpcBvDHmKRx55aZ8BEkKhIhsWlZJMsE5prZOz3pwT5_pAp1h9u7sw60NnWisoTdBM08hP-JD06OWB_OFPa3I0x1boTojwlzVpiVGUdNeMgpWKa9wQj6rVsEl3-UFIyrKNpgir2df5m5q9vxZ3TSKawBZUAQJnQp9aYgysMtCnUCNrZ-zaC6mojA6cBLk-g5rCcXsyd1WqkHrFwYoPAu5593tQA-ttSVSFCUQxCILqKUZx1-fw2NIchE-NUak3dAZ4RTWm6EwMGXh6rmanI2swBjkglVxw3CfmOAsL7yXEhm2tOofu5EoADa_lEdy8ihHgsCPoJiq4hxlwFXrg9y-Pww0xsrldPuFcc6AAIpPR9UrKHoEdxoDnANqi6zsBTsp-VdyaNj5nFWgpm5mxgnuWUrBGif-U5ldingoapB0hJ50--CucJyHaLHHV2m7WcVDTXiykeHhjIp8qnKBaXwoyezqmLgzIOmhrJgqBH-drr_Usl2Mtzq5lyA2if9MFtKcktldky2GXDiMlwLWSf70Jj5d2Tq8_4P0C-StEZ66V_PkVarTSrFahni4g1OqUJbxxsK7oV932wEtpHJPo6MYnkebOFGlGQlxxk6OlqoZwyP6xbJCwu1_36FuIYcl09Vy11EXK58g62eDyg9eGaAAe1mU4fTByEowy94v67qTC9otmjGlB6K3pyqsGnpWEGz5FujtRPO_ChDNN84qZRMSk5QMU3jx1t3-_0Mg48WnuWGiDDveAhZVxNz9HThbvMviECVk2E70W0nj9XEybPhNLcKQxKMekE6_3qJxUTk8Q7KJpoDysmWznz0Brg-GT6NSJG0pFFfgdNCAK_K5G9SkdnS7Pr2S7DcDIasmdvIciCzw0Lv7Z2rZR8eiica4lrrz52lwO-rD2380r-UgaLsbX5PhZDc57JSkIKnAfS5qeqxK9koKyD4UyR-6gfA2SsoRbxayLigQOk4O6bIDoJ0ECvEoyaJTohselYUhhQDuwaYQ3UVBsxyNzFxXv4i_ldHItOjckkNBLTyz0rfh0bAbqP5ROsXG7Q9OIMglRSRyDjZdlMaRVO1-lXy_zQ8AoBxuAwGOyc2CQm4zvxMjmiAyMymBdZS5w3-aa6ILoaqvhMzYTEyP8pojxTER7-swPs4J_zroRVV-USiheF9qLRr8C7WtZnzaJXYhAap3HrTtfCVMAy8bHYFjk5zYLmVYw09C04sFxQ3apXWUc6A-30D_Ix_x-Nh0LmnhBXc-BiCPdaGA-iqaCScX94nyMmCC5-26KpbcKZL9qH6ZFUez72d2gmu0oX59AgiJkLaVqmWkC2fKMc-GxO7SI-tzO8AGmi2G5vVeYHIwc2zfRhHuNn8znS7SSRKD1uzTLvJzt0Bonu6NLukVUamhLf5SYmHR3Rd9Qb6NNprHYCyJkim-szlYjso9-EhfRqt3TZtuNx7zbXIoJJ_anSIBQKXrWpLJHr4CMexa0xlnVrB_K6-RPVBfKMZWdcRc2cltFzo-w1VvqOzmK_-B_9FkVhCdObJ-aak26s2CjdzF4SmyetdbUt1U6zDx3lb2InlGz544dNY6OjjQX0X0ImPVTlFAFWFO4ONwnUp5GQmqBjYQZ7CYKqx7RZexDqbmGsW33jnf17hPsToLphEo8M6_p9-I4-PSity9OSX3Gw35Lon-myQxV9Nq_Ui9Mtql08C_Uyhdqwk2FH8wESENlRPoM8Dq044Yj0gHqwUj4xqUht8j9Hk-au6fYM_fLPRyXv9jqjT_KklnmfaeAqZOb4hHRIFBxXA9Q-1rreVfYFWVMz-FRiyf3cWd7QQdMciuMBulWeJjgOUoZK3vQIS5f4AZzwYkNOt6F96hwRtdI8bU6tKJU2afAeqNQ6xiSa85tx8_YGzMsrdKdWAPQIKe66QmQLlQP04k_EoSLH_f9dc51NZYfGF8YwzJuvclpqtAeMNguhPuGj-7V5wFMYhni7osiiPQ==', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de', + signature='gAAAAABoxCzZ6TwL-z6tYv85YPC9CwMFJRrSrWgYUyOhSFYLkdfGwRUIbrgBnmAW0qtzE-shPNPNfbUltLnBS4uU8kMuSMPxotFngVcFFnZ8qmzDUJiEf2CsnqYqH5d2RmuvIXUQTau20SjGte8vOLksGsz0sXRUQnFs7ZoT_2DSy7tKVCCN7fbvkxm2l9D-IibdvGiflbP6lGGgYWczEl3_QyEyJGhDTcL_nUk511C2hjvqI6YkEjujvYjEGMh-BdhFrJeLFL2wCbn6beWaDB2IXYVo7LqhlQUtKksY2PQ4ybBgPhERNvWWf2N-K4NxEQuv6vdB_5ni_BlUKFMabeeeI4wVr5M3HKE6cSgnM8cpi93o_rGu9uSh5fbN5zZcIYumnjkGJ-ULwku7TVtpw_Vha8bJl67qCLvRe90MaCCgJxFKp-IsxakpnNCXVrAlN70cIchPEjOWW3VKrGZ-omyQLgs3EzddhaPmSqDELbmYkxCUuRYdLvZPzhI5VvNiW_j-WGBKEMJLFz0k33oPbH3Q6Fn9HcJSruSsQ8Lc-QWQsibGoABEY_auM7LDLjbvpEYcdsP5BJOBUS8wpyOD7N5jEQL2PYPT3tsP6mvWy7csRIkwEbh1x1sXp6NL3skS6QwpqNiWalP4OQvs8jDi8Gz-NrtNvmX3RR4A0MIuX4q0Tb1VI9PilRUvOvg9hF-fk3bqIh7wW7_iD2eDoXjvI99M-UZ2QZGZlPa1O039QVGLBTi-KwrLuhh-D5q3N-3-DyXY0sjsdFzM5Qf__lVaxtRhZRKyxSONZsTt8mGatlOH4Q-MIPgCXsrLu25gWn6Jr6vt_iQ1eZG30cox98F4aU11Hp-o4tFKuHL8Kbgl9Eetpd4ggfJrTe9QxQfWfgCHAKnhjVRJOepHPEFzSRFKiHrOgATIw_x5xNRacsF_tO1WkpeBdBJhpAUozarHgPQi2A71LCcmd5Zzy7FAL6R_5QtHW-H7NE2PjqqXnf2ZMiMM-oYLHKhfu8tZu9EV7V21xKkovIGH-0OQ-lk44ww8-j3rBNXjWIwp8SO73O85PP7vzE_zJJCF8riB_rOpazJpMCaDP_HUOZq5XhcfHseiS1SownunaXj2wOmgLJ103BowC18-i83n8RVTtRQxLsiCRzMwRH3eEbEClqZ1Fqt4V6NKqICKK3kF3_R_oPtX_-7xYBpl8LGR2Ei_2hXkEIuQ8cCRz1zmuyfjLEWIbm6Rm9wgYafXIXugOqGl4lUc2NSeeJ5T_-ziLEX9-Z6LZafWo9PMvxbxpm86-e5ZqTBlsbukWWIePrKZ6BjElMcxTOUr2XYg-vMAc7QRx11Ld11DwesN_Xj62Kc0TUQRfREPp2AF0gAlYYKLvl7XKwU12Rg6UlWBfJWjX-hUvPY83B7H1saGyAv6V4RR9PODI0p8duptI4mC6u3cYPUk8pOVwFvX1PYCTM3I2yik_XG5ZyI6BIGBNAGL5SoAyMfpqYu0Da4duOIve6tQ3FWkMYnU9sSjxvS00mRJ3JscA-pNm2B_dUXBRATIAD6XVg1m19-pV6OLG58tuDtbjE7nBHUHuS2sm2gbm4PFjpGKFMS07LUSfYax19Ombld0hV_0kwaIjl-4UTcRcqqLK-Tc2E3NPwmdJuzb95-lUoAJG9Jp8UCoyXQRcZk33IGXMYtNquee5K-Oc-ajKjbbevpi6rIEOVjwKrZYwTC5ddl8FBcCBTm0NunKUzo9TkDeEIF6kce9zYdKo9GwYc8Go2S9lxbb6tlizDql2Uv_ZiTz0d5RUvShsMH6RzKiXu8eFzv5sUraMbLUtm3VtZsz9Ld0iztNIqV7q6glrqD2UuLgWxKsa7EbDRvrlBnAOP1iMRtg6ICr2YHYtlwU6R5RzKllG4LGMccZ3x6HsZL6MMaMJc8rLMTtQYqE067kCnXAIBz_-FJS0CzwCwnbh70tc-ytaiTm404Jp3CIBTlGwDwTvXUqzzNAdFRHrilKUPNgtKb6uQAyPhJZwbFIfrFevaMdOGZ9UhJoKtQtsSj1qM-dhXIkn4T_SL0o72wgb08zYSjsemhfJdbNO6jPG_GfWV6FDAhY9vNyTT8XlqgsePnALnV60AIvRZPI7mfh8D7F8SI0yZU4AJVtEHKKgStPvCuixxtjTt9nSWm-cXOItJdKYxMjVtWCmcCI9LbPolXXkewgNhmUx-b0XlY_BN9cX2j0COic5Ml6LS0BZ6ikG65a-7kIl_yofLeat8q9-4OI-lhKYOxwMhQq8yWNCBuJZCGg5n3DM_QgEQt7cqWYuTuTMTgMnRIvSefK_Q-ZSY-ZfzPcNp13-v56KgA_yUqYOHvQDu4ZuZCI3KvlO1WSO17SiqiNZvo3iaM2BrrgzOAJYcSx4TUzl7ZuFE_6LkokGlxguZH82W9dpewDyN83yLLwakOhgLfbTlMCFs8NCLzMr17eBFNX8YqP9bh88f98KtLSYr09naEesCwW3v-M-I1MUdR7oEC64ixrAWEwpSI-Jcc60oUgvLBVbwkeoQWI29NqZCS2JYGsxjXfNmhWWB3kW7_7ik5RHk3oNRWXiEQ_N_K7c97Ui1YkomyAAZv4t3zQYHwsLBmnf2DCEMBViQn2nXXjGwBxEf9KY2dlT1ihIbcPBmyzI17UrKYXvYKkfE25c_R0VjQtRSiXrlEWkBgLwRzWt18_62P00dJRAeJOEq6etGKoSh0PsrmtCGfnOf1EJhksjZPyObdHWm_yrNiX-h3myewuYT4BIanBFdUQxQvpNyvoQJIMtKH3gAh9oCJY8os-vS1Mx7h4Zh0gEdQZhIVn7KoJwqbx09F8hGokOaVXx6H9gMD5kVZkXkX56AFC78ykpMLSsolvyUhAI_qxcpTVGSgDIzfK7BzQsMd4TawOtHObxfvVr9qojhx__eQEipXplbfOVh8vjM8TFY7eb8k5EvxaU_pBuEmSagGoV0fiPUmMTzipVTMQ-cpaF6xQSVYZK3CvmUwxHfcX2r8lPPH_SyeiVFKRdqTmpIGYw8drhwc9GFgFM_N1O_iJuhjSt-8iLt9BExKYJZftIcXPYl4eGgC1yC6oUBurdmvQUOZD2tv_isd28fMNeoiWAy7HCDz57TAkJg9nJsfULk_z5ClBqz7rPP9Qq9CZrYEsz6Lggj19AXh6PmA9Skl9nUSgsqn2GvDI3I5E8YmxhlP58XrZyYKLkYLqqAMDy4tqI2eiQMe4z1OhMGpVxoEt7ACxw8-YaQTKgItzSNNskrXkRsGvWa2m9XcaZNwbZFeqek7OZ0vxLMsQJ3InnvY1lj9aMUUGukolxZEZ0KolEPOsIKhwH4iMg79yNlxeqdM2e-OoxrUyIBvBqC5uNemtqnulwarV_0K4XYtimpR2ONcwjzSO-eY9untVEmJRdw-OYEJiKJoRRNEjmr77UuJLDhPqjtxmcF2LHRTbpQ8b73Vp-mt-1okyP2yOr8Rd6LbsJuntv77VWE6Mt2JBzJpwJZab3mKd-2c6VkTswJX8p8Lf3g6m3uPwBRrvyCuuxztoxG2rDrh-3krcjDFnwU5tZjpZ3G3pq6KXbcmsX3kvJhJc6er38kO6uR9SkJUcRkbQPZ5nUKCtRZ3AkFukiT_YHtUamsUlA0nX5DI0CcrrNtu71HD7jSkwF9-P_QNX3_c9k31cSfHQ8BCMHcy7DO0vPYuzj2BiStEdTymAXfMeTFVO3wUvQf9KyuqVnKFMtFwP2DaospAJCd4TaHeDCm-uczeg1of-R2SB0f5XorCQ5MljHFk1VTHmWG3LHgCTEmAtx2KKbdMO8zXsBop6LAnFj3dNEBv1grO5lMCZRqKRo-csAJKwqXn9kuIa6GXi-NMZWBGLvxWhJpWdCeGnaFjCk-7uzPQ7PN_JhtPjeI3W-9A5bY8RvzYLrKKIEOEMGyHb-77dcYPhhLgn10-HpglS0_uJw5f0STZE60rxVXH-sb7vrpyAyBqMUh-OdoGAqR4r9dflKk-jECG0sggRuzx8jLGGfO-dNZSznD8JbaCsRDdLuHWiFSZKJswXwX5PS9rmVpYRrH-0QniMhPiMOuINwp9GvTtzSvXNIPBWtNMsY_jN_O2gIKxL-KnyoQkyUFWHN0Anuyv5pCHQk1lhfcR0alSvDLVmVVgi1tQdjsdAl19qMdfm43ViBTRLDwzP8iauhipIfCpxFjak0Ka8uFaHfEhKstcmUdxEnzIsN3SQXrPud-p0YJ3O1MsyUDjzMROP43FKMhVCSnM5PsXVvuPZKRmuEFbJyj0dwwBnSH-rk8tuK5SYoX8PIrJXyAySgj2VouGdzvkqa9WPSHU42AxDZNQT2c5pEI3gUS7VzcGCTwoznmFtmHKGOJj8HxKswzB2z0AumI_ht8zx6kehnvKK4cJfKjdJfO--2o_gzVR0DkA1HcenMD4ugxj6rWQDiJvo6cFdfkXpMfLAe4NQRLVLNv4UdIehCxCHMsF1RZJf93Z6sdxW_2PumLLcfdb2XIkouuFN0mECzZlWgM4XLUErlaaqDc8oU_gRrgHEJbjZqF7by2nHtqCjyWOZC9n7vF18iSRJES5DX71nY84a8ydPR2_KEYfHHgqF51Nz9zMo2Gv6ramAFs6lZC5rjOUR1VmpLd2pKs-sPQJpYNncwbDe8dG_NDJI1wIgs2K42eKPE4lEueCtp359ifPU58DpJA0JiB_FW3jBBh_9MphsnQjuso9S-YSaSFt4Llc_Zf0MJ3CbiEsk-IwfgsLysFQg-vJq9hHR48ZoW0kx7CaIAUgkiJg7-7m_dVNsfaUM-OSHtfryYXWrUsotLJ6OTuicPOfb_LfaYz5OoasG0o-4vdtF8e4VX6ZpR_Krje-dZaCph1XjgGLfFlRRkywl7i8IEUirHpQJaoCPmc9q61hjETcuPCEVDy-dJMwPLiNzXY1mkJI1lQQ1LL8Ke5EgtAcC-2K_5Nwh4h4bafWA44XgnisMfYDv66CzsL35i0XtZHibfLqPwdLyHqInlLPtiFyhJZifcJ_GsiQ0U4SZO3WHmvSG9AHy0YnA2jC3O4x7yj73RmroELKFvT-_CSO5LVz3qRRVdlyL0CQr3lkHUXJbFNpOz7Uek4q6MjB8Cn0xAKzt9ztcClLdAA9NkR88Dy3rOP5yPjRJJVVG6SbelsE1SnPDaKQqu2ZN1zdtGUY9AcULc2dGFb4mezcbJsC_eL3DD0LwfwcSAILDfDIrqHACR0XmI7jmF_p_PzmBhMsocLnblzKTho5ufo4htqhTEjVdFywm9WIjw1N_9PWge3i3J8mSdILp0HQ1QvbRlMt13qPyLNwAmY75m4Zw7EIlk4cyxMjcTSY02TRCC3cBKX2e6xl0DIAygChReVOxL16BT21sEgT2ps24Mljsvht-fokU3JPtj3fY8wojksHAWNv2hlF62xKrOv9h9AqM_Q9JlghHHNTrzxvT8SVeLBhEvysbhErrgtTPcgvKfMUCT1JMWolxLZUSFEFKNR9cl2GiSqMIhdTL3JvA0-etZ7ykeIbUEU0jlRZAw4a3vY1R1zW1-c6XRSNiS9VDPAfcN2OD4bXL8Hi2Un7Vc_pRyWn32kWQqQuw7v6J4RB-sr3Bkb4OzUljytF3ixqGkMIpuA-LjJwdBJ-XgR8Fj_DONbguNct7MTkMtQqWU9twa8XF_sot8iEYc1UOkZQVJvTtNclIkklJhP8VNj1aY18Y1Gtnn0fvfaOFfY4wa7HIq0U7paT2Fqb0xtY62bqNM6rRXLsAQex5HvMvHQvL_9JbQngBOD2ehk7zIAJKZWzbAKqKCgH-_v4kaGBVrciIxffYF6WnWq35pQwbsvNqQG4uJR0qhLEXfc5akEon1sL2fjxim_GFcgunyCqL28lMB8yhnzA48QESW0sotVss_GIeeftSYS74zPaHXiuSx0RoAmw90kERXPDGVCRkwTTwaW2BkshCJCx2JOSDEWVRMjxngzaoroybl9A1VzTrDEbodeq2O_kVyZfrZE58BO8DDd6ZH07m4zuiL_NKXLw23NmC4CuAN0ufn7HFtX_ow4ZJILfZI9PczBi16liV0LWrBwvadZ2Lf4o3sV65CLg1VKujttEiOhtpYjmB9zIRLfAHViz5vgTonL6H_9N4D2dXLzUWlaDPNGJNnt7EbHS64f3jSXGG1fb7LGKhNtTHqbfBJnMpmPjFQGb4ae2kKv_V_L8xgXNpQRi5I_QNTzDzfBs4avowydppTpEE1b8WNITLc7qvMa6gwpDxp2N91fIVC9wyd0k2DXaz3VbDn-2v7W72D2UPa0L00NKvIKYecd9FMpYmkEyxJfFFr7b9hKA1ZXdqlejjPJPjVYC9XTEZLEwzdeoG6yrxtYMrl7o72M37uIRNZAj1Jf0B8s0qhPaaBfUVKtKl7bd2Ub2503LZ7ZvJ_1segaIT4S8nt17hjfep3re_4rEKA2rrxMbWoLhM4qkAPZvdjyAFF1YNB7u-Uex7l4STRYSpzl4eQIMSl7N0pGlKk58Z1FxTKHsAZTkZYtj40lptma1AfcwRPViNPceCFA36XfVjaratWPYgDhcjK8nNnAhxvL7t25nPbCXazPK1D16ZkY2SwcX7sMx8QklNQdzukZwGyP51yhU8o0PT-u3xGDaXnP6Wh_o35cCIRnar6Id9h2ovViZXJRUzNa8aXedxiFp7hLScSQfIPrPBcqN45EvLjEmtLvzzxNgHY7zw6gzj5QFgv64u2fI9zAY00B9U37bHIZPQnFAhge0466vyXNENzYO3acUGo5HhyFDlcuiBCbIZ413bmfbtRbj5W1FZMY58l1plTmNljfcwQ7Kd0PUGvGEb_jwKlmyKni1HzyyUmElGHdRkyS5Yk7aja6AJOk6z12WUM5snqG-uRVkByxCXQ2KaFR6Qm-IOHMFqzrPINkjyEJgG6KyKfkF5ScVfQaThHBuMrb7ETWMnlk0L28ZszB-TLt3HfaxINsoD5pndSSqBpHB1z_2kEweik3y_PdxIchV3CyBLnmrlqBPBIarCoM8VwzForh3RzQmgNsOGkJXy3Lk0rIr3t-BE7qgXWsrDolobtH6MMFO96Taa6MYIYYYbYvzQYcDuQwD21yGTLwKAnynBDn99bGYEg65LomsJbTSKCYQRcj2Rh2AaScsq8JiHYJEGAnRkgsXNivZnioTlkI9_5XqXBJt3GKMY37YL6qIU3XJ7HapKELorbX4fH_JlOIZLIOIaU80295GZcFdx1I2La9lp_UvAtALEDJklGNvbcDG51NNn2mj_P85vIfzsVdrfX7N_AftR8t1kQx7bdbVLyP4ls_qKnXXigfNJajWtPVgwGeroQq2jtaQw6Tj2Wsi3Itmo5QNg3N_ja3erlEHEdTo8lm4XZHjbl2bAH3n_wuEdYKTt2B3jhj4ddhO8atc1fryqbRfn61YFKUnR3f5vQ1qUq79uisQi0cvHr6DQ_12FpKzFvFckAkQmbk5fcS5Ri5S4L_JtFAexj8n2f_oYuG_9CYYplOU5i1Q84MyXUZ2fZyDhRPRiyjvPJ07_IAiL2ny1btmIFtVPeQSHVwfun-m5Lba3KgnZIJ6CRFqxR-o6F8e5K78d-bAotgA5vOcfeC_fBQfaom-EX0mJyzf7_Wjgam4IA_W3PO_wGoVULHfr7mwUw2Qc-VzITtjajZvRoT-SkVREyJVnKBxHFj2cNTcTtooSxCu115KmbtePf2OwgJocB2jyPT2GK-kIVZtuGdv4Dns8m7Z7FpT7PvjCVjidQqVsJxFQUs7ZzcTXX4vdChdcVK1_OiUwCJKiYN9ZKGA_OmwQJjhnV6gutHFYanu3Gm0m5PQLIM6Pip7yXCw8-Lhq0sxFTl2f-7DeYlfrWpYJyc2wR3T2u-kHl1g52CxX5XoHCV1LsBIU75L23Igsx5_v9ZNeewK2Qh8yWwlWZ18qnXOh5ZJqJUpYtxy3sUhHMG8fe5RKVGbbJyHltosuW26yJ9eUQXqJOSj4wv0YN6a-BezPdkkCqdiUGDHllrgAi96kkeM4jES6iZV60rTgdmfOS03JL0eqCwLnH0gP9t5Xq7l0-GUKp7mrsUjgN4Utb89AVPyIDFWxfJTuFJK-g6Z1EHexEvDY4iTsuOdq9M49_zV6iL8ChB4p5l0lUOiFzIH1Qj-gNMqpU2p0H73cMd3MNeecFhMsCfRadVCO8D4UN39W2mEXDxLBlTN2f4m6aDKjLHi58zyDiJ4aga_ntZRnv56KJpWob0A-4U6_GRJI3OynwKPfb0wpAzK8Gm6Ak1OpxvD-8TmbKUKVA5m55PMoBgGbmvtrwC9Q9Exg-zdotpZ5-iWM1ssnKLXobFa2SmYJeOcGbEjh_yvRvjBRNHxWmq_sP1ohPCTce4Pt97WVQs0Kc_Peb85RqZEnCyjRfV4C3nFUkTxJhFJbmIBPG-VPJDfKEMVTtUe7xB_w55BKViE87CTrd9AAveBFKkBrL3x4bVba3SK5HLU3tOgUPMDnN6Q-waVbjTXsNPGPwJjvbDAN-xwm1V19e-gYcI9sExy4hH9fCkx7Y93e3EMo_EvPA8ZFO8C-KKKlKttqg66BlOp_WYj4GnTpurNDHjVtBQZI6FN5HGl72n7ZL0me0cbfiDkFh7mIfHJCc3EcRCp__gjeBYQaGaR3hh7hLrNeuJB_oAfW5mz-2mIgUYz7vGxRrTeo9CyNYjr5CNwd-hp06pklYw1Bmce-1ZqG87pwFGjfWaAABwqNElf9Wdhgzll31WmopAxDC12Q8pzpAiFfkWWeHsPgvx_Hfm6B50TiIn_LCi8hjTaVUkvtNxZgiKJdAdL5btiUvPwVD10EkysT4dfAEg6l9Z64sZT6oss0KlH55VrNoLOybfx9-TGJZOCB5Zf7JU0KuA1Dpfp8I8TlCOUBwybFvNbECafzsrKB8XI6cmvDtsG0NqNzifoYUPzZDv4eNQhb4QAxlWx_xjiD_G33rgZ27DfvecgVkhDUc317uWUTrWt0f4WJItv4A8P4fj2CDa4cAjfe9CCWM8oehppoxScG5nBFdeebs1m3efdBi0VlYbJTEFQC92q0Zdr7kdfo0FbR1GQ05x66u5b0qLRqqsgF6n72p8Vo_izkLs1N3HKOz9AvcoTmD_tD70rZC6SVJ0jQcKtOMre7VK7lJQJwkuuUL-TRcVYVFeKln1CDs0zpqwza1iCVw3LcUdh96iPsN3XcHrH9pqUxSEY_T6Bq8aSTHdf-iqucTB2u2zsq5BgU40_zXUqvfvQRhcHbaNl0NkdbWKVr8AA3KkoGHMe-H_FBRmyBFX2KL7F4naGngOz7crLfNoSqvPF6cBudn3Q_PPxutj_F5d3FxcfHSHizhfZ3sC39DiwyKgWMU4rUm4gsyYpnKQ90aXtF9nuLWDyNZEb1hsHiVyIoNkUx4IznUY94rrMNzlobnMyqtaic819_vgKqTo9jYA-i5JgMoTPy2DTtIZIpU_p-TggdpEActJ7qncHdQjM0mCrZGYo78NvZ0697fexOgo-dQjfUmNNKNtLp1UQiMBllHwIDZzRePAgOeisXx-E10lLdPUm6AKQcg6IYbvrPDil1_EaQyV3JXqEgNCZwXvkDIh2cnaBLUzyWsep_iupiypilShz_QWLsa467qw5dJ_Q0vR1ulAzMWokaCmTTiJQ6RL71J4WBiGAnobFDrluwJtRr4BTRNDmzDBh8_G3EKTS5mr6W1EQnFnMAqIrW_TOvKasBlQqlLVcFDlllp7X2akyW6Z23NBe7JCnYi4m1HkM0_gnHqnFbnT3cS4umAd22ugbPbo8gn0KRoFxAZK4_4JPHbz_T2itrnDcl4z6_50F-I0Ynp9nHSKnlG5x5V6IGd47vfF7sIks8Vfpq8LUKgQu2g9XHzwf-q_jmwH-eokmnUlznsJnZWnz_GnHyeEMsdQbBKDGK9rjNuMC_QZGuiaARSlSvP7hMyowcczvtuKrN7sZc5nTWPD31UV-TBzrDnzmmsKZ_3BdPebNj71vt31hatE4Mc6OJJUZ-HPPUieICZJFiYXltJBqApmSrscPjDUy9fUoD0iJudrtDu6UJ31SFMkaapXqHG2FqMOwkEk_T5wGmdZ3Y6I8QKKiI4bXRcjPexjVQUJdHnGLRZ4L7tyKU1mFJHMEIMwAer1LiYsnFLHBt3XoAQbNu7LewtB3Cd1Qzeo16USsORAgO8DYtAiu9T0yfTOMAn6lfMgEIdqdJdY5KiPC2TWro08m4pn3mhDlfIWB4XzyBsaO8JiRlF_7Dfg0UpDEnk2AN7ACqsjeUoMk5478ov9JeTPOnCDw2W3x4-w3VhTndvrAD3OrnDoxsc7OcoQjni96fsh-E72g_FKaHJVqH591bROjD5nAPTj5rseGJYDTJkAlHauG67pXgIpMLSLgTUUeplBgjDDTWPdww6dYp8yW9CJNOXCrqmAunZDJe5d0n2BmzGLiOHxiDLKT4-7XoycRXq9adUn2uWgHUooKJbs4BI9sF_28FhxsbN5E2KT4b51aZsK91802OXcSbLCF1K-HqxFNeELpvrlnYT4Cefr_gQydbzRvzSdpTSpUTLtCspJ8RZzJZzQT6x6DnOT8KVt95Sx2OsaE6zCOEBUf5EX85M3Xw630kFQPAjAXx85FxEos_Fl5NtgSssugztP0Q6dbXJTuQrsSgSb6TWsJWaC6agqNudU2lkI3lWpxcxjnYdlDisZE2CVtPXIbMc0fP81Oz9g-LybenNrYDUdIL_FvJ9FM2ZSAleLrEgMM6IyDUXBC8PXA7QP-DukpVBDGkt6GRaNqiqMFN6ceHu1IcTRy8RBucg2ahZqS9BgLlbj2xGANaeZKjzvNKBbtqawx-RkwsHludZ4I6WaLC6-fCnqE0GuK3kw8mbym6gAbfHouwbWarAdtesd3tjoa620dCNg9QwQ1Hzgs4Fd0pjsSgMFB7ahRSDy78GWbdPXZqPollN22uUgQ1zWEva_VxrPK2C05iQMPE4Cg5X8XQbxGH6GY7wuOnc23Pvh9qe6po8voXKaUAPVb3oUGgYx7lgsWZIW-2c861ip10CSjcfFm6AVrS5Iaf7m0OZvUvL52q2r5Py_LWxLbgf0ubrDXMtHbhEGXYmiRaHcmuOxoFUtaqCB6kr6970im-84hk-SiCoL_96yg6Bna4isurYJb2JQgGktUX_SjcB4TshvDDx-G4H-lUYId4AaqP1zNJ0ryUPOlQQXlKtc6s0tUfEZu5SagAE6h6iTUkCr4hJ9hLanj_mMSMJiCjBCFUYMeZ4LCxzQagyR5qWxq90n2HlHhmPy5eCj16DTBIL49ScuUqyN5x8fWt23H-B0VjTUdFEVk8FFaPsSFv0SddM9LEvrlUcA-RcMpyZ1a2ifF7N_HwvRlMslVSzW2BUZRibnB0xpeZlUbqy2CDkr10azuxJYajE6giMCnSHfiKM2EPMuFl5-sX6FiyfsTIA3CmcdoHvd83KNQbMuDRp_nDCAl6LNcj8CXPyenI56CAX5owOddnszaI3C7fEfW7MavfzLE4KlNBPYeFmQLL7w0Rw6uZfqjBKLFLNtXNDBnJW3GSWYKFB0QiAMjf_9_nfOU0w3cwgnfsdmUU0BG_9bXy-qvzYvnWs1eLfoCfruH7gt5Bvb4iGPr37EFMI8yv-df__xbRHgDxVtAd-A5kL8N8DR4U6eSsw5UH8--p3ZpLyrh9vklTf4LDr0xt62qvZjUKzcuMZjQpcBvDHmKRx55aZ8BEkKhIhsWlZJMsE5prZOz3pwT5_pAp1h9u7sw60NnWisoTdBM08hP-JD06OWB_OFPa3I0x1boTojwlzVpiVGUdNeMgpWKa9wQj6rVsEl3-UFIyrKNpgir2df5m5q9vxZ3TSKawBZUAQJnQp9aYgysMtCnUCNrZ-zaC6mojA6cBLk-g5rCcXsyd1WqkHrFwYoPAu5593tQA-ttSVSFCUQxCILqKUZx1-fw2NIchE-NUak3dAZ4RTWm6EwMGXh6rmanI2swBjkglVxw3CfmOAsL7yXEhm2tOofu5EoADa_lEdy8ihHgsCPoJiq4hxlwFXrg9y-Pww0xsrldPuFcc6AAIpPR9UrKHoEdxoDnANqi6zsBTsp-VdyaNj5nFWgpm5mxgnuWUrBGif-U5ldingoapB0hJ50--CucJyHaLHHV2m7WcVDTXiykeHhjIp8qnKBaXwoyezqmLgzIOmhrJgqBH-drr_Usl2Mtzq5lyA2if9MFtKcktldky2GXDiMlwLWSf70Jj5d2Tq8_4P0C-StEZ66V_PkVarTSrFahni4g1OqUJbxxsK7oV932wEtpHJPo6MYnkebOFGlGQlxxk6OlqoZwyP6xbJCwu1_36FuIYcl09Vy11EXK58g62eDyg9eGaAAe1mU4fTByEowy94v67qTC9otmjGlB6K3pyqsGnpWEGz5FujtRPO_ChDNN84qZRMSk5QMU3jx1t3-_0Mg48WnuWGiDDveAhZVxNz9HThbvMviECVk2E70W0nj9XEybPhNLcKQxKMekE6_3qJxUTk8Q7KJpoDysmWznz0Brg-GT6NSJG0pFFfgdNCAK_K5G9SkdnS7Pr2S7DcDIasmdvIciCzw0Lv7Z2rZR8eiica4lrrz52lwO-rD2380r-UgaLsbX5PhZDc57JSkIKnAfS5qeqxK9koKyD4UyR-6gfA2SsoRbxayLigQOk4O6bIDoJ0ECvEoyaJTohselYUhhQDuwaYQ3UVBsxyNzFxXv4i_ldHItOjckkNBLTyz0rfh0bAbqP5ROsXG7Q9OIMglRSRyDjZdlMaRVO1-lXy_zQ8AoBxuAwGOyc2CQm4zvxMjmiAyMymBdZS5w3-aa6ILoaqvhMzYTEyP8pojxTER7-swPs4J_zroRVV-USiheF9qLRr8C7WtZnzaJXYhAap3HrTtfCVMAy8bHYFjk5zYLmVYw09C04sFxQ3apXWUc6A-30D_Ix_x-Nh0LmnhBXc-BiCPdaGA-iqaCScX94nyMmCC5-26KpbcKZL9qH6ZFUez72d2gmu0oX59AgiJkLaVqmWkC2fKMc-GxO7SI-tzO8AGmi2G5vVeYHIwc2zfRhHuNn8znS7SSRKD1uzTLvJzt0Bonu6NLukVUamhLf5SYmHR3Rd9Qb6NNprHYCyJkim-szlYjso9-EhfRqt3TZtuNx7zbXIoJJ_anSIBQKXrWpLJHr4CMexa0xlnVrB_K6-RPVBfKMZWdcRc2cltFzo-w1VvqOzmK_-B_9FkVhCdObJ-aak26s2CjdzF4SmyetdbUt1U6zDx3lb2InlGz544dNY6OjjQX0X0ImPVTlFAFWFO4ONwnUp5GQmqBjYQZ7CYKqx7RZexDqbmGsW33jnf17hPsToLphEo8M6_p9-I4-PSity9OSX3Gw35Lon-myQxV9Nq_Ui9Mtql08C_Uyhdqwk2FH8wESENlRPoM8Dq044Yj0gHqwUj4xqUht8j9Hk-au6fYM_fLPRyXv9jqjT_KklnmfaeAqZOb4hHRIFBxXA9Q-1rreVfYFWVMz-FRiyf3cWd7QQdMciuMBulWeJjgOUoZK3vQIS5f4AZzwYkNOt6F96hwRtdI8bU6tKJU2afAeqNQ6xiSa85tx8_YGzMsrdKdWAPQIKe66QmQLlQP04k_EoSLH_f9dc51NZYfGF8YwzJuvclpqtAeMNguhPuGj-7V5wFMYhni7osiiPQ==', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de', + signature='gAAAAABoxCzZ6TwL-z6tYv85YPC9CwMFJRrSrWgYUyOhSFYLkdfGwRUIbrgBnmAW0qtzE-shPNPNfbUltLnBS4uU8kMuSMPxotFngVcFFnZ8qmzDUJiEf2CsnqYqH5d2RmuvIXUQTau20SjGte8vOLksGsz0sXRUQnFs7ZoT_2DSy7tKVCCN7fbvkxm2l9D-IibdvGiflbP6lGGgYWczEl3_QyEyJGhDTcL_nUk511C2hjvqI6YkEjujvYjEGMh-BdhFrJeLFL2wCbn6beWaDB2IXYVo7LqhlQUtKksY2PQ4ybBgPhERNvWWf2N-K4NxEQuv6vdB_5ni_BlUKFMabeeeI4wVr5M3HKE6cSgnM8cpi93o_rGu9uSh5fbN5zZcIYumnjkGJ-ULwku7TVtpw_Vha8bJl67qCLvRe90MaCCgJxFKp-IsxakpnNCXVrAlN70cIchPEjOWW3VKrGZ-omyQLgs3EzddhaPmSqDELbmYkxCUuRYdLvZPzhI5VvNiW_j-WGBKEMJLFz0k33oPbH3Q6Fn9HcJSruSsQ8Lc-QWQsibGoABEY_auM7LDLjbvpEYcdsP5BJOBUS8wpyOD7N5jEQL2PYPT3tsP6mvWy7csRIkwEbh1x1sXp6NL3skS6QwpqNiWalP4OQvs8jDi8Gz-NrtNvmX3RR4A0MIuX4q0Tb1VI9PilRUvOvg9hF-fk3bqIh7wW7_iD2eDoXjvI99M-UZ2QZGZlPa1O039QVGLBTi-KwrLuhh-D5q3N-3-DyXY0sjsdFzM5Qf__lVaxtRhZRKyxSONZsTt8mGatlOH4Q-MIPgCXsrLu25gWn6Jr6vt_iQ1eZG30cox98F4aU11Hp-o4tFKuHL8Kbgl9Eetpd4ggfJrTe9QxQfWfgCHAKnhjVRJOepHPEFzSRFKiHrOgATIw_x5xNRacsF_tO1WkpeBdBJhpAUozarHgPQi2A71LCcmd5Zzy7FAL6R_5QtHW-H7NE2PjqqXnf2ZMiMM-oYLHKhfu8tZu9EV7V21xKkovIGH-0OQ-lk44ww8-j3rBNXjWIwp8SO73O85PP7vzE_zJJCF8riB_rOpazJpMCaDP_HUOZq5XhcfHseiS1SownunaXj2wOmgLJ103BowC18-i83n8RVTtRQxLsiCRzMwRH3eEbEClqZ1Fqt4V6NKqICKK3kF3_R_oPtX_-7xYBpl8LGR2Ei_2hXkEIuQ8cCRz1zmuyfjLEWIbm6Rm9wgYafXIXugOqGl4lUc2NSeeJ5T_-ziLEX9-Z6LZafWo9PMvxbxpm86-e5ZqTBlsbukWWIePrKZ6BjElMcxTOUr2XYg-vMAc7QRx11Ld11DwesN_Xj62Kc0TUQRfREPp2AF0gAlYYKLvl7XKwU12Rg6UlWBfJWjX-hUvPY83B7H1saGyAv6V4RR9PODI0p8duptI4mC6u3cYPUk8pOVwFvX1PYCTM3I2yik_XG5ZyI6BIGBNAGL5SoAyMfpqYu0Da4duOIve6tQ3FWkMYnU9sSjxvS00mRJ3JscA-pNm2B_dUXBRATIAD6XVg1m19-pV6OLG58tuDtbjE7nBHUHuS2sm2gbm4PFjpGKFMS07LUSfYax19Ombld0hV_0kwaIjl-4UTcRcqqLK-Tc2E3NPwmdJuzb95-lUoAJG9Jp8UCoyXQRcZk33IGXMYtNquee5K-Oc-ajKjbbevpi6rIEOVjwKrZYwTC5ddl8FBcCBTm0NunKUzo9TkDeEIF6kce9zYdKo9GwYc8Go2S9lxbb6tlizDql2Uv_ZiTz0d5RUvShsMH6RzKiXu8eFzv5sUraMbLUtm3VtZsz9Ld0iztNIqV7q6glrqD2UuLgWxKsa7EbDRvrlBnAOP1iMRtg6ICr2YHYtlwU6R5RzKllG4LGMccZ3x6HsZL6MMaMJc8rLMTtQYqE067kCnXAIBz_-FJS0CzwCwnbh70tc-ytaiTm404Jp3CIBTlGwDwTvXUqzzNAdFRHrilKUPNgtKb6uQAyPhJZwbFIfrFevaMdOGZ9UhJoKtQtsSj1qM-dhXIkn4T_SL0o72wgb08zYSjsemhfJdbNO6jPG_GfWV6FDAhY9vNyTT8XlqgsePnALnV60AIvRZPI7mfh8D7F8SI0yZU4AJVtEHKKgStPvCuixxtjTt9nSWm-cXOItJdKYxMjVtWCmcCI9LbPolXXkewgNhmUx-b0XlY_BN9cX2j0COic5Ml6LS0BZ6ikG65a-7kIl_yofLeat8q9-4OI-lhKYOxwMhQq8yWNCBuJZCGg5n3DM_QgEQt7cqWYuTuTMTgMnRIvSefK_Q-ZSY-ZfzPcNp13-v56KgA_yUqYOHvQDu4ZuZCI3KvlO1WSO17SiqiNZvo3iaM2BrrgzOAJYcSx4TUzl7ZuFE_6LkokGlxguZH82W9dpewDyN83yLLwakOhgLfbTlMCFs8NCLzMr17eBFNX8YqP9bh88f98KtLSYr09naEesCwW3v-M-I1MUdR7oEC64ixrAWEwpSI-Jcc60oUgvLBVbwkeoQWI29NqZCS2JYGsxjXfNmhWWB3kW7_7ik5RHk3oNRWXiEQ_N_K7c97Ui1YkomyAAZv4t3zQYHwsLBmnf2DCEMBViQn2nXXjGwBxEf9KY2dlT1ihIbcPBmyzI17UrKYXvYKkfE25c_R0VjQtRSiXrlEWkBgLwRzWt18_62P00dJRAeJOEq6etGKoSh0PsrmtCGfnOf1EJhksjZPyObdHWm_yrNiX-h3myewuYT4BIanBFdUQxQvpNyvoQJIMtKH3gAh9oCJY8os-vS1Mx7h4Zh0gEdQZhIVn7KoJwqbx09F8hGokOaVXx6H9gMD5kVZkXkX56AFC78ykpMLSsolvyUhAI_qxcpTVGSgDIzfK7BzQsMd4TawOtHObxfvVr9qojhx__eQEipXplbfOVh8vjM8TFY7eb8k5EvxaU_pBuEmSagGoV0fiPUmMTzipVTMQ-cpaF6xQSVYZK3CvmUwxHfcX2r8lPPH_SyeiVFKRdqTmpIGYw8drhwc9GFgFM_N1O_iJuhjSt-8iLt9BExKYJZftIcXPYl4eGgC1yC6oUBurdmvQUOZD2tv_isd28fMNeoiWAy7HCDz57TAkJg9nJsfULk_z5ClBqz7rPP9Qq9CZrYEsz6Lggj19AXh6PmA9Skl9nUSgsqn2GvDI3I5E8YmxhlP58XrZyYKLkYLqqAMDy4tqI2eiQMe4z1OhMGpVxoEt7ACxw8-YaQTKgItzSNNskrXkRsGvWa2m9XcaZNwbZFeqek7OZ0vxLMsQJ3InnvY1lj9aMUUGukolxZEZ0KolEPOsIKhwH4iMg79yNlxeqdM2e-OoxrUyIBvBqC5uNemtqnulwarV_0K4XYtimpR2ONcwjzSO-eY9untVEmJRdw-OYEJiKJoRRNEjmr77UuJLDhPqjtxmcF2LHRTbpQ8b73Vp-mt-1okyP2yOr8Rd6LbsJuntv77VWE6Mt2JBzJpwJZab3mKd-2c6VkTswJX8p8Lf3g6m3uPwBRrvyCuuxztoxG2rDrh-3krcjDFnwU5tZjpZ3G3pq6KXbcmsX3kvJhJc6er38kO6uR9SkJUcRkbQPZ5nUKCtRZ3AkFukiT_YHtUamsUlA0nX5DI0CcrrNtu71HD7jSkwF9-P_QNX3_c9k31cSfHQ8BCMHcy7DO0vPYuzj2BiStEdTymAXfMeTFVO3wUvQf9KyuqVnKFMtFwP2DaospAJCd4TaHeDCm-uczeg1of-R2SB0f5XorCQ5MljHFk1VTHmWG3LHgCTEmAtx2KKbdMO8zXsBop6LAnFj3dNEBv1grO5lMCZRqKRo-csAJKwqXn9kuIa6GXi-NMZWBGLvxWhJpWdCeGnaFjCk-7uzPQ7PN_JhtPjeI3W-9A5bY8RvzYLrKKIEOEMGyHb-77dcYPhhLgn10-HpglS0_uJw5f0STZE60rxVXH-sb7vrpyAyBqMUh-OdoGAqR4r9dflKk-jECG0sggRuzx8jLGGfO-dNZSznD8JbaCsRDdLuHWiFSZKJswXwX5PS9rmVpYRrH-0QniMhPiMOuINwp9GvTtzSvXNIPBWtNMsY_jN_O2gIKxL-KnyoQkyUFWHN0Anuyv5pCHQk1lhfcR0alSvDLVmVVgi1tQdjsdAl19qMdfm43ViBTRLDwzP8iauhipIfCpxFjak0Ka8uFaHfEhKstcmUdxEnzIsN3SQXrPud-p0YJ3O1MsyUDjzMROP43FKMhVCSnM5PsXVvuPZKRmuEFbJyj0dwwBnSH-rk8tuK5SYoX8PIrJXyAySgj2VouGdzvkqa9WPSHU42AxDZNQT2c5pEI3gUS7VzcGCTwoznmFtmHKGOJj8HxKswzB2z0AumI_ht8zx6kehnvKK4cJfKjdJfO--2o_gzVR0DkA1HcenMD4ugxj6rWQDiJvo6cFdfkXpMfLAe4NQRLVLNv4UdIehCxCHMsF1RZJf93Z6sdxW_2PumLLcfdb2XIkouuFN0mECzZlWgM4XLUErlaaqDc8oU_gRrgHEJbjZqF7by2nHtqCjyWOZC9n7vF18iSRJES5DX71nY84a8ydPR2_KEYfHHgqF51Nz9zMo2Gv6ramAFs6lZC5rjOUR1VmpLd2pKs-sPQJpYNncwbDe8dG_NDJI1wIgs2K42eKPE4lEueCtp359ifPU58DpJA0JiB_FW3jBBh_9MphsnQjuso9S-YSaSFt4Llc_Zf0MJ3CbiEsk-IwfgsLysFQg-vJq9hHR48ZoW0kx7CaIAUgkiJg7-7m_dVNsfaUM-OSHtfryYXWrUsotLJ6OTuicPOfb_LfaYz5OoasG0o-4vdtF8e4VX6ZpR_Krje-dZaCph1XjgGLfFlRRkywl7i8IEUirHpQJaoCPmc9q61hjETcuPCEVDy-dJMwPLiNzXY1mkJI1lQQ1LL8Ke5EgtAcC-2K_5Nwh4h4bafWA44XgnisMfYDv66CzsL35i0XtZHibfLqPwdLyHqInlLPtiFyhJZifcJ_GsiQ0U4SZO3WHmvSG9AHy0YnA2jC3O4x7yj73RmroELKFvT-_CSO5LVz3qRRVdlyL0CQr3lkHUXJbFNpOz7Uek4q6MjB8Cn0xAKzt9ztcClLdAA9NkR88Dy3rOP5yPjRJJVVG6SbelsE1SnPDaKQqu2ZN1zdtGUY9AcULc2dGFb4mezcbJsC_eL3DD0LwfwcSAILDfDIrqHACR0XmI7jmF_p_PzmBhMsocLnblzKTho5ufo4htqhTEjVdFywm9WIjw1N_9PWge3i3J8mSdILp0HQ1QvbRlMt13qPyLNwAmY75m4Zw7EIlk4cyxMjcTSY02TRCC3cBKX2e6xl0DIAygChReVOxL16BT21sEgT2ps24Mljsvht-fokU3JPtj3fY8wojksHAWNv2hlF62xKrOv9h9AqM_Q9JlghHHNTrzxvT8SVeLBhEvysbhErrgtTPcgvKfMUCT1JMWolxLZUSFEFKNR9cl2GiSqMIhdTL3JvA0-etZ7ykeIbUEU0jlRZAw4a3vY1R1zW1-c6XRSNiS9VDPAfcN2OD4bXL8Hi2Un7Vc_pRyWn32kWQqQuw7v6J4RB-sr3Bkb4OzUljytF3ixqGkMIpuA-LjJwdBJ-XgR8Fj_DONbguNct7MTkMtQqWU9twa8XF_sot8iEYc1UOkZQVJvTtNclIkklJhP8VNj1aY18Y1Gtnn0fvfaOFfY4wa7HIq0U7paT2Fqb0xtY62bqNM6rRXLsAQex5HvMvHQvL_9JbQngBOD2ehk7zIAJKZWzbAKqKCgH-_v4kaGBVrciIxffYF6WnWq35pQwbsvNqQG4uJR0qhLEXfc5akEon1sL2fjxim_GFcgunyCqL28lMB8yhnzA48QESW0sotVss_GIeeftSYS74zPaHXiuSx0RoAmw90kERXPDGVCRkwTTwaW2BkshCJCx2JOSDEWVRMjxngzaoroybl9A1VzTrDEbodeq2O_kVyZfrZE58BO8DDd6ZH07m4zuiL_NKXLw23NmC4CuAN0ufn7HFtX_ow4ZJILfZI9PczBi16liV0LWrBwvadZ2Lf4o3sV65CLg1VKujttEiOhtpYjmB9zIRLfAHViz5vgTonL6H_9N4D2dXLzUWlaDPNGJNnt7EbHS64f3jSXGG1fb7LGKhNtTHqbfBJnMpmPjFQGb4ae2kKv_V_L8xgXNpQRi5I_QNTzDzfBs4avowydppTpEE1b8WNITLc7qvMa6gwpDxp2N91fIVC9wyd0k2DXaz3VbDn-2v7W72D2UPa0L00NKvIKYecd9FMpYmkEyxJfFFr7b9hKA1ZXdqlejjPJPjVYC9XTEZLEwzdeoG6yrxtYMrl7o72M37uIRNZAj1Jf0B8s0qhPaaBfUVKtKl7bd2Ub2503LZ7ZvJ_1segaIT4S8nt17hjfep3re_4rEKA2rrxMbWoLhM4qkAPZvdjyAFF1YNB7u-Uex7l4STRYSpzl4eQIMSl7N0pGlKk58Z1FxTKHsAZTkZYtj40lptma1AfcwRPViNPceCFA36XfVjaratWPYgDhcjK8nNnAhxvL7t25nPbCXazPK1D16ZkY2SwcX7sMx8QklNQdzukZwGyP51yhU8o0PT-u3xGDaXnP6Wh_o35cCIRnar6Id9h2ovViZXJRUzNa8aXedxiFp7hLScSQfIPrPBcqN45EvLjEmtLvzzxNgHY7zw6gzj5QFgv64u2fI9zAY00B9U37bHIZPQnFAhge0466vyXNENzYO3acUGo5HhyFDlcuiBCbIZ413bmfbtRbj5W1FZMY58l1plTmNljfcwQ7Kd0PUGvGEb_jwKlmyKni1HzyyUmElGHdRkyS5Yk7aja6AJOk6z12WUM5snqG-uRVkByxCXQ2KaFR6Qm-IOHMFqzrPINkjyEJgG6KyKfkF5ScVfQaThHBuMrb7ETWMnlk0L28ZszB-TLt3HfaxINsoD5pndSSqBpHB1z_2kEweik3y_PdxIchV3CyBLnmrlqBPBIarCoM8VwzForh3RzQmgNsOGkJXy3Lk0rIr3t-BE7qgXWsrDolobtH6MMFO96Taa6MYIYYYbYvzQYcDuQwD21yGTLwKAnynBDn99bGYEg65LomsJbTSKCYQRcj2Rh2AaScsq8JiHYJEGAnRkgsXNivZnioTlkI9_5XqXBJt3GKMY37YL6qIU3XJ7HapKELorbX4fH_JlOIZLIOIaU80295GZcFdx1I2La9lp_UvAtALEDJklGNvbcDG51NNn2mj_P85vIfzsVdrfX7N_AftR8t1kQx7bdbVLyP4ls_qKnXXigfNJajWtPVgwGeroQq2jtaQw6Tj2Wsi3Itmo5QNg3N_ja3erlEHEdTo8lm4XZHjbl2bAH3n_wuEdYKTt2B3jhj4ddhO8atc1fryqbRfn61YFKUnR3f5vQ1qUq79uisQi0cvHr6DQ_12FpKzFvFckAkQmbk5fcS5Ri5S4L_JtFAexj8n2f_oYuG_9CYYplOU5i1Q84MyXUZ2fZyDhRPRiyjvPJ07_IAiL2ny1btmIFtVPeQSHVwfun-m5Lba3KgnZIJ6CRFqxR-o6F8e5K78d-bAotgA5vOcfeC_fBQfaom-EX0mJyzf7_Wjgam4IA_W3PO_wGoVULHfr7mwUw2Qc-VzITtjajZvRoT-SkVREyJVnKBxHFj2cNTcTtooSxCu115KmbtePf2OwgJocB2jyPT2GK-kIVZtuGdv4Dns8m7Z7FpT7PvjCVjidQqVsJxFQUs7ZzcTXX4vdChdcVK1_OiUwCJKiYN9ZKGA_OmwQJjhnV6gutHFYanu3Gm0m5PQLIM6Pip7yXCw8-Lhq0sxFTl2f-7DeYlfrWpYJyc2wR3T2u-kHl1g52CxX5XoHCV1LsBIU75L23Igsx5_v9ZNeewK2Qh8yWwlWZ18qnXOh5ZJqJUpYtxy3sUhHMG8fe5RKVGbbJyHltosuW26yJ9eUQXqJOSj4wv0YN6a-BezPdkkCqdiUGDHllrgAi96kkeM4jES6iZV60rTgdmfOS03JL0eqCwLnH0gP9t5Xq7l0-GUKp7mrsUjgN4Utb89AVPyIDFWxfJTuFJK-g6Z1EHexEvDY4iTsuOdq9M49_zV6iL8ChB4p5l0lUOiFzIH1Qj-gNMqpU2p0H73cMd3MNeecFhMsCfRadVCO8D4UN39W2mEXDxLBlTN2f4m6aDKjLHi58zyDiJ4aga_ntZRnv56KJpWob0A-4U6_GRJI3OynwKPfb0wpAzK8Gm6Ak1OpxvD-8TmbKUKVA5m55PMoBgGbmvtrwC9Q9Exg-zdotpZ5-iWM1ssnKLXobFa2SmYJeOcGbEjh_yvRvjBRNHxWmq_sP1ohPCTce4Pt97WVQs0Kc_Peb85RqZEnCyjRfV4C3nFUkTxJhFJbmIBPG-VPJDfKEMVTtUe7xB_w55BKViE87CTrd9AAveBFKkBrL3x4bVba3SK5HLU3tOgUPMDnN6Q-waVbjTXsNPGPwJjvbDAN-xwm1V19e-gYcI9sExy4hH9fCkx7Y93e3EMo_EvPA8ZFO8C-KKKlKttqg66BlOp_WYj4GnTpurNDHjVtBQZI6FN5HGl72n7ZL0me0cbfiDkFh7mIfHJCc3EcRCp__gjeBYQaGaR3hh7hLrNeuJB_oAfW5mz-2mIgUYz7vGxRrTeo9CyNYjr5CNwd-hp06pklYw1Bmce-1ZqG87pwFGjfWaAABwqNElf9Wdhgzll31WmopAxDC12Q8pzpAiFfkWWeHsPgvx_Hfm6B50TiIn_LCi8hjTaVUkvtNxZgiKJdAdL5btiUvPwVD10EkysT4dfAEg6l9Z64sZT6oss0KlH55VrNoLOybfx9-TGJZOCB5Zf7JU0KuA1Dpfp8I8TlCOUBwybFvNbECafzsrKB8XI6cmvDtsG0NqNzifoYUPzZDv4eNQhb4QAxlWx_xjiD_G33rgZ27DfvecgVkhDUc317uWUTrWt0f4WJItv4A8P4fj2CDa4cAjfe9CCWM8oehppoxScG5nBFdeebs1m3efdBi0VlYbJTEFQC92q0Zdr7kdfo0FbR1GQ05x66u5b0qLRqqsgF6n72p8Vo_izkLs1N3HKOz9AvcoTmD_tD70rZC6SVJ0jQcKtOMre7VK7lJQJwkuuUL-TRcVYVFeKln1CDs0zpqwza1iCVw3LcUdh96iPsN3XcHrH9pqUxSEY_T6Bq8aSTHdf-iqucTB2u2zsq5BgU40_zXUqvfvQRhcHbaNl0NkdbWKVr8AA3KkoGHMe-H_FBRmyBFX2KL7F4naGngOz7crLfNoSqvPF6cBudn3Q_PPxutj_F5d3FxcfHSHizhfZ3sC39DiwyKgWMU4rUm4gsyYpnKQ90aXtF9nuLWDyNZEb1hsHiVyIoNkUx4IznUY94rrMNzlobnMyqtaic819_vgKqTo9jYA-i5JgMoTPy2DTtIZIpU_p-TggdpEActJ7qncHdQjM0mCrZGYo78NvZ0697fexOgo-dQjfUmNNKNtLp1UQiMBllHwIDZzRePAgOeisXx-E10lLdPUm6AKQcg6IYbvrPDil1_EaQyV3JXqEgNCZwXvkDIh2cnaBLUzyWsep_iupiypilShz_QWLsa467qw5dJ_Q0vR1ulAzMWokaCmTTiJQ6RL71J4WBiGAnobFDrluwJtRr4BTRNDmzDBh8_G3EKTS5mr6W1EQnFnMAqIrW_TOvKasBlQqlLVcFDlllp7X2akyW6Z23NBe7JCnYi4m1HkM0_gnHqnFbnT3cS4umAd22ugbPbo8gn0KRoFxAZK4_4JPHbz_T2itrnDcl4z6_50F-I0Ynp9nHSKnlG5x5V6IGd47vfF7sIks8Vfpq8LUKgQu2g9XHzwf-q_jmwH-eokmnUlznsJnZWnz_GnHyeEMsdQbBKDGK9rjNuMC_QZGuiaARSlSvP7hMyowcczvtuKrN7sZc5nTWPD31UV-TBzrDnzmmsKZ_3BdPebNj71vt31hatE4Mc6OJJUZ-HPPUieICZJFiYXltJBqApmSrscPjDUy9fUoD0iJudrtDu6UJ31SFMkaapXqHG2FqMOwkEk_T5wGmdZ3Y6I8QKKiI4bXRcjPexjVQUJdHnGLRZ4L7tyKU1mFJHMEIMwAer1LiYsnFLHBt3XoAQbNu7LewtB3Cd1Qzeo16USsORAgO8DYtAiu9T0yfTOMAn6lfMgEIdqdJdY5KiPC2TWro08m4pn3mhDlfIWB4XzyBsaO8JiRlF_7Dfg0UpDEnk2AN7ACqsjeUoMk5478ov9JeTPOnCDw2W3x4-w3VhTndvrAD3OrnDoxsc7OcoQjni96fsh-E72g_FKaHJVqH591bROjD5nAPTj5rseGJYDTJkAlHauG67pXgIpMLSLgTUUeplBgjDDTWPdww6dYp8yW9CJNOXCrqmAunZDJe5d0n2BmzGLiOHxiDLKT4-7XoycRXq9adUn2uWgHUooKJbs4BI9sF_28FhxsbN5E2KT4b51aZsK91802OXcSbLCF1K-HqxFNeELpvrlnYT4Cefr_gQydbzRvzSdpTSpUTLtCspJ8RZzJZzQT6x6DnOT8KVt95Sx2OsaE6zCOEBUf5EX85M3Xw630kFQPAjAXx85FxEos_Fl5NtgSssugztP0Q6dbXJTuQrsSgSb6TWsJWaC6agqNudU2lkI3lWpxcxjnYdlDisZE2CVtPXIbMc0fP81Oz9g-LybenNrYDUdIL_FvJ9FM2ZSAleLrEgMM6IyDUXBC8PXA7QP-DukpVBDGkt6GRaNqiqMFN6ceHu1IcTRy8RBucg2ahZqS9BgLlbj2xGANaeZKjzvNKBbtqawx-RkwsHludZ4I6WaLC6-fCnqE0GuK3kw8mbym6gAbfHouwbWarAdtesd3tjoa620dCNg9QwQ1Hzgs4Fd0pjsSgMFB7ahRSDy78GWbdPXZqPollN22uUgQ1zWEva_VxrPK2C05iQMPE4Cg5X8XQbxGH6GY7wuOnc23Pvh9qe6po8voXKaUAPVb3oUGgYx7lgsWZIW-2c861ip10CSjcfFm6AVrS5Iaf7m0OZvUvL52q2r5Py_LWxLbgf0ubrDXMtHbhEGXYmiRaHcmuOxoFUtaqCB6kr6970im-84hk-SiCoL_96yg6Bna4isurYJb2JQgGktUX_SjcB4TshvDDx-G4H-lUYId4AaqP1zNJ0ryUPOlQQXlKtc6s0tUfEZu5SagAE6h6iTUkCr4hJ9hLanj_mMSMJiCjBCFUYMeZ4LCxzQagyR5qWxq90n2HlHhmPy5eCj16DTBIL49ScuUqyN5x8fWt23H-B0VjTUdFEVk8FFaPsSFv0SddM9LEvrlUcA-RcMpyZ1a2ifF7N_HwvRlMslVSzW2BUZRibnB0xpeZlUbqy2CDkr10azuxJYajE6giMCnSHfiKM2EPMuFl5-sX6FiyfsTIA3CmcdoHvd83KNQbMuDRp_nDCAl6LNcj8CXPyenI56CAX5owOddnszaI3C7fEfW7MavfzLE4KlNBPYeFmQLL7w0Rw6uZfqjBKLFLNtXNDBnJW3GSWYKFB0QiAMjf_9_nfOU0w3cwgnfsdmUU0BG_9bXy-qvzYvnWs1eLfoCfruH7gt5Bvb4iGPr37EFMI8yv-df__xbRHgDxVtAd-A5kL8N8DR4U6eSsw5UH8--p3ZpLyrh9vklTf4LDr0xt62qvZjUKzcuMZjQpcBvDHmKRx55aZ8BEkKhIhsWlZJMsE5prZOz3pwT5_pAp1h9u7sw60NnWisoTdBM08hP-JD06OWB_OFPa3I0x1boTojwlzVpiVGUdNeMgpWKa9wQj6rVsEl3-UFIyrKNpgir2df5m5q9vxZ3TSKawBZUAQJnQp9aYgysMtCnUCNrZ-zaC6mojA6cBLk-g5rCcXsyd1WqkHrFwYoPAu5593tQA-ttSVSFCUQxCILqKUZx1-fw2NIchE-NUak3dAZ4RTWm6EwMGXh6rmanI2swBjkglVxw3CfmOAsL7yXEhm2tOofu5EoADa_lEdy8ihHgsCPoJiq4hxlwFXrg9y-Pww0xsrldPuFcc6AAIpPR9UrKHoEdxoDnANqi6zsBTsp-VdyaNj5nFWgpm5mxgnuWUrBGif-U5ldingoapB0hJ50--CucJyHaLHHV2m7WcVDTXiykeHhjIp8qnKBaXwoyezqmLgzIOmhrJgqBH-drr_Usl2Mtzq5lyA2if9MFtKcktldky2GXDiMlwLWSf70Jj5d2Tq8_4P0C-StEZ66V_PkVarTSrFahni4g1OqUJbxxsK7oV932wEtpHJPo6MYnkebOFGlGQlxxk6OlqoZwyP6xbJCwu1_36FuIYcl09Vy11EXK58g62eDyg9eGaAAe1mU4fTByEowy94v67qTC9otmjGlB6K3pyqsGnpWEGz5FujtRPO_ChDNN84qZRMSk5QMU3jx1t3-_0Mg48WnuWGiDDveAhZVxNz9HThbvMviECVk2E70W0nj9XEybPhNLcKQxKMekE6_3qJxUTk8Q7KJpoDysmWznz0Brg-GT6NSJG0pFFfgdNCAK_K5G9SkdnS7Pr2S7DcDIasmdvIciCzw0Lv7Z2rZR8eiica4lrrz52lwO-rD2380r-UgaLsbX5PhZDc57JSkIKnAfS5qeqxK9koKyD4UyR-6gfA2SsoRbxayLigQOk4O6bIDoJ0ECvEoyaJTohselYUhhQDuwaYQ3UVBsxyNzFxXv4i_ldHItOjckkNBLTyz0rfh0bAbqP5ROsXG7Q9OIMglRSRyDjZdlMaRVO1-lXy_zQ8AoBxuAwGOyc2CQm4zvxMjmiAyMymBdZS5w3-aa6ILoaqvhMzYTEyP8pojxTER7-swPs4J_zroRVV-USiheF9qLRr8C7WtZnzaJXYhAap3HrTtfCVMAy8bHYFjk5zYLmVYw09C04sFxQ3apXWUc6A-30D_Ix_x-Nh0LmnhBXc-BiCPdaGA-iqaCScX94nyMmCC5-26KpbcKZL9qH6ZFUez72d2gmu0oX59AgiJkLaVqmWkC2fKMc-GxO7SI-tzO8AGmi2G5vVeYHIwc2zfRhHuNn8znS7SSRKD1uzTLvJzt0Bonu6NLukVUamhLf5SYmHR3Rd9Qb6NNprHYCyJkim-szlYjso9-EhfRqt3TZtuNx7zbXIoJJ_anSIBQKXrWpLJHr4CMexa0xlnVrB_K6-RPVBfKMZWdcRc2cltFzo-w1VvqOzmK_-B_9FkVhCdObJ-aak26s2CjdzF4SmyetdbUt1U6zDx3lb2InlGz544dNY6OjjQX0X0ImPVTlFAFWFO4ONwnUp5GQmqBjYQZ7CYKqx7RZexDqbmGsW33jnf17hPsToLphEo8M6_p9-I4-PSity9OSX3Gw35Lon-myQxV9Nq_Ui9Mtql08C_Uyhdqwk2FH8wESENlRPoM8Dq044Yj0gHqwUj4xqUht8j9Hk-au6fYM_fLPRyXv9jqjT_KklnmfaeAqZOb4hHRIFBxXA9Q-1rreVfYFWVMz-FRiyf3cWd7QQdMciuMBulWeJjgOUoZK3vQIS5f4AZzwYkNOt6F96hwRtdI8bU6tKJU2afAeqNQ6xiSa85tx8_YGzMsrdKdWAPQIKe66QmQLlQP04k_EoSLH_f9dc51NZYfGF8YwzJuvclpqtAeMNguhPuGj-7V5wFMYhni7osiiPQ==', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de', + signature='gAAAAABoxCzZ6TwL-z6tYv85YPC9CwMFJRrSrWgYUyOhSFYLkdfGwRUIbrgBnmAW0qtzE-shPNPNfbUltLnBS4uU8kMuSMPxotFngVcFFnZ8qmzDUJiEf2CsnqYqH5d2RmuvIXUQTau20SjGte8vOLksGsz0sXRUQnFs7ZoT_2DSy7tKVCCN7fbvkxm2l9D-IibdvGiflbP6lGGgYWczEl3_QyEyJGhDTcL_nUk511C2hjvqI6YkEjujvYjEGMh-BdhFrJeLFL2wCbn6beWaDB2IXYVo7LqhlQUtKksY2PQ4ybBgPhERNvWWf2N-K4NxEQuv6vdB_5ni_BlUKFMabeeeI4wVr5M3HKE6cSgnM8cpi93o_rGu9uSh5fbN5zZcIYumnjkGJ-ULwku7TVtpw_Vha8bJl67qCLvRe90MaCCgJxFKp-IsxakpnNCXVrAlN70cIchPEjOWW3VKrGZ-omyQLgs3EzddhaPmSqDELbmYkxCUuRYdLvZPzhI5VvNiW_j-WGBKEMJLFz0k33oPbH3Q6Fn9HcJSruSsQ8Lc-QWQsibGoABEY_auM7LDLjbvpEYcdsP5BJOBUS8wpyOD7N5jEQL2PYPT3tsP6mvWy7csRIkwEbh1x1sXp6NL3skS6QwpqNiWalP4OQvs8jDi8Gz-NrtNvmX3RR4A0MIuX4q0Tb1VI9PilRUvOvg9hF-fk3bqIh7wW7_iD2eDoXjvI99M-UZ2QZGZlPa1O039QVGLBTi-KwrLuhh-D5q3N-3-DyXY0sjsdFzM5Qf__lVaxtRhZRKyxSONZsTt8mGatlOH4Q-MIPgCXsrLu25gWn6Jr6vt_iQ1eZG30cox98F4aU11Hp-o4tFKuHL8Kbgl9Eetpd4ggfJrTe9QxQfWfgCHAKnhjVRJOepHPEFzSRFKiHrOgATIw_x5xNRacsF_tO1WkpeBdBJhpAUozarHgPQi2A71LCcmd5Zzy7FAL6R_5QtHW-H7NE2PjqqXnf2ZMiMM-oYLHKhfu8tZu9EV7V21xKkovIGH-0OQ-lk44ww8-j3rBNXjWIwp8SO73O85PP7vzE_zJJCF8riB_rOpazJpMCaDP_HUOZq5XhcfHseiS1SownunaXj2wOmgLJ103BowC18-i83n8RVTtRQxLsiCRzMwRH3eEbEClqZ1Fqt4V6NKqICKK3kF3_R_oPtX_-7xYBpl8LGR2Ei_2hXkEIuQ8cCRz1zmuyfjLEWIbm6Rm9wgYafXIXugOqGl4lUc2NSeeJ5T_-ziLEX9-Z6LZafWo9PMvxbxpm86-e5ZqTBlsbukWWIePrKZ6BjElMcxTOUr2XYg-vMAc7QRx11Ld11DwesN_Xj62Kc0TUQRfREPp2AF0gAlYYKLvl7XKwU12Rg6UlWBfJWjX-hUvPY83B7H1saGyAv6V4RR9PODI0p8duptI4mC6u3cYPUk8pOVwFvX1PYCTM3I2yik_XG5ZyI6BIGBNAGL5SoAyMfpqYu0Da4duOIve6tQ3FWkMYnU9sSjxvS00mRJ3JscA-pNm2B_dUXBRATIAD6XVg1m19-pV6OLG58tuDtbjE7nBHUHuS2sm2gbm4PFjpGKFMS07LUSfYax19Ombld0hV_0kwaIjl-4UTcRcqqLK-Tc2E3NPwmdJuzb95-lUoAJG9Jp8UCoyXQRcZk33IGXMYtNquee5K-Oc-ajKjbbevpi6rIEOVjwKrZYwTC5ddl8FBcCBTm0NunKUzo9TkDeEIF6kce9zYdKo9GwYc8Go2S9lxbb6tlizDql2Uv_ZiTz0d5RUvShsMH6RzKiXu8eFzv5sUraMbLUtm3VtZsz9Ld0iztNIqV7q6glrqD2UuLgWxKsa7EbDRvrlBnAOP1iMRtg6ICr2YHYtlwU6R5RzKllG4LGMccZ3x6HsZL6MMaMJc8rLMTtQYqE067kCnXAIBz_-FJS0CzwCwnbh70tc-ytaiTm404Jp3CIBTlGwDwTvXUqzzNAdFRHrilKUPNgtKb6uQAyPhJZwbFIfrFevaMdOGZ9UhJoKtQtsSj1qM-dhXIkn4T_SL0o72wgb08zYSjsemhfJdbNO6jPG_GfWV6FDAhY9vNyTT8XlqgsePnALnV60AIvRZPI7mfh8D7F8SI0yZU4AJVtEHKKgStPvCuixxtjTt9nSWm-cXOItJdKYxMjVtWCmcCI9LbPolXXkewgNhmUx-b0XlY_BN9cX2j0COic5Ml6LS0BZ6ikG65a-7kIl_yofLeat8q9-4OI-lhKYOxwMhQq8yWNCBuJZCGg5n3DM_QgEQt7cqWYuTuTMTgMnRIvSefK_Q-ZSY-ZfzPcNp13-v56KgA_yUqYOHvQDu4ZuZCI3KvlO1WSO17SiqiNZvo3iaM2BrrgzOAJYcSx4TUzl7ZuFE_6LkokGlxguZH82W9dpewDyN83yLLwakOhgLfbTlMCFs8NCLzMr17eBFNX8YqP9bh88f98KtLSYr09naEesCwW3v-M-I1MUdR7oEC64ixrAWEwpSI-Jcc60oUgvLBVbwkeoQWI29NqZCS2JYGsxjXfNmhWWB3kW7_7ik5RHk3oNRWXiEQ_N_K7c97Ui1YkomyAAZv4t3zQYHwsLBmnf2DCEMBViQn2nXXjGwBxEf9KY2dlT1ihIbcPBmyzI17UrKYXvYKkfE25c_R0VjQtRSiXrlEWkBgLwRzWt18_62P00dJRAeJOEq6etGKoSh0PsrmtCGfnOf1EJhksjZPyObdHWm_yrNiX-h3myewuYT4BIanBFdUQxQvpNyvoQJIMtKH3gAh9oCJY8os-vS1Mx7h4Zh0gEdQZhIVn7KoJwqbx09F8hGokOaVXx6H9gMD5kVZkXkX56AFC78ykpMLSsolvyUhAI_qxcpTVGSgDIzfK7BzQsMd4TawOtHObxfvVr9qojhx__eQEipXplbfOVh8vjM8TFY7eb8k5EvxaU_pBuEmSagGoV0fiPUmMTzipVTMQ-cpaF6xQSVYZK3CvmUwxHfcX2r8lPPH_SyeiVFKRdqTmpIGYw8drhwc9GFgFM_N1O_iJuhjSt-8iLt9BExKYJZftIcXPYl4eGgC1yC6oUBurdmvQUOZD2tv_isd28fMNeoiWAy7HCDz57TAkJg9nJsfULk_z5ClBqz7rPP9Qq9CZrYEsz6Lggj19AXh6PmA9Skl9nUSgsqn2GvDI3I5E8YmxhlP58XrZyYKLkYLqqAMDy4tqI2eiQMe4z1OhMGpVxoEt7ACxw8-YaQTKgItzSNNskrXkRsGvWa2m9XcaZNwbZFeqek7OZ0vxLMsQJ3InnvY1lj9aMUUGukolxZEZ0KolEPOsIKhwH4iMg79yNlxeqdM2e-OoxrUyIBvBqC5uNemtqnulwarV_0K4XYtimpR2ONcwjzSO-eY9untVEmJRdw-OYEJiKJoRRNEjmr77UuJLDhPqjtxmcF2LHRTbpQ8b73Vp-mt-1okyP2yOr8Rd6LbsJuntv77VWE6Mt2JBzJpwJZab3mKd-2c6VkTswJX8p8Lf3g6m3uPwBRrvyCuuxztoxG2rDrh-3krcjDFnwU5tZjpZ3G3pq6KXbcmsX3kvJhJc6er38kO6uR9SkJUcRkbQPZ5nUKCtRZ3AkFukiT_YHtUamsUlA0nX5DI0CcrrNtu71HD7jSkwF9-P_QNX3_c9k31cSfHQ8BCMHcy7DO0vPYuzj2BiStEdTymAXfMeTFVO3wUvQf9KyuqVnKFMtFwP2DaospAJCd4TaHeDCm-uczeg1of-R2SB0f5XorCQ5MljHFk1VTHmWG3LHgCTEmAtx2KKbdMO8zXsBop6LAnFj3dNEBv1grO5lMCZRqKRo-csAJKwqXn9kuIa6GXi-NMZWBGLvxWhJpWdCeGnaFjCk-7uzPQ7PN_JhtPjeI3W-9A5bY8RvzYLrKKIEOEMGyHb-77dcYPhhLgn10-HpglS0_uJw5f0STZE60rxVXH-sb7vrpyAyBqMUh-OdoGAqR4r9dflKk-jECG0sggRuzx8jLGGfO-dNZSznD8JbaCsRDdLuHWiFSZKJswXwX5PS9rmVpYRrH-0QniMhPiMOuINwp9GvTtzSvXNIPBWtNMsY_jN_O2gIKxL-KnyoQkyUFWHN0Anuyv5pCHQk1lhfcR0alSvDLVmVVgi1tQdjsdAl19qMdfm43ViBTRLDwzP8iauhipIfCpxFjak0Ka8uFaHfEhKstcmUdxEnzIsN3SQXrPud-p0YJ3O1MsyUDjzMROP43FKMhVCSnM5PsXVvuPZKRmuEFbJyj0dwwBnSH-rk8tuK5SYoX8PIrJXyAySgj2VouGdzvkqa9WPSHU42AxDZNQT2c5pEI3gUS7VzcGCTwoznmFtmHKGOJj8HxKswzB2z0AumI_ht8zx6kehnvKK4cJfKjdJfO--2o_gzVR0DkA1HcenMD4ugxj6rWQDiJvo6cFdfkXpMfLAe4NQRLVLNv4UdIehCxCHMsF1RZJf93Z6sdxW_2PumLLcfdb2XIkouuFN0mECzZlWgM4XLUErlaaqDc8oU_gRrgHEJbjZqF7by2nHtqCjyWOZC9n7vF18iSRJES5DX71nY84a8ydPR2_KEYfHHgqF51Nz9zMo2Gv6ramAFs6lZC5rjOUR1VmpLd2pKs-sPQJpYNncwbDe8dG_NDJI1wIgs2K42eKPE4lEueCtp359ifPU58DpJA0JiB_FW3jBBh_9MphsnQjuso9S-YSaSFt4Llc_Zf0MJ3CbiEsk-IwfgsLysFQg-vJq9hHR48ZoW0kx7CaIAUgkiJg7-7m_dVNsfaUM-OSHtfryYXWrUsotLJ6OTuicPOfb_LfaYz5OoasG0o-4vdtF8e4VX6ZpR_Krje-dZaCph1XjgGLfFlRRkywl7i8IEUirHpQJaoCPmc9q61hjETcuPCEVDy-dJMwPLiNzXY1mkJI1lQQ1LL8Ke5EgtAcC-2K_5Nwh4h4bafWA44XgnisMfYDv66CzsL35i0XtZHibfLqPwdLyHqInlLPtiFyhJZifcJ_GsiQ0U4SZO3WHmvSG9AHy0YnA2jC3O4x7yj73RmroELKFvT-_CSO5LVz3qRRVdlyL0CQr3lkHUXJbFNpOz7Uek4q6MjB8Cn0xAKzt9ztcClLdAA9NkR88Dy3rOP5yPjRJJVVG6SbelsE1SnPDaKQqu2ZN1zdtGUY9AcULc2dGFb4mezcbJsC_eL3DD0LwfwcSAILDfDIrqHACR0XmI7jmF_p_PzmBhMsocLnblzKTho5ufo4htqhTEjVdFywm9WIjw1N_9PWge3i3J8mSdILp0HQ1QvbRlMt13qPyLNwAmY75m4Zw7EIlk4cyxMjcTSY02TRCC3cBKX2e6xl0DIAygChReVOxL16BT21sEgT2ps24Mljsvht-fokU3JPtj3fY8wojksHAWNv2hlF62xKrOv9h9AqM_Q9JlghHHNTrzxvT8SVeLBhEvysbhErrgtTPcgvKfMUCT1JMWolxLZUSFEFKNR9cl2GiSqMIhdTL3JvA0-etZ7ykeIbUEU0jlRZAw4a3vY1R1zW1-c6XRSNiS9VDPAfcN2OD4bXL8Hi2Un7Vc_pRyWn32kWQqQuw7v6J4RB-sr3Bkb4OzUljytF3ixqGkMIpuA-LjJwdBJ-XgR8Fj_DONbguNct7MTkMtQqWU9twa8XF_sot8iEYc1UOkZQVJvTtNclIkklJhP8VNj1aY18Y1Gtnn0fvfaOFfY4wa7HIq0U7paT2Fqb0xtY62bqNM6rRXLsAQex5HvMvHQvL_9JbQngBOD2ehk7zIAJKZWzbAKqKCgH-_v4kaGBVrciIxffYF6WnWq35pQwbsvNqQG4uJR0qhLEXfc5akEon1sL2fjxim_GFcgunyCqL28lMB8yhnzA48QESW0sotVss_GIeeftSYS74zPaHXiuSx0RoAmw90kERXPDGVCRkwTTwaW2BkshCJCx2JOSDEWVRMjxngzaoroybl9A1VzTrDEbodeq2O_kVyZfrZE58BO8DDd6ZH07m4zuiL_NKXLw23NmC4CuAN0ufn7HFtX_ow4ZJILfZI9PczBi16liV0LWrBwvadZ2Lf4o3sV65CLg1VKujttEiOhtpYjmB9zIRLfAHViz5vgTonL6H_9N4D2dXLzUWlaDPNGJNnt7EbHS64f3jSXGG1fb7LGKhNtTHqbfBJnMpmPjFQGb4ae2kKv_V_L8xgXNpQRi5I_QNTzDzfBs4avowydppTpEE1b8WNITLc7qvMa6gwpDxp2N91fIVC9wyd0k2DXaz3VbDn-2v7W72D2UPa0L00NKvIKYecd9FMpYmkEyxJfFFr7b9hKA1ZXdqlejjPJPjVYC9XTEZLEwzdeoG6yrxtYMrl7o72M37uIRNZAj1Jf0B8s0qhPaaBfUVKtKl7bd2Ub2503LZ7ZvJ_1segaIT4S8nt17hjfep3re_4rEKA2rrxMbWoLhM4qkAPZvdjyAFF1YNB7u-Uex7l4STRYSpzl4eQIMSl7N0pGlKk58Z1FxTKHsAZTkZYtj40lptma1AfcwRPViNPceCFA36XfVjaratWPYgDhcjK8nNnAhxvL7t25nPbCXazPK1D16ZkY2SwcX7sMx8QklNQdzukZwGyP51yhU8o0PT-u3xGDaXnP6Wh_o35cCIRnar6Id9h2ovViZXJRUzNa8aXedxiFp7hLScSQfIPrPBcqN45EvLjEmtLvzzxNgHY7zw6gzj5QFgv64u2fI9zAY00B9U37bHIZPQnFAhge0466vyXNENzYO3acUGo5HhyFDlcuiBCbIZ413bmfbtRbj5W1FZMY58l1plTmNljfcwQ7Kd0PUGvGEb_jwKlmyKni1HzyyUmElGHdRkyS5Yk7aja6AJOk6z12WUM5snqG-uRVkByxCXQ2KaFR6Qm-IOHMFqzrPINkjyEJgG6KyKfkF5ScVfQaThHBuMrb7ETWMnlk0L28ZszB-TLt3HfaxINsoD5pndSSqBpHB1z_2kEweik3y_PdxIchV3CyBLnmrlqBPBIarCoM8VwzForh3RzQmgNsOGkJXy3Lk0rIr3t-BE7qgXWsrDolobtH6MMFO96Taa6MYIYYYbYvzQYcDuQwD21yGTLwKAnynBDn99bGYEg65LomsJbTSKCYQRcj2Rh2AaScsq8JiHYJEGAnRkgsXNivZnioTlkI9_5XqXBJt3GKMY37YL6qIU3XJ7HapKELorbX4fH_JlOIZLIOIaU80295GZcFdx1I2La9lp_UvAtALEDJklGNvbcDG51NNn2mj_P85vIfzsVdrfX7N_AftR8t1kQx7bdbVLyP4ls_qKnXXigfNJajWtPVgwGeroQq2jtaQw6Tj2Wsi3Itmo5QNg3N_ja3erlEHEdTo8lm4XZHjbl2bAH3n_wuEdYKTt2B3jhj4ddhO8atc1fryqbRfn61YFKUnR3f5vQ1qUq79uisQi0cvHr6DQ_12FpKzFvFckAkQmbk5fcS5Ri5S4L_JtFAexj8n2f_oYuG_9CYYplOU5i1Q84MyXUZ2fZyDhRPRiyjvPJ07_IAiL2ny1btmIFtVPeQSHVwfun-m5Lba3KgnZIJ6CRFqxR-o6F8e5K78d-bAotgA5vOcfeC_fBQfaom-EX0mJyzf7_Wjgam4IA_W3PO_wGoVULHfr7mwUw2Qc-VzITtjajZvRoT-SkVREyJVnKBxHFj2cNTcTtooSxCu115KmbtePf2OwgJocB2jyPT2GK-kIVZtuGdv4Dns8m7Z7FpT7PvjCVjidQqVsJxFQUs7ZzcTXX4vdChdcVK1_OiUwCJKiYN9ZKGA_OmwQJjhnV6gutHFYanu3Gm0m5PQLIM6Pip7yXCw8-Lhq0sxFTl2f-7DeYlfrWpYJyc2wR3T2u-kHl1g52CxX5XoHCV1LsBIU75L23Igsx5_v9ZNeewK2Qh8yWwlWZ18qnXOh5ZJqJUpYtxy3sUhHMG8fe5RKVGbbJyHltosuW26yJ9eUQXqJOSj4wv0YN6a-BezPdkkCqdiUGDHllrgAi96kkeM4jES6iZV60rTgdmfOS03JL0eqCwLnH0gP9t5Xq7l0-GUKp7mrsUjgN4Utb89AVPyIDFWxfJTuFJK-g6Z1EHexEvDY4iTsuOdq9M49_zV6iL8ChB4p5l0lUOiFzIH1Qj-gNMqpU2p0H73cMd3MNeecFhMsCfRadVCO8D4UN39W2mEXDxLBlTN2f4m6aDKjLHi58zyDiJ4aga_ntZRnv56KJpWob0A-4U6_GRJI3OynwKPfb0wpAzK8Gm6Ak1OpxvD-8TmbKUKVA5m55PMoBgGbmvtrwC9Q9Exg-zdotpZ5-iWM1ssnKLXobFa2SmYJeOcGbEjh_yvRvjBRNHxWmq_sP1ohPCTce4Pt97WVQs0Kc_Peb85RqZEnCyjRfV4C3nFUkTxJhFJbmIBPG-VPJDfKEMVTtUe7xB_w55BKViE87CTrd9AAveBFKkBrL3x4bVba3SK5HLU3tOgUPMDnN6Q-waVbjTXsNPGPwJjvbDAN-xwm1V19e-gYcI9sExy4hH9fCkx7Y93e3EMo_EvPA8ZFO8C-KKKlKttqg66BlOp_WYj4GnTpurNDHjVtBQZI6FN5HGl72n7ZL0me0cbfiDkFh7mIfHJCc3EcRCp__gjeBYQaGaR3hh7hLrNeuJB_oAfW5mz-2mIgUYz7vGxRrTeo9CyNYjr5CNwd-hp06pklYw1Bmce-1ZqG87pwFGjfWaAABwqNElf9Wdhgzll31WmopAxDC12Q8pzpAiFfkWWeHsPgvx_Hfm6B50TiIn_LCi8hjTaVUkvtNxZgiKJdAdL5btiUvPwVD10EkysT4dfAEg6l9Z64sZT6oss0KlH55VrNoLOybfx9-TGJZOCB5Zf7JU0KuA1Dpfp8I8TlCOUBwybFvNbECafzsrKB8XI6cmvDtsG0NqNzifoYUPzZDv4eNQhb4QAxlWx_xjiD_G33rgZ27DfvecgVkhDUc317uWUTrWt0f4WJItv4A8P4fj2CDa4cAjfe9CCWM8oehppoxScG5nBFdeebs1m3efdBi0VlYbJTEFQC92q0Zdr7kdfo0FbR1GQ05x66u5b0qLRqqsgF6n72p8Vo_izkLs1N3HKOz9AvcoTmD_tD70rZC6SVJ0jQcKtOMre7VK7lJQJwkuuUL-TRcVYVFeKln1CDs0zpqwza1iCVw3LcUdh96iPsN3XcHrH9pqUxSEY_T6Bq8aSTHdf-iqucTB2u2zsq5BgU40_zXUqvfvQRhcHbaNl0NkdbWKVr8AA3KkoGHMe-H_FBRmyBFX2KL7F4naGngOz7crLfNoSqvPF6cBudn3Q_PPxutj_F5d3FxcfHSHizhfZ3sC39DiwyKgWMU4rUm4gsyYpnKQ90aXtF9nuLWDyNZEb1hsHiVyIoNkUx4IznUY94rrMNzlobnMyqtaic819_vgKqTo9jYA-i5JgMoTPy2DTtIZIpU_p-TggdpEActJ7qncHdQjM0mCrZGYo78NvZ0697fexOgo-dQjfUmNNKNtLp1UQiMBllHwIDZzRePAgOeisXx-E10lLdPUm6AKQcg6IYbvrPDil1_EaQyV3JXqEgNCZwXvkDIh2cnaBLUzyWsep_iupiypilShz_QWLsa467qw5dJ_Q0vR1ulAzMWokaCmTTiJQ6RL71J4WBiGAnobFDrluwJtRr4BTRNDmzDBh8_G3EKTS5mr6W1EQnFnMAqIrW_TOvKasBlQqlLVcFDlllp7X2akyW6Z23NBe7JCnYi4m1HkM0_gnHqnFbnT3cS4umAd22ugbPbo8gn0KRoFxAZK4_4JPHbz_T2itrnDcl4z6_50F-I0Ynp9nHSKnlG5x5V6IGd47vfF7sIks8Vfpq8LUKgQu2g9XHzwf-q_jmwH-eokmnUlznsJnZWnz_GnHyeEMsdQbBKDGK9rjNuMC_QZGuiaARSlSvP7hMyowcczvtuKrN7sZc5nTWPD31UV-TBzrDnzmmsKZ_3BdPebNj71vt31hatE4Mc6OJJUZ-HPPUieICZJFiYXltJBqApmSrscPjDUy9fUoD0iJudrtDu6UJ31SFMkaapXqHG2FqMOwkEk_T5wGmdZ3Y6I8QKKiI4bXRcjPexjVQUJdHnGLRZ4L7tyKU1mFJHMEIMwAer1LiYsnFLHBt3XoAQbNu7LewtB3Cd1Qzeo16USsORAgO8DYtAiu9T0yfTOMAn6lfMgEIdqdJdY5KiPC2TWro08m4pn3mhDlfIWB4XzyBsaO8JiRlF_7Dfg0UpDEnk2AN7ACqsjeUoMk5478ov9JeTPOnCDw2W3x4-w3VhTndvrAD3OrnDoxsc7OcoQjni96fsh-E72g_FKaHJVqH591bROjD5nAPTj5rseGJYDTJkAlHauG67pXgIpMLSLgTUUeplBgjDDTWPdww6dYp8yW9CJNOXCrqmAunZDJe5d0n2BmzGLiOHxiDLKT4-7XoycRXq9adUn2uWgHUooKJbs4BI9sF_28FhxsbN5E2KT4b51aZsK91802OXcSbLCF1K-HqxFNeELpvrlnYT4Cefr_gQydbzRvzSdpTSpUTLtCspJ8RZzJZzQT6x6DnOT8KVt95Sx2OsaE6zCOEBUf5EX85M3Xw630kFQPAjAXx85FxEos_Fl5NtgSssugztP0Q6dbXJTuQrsSgSb6TWsJWaC6agqNudU2lkI3lWpxcxjnYdlDisZE2CVtPXIbMc0fP81Oz9g-LybenNrYDUdIL_FvJ9FM2ZSAleLrEgMM6IyDUXBC8PXA7QP-DukpVBDGkt6GRaNqiqMFN6ceHu1IcTRy8RBucg2ahZqS9BgLlbj2xGANaeZKjzvNKBbtqawx-RkwsHludZ4I6WaLC6-fCnqE0GuK3kw8mbym6gAbfHouwbWarAdtesd3tjoa620dCNg9QwQ1Hzgs4Fd0pjsSgMFB7ahRSDy78GWbdPXZqPollN22uUgQ1zWEva_VxrPK2C05iQMPE4Cg5X8XQbxGH6GY7wuOnc23Pvh9qe6po8voXKaUAPVb3oUGgYx7lgsWZIW-2c861ip10CSjcfFm6AVrS5Iaf7m0OZvUvL52q2r5Py_LWxLbgf0ubrDXMtHbhEGXYmiRaHcmuOxoFUtaqCB6kr6970im-84hk-SiCoL_96yg6Bna4isurYJb2JQgGktUX_SjcB4TshvDDx-G4H-lUYId4AaqP1zNJ0ryUPOlQQXlKtc6s0tUfEZu5SagAE6h6iTUkCr4hJ9hLanj_mMSMJiCjBCFUYMeZ4LCxzQagyR5qWxq90n2HlHhmPy5eCj16DTBIL49ScuUqyN5x8fWt23H-B0VjTUdFEVk8FFaPsSFv0SddM9LEvrlUcA-RcMpyZ1a2ifF7N_HwvRlMslVSzW2BUZRibnB0xpeZlUbqy2CDkr10azuxJYajE6giMCnSHfiKM2EPMuFl5-sX6FiyfsTIA3CmcdoHvd83KNQbMuDRp_nDCAl6LNcj8CXPyenI56CAX5owOddnszaI3C7fEfW7MavfzLE4KlNBPYeFmQLL7w0Rw6uZfqjBKLFLNtXNDBnJW3GSWYKFB0QiAMjf_9_nfOU0w3cwgnfsdmUU0BG_9bXy-qvzYvnWs1eLfoCfruH7gt5Bvb4iGPr37EFMI8yv-df__xbRHgDxVtAd-A5kL8N8DR4U6eSsw5UH8--p3ZpLyrh9vklTf4LDr0xt62qvZjUKzcuMZjQpcBvDHmKRx55aZ8BEkKhIhsWlZJMsE5prZOz3pwT5_pAp1h9u7sw60NnWisoTdBM08hP-JD06OWB_OFPa3I0x1boTojwlzVpiVGUdNeMgpWKa9wQj6rVsEl3-UFIyrKNpgir2df5m5q9vxZ3TSKawBZUAQJnQp9aYgysMtCnUCNrZ-zaC6mojA6cBLk-g5rCcXsyd1WqkHrFwYoPAu5593tQA-ttSVSFCUQxCILqKUZx1-fw2NIchE-NUak3dAZ4RTWm6EwMGXh6rmanI2swBjkglVxw3CfmOAsL7yXEhm2tOofu5EoADa_lEdy8ihHgsCPoJiq4hxlwFXrg9y-Pww0xsrldPuFcc6AAIpPR9UrKHoEdxoDnANqi6zsBTsp-VdyaNj5nFWgpm5mxgnuWUrBGif-U5ldingoapB0hJ50--CucJyHaLHHV2m7WcVDTXiykeHhjIp8qnKBaXwoyezqmLgzIOmhrJgqBH-drr_Usl2Mtzq5lyA2if9MFtKcktldky2GXDiMlwLWSf70Jj5d2Tq8_4P0C-StEZ66V_PkVarTSrFahni4g1OqUJbxxsK7oV932wEtpHJPo6MYnkebOFGlGQlxxk6OlqoZwyP6xbJCwu1_36FuIYcl09Vy11EXK58g62eDyg9eGaAAe1mU4fTByEowy94v67qTC9otmjGlB6K3pyqsGnpWEGz5FujtRPO_ChDNN84qZRMSk5QMU3jx1t3-_0Mg48WnuWGiDDveAhZVxNz9HThbvMviECVk2E70W0nj9XEybPhNLcKQxKMekE6_3qJxUTk8Q7KJpoDysmWznz0Brg-GT6NSJG0pFFfgdNCAK_K5G9SkdnS7Pr2S7DcDIasmdvIciCzw0Lv7Z2rZR8eiica4lrrz52lwO-rD2380r-UgaLsbX5PhZDc57JSkIKnAfS5qeqxK9koKyD4UyR-6gfA2SsoRbxayLigQOk4O6bIDoJ0ECvEoyaJTohselYUhhQDuwaYQ3UVBsxyNzFxXv4i_ldHItOjckkNBLTyz0rfh0bAbqP5ROsXG7Q9OIMglRSRyDjZdlMaRVO1-lXy_zQ8AoBxuAwGOyc2CQm4zvxMjmiAyMymBdZS5w3-aa6ILoaqvhMzYTEyP8pojxTER7-swPs4J_zroRVV-USiheF9qLRr8C7WtZnzaJXYhAap3HrTtfCVMAy8bHYFjk5zYLmVYw09C04sFxQ3apXWUc6A-30D_Ix_x-Nh0LmnhBXc-BiCPdaGA-iqaCScX94nyMmCC5-26KpbcKZL9qH6ZFUez72d2gmu0oX59AgiJkLaVqmWkC2fKMc-GxO7SI-tzO8AGmi2G5vVeYHIwc2zfRhHuNn8znS7SSRKD1uzTLvJzt0Bonu6NLukVUamhLf5SYmHR3Rd9Qb6NNprHYCyJkim-szlYjso9-EhfRqt3TZtuNx7zbXIoJJ_anSIBQKXrWpLJHr4CMexa0xlnVrB_K6-RPVBfKMZWdcRc2cltFzo-w1VvqOzmK_-B_9FkVhCdObJ-aak26s2CjdzF4SmyetdbUt1U6zDx3lb2InlGz544dNY6OjjQX0X0ImPVTlFAFWFO4ONwnUp5GQmqBjYQZ7CYKqx7RZexDqbmGsW33jnf17hPsToLphEo8M6_p9-I4-PSity9OSX3Gw35Lon-myQxV9Nq_Ui9Mtql08C_Uyhdqwk2FH8wESENlRPoM8Dq044Yj0gHqwUj4xqUht8j9Hk-au6fYM_fLPRyXv9jqjT_KklnmfaeAqZOb4hHRIFBxXA9Q-1rreVfYFWVMz-FRiyf3cWd7QQdMciuMBulWeJjgOUoZK3vQIS5f4AZzwYkNOt6F96hwRtdI8bU6tKJU2afAeqNQ6xiSa85tx8_YGzMsrdKdWAPQIKe66QmQLlQP04k_EoSLH_f9dc51NZYfGF8YwzJuvclpqtAeMNguhPuGj-7V5wFMYhni7osiiPQ==', + provider_name='openai', + ), TextPart( content=IsStr(), id='msg_68c42cd36134819c800463490961f7df07460311b0c8d3de', @@ -2377,11 +2422,36 @@ async def test_openai_responses_thinking_part_from_other_model( signature=IsStr(), provider_name='openai', ), - ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), - ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), - ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), - ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), - ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), + ThinkingPart( + content=IsStr(), + id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc', + signature='gAAAAABoxC0Pe79v2UqAMj3Y1BkJi0m_G8llzMHMeav3XGlfPIsphSfHvJVzbyv5s7pvfPLs2-ECy9vhTMaN1UfI_PYmoJ17y_k_lLjvC6sK7SdFeCmdGNjbrgIcah2DJecVqDdoT8P0Aaz6COw982zu34UyGL59e5FTol9mAGvtInH9vXmmQUnGS5fGktT90wC6-MrIxBc3Og92F-e5ciGk0DAVMC90pDTyP4z_Qkj8Jv1QYKqCv4GwFO8LyUicPTbML6l39jyTfH8L86uDWMMxKNsvHEIrqgTQnsInlwnHYVbPURb93_gMtcjOpZwc2ESnjqUtMLXzs8XaKxhU2NVBAzcXL5x2kg7OI7HbS4Vl90Hx5cVwp3i8OTfpw8aRhDoxZJWptxNBKwDDEtjqLbylKQ7m2uJ8_TkK030O0fb81_W1-36qeRn-yNE5jjkKTezyHP0DlpKjCzoY3pZ0GtIj0FRDJOJJOmbHXjC8HfrwBz76tIA64sOz8P5lS1parnESooZidtVudhrYPl5hgZ25w_X5JCOXhXBUGHFaCkiEYUZTydLK9i5W2nfmriUt5wxzG4rSHSq7B2zqLi1GdKg1So2VHEPRfL2GvDVQiRM3K5TPyrjVgoxM8rhmQp65uQ9pM_qHhzWAAr5BvMFVax32yI-gtTzOn8_gC89MleQkHueUbdLxiUDjesO8yIIc2rbzg-KatRma92xVYOS_P9uxzVR8ZI2VuhRfdlrHbvvLC7Crp-Vq-vO3XyNooIl8N6USQbSSCG4m1mt2yqcaUyUZBLPLLi2_mE0g5pF2sm3PRCEYiWtT26go3tZt8_HLF9exTvjOMny_CKAL7Mx2evk40fqbrVY8su1uhqK6AP9XxfkoyZoYWlBkQ3vVSUuFC6lNc2ACGfUFSNqJtE9XKZnwkB3gzw7N5zqFStYvCAjhqqoxFh4peSUf4oEdDEncLFQbct-TFezeTpxEe7wSSMYm9d-YpV48Ne_T_aUMrFevTEnB3x2oqY6M-tokB2mOOjCVJv_QUbDbjigVmBpuOmW_NTTQmVxRIO7_c90ywoMs3KmVmJXgV3Oec7Rp0tC4DjxM3-MznjZ3ctAuO25oxRBlFE5kABPTAZHPwX2nr9HNbH1SyE4GfmzHFzs4qkFNWXMlLcsgrHQ6HsyHoa00_eA40Uy4UucVzS8pDHF3Nt4yy1pDWyRGIkIyp-ptbkSac4Ceq8Gd1CVak6X-xpqe4kdk9Db1BjyBGLo9BMBbAwT54KMwEUrmqRFjTBl4Lqp6AMtoRRDbxAWzKI4X0al1g64B9S2FFKNGm4zs0bDitII2LyON7BZe7x5Bm_agD1SbkdHbmpOtxY10eFPdtShwYPYKr3jGUOILARRxYCICiVRPRKaNvoozEqy0mQVyGREv0byUp3r5YarGhretLddtfZIqFPYcdJhoB2ar25710xMSdnmGGKze-yjxFq-DVKPN-ihWtqpdFaJG93FVAO56v_jURwNM3zIBkTjEDDU80wo6hOiCrm3vjmDN0RzdsXo17WTs_QrD80ZDMI3S5UBqgJqE1Rk8FE2FBZvgQOk9kqWwhVt2XeK7KsOO9uHEMdFthxUTzMWdmbByQBPUeHI-dJHKkbl8kDOc7ljnN80U-eI4vr66kBkg-evTcOLZILsJ0-7IXaTDCiszLae_EbdYeXEIRriHsp63skqod8golNLWT56DkZLyNt5lu8ZE8Bp4QdkSL3rcNv1GQg-sT3DI_bOyQuHZ3zP5-OeEFdrI1n13KrnuaecyDa-lYU23BlGuMBDC3Q6bld3FPcHswew-H0sYgJwry4lhi1qMCRSzQVKvfUc2V658fOqpJO_85ssiSfzkMzNnrE0G1uRPH5_LUA1bAfmoLU5SkbkajMi35nZJzLTg79rVXpUtK8l2xJAKRnobSVKzPD1HT-b1x68vDHp1jFzeGPaM9z7wAC4iwXJLFDJhI_U_uoomw1d5lb47WHuAjpj0Q8Psgk6IMKntdWb0g61GcLZ9OoRyKDkjxar6KtEIZ1cyYVxUGTHTSKKWyrKvhWM9koj8EXkMeKtX3KFleH9AtGBFhExeSPTSJcmnv6t1ZVGSclQxVELOZh-RusLdy-wL06mT-eiBeHGw1H-0S5My-Py2AowI3aBk8YyDPGVH1pCnVfXTIOdQH6idOAsF6SmQahhjxr2KvKPr5Xf3zRAMrlTw6-50HgiEBibhSSWr0fxtZ77dIlesxym_eTfS2V1VHv58Rb3NjFIpL2ayLI6AKAnq29U7RDPXgLjWF4WoNxGkmo6Cc7dWIOsekjQuAQUtJaSSObwP_2HaMwfg5QPdFgt8KkkqOGsDEhXd2Si5ikvN2OFA_dUigfQ8aevQHqv-V7n4nFG8XGWkgfSdYJWMt7Y0SxuBJz7nlsnnggqjRrEI1C5Ae_HjlXKtH9WdYygzOtFGR_iVm--LWQE48-EIeym8g5Q6jwqAbnARFiCcfHyvU2omiGdiN8G9FIVRetDqWUDmdnza2GbJJ0JvoT2O8KPVkXZt8_qWJvTFuJ4Cqkwr-n3aa4BOQQtkB1lELR5rXed2RMNbReXmalMujHSVozgilhQauc6D89CY98ks4Yce32HbUOF753_eMD__ewBxA9DK31i50MrKQVID7UvKot3BsOK4JH2ExIg9CCx-mAbEL6HatGwoiE3zhX0RCO2OHYf66jrbKJ220wTH2O6_BCkihzNKLqTVmpYpPSprwPkkMBNfQTgtEJPJWp9hPoXux4g4z0EtYymZpC4sRVxpBH5mvno2D9i09fh9LM4QT6cf1Plh-6Q3HCupQpiq65g9CmAtJDEiSoIhrxYRkuza65jjabRvkudS8rP4Wm5Qn5ZYlykXUIzC1BVSIvjZPK2OLw_vLG1_iTbsBONDeb9AqQaXiAc4oHqUDSp3RJXvjRfQFNI48eVtk_LLkDd1WNuwQtzAjLAg9UZA6JZGLn66SpFpU_F_bwfHvNWrQ88ZieRDdQcbyCDYNJuqMMq5YOZBpz-Oa0Lun5L8hhUGB_B5FTUQPiiLVIKuHPJP0qLgC2o_R3u9VNfgwnMENnP6pmmVI2mPMFJSHEuDeShRshUSzZ4JOs9fnvpKT3TlyXFOeAtcn89Gilua2ziEfBy78d4Quuik1aL1wQtnr3PBTbn2Z0JGOPZoKybk9CF1a-1K0hoEK54-jRgTrPGseSMibhGO9x-5bW5viQVORDH1L9g2kcfJur1D-04cDlzkAB6hfjuqk1pvT3S3O2UGU37CZcVF_iolUucC8snhW5uhuvSdoBXXcnF7TuwsgAKNvztnf7B3tPJTW8x5Q5PGqHmRsoilCFlbslJCGq4h6NraPfKGY0Qq48A_i9QQGOihf1BI3OJE5usPGaxe6yJTpGQt5xCNuMCI920xIfCuQUx5BmVDAjho7EPkcDHoUWF53iZHPp7RSlC0uVABjJaaOREGT3oludmKOYY4PoZGMFNU_4Qm2UlT_OQ3XXhon0dcjT9j7OffzgjOiYy1HUMGpSyFdvIotQQSfAzNirsXZtZX7sVKXDPtOwzALnhd27odnEnYHpep03mmDI58plDhffF_rnw326mggOpYGBEgFNdtQCwoOe9P73E3762lRYHl6IOidAG6oaIP8sr3TU5xXhzJ7iqSKQbD4UMwolnNjUjVCwGMsLj137JYfUgQBmiu-5HuRuyD3jcRmddrWnofPg_uv_99W9i0tLvW9pAk5YDDUm6fFruGbYGXUa85g7iYuB6cY3lArHpPvBhpgFuH8FEexXhtJVRAFsT-Z7nvI5Hfh-Dk2M-Dv7ITg7er2mCwxG0ZmPMSx2kglqF8bZTxk7EqfGVQMvtgQMZTDij5dCIK3PzpoLqwNMd44fViVc4VXNR6o_gFx-XyKY6PVCN-OtGVQB2B6f6LikWyIMaIB5Jic7zT0lMsf8n9aSgi1UQdiR9RuizqInhxoW3IcdPpbHzyYKMyfsgE-VKX15pPOiL3stMrq7gSmX4itErJBKq2yocNH4QHjoqFsndWK3VNc6rzkdcZZqhu_ZN3xW31q57PzZbNMfQ_IUCuNPwcTCHnBiQVRZQaaiXvyVBh2NcBXLEdqr3Xuh8Q2BgCo9ZiW6fdqXOgSAd5gwxGOeQ_Cr-HLQMhB8bFE2szFWttri01hxyXOnpPt6ziDw_t4bGYB9WqaEMjCe_3iUgLjniX9hwPuQVhTDHvwkTaddSQ-SVE4JJJ5-IY7_0MAy7_swITfNP_7Wd_-XrdJ-PzUgKdKs8E7QSd2hpK6Vv7SGlsEHzPxljtHLsvEOGeTxkuBhc4KktOI3ezaooG0IgpQr7d7-viS2PF2Ri6-zkoXH3fosjCc_d5DtOvbPn_hE1Pnu-rCWnilbekyGhOquEAYsErlioLhpSaP15wkFzcZIMlV1aEPlrM6WzcCJX8cdeV0Z7fL1v7R11Jhux8h7bpW5Dm5mWtwpfg23XtywAcSXB8F1GuSZXJ4CZHq6vj6lAUqS0YigZBzMZe7UdOZUIK0VFTY1Kl50eI9Sptiy5AEPhDdaUT1daa-_g4BqJtelvtpF7XvIpPvEtlrLJBjimxCJU28-QUJDaBeKa9rtQTWf-4kyY05ITG9ke7qUnC9Sc_LDkeCEnDNjzStbf2B-r-ov9f2pUTJXDKkP4TwwiZ-AlDGHoKExZLJQYsek_DHS8rzwbRsjuhnU-toirFjZ1nH83XcYh6OKaE-7EsoUXWs5z16ntWeNJpEifCh5JNZJ_XC7BeKiL2uldqu4naYwBnwrrz7v2UAxOv2KusUwC5WHjkueRjgQtgS15Uf3khMDZYxMIKJeU_27POO84uQXsAVdPs_L4yL36hqVdT69WNfJzPuKsFiGkheoxC8SdGCaeUgpPZ24KZgDE6TLVaYin1xRBm3h-HxpAo86vjvM5LnpuVAy_0iJa4r5ozxhfjzJ7fPjQSk835tjZ8hls4yftUJNpOJM0cruJT25qsQS-RD36X4EF0BSPEdFJdN-z_CQK3LfAKcNSvO8UR7T_FEFzpH58qS98DR83avQuNx54lQ5h9ICIi3fxSHs1eO7c5m7jaCV8VHL6Mjkniqf_ZW0123BZxC2AeGcucAD9iPYeXFI5ob65AcL6TA3k1J8gOX58RIdIdzW9mkwMjJNMNEWYpEbsevRuQ_APKGJVyu014wYGeueKk9jQjgt8YQyLC7bT7eQKNrhWrT4Xfib6neWmhV9NRXVB8o434srI7Cw2sJaWSbJGAKgov2m-fvSEq2zqbNKQNqguIqsw-QvubN5u5c00PUldQs0zISnVthXAWJKlmuNxVykdN5HoDkKfAthnQv2pVc4mZK34DfcEo3Xc-1Ssysg4qOzHR4zTCY1GFX9FVKvO3C_CHI27gi_3pFjq3CcgV2_LZ3_p0g9IlCy2-6WKcRzBf_8jbuLb2kw4zGK_cG06YeeAzzMqPrtmx1tEshJF0sKAWWBzYYc2RE1Sn_QOP6YSxei2TKvB3k8Xvnp7TK-28hcJIDnZIbbU_4TkuoXz_MwbNEcE2q6YMxC86WT0qc7YXxAY3Gp0sNOypZ7QDxz8kBrzo3px5j81zDq1kxF-ZEIclPuFCXJ9s4NPaXrkjFmWnTvPmVc9F2u0JmkNgl71WaC7pRar3QpD_kbEJp-zcOFzyUnteiJKnQdbTdxZal7OT2GyfNDWpfJ3wmRZHjgAihyhDeGR7bPC95eMwEfp7ggXQrCrfLuFwMtkFPq539rnmbQ2D1GoW6f4RMtkF5p9UyihUaAjP4LC69e9dH4A5InMJmDpPfExf-_PEoiSgVTXWC58pb4DXm5QcvZj-4c-NDnlbWb_YbU-skdRq6ReAjIjWMNdRUoaU3b3EpWLTqVCsN2ZZNmqp7is5oGJG8Xyswb6VlGQq4ij5ZgGRE1YVVzMnoBVObpw2lxeDPldsK6ZbmzLq2cG4glgKPi13X5ZlQGb7eVdAgp9LZehOm8kOTljE5sLGmYJJpkmKE6hiddQeG7wxRSqcEoIctTRfMruXQL4gsPXgtpaYsTR6vi_MVrFSobxf_8DmhAkbUHNcyj6H1HVm4JRA0isGBoicUxzhybBn0heWjprPfnOD9eO_YpuUXxBrlC63LBKLQmsVkqkNI2mfTSKxVnx_f1QeuhJw4Rrp7iVyvCCE83XEr2uujo9uxm62zHvu6FHlJBSpdeX11DGUkXLScUtkFaCgHw8dcBsnG7jloDKJFOOs3i-cxOe-dWqlaVti5_sUmCLxNFIBk2TjZP44qQ7pQMT-Wp7b0o28IHGkaiIebz20xiWNOSYstZwq1xYIwhnQtCnAibqxE5kc6gtZbuF06NqD1h9fROgp9jdqGyucjHXs0zlkO1sBGgkz-8VnkF97h3rtdkqWSTZweI28dYQ0GYXagSSIgXmQp0QM7pzDp_JO85NYpR3CZW29aB6gdzuSbDoFciWd2UTsQX3HTEIsGxhtRtMa4ZPHyS5tHAKSlquhLOTHMTQfi8GO_VHsj241Hk3S56jM9Czovx-5OwRB8qKFNiHwKOvliSJR1HgXBkAleRIALJ64fDz5cUgy6Mn13Loue3JcowCAIgkrnusjVLig-y95xVvbs1Ys1rUFFKy3mmVaVyYd4Qe-WBLG-pZXug1z8gLTEZkY636ssMr_wIl2Zl-ciykcbiH6S9yTY358VqZgzQBS-44sQTdT_qelrVSNMLKneMs06JSjhSJOpmogW1I_hdHMtxkkSOQxKINvyEHPFbIkUR734qjhDVUPweD3IUQdMJ995R89D5cl94H0REAU_wJxDSGwGlux1P9ul1FHsX9hGTiNU6cE_qAD8fWX5ceOBa2iCoNefiQw1Ft9xh6QYDe2lOPdpIeihKm2ABWMVJ3hGCYwg-QPhj6yrSbZ4DSxCMPfC3NQ0Zarj5VgvfHOIO_gGiE9plkknoLBM_j1VSP7prfUOXQsA4sSu8eYhkreMkSVRk2JJ4JY2u1s9zATCq4cTUcKwdhgasU-mzPJRc0PF_7JsrojJ-GphyN_vGSzv_kBtl1Oo7IIHNo4UYiMpioxeBd3UV44oL8wOgImfs3a1Fnb-fHOS0RHkn1P57V-QGQcbQOoXtSqcDLjCJEJ144_QQa9jSCRUYXVv5VEYGfEcpaeyP62FFvLkeNfonGiObjVxXM2mnqV9gXm8Tf_NE7HgbthKKN9zbfOSyHos03LDBIYqScCnENopFX6XyY_iHOZwtfRojYmlZcfbtM7AA5K47Ycx1hC7A3U3x9CjHjhLZhqcQXdFeMNyfbEMabj4ESo0vqfKOFhif_U49MwLg9Q7cquuJ7zoduXmiBrlm2hPgzzpEK_JBC9vmc3FrxbBV4fZKr2EXYevtvSrWJ2-trlF5u9WO2xC6oxCuTUVisluvCWwhy0de3tulbLHlKV8xYEh_MvJy8tyqeOS4Y5lLtTtwuA4rTVNrYp4-otD6ZPQolK9k1vGCQtuTbgUR0Ya2m7vMDd10zU79haM0C6y723o3meJ6Yf2tIqffTk6YRpDw4yFiM0xKRP1NvkMT8T-3ptVnIBz4laUp_HDoTT1EQsmKYFtgMMaqTRImxH75v7FW0MGXT1578lBSB-PW_3U4zR8NpxvuBfLrzHcWOQv1bJ5m-v3ho91V0wXM9X4qEiA0CbGw3UdrrZ80VSeEa_wU6mQFG5IUB85_AaMkKjZsqoO7rZ4T_GAn3uqVmObN59eCgERccyBogj3s3oHk8yEXIhtzIC4wwNbiNhPBVako-_6YJOU5FnYu7VXVAWBNZsTMi9XuZY9oXTQLoU8Ya_Ix8baVrArLSAEDUih5mZvtgEzn9rBRJEarsCi5VMojQk5vzDpKjz21R7sNYTaiNikeM7AKRTtEa-N7FtdO432Gf4y4BYTctIi6ftUPj5mRbDm-ul19u89mnGx6VA4h4GZ0oWRtCP72svGw7zV_I301Qcl1m9TxFRCZvqDEvbU_GaRlL1VzR_QUOixSfCMrlovCtycE_zXE_oyMSjPXzA17wklLjG-gEFT0FUcvlohTKLlQKAUOvkalRMsao_DoGOYRfd6e8LtuKfaRnat9iq2RJ8OfbZw4kLmT73kaszYaFDPufKFvXt0nIxi_ysbX28Y5zZq6KHKwLmcceFqwwmZV2ayAvYjBZqBYpPLTfvEUd0-3n00bXi0hLP8Il8D1F_2ZcrQcHyc2g-g1Z-rxl_XaFnipOWuqRxq3ocMZLZ4YpUmMMA89icLRAoU9mG24RHcMrzkPD9IGUZv3SJVdKwcbmQCD3cBZBb4PEFenDnLbx51GodWRuXniQ0bl4cTlKbTkTJfAe3MpOuUDkcM0FXfnLdq86Hye5N-ygCdFfGozi_EjxF1kNQ6ItrNb_0i9eBhMTgCFHGCVBGWamswc6tICnbQRCDnUXVnvr5qqjno4w3hlXSmlE5w6j5yv7CskyIj8-rsbKW3zZTLMDHIyRqL4xtEqcJSlk-86nfCQj9QVXB4O3W_HLuyWo5cWoTHPwKlArTHx8Ml4Vub7qsgFvEnFzGLwd9QAWnaqD7ENALvims52mSBivuiMMR90nh-jsjbOq6GhckHhWRrtDlfLNcaTVJz-a-s7Zt2Hw-afODG7EemMCtGVRDDZn1Eo0katat1aXH7GU2LCfh-FP80eajowVmMYb5lRHWavhRwpSGTBOsmRECrJHym4ImOGcnxX6VE3Dczh-WNYYjEa0Q4OY1y-S21xExqdgx3SkaOc5G4KGuKdPCh6FAqg4P8Is0QAYnwnjbZZ5mQHfy-oUg1tzbO7yPkY_LNV22NlVqkUfVa1cMMhOzGqTOODaw5ECto3kW1LrIhVieIvKDUnztMMVj6jU8jjZ-mbaOc_Db0JLD4pgEtSmWybS9TqiGk6dcJGXOjDFi3PjwDCSKgwND_0xpTE0QJnumUhlflz6R1sFsE5Nc8rV0QglWQQyseJm-h-taauAkIBzyH3C0595Jkm5LBlM7V-bxtDeFjx-LFqB1rslSSW0dhPxrO6JAB4W6wtyL32UIRTGNOrgh26yboEvUSSZjJBeAO8Tiv3BCKTep1i1d-V291rJjb7sj2o_8XWaNm4tpl04vVY49WttNCxHJ5fM1PuVzbRSoOEF2btxCklDFhp5t8u1Y9mVnJpNMmn5AiCXZZSoyPqrv_j78QUZZXj-x5xwVft5363F1LjjoZ5s3LdEoGbsMAUiwkm7Z7aSr8gmV3uzrv8WyjiJjlc-rpPTE0RHbK_Hc5L9x1HYTJXECSdwZ8Q38yg6uc5EpTut5WPyScHFiDy1ybxnBPPx0tWas7jVULTZaeoGbnkUFo6xTJLMd9Tzzl2IM2zpgL5ZP5c79zxJvUtxgVFwTVmqMQQESj-qXikjBmaXgMLUb4Kv4n9655bgjr3ZuF_rxDagbRdt-_2pgf6VqsHEsaZJHwIpxh01vmyp6ZcQxzSUmi-8faZ_RWCJ5iTpHrMAHvrlPzrerOYBG-RGl2pxJDCVYr_WyUjKbPDxWkjKopcXx0DrYu1C6Cz1-gtGCT18LqoW73MCtdcrwKUXAmLdGUPFG5UFq2vuqItkeXcB1AA2hUhO1rzWYqHnqy2fXm4xtBgXMHVK8dqiXCmWWJ81sezBMVYDUP4MvpPkHRFSLdmG3YrZr0IwT9RzyyDfGItqWheKUJ7fkv0koRczg1J92z4BbyVBzdnEQX4edyyKCYd96ruWi-lEILIFHCY-viwPOIP3wCifcKgMCNGOzaTX3raFo2_VcNfvDSC8cLQq9X0o79qCE1Jeog6jSHUrKYhGsjn8mAJcdf7VzAjNsMpXypG57SMUBz4rd5QGvw3uGTs6M_p4BhciR8o1yOlqCjgRYyxUbCukRH-Od8QDHjRogTAeMjwL_fxEOIKf0pXWw_L3SeEddEfBDGaSU0CWPtCiEpUdu8pXQ-PEPvUFljROnxSr4Q4NQAro_b0FL2Lfk7rSLVJ-mlV8HpUwggz2VC0jjriGZDTCQmLCGFtyYA4qMeL0nJyUD0gfujHGMrqjnBP_TmwUr2qHn6y0jVreD7SpX8ojSYWeO0ebFHyBu6LAJy9VLS7d9Gu5tZ9EVVDCd7MfbDozD1UTevnfxnyGT2-_3xJXnJ2fIzISqkV6vYDmvXAhMHwggCBamQ5VUb5Ri-JQyAOkH-P_d5AzM4vLH3NovPaTs41-EZ9LoA_ACgTwMdXcI6yKNhvbYfHK92GWG0k_HUoZp31nOrUY4hsvoDr1VyJHeFjH2WulFKr4hTj--htE99X95MtcYL1BYJ5KZVT92oX2m2Tauayqr_VP-iYgeiC7WWoo526r5jVWXs1ZgxtzXzylpf5f5z35G4YMC37RFlzgY9kDaeLkMMqUvQo4GbEFbLQ5rF-9zMA2NYFKC-6fUh0hvN1UziR-Co6ZhXi5KP1_3aw2sjSiEwlF3umF4zZcIKjKWtAHrFblBLnUyp79qId8ibcUQm4EHQ92CnkKtAf_e-OB-eZA9Vz8NGagOAFdyAtOFZ17MBcv049eh2izFmxKl4FctOKAEIU1HVWv8IWqmlDyQvsUlwImE-0YFl2EHPizSCLgHM2FgRe1a_k4YEJnQxONr2GUIGL2x8mDl7aBejUmYkkyrCj4Y5XDS1RO_hrmhDB9rAJtukT1PozIgqJTGNHyH_99wqT3cfG37PPWiSuGOG1Rbujp_by2zqGmJx1PjvoRSX7YO_s_apGzAARHZL9n-xFsoXqiJkqM242r7SHsMrqkYckG5IyxjTrpqDWdOSe4xxTc9snA6Bk5EjQ6kb0_VVG20g6kKua9Qy1n-6Jj3BMOaBHcrP4hKKStHySqqLCPOOrqn9hH2s0YKsxknqCVcR6kkCbLi2xD7dpBXmmc-X5MvuK9g9kGBWjfjQSPEfCnhD7b8cDbvWAKJh9vmdR9ofySSWMWQUjRJA43dOTlUpuskklOImDZqitGamjZTfLK4L-gE3wDkavF___kozI04zsB7xOFdPcyL76sUumoAQ_gHA0he0YE0gamTjbJEk6p6NnzuK7PisLkvNS3ZdKqTZ_msTrRSV0IUyypI1qMB-RZDgjWgdccbBTxa9xeoLTLZM8OIEmhsubQF_danFfla5dm8aDiU6k7QpiutDFosvkIJlt5sBbr5Qhwbp-DWyDaX1TI8cCqlDoplTZiZrzf-n65eZMKAcNL3xp0bMYWslR10All84u6IlOqbiiMqIsCFQS4A-Ff3uftu6JqNl8tC_J7H2F0D2W1rDUVYavmTevdbk3MfH6vEClLwnLsB2wQlripHxv77bwlwK5g-4LWHu5N6shsdVMsk7RwdaozdpDB23r4FAok05qbNgHhgpOgu-1MnRK9res5CoVia32tb846NNom_CRss0fLhnAqeU1A8hSZPwsDChHiz8fYCVLpVkCfEX-hgaloQ07R4QyTBXY9puuuJOuOCzhe1IANS4bS1EdGOSWBiDW_Df3q5ky5LOXCOfJjZBvAEkpnX3KJyxdE8K05P3Sj9akt0eG2buFfBLL3rEqBAvOjSWA8FkSF6b8NlLx53itZnn9yiEyL847Z6WGg-Wjs1y-hWSzBh587FAB2z8nTrIAYOQkW0dWJW9Grerc2NraD-hmK4AzTK9f8dCwWSfmc5TB24s6qNRU8Dk4hZ04wAuSQLximtJh3Gv58EABNSSZO6SS8S3SvTR3rRGRYe0Op5EnjoLvT4ZSkLaRFQxld15H3vq66hs9PZo3F3ZxNBO_oDulDXYVvOfeP-16sMfE744LGlucoZBvfeEtjE6Lqabl5jbgByNm08nluPSNGAVOQgExxHcAlL2H29yvMpo78qeqLlkOw3iHi1rEleBFQxcTOE2Ql0vh7gSjgZba0WoI2rl2nD5Bbc5rlTkSa_0-SoDl_aWnpSHLSXHr9y8S1Ryphc6-Tz5uy9lCrplcuHoiF7WUCChE4gv65yf1i0VTw0QjsnwPdnq5Z_EXAou2jLuXaWwNfhIPyyl69n2zEKrKDpDIxS44J4IB5zCA_DFrO1gcI71ibRrcPQiY7Y-H7ejlrGv1TfE1FwZwvphixyc5cVoUJYDZ3pljYH_vIjKAAWr-FC5rNeJDCkXdBwGzrB_fjvju9lNu0bH8xXbQ5xB4vGoorscYBverGCtbbgPof05Ga6uVo_W3_6EJQbJg71kriFa_6haOFWz9Q4sAAOYW1aA1mrEDJY40nG59r2VdQ7EU0X_5mqkwoQGcWddMWgZDFPIITpWOo672O9Egh8luGo8EP9zhRtFIGn2vC494VBDUyVGrKMJLLI1lpoUgGfsndA9JfVJH5J9BaKRqD-GcZh2Fojj05eyJS1Bj62AoqB15nSx1X5ouHF_SkkRBZUPYQqByCrtvcrQxA32PeFZXzc1YVltoLa75LmnhBU4PBA4-KZOaGjL1EYUSU5VcZkLdQVyEXXT7NZDZ9ZchBp5IZEMLkLDNSeguPTpJyTdodbbye-QZdGzHVG9yVH3bqTB_KsEqIaJ30sjX_zi6boK6ZC7ZeGI59ChA_W7jVIT4kHWWPp4WVVlecuKDzePIhc5vr3wUlXotk95470wDp3Jw81QNNu_jRgxJ0dWcIl0Ew41OV8YomZsud_VkXBTn-68KwYcBq-rYGwVFktGpVIOvoIspZvch8d6UhSVG9LcPjN1_TD1GAJ5EQtwSoVak2I9X3zHl0bVeyJ8qrcOQcLc-4ss_YUfY3sOxrv3WO3livMq2e40ec6osSm3EfhR6RKEgOAwnU_VBkS9remIUxsTftJ2ZefPU0ql_HnT7NmiYjO1s38dQbBI68scRYZtzlJ1Yh3uKqww8CG4Sr3s7hkXDl8yEHfQdSza_YSphJWn9TBflKcBa_t05qW2eTtgri54pqNvcDE1V6sJQqucT2xQAodfMaydGk-m2XPCTuAJ3kCgCpJdzH2Ar1eBv-7XLywrFGo9ayBY1cQBOT96XY0txWY3Ju5BPwU1JlRxgitQI8kGND3b3HTDGn-U__abQUMkyL18FPXkEsD5ZnRRvhTeQjeNpjM0TO6uPvk1Xxmnr6_8sR2s0bJKhuHxC47SIospvgW7Fl9BqlCaU1UoQIuP0c1rN1IfKk0OIsAZSMDvSLCze33-8vFyCes1hHSc0MI1zU2CR3cRt9-3TE08lQw6SsUAIM2SSvfsHBXP2Ib7AnoRby4HTrRKngGPXsNIRtMzthrGT1gj1Ey9Ka33YcEz3j1PGK5mJllRi7nrCWDJQt1C9kLcp3qPwWnkq5J3b6VSgLwvdrMSEPKrIJGhB8kugfey0fJduu5-Puw3dH6DvV3sQo7WKdim3JUz611z_oiwL_UzeL48yaDoBQbfe3LH8S6pWoXeCU-Pr2KASZGM8cZlkVKnJWTKa8ne9LdBuRiDpVwVePQ5cDmUn88SYs1KEEqguwB7te3xJ_3HxuPRHqy7gTs70trvBGl8zqVNJsnmKpS3V_E1UtMGLYQ8MFApSA3b6YcJP4j4E6aCD5lakVLGSnMoq3PUof7Kc92NZSWzNq7YfCoAzL1BJoz47MdWn50bnVy4Xa48GLvQgjEJ-MF2i1txejCCw8jpQSZqHLx_PvKT69cw9UkcEzktnd-uT7BruxwIl6mcWdc0oeOjt25zg0IxB62WVVcNHQi_PSC4_kM_cvIx6749xXi_6hyui-2L5ZNQmcd8-7-y_0gaQTaijKThaSg0QtGkWv1lFtBjxxe2_mcANoTlnJPsHOvriL_brQeBfNf0WXwRgUzfUF62hrYCw7OOqH_rbQNBJbHgyyTMhxVtxc-DoGqw9QIVIwZZC-XEl_8vk0D7r-QCW1Desu8eyXl6tDy6kfP-UkuvZv4kZT8cbihvUXmAghgfRfUzR0OK9V1zMIfVgDYPflxtYgAT67creQ7Re3R8f68cVFGT0oJ_ZpN7rYREZ-mGghxVwmNndFboo97n2aLZbBXfqCfLPqMgaE0-nCKB-CYN-PX7Z1tJcNerMllFlpyE8UTw064GPNxAx9J_ZcRPVgAAFdHOe23ajDzaeSRMRKVITIUPugxbKPTWb55fOIwgWOS31s0w9uiGFrScu_7aDvrsI8pXFXLZhSZ2qPnARC6Cz6t3DQPLc-_0W3T5q9iy00AjgTUBSJIIL0WdoU1zoUyJnDY2JZLYYQxaFp1aI9AzMmm9c56Qb_NiBUfJfyVS3I9NaJq91x8QebR4IdO49boC5oAWIERJCkOTLxQUbKy6EXtxpgO1-zhBXXDPKyhAuSj5jnRa7wvRdbKXza6stM81md-AqEvDl6Cnj-FSXdaEo8glAF_XxdgA3UpMx1EyvkuoGcEcoyEsqxc5AdOD4R6cKEdMRl04GGSI7fJp1cuWmJLQqesAjK_VAEnYYrmoQxdZLw8BR1SM13XoWSfEq9dN_uZiwME1CwkTR6mN-WxXfeg-JYDRebAY_idA3xP6lcwFBQsIRebdcRyqgmiZCMyaRJ28ZwOUmpHaqJEiccfbBL0oqO5VFNP1bAq5nsjrvXkmB-a_jAJyAliToyuKc4i-VXMiVwp1jV_outA53A8csMgLmkYHrON3ZA79psVTdnJehE5zdAaObGZt_h4U1fXGGfdzuTIZ8Nr1UlNJVHwrC5Z23DY_Dp7JNHt9TIwktbfaQieUW5IR3-x8vczQewwU3lIu9KrSESjQZSe3Xr029LQpqSe3DuyWCWrLSEun0npCWaCiskfrT3zI31957vIbKdKFD_rfUzKs1byozDw6o0K19litvEClc2PQ8gZWW347WfHIwek-9qAMsRlreFc8n9ASWW_QQxgTRnBBeC4DkuwWmuj4Cfs6xwfu9b9T15jJNYGxIsLVer38U3AS6dEgtwCjwjZ0jfQRV2o_Lr89Qsj4E_EnIbJzZGEKBOIobO-lj72l0sFG5b5_qaMhUsndRRRQo3KoNa3jTtGsBI8EkMb58uLLlqD7sdIEuJ-a-1SQwiSyb9m5P5FIlyykGPFK5okoEOxzwIZSEgdghKXGIq8SQbgkQ83kHkocq7NxBHdX61Egr0V3uEEytgcO2chYZd-WiJWFLLm5zmTeLQfUl7G5CJZwhFGRjpGpYbYGcMkRCEgATzT4jcwzH7KYBMCIXi1bskCDctAy2as0jQnc5ICFzWl76doHdMVJZSvFzFY29_vP8IuVRHSW3hCtODDxLhnvDXMPGt6dOjHN-dq3_NB9mfvHKkOEK10JDpRnvz0k6gstUZDHs28a_BEH8RTb0pXh1rcO35elGh4yDNNKUk26xXKabN3OZMVmsZxxqL_JqptdmC9cNwg7XZ-S1Ey4-6acvec5J4R6GjTcPZWluZLERc2tTSeOtQoJbCJD1shS2NvR60jahncVhdp0ynV1-ZX8oAsMxKFKiB0ZtxdVNLlk4FM2nDzwlHkjbJNlz6xXuR8M74qcWVsgEzEBWyL0INt-KlkSSTIW_JPPnULrxNfDTu20ZQScBx55So1xEURFaCHjUf5P8MV5vr4paC7h0UXlWlj2LD_j9h0T3FYugMqTZuJ_NfPpmY0DpebI-_DY_cbNz6DZEIyicaqZ6MdFZlUz4Q1bpCI6773qdFLUdKS436u4jQcQjlpSbaA0sHl-7Mmr4UWKtEIZv69KCi0XQPqCOsMSYhnteyv7rrH8tL5zNqCIkUW_hKmle5Vblbafbg8wVhaObzO4nZKks-se9yVoMZnYzykm6A9C79qdWg3bRPQ8t7nWcwo42fB6kJ_K4OiMlPklzpWmAkDbTjUeFnqdUV5XhKdZPRWfHABG1jye0AZ9TZR8cS_lutJQGx6NzNzJ2h7qaeWM97ahd1rbGqeYhC3V3El75LYabMagyR5FqKaPXAPvTXdiulOFSb5QjjtOpxjBZQKC4kH_Z_jTmFCqjZ9KHB9FIdkVqqPSZV9eWPHdh4GB1RlfnJoO1qBGXEJfsTrI4BvIGn4FFudiZmQNar57xgkDx2CL3hejyIWssU6MkmvtLqwcha7NgSa9Li6zQHd2pBrfyKUtvE17_aEL9vys-2U8o4KqKph6vSzTprKRShTAmk7hUY8Hn2I2N1frQzOO6sD8NUcGqGlLMh4rjaKQXdideiNkn74J6Wdo2-hlie99H9qpbz26SCsSE0Ucn_HTvynOg3O4HGB4uMhz-CQHsdLh-9aZjw-xLtmbfLDdUEQC8U83rsX9JysbyySFP0bZA5kUTbhN1En5_-E8sXUburEg-nAshSW6WvSvM0ZRVsA0SoaDKIR0Wq8X8hXhK9tpx6rOMmXlcLFwNefRgNvoR7aoM7sRFeBT2QL3yjuHnOV1cZ-li3Fgfb8chV5CCsqAXucplybckQ1SmtDmiGxG9u6M77ODMpU_Cgn_bwtrDwwFci1dFyBPaBhQDx08jIb5tRUoAv0oLbTbl3CTemYSjNQaqWtX_wiDjH4uW1oU89m3CE=', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc', + signature='gAAAAABoxC0Pe79v2UqAMj3Y1BkJi0m_G8llzMHMeav3XGlfPIsphSfHvJVzbyv5s7pvfPLs2-ECy9vhTMaN1UfI_PYmoJ17y_k_lLjvC6sK7SdFeCmdGNjbrgIcah2DJecVqDdoT8P0Aaz6COw982zu34UyGL59e5FTol9mAGvtInH9vXmmQUnGS5fGktT90wC6-MrIxBc3Og92F-e5ciGk0DAVMC90pDTyP4z_Qkj8Jv1QYKqCv4GwFO8LyUicPTbML6l39jyTfH8L86uDWMMxKNsvHEIrqgTQnsInlwnHYVbPURb93_gMtcjOpZwc2ESnjqUtMLXzs8XaKxhU2NVBAzcXL5x2kg7OI7HbS4Vl90Hx5cVwp3i8OTfpw8aRhDoxZJWptxNBKwDDEtjqLbylKQ7m2uJ8_TkK030O0fb81_W1-36qeRn-yNE5jjkKTezyHP0DlpKjCzoY3pZ0GtIj0FRDJOJJOmbHXjC8HfrwBz76tIA64sOz8P5lS1parnESooZidtVudhrYPl5hgZ25w_X5JCOXhXBUGHFaCkiEYUZTydLK9i5W2nfmriUt5wxzG4rSHSq7B2zqLi1GdKg1So2VHEPRfL2GvDVQiRM3K5TPyrjVgoxM8rhmQp65uQ9pM_qHhzWAAr5BvMFVax32yI-gtTzOn8_gC89MleQkHueUbdLxiUDjesO8yIIc2rbzg-KatRma92xVYOS_P9uxzVR8ZI2VuhRfdlrHbvvLC7Crp-Vq-vO3XyNooIl8N6USQbSSCG4m1mt2yqcaUyUZBLPLLi2_mE0g5pF2sm3PRCEYiWtT26go3tZt8_HLF9exTvjOMny_CKAL7Mx2evk40fqbrVY8su1uhqK6AP9XxfkoyZoYWlBkQ3vVSUuFC6lNc2ACGfUFSNqJtE9XKZnwkB3gzw7N5zqFStYvCAjhqqoxFh4peSUf4oEdDEncLFQbct-TFezeTpxEe7wSSMYm9d-YpV48Ne_T_aUMrFevTEnB3x2oqY6M-tokB2mOOjCVJv_QUbDbjigVmBpuOmW_NTTQmVxRIO7_c90ywoMs3KmVmJXgV3Oec7Rp0tC4DjxM3-MznjZ3ctAuO25oxRBlFE5kABPTAZHPwX2nr9HNbH1SyE4GfmzHFzs4qkFNWXMlLcsgrHQ6HsyHoa00_eA40Uy4UucVzS8pDHF3Nt4yy1pDWyRGIkIyp-ptbkSac4Ceq8Gd1CVak6X-xpqe4kdk9Db1BjyBGLo9BMBbAwT54KMwEUrmqRFjTBl4Lqp6AMtoRRDbxAWzKI4X0al1g64B9S2FFKNGm4zs0bDitII2LyON7BZe7x5Bm_agD1SbkdHbmpOtxY10eFPdtShwYPYKr3jGUOILARRxYCICiVRPRKaNvoozEqy0mQVyGREv0byUp3r5YarGhretLddtfZIqFPYcdJhoB2ar25710xMSdnmGGKze-yjxFq-DVKPN-ihWtqpdFaJG93FVAO56v_jURwNM3zIBkTjEDDU80wo6hOiCrm3vjmDN0RzdsXo17WTs_QrD80ZDMI3S5UBqgJqE1Rk8FE2FBZvgQOk9kqWwhVt2XeK7KsOO9uHEMdFthxUTzMWdmbByQBPUeHI-dJHKkbl8kDOc7ljnN80U-eI4vr66kBkg-evTcOLZILsJ0-7IXaTDCiszLae_EbdYeXEIRriHsp63skqod8golNLWT56DkZLyNt5lu8ZE8Bp4QdkSL3rcNv1GQg-sT3DI_bOyQuHZ3zP5-OeEFdrI1n13KrnuaecyDa-lYU23BlGuMBDC3Q6bld3FPcHswew-H0sYgJwry4lhi1qMCRSzQVKvfUc2V658fOqpJO_85ssiSfzkMzNnrE0G1uRPH5_LUA1bAfmoLU5SkbkajMi35nZJzLTg79rVXpUtK8l2xJAKRnobSVKzPD1HT-b1x68vDHp1jFzeGPaM9z7wAC4iwXJLFDJhI_U_uoomw1d5lb47WHuAjpj0Q8Psgk6IMKntdWb0g61GcLZ9OoRyKDkjxar6KtEIZ1cyYVxUGTHTSKKWyrKvhWM9koj8EXkMeKtX3KFleH9AtGBFhExeSPTSJcmnv6t1ZVGSclQxVELOZh-RusLdy-wL06mT-eiBeHGw1H-0S5My-Py2AowI3aBk8YyDPGVH1pCnVfXTIOdQH6idOAsF6SmQahhjxr2KvKPr5Xf3zRAMrlTw6-50HgiEBibhSSWr0fxtZ77dIlesxym_eTfS2V1VHv58Rb3NjFIpL2ayLI6AKAnq29U7RDPXgLjWF4WoNxGkmo6Cc7dWIOsekjQuAQUtJaSSObwP_2HaMwfg5QPdFgt8KkkqOGsDEhXd2Si5ikvN2OFA_dUigfQ8aevQHqv-V7n4nFG8XGWkgfSdYJWMt7Y0SxuBJz7nlsnnggqjRrEI1C5Ae_HjlXKtH9WdYygzOtFGR_iVm--LWQE48-EIeym8g5Q6jwqAbnARFiCcfHyvU2omiGdiN8G9FIVRetDqWUDmdnza2GbJJ0JvoT2O8KPVkXZt8_qWJvTFuJ4Cqkwr-n3aa4BOQQtkB1lELR5rXed2RMNbReXmalMujHSVozgilhQauc6D89CY98ks4Yce32HbUOF753_eMD__ewBxA9DK31i50MrKQVID7UvKot3BsOK4JH2ExIg9CCx-mAbEL6HatGwoiE3zhX0RCO2OHYf66jrbKJ220wTH2O6_BCkihzNKLqTVmpYpPSprwPkkMBNfQTgtEJPJWp9hPoXux4g4z0EtYymZpC4sRVxpBH5mvno2D9i09fh9LM4QT6cf1Plh-6Q3HCupQpiq65g9CmAtJDEiSoIhrxYRkuza65jjabRvkudS8rP4Wm5Qn5ZYlykXUIzC1BVSIvjZPK2OLw_vLG1_iTbsBONDeb9AqQaXiAc4oHqUDSp3RJXvjRfQFNI48eVtk_LLkDd1WNuwQtzAjLAg9UZA6JZGLn66SpFpU_F_bwfHvNWrQ88ZieRDdQcbyCDYNJuqMMq5YOZBpz-Oa0Lun5L8hhUGB_B5FTUQPiiLVIKuHPJP0qLgC2o_R3u9VNfgwnMENnP6pmmVI2mPMFJSHEuDeShRshUSzZ4JOs9fnvpKT3TlyXFOeAtcn89Gilua2ziEfBy78d4Quuik1aL1wQtnr3PBTbn2Z0JGOPZoKybk9CF1a-1K0hoEK54-jRgTrPGseSMibhGO9x-5bW5viQVORDH1L9g2kcfJur1D-04cDlzkAB6hfjuqk1pvT3S3O2UGU37CZcVF_iolUucC8snhW5uhuvSdoBXXcnF7TuwsgAKNvztnf7B3tPJTW8x5Q5PGqHmRsoilCFlbslJCGq4h6NraPfKGY0Qq48A_i9QQGOihf1BI3OJE5usPGaxe6yJTpGQt5xCNuMCI920xIfCuQUx5BmVDAjho7EPkcDHoUWF53iZHPp7RSlC0uVABjJaaOREGT3oludmKOYY4PoZGMFNU_4Qm2UlT_OQ3XXhon0dcjT9j7OffzgjOiYy1HUMGpSyFdvIotQQSfAzNirsXZtZX7sVKXDPtOwzALnhd27odnEnYHpep03mmDI58plDhffF_rnw326mggOpYGBEgFNdtQCwoOe9P73E3762lRYHl6IOidAG6oaIP8sr3TU5xXhzJ7iqSKQbD4UMwolnNjUjVCwGMsLj137JYfUgQBmiu-5HuRuyD3jcRmddrWnofPg_uv_99W9i0tLvW9pAk5YDDUm6fFruGbYGXUa85g7iYuB6cY3lArHpPvBhpgFuH8FEexXhtJVRAFsT-Z7nvI5Hfh-Dk2M-Dv7ITg7er2mCwxG0ZmPMSx2kglqF8bZTxk7EqfGVQMvtgQMZTDij5dCIK3PzpoLqwNMd44fViVc4VXNR6o_gFx-XyKY6PVCN-OtGVQB2B6f6LikWyIMaIB5Jic7zT0lMsf8n9aSgi1UQdiR9RuizqInhxoW3IcdPpbHzyYKMyfsgE-VKX15pPOiL3stMrq7gSmX4itErJBKq2yocNH4QHjoqFsndWK3VNc6rzkdcZZqhu_ZN3xW31q57PzZbNMfQ_IUCuNPwcTCHnBiQVRZQaaiXvyVBh2NcBXLEdqr3Xuh8Q2BgCo9ZiW6fdqXOgSAd5gwxGOeQ_Cr-HLQMhB8bFE2szFWttri01hxyXOnpPt6ziDw_t4bGYB9WqaEMjCe_3iUgLjniX9hwPuQVhTDHvwkTaddSQ-SVE4JJJ5-IY7_0MAy7_swITfNP_7Wd_-XrdJ-PzUgKdKs8E7QSd2hpK6Vv7SGlsEHzPxljtHLsvEOGeTxkuBhc4KktOI3ezaooG0IgpQr7d7-viS2PF2Ri6-zkoXH3fosjCc_d5DtOvbPn_hE1Pnu-rCWnilbekyGhOquEAYsErlioLhpSaP15wkFzcZIMlV1aEPlrM6WzcCJX8cdeV0Z7fL1v7R11Jhux8h7bpW5Dm5mWtwpfg23XtywAcSXB8F1GuSZXJ4CZHq6vj6lAUqS0YigZBzMZe7UdOZUIK0VFTY1Kl50eI9Sptiy5AEPhDdaUT1daa-_g4BqJtelvtpF7XvIpPvEtlrLJBjimxCJU28-QUJDaBeKa9rtQTWf-4kyY05ITG9ke7qUnC9Sc_LDkeCEnDNjzStbf2B-r-ov9f2pUTJXDKkP4TwwiZ-AlDGHoKExZLJQYsek_DHS8rzwbRsjuhnU-toirFjZ1nH83XcYh6OKaE-7EsoUXWs5z16ntWeNJpEifCh5JNZJ_XC7BeKiL2uldqu4naYwBnwrrz7v2UAxOv2KusUwC5WHjkueRjgQtgS15Uf3khMDZYxMIKJeU_27POO84uQXsAVdPs_L4yL36hqVdT69WNfJzPuKsFiGkheoxC8SdGCaeUgpPZ24KZgDE6TLVaYin1xRBm3h-HxpAo86vjvM5LnpuVAy_0iJa4r5ozxhfjzJ7fPjQSk835tjZ8hls4yftUJNpOJM0cruJT25qsQS-RD36X4EF0BSPEdFJdN-z_CQK3LfAKcNSvO8UR7T_FEFzpH58qS98DR83avQuNx54lQ5h9ICIi3fxSHs1eO7c5m7jaCV8VHL6Mjkniqf_ZW0123BZxC2AeGcucAD9iPYeXFI5ob65AcL6TA3k1J8gOX58RIdIdzW9mkwMjJNMNEWYpEbsevRuQ_APKGJVyu014wYGeueKk9jQjgt8YQyLC7bT7eQKNrhWrT4Xfib6neWmhV9NRXVB8o434srI7Cw2sJaWSbJGAKgov2m-fvSEq2zqbNKQNqguIqsw-QvubN5u5c00PUldQs0zISnVthXAWJKlmuNxVykdN5HoDkKfAthnQv2pVc4mZK34DfcEo3Xc-1Ssysg4qOzHR4zTCY1GFX9FVKvO3C_CHI27gi_3pFjq3CcgV2_LZ3_p0g9IlCy2-6WKcRzBf_8jbuLb2kw4zGK_cG06YeeAzzMqPrtmx1tEshJF0sKAWWBzYYc2RE1Sn_QOP6YSxei2TKvB3k8Xvnp7TK-28hcJIDnZIbbU_4TkuoXz_MwbNEcE2q6YMxC86WT0qc7YXxAY3Gp0sNOypZ7QDxz8kBrzo3px5j81zDq1kxF-ZEIclPuFCXJ9s4NPaXrkjFmWnTvPmVc9F2u0JmkNgl71WaC7pRar3QpD_kbEJp-zcOFzyUnteiJKnQdbTdxZal7OT2GyfNDWpfJ3wmRZHjgAihyhDeGR7bPC95eMwEfp7ggXQrCrfLuFwMtkFPq539rnmbQ2D1GoW6f4RMtkF5p9UyihUaAjP4LC69e9dH4A5InMJmDpPfExf-_PEoiSgVTXWC58pb4DXm5QcvZj-4c-NDnlbWb_YbU-skdRq6ReAjIjWMNdRUoaU3b3EpWLTqVCsN2ZZNmqp7is5oGJG8Xyswb6VlGQq4ij5ZgGRE1YVVzMnoBVObpw2lxeDPldsK6ZbmzLq2cG4glgKPi13X5ZlQGb7eVdAgp9LZehOm8kOTljE5sLGmYJJpkmKE6hiddQeG7wxRSqcEoIctTRfMruXQL4gsPXgtpaYsTR6vi_MVrFSobxf_8DmhAkbUHNcyj6H1HVm4JRA0isGBoicUxzhybBn0heWjprPfnOD9eO_YpuUXxBrlC63LBKLQmsVkqkNI2mfTSKxVnx_f1QeuhJw4Rrp7iVyvCCE83XEr2uujo9uxm62zHvu6FHlJBSpdeX11DGUkXLScUtkFaCgHw8dcBsnG7jloDKJFOOs3i-cxOe-dWqlaVti5_sUmCLxNFIBk2TjZP44qQ7pQMT-Wp7b0o28IHGkaiIebz20xiWNOSYstZwq1xYIwhnQtCnAibqxE5kc6gtZbuF06NqD1h9fROgp9jdqGyucjHXs0zlkO1sBGgkz-8VnkF97h3rtdkqWSTZweI28dYQ0GYXagSSIgXmQp0QM7pzDp_JO85NYpR3CZW29aB6gdzuSbDoFciWd2UTsQX3HTEIsGxhtRtMa4ZPHyS5tHAKSlquhLOTHMTQfi8GO_VHsj241Hk3S56jM9Czovx-5OwRB8qKFNiHwKOvliSJR1HgXBkAleRIALJ64fDz5cUgy6Mn13Loue3JcowCAIgkrnusjVLig-y95xVvbs1Ys1rUFFKy3mmVaVyYd4Qe-WBLG-pZXug1z8gLTEZkY636ssMr_wIl2Zl-ciykcbiH6S9yTY358VqZgzQBS-44sQTdT_qelrVSNMLKneMs06JSjhSJOpmogW1I_hdHMtxkkSOQxKINvyEHPFbIkUR734qjhDVUPweD3IUQdMJ995R89D5cl94H0REAU_wJxDSGwGlux1P9ul1FHsX9hGTiNU6cE_qAD8fWX5ceOBa2iCoNefiQw1Ft9xh6QYDe2lOPdpIeihKm2ABWMVJ3hGCYwg-QPhj6yrSbZ4DSxCMPfC3NQ0Zarj5VgvfHOIO_gGiE9plkknoLBM_j1VSP7prfUOXQsA4sSu8eYhkreMkSVRk2JJ4JY2u1s9zATCq4cTUcKwdhgasU-mzPJRc0PF_7JsrojJ-GphyN_vGSzv_kBtl1Oo7IIHNo4UYiMpioxeBd3UV44oL8wOgImfs3a1Fnb-fHOS0RHkn1P57V-QGQcbQOoXtSqcDLjCJEJ144_QQa9jSCRUYXVv5VEYGfEcpaeyP62FFvLkeNfonGiObjVxXM2mnqV9gXm8Tf_NE7HgbthKKN9zbfOSyHos03LDBIYqScCnENopFX6XyY_iHOZwtfRojYmlZcfbtM7AA5K47Ycx1hC7A3U3x9CjHjhLZhqcQXdFeMNyfbEMabj4ESo0vqfKOFhif_U49MwLg9Q7cquuJ7zoduXmiBrlm2hPgzzpEK_JBC9vmc3FrxbBV4fZKr2EXYevtvSrWJ2-trlF5u9WO2xC6oxCuTUVisluvCWwhy0de3tulbLHlKV8xYEh_MvJy8tyqeOS4Y5lLtTtwuA4rTVNrYp4-otD6ZPQolK9k1vGCQtuTbgUR0Ya2m7vMDd10zU79haM0C6y723o3meJ6Yf2tIqffTk6YRpDw4yFiM0xKRP1NvkMT8T-3ptVnIBz4laUp_HDoTT1EQsmKYFtgMMaqTRImxH75v7FW0MGXT1578lBSB-PW_3U4zR8NpxvuBfLrzHcWOQv1bJ5m-v3ho91V0wXM9X4qEiA0CbGw3UdrrZ80VSeEa_wU6mQFG5IUB85_AaMkKjZsqoO7rZ4T_GAn3uqVmObN59eCgERccyBogj3s3oHk8yEXIhtzIC4wwNbiNhPBVako-_6YJOU5FnYu7VXVAWBNZsTMi9XuZY9oXTQLoU8Ya_Ix8baVrArLSAEDUih5mZvtgEzn9rBRJEarsCi5VMojQk5vzDpKjz21R7sNYTaiNikeM7AKRTtEa-N7FtdO432Gf4y4BYTctIi6ftUPj5mRbDm-ul19u89mnGx6VA4h4GZ0oWRtCP72svGw7zV_I301Qcl1m9TxFRCZvqDEvbU_GaRlL1VzR_QUOixSfCMrlovCtycE_zXE_oyMSjPXzA17wklLjG-gEFT0FUcvlohTKLlQKAUOvkalRMsao_DoGOYRfd6e8LtuKfaRnat9iq2RJ8OfbZw4kLmT73kaszYaFDPufKFvXt0nIxi_ysbX28Y5zZq6KHKwLmcceFqwwmZV2ayAvYjBZqBYpPLTfvEUd0-3n00bXi0hLP8Il8D1F_2ZcrQcHyc2g-g1Z-rxl_XaFnipOWuqRxq3ocMZLZ4YpUmMMA89icLRAoU9mG24RHcMrzkPD9IGUZv3SJVdKwcbmQCD3cBZBb4PEFenDnLbx51GodWRuXniQ0bl4cTlKbTkTJfAe3MpOuUDkcM0FXfnLdq86Hye5N-ygCdFfGozi_EjxF1kNQ6ItrNb_0i9eBhMTgCFHGCVBGWamswc6tICnbQRCDnUXVnvr5qqjno4w3hlXSmlE5w6j5yv7CskyIj8-rsbKW3zZTLMDHIyRqL4xtEqcJSlk-86nfCQj9QVXB4O3W_HLuyWo5cWoTHPwKlArTHx8Ml4Vub7qsgFvEnFzGLwd9QAWnaqD7ENALvims52mSBivuiMMR90nh-jsjbOq6GhckHhWRrtDlfLNcaTVJz-a-s7Zt2Hw-afODG7EemMCtGVRDDZn1Eo0katat1aXH7GU2LCfh-FP80eajowVmMYb5lRHWavhRwpSGTBOsmRECrJHym4ImOGcnxX6VE3Dczh-WNYYjEa0Q4OY1y-S21xExqdgx3SkaOc5G4KGuKdPCh6FAqg4P8Is0QAYnwnjbZZ5mQHfy-oUg1tzbO7yPkY_LNV22NlVqkUfVa1cMMhOzGqTOODaw5ECto3kW1LrIhVieIvKDUnztMMVj6jU8jjZ-mbaOc_Db0JLD4pgEtSmWybS9TqiGk6dcJGXOjDFi3PjwDCSKgwND_0xpTE0QJnumUhlflz6R1sFsE5Nc8rV0QglWQQyseJm-h-taauAkIBzyH3C0595Jkm5LBlM7V-bxtDeFjx-LFqB1rslSSW0dhPxrO6JAB4W6wtyL32UIRTGNOrgh26yboEvUSSZjJBeAO8Tiv3BCKTep1i1d-V291rJjb7sj2o_8XWaNm4tpl04vVY49WttNCxHJ5fM1PuVzbRSoOEF2btxCklDFhp5t8u1Y9mVnJpNMmn5AiCXZZSoyPqrv_j78QUZZXj-x5xwVft5363F1LjjoZ5s3LdEoGbsMAUiwkm7Z7aSr8gmV3uzrv8WyjiJjlc-rpPTE0RHbK_Hc5L9x1HYTJXECSdwZ8Q38yg6uc5EpTut5WPyScHFiDy1ybxnBPPx0tWas7jVULTZaeoGbnkUFo6xTJLMd9Tzzl2IM2zpgL5ZP5c79zxJvUtxgVFwTVmqMQQESj-qXikjBmaXgMLUb4Kv4n9655bgjr3ZuF_rxDagbRdt-_2pgf6VqsHEsaZJHwIpxh01vmyp6ZcQxzSUmi-8faZ_RWCJ5iTpHrMAHvrlPzrerOYBG-RGl2pxJDCVYr_WyUjKbPDxWkjKopcXx0DrYu1C6Cz1-gtGCT18LqoW73MCtdcrwKUXAmLdGUPFG5UFq2vuqItkeXcB1AA2hUhO1rzWYqHnqy2fXm4xtBgXMHVK8dqiXCmWWJ81sezBMVYDUP4MvpPkHRFSLdmG3YrZr0IwT9RzyyDfGItqWheKUJ7fkv0koRczg1J92z4BbyVBzdnEQX4edyyKCYd96ruWi-lEILIFHCY-viwPOIP3wCifcKgMCNGOzaTX3raFo2_VcNfvDSC8cLQq9X0o79qCE1Jeog6jSHUrKYhGsjn8mAJcdf7VzAjNsMpXypG57SMUBz4rd5QGvw3uGTs6M_p4BhciR8o1yOlqCjgRYyxUbCukRH-Od8QDHjRogTAeMjwL_fxEOIKf0pXWw_L3SeEddEfBDGaSU0CWPtCiEpUdu8pXQ-PEPvUFljROnxSr4Q4NQAro_b0FL2Lfk7rSLVJ-mlV8HpUwggz2VC0jjriGZDTCQmLCGFtyYA4qMeL0nJyUD0gfujHGMrqjnBP_TmwUr2qHn6y0jVreD7SpX8ojSYWeO0ebFHyBu6LAJy9VLS7d9Gu5tZ9EVVDCd7MfbDozD1UTevnfxnyGT2-_3xJXnJ2fIzISqkV6vYDmvXAhMHwggCBamQ5VUb5Ri-JQyAOkH-P_d5AzM4vLH3NovPaTs41-EZ9LoA_ACgTwMdXcI6yKNhvbYfHK92GWG0k_HUoZp31nOrUY4hsvoDr1VyJHeFjH2WulFKr4hTj--htE99X95MtcYL1BYJ5KZVT92oX2m2Tauayqr_VP-iYgeiC7WWoo526r5jVWXs1ZgxtzXzylpf5f5z35G4YMC37RFlzgY9kDaeLkMMqUvQo4GbEFbLQ5rF-9zMA2NYFKC-6fUh0hvN1UziR-Co6ZhXi5KP1_3aw2sjSiEwlF3umF4zZcIKjKWtAHrFblBLnUyp79qId8ibcUQm4EHQ92CnkKtAf_e-OB-eZA9Vz8NGagOAFdyAtOFZ17MBcv049eh2izFmxKl4FctOKAEIU1HVWv8IWqmlDyQvsUlwImE-0YFl2EHPizSCLgHM2FgRe1a_k4YEJnQxONr2GUIGL2x8mDl7aBejUmYkkyrCj4Y5XDS1RO_hrmhDB9rAJtukT1PozIgqJTGNHyH_99wqT3cfG37PPWiSuGOG1Rbujp_by2zqGmJx1PjvoRSX7YO_s_apGzAARHZL9n-xFsoXqiJkqM242r7SHsMrqkYckG5IyxjTrpqDWdOSe4xxTc9snA6Bk5EjQ6kb0_VVG20g6kKua9Qy1n-6Jj3BMOaBHcrP4hKKStHySqqLCPOOrqn9hH2s0YKsxknqCVcR6kkCbLi2xD7dpBXmmc-X5MvuK9g9kGBWjfjQSPEfCnhD7b8cDbvWAKJh9vmdR9ofySSWMWQUjRJA43dOTlUpuskklOImDZqitGamjZTfLK4L-gE3wDkavF___kozI04zsB7xOFdPcyL76sUumoAQ_gHA0he0YE0gamTjbJEk6p6NnzuK7PisLkvNS3ZdKqTZ_msTrRSV0IUyypI1qMB-RZDgjWgdccbBTxa9xeoLTLZM8OIEmhsubQF_danFfla5dm8aDiU6k7QpiutDFosvkIJlt5sBbr5Qhwbp-DWyDaX1TI8cCqlDoplTZiZrzf-n65eZMKAcNL3xp0bMYWslR10All84u6IlOqbiiMqIsCFQS4A-Ff3uftu6JqNl8tC_J7H2F0D2W1rDUVYavmTevdbk3MfH6vEClLwnLsB2wQlripHxv77bwlwK5g-4LWHu5N6shsdVMsk7RwdaozdpDB23r4FAok05qbNgHhgpOgu-1MnRK9res5CoVia32tb846NNom_CRss0fLhnAqeU1A8hSZPwsDChHiz8fYCVLpVkCfEX-hgaloQ07R4QyTBXY9puuuJOuOCzhe1IANS4bS1EdGOSWBiDW_Df3q5ky5LOXCOfJjZBvAEkpnX3KJyxdE8K05P3Sj9akt0eG2buFfBLL3rEqBAvOjSWA8FkSF6b8NlLx53itZnn9yiEyL847Z6WGg-Wjs1y-hWSzBh587FAB2z8nTrIAYOQkW0dWJW9Grerc2NraD-hmK4AzTK9f8dCwWSfmc5TB24s6qNRU8Dk4hZ04wAuSQLximtJh3Gv58EABNSSZO6SS8S3SvTR3rRGRYe0Op5EnjoLvT4ZSkLaRFQxld15H3vq66hs9PZo3F3ZxNBO_oDulDXYVvOfeP-16sMfE744LGlucoZBvfeEtjE6Lqabl5jbgByNm08nluPSNGAVOQgExxHcAlL2H29yvMpo78qeqLlkOw3iHi1rEleBFQxcTOE2Ql0vh7gSjgZba0WoI2rl2nD5Bbc5rlTkSa_0-SoDl_aWnpSHLSXHr9y8S1Ryphc6-Tz5uy9lCrplcuHoiF7WUCChE4gv65yf1i0VTw0QjsnwPdnq5Z_EXAou2jLuXaWwNfhIPyyl69n2zEKrKDpDIxS44J4IB5zCA_DFrO1gcI71ibRrcPQiY7Y-H7ejlrGv1TfE1FwZwvphixyc5cVoUJYDZ3pljYH_vIjKAAWr-FC5rNeJDCkXdBwGzrB_fjvju9lNu0bH8xXbQ5xB4vGoorscYBverGCtbbgPof05Ga6uVo_W3_6EJQbJg71kriFa_6haOFWz9Q4sAAOYW1aA1mrEDJY40nG59r2VdQ7EU0X_5mqkwoQGcWddMWgZDFPIITpWOo672O9Egh8luGo8EP9zhRtFIGn2vC494VBDUyVGrKMJLLI1lpoUgGfsndA9JfVJH5J9BaKRqD-GcZh2Fojj05eyJS1Bj62AoqB15nSx1X5ouHF_SkkRBZUPYQqByCrtvcrQxA32PeFZXzc1YVltoLa75LmnhBU4PBA4-KZOaGjL1EYUSU5VcZkLdQVyEXXT7NZDZ9ZchBp5IZEMLkLDNSeguPTpJyTdodbbye-QZdGzHVG9yVH3bqTB_KsEqIaJ30sjX_zi6boK6ZC7ZeGI59ChA_W7jVIT4kHWWPp4WVVlecuKDzePIhc5vr3wUlXotk95470wDp3Jw81QNNu_jRgxJ0dWcIl0Ew41OV8YomZsud_VkXBTn-68KwYcBq-rYGwVFktGpVIOvoIspZvch8d6UhSVG9LcPjN1_TD1GAJ5EQtwSoVak2I9X3zHl0bVeyJ8qrcOQcLc-4ss_YUfY3sOxrv3WO3livMq2e40ec6osSm3EfhR6RKEgOAwnU_VBkS9remIUxsTftJ2ZefPU0ql_HnT7NmiYjO1s38dQbBI68scRYZtzlJ1Yh3uKqww8CG4Sr3s7hkXDl8yEHfQdSza_YSphJWn9TBflKcBa_t05qW2eTtgri54pqNvcDE1V6sJQqucT2xQAodfMaydGk-m2XPCTuAJ3kCgCpJdzH2Ar1eBv-7XLywrFGo9ayBY1cQBOT96XY0txWY3Ju5BPwU1JlRxgitQI8kGND3b3HTDGn-U__abQUMkyL18FPXkEsD5ZnRRvhTeQjeNpjM0TO6uPvk1Xxmnr6_8sR2s0bJKhuHxC47SIospvgW7Fl9BqlCaU1UoQIuP0c1rN1IfKk0OIsAZSMDvSLCze33-8vFyCes1hHSc0MI1zU2CR3cRt9-3TE08lQw6SsUAIM2SSvfsHBXP2Ib7AnoRby4HTrRKngGPXsNIRtMzthrGT1gj1Ey9Ka33YcEz3j1PGK5mJllRi7nrCWDJQt1C9kLcp3qPwWnkq5J3b6VSgLwvdrMSEPKrIJGhB8kugfey0fJduu5-Puw3dH6DvV3sQo7WKdim3JUz611z_oiwL_UzeL48yaDoBQbfe3LH8S6pWoXeCU-Pr2KASZGM8cZlkVKnJWTKa8ne9LdBuRiDpVwVePQ5cDmUn88SYs1KEEqguwB7te3xJ_3HxuPRHqy7gTs70trvBGl8zqVNJsnmKpS3V_E1UtMGLYQ8MFApSA3b6YcJP4j4E6aCD5lakVLGSnMoq3PUof7Kc92NZSWzNq7YfCoAzL1BJoz47MdWn50bnVy4Xa48GLvQgjEJ-MF2i1txejCCw8jpQSZqHLx_PvKT69cw9UkcEzktnd-uT7BruxwIl6mcWdc0oeOjt25zg0IxB62WVVcNHQi_PSC4_kM_cvIx6749xXi_6hyui-2L5ZNQmcd8-7-y_0gaQTaijKThaSg0QtGkWv1lFtBjxxe2_mcANoTlnJPsHOvriL_brQeBfNf0WXwRgUzfUF62hrYCw7OOqH_rbQNBJbHgyyTMhxVtxc-DoGqw9QIVIwZZC-XEl_8vk0D7r-QCW1Desu8eyXl6tDy6kfP-UkuvZv4kZT8cbihvUXmAghgfRfUzR0OK9V1zMIfVgDYPflxtYgAT67creQ7Re3R8f68cVFGT0oJ_ZpN7rYREZ-mGghxVwmNndFboo97n2aLZbBXfqCfLPqMgaE0-nCKB-CYN-PX7Z1tJcNerMllFlpyE8UTw064GPNxAx9J_ZcRPVgAAFdHOe23ajDzaeSRMRKVITIUPugxbKPTWb55fOIwgWOS31s0w9uiGFrScu_7aDvrsI8pXFXLZhSZ2qPnARC6Cz6t3DQPLc-_0W3T5q9iy00AjgTUBSJIIL0WdoU1zoUyJnDY2JZLYYQxaFp1aI9AzMmm9c56Qb_NiBUfJfyVS3I9NaJq91x8QebR4IdO49boC5oAWIERJCkOTLxQUbKy6EXtxpgO1-zhBXXDPKyhAuSj5jnRa7wvRdbKXza6stM81md-AqEvDl6Cnj-FSXdaEo8glAF_XxdgA3UpMx1EyvkuoGcEcoyEsqxc5AdOD4R6cKEdMRl04GGSI7fJp1cuWmJLQqesAjK_VAEnYYrmoQxdZLw8BR1SM13XoWSfEq9dN_uZiwME1CwkTR6mN-WxXfeg-JYDRebAY_idA3xP6lcwFBQsIRebdcRyqgmiZCMyaRJ28ZwOUmpHaqJEiccfbBL0oqO5VFNP1bAq5nsjrvXkmB-a_jAJyAliToyuKc4i-VXMiVwp1jV_outA53A8csMgLmkYHrON3ZA79psVTdnJehE5zdAaObGZt_h4U1fXGGfdzuTIZ8Nr1UlNJVHwrC5Z23DY_Dp7JNHt9TIwktbfaQieUW5IR3-x8vczQewwU3lIu9KrSESjQZSe3Xr029LQpqSe3DuyWCWrLSEun0npCWaCiskfrT3zI31957vIbKdKFD_rfUzKs1byozDw6o0K19litvEClc2PQ8gZWW347WfHIwek-9qAMsRlreFc8n9ASWW_QQxgTRnBBeC4DkuwWmuj4Cfs6xwfu9b9T15jJNYGxIsLVer38U3AS6dEgtwCjwjZ0jfQRV2o_Lr89Qsj4E_EnIbJzZGEKBOIobO-lj72l0sFG5b5_qaMhUsndRRRQo3KoNa3jTtGsBI8EkMb58uLLlqD7sdIEuJ-a-1SQwiSyb9m5P5FIlyykGPFK5okoEOxzwIZSEgdghKXGIq8SQbgkQ83kHkocq7NxBHdX61Egr0V3uEEytgcO2chYZd-WiJWFLLm5zmTeLQfUl7G5CJZwhFGRjpGpYbYGcMkRCEgATzT4jcwzH7KYBMCIXi1bskCDctAy2as0jQnc5ICFzWl76doHdMVJZSvFzFY29_vP8IuVRHSW3hCtODDxLhnvDXMPGt6dOjHN-dq3_NB9mfvHKkOEK10JDpRnvz0k6gstUZDHs28a_BEH8RTb0pXh1rcO35elGh4yDNNKUk26xXKabN3OZMVmsZxxqL_JqptdmC9cNwg7XZ-S1Ey4-6acvec5J4R6GjTcPZWluZLERc2tTSeOtQoJbCJD1shS2NvR60jahncVhdp0ynV1-ZX8oAsMxKFKiB0ZtxdVNLlk4FM2nDzwlHkjbJNlz6xXuR8M74qcWVsgEzEBWyL0INt-KlkSSTIW_JPPnULrxNfDTu20ZQScBx55So1xEURFaCHjUf5P8MV5vr4paC7h0UXlWlj2LD_j9h0T3FYugMqTZuJ_NfPpmY0DpebI-_DY_cbNz6DZEIyicaqZ6MdFZlUz4Q1bpCI6773qdFLUdKS436u4jQcQjlpSbaA0sHl-7Mmr4UWKtEIZv69KCi0XQPqCOsMSYhnteyv7rrH8tL5zNqCIkUW_hKmle5Vblbafbg8wVhaObzO4nZKks-se9yVoMZnYzykm6A9C79qdWg3bRPQ8t7nWcwo42fB6kJ_K4OiMlPklzpWmAkDbTjUeFnqdUV5XhKdZPRWfHABG1jye0AZ9TZR8cS_lutJQGx6NzNzJ2h7qaeWM97ahd1rbGqeYhC3V3El75LYabMagyR5FqKaPXAPvTXdiulOFSb5QjjtOpxjBZQKC4kH_Z_jTmFCqjZ9KHB9FIdkVqqPSZV9eWPHdh4GB1RlfnJoO1qBGXEJfsTrI4BvIGn4FFudiZmQNar57xgkDx2CL3hejyIWssU6MkmvtLqwcha7NgSa9Li6zQHd2pBrfyKUtvE17_aEL9vys-2U8o4KqKph6vSzTprKRShTAmk7hUY8Hn2I2N1frQzOO6sD8NUcGqGlLMh4rjaKQXdideiNkn74J6Wdo2-hlie99H9qpbz26SCsSE0Ucn_HTvynOg3O4HGB4uMhz-CQHsdLh-9aZjw-xLtmbfLDdUEQC8U83rsX9JysbyySFP0bZA5kUTbhN1En5_-E8sXUburEg-nAshSW6WvSvM0ZRVsA0SoaDKIR0Wq8X8hXhK9tpx6rOMmXlcLFwNefRgNvoR7aoM7sRFeBT2QL3yjuHnOV1cZ-li3Fgfb8chV5CCsqAXucplybckQ1SmtDmiGxG9u6M77ODMpU_Cgn_bwtrDwwFci1dFyBPaBhQDx08jIb5tRUoAv0oLbTbl3CTemYSjNQaqWtX_wiDjH4uW1oU89m3CE=', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc', + signature='gAAAAABoxC0Pe79v2UqAMj3Y1BkJi0m_G8llzMHMeav3XGlfPIsphSfHvJVzbyv5s7pvfPLs2-ECy9vhTMaN1UfI_PYmoJ17y_k_lLjvC6sK7SdFeCmdGNjbrgIcah2DJecVqDdoT8P0Aaz6COw982zu34UyGL59e5FTol9mAGvtInH9vXmmQUnGS5fGktT90wC6-MrIxBc3Og92F-e5ciGk0DAVMC90pDTyP4z_Qkj8Jv1QYKqCv4GwFO8LyUicPTbML6l39jyTfH8L86uDWMMxKNsvHEIrqgTQnsInlwnHYVbPURb93_gMtcjOpZwc2ESnjqUtMLXzs8XaKxhU2NVBAzcXL5x2kg7OI7HbS4Vl90Hx5cVwp3i8OTfpw8aRhDoxZJWptxNBKwDDEtjqLbylKQ7m2uJ8_TkK030O0fb81_W1-36qeRn-yNE5jjkKTezyHP0DlpKjCzoY3pZ0GtIj0FRDJOJJOmbHXjC8HfrwBz76tIA64sOz8P5lS1parnESooZidtVudhrYPl5hgZ25w_X5JCOXhXBUGHFaCkiEYUZTydLK9i5W2nfmriUt5wxzG4rSHSq7B2zqLi1GdKg1So2VHEPRfL2GvDVQiRM3K5TPyrjVgoxM8rhmQp65uQ9pM_qHhzWAAr5BvMFVax32yI-gtTzOn8_gC89MleQkHueUbdLxiUDjesO8yIIc2rbzg-KatRma92xVYOS_P9uxzVR8ZI2VuhRfdlrHbvvLC7Crp-Vq-vO3XyNooIl8N6USQbSSCG4m1mt2yqcaUyUZBLPLLi2_mE0g5pF2sm3PRCEYiWtT26go3tZt8_HLF9exTvjOMny_CKAL7Mx2evk40fqbrVY8su1uhqK6AP9XxfkoyZoYWlBkQ3vVSUuFC6lNc2ACGfUFSNqJtE9XKZnwkB3gzw7N5zqFStYvCAjhqqoxFh4peSUf4oEdDEncLFQbct-TFezeTpxEe7wSSMYm9d-YpV48Ne_T_aUMrFevTEnB3x2oqY6M-tokB2mOOjCVJv_QUbDbjigVmBpuOmW_NTTQmVxRIO7_c90ywoMs3KmVmJXgV3Oec7Rp0tC4DjxM3-MznjZ3ctAuO25oxRBlFE5kABPTAZHPwX2nr9HNbH1SyE4GfmzHFzs4qkFNWXMlLcsgrHQ6HsyHoa00_eA40Uy4UucVzS8pDHF3Nt4yy1pDWyRGIkIyp-ptbkSac4Ceq8Gd1CVak6X-xpqe4kdk9Db1BjyBGLo9BMBbAwT54KMwEUrmqRFjTBl4Lqp6AMtoRRDbxAWzKI4X0al1g64B9S2FFKNGm4zs0bDitII2LyON7BZe7x5Bm_agD1SbkdHbmpOtxY10eFPdtShwYPYKr3jGUOILARRxYCICiVRPRKaNvoozEqy0mQVyGREv0byUp3r5YarGhretLddtfZIqFPYcdJhoB2ar25710xMSdnmGGKze-yjxFq-DVKPN-ihWtqpdFaJG93FVAO56v_jURwNM3zIBkTjEDDU80wo6hOiCrm3vjmDN0RzdsXo17WTs_QrD80ZDMI3S5UBqgJqE1Rk8FE2FBZvgQOk9kqWwhVt2XeK7KsOO9uHEMdFthxUTzMWdmbByQBPUeHI-dJHKkbl8kDOc7ljnN80U-eI4vr66kBkg-evTcOLZILsJ0-7IXaTDCiszLae_EbdYeXEIRriHsp63skqod8golNLWT56DkZLyNt5lu8ZE8Bp4QdkSL3rcNv1GQg-sT3DI_bOyQuHZ3zP5-OeEFdrI1n13KrnuaecyDa-lYU23BlGuMBDC3Q6bld3FPcHswew-H0sYgJwry4lhi1qMCRSzQVKvfUc2V658fOqpJO_85ssiSfzkMzNnrE0G1uRPH5_LUA1bAfmoLU5SkbkajMi35nZJzLTg79rVXpUtK8l2xJAKRnobSVKzPD1HT-b1x68vDHp1jFzeGPaM9z7wAC4iwXJLFDJhI_U_uoomw1d5lb47WHuAjpj0Q8Psgk6IMKntdWb0g61GcLZ9OoRyKDkjxar6KtEIZ1cyYVxUGTHTSKKWyrKvhWM9koj8EXkMeKtX3KFleH9AtGBFhExeSPTSJcmnv6t1ZVGSclQxVELOZh-RusLdy-wL06mT-eiBeHGw1H-0S5My-Py2AowI3aBk8YyDPGVH1pCnVfXTIOdQH6idOAsF6SmQahhjxr2KvKPr5Xf3zRAMrlTw6-50HgiEBibhSSWr0fxtZ77dIlesxym_eTfS2V1VHv58Rb3NjFIpL2ayLI6AKAnq29U7RDPXgLjWF4WoNxGkmo6Cc7dWIOsekjQuAQUtJaSSObwP_2HaMwfg5QPdFgt8KkkqOGsDEhXd2Si5ikvN2OFA_dUigfQ8aevQHqv-V7n4nFG8XGWkgfSdYJWMt7Y0SxuBJz7nlsnnggqjRrEI1C5Ae_HjlXKtH9WdYygzOtFGR_iVm--LWQE48-EIeym8g5Q6jwqAbnARFiCcfHyvU2omiGdiN8G9FIVRetDqWUDmdnza2GbJJ0JvoT2O8KPVkXZt8_qWJvTFuJ4Cqkwr-n3aa4BOQQtkB1lELR5rXed2RMNbReXmalMujHSVozgilhQauc6D89CY98ks4Yce32HbUOF753_eMD__ewBxA9DK31i50MrKQVID7UvKot3BsOK4JH2ExIg9CCx-mAbEL6HatGwoiE3zhX0RCO2OHYf66jrbKJ220wTH2O6_BCkihzNKLqTVmpYpPSprwPkkMBNfQTgtEJPJWp9hPoXux4g4z0EtYymZpC4sRVxpBH5mvno2D9i09fh9LM4QT6cf1Plh-6Q3HCupQpiq65g9CmAtJDEiSoIhrxYRkuza65jjabRvkudS8rP4Wm5Qn5ZYlykXUIzC1BVSIvjZPK2OLw_vLG1_iTbsBONDeb9AqQaXiAc4oHqUDSp3RJXvjRfQFNI48eVtk_LLkDd1WNuwQtzAjLAg9UZA6JZGLn66SpFpU_F_bwfHvNWrQ88ZieRDdQcbyCDYNJuqMMq5YOZBpz-Oa0Lun5L8hhUGB_B5FTUQPiiLVIKuHPJP0qLgC2o_R3u9VNfgwnMENnP6pmmVI2mPMFJSHEuDeShRshUSzZ4JOs9fnvpKT3TlyXFOeAtcn89Gilua2ziEfBy78d4Quuik1aL1wQtnr3PBTbn2Z0JGOPZoKybk9CF1a-1K0hoEK54-jRgTrPGseSMibhGO9x-5bW5viQVORDH1L9g2kcfJur1D-04cDlzkAB6hfjuqk1pvT3S3O2UGU37CZcVF_iolUucC8snhW5uhuvSdoBXXcnF7TuwsgAKNvztnf7B3tPJTW8x5Q5PGqHmRsoilCFlbslJCGq4h6NraPfKGY0Qq48A_i9QQGOihf1BI3OJE5usPGaxe6yJTpGQt5xCNuMCI920xIfCuQUx5BmVDAjho7EPkcDHoUWF53iZHPp7RSlC0uVABjJaaOREGT3oludmKOYY4PoZGMFNU_4Qm2UlT_OQ3XXhon0dcjT9j7OffzgjOiYy1HUMGpSyFdvIotQQSfAzNirsXZtZX7sVKXDPtOwzALnhd27odnEnYHpep03mmDI58plDhffF_rnw326mggOpYGBEgFNdtQCwoOe9P73E3762lRYHl6IOidAG6oaIP8sr3TU5xXhzJ7iqSKQbD4UMwolnNjUjVCwGMsLj137JYfUgQBmiu-5HuRuyD3jcRmddrWnofPg_uv_99W9i0tLvW9pAk5YDDUm6fFruGbYGXUa85g7iYuB6cY3lArHpPvBhpgFuH8FEexXhtJVRAFsT-Z7nvI5Hfh-Dk2M-Dv7ITg7er2mCwxG0ZmPMSx2kglqF8bZTxk7EqfGVQMvtgQMZTDij5dCIK3PzpoLqwNMd44fViVc4VXNR6o_gFx-XyKY6PVCN-OtGVQB2B6f6LikWyIMaIB5Jic7zT0lMsf8n9aSgi1UQdiR9RuizqInhxoW3IcdPpbHzyYKMyfsgE-VKX15pPOiL3stMrq7gSmX4itErJBKq2yocNH4QHjoqFsndWK3VNc6rzkdcZZqhu_ZN3xW31q57PzZbNMfQ_IUCuNPwcTCHnBiQVRZQaaiXvyVBh2NcBXLEdqr3Xuh8Q2BgCo9ZiW6fdqXOgSAd5gwxGOeQ_Cr-HLQMhB8bFE2szFWttri01hxyXOnpPt6ziDw_t4bGYB9WqaEMjCe_3iUgLjniX9hwPuQVhTDHvwkTaddSQ-SVE4JJJ5-IY7_0MAy7_swITfNP_7Wd_-XrdJ-PzUgKdKs8E7QSd2hpK6Vv7SGlsEHzPxljtHLsvEOGeTxkuBhc4KktOI3ezaooG0IgpQr7d7-viS2PF2Ri6-zkoXH3fosjCc_d5DtOvbPn_hE1Pnu-rCWnilbekyGhOquEAYsErlioLhpSaP15wkFzcZIMlV1aEPlrM6WzcCJX8cdeV0Z7fL1v7R11Jhux8h7bpW5Dm5mWtwpfg23XtywAcSXB8F1GuSZXJ4CZHq6vj6lAUqS0YigZBzMZe7UdOZUIK0VFTY1Kl50eI9Sptiy5AEPhDdaUT1daa-_g4BqJtelvtpF7XvIpPvEtlrLJBjimxCJU28-QUJDaBeKa9rtQTWf-4kyY05ITG9ke7qUnC9Sc_LDkeCEnDNjzStbf2B-r-ov9f2pUTJXDKkP4TwwiZ-AlDGHoKExZLJQYsek_DHS8rzwbRsjuhnU-toirFjZ1nH83XcYh6OKaE-7EsoUXWs5z16ntWeNJpEifCh5JNZJ_XC7BeKiL2uldqu4naYwBnwrrz7v2UAxOv2KusUwC5WHjkueRjgQtgS15Uf3khMDZYxMIKJeU_27POO84uQXsAVdPs_L4yL36hqVdT69WNfJzPuKsFiGkheoxC8SdGCaeUgpPZ24KZgDE6TLVaYin1xRBm3h-HxpAo86vjvM5LnpuVAy_0iJa4r5ozxhfjzJ7fPjQSk835tjZ8hls4yftUJNpOJM0cruJT25qsQS-RD36X4EF0BSPEdFJdN-z_CQK3LfAKcNSvO8UR7T_FEFzpH58qS98DR83avQuNx54lQ5h9ICIi3fxSHs1eO7c5m7jaCV8VHL6Mjkniqf_ZW0123BZxC2AeGcucAD9iPYeXFI5ob65AcL6TA3k1J8gOX58RIdIdzW9mkwMjJNMNEWYpEbsevRuQ_APKGJVyu014wYGeueKk9jQjgt8YQyLC7bT7eQKNrhWrT4Xfib6neWmhV9NRXVB8o434srI7Cw2sJaWSbJGAKgov2m-fvSEq2zqbNKQNqguIqsw-QvubN5u5c00PUldQs0zISnVthXAWJKlmuNxVykdN5HoDkKfAthnQv2pVc4mZK34DfcEo3Xc-1Ssysg4qOzHR4zTCY1GFX9FVKvO3C_CHI27gi_3pFjq3CcgV2_LZ3_p0g9IlCy2-6WKcRzBf_8jbuLb2kw4zGK_cG06YeeAzzMqPrtmx1tEshJF0sKAWWBzYYc2RE1Sn_QOP6YSxei2TKvB3k8Xvnp7TK-28hcJIDnZIbbU_4TkuoXz_MwbNEcE2q6YMxC86WT0qc7YXxAY3Gp0sNOypZ7QDxz8kBrzo3px5j81zDq1kxF-ZEIclPuFCXJ9s4NPaXrkjFmWnTvPmVc9F2u0JmkNgl71WaC7pRar3QpD_kbEJp-zcOFzyUnteiJKnQdbTdxZal7OT2GyfNDWpfJ3wmRZHjgAihyhDeGR7bPC95eMwEfp7ggXQrCrfLuFwMtkFPq539rnmbQ2D1GoW6f4RMtkF5p9UyihUaAjP4LC69e9dH4A5InMJmDpPfExf-_PEoiSgVTXWC58pb4DXm5QcvZj-4c-NDnlbWb_YbU-skdRq6ReAjIjWMNdRUoaU3b3EpWLTqVCsN2ZZNmqp7is5oGJG8Xyswb6VlGQq4ij5ZgGRE1YVVzMnoBVObpw2lxeDPldsK6ZbmzLq2cG4glgKPi13X5ZlQGb7eVdAgp9LZehOm8kOTljE5sLGmYJJpkmKE6hiddQeG7wxRSqcEoIctTRfMruXQL4gsPXgtpaYsTR6vi_MVrFSobxf_8DmhAkbUHNcyj6H1HVm4JRA0isGBoicUxzhybBn0heWjprPfnOD9eO_YpuUXxBrlC63LBKLQmsVkqkNI2mfTSKxVnx_f1QeuhJw4Rrp7iVyvCCE83XEr2uujo9uxm62zHvu6FHlJBSpdeX11DGUkXLScUtkFaCgHw8dcBsnG7jloDKJFOOs3i-cxOe-dWqlaVti5_sUmCLxNFIBk2TjZP44qQ7pQMT-Wp7b0o28IHGkaiIebz20xiWNOSYstZwq1xYIwhnQtCnAibqxE5kc6gtZbuF06NqD1h9fROgp9jdqGyucjHXs0zlkO1sBGgkz-8VnkF97h3rtdkqWSTZweI28dYQ0GYXagSSIgXmQp0QM7pzDp_JO85NYpR3CZW29aB6gdzuSbDoFciWd2UTsQX3HTEIsGxhtRtMa4ZPHyS5tHAKSlquhLOTHMTQfi8GO_VHsj241Hk3S56jM9Czovx-5OwRB8qKFNiHwKOvliSJR1HgXBkAleRIALJ64fDz5cUgy6Mn13Loue3JcowCAIgkrnusjVLig-y95xVvbs1Ys1rUFFKy3mmVaVyYd4Qe-WBLG-pZXug1z8gLTEZkY636ssMr_wIl2Zl-ciykcbiH6S9yTY358VqZgzQBS-44sQTdT_qelrVSNMLKneMs06JSjhSJOpmogW1I_hdHMtxkkSOQxKINvyEHPFbIkUR734qjhDVUPweD3IUQdMJ995R89D5cl94H0REAU_wJxDSGwGlux1P9ul1FHsX9hGTiNU6cE_qAD8fWX5ceOBa2iCoNefiQw1Ft9xh6QYDe2lOPdpIeihKm2ABWMVJ3hGCYwg-QPhj6yrSbZ4DSxCMPfC3NQ0Zarj5VgvfHOIO_gGiE9plkknoLBM_j1VSP7prfUOXQsA4sSu8eYhkreMkSVRk2JJ4JY2u1s9zATCq4cTUcKwdhgasU-mzPJRc0PF_7JsrojJ-GphyN_vGSzv_kBtl1Oo7IIHNo4UYiMpioxeBd3UV44oL8wOgImfs3a1Fnb-fHOS0RHkn1P57V-QGQcbQOoXtSqcDLjCJEJ144_QQa9jSCRUYXVv5VEYGfEcpaeyP62FFvLkeNfonGiObjVxXM2mnqV9gXm8Tf_NE7HgbthKKN9zbfOSyHos03LDBIYqScCnENopFX6XyY_iHOZwtfRojYmlZcfbtM7AA5K47Ycx1hC7A3U3x9CjHjhLZhqcQXdFeMNyfbEMabj4ESo0vqfKOFhif_U49MwLg9Q7cquuJ7zoduXmiBrlm2hPgzzpEK_JBC9vmc3FrxbBV4fZKr2EXYevtvSrWJ2-trlF5u9WO2xC6oxCuTUVisluvCWwhy0de3tulbLHlKV8xYEh_MvJy8tyqeOS4Y5lLtTtwuA4rTVNrYp4-otD6ZPQolK9k1vGCQtuTbgUR0Ya2m7vMDd10zU79haM0C6y723o3meJ6Yf2tIqffTk6YRpDw4yFiM0xKRP1NvkMT8T-3ptVnIBz4laUp_HDoTT1EQsmKYFtgMMaqTRImxH75v7FW0MGXT1578lBSB-PW_3U4zR8NpxvuBfLrzHcWOQv1bJ5m-v3ho91V0wXM9X4qEiA0CbGw3UdrrZ80VSeEa_wU6mQFG5IUB85_AaMkKjZsqoO7rZ4T_GAn3uqVmObN59eCgERccyBogj3s3oHk8yEXIhtzIC4wwNbiNhPBVako-_6YJOU5FnYu7VXVAWBNZsTMi9XuZY9oXTQLoU8Ya_Ix8baVrArLSAEDUih5mZvtgEzn9rBRJEarsCi5VMojQk5vzDpKjz21R7sNYTaiNikeM7AKRTtEa-N7FtdO432Gf4y4BYTctIi6ftUPj5mRbDm-ul19u89mnGx6VA4h4GZ0oWRtCP72svGw7zV_I301Qcl1m9TxFRCZvqDEvbU_GaRlL1VzR_QUOixSfCMrlovCtycE_zXE_oyMSjPXzA17wklLjG-gEFT0FUcvlohTKLlQKAUOvkalRMsao_DoGOYRfd6e8LtuKfaRnat9iq2RJ8OfbZw4kLmT73kaszYaFDPufKFvXt0nIxi_ysbX28Y5zZq6KHKwLmcceFqwwmZV2ayAvYjBZqBYpPLTfvEUd0-3n00bXi0hLP8Il8D1F_2ZcrQcHyc2g-g1Z-rxl_XaFnipOWuqRxq3ocMZLZ4YpUmMMA89icLRAoU9mG24RHcMrzkPD9IGUZv3SJVdKwcbmQCD3cBZBb4PEFenDnLbx51GodWRuXniQ0bl4cTlKbTkTJfAe3MpOuUDkcM0FXfnLdq86Hye5N-ygCdFfGozi_EjxF1kNQ6ItrNb_0i9eBhMTgCFHGCVBGWamswc6tICnbQRCDnUXVnvr5qqjno4w3hlXSmlE5w6j5yv7CskyIj8-rsbKW3zZTLMDHIyRqL4xtEqcJSlk-86nfCQj9QVXB4O3W_HLuyWo5cWoTHPwKlArTHx8Ml4Vub7qsgFvEnFzGLwd9QAWnaqD7ENALvims52mSBivuiMMR90nh-jsjbOq6GhckHhWRrtDlfLNcaTVJz-a-s7Zt2Hw-afODG7EemMCtGVRDDZn1Eo0katat1aXH7GU2LCfh-FP80eajowVmMYb5lRHWavhRwpSGTBOsmRECrJHym4ImOGcnxX6VE3Dczh-WNYYjEa0Q4OY1y-S21xExqdgx3SkaOc5G4KGuKdPCh6FAqg4P8Is0QAYnwnjbZZ5mQHfy-oUg1tzbO7yPkY_LNV22NlVqkUfVa1cMMhOzGqTOODaw5ECto3kW1LrIhVieIvKDUnztMMVj6jU8jjZ-mbaOc_Db0JLD4pgEtSmWybS9TqiGk6dcJGXOjDFi3PjwDCSKgwND_0xpTE0QJnumUhlflz6R1sFsE5Nc8rV0QglWQQyseJm-h-taauAkIBzyH3C0595Jkm5LBlM7V-bxtDeFjx-LFqB1rslSSW0dhPxrO6JAB4W6wtyL32UIRTGNOrgh26yboEvUSSZjJBeAO8Tiv3BCKTep1i1d-V291rJjb7sj2o_8XWaNm4tpl04vVY49WttNCxHJ5fM1PuVzbRSoOEF2btxCklDFhp5t8u1Y9mVnJpNMmn5AiCXZZSoyPqrv_j78QUZZXj-x5xwVft5363F1LjjoZ5s3LdEoGbsMAUiwkm7Z7aSr8gmV3uzrv8WyjiJjlc-rpPTE0RHbK_Hc5L9x1HYTJXECSdwZ8Q38yg6uc5EpTut5WPyScHFiDy1ybxnBPPx0tWas7jVULTZaeoGbnkUFo6xTJLMd9Tzzl2IM2zpgL5ZP5c79zxJvUtxgVFwTVmqMQQESj-qXikjBmaXgMLUb4Kv4n9655bgjr3ZuF_rxDagbRdt-_2pgf6VqsHEsaZJHwIpxh01vmyp6ZcQxzSUmi-8faZ_RWCJ5iTpHrMAHvrlPzrerOYBG-RGl2pxJDCVYr_WyUjKbPDxWkjKopcXx0DrYu1C6Cz1-gtGCT18LqoW73MCtdcrwKUXAmLdGUPFG5UFq2vuqItkeXcB1AA2hUhO1rzWYqHnqy2fXm4xtBgXMHVK8dqiXCmWWJ81sezBMVYDUP4MvpPkHRFSLdmG3YrZr0IwT9RzyyDfGItqWheKUJ7fkv0koRczg1J92z4BbyVBzdnEQX4edyyKCYd96ruWi-lEILIFHCY-viwPOIP3wCifcKgMCNGOzaTX3raFo2_VcNfvDSC8cLQq9X0o79qCE1Jeog6jSHUrKYhGsjn8mAJcdf7VzAjNsMpXypG57SMUBz4rd5QGvw3uGTs6M_p4BhciR8o1yOlqCjgRYyxUbCukRH-Od8QDHjRogTAeMjwL_fxEOIKf0pXWw_L3SeEddEfBDGaSU0CWPtCiEpUdu8pXQ-PEPvUFljROnxSr4Q4NQAro_b0FL2Lfk7rSLVJ-mlV8HpUwggz2VC0jjriGZDTCQmLCGFtyYA4qMeL0nJyUD0gfujHGMrqjnBP_TmwUr2qHn6y0jVreD7SpX8ojSYWeO0ebFHyBu6LAJy9VLS7d9Gu5tZ9EVVDCd7MfbDozD1UTevnfxnyGT2-_3xJXnJ2fIzISqkV6vYDmvXAhMHwggCBamQ5VUb5Ri-JQyAOkH-P_d5AzM4vLH3NovPaTs41-EZ9LoA_ACgTwMdXcI6yKNhvbYfHK92GWG0k_HUoZp31nOrUY4hsvoDr1VyJHeFjH2WulFKr4hTj--htE99X95MtcYL1BYJ5KZVT92oX2m2Tauayqr_VP-iYgeiC7WWoo526r5jVWXs1ZgxtzXzylpf5f5z35G4YMC37RFlzgY9kDaeLkMMqUvQo4GbEFbLQ5rF-9zMA2NYFKC-6fUh0hvN1UziR-Co6ZhXi5KP1_3aw2sjSiEwlF3umF4zZcIKjKWtAHrFblBLnUyp79qId8ibcUQm4EHQ92CnkKtAf_e-OB-eZA9Vz8NGagOAFdyAtOFZ17MBcv049eh2izFmxKl4FctOKAEIU1HVWv8IWqmlDyQvsUlwImE-0YFl2EHPizSCLgHM2FgRe1a_k4YEJnQxONr2GUIGL2x8mDl7aBejUmYkkyrCj4Y5XDS1RO_hrmhDB9rAJtukT1PozIgqJTGNHyH_99wqT3cfG37PPWiSuGOG1Rbujp_by2zqGmJx1PjvoRSX7YO_s_apGzAARHZL9n-xFsoXqiJkqM242r7SHsMrqkYckG5IyxjTrpqDWdOSe4xxTc9snA6Bk5EjQ6kb0_VVG20g6kKua9Qy1n-6Jj3BMOaBHcrP4hKKStHySqqLCPOOrqn9hH2s0YKsxknqCVcR6kkCbLi2xD7dpBXmmc-X5MvuK9g9kGBWjfjQSPEfCnhD7b8cDbvWAKJh9vmdR9ofySSWMWQUjRJA43dOTlUpuskklOImDZqitGamjZTfLK4L-gE3wDkavF___kozI04zsB7xOFdPcyL76sUumoAQ_gHA0he0YE0gamTjbJEk6p6NnzuK7PisLkvNS3ZdKqTZ_msTrRSV0IUyypI1qMB-RZDgjWgdccbBTxa9xeoLTLZM8OIEmhsubQF_danFfla5dm8aDiU6k7QpiutDFosvkIJlt5sBbr5Qhwbp-DWyDaX1TI8cCqlDoplTZiZrzf-n65eZMKAcNL3xp0bMYWslR10All84u6IlOqbiiMqIsCFQS4A-Ff3uftu6JqNl8tC_J7H2F0D2W1rDUVYavmTevdbk3MfH6vEClLwnLsB2wQlripHxv77bwlwK5g-4LWHu5N6shsdVMsk7RwdaozdpDB23r4FAok05qbNgHhgpOgu-1MnRK9res5CoVia32tb846NNom_CRss0fLhnAqeU1A8hSZPwsDChHiz8fYCVLpVkCfEX-hgaloQ07R4QyTBXY9puuuJOuOCzhe1IANS4bS1EdGOSWBiDW_Df3q5ky5LOXCOfJjZBvAEkpnX3KJyxdE8K05P3Sj9akt0eG2buFfBLL3rEqBAvOjSWA8FkSF6b8NlLx53itZnn9yiEyL847Z6WGg-Wjs1y-hWSzBh587FAB2z8nTrIAYOQkW0dWJW9Grerc2NraD-hmK4AzTK9f8dCwWSfmc5TB24s6qNRU8Dk4hZ04wAuSQLximtJh3Gv58EABNSSZO6SS8S3SvTR3rRGRYe0Op5EnjoLvT4ZSkLaRFQxld15H3vq66hs9PZo3F3ZxNBO_oDulDXYVvOfeP-16sMfE744LGlucoZBvfeEtjE6Lqabl5jbgByNm08nluPSNGAVOQgExxHcAlL2H29yvMpo78qeqLlkOw3iHi1rEleBFQxcTOE2Ql0vh7gSjgZba0WoI2rl2nD5Bbc5rlTkSa_0-SoDl_aWnpSHLSXHr9y8S1Ryphc6-Tz5uy9lCrplcuHoiF7WUCChE4gv65yf1i0VTw0QjsnwPdnq5Z_EXAou2jLuXaWwNfhIPyyl69n2zEKrKDpDIxS44J4IB5zCA_DFrO1gcI71ibRrcPQiY7Y-H7ejlrGv1TfE1FwZwvphixyc5cVoUJYDZ3pljYH_vIjKAAWr-FC5rNeJDCkXdBwGzrB_fjvju9lNu0bH8xXbQ5xB4vGoorscYBverGCtbbgPof05Ga6uVo_W3_6EJQbJg71kriFa_6haOFWz9Q4sAAOYW1aA1mrEDJY40nG59r2VdQ7EU0X_5mqkwoQGcWddMWgZDFPIITpWOo672O9Egh8luGo8EP9zhRtFIGn2vC494VBDUyVGrKMJLLI1lpoUgGfsndA9JfVJH5J9BaKRqD-GcZh2Fojj05eyJS1Bj62AoqB15nSx1X5ouHF_SkkRBZUPYQqByCrtvcrQxA32PeFZXzc1YVltoLa75LmnhBU4PBA4-KZOaGjL1EYUSU5VcZkLdQVyEXXT7NZDZ9ZchBp5IZEMLkLDNSeguPTpJyTdodbbye-QZdGzHVG9yVH3bqTB_KsEqIaJ30sjX_zi6boK6ZC7ZeGI59ChA_W7jVIT4kHWWPp4WVVlecuKDzePIhc5vr3wUlXotk95470wDp3Jw81QNNu_jRgxJ0dWcIl0Ew41OV8YomZsud_VkXBTn-68KwYcBq-rYGwVFktGpVIOvoIspZvch8d6UhSVG9LcPjN1_TD1GAJ5EQtwSoVak2I9X3zHl0bVeyJ8qrcOQcLc-4ss_YUfY3sOxrv3WO3livMq2e40ec6osSm3EfhR6RKEgOAwnU_VBkS9remIUxsTftJ2ZefPU0ql_HnT7NmiYjO1s38dQbBI68scRYZtzlJ1Yh3uKqww8CG4Sr3s7hkXDl8yEHfQdSza_YSphJWn9TBflKcBa_t05qW2eTtgri54pqNvcDE1V6sJQqucT2xQAodfMaydGk-m2XPCTuAJ3kCgCpJdzH2Ar1eBv-7XLywrFGo9ayBY1cQBOT96XY0txWY3Ju5BPwU1JlRxgitQI8kGND3b3HTDGn-U__abQUMkyL18FPXkEsD5ZnRRvhTeQjeNpjM0TO6uPvk1Xxmnr6_8sR2s0bJKhuHxC47SIospvgW7Fl9BqlCaU1UoQIuP0c1rN1IfKk0OIsAZSMDvSLCze33-8vFyCes1hHSc0MI1zU2CR3cRt9-3TE08lQw6SsUAIM2SSvfsHBXP2Ib7AnoRby4HTrRKngGPXsNIRtMzthrGT1gj1Ey9Ka33YcEz3j1PGK5mJllRi7nrCWDJQt1C9kLcp3qPwWnkq5J3b6VSgLwvdrMSEPKrIJGhB8kugfey0fJduu5-Puw3dH6DvV3sQo7WKdim3JUz611z_oiwL_UzeL48yaDoBQbfe3LH8S6pWoXeCU-Pr2KASZGM8cZlkVKnJWTKa8ne9LdBuRiDpVwVePQ5cDmUn88SYs1KEEqguwB7te3xJ_3HxuPRHqy7gTs70trvBGl8zqVNJsnmKpS3V_E1UtMGLYQ8MFApSA3b6YcJP4j4E6aCD5lakVLGSnMoq3PUof7Kc92NZSWzNq7YfCoAzL1BJoz47MdWn50bnVy4Xa48GLvQgjEJ-MF2i1txejCCw8jpQSZqHLx_PvKT69cw9UkcEzktnd-uT7BruxwIl6mcWdc0oeOjt25zg0IxB62WVVcNHQi_PSC4_kM_cvIx6749xXi_6hyui-2L5ZNQmcd8-7-y_0gaQTaijKThaSg0QtGkWv1lFtBjxxe2_mcANoTlnJPsHOvriL_brQeBfNf0WXwRgUzfUF62hrYCw7OOqH_rbQNBJbHgyyTMhxVtxc-DoGqw9QIVIwZZC-XEl_8vk0D7r-QCW1Desu8eyXl6tDy6kfP-UkuvZv4kZT8cbihvUXmAghgfRfUzR0OK9V1zMIfVgDYPflxtYgAT67creQ7Re3R8f68cVFGT0oJ_ZpN7rYREZ-mGghxVwmNndFboo97n2aLZbBXfqCfLPqMgaE0-nCKB-CYN-PX7Z1tJcNerMllFlpyE8UTw064GPNxAx9J_ZcRPVgAAFdHOe23ajDzaeSRMRKVITIUPugxbKPTWb55fOIwgWOS31s0w9uiGFrScu_7aDvrsI8pXFXLZhSZ2qPnARC6Cz6t3DQPLc-_0W3T5q9iy00AjgTUBSJIIL0WdoU1zoUyJnDY2JZLYYQxaFp1aI9AzMmm9c56Qb_NiBUfJfyVS3I9NaJq91x8QebR4IdO49boC5oAWIERJCkOTLxQUbKy6EXtxpgO1-zhBXXDPKyhAuSj5jnRa7wvRdbKXza6stM81md-AqEvDl6Cnj-FSXdaEo8glAF_XxdgA3UpMx1EyvkuoGcEcoyEsqxc5AdOD4R6cKEdMRl04GGSI7fJp1cuWmJLQqesAjK_VAEnYYrmoQxdZLw8BR1SM13XoWSfEq9dN_uZiwME1CwkTR6mN-WxXfeg-JYDRebAY_idA3xP6lcwFBQsIRebdcRyqgmiZCMyaRJ28ZwOUmpHaqJEiccfbBL0oqO5VFNP1bAq5nsjrvXkmB-a_jAJyAliToyuKc4i-VXMiVwp1jV_outA53A8csMgLmkYHrON3ZA79psVTdnJehE5zdAaObGZt_h4U1fXGGfdzuTIZ8Nr1UlNJVHwrC5Z23DY_Dp7JNHt9TIwktbfaQieUW5IR3-x8vczQewwU3lIu9KrSESjQZSe3Xr029LQpqSe3DuyWCWrLSEun0npCWaCiskfrT3zI31957vIbKdKFD_rfUzKs1byozDw6o0K19litvEClc2PQ8gZWW347WfHIwek-9qAMsRlreFc8n9ASWW_QQxgTRnBBeC4DkuwWmuj4Cfs6xwfu9b9T15jJNYGxIsLVer38U3AS6dEgtwCjwjZ0jfQRV2o_Lr89Qsj4E_EnIbJzZGEKBOIobO-lj72l0sFG5b5_qaMhUsndRRRQo3KoNa3jTtGsBI8EkMb58uLLlqD7sdIEuJ-a-1SQwiSyb9m5P5FIlyykGPFK5okoEOxzwIZSEgdghKXGIq8SQbgkQ83kHkocq7NxBHdX61Egr0V3uEEytgcO2chYZd-WiJWFLLm5zmTeLQfUl7G5CJZwhFGRjpGpYbYGcMkRCEgATzT4jcwzH7KYBMCIXi1bskCDctAy2as0jQnc5ICFzWl76doHdMVJZSvFzFY29_vP8IuVRHSW3hCtODDxLhnvDXMPGt6dOjHN-dq3_NB9mfvHKkOEK10JDpRnvz0k6gstUZDHs28a_BEH8RTb0pXh1rcO35elGh4yDNNKUk26xXKabN3OZMVmsZxxqL_JqptdmC9cNwg7XZ-S1Ey4-6acvec5J4R6GjTcPZWluZLERc2tTSeOtQoJbCJD1shS2NvR60jahncVhdp0ynV1-ZX8oAsMxKFKiB0ZtxdVNLlk4FM2nDzwlHkjbJNlz6xXuR8M74qcWVsgEzEBWyL0INt-KlkSSTIW_JPPnULrxNfDTu20ZQScBx55So1xEURFaCHjUf5P8MV5vr4paC7h0UXlWlj2LD_j9h0T3FYugMqTZuJ_NfPpmY0DpebI-_DY_cbNz6DZEIyicaqZ6MdFZlUz4Q1bpCI6773qdFLUdKS436u4jQcQjlpSbaA0sHl-7Mmr4UWKtEIZv69KCi0XQPqCOsMSYhnteyv7rrH8tL5zNqCIkUW_hKmle5Vblbafbg8wVhaObzO4nZKks-se9yVoMZnYzykm6A9C79qdWg3bRPQ8t7nWcwo42fB6kJ_K4OiMlPklzpWmAkDbTjUeFnqdUV5XhKdZPRWfHABG1jye0AZ9TZR8cS_lutJQGx6NzNzJ2h7qaeWM97ahd1rbGqeYhC3V3El75LYabMagyR5FqKaPXAPvTXdiulOFSb5QjjtOpxjBZQKC4kH_Z_jTmFCqjZ9KHB9FIdkVqqPSZV9eWPHdh4GB1RlfnJoO1qBGXEJfsTrI4BvIGn4FFudiZmQNar57xgkDx2CL3hejyIWssU6MkmvtLqwcha7NgSa9Li6zQHd2pBrfyKUtvE17_aEL9vys-2U8o4KqKph6vSzTprKRShTAmk7hUY8Hn2I2N1frQzOO6sD8NUcGqGlLMh4rjaKQXdideiNkn74J6Wdo2-hlie99H9qpbz26SCsSE0Ucn_HTvynOg3O4HGB4uMhz-CQHsdLh-9aZjw-xLtmbfLDdUEQC8U83rsX9JysbyySFP0bZA5kUTbhN1En5_-E8sXUburEg-nAshSW6WvSvM0ZRVsA0SoaDKIR0Wq8X8hXhK9tpx6rOMmXlcLFwNefRgNvoR7aoM7sRFeBT2QL3yjuHnOV1cZ-li3Fgfb8chV5CCsqAXucplybckQ1SmtDmiGxG9u6M77ODMpU_Cgn_bwtrDwwFci1dFyBPaBhQDx08jIb5tRUoAv0oLbTbl3CTemYSjNQaqWtX_wiDjH4uW1oU89m3CE=', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc', + signature='gAAAAABoxC0Pe79v2UqAMj3Y1BkJi0m_G8llzMHMeav3XGlfPIsphSfHvJVzbyv5s7pvfPLs2-ECy9vhTMaN1UfI_PYmoJ17y_k_lLjvC6sK7SdFeCmdGNjbrgIcah2DJecVqDdoT8P0Aaz6COw982zu34UyGL59e5FTol9mAGvtInH9vXmmQUnGS5fGktT90wC6-MrIxBc3Og92F-e5ciGk0DAVMC90pDTyP4z_Qkj8Jv1QYKqCv4GwFO8LyUicPTbML6l39jyTfH8L86uDWMMxKNsvHEIrqgTQnsInlwnHYVbPURb93_gMtcjOpZwc2ESnjqUtMLXzs8XaKxhU2NVBAzcXL5x2kg7OI7HbS4Vl90Hx5cVwp3i8OTfpw8aRhDoxZJWptxNBKwDDEtjqLbylKQ7m2uJ8_TkK030O0fb81_W1-36qeRn-yNE5jjkKTezyHP0DlpKjCzoY3pZ0GtIj0FRDJOJJOmbHXjC8HfrwBz76tIA64sOz8P5lS1parnESooZidtVudhrYPl5hgZ25w_X5JCOXhXBUGHFaCkiEYUZTydLK9i5W2nfmriUt5wxzG4rSHSq7B2zqLi1GdKg1So2VHEPRfL2GvDVQiRM3K5TPyrjVgoxM8rhmQp65uQ9pM_qHhzWAAr5BvMFVax32yI-gtTzOn8_gC89MleQkHueUbdLxiUDjesO8yIIc2rbzg-KatRma92xVYOS_P9uxzVR8ZI2VuhRfdlrHbvvLC7Crp-Vq-vO3XyNooIl8N6USQbSSCG4m1mt2yqcaUyUZBLPLLi2_mE0g5pF2sm3PRCEYiWtT26go3tZt8_HLF9exTvjOMny_CKAL7Mx2evk40fqbrVY8su1uhqK6AP9XxfkoyZoYWlBkQ3vVSUuFC6lNc2ACGfUFSNqJtE9XKZnwkB3gzw7N5zqFStYvCAjhqqoxFh4peSUf4oEdDEncLFQbct-TFezeTpxEe7wSSMYm9d-YpV48Ne_T_aUMrFevTEnB3x2oqY6M-tokB2mOOjCVJv_QUbDbjigVmBpuOmW_NTTQmVxRIO7_c90ywoMs3KmVmJXgV3Oec7Rp0tC4DjxM3-MznjZ3ctAuO25oxRBlFE5kABPTAZHPwX2nr9HNbH1SyE4GfmzHFzs4qkFNWXMlLcsgrHQ6HsyHoa00_eA40Uy4UucVzS8pDHF3Nt4yy1pDWyRGIkIyp-ptbkSac4Ceq8Gd1CVak6X-xpqe4kdk9Db1BjyBGLo9BMBbAwT54KMwEUrmqRFjTBl4Lqp6AMtoRRDbxAWzKI4X0al1g64B9S2FFKNGm4zs0bDitII2LyON7BZe7x5Bm_agD1SbkdHbmpOtxY10eFPdtShwYPYKr3jGUOILARRxYCICiVRPRKaNvoozEqy0mQVyGREv0byUp3r5YarGhretLddtfZIqFPYcdJhoB2ar25710xMSdnmGGKze-yjxFq-DVKPN-ihWtqpdFaJG93FVAO56v_jURwNM3zIBkTjEDDU80wo6hOiCrm3vjmDN0RzdsXo17WTs_QrD80ZDMI3S5UBqgJqE1Rk8FE2FBZvgQOk9kqWwhVt2XeK7KsOO9uHEMdFthxUTzMWdmbByQBPUeHI-dJHKkbl8kDOc7ljnN80U-eI4vr66kBkg-evTcOLZILsJ0-7IXaTDCiszLae_EbdYeXEIRriHsp63skqod8golNLWT56DkZLyNt5lu8ZE8Bp4QdkSL3rcNv1GQg-sT3DI_bOyQuHZ3zP5-OeEFdrI1n13KrnuaecyDa-lYU23BlGuMBDC3Q6bld3FPcHswew-H0sYgJwry4lhi1qMCRSzQVKvfUc2V658fOqpJO_85ssiSfzkMzNnrE0G1uRPH5_LUA1bAfmoLU5SkbkajMi35nZJzLTg79rVXpUtK8l2xJAKRnobSVKzPD1HT-b1x68vDHp1jFzeGPaM9z7wAC4iwXJLFDJhI_U_uoomw1d5lb47WHuAjpj0Q8Psgk6IMKntdWb0g61GcLZ9OoRyKDkjxar6KtEIZ1cyYVxUGTHTSKKWyrKvhWM9koj8EXkMeKtX3KFleH9AtGBFhExeSPTSJcmnv6t1ZVGSclQxVELOZh-RusLdy-wL06mT-eiBeHGw1H-0S5My-Py2AowI3aBk8YyDPGVH1pCnVfXTIOdQH6idOAsF6SmQahhjxr2KvKPr5Xf3zRAMrlTw6-50HgiEBibhSSWr0fxtZ77dIlesxym_eTfS2V1VHv58Rb3NjFIpL2ayLI6AKAnq29U7RDPXgLjWF4WoNxGkmo6Cc7dWIOsekjQuAQUtJaSSObwP_2HaMwfg5QPdFgt8KkkqOGsDEhXd2Si5ikvN2OFA_dUigfQ8aevQHqv-V7n4nFG8XGWkgfSdYJWMt7Y0SxuBJz7nlsnnggqjRrEI1C5Ae_HjlXKtH9WdYygzOtFGR_iVm--LWQE48-EIeym8g5Q6jwqAbnARFiCcfHyvU2omiGdiN8G9FIVRetDqWUDmdnza2GbJJ0JvoT2O8KPVkXZt8_qWJvTFuJ4Cqkwr-n3aa4BOQQtkB1lELR5rXed2RMNbReXmalMujHSVozgilhQauc6D89CY98ks4Yce32HbUOF753_eMD__ewBxA9DK31i50MrKQVID7UvKot3BsOK4JH2ExIg9CCx-mAbEL6HatGwoiE3zhX0RCO2OHYf66jrbKJ220wTH2O6_BCkihzNKLqTVmpYpPSprwPkkMBNfQTgtEJPJWp9hPoXux4g4z0EtYymZpC4sRVxpBH5mvno2D9i09fh9LM4QT6cf1Plh-6Q3HCupQpiq65g9CmAtJDEiSoIhrxYRkuza65jjabRvkudS8rP4Wm5Qn5ZYlykXUIzC1BVSIvjZPK2OLw_vLG1_iTbsBONDeb9AqQaXiAc4oHqUDSp3RJXvjRfQFNI48eVtk_LLkDd1WNuwQtzAjLAg9UZA6JZGLn66SpFpU_F_bwfHvNWrQ88ZieRDdQcbyCDYNJuqMMq5YOZBpz-Oa0Lun5L8hhUGB_B5FTUQPiiLVIKuHPJP0qLgC2o_R3u9VNfgwnMENnP6pmmVI2mPMFJSHEuDeShRshUSzZ4JOs9fnvpKT3TlyXFOeAtcn89Gilua2ziEfBy78d4Quuik1aL1wQtnr3PBTbn2Z0JGOPZoKybk9CF1a-1K0hoEK54-jRgTrPGseSMibhGO9x-5bW5viQVORDH1L9g2kcfJur1D-04cDlzkAB6hfjuqk1pvT3S3O2UGU37CZcVF_iolUucC8snhW5uhuvSdoBXXcnF7TuwsgAKNvztnf7B3tPJTW8x5Q5PGqHmRsoilCFlbslJCGq4h6NraPfKGY0Qq48A_i9QQGOihf1BI3OJE5usPGaxe6yJTpGQt5xCNuMCI920xIfCuQUx5BmVDAjho7EPkcDHoUWF53iZHPp7RSlC0uVABjJaaOREGT3oludmKOYY4PoZGMFNU_4Qm2UlT_OQ3XXhon0dcjT9j7OffzgjOiYy1HUMGpSyFdvIotQQSfAzNirsXZtZX7sVKXDPtOwzALnhd27odnEnYHpep03mmDI58plDhffF_rnw326mggOpYGBEgFNdtQCwoOe9P73E3762lRYHl6IOidAG6oaIP8sr3TU5xXhzJ7iqSKQbD4UMwolnNjUjVCwGMsLj137JYfUgQBmiu-5HuRuyD3jcRmddrWnofPg_uv_99W9i0tLvW9pAk5YDDUm6fFruGbYGXUa85g7iYuB6cY3lArHpPvBhpgFuH8FEexXhtJVRAFsT-Z7nvI5Hfh-Dk2M-Dv7ITg7er2mCwxG0ZmPMSx2kglqF8bZTxk7EqfGVQMvtgQMZTDij5dCIK3PzpoLqwNMd44fViVc4VXNR6o_gFx-XyKY6PVCN-OtGVQB2B6f6LikWyIMaIB5Jic7zT0lMsf8n9aSgi1UQdiR9RuizqInhxoW3IcdPpbHzyYKMyfsgE-VKX15pPOiL3stMrq7gSmX4itErJBKq2yocNH4QHjoqFsndWK3VNc6rzkdcZZqhu_ZN3xW31q57PzZbNMfQ_IUCuNPwcTCHnBiQVRZQaaiXvyVBh2NcBXLEdqr3Xuh8Q2BgCo9ZiW6fdqXOgSAd5gwxGOeQ_Cr-HLQMhB8bFE2szFWttri01hxyXOnpPt6ziDw_t4bGYB9WqaEMjCe_3iUgLjniX9hwPuQVhTDHvwkTaddSQ-SVE4JJJ5-IY7_0MAy7_swITfNP_7Wd_-XrdJ-PzUgKdKs8E7QSd2hpK6Vv7SGlsEHzPxljtHLsvEOGeTxkuBhc4KktOI3ezaooG0IgpQr7d7-viS2PF2Ri6-zkoXH3fosjCc_d5DtOvbPn_hE1Pnu-rCWnilbekyGhOquEAYsErlioLhpSaP15wkFzcZIMlV1aEPlrM6WzcCJX8cdeV0Z7fL1v7R11Jhux8h7bpW5Dm5mWtwpfg23XtywAcSXB8F1GuSZXJ4CZHq6vj6lAUqS0YigZBzMZe7UdOZUIK0VFTY1Kl50eI9Sptiy5AEPhDdaUT1daa-_g4BqJtelvtpF7XvIpPvEtlrLJBjimxCJU28-QUJDaBeKa9rtQTWf-4kyY05ITG9ke7qUnC9Sc_LDkeCEnDNjzStbf2B-r-ov9f2pUTJXDKkP4TwwiZ-AlDGHoKExZLJQYsek_DHS8rzwbRsjuhnU-toirFjZ1nH83XcYh6OKaE-7EsoUXWs5z16ntWeNJpEifCh5JNZJ_XC7BeKiL2uldqu4naYwBnwrrz7v2UAxOv2KusUwC5WHjkueRjgQtgS15Uf3khMDZYxMIKJeU_27POO84uQXsAVdPs_L4yL36hqVdT69WNfJzPuKsFiGkheoxC8SdGCaeUgpPZ24KZgDE6TLVaYin1xRBm3h-HxpAo86vjvM5LnpuVAy_0iJa4r5ozxhfjzJ7fPjQSk835tjZ8hls4yftUJNpOJM0cruJT25qsQS-RD36X4EF0BSPEdFJdN-z_CQK3LfAKcNSvO8UR7T_FEFzpH58qS98DR83avQuNx54lQ5h9ICIi3fxSHs1eO7c5m7jaCV8VHL6Mjkniqf_ZW0123BZxC2AeGcucAD9iPYeXFI5ob65AcL6TA3k1J8gOX58RIdIdzW9mkwMjJNMNEWYpEbsevRuQ_APKGJVyu014wYGeueKk9jQjgt8YQyLC7bT7eQKNrhWrT4Xfib6neWmhV9NRXVB8o434srI7Cw2sJaWSbJGAKgov2m-fvSEq2zqbNKQNqguIqsw-QvubN5u5c00PUldQs0zISnVthXAWJKlmuNxVykdN5HoDkKfAthnQv2pVc4mZK34DfcEo3Xc-1Ssysg4qOzHR4zTCY1GFX9FVKvO3C_CHI27gi_3pFjq3CcgV2_LZ3_p0g9IlCy2-6WKcRzBf_8jbuLb2kw4zGK_cG06YeeAzzMqPrtmx1tEshJF0sKAWWBzYYc2RE1Sn_QOP6YSxei2TKvB3k8Xvnp7TK-28hcJIDnZIbbU_4TkuoXz_MwbNEcE2q6YMxC86WT0qc7YXxAY3Gp0sNOypZ7QDxz8kBrzo3px5j81zDq1kxF-ZEIclPuFCXJ9s4NPaXrkjFmWnTvPmVc9F2u0JmkNgl71WaC7pRar3QpD_kbEJp-zcOFzyUnteiJKnQdbTdxZal7OT2GyfNDWpfJ3wmRZHjgAihyhDeGR7bPC95eMwEfp7ggXQrCrfLuFwMtkFPq539rnmbQ2D1GoW6f4RMtkF5p9UyihUaAjP4LC69e9dH4A5InMJmDpPfExf-_PEoiSgVTXWC58pb4DXm5QcvZj-4c-NDnlbWb_YbU-skdRq6ReAjIjWMNdRUoaU3b3EpWLTqVCsN2ZZNmqp7is5oGJG8Xyswb6VlGQq4ij5ZgGRE1YVVzMnoBVObpw2lxeDPldsK6ZbmzLq2cG4glgKPi13X5ZlQGb7eVdAgp9LZehOm8kOTljE5sLGmYJJpkmKE6hiddQeG7wxRSqcEoIctTRfMruXQL4gsPXgtpaYsTR6vi_MVrFSobxf_8DmhAkbUHNcyj6H1HVm4JRA0isGBoicUxzhybBn0heWjprPfnOD9eO_YpuUXxBrlC63LBKLQmsVkqkNI2mfTSKxVnx_f1QeuhJw4Rrp7iVyvCCE83XEr2uujo9uxm62zHvu6FHlJBSpdeX11DGUkXLScUtkFaCgHw8dcBsnG7jloDKJFOOs3i-cxOe-dWqlaVti5_sUmCLxNFIBk2TjZP44qQ7pQMT-Wp7b0o28IHGkaiIebz20xiWNOSYstZwq1xYIwhnQtCnAibqxE5kc6gtZbuF06NqD1h9fROgp9jdqGyucjHXs0zlkO1sBGgkz-8VnkF97h3rtdkqWSTZweI28dYQ0GYXagSSIgXmQp0QM7pzDp_JO85NYpR3CZW29aB6gdzuSbDoFciWd2UTsQX3HTEIsGxhtRtMa4ZPHyS5tHAKSlquhLOTHMTQfi8GO_VHsj241Hk3S56jM9Czovx-5OwRB8qKFNiHwKOvliSJR1HgXBkAleRIALJ64fDz5cUgy6Mn13Loue3JcowCAIgkrnusjVLig-y95xVvbs1Ys1rUFFKy3mmVaVyYd4Qe-WBLG-pZXug1z8gLTEZkY636ssMr_wIl2Zl-ciykcbiH6S9yTY358VqZgzQBS-44sQTdT_qelrVSNMLKneMs06JSjhSJOpmogW1I_hdHMtxkkSOQxKINvyEHPFbIkUR734qjhDVUPweD3IUQdMJ995R89D5cl94H0REAU_wJxDSGwGlux1P9ul1FHsX9hGTiNU6cE_qAD8fWX5ceOBa2iCoNefiQw1Ft9xh6QYDe2lOPdpIeihKm2ABWMVJ3hGCYwg-QPhj6yrSbZ4DSxCMPfC3NQ0Zarj5VgvfHOIO_gGiE9plkknoLBM_j1VSP7prfUOXQsA4sSu8eYhkreMkSVRk2JJ4JY2u1s9zATCq4cTUcKwdhgasU-mzPJRc0PF_7JsrojJ-GphyN_vGSzv_kBtl1Oo7IIHNo4UYiMpioxeBd3UV44oL8wOgImfs3a1Fnb-fHOS0RHkn1P57V-QGQcbQOoXtSqcDLjCJEJ144_QQa9jSCRUYXVv5VEYGfEcpaeyP62FFvLkeNfonGiObjVxXM2mnqV9gXm8Tf_NE7HgbthKKN9zbfOSyHos03LDBIYqScCnENopFX6XyY_iHOZwtfRojYmlZcfbtM7AA5K47Ycx1hC7A3U3x9CjHjhLZhqcQXdFeMNyfbEMabj4ESo0vqfKOFhif_U49MwLg9Q7cquuJ7zoduXmiBrlm2hPgzzpEK_JBC9vmc3FrxbBV4fZKr2EXYevtvSrWJ2-trlF5u9WO2xC6oxCuTUVisluvCWwhy0de3tulbLHlKV8xYEh_MvJy8tyqeOS4Y5lLtTtwuA4rTVNrYp4-otD6ZPQolK9k1vGCQtuTbgUR0Ya2m7vMDd10zU79haM0C6y723o3meJ6Yf2tIqffTk6YRpDw4yFiM0xKRP1NvkMT8T-3ptVnIBz4laUp_HDoTT1EQsmKYFtgMMaqTRImxH75v7FW0MGXT1578lBSB-PW_3U4zR8NpxvuBfLrzHcWOQv1bJ5m-v3ho91V0wXM9X4qEiA0CbGw3UdrrZ80VSeEa_wU6mQFG5IUB85_AaMkKjZsqoO7rZ4T_GAn3uqVmObN59eCgERccyBogj3s3oHk8yEXIhtzIC4wwNbiNhPBVako-_6YJOU5FnYu7VXVAWBNZsTMi9XuZY9oXTQLoU8Ya_Ix8baVrArLSAEDUih5mZvtgEzn9rBRJEarsCi5VMojQk5vzDpKjz21R7sNYTaiNikeM7AKRTtEa-N7FtdO432Gf4y4BYTctIi6ftUPj5mRbDm-ul19u89mnGx6VA4h4GZ0oWRtCP72svGw7zV_I301Qcl1m9TxFRCZvqDEvbU_GaRlL1VzR_QUOixSfCMrlovCtycE_zXE_oyMSjPXzA17wklLjG-gEFT0FUcvlohTKLlQKAUOvkalRMsao_DoGOYRfd6e8LtuKfaRnat9iq2RJ8OfbZw4kLmT73kaszYaFDPufKFvXt0nIxi_ysbX28Y5zZq6KHKwLmcceFqwwmZV2ayAvYjBZqBYpPLTfvEUd0-3n00bXi0hLP8Il8D1F_2ZcrQcHyc2g-g1Z-rxl_XaFnipOWuqRxq3ocMZLZ4YpUmMMA89icLRAoU9mG24RHcMrzkPD9IGUZv3SJVdKwcbmQCD3cBZBb4PEFenDnLbx51GodWRuXniQ0bl4cTlKbTkTJfAe3MpOuUDkcM0FXfnLdq86Hye5N-ygCdFfGozi_EjxF1kNQ6ItrNb_0i9eBhMTgCFHGCVBGWamswc6tICnbQRCDnUXVnvr5qqjno4w3hlXSmlE5w6j5yv7CskyIj8-rsbKW3zZTLMDHIyRqL4xtEqcJSlk-86nfCQj9QVXB4O3W_HLuyWo5cWoTHPwKlArTHx8Ml4Vub7qsgFvEnFzGLwd9QAWnaqD7ENALvims52mSBivuiMMR90nh-jsjbOq6GhckHhWRrtDlfLNcaTVJz-a-s7Zt2Hw-afODG7EemMCtGVRDDZn1Eo0katat1aXH7GU2LCfh-FP80eajowVmMYb5lRHWavhRwpSGTBOsmRECrJHym4ImOGcnxX6VE3Dczh-WNYYjEa0Q4OY1y-S21xExqdgx3SkaOc5G4KGuKdPCh6FAqg4P8Is0QAYnwnjbZZ5mQHfy-oUg1tzbO7yPkY_LNV22NlVqkUfVa1cMMhOzGqTOODaw5ECto3kW1LrIhVieIvKDUnztMMVj6jU8jjZ-mbaOc_Db0JLD4pgEtSmWybS9TqiGk6dcJGXOjDFi3PjwDCSKgwND_0xpTE0QJnumUhlflz6R1sFsE5Nc8rV0QglWQQyseJm-h-taauAkIBzyH3C0595Jkm5LBlM7V-bxtDeFjx-LFqB1rslSSW0dhPxrO6JAB4W6wtyL32UIRTGNOrgh26yboEvUSSZjJBeAO8Tiv3BCKTep1i1d-V291rJjb7sj2o_8XWaNm4tpl04vVY49WttNCxHJ5fM1PuVzbRSoOEF2btxCklDFhp5t8u1Y9mVnJpNMmn5AiCXZZSoyPqrv_j78QUZZXj-x5xwVft5363F1LjjoZ5s3LdEoGbsMAUiwkm7Z7aSr8gmV3uzrv8WyjiJjlc-rpPTE0RHbK_Hc5L9x1HYTJXECSdwZ8Q38yg6uc5EpTut5WPyScHFiDy1ybxnBPPx0tWas7jVULTZaeoGbnkUFo6xTJLMd9Tzzl2IM2zpgL5ZP5c79zxJvUtxgVFwTVmqMQQESj-qXikjBmaXgMLUb4Kv4n9655bgjr3ZuF_rxDagbRdt-_2pgf6VqsHEsaZJHwIpxh01vmyp6ZcQxzSUmi-8faZ_RWCJ5iTpHrMAHvrlPzrerOYBG-RGl2pxJDCVYr_WyUjKbPDxWkjKopcXx0DrYu1C6Cz1-gtGCT18LqoW73MCtdcrwKUXAmLdGUPFG5UFq2vuqItkeXcB1AA2hUhO1rzWYqHnqy2fXm4xtBgXMHVK8dqiXCmWWJ81sezBMVYDUP4MvpPkHRFSLdmG3YrZr0IwT9RzyyDfGItqWheKUJ7fkv0koRczg1J92z4BbyVBzdnEQX4edyyKCYd96ruWi-lEILIFHCY-viwPOIP3wCifcKgMCNGOzaTX3raFo2_VcNfvDSC8cLQq9X0o79qCE1Jeog6jSHUrKYhGsjn8mAJcdf7VzAjNsMpXypG57SMUBz4rd5QGvw3uGTs6M_p4BhciR8o1yOlqCjgRYyxUbCukRH-Od8QDHjRogTAeMjwL_fxEOIKf0pXWw_L3SeEddEfBDGaSU0CWPtCiEpUdu8pXQ-PEPvUFljROnxSr4Q4NQAro_b0FL2Lfk7rSLVJ-mlV8HpUwggz2VC0jjriGZDTCQmLCGFtyYA4qMeL0nJyUD0gfujHGMrqjnBP_TmwUr2qHn6y0jVreD7SpX8ojSYWeO0ebFHyBu6LAJy9VLS7d9Gu5tZ9EVVDCd7MfbDozD1UTevnfxnyGT2-_3xJXnJ2fIzISqkV6vYDmvXAhMHwggCBamQ5VUb5Ri-JQyAOkH-P_d5AzM4vLH3NovPaTs41-EZ9LoA_ACgTwMdXcI6yKNhvbYfHK92GWG0k_HUoZp31nOrUY4hsvoDr1VyJHeFjH2WulFKr4hTj--htE99X95MtcYL1BYJ5KZVT92oX2m2Tauayqr_VP-iYgeiC7WWoo526r5jVWXs1ZgxtzXzylpf5f5z35G4YMC37RFlzgY9kDaeLkMMqUvQo4GbEFbLQ5rF-9zMA2NYFKC-6fUh0hvN1UziR-Co6ZhXi5KP1_3aw2sjSiEwlF3umF4zZcIKjKWtAHrFblBLnUyp79qId8ibcUQm4EHQ92CnkKtAf_e-OB-eZA9Vz8NGagOAFdyAtOFZ17MBcv049eh2izFmxKl4FctOKAEIU1HVWv8IWqmlDyQvsUlwImE-0YFl2EHPizSCLgHM2FgRe1a_k4YEJnQxONr2GUIGL2x8mDl7aBejUmYkkyrCj4Y5XDS1RO_hrmhDB9rAJtukT1PozIgqJTGNHyH_99wqT3cfG37PPWiSuGOG1Rbujp_by2zqGmJx1PjvoRSX7YO_s_apGzAARHZL9n-xFsoXqiJkqM242r7SHsMrqkYckG5IyxjTrpqDWdOSe4xxTc9snA6Bk5EjQ6kb0_VVG20g6kKua9Qy1n-6Jj3BMOaBHcrP4hKKStHySqqLCPOOrqn9hH2s0YKsxknqCVcR6kkCbLi2xD7dpBXmmc-X5MvuK9g9kGBWjfjQSPEfCnhD7b8cDbvWAKJh9vmdR9ofySSWMWQUjRJA43dOTlUpuskklOImDZqitGamjZTfLK4L-gE3wDkavF___kozI04zsB7xOFdPcyL76sUumoAQ_gHA0he0YE0gamTjbJEk6p6NnzuK7PisLkvNS3ZdKqTZ_msTrRSV0IUyypI1qMB-RZDgjWgdccbBTxa9xeoLTLZM8OIEmhsubQF_danFfla5dm8aDiU6k7QpiutDFosvkIJlt5sBbr5Qhwbp-DWyDaX1TI8cCqlDoplTZiZrzf-n65eZMKAcNL3xp0bMYWslR10All84u6IlOqbiiMqIsCFQS4A-Ff3uftu6JqNl8tC_J7H2F0D2W1rDUVYavmTevdbk3MfH6vEClLwnLsB2wQlripHxv77bwlwK5g-4LWHu5N6shsdVMsk7RwdaozdpDB23r4FAok05qbNgHhgpOgu-1MnRK9res5CoVia32tb846NNom_CRss0fLhnAqeU1A8hSZPwsDChHiz8fYCVLpVkCfEX-hgaloQ07R4QyTBXY9puuuJOuOCzhe1IANS4bS1EdGOSWBiDW_Df3q5ky5LOXCOfJjZBvAEkpnX3KJyxdE8K05P3Sj9akt0eG2buFfBLL3rEqBAvOjSWA8FkSF6b8NlLx53itZnn9yiEyL847Z6WGg-Wjs1y-hWSzBh587FAB2z8nTrIAYOQkW0dWJW9Grerc2NraD-hmK4AzTK9f8dCwWSfmc5TB24s6qNRU8Dk4hZ04wAuSQLximtJh3Gv58EABNSSZO6SS8S3SvTR3rRGRYe0Op5EnjoLvT4ZSkLaRFQxld15H3vq66hs9PZo3F3ZxNBO_oDulDXYVvOfeP-16sMfE744LGlucoZBvfeEtjE6Lqabl5jbgByNm08nluPSNGAVOQgExxHcAlL2H29yvMpo78qeqLlkOw3iHi1rEleBFQxcTOE2Ql0vh7gSjgZba0WoI2rl2nD5Bbc5rlTkSa_0-SoDl_aWnpSHLSXHr9y8S1Ryphc6-Tz5uy9lCrplcuHoiF7WUCChE4gv65yf1i0VTw0QjsnwPdnq5Z_EXAou2jLuXaWwNfhIPyyl69n2zEKrKDpDIxS44J4IB5zCA_DFrO1gcI71ibRrcPQiY7Y-H7ejlrGv1TfE1FwZwvphixyc5cVoUJYDZ3pljYH_vIjKAAWr-FC5rNeJDCkXdBwGzrB_fjvju9lNu0bH8xXbQ5xB4vGoorscYBverGCtbbgPof05Ga6uVo_W3_6EJQbJg71kriFa_6haOFWz9Q4sAAOYW1aA1mrEDJY40nG59r2VdQ7EU0X_5mqkwoQGcWddMWgZDFPIITpWOo672O9Egh8luGo8EP9zhRtFIGn2vC494VBDUyVGrKMJLLI1lpoUgGfsndA9JfVJH5J9BaKRqD-GcZh2Fojj05eyJS1Bj62AoqB15nSx1X5ouHF_SkkRBZUPYQqByCrtvcrQxA32PeFZXzc1YVltoLa75LmnhBU4PBA4-KZOaGjL1EYUSU5VcZkLdQVyEXXT7NZDZ9ZchBp5IZEMLkLDNSeguPTpJyTdodbbye-QZdGzHVG9yVH3bqTB_KsEqIaJ30sjX_zi6boK6ZC7ZeGI59ChA_W7jVIT4kHWWPp4WVVlecuKDzePIhc5vr3wUlXotk95470wDp3Jw81QNNu_jRgxJ0dWcIl0Ew41OV8YomZsud_VkXBTn-68KwYcBq-rYGwVFktGpVIOvoIspZvch8d6UhSVG9LcPjN1_TD1GAJ5EQtwSoVak2I9X3zHl0bVeyJ8qrcOQcLc-4ss_YUfY3sOxrv3WO3livMq2e40ec6osSm3EfhR6RKEgOAwnU_VBkS9remIUxsTftJ2ZefPU0ql_HnT7NmiYjO1s38dQbBI68scRYZtzlJ1Yh3uKqww8CG4Sr3s7hkXDl8yEHfQdSza_YSphJWn9TBflKcBa_t05qW2eTtgri54pqNvcDE1V6sJQqucT2xQAodfMaydGk-m2XPCTuAJ3kCgCpJdzH2Ar1eBv-7XLywrFGo9ayBY1cQBOT96XY0txWY3Ju5BPwU1JlRxgitQI8kGND3b3HTDGn-U__abQUMkyL18FPXkEsD5ZnRRvhTeQjeNpjM0TO6uPvk1Xxmnr6_8sR2s0bJKhuHxC47SIospvgW7Fl9BqlCaU1UoQIuP0c1rN1IfKk0OIsAZSMDvSLCze33-8vFyCes1hHSc0MI1zU2CR3cRt9-3TE08lQw6SsUAIM2SSvfsHBXP2Ib7AnoRby4HTrRKngGPXsNIRtMzthrGT1gj1Ey9Ka33YcEz3j1PGK5mJllRi7nrCWDJQt1C9kLcp3qPwWnkq5J3b6VSgLwvdrMSEPKrIJGhB8kugfey0fJduu5-Puw3dH6DvV3sQo7WKdim3JUz611z_oiwL_UzeL48yaDoBQbfe3LH8S6pWoXeCU-Pr2KASZGM8cZlkVKnJWTKa8ne9LdBuRiDpVwVePQ5cDmUn88SYs1KEEqguwB7te3xJ_3HxuPRHqy7gTs70trvBGl8zqVNJsnmKpS3V_E1UtMGLYQ8MFApSA3b6YcJP4j4E6aCD5lakVLGSnMoq3PUof7Kc92NZSWzNq7YfCoAzL1BJoz47MdWn50bnVy4Xa48GLvQgjEJ-MF2i1txejCCw8jpQSZqHLx_PvKT69cw9UkcEzktnd-uT7BruxwIl6mcWdc0oeOjt25zg0IxB62WVVcNHQi_PSC4_kM_cvIx6749xXi_6hyui-2L5ZNQmcd8-7-y_0gaQTaijKThaSg0QtGkWv1lFtBjxxe2_mcANoTlnJPsHOvriL_brQeBfNf0WXwRgUzfUF62hrYCw7OOqH_rbQNBJbHgyyTMhxVtxc-DoGqw9QIVIwZZC-XEl_8vk0D7r-QCW1Desu8eyXl6tDy6kfP-UkuvZv4kZT8cbihvUXmAghgfRfUzR0OK9V1zMIfVgDYPflxtYgAT67creQ7Re3R8f68cVFGT0oJ_ZpN7rYREZ-mGghxVwmNndFboo97n2aLZbBXfqCfLPqMgaE0-nCKB-CYN-PX7Z1tJcNerMllFlpyE8UTw064GPNxAx9J_ZcRPVgAAFdHOe23ajDzaeSRMRKVITIUPugxbKPTWb55fOIwgWOS31s0w9uiGFrScu_7aDvrsI8pXFXLZhSZ2qPnARC6Cz6t3DQPLc-_0W3T5q9iy00AjgTUBSJIIL0WdoU1zoUyJnDY2JZLYYQxaFp1aI9AzMmm9c56Qb_NiBUfJfyVS3I9NaJq91x8QebR4IdO49boC5oAWIERJCkOTLxQUbKy6EXtxpgO1-zhBXXDPKyhAuSj5jnRa7wvRdbKXza6stM81md-AqEvDl6Cnj-FSXdaEo8glAF_XxdgA3UpMx1EyvkuoGcEcoyEsqxc5AdOD4R6cKEdMRl04GGSI7fJp1cuWmJLQqesAjK_VAEnYYrmoQxdZLw8BR1SM13XoWSfEq9dN_uZiwME1CwkTR6mN-WxXfeg-JYDRebAY_idA3xP6lcwFBQsIRebdcRyqgmiZCMyaRJ28ZwOUmpHaqJEiccfbBL0oqO5VFNP1bAq5nsjrvXkmB-a_jAJyAliToyuKc4i-VXMiVwp1jV_outA53A8csMgLmkYHrON3ZA79psVTdnJehE5zdAaObGZt_h4U1fXGGfdzuTIZ8Nr1UlNJVHwrC5Z23DY_Dp7JNHt9TIwktbfaQieUW5IR3-x8vczQewwU3lIu9KrSESjQZSe3Xr029LQpqSe3DuyWCWrLSEun0npCWaCiskfrT3zI31957vIbKdKFD_rfUzKs1byozDw6o0K19litvEClc2PQ8gZWW347WfHIwek-9qAMsRlreFc8n9ASWW_QQxgTRnBBeC4DkuwWmuj4Cfs6xwfu9b9T15jJNYGxIsLVer38U3AS6dEgtwCjwjZ0jfQRV2o_Lr89Qsj4E_EnIbJzZGEKBOIobO-lj72l0sFG5b5_qaMhUsndRRRQo3KoNa3jTtGsBI8EkMb58uLLlqD7sdIEuJ-a-1SQwiSyb9m5P5FIlyykGPFK5okoEOxzwIZSEgdghKXGIq8SQbgkQ83kHkocq7NxBHdX61Egr0V3uEEytgcO2chYZd-WiJWFLLm5zmTeLQfUl7G5CJZwhFGRjpGpYbYGcMkRCEgATzT4jcwzH7KYBMCIXi1bskCDctAy2as0jQnc5ICFzWl76doHdMVJZSvFzFY29_vP8IuVRHSW3hCtODDxLhnvDXMPGt6dOjHN-dq3_NB9mfvHKkOEK10JDpRnvz0k6gstUZDHs28a_BEH8RTb0pXh1rcO35elGh4yDNNKUk26xXKabN3OZMVmsZxxqL_JqptdmC9cNwg7XZ-S1Ey4-6acvec5J4R6GjTcPZWluZLERc2tTSeOtQoJbCJD1shS2NvR60jahncVhdp0ynV1-ZX8oAsMxKFKiB0ZtxdVNLlk4FM2nDzwlHkjbJNlz6xXuR8M74qcWVsgEzEBWyL0INt-KlkSSTIW_JPPnULrxNfDTu20ZQScBx55So1xEURFaCHjUf5P8MV5vr4paC7h0UXlWlj2LD_j9h0T3FYugMqTZuJ_NfPpmY0DpebI-_DY_cbNz6DZEIyicaqZ6MdFZlUz4Q1bpCI6773qdFLUdKS436u4jQcQjlpSbaA0sHl-7Mmr4UWKtEIZv69KCi0XQPqCOsMSYhnteyv7rrH8tL5zNqCIkUW_hKmle5Vblbafbg8wVhaObzO4nZKks-se9yVoMZnYzykm6A9C79qdWg3bRPQ8t7nWcwo42fB6kJ_K4OiMlPklzpWmAkDbTjUeFnqdUV5XhKdZPRWfHABG1jye0AZ9TZR8cS_lutJQGx6NzNzJ2h7qaeWM97ahd1rbGqeYhC3V3El75LYabMagyR5FqKaPXAPvTXdiulOFSb5QjjtOpxjBZQKC4kH_Z_jTmFCqjZ9KHB9FIdkVqqPSZV9eWPHdh4GB1RlfnJoO1qBGXEJfsTrI4BvIGn4FFudiZmQNar57xgkDx2CL3hejyIWssU6MkmvtLqwcha7NgSa9Li6zQHd2pBrfyKUtvE17_aEL9vys-2U8o4KqKph6vSzTprKRShTAmk7hUY8Hn2I2N1frQzOO6sD8NUcGqGlLMh4rjaKQXdideiNkn74J6Wdo2-hlie99H9qpbz26SCsSE0Ucn_HTvynOg3O4HGB4uMhz-CQHsdLh-9aZjw-xLtmbfLDdUEQC8U83rsX9JysbyySFP0bZA5kUTbhN1En5_-E8sXUburEg-nAshSW6WvSvM0ZRVsA0SoaDKIR0Wq8X8hXhK9tpx6rOMmXlcLFwNefRgNvoR7aoM7sRFeBT2QL3yjuHnOV1cZ-li3Fgfb8chV5CCsqAXucplybckQ1SmtDmiGxG9u6M77ODMpU_Cgn_bwtrDwwFci1dFyBPaBhQDx08jIb5tRUoAv0oLbTbl3CTemYSjNQaqWtX_wiDjH4uW1oU89m3CE=', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc', + signature='gAAAAABoxC0Pe79v2UqAMj3Y1BkJi0m_G8llzMHMeav3XGlfPIsphSfHvJVzbyv5s7pvfPLs2-ECy9vhTMaN1UfI_PYmoJ17y_k_lLjvC6sK7SdFeCmdGNjbrgIcah2DJecVqDdoT8P0Aaz6COw982zu34UyGL59e5FTol9mAGvtInH9vXmmQUnGS5fGktT90wC6-MrIxBc3Og92F-e5ciGk0DAVMC90pDTyP4z_Qkj8Jv1QYKqCv4GwFO8LyUicPTbML6l39jyTfH8L86uDWMMxKNsvHEIrqgTQnsInlwnHYVbPURb93_gMtcjOpZwc2ESnjqUtMLXzs8XaKxhU2NVBAzcXL5x2kg7OI7HbS4Vl90Hx5cVwp3i8OTfpw8aRhDoxZJWptxNBKwDDEtjqLbylKQ7m2uJ8_TkK030O0fb81_W1-36qeRn-yNE5jjkKTezyHP0DlpKjCzoY3pZ0GtIj0FRDJOJJOmbHXjC8HfrwBz76tIA64sOz8P5lS1parnESooZidtVudhrYPl5hgZ25w_X5JCOXhXBUGHFaCkiEYUZTydLK9i5W2nfmriUt5wxzG4rSHSq7B2zqLi1GdKg1So2VHEPRfL2GvDVQiRM3K5TPyrjVgoxM8rhmQp65uQ9pM_qHhzWAAr5BvMFVax32yI-gtTzOn8_gC89MleQkHueUbdLxiUDjesO8yIIc2rbzg-KatRma92xVYOS_P9uxzVR8ZI2VuhRfdlrHbvvLC7Crp-Vq-vO3XyNooIl8N6USQbSSCG4m1mt2yqcaUyUZBLPLLi2_mE0g5pF2sm3PRCEYiWtT26go3tZt8_HLF9exTvjOMny_CKAL7Mx2evk40fqbrVY8su1uhqK6AP9XxfkoyZoYWlBkQ3vVSUuFC6lNc2ACGfUFSNqJtE9XKZnwkB3gzw7N5zqFStYvCAjhqqoxFh4peSUf4oEdDEncLFQbct-TFezeTpxEe7wSSMYm9d-YpV48Ne_T_aUMrFevTEnB3x2oqY6M-tokB2mOOjCVJv_QUbDbjigVmBpuOmW_NTTQmVxRIO7_c90ywoMs3KmVmJXgV3Oec7Rp0tC4DjxM3-MznjZ3ctAuO25oxRBlFE5kABPTAZHPwX2nr9HNbH1SyE4GfmzHFzs4qkFNWXMlLcsgrHQ6HsyHoa00_eA40Uy4UucVzS8pDHF3Nt4yy1pDWyRGIkIyp-ptbkSac4Ceq8Gd1CVak6X-xpqe4kdk9Db1BjyBGLo9BMBbAwT54KMwEUrmqRFjTBl4Lqp6AMtoRRDbxAWzKI4X0al1g64B9S2FFKNGm4zs0bDitII2LyON7BZe7x5Bm_agD1SbkdHbmpOtxY10eFPdtShwYPYKr3jGUOILARRxYCICiVRPRKaNvoozEqy0mQVyGREv0byUp3r5YarGhretLddtfZIqFPYcdJhoB2ar25710xMSdnmGGKze-yjxFq-DVKPN-ihWtqpdFaJG93FVAO56v_jURwNM3zIBkTjEDDU80wo6hOiCrm3vjmDN0RzdsXo17WTs_QrD80ZDMI3S5UBqgJqE1Rk8FE2FBZvgQOk9kqWwhVt2XeK7KsOO9uHEMdFthxUTzMWdmbByQBPUeHI-dJHKkbl8kDOc7ljnN80U-eI4vr66kBkg-evTcOLZILsJ0-7IXaTDCiszLae_EbdYeXEIRriHsp63skqod8golNLWT56DkZLyNt5lu8ZE8Bp4QdkSL3rcNv1GQg-sT3DI_bOyQuHZ3zP5-OeEFdrI1n13KrnuaecyDa-lYU23BlGuMBDC3Q6bld3FPcHswew-H0sYgJwry4lhi1qMCRSzQVKvfUc2V658fOqpJO_85ssiSfzkMzNnrE0G1uRPH5_LUA1bAfmoLU5SkbkajMi35nZJzLTg79rVXpUtK8l2xJAKRnobSVKzPD1HT-b1x68vDHp1jFzeGPaM9z7wAC4iwXJLFDJhI_U_uoomw1d5lb47WHuAjpj0Q8Psgk6IMKntdWb0g61GcLZ9OoRyKDkjxar6KtEIZ1cyYVxUGTHTSKKWyrKvhWM9koj8EXkMeKtX3KFleH9AtGBFhExeSPTSJcmnv6t1ZVGSclQxVELOZh-RusLdy-wL06mT-eiBeHGw1H-0S5My-Py2AowI3aBk8YyDPGVH1pCnVfXTIOdQH6idOAsF6SmQahhjxr2KvKPr5Xf3zRAMrlTw6-50HgiEBibhSSWr0fxtZ77dIlesxym_eTfS2V1VHv58Rb3NjFIpL2ayLI6AKAnq29U7RDPXgLjWF4WoNxGkmo6Cc7dWIOsekjQuAQUtJaSSObwP_2HaMwfg5QPdFgt8KkkqOGsDEhXd2Si5ikvN2OFA_dUigfQ8aevQHqv-V7n4nFG8XGWkgfSdYJWMt7Y0SxuBJz7nlsnnggqjRrEI1C5Ae_HjlXKtH9WdYygzOtFGR_iVm--LWQE48-EIeym8g5Q6jwqAbnARFiCcfHyvU2omiGdiN8G9FIVRetDqWUDmdnza2GbJJ0JvoT2O8KPVkXZt8_qWJvTFuJ4Cqkwr-n3aa4BOQQtkB1lELR5rXed2RMNbReXmalMujHSVozgilhQauc6D89CY98ks4Yce32HbUOF753_eMD__ewBxA9DK31i50MrKQVID7UvKot3BsOK4JH2ExIg9CCx-mAbEL6HatGwoiE3zhX0RCO2OHYf66jrbKJ220wTH2O6_BCkihzNKLqTVmpYpPSprwPkkMBNfQTgtEJPJWp9hPoXux4g4z0EtYymZpC4sRVxpBH5mvno2D9i09fh9LM4QT6cf1Plh-6Q3HCupQpiq65g9CmAtJDEiSoIhrxYRkuza65jjabRvkudS8rP4Wm5Qn5ZYlykXUIzC1BVSIvjZPK2OLw_vLG1_iTbsBONDeb9AqQaXiAc4oHqUDSp3RJXvjRfQFNI48eVtk_LLkDd1WNuwQtzAjLAg9UZA6JZGLn66SpFpU_F_bwfHvNWrQ88ZieRDdQcbyCDYNJuqMMq5YOZBpz-Oa0Lun5L8hhUGB_B5FTUQPiiLVIKuHPJP0qLgC2o_R3u9VNfgwnMENnP6pmmVI2mPMFJSHEuDeShRshUSzZ4JOs9fnvpKT3TlyXFOeAtcn89Gilua2ziEfBy78d4Quuik1aL1wQtnr3PBTbn2Z0JGOPZoKybk9CF1a-1K0hoEK54-jRgTrPGseSMibhGO9x-5bW5viQVORDH1L9g2kcfJur1D-04cDlzkAB6hfjuqk1pvT3S3O2UGU37CZcVF_iolUucC8snhW5uhuvSdoBXXcnF7TuwsgAKNvztnf7B3tPJTW8x5Q5PGqHmRsoilCFlbslJCGq4h6NraPfKGY0Qq48A_i9QQGOihf1BI3OJE5usPGaxe6yJTpGQt5xCNuMCI920xIfCuQUx5BmVDAjho7EPkcDHoUWF53iZHPp7RSlC0uVABjJaaOREGT3oludmKOYY4PoZGMFNU_4Qm2UlT_OQ3XXhon0dcjT9j7OffzgjOiYy1HUMGpSyFdvIotQQSfAzNirsXZtZX7sVKXDPtOwzALnhd27odnEnYHpep03mmDI58plDhffF_rnw326mggOpYGBEgFNdtQCwoOe9P73E3762lRYHl6IOidAG6oaIP8sr3TU5xXhzJ7iqSKQbD4UMwolnNjUjVCwGMsLj137JYfUgQBmiu-5HuRuyD3jcRmddrWnofPg_uv_99W9i0tLvW9pAk5YDDUm6fFruGbYGXUa85g7iYuB6cY3lArHpPvBhpgFuH8FEexXhtJVRAFsT-Z7nvI5Hfh-Dk2M-Dv7ITg7er2mCwxG0ZmPMSx2kglqF8bZTxk7EqfGVQMvtgQMZTDij5dCIK3PzpoLqwNMd44fViVc4VXNR6o_gFx-XyKY6PVCN-OtGVQB2B6f6LikWyIMaIB5Jic7zT0lMsf8n9aSgi1UQdiR9RuizqInhxoW3IcdPpbHzyYKMyfsgE-VKX15pPOiL3stMrq7gSmX4itErJBKq2yocNH4QHjoqFsndWK3VNc6rzkdcZZqhu_ZN3xW31q57PzZbNMfQ_IUCuNPwcTCHnBiQVRZQaaiXvyVBh2NcBXLEdqr3Xuh8Q2BgCo9ZiW6fdqXOgSAd5gwxGOeQ_Cr-HLQMhB8bFE2szFWttri01hxyXOnpPt6ziDw_t4bGYB9WqaEMjCe_3iUgLjniX9hwPuQVhTDHvwkTaddSQ-SVE4JJJ5-IY7_0MAy7_swITfNP_7Wd_-XrdJ-PzUgKdKs8E7QSd2hpK6Vv7SGlsEHzPxljtHLsvEOGeTxkuBhc4KktOI3ezaooG0IgpQr7d7-viS2PF2Ri6-zkoXH3fosjCc_d5DtOvbPn_hE1Pnu-rCWnilbekyGhOquEAYsErlioLhpSaP15wkFzcZIMlV1aEPlrM6WzcCJX8cdeV0Z7fL1v7R11Jhux8h7bpW5Dm5mWtwpfg23XtywAcSXB8F1GuSZXJ4CZHq6vj6lAUqS0YigZBzMZe7UdOZUIK0VFTY1Kl50eI9Sptiy5AEPhDdaUT1daa-_g4BqJtelvtpF7XvIpPvEtlrLJBjimxCJU28-QUJDaBeKa9rtQTWf-4kyY05ITG9ke7qUnC9Sc_LDkeCEnDNjzStbf2B-r-ov9f2pUTJXDKkP4TwwiZ-AlDGHoKExZLJQYsek_DHS8rzwbRsjuhnU-toirFjZ1nH83XcYh6OKaE-7EsoUXWs5z16ntWeNJpEifCh5JNZJ_XC7BeKiL2uldqu4naYwBnwrrz7v2UAxOv2KusUwC5WHjkueRjgQtgS15Uf3khMDZYxMIKJeU_27POO84uQXsAVdPs_L4yL36hqVdT69WNfJzPuKsFiGkheoxC8SdGCaeUgpPZ24KZgDE6TLVaYin1xRBm3h-HxpAo86vjvM5LnpuVAy_0iJa4r5ozxhfjzJ7fPjQSk835tjZ8hls4yftUJNpOJM0cruJT25qsQS-RD36X4EF0BSPEdFJdN-z_CQK3LfAKcNSvO8UR7T_FEFzpH58qS98DR83avQuNx54lQ5h9ICIi3fxSHs1eO7c5m7jaCV8VHL6Mjkniqf_ZW0123BZxC2AeGcucAD9iPYeXFI5ob65AcL6TA3k1J8gOX58RIdIdzW9mkwMjJNMNEWYpEbsevRuQ_APKGJVyu014wYGeueKk9jQjgt8YQyLC7bT7eQKNrhWrT4Xfib6neWmhV9NRXVB8o434srI7Cw2sJaWSbJGAKgov2m-fvSEq2zqbNKQNqguIqsw-QvubN5u5c00PUldQs0zISnVthXAWJKlmuNxVykdN5HoDkKfAthnQv2pVc4mZK34DfcEo3Xc-1Ssysg4qOzHR4zTCY1GFX9FVKvO3C_CHI27gi_3pFjq3CcgV2_LZ3_p0g9IlCy2-6WKcRzBf_8jbuLb2kw4zGK_cG06YeeAzzMqPrtmx1tEshJF0sKAWWBzYYc2RE1Sn_QOP6YSxei2TKvB3k8Xvnp7TK-28hcJIDnZIbbU_4TkuoXz_MwbNEcE2q6YMxC86WT0qc7YXxAY3Gp0sNOypZ7QDxz8kBrzo3px5j81zDq1kxF-ZEIclPuFCXJ9s4NPaXrkjFmWnTvPmVc9F2u0JmkNgl71WaC7pRar3QpD_kbEJp-zcOFzyUnteiJKnQdbTdxZal7OT2GyfNDWpfJ3wmRZHjgAihyhDeGR7bPC95eMwEfp7ggXQrCrfLuFwMtkFPq539rnmbQ2D1GoW6f4RMtkF5p9UyihUaAjP4LC69e9dH4A5InMJmDpPfExf-_PEoiSgVTXWC58pb4DXm5QcvZj-4c-NDnlbWb_YbU-skdRq6ReAjIjWMNdRUoaU3b3EpWLTqVCsN2ZZNmqp7is5oGJG8Xyswb6VlGQq4ij5ZgGRE1YVVzMnoBVObpw2lxeDPldsK6ZbmzLq2cG4glgKPi13X5ZlQGb7eVdAgp9LZehOm8kOTljE5sLGmYJJpkmKE6hiddQeG7wxRSqcEoIctTRfMruXQL4gsPXgtpaYsTR6vi_MVrFSobxf_8DmhAkbUHNcyj6H1HVm4JRA0isGBoicUxzhybBn0heWjprPfnOD9eO_YpuUXxBrlC63LBKLQmsVkqkNI2mfTSKxVnx_f1QeuhJw4Rrp7iVyvCCE83XEr2uujo9uxm62zHvu6FHlJBSpdeX11DGUkXLScUtkFaCgHw8dcBsnG7jloDKJFOOs3i-cxOe-dWqlaVti5_sUmCLxNFIBk2TjZP44qQ7pQMT-Wp7b0o28IHGkaiIebz20xiWNOSYstZwq1xYIwhnQtCnAibqxE5kc6gtZbuF06NqD1h9fROgp9jdqGyucjHXs0zlkO1sBGgkz-8VnkF97h3rtdkqWSTZweI28dYQ0GYXagSSIgXmQp0QM7pzDp_JO85NYpR3CZW29aB6gdzuSbDoFciWd2UTsQX3HTEIsGxhtRtMa4ZPHyS5tHAKSlquhLOTHMTQfi8GO_VHsj241Hk3S56jM9Czovx-5OwRB8qKFNiHwKOvliSJR1HgXBkAleRIALJ64fDz5cUgy6Mn13Loue3JcowCAIgkrnusjVLig-y95xVvbs1Ys1rUFFKy3mmVaVyYd4Qe-WBLG-pZXug1z8gLTEZkY636ssMr_wIl2Zl-ciykcbiH6S9yTY358VqZgzQBS-44sQTdT_qelrVSNMLKneMs06JSjhSJOpmogW1I_hdHMtxkkSOQxKINvyEHPFbIkUR734qjhDVUPweD3IUQdMJ995R89D5cl94H0REAU_wJxDSGwGlux1P9ul1FHsX9hGTiNU6cE_qAD8fWX5ceOBa2iCoNefiQw1Ft9xh6QYDe2lOPdpIeihKm2ABWMVJ3hGCYwg-QPhj6yrSbZ4DSxCMPfC3NQ0Zarj5VgvfHOIO_gGiE9plkknoLBM_j1VSP7prfUOXQsA4sSu8eYhkreMkSVRk2JJ4JY2u1s9zATCq4cTUcKwdhgasU-mzPJRc0PF_7JsrojJ-GphyN_vGSzv_kBtl1Oo7IIHNo4UYiMpioxeBd3UV44oL8wOgImfs3a1Fnb-fHOS0RHkn1P57V-QGQcbQOoXtSqcDLjCJEJ144_QQa9jSCRUYXVv5VEYGfEcpaeyP62FFvLkeNfonGiObjVxXM2mnqV9gXm8Tf_NE7HgbthKKN9zbfOSyHos03LDBIYqScCnENopFX6XyY_iHOZwtfRojYmlZcfbtM7AA5K47Ycx1hC7A3U3x9CjHjhLZhqcQXdFeMNyfbEMabj4ESo0vqfKOFhif_U49MwLg9Q7cquuJ7zoduXmiBrlm2hPgzzpEK_JBC9vmc3FrxbBV4fZKr2EXYevtvSrWJ2-trlF5u9WO2xC6oxCuTUVisluvCWwhy0de3tulbLHlKV8xYEh_MvJy8tyqeOS4Y5lLtTtwuA4rTVNrYp4-otD6ZPQolK9k1vGCQtuTbgUR0Ya2m7vMDd10zU79haM0C6y723o3meJ6Yf2tIqffTk6YRpDw4yFiM0xKRP1NvkMT8T-3ptVnIBz4laUp_HDoTT1EQsmKYFtgMMaqTRImxH75v7FW0MGXT1578lBSB-PW_3U4zR8NpxvuBfLrzHcWOQv1bJ5m-v3ho91V0wXM9X4qEiA0CbGw3UdrrZ80VSeEa_wU6mQFG5IUB85_AaMkKjZsqoO7rZ4T_GAn3uqVmObN59eCgERccyBogj3s3oHk8yEXIhtzIC4wwNbiNhPBVako-_6YJOU5FnYu7VXVAWBNZsTMi9XuZY9oXTQLoU8Ya_Ix8baVrArLSAEDUih5mZvtgEzn9rBRJEarsCi5VMojQk5vzDpKjz21R7sNYTaiNikeM7AKRTtEa-N7FtdO432Gf4y4BYTctIi6ftUPj5mRbDm-ul19u89mnGx6VA4h4GZ0oWRtCP72svGw7zV_I301Qcl1m9TxFRCZvqDEvbU_GaRlL1VzR_QUOixSfCMrlovCtycE_zXE_oyMSjPXzA17wklLjG-gEFT0FUcvlohTKLlQKAUOvkalRMsao_DoGOYRfd6e8LtuKfaRnat9iq2RJ8OfbZw4kLmT73kaszYaFDPufKFvXt0nIxi_ysbX28Y5zZq6KHKwLmcceFqwwmZV2ayAvYjBZqBYpPLTfvEUd0-3n00bXi0hLP8Il8D1F_2ZcrQcHyc2g-g1Z-rxl_XaFnipOWuqRxq3ocMZLZ4YpUmMMA89icLRAoU9mG24RHcMrzkPD9IGUZv3SJVdKwcbmQCD3cBZBb4PEFenDnLbx51GodWRuXniQ0bl4cTlKbTkTJfAe3MpOuUDkcM0FXfnLdq86Hye5N-ygCdFfGozi_EjxF1kNQ6ItrNb_0i9eBhMTgCFHGCVBGWamswc6tICnbQRCDnUXVnvr5qqjno4w3hlXSmlE5w6j5yv7CskyIj8-rsbKW3zZTLMDHIyRqL4xtEqcJSlk-86nfCQj9QVXB4O3W_HLuyWo5cWoTHPwKlArTHx8Ml4Vub7qsgFvEnFzGLwd9QAWnaqD7ENALvims52mSBivuiMMR90nh-jsjbOq6GhckHhWRrtDlfLNcaTVJz-a-s7Zt2Hw-afODG7EemMCtGVRDDZn1Eo0katat1aXH7GU2LCfh-FP80eajowVmMYb5lRHWavhRwpSGTBOsmRECrJHym4ImOGcnxX6VE3Dczh-WNYYjEa0Q4OY1y-S21xExqdgx3SkaOc5G4KGuKdPCh6FAqg4P8Is0QAYnwnjbZZ5mQHfy-oUg1tzbO7yPkY_LNV22NlVqkUfVa1cMMhOzGqTOODaw5ECto3kW1LrIhVieIvKDUnztMMVj6jU8jjZ-mbaOc_Db0JLD4pgEtSmWybS9TqiGk6dcJGXOjDFi3PjwDCSKgwND_0xpTE0QJnumUhlflz6R1sFsE5Nc8rV0QglWQQyseJm-h-taauAkIBzyH3C0595Jkm5LBlM7V-bxtDeFjx-LFqB1rslSSW0dhPxrO6JAB4W6wtyL32UIRTGNOrgh26yboEvUSSZjJBeAO8Tiv3BCKTep1i1d-V291rJjb7sj2o_8XWaNm4tpl04vVY49WttNCxHJ5fM1PuVzbRSoOEF2btxCklDFhp5t8u1Y9mVnJpNMmn5AiCXZZSoyPqrv_j78QUZZXj-x5xwVft5363F1LjjoZ5s3LdEoGbsMAUiwkm7Z7aSr8gmV3uzrv8WyjiJjlc-rpPTE0RHbK_Hc5L9x1HYTJXECSdwZ8Q38yg6uc5EpTut5WPyScHFiDy1ybxnBPPx0tWas7jVULTZaeoGbnkUFo6xTJLMd9Tzzl2IM2zpgL5ZP5c79zxJvUtxgVFwTVmqMQQESj-qXikjBmaXgMLUb4Kv4n9655bgjr3ZuF_rxDagbRdt-_2pgf6VqsHEsaZJHwIpxh01vmyp6ZcQxzSUmi-8faZ_RWCJ5iTpHrMAHvrlPzrerOYBG-RGl2pxJDCVYr_WyUjKbPDxWkjKopcXx0DrYu1C6Cz1-gtGCT18LqoW73MCtdcrwKUXAmLdGUPFG5UFq2vuqItkeXcB1AA2hUhO1rzWYqHnqy2fXm4xtBgXMHVK8dqiXCmWWJ81sezBMVYDUP4MvpPkHRFSLdmG3YrZr0IwT9RzyyDfGItqWheKUJ7fkv0koRczg1J92z4BbyVBzdnEQX4edyyKCYd96ruWi-lEILIFHCY-viwPOIP3wCifcKgMCNGOzaTX3raFo2_VcNfvDSC8cLQq9X0o79qCE1Jeog6jSHUrKYhGsjn8mAJcdf7VzAjNsMpXypG57SMUBz4rd5QGvw3uGTs6M_p4BhciR8o1yOlqCjgRYyxUbCukRH-Od8QDHjRogTAeMjwL_fxEOIKf0pXWw_L3SeEddEfBDGaSU0CWPtCiEpUdu8pXQ-PEPvUFljROnxSr4Q4NQAro_b0FL2Lfk7rSLVJ-mlV8HpUwggz2VC0jjriGZDTCQmLCGFtyYA4qMeL0nJyUD0gfujHGMrqjnBP_TmwUr2qHn6y0jVreD7SpX8ojSYWeO0ebFHyBu6LAJy9VLS7d9Gu5tZ9EVVDCd7MfbDozD1UTevnfxnyGT2-_3xJXnJ2fIzISqkV6vYDmvXAhMHwggCBamQ5VUb5Ri-JQyAOkH-P_d5AzM4vLH3NovPaTs41-EZ9LoA_ACgTwMdXcI6yKNhvbYfHK92GWG0k_HUoZp31nOrUY4hsvoDr1VyJHeFjH2WulFKr4hTj--htE99X95MtcYL1BYJ5KZVT92oX2m2Tauayqr_VP-iYgeiC7WWoo526r5jVWXs1ZgxtzXzylpf5f5z35G4YMC37RFlzgY9kDaeLkMMqUvQo4GbEFbLQ5rF-9zMA2NYFKC-6fUh0hvN1UziR-Co6ZhXi5KP1_3aw2sjSiEwlF3umF4zZcIKjKWtAHrFblBLnUyp79qId8ibcUQm4EHQ92CnkKtAf_e-OB-eZA9Vz8NGagOAFdyAtOFZ17MBcv049eh2izFmxKl4FctOKAEIU1HVWv8IWqmlDyQvsUlwImE-0YFl2EHPizSCLgHM2FgRe1a_k4YEJnQxONr2GUIGL2x8mDl7aBejUmYkkyrCj4Y5XDS1RO_hrmhDB9rAJtukT1PozIgqJTGNHyH_99wqT3cfG37PPWiSuGOG1Rbujp_by2zqGmJx1PjvoRSX7YO_s_apGzAARHZL9n-xFsoXqiJkqM242r7SHsMrqkYckG5IyxjTrpqDWdOSe4xxTc9snA6Bk5EjQ6kb0_VVG20g6kKua9Qy1n-6Jj3BMOaBHcrP4hKKStHySqqLCPOOrqn9hH2s0YKsxknqCVcR6kkCbLi2xD7dpBXmmc-X5MvuK9g9kGBWjfjQSPEfCnhD7b8cDbvWAKJh9vmdR9ofySSWMWQUjRJA43dOTlUpuskklOImDZqitGamjZTfLK4L-gE3wDkavF___kozI04zsB7xOFdPcyL76sUumoAQ_gHA0he0YE0gamTjbJEk6p6NnzuK7PisLkvNS3ZdKqTZ_msTrRSV0IUyypI1qMB-RZDgjWgdccbBTxa9xeoLTLZM8OIEmhsubQF_danFfla5dm8aDiU6k7QpiutDFosvkIJlt5sBbr5Qhwbp-DWyDaX1TI8cCqlDoplTZiZrzf-n65eZMKAcNL3xp0bMYWslR10All84u6IlOqbiiMqIsCFQS4A-Ff3uftu6JqNl8tC_J7H2F0D2W1rDUVYavmTevdbk3MfH6vEClLwnLsB2wQlripHxv77bwlwK5g-4LWHu5N6shsdVMsk7RwdaozdpDB23r4FAok05qbNgHhgpOgu-1MnRK9res5CoVia32tb846NNom_CRss0fLhnAqeU1A8hSZPwsDChHiz8fYCVLpVkCfEX-hgaloQ07R4QyTBXY9puuuJOuOCzhe1IANS4bS1EdGOSWBiDW_Df3q5ky5LOXCOfJjZBvAEkpnX3KJyxdE8K05P3Sj9akt0eG2buFfBLL3rEqBAvOjSWA8FkSF6b8NlLx53itZnn9yiEyL847Z6WGg-Wjs1y-hWSzBh587FAB2z8nTrIAYOQkW0dWJW9Grerc2NraD-hmK4AzTK9f8dCwWSfmc5TB24s6qNRU8Dk4hZ04wAuSQLximtJh3Gv58EABNSSZO6SS8S3SvTR3rRGRYe0Op5EnjoLvT4ZSkLaRFQxld15H3vq66hs9PZo3F3ZxNBO_oDulDXYVvOfeP-16sMfE744LGlucoZBvfeEtjE6Lqabl5jbgByNm08nluPSNGAVOQgExxHcAlL2H29yvMpo78qeqLlkOw3iHi1rEleBFQxcTOE2Ql0vh7gSjgZba0WoI2rl2nD5Bbc5rlTkSa_0-SoDl_aWnpSHLSXHr9y8S1Ryphc6-Tz5uy9lCrplcuHoiF7WUCChE4gv65yf1i0VTw0QjsnwPdnq5Z_EXAou2jLuXaWwNfhIPyyl69n2zEKrKDpDIxS44J4IB5zCA_DFrO1gcI71ibRrcPQiY7Y-H7ejlrGv1TfE1FwZwvphixyc5cVoUJYDZ3pljYH_vIjKAAWr-FC5rNeJDCkXdBwGzrB_fjvju9lNu0bH8xXbQ5xB4vGoorscYBverGCtbbgPof05Ga6uVo_W3_6EJQbJg71kriFa_6haOFWz9Q4sAAOYW1aA1mrEDJY40nG59r2VdQ7EU0X_5mqkwoQGcWddMWgZDFPIITpWOo672O9Egh8luGo8EP9zhRtFIGn2vC494VBDUyVGrKMJLLI1lpoUgGfsndA9JfVJH5J9BaKRqD-GcZh2Fojj05eyJS1Bj62AoqB15nSx1X5ouHF_SkkRBZUPYQqByCrtvcrQxA32PeFZXzc1YVltoLa75LmnhBU4PBA4-KZOaGjL1EYUSU5VcZkLdQVyEXXT7NZDZ9ZchBp5IZEMLkLDNSeguPTpJyTdodbbye-QZdGzHVG9yVH3bqTB_KsEqIaJ30sjX_zi6boK6ZC7ZeGI59ChA_W7jVIT4kHWWPp4WVVlecuKDzePIhc5vr3wUlXotk95470wDp3Jw81QNNu_jRgxJ0dWcIl0Ew41OV8YomZsud_VkXBTn-68KwYcBq-rYGwVFktGpVIOvoIspZvch8d6UhSVG9LcPjN1_TD1GAJ5EQtwSoVak2I9X3zHl0bVeyJ8qrcOQcLc-4ss_YUfY3sOxrv3WO3livMq2e40ec6osSm3EfhR6RKEgOAwnU_VBkS9remIUxsTftJ2ZefPU0ql_HnT7NmiYjO1s38dQbBI68scRYZtzlJ1Yh3uKqww8CG4Sr3s7hkXDl8yEHfQdSza_YSphJWn9TBflKcBa_t05qW2eTtgri54pqNvcDE1V6sJQqucT2xQAodfMaydGk-m2XPCTuAJ3kCgCpJdzH2Ar1eBv-7XLywrFGo9ayBY1cQBOT96XY0txWY3Ju5BPwU1JlRxgitQI8kGND3b3HTDGn-U__abQUMkyL18FPXkEsD5ZnRRvhTeQjeNpjM0TO6uPvk1Xxmnr6_8sR2s0bJKhuHxC47SIospvgW7Fl9BqlCaU1UoQIuP0c1rN1IfKk0OIsAZSMDvSLCze33-8vFyCes1hHSc0MI1zU2CR3cRt9-3TE08lQw6SsUAIM2SSvfsHBXP2Ib7AnoRby4HTrRKngGPXsNIRtMzthrGT1gj1Ey9Ka33YcEz3j1PGK5mJllRi7nrCWDJQt1C9kLcp3qPwWnkq5J3b6VSgLwvdrMSEPKrIJGhB8kugfey0fJduu5-Puw3dH6DvV3sQo7WKdim3JUz611z_oiwL_UzeL48yaDoBQbfe3LH8S6pWoXeCU-Pr2KASZGM8cZlkVKnJWTKa8ne9LdBuRiDpVwVePQ5cDmUn88SYs1KEEqguwB7te3xJ_3HxuPRHqy7gTs70trvBGl8zqVNJsnmKpS3V_E1UtMGLYQ8MFApSA3b6YcJP4j4E6aCD5lakVLGSnMoq3PUof7Kc92NZSWzNq7YfCoAzL1BJoz47MdWn50bnVy4Xa48GLvQgjEJ-MF2i1txejCCw8jpQSZqHLx_PvKT69cw9UkcEzktnd-uT7BruxwIl6mcWdc0oeOjt25zg0IxB62WVVcNHQi_PSC4_kM_cvIx6749xXi_6hyui-2L5ZNQmcd8-7-y_0gaQTaijKThaSg0QtGkWv1lFtBjxxe2_mcANoTlnJPsHOvriL_brQeBfNf0WXwRgUzfUF62hrYCw7OOqH_rbQNBJbHgyyTMhxVtxc-DoGqw9QIVIwZZC-XEl_8vk0D7r-QCW1Desu8eyXl6tDy6kfP-UkuvZv4kZT8cbihvUXmAghgfRfUzR0OK9V1zMIfVgDYPflxtYgAT67creQ7Re3R8f68cVFGT0oJ_ZpN7rYREZ-mGghxVwmNndFboo97n2aLZbBXfqCfLPqMgaE0-nCKB-CYN-PX7Z1tJcNerMllFlpyE8UTw064GPNxAx9J_ZcRPVgAAFdHOe23ajDzaeSRMRKVITIUPugxbKPTWb55fOIwgWOS31s0w9uiGFrScu_7aDvrsI8pXFXLZhSZ2qPnARC6Cz6t3DQPLc-_0W3T5q9iy00AjgTUBSJIIL0WdoU1zoUyJnDY2JZLYYQxaFp1aI9AzMmm9c56Qb_NiBUfJfyVS3I9NaJq91x8QebR4IdO49boC5oAWIERJCkOTLxQUbKy6EXtxpgO1-zhBXXDPKyhAuSj5jnRa7wvRdbKXza6stM81md-AqEvDl6Cnj-FSXdaEo8glAF_XxdgA3UpMx1EyvkuoGcEcoyEsqxc5AdOD4R6cKEdMRl04GGSI7fJp1cuWmJLQqesAjK_VAEnYYrmoQxdZLw8BR1SM13XoWSfEq9dN_uZiwME1CwkTR6mN-WxXfeg-JYDRebAY_idA3xP6lcwFBQsIRebdcRyqgmiZCMyaRJ28ZwOUmpHaqJEiccfbBL0oqO5VFNP1bAq5nsjrvXkmB-a_jAJyAliToyuKc4i-VXMiVwp1jV_outA53A8csMgLmkYHrON3ZA79psVTdnJehE5zdAaObGZt_h4U1fXGGfdzuTIZ8Nr1UlNJVHwrC5Z23DY_Dp7JNHt9TIwktbfaQieUW5IR3-x8vczQewwU3lIu9KrSESjQZSe3Xr029LQpqSe3DuyWCWrLSEun0npCWaCiskfrT3zI31957vIbKdKFD_rfUzKs1byozDw6o0K19litvEClc2PQ8gZWW347WfHIwek-9qAMsRlreFc8n9ASWW_QQxgTRnBBeC4DkuwWmuj4Cfs6xwfu9b9T15jJNYGxIsLVer38U3AS6dEgtwCjwjZ0jfQRV2o_Lr89Qsj4E_EnIbJzZGEKBOIobO-lj72l0sFG5b5_qaMhUsndRRRQo3KoNa3jTtGsBI8EkMb58uLLlqD7sdIEuJ-a-1SQwiSyb9m5P5FIlyykGPFK5okoEOxzwIZSEgdghKXGIq8SQbgkQ83kHkocq7NxBHdX61Egr0V3uEEytgcO2chYZd-WiJWFLLm5zmTeLQfUl7G5CJZwhFGRjpGpYbYGcMkRCEgATzT4jcwzH7KYBMCIXi1bskCDctAy2as0jQnc5ICFzWl76doHdMVJZSvFzFY29_vP8IuVRHSW3hCtODDxLhnvDXMPGt6dOjHN-dq3_NB9mfvHKkOEK10JDpRnvz0k6gstUZDHs28a_BEH8RTb0pXh1rcO35elGh4yDNNKUk26xXKabN3OZMVmsZxxqL_JqptdmC9cNwg7XZ-S1Ey4-6acvec5J4R6GjTcPZWluZLERc2tTSeOtQoJbCJD1shS2NvR60jahncVhdp0ynV1-ZX8oAsMxKFKiB0ZtxdVNLlk4FM2nDzwlHkjbJNlz6xXuR8M74qcWVsgEzEBWyL0INt-KlkSSTIW_JPPnULrxNfDTu20ZQScBx55So1xEURFaCHjUf5P8MV5vr4paC7h0UXlWlj2LD_j9h0T3FYugMqTZuJ_NfPpmY0DpebI-_DY_cbNz6DZEIyicaqZ6MdFZlUz4Q1bpCI6773qdFLUdKS436u4jQcQjlpSbaA0sHl-7Mmr4UWKtEIZv69KCi0XQPqCOsMSYhnteyv7rrH8tL5zNqCIkUW_hKmle5Vblbafbg8wVhaObzO4nZKks-se9yVoMZnYzykm6A9C79qdWg3bRPQ8t7nWcwo42fB6kJ_K4OiMlPklzpWmAkDbTjUeFnqdUV5XhKdZPRWfHABG1jye0AZ9TZR8cS_lutJQGx6NzNzJ2h7qaeWM97ahd1rbGqeYhC3V3El75LYabMagyR5FqKaPXAPvTXdiulOFSb5QjjtOpxjBZQKC4kH_Z_jTmFCqjZ9KHB9FIdkVqqPSZV9eWPHdh4GB1RlfnJoO1qBGXEJfsTrI4BvIGn4FFudiZmQNar57xgkDx2CL3hejyIWssU6MkmvtLqwcha7NgSa9Li6zQHd2pBrfyKUtvE17_aEL9vys-2U8o4KqKph6vSzTprKRShTAmk7hUY8Hn2I2N1frQzOO6sD8NUcGqGlLMh4rjaKQXdideiNkn74J6Wdo2-hlie99H9qpbz26SCsSE0Ucn_HTvynOg3O4HGB4uMhz-CQHsdLh-9aZjw-xLtmbfLDdUEQC8U83rsX9JysbyySFP0bZA5kUTbhN1En5_-E8sXUburEg-nAshSW6WvSvM0ZRVsA0SoaDKIR0Wq8X8hXhK9tpx6rOMmXlcLFwNefRgNvoR7aoM7sRFeBT2QL3yjuHnOV1cZ-li3Fgfb8chV5CCsqAXucplybckQ1SmtDmiGxG9u6M77ODMpU_Cgn_bwtrDwwFci1dFyBPaBhQDx08jIb5tRUoAv0oLbTbl3CTemYSjNQaqWtX_wiDjH4uW1oU89m3CE=', + provider_name='openai', + ), TextPart(content=IsStr(), id='msg_68c42d0b5e5c819385352dde1f447d910ad492c7955fc6fc'), ], usage=RequestUsage(input_tokens=306, output_tokens=3134, details={'reasoning_tokens': 2496}), @@ -2518,10 +2588,30 @@ def update_plan(plan: str) -> str: signature=IsStr(), provider_name='openai', ), - ThinkingPart(content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6'), - ThinkingPart(content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6'), - ThinkingPart(content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6'), - ThinkingPart(content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6'), + ThinkingPart( + content=IsStr(), + id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6', + signature='gAAAAABoxC0_aDtrISw_zls0dyams-nhm23et1xecYaqlI8y44ih0g9FA5T3R9ueXIOX9seSrysa48qci5QTep_TNFkxcjPMbWeQxolRKeCjWk0jLpC2FdKdscfb56KfeSTklKz_CaD-VubFOUgtqg8bQfJTvrdEtKj8Q74c2-XOtHTB-0OjenFtkZMtLMu3uc009ktnOSiWIxkuaDXcvgENQlU60WswxDC_3j92V9o0XsSnXxS8ZmvfWcmYxsFAo575ybwZin6GI709AxlJ6iPkSYIyRy_Sn_O2B68S5ABs8gq0yzaDtX2Wtibqys1NooceCWvxBSjZUKKD3N3FG9Hx_GzaUyvB5DblDmqgfP3AC_VfxaXm990esMW22fQvrEmuRNJc7AF0-KSBCNjatP6eHKj7WSiyGplUFCukk1tRHxOeDi9GD6s51_jTSyADenpzvdBLoELPR0JQIUuraSBpS3aZS8ODJDUbIX8niI_RYzRCvqBDMbLi9MaI_jTdEJknhEgmZZaV-53FXEVM7LoK6BWBpocwDC0zbcA-Da2rY6y3h_4x-PD-DL_W-V0_XDqwhx6NZOJBDpGrJIKY1BU-QjjEdZeXg1hv7CmLCH9ykOr-ja8B72fGaY2sJ9Lg2dFnaEkalEnYPCOY1hWDok1o5H0YVwA3MoZPr4VuFbGKD1EEAcB10UYgY5_WRK5Zk2CYK9EMOyLMA-_DU5qMLw0qrpj7lGRe7PLM0UYBbjP3jFZX6Gy5e1RcibH2MsrbfH4SlVkc1TTak4vuBEIR7Q4q8dYCoKTPgHAWFULzFbaCwhQQtyL1_lG-OpiGGUSZE_VRj3yVKbrv4Nz1l44ah5DdlG0BCiKthdMqcVxc3Bh3VKofIN6G_rArAtZ4ZmcoPVXIUlkfSPm9efNSx1tUpZPKkFk_dtP9B0dU5gD9F3tTU73I7CtuDaIXfe5JOBegu0_kBjEXb33s1B6mnUJJld1f3c13AwcRhMimtidTdtZFp4iAaKH0hWKrC6fOMlzTmz7O7R79sl_81XTQQbIR31yojRzDSvwhRoenyRWvQQMV4PeZ8h-2ioG2l0DQ89YRjkjeUEwZyog0ZWHflw3nr8zjJ7xkliqfJpspfE0scWrCq5KmY21vYkf3EcH-HU5s_S7_vo-JwnNIlTaDJUHbEo8sl_pJAsWix3OgzBSmBPneL-dknHi4IL8NNoGYkH62mbIKVPlBqn52e9QtO7v_yFLxGrZEBC_Z7jsFQQDarKvKk5L1nmWLRUffZvNP0hEy9M93wPDVNZ7fU51jD15tpuj92gBKXIM2sM2KWXFiVqg5PhkT7FvFHii1f-cc0emUTvzlO-ZU3oV73eSiisAUjHK3CO-rWD_WCiSAy1YSSOgORY0NrpwcIY3iuwu8yKxunf2F_bYK8mZPyAiI87-KYctZA2BLRe3UVhcbdkXQqHMTbOe8_yRmm20RnsHNTAk7ZlPNUihqE4kxbK6T0Bm0rtWLx8kZHWqq_netnSDiLa8Jtxzxu6UrKOtoWi7P26FE4pGwS5vPVCJ1Z55IcOZ6kQ_I2JpZA49MFJw6YDhKVnJlBEw8D5DfRC7A2YJ1x7ZVufyrYKiew6FYPaj4hpM95SN7o2PXz-vgTvp0oM0qknmcqdtuMgQcuWR5NED6cYccQJ4DQV2Nodzn_bFokhIcqbQVeheE7Jzy2MrzF_CJ3bD2LEmTKgDeoRfH4f4APSh00c2JAqtrKGmF7yMpBYC4vTTnbjPD4shMEcwgMeQKv8rWIaoRZR68Uhd_qwhW-wLqLawd42RaMzKebvCX78epU6rMz1VAlhZzlKS1keFXp-5xXjy4JQcu_WY-GXqSv7ah8CWGItBFc2yW2vQaDfgeHxc5MZTg7Q_VJkGSIEhttIb_0na2S6UfKXczrF1aoBFCKfxirIrOs-VHvbQCyWXwUdKidKNIqexkOucVOo4MaDMMKYSX7LINIdf4WPwrsa2SBW_UpFp-jrjF-aHmykLShhIEv_nCAHGMmfPwbu3ZsARJYusP6vRL8JdVq7pigfBkcIONWRVO7aM0X4ae43bGPfIzzLkdOKIBMR7KFsAv-4THPPH3UWTUG0MN0dAQPAAd6Jbp2xe3heqTY1J84QLaPFRY66r6rmZDWt8yzFB2IqLlupMgINWWLL8e0v6BLd0C8_jc7kwHmMvaPoXlZwqVFXed47bJOFfDXgymjs9Uw2ubeb1VMydQFmftVwzFY0vFTqqAWWnHIw5udvxgCTXDv2daFOdWPfrE6wKqVb9azxmGGXsoLcigmzwapcHBIUHAKKBE8SO9G3ciUkVFnK1JQEJ8Q96TdxMbnaXsPfy_CDaNUQFTnLYatnTbNq2kr20TudmpMYbm3V6_51K-gZyBh0-ESsRtsW1xaD68FgwS2Hi4zgd5zmko4c4vh3ncQt5eWB4Zy3VPCcNSPvgEVv_1psLFVPWMhhrC7pwV0PeuEE9h-rr66lwV9cgFIJkQf1Q3NzXMOa65aNKvmjAfP40H6jDUrKW03_JH56kb3R9YwE4kDpkkSJzHUsbPLjWPUr6SOUQKT2je9oxE3ioEgtwAlnYlxf5JU_BPyj7EsgLPpe8ZIuaTn7pU_tU8fBo26MEn78g3rwaFZ7PpWn6DeMTG_hDvAaTSZ0qZ6bAqGoj1UP_XzuQOuRvdbO_jNsclKBfZPj3RQcx1c_4H51aKTrJrYLndXSzsMox2BLoNXuUYoDyIeu_J36iUid5W4M7gykJADbUZBIbag8ordczWIaIYGxJHpxqiZvluHO1ufCLYWj3r8GhNNU_BjdyCmisGVV1he4ZdRiNHNlpfAL5SSQv7QynjdrPTIwmugGfinfzq0E7-2MpEOtBxDwlZtLBQsHLracKuIjYorhTzbj2dnvCBWTdfeBnaut-x7dfKr8ReAZnfhn5-qtvJdwFfx77y3t1kUIEBFr1CTmpUh3q5SJtQvR8TeTcPJORHk31EnafeipUwT4JnqA3oEiiqXLs2wTlLAt1SOx-uwMmyMeBEOhK7FS7Tdwgr2f0K-oEaUP_3AAENamy7U975-bvrQC5NQR91rCee0_h13qvdnYG0S_OS1vswYCoq0Z2wnR6wa4nx-ZoEZmnH0YoGyIt14_gOGQ9X5TAWFNlqbbHzhsOUIrN6TM-f5HQzXF7X_V7c1rMtPR-ZlYeXu7lla81J3_eIO_XzOlD4BO2nosgagiT89GQB5Sj16Ehd_KGMPpCsvqOxg_UpPL_kQ7qJtDs8okP4YmvWjp4IHVD_CmV0kyA26B3tlwkD8IUHzlAq7Bxq3TKgnGIgxi0-scAmiMvN-TlXvDjBp0Uh-AWz2zxwAGqsq298xeLkPRpJJJECMlZVPppr2RdKgCyrqBhGLyWIjmIx5-jWY-1XuwT7cb9NGXe6RFfmCXVX_B_0_1ribDdgLMRtGXziYbI8qxmN3tsw6BmPEsDCuofe6Zqm97JipN17tTmv-rdOHeeV9UgeiYQ0xJe6Q9psmhHBxGW6LVp_e9dWt4-aYZ24hSGf8CileysyUV0etiXPh2fVacS4HKQXry29CMP6j6gO6Ca2T3CNIYYd_aG6hVBO4Lk6ENkS4kkl7Wen5tOTI5TCD0pGAIuHIwey-DIfqPbW-ZHhQO3sBYSVtHPMSXP3hrojuR1qEnFVrVyqLABusBzlqB2mAnvSKZRCpZ9VFGUABN6ytItEXv4JDIu8eo0IvMQmWRRguaADU5pBiyQZ_5C3UEyX_QveHmDri9IXaVQz_3a9gowZfMuGj9CVwuhCq8R3ZLclacFxWRFw6byEOm2KZb6jH5qemc-V-Ci1mtcIsOdVLFQXuHkiOyZE2zISd0ckGUWihME4lg0imlSu_XI1MjWwao049bmP0VD5iqqpccIVsJuNkrSmw15AcrHqjlVhIWrD8u6e90uBqvm_l-Yfxe78_cIl-VuWTTa1qI8yw-LeNWloZCTbls5pRQr7MCm5dkZeAt1PBdnBpXTk-8VcvlDsA_hheV-QVbrdP4UTtDArx6QfxDU8PNLMpMgovTDTn6WnaJpdP-WVTSYH-78a7rp01RAmIQTl12vXuNRhPtj7jlortf8YobH2jMog2vRc4uXQpqZyWtSr-BF4vhh7QfzK6myLiEj_ciHNXqd64WzYl__hPaULy2xkwkpnD6mWQnRkoNeFGA-kt0f5J-M4JrRG3qCOdVrccmyLye-vVQyVkqfqgau6YLXd3QdpJkmA7Puu0ie1BeQBnBG4nJcWvDE1R19MdYBT7v-IDTdFBTtPxc5KerxoUy-Zn7xzvmUt6rRuk0pmBwzriAtzZctD2PI8BfoC4zhP-xpMhcNNaqCUBUQ260pWVdhqUCpkoBrskVHMMndizoMbeIeAcdAp4-lI5l-6zTO2APjygljfVHHLjpbTxs1ZA8DYpjrmzWSC07IXpK54MR258kedSamj-6IcUY4OOVVsuLvioELKt5JHwx5oADllUevxdA6K-9vddx7tuhgvkBvL1TpSp0XxDGwH3dRJDFwcDl3ah_PaOAjc33Z2IlcnXynaERtl3ysxBoPSY_4KPn5NoWQ7YHxzA-zQMKaa9fpi2VLN8Ud8redK0EKc9WwKXp-zmJbCf-KBsVCbFcrj9WUz38x-Iv-JEwFnUVpfTporFsB2eYlAPaMrXbf4Vz-Um1nfSVuq0F1V4cCPtZK6I_H-KWLbIseWZxNTJCWlmCaBe7ZQgt8ICUXqspyD9OOU6VNfr0nU7aW0itJEnvmKSfxnj3wQhrmEJ7HsX8mRHaDqAQKCr5B8YT4FOqTISRnTgDsV16ZRp43TaWH4QFpeanUD3KvmpvvfYGXUKVHlud2dUwPCr5FNM1QRFG9cgMBJn3y7ewbuixmPAIU_se3fYA1nYBtMlPpSHMGfXsqrIlMGNXmwsTs7TjG-kLzFrSA2ku5ZFX6N4wQim45hr1fBHI3GDF7IwoHKVCjXLjrkdCOGW0mV-n5uOAJxu5r_Ire3WFys0V9nlPpp9vy40PaNbXTiO0bLZu2u7LVDKAmxvvHxpUZxtW6v5lzoJjhdy1j4yAYCSgctwmH1pwhe8-wzU3JU9Rt1LFTs9t0XRUq_HXAb2kTGBMvk4OuuE1huBo75zhmFb1DVTzjr3Lpx656PZNk_frJiwupQ3qQj7b77ud_OzWgmRcLfmV2HPratlaB7pHQy6srJX-z2So9VD6TdbUUuOlSoGmK6jd1aGMNyhc2SM99TMQsQwbMEpZQ5tkexBf3Yc2TzQKON23R6xP90ctuAD976TtM2mZhV8o_7oB8jY9pyNwyf4tRUz0TPGIWBGgv3XhPugBTB5gfkRWXRvmeA2-Q38To85FnGpZib0yhVqpfS1ol9fZ6qmGQtgN5iZkXceAhYJRBwIq3jZM5-9Kc4QUO4aW4V8P7OXY66kxtcaoxXFcaug_EXomyGVhvLJ99QDE1zxTfZZ99Z7ZbAhYKQhctP43NCx3WPN4P0dP4HOG1HDhCW4wFOdWTKXQOKA1wOhuGUGyxpi6DcnMkM-vCpbWfHNzeSOKOXkBHbKycZiQ13mAv-eKpd0wg15sgkX3XdzHu8Xxc8HqDxsdJoyK0kT9lA8Y8PpF03mwhSqmOpxM4RjLL5U6HSt4FxDSsdVoTr3bzlKplWA29yVjlOU9D0xcbp9_Vkb981glTcmIhmpkP-10LD88arU_kHIkv_Oprhm-sCnNgI0RzmH71j5RxUuJDEKvj-l9A3f4lLEudcJw8ZBe_y7voD2-wNJ55hB5hYjzX45A5JCGbh7bE45bdq-hZ7a5rHekQAKMe1YO0zRzrkUagXurtqAXrZcLAq6NREGetDb8ICCJWA9fYoBWwz1mIBzn0fXUZlPRST-N7btljgD9RqiScsTA5NmGVG63cFq7JR7q0Na6eXVAKBODjcF6pMa4LIExSQq6W8CgXnfmGGTQp7p48TR0wan6nvSCOaaqty0hnELs2AkOb3otvg3T8ISPj36kApd3M5NcOrxW87LV7WEaN2Xy3aHkhxhZNMhAWHAtQpeg66rIsBat_Enqw56zTnSdjbKAAM7_mda7iQg5QEHKPSxkN4J2dAwzG-XmWTQJZhhxkAG0PDpN0sZkXRORxQV9TRBGmXWarK_GWkw2oAFFtf4H2d1KxlNiNQ6t0_6tWvN5piuPQTPhkIDmbSpbELp_sxYPdp2EBGN_08JbukeZ7P7M-eC4ps1e3mU1-l5j53tc1pYmauqc16J7ulQUe4WTMNWBBg3rBKdnR_E2wWMsirHhRHw8PZwTMmczbHVLAg6TX_RAafz-OOPaqrq2B_m-teT_-89rMWmrhIDnZMUTKPNQiInT0KPqZhZ981yZqkcKPKtJ2wYtliN6DE-GfubhjhCeNEoijF5wx6CruwB8F68SqANak21pj6LFT-gUdVI0S40PGAG87FelsPUVVrOmQJjoLgeE_zaHi684rPgknZbKW9PI-w5DhXfqqwn-8Nw3zanwa9aQ6TNzmZ_3hExa3yn7E4YrGvQFNz2EcpvBmOLl_7aU6OB_ofPFc8xGgwWm2vQQnj2XIMW15AdD9Jw9C63LIfsBd9krF1v9SzmDHVe4C2yRjGoNmaHCpXmzGcCdKKYkLRIVR6jclh5-fs5rU0L4hQC9LjQoS946Dlt731DBShTzh-pzwFn3TwmCOzTw03px_cwGXubDcbV9UP3WwJ5lbmaa9Sb2LLyQ2CE4aDrNeQvIDjnCzkWVHdHDkcTpnaYZCGjOcpf1jcK6lEDN2DKxEosgVM_sR0wg1rKTsm-i_K3Q_ByyYGooRCNv8xTd2mD2YM7AeucLEXDJyNFu5GGjommw8Pm2iq_Y0WyXkkch-PUAnlaDhunHhi0e22faVzG3jfHfy77aArXiWekmRbWwMcWesUVGTP2MMLOSwdbvF4h2Ww84U-V2ez9DHVTjTeN88C9BbAbwVbK5QSLcmAEK89GdSgss4VOI71f-mWih_oAjkMinFQuWW6K2OCrB95lp4SUBlNPOClNOChG1OoRWmbXiejGW8LPIoNK84FsccgEOtk05kjng11Wszj8JTt049ip7xgs1JeFZnazDT0WBzkabPxEEgz1KrZJj7OKqPT3yHtxgZ-NOfXg0AvdJuThwuvKsrQwkQ12AuUDDiODLZtWuBP23Z8wp-IqySHGpC5yrcZkWVBF58n7gSTXcpjsPStPYIXzxmouuRTSujRUcPE3tVgdDoh1jZLZKEOO-z2PWHom508mFbioDC6gluzv9bEv9SyJQcblMbaRR1W7CbvU1W_w6j8wqUVf_ZT3j4zY7CHoSD6AkOrSITmK1nFoivUmZ56LI7ENM34H45TskDgrwV31Jfm9zbnihQ-RTKUrAxRYwCF-5VsoBParjjuJ6qoExAEPXn1Y-yYt6QC29baQVK1lcwuMt05y--cTx0xpDwsLqUki9q6MYQvFAg0toEyW_VNuCJCo8Chsp2VHgG3eNBTfwbQ2M6ipHcldDd5OaEJZmzk6phdbFbaGo8xCJ8PUqiQr3yd5hommaM3W7JgNvUHPif0q8olUK5um-qzUCBSizSzoigdv2vsduE6acPFaHw7I1E4ycTrB1W8FyEsWlMhzofReeoQLmnH0o8IEeGrWMFdrRe5yDw5BjixK_daKBK2REC7mctNl_nx-_DAsgoBjZWYn2cTN0f9nraM0p2PibFqLcOLo-prjcdirllamEIVCSKlgQeBs9VlS5gEFMknLEzeCjkHB3ZQvyo-7VO6N4cDAnSQ_QwZLwIzXZ1Zp1vx5Tc1J8foMb6DP8QU-v4lho48Ac8Pa7PSUTQX-ta3nukBreTGlqmYveL6zBK-K53rHPiZBcn4P3iJ89xCy41LZe6IeUMMejp_65uVSzwMEo1enpzEgFrECaZwt2WezJITOfy0A3VrIdMsGwerm9qpUbOcnxfpBIjkblJHyQ_L8Gdw0uhpQHR44HA4yRKHCsKPP9-J6OP9OakZ_a7kzdhfr8DHNwBb82CG5NCAoQf_i8rD1dImQjOHixPXIITj8NZbnxiUzAYoXBNTqqRsNp4qtd2oQ7mEjTlpIr2w1vm_rTmlfy2zYwL9nRpgkkgVSvhdUJXL052VHDEtyvks3AxxmU5Bx5KqriIzPEK3aLc5whMVpUKjGNPDXC00kCeUmWLaoO3r-9rOAcWJJR6XLN9MrJLiM05E5D1OITRlXIAF4WE31ttkG1v77lpn-VvFtPdYFWfHUVY3dE8ZllQdIjo861QQqxoWgYJYKerDERrtrb_A_oCP-g-iXHNejenr5vCXx5jfOpKfJrFt5mP1w8m-lQe0Nfi_faieqwIT1YypW-DaemCGAI3-CylaoM4qlL9U_mT1qVVkaPgTwoqYeY40W39N0_q4rk3I88HRsUBlCDp6nshfF92Q5pTCnFGDyVJYsBX93qiSvMZiOus2XlNrLF5tVzXP3wwFrmaXi6fRtrJNuq-9-oQWeernrWCP8ArOu2MLcZ81KpGOrVxXmyZt_BEo2UFayEXdVsrS32X76fDPTt7Oxj0iBKWXOcFX9fk0KHWAmaljnnC9pa0qJfR7gHiHFAV3P_RW8IkJNp8QxyVkmFWaFKRAmKTfiaAspbX8qqSiARmUhObJnsWRM6Nhj81GofbF0t15g1NuyZFNm49RCm6ARybWkucUCKqvsVftiKL6uQnVzp30Nx4HZoxWCOd_Viy6cq_E26_ObCN6rHD1v-xjdYKGrtfwHyT3KyZoIBxo0i_H-krjbWpAPn4PNCeEiejKGmkl2ZZDqrap1dE_-BLXtJ1t2BpB2jzAOnyW4Am4P0ELyT37D1JTLZacrrVn9gCdCle3LxbPm3N-3UBPU0g32Knp8ldD9wYVFRY3hDfIoUH7zPm217Q810oRTysntF8TKqtHlNn3cGp1n7iv9zTgS-E2GlFBuPlRM2QtxB3uOYoFE6dl5m8Hcf5ltUeZ9etbogBg3aqcIiCmgOZQqQ9C9QEIHkHLLaaR3eLGPy4Wel1ghGin2DLSaGM-gGSe0nEJdbyj2ctO41r65Xm24uhLxB29vFtcVlJszQedMmN3oifoGwUr0U-E6mAuuN0QfA3-XIn0G7bm6_bBB1fOLN-YTfl2cj1RdEweiQL5rFV7VQ5j_51-UdNZT70PjZab7qovXoYnPmX3NQEqgqq4QilQqrkhVDEZ-oZKZ0CKNa03vESEgCXTdeWmH4AZk-jU0aHK_wyfTmKHltA4VZPDERflMDVpkmZm6BnGACnQo7QmijENqr68fr6YjbrndRTSwungUCxEoZeyqcEJUGhnfn4yJWRb82YvXFkLry-hF7iw_wzGqo4QOhRlVdOWbqMO5Kt_0EOKKWtVARQYr96Y32pzw_Shb2NwotT5xpA2kPZoET2EDdobaAtVAV8h2e7ctCN3pCD-nzd50A0udREP0hl3Hl8L-j28gsEeDETXvfC4PRuZiyJU6F_ac_Qqvu-_wNtuWn_cId5nVbf-hg6YaOi9nAKuQGnlCFMhf1RfDs-Rqegqwvhs9HrXufQUbKpe9DOM4aeW05iSANWB6a3vhaaVJkMdsDc0rrpfQHJJkMht7Mq865810g==', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6', + signature='gAAAAABoxC0_aDtrISw_zls0dyams-nhm23et1xecYaqlI8y44ih0g9FA5T3R9ueXIOX9seSrysa48qci5QTep_TNFkxcjPMbWeQxolRKeCjWk0jLpC2FdKdscfb56KfeSTklKz_CaD-VubFOUgtqg8bQfJTvrdEtKj8Q74c2-XOtHTB-0OjenFtkZMtLMu3uc009ktnOSiWIxkuaDXcvgENQlU60WswxDC_3j92V9o0XsSnXxS8ZmvfWcmYxsFAo575ybwZin6GI709AxlJ6iPkSYIyRy_Sn_O2B68S5ABs8gq0yzaDtX2Wtibqys1NooceCWvxBSjZUKKD3N3FG9Hx_GzaUyvB5DblDmqgfP3AC_VfxaXm990esMW22fQvrEmuRNJc7AF0-KSBCNjatP6eHKj7WSiyGplUFCukk1tRHxOeDi9GD6s51_jTSyADenpzvdBLoELPR0JQIUuraSBpS3aZS8ODJDUbIX8niI_RYzRCvqBDMbLi9MaI_jTdEJknhEgmZZaV-53FXEVM7LoK6BWBpocwDC0zbcA-Da2rY6y3h_4x-PD-DL_W-V0_XDqwhx6NZOJBDpGrJIKY1BU-QjjEdZeXg1hv7CmLCH9ykOr-ja8B72fGaY2sJ9Lg2dFnaEkalEnYPCOY1hWDok1o5H0YVwA3MoZPr4VuFbGKD1EEAcB10UYgY5_WRK5Zk2CYK9EMOyLMA-_DU5qMLw0qrpj7lGRe7PLM0UYBbjP3jFZX6Gy5e1RcibH2MsrbfH4SlVkc1TTak4vuBEIR7Q4q8dYCoKTPgHAWFULzFbaCwhQQtyL1_lG-OpiGGUSZE_VRj3yVKbrv4Nz1l44ah5DdlG0BCiKthdMqcVxc3Bh3VKofIN6G_rArAtZ4ZmcoPVXIUlkfSPm9efNSx1tUpZPKkFk_dtP9B0dU5gD9F3tTU73I7CtuDaIXfe5JOBegu0_kBjEXb33s1B6mnUJJld1f3c13AwcRhMimtidTdtZFp4iAaKH0hWKrC6fOMlzTmz7O7R79sl_81XTQQbIR31yojRzDSvwhRoenyRWvQQMV4PeZ8h-2ioG2l0DQ89YRjkjeUEwZyog0ZWHflw3nr8zjJ7xkliqfJpspfE0scWrCq5KmY21vYkf3EcH-HU5s_S7_vo-JwnNIlTaDJUHbEo8sl_pJAsWix3OgzBSmBPneL-dknHi4IL8NNoGYkH62mbIKVPlBqn52e9QtO7v_yFLxGrZEBC_Z7jsFQQDarKvKk5L1nmWLRUffZvNP0hEy9M93wPDVNZ7fU51jD15tpuj92gBKXIM2sM2KWXFiVqg5PhkT7FvFHii1f-cc0emUTvzlO-ZU3oV73eSiisAUjHK3CO-rWD_WCiSAy1YSSOgORY0NrpwcIY3iuwu8yKxunf2F_bYK8mZPyAiI87-KYctZA2BLRe3UVhcbdkXQqHMTbOe8_yRmm20RnsHNTAk7ZlPNUihqE4kxbK6T0Bm0rtWLx8kZHWqq_netnSDiLa8Jtxzxu6UrKOtoWi7P26FE4pGwS5vPVCJ1Z55IcOZ6kQ_I2JpZA49MFJw6YDhKVnJlBEw8D5DfRC7A2YJ1x7ZVufyrYKiew6FYPaj4hpM95SN7o2PXz-vgTvp0oM0qknmcqdtuMgQcuWR5NED6cYccQJ4DQV2Nodzn_bFokhIcqbQVeheE7Jzy2MrzF_CJ3bD2LEmTKgDeoRfH4f4APSh00c2JAqtrKGmF7yMpBYC4vTTnbjPD4shMEcwgMeQKv8rWIaoRZR68Uhd_qwhW-wLqLawd42RaMzKebvCX78epU6rMz1VAlhZzlKS1keFXp-5xXjy4JQcu_WY-GXqSv7ah8CWGItBFc2yW2vQaDfgeHxc5MZTg7Q_VJkGSIEhttIb_0na2S6UfKXczrF1aoBFCKfxirIrOs-VHvbQCyWXwUdKidKNIqexkOucVOo4MaDMMKYSX7LINIdf4WPwrsa2SBW_UpFp-jrjF-aHmykLShhIEv_nCAHGMmfPwbu3ZsARJYusP6vRL8JdVq7pigfBkcIONWRVO7aM0X4ae43bGPfIzzLkdOKIBMR7KFsAv-4THPPH3UWTUG0MN0dAQPAAd6Jbp2xe3heqTY1J84QLaPFRY66r6rmZDWt8yzFB2IqLlupMgINWWLL8e0v6BLd0C8_jc7kwHmMvaPoXlZwqVFXed47bJOFfDXgymjs9Uw2ubeb1VMydQFmftVwzFY0vFTqqAWWnHIw5udvxgCTXDv2daFOdWPfrE6wKqVb9azxmGGXsoLcigmzwapcHBIUHAKKBE8SO9G3ciUkVFnK1JQEJ8Q96TdxMbnaXsPfy_CDaNUQFTnLYatnTbNq2kr20TudmpMYbm3V6_51K-gZyBh0-ESsRtsW1xaD68FgwS2Hi4zgd5zmko4c4vh3ncQt5eWB4Zy3VPCcNSPvgEVv_1psLFVPWMhhrC7pwV0PeuEE9h-rr66lwV9cgFIJkQf1Q3NzXMOa65aNKvmjAfP40H6jDUrKW03_JH56kb3R9YwE4kDpkkSJzHUsbPLjWPUr6SOUQKT2je9oxE3ioEgtwAlnYlxf5JU_BPyj7EsgLPpe8ZIuaTn7pU_tU8fBo26MEn78g3rwaFZ7PpWn6DeMTG_hDvAaTSZ0qZ6bAqGoj1UP_XzuQOuRvdbO_jNsclKBfZPj3RQcx1c_4H51aKTrJrYLndXSzsMox2BLoNXuUYoDyIeu_J36iUid5W4M7gykJADbUZBIbag8ordczWIaIYGxJHpxqiZvluHO1ufCLYWj3r8GhNNU_BjdyCmisGVV1he4ZdRiNHNlpfAL5SSQv7QynjdrPTIwmugGfinfzq0E7-2MpEOtBxDwlZtLBQsHLracKuIjYorhTzbj2dnvCBWTdfeBnaut-x7dfKr8ReAZnfhn5-qtvJdwFfx77y3t1kUIEBFr1CTmpUh3q5SJtQvR8TeTcPJORHk31EnafeipUwT4JnqA3oEiiqXLs2wTlLAt1SOx-uwMmyMeBEOhK7FS7Tdwgr2f0K-oEaUP_3AAENamy7U975-bvrQC5NQR91rCee0_h13qvdnYG0S_OS1vswYCoq0Z2wnR6wa4nx-ZoEZmnH0YoGyIt14_gOGQ9X5TAWFNlqbbHzhsOUIrN6TM-f5HQzXF7X_V7c1rMtPR-ZlYeXu7lla81J3_eIO_XzOlD4BO2nosgagiT89GQB5Sj16Ehd_KGMPpCsvqOxg_UpPL_kQ7qJtDs8okP4YmvWjp4IHVD_CmV0kyA26B3tlwkD8IUHzlAq7Bxq3TKgnGIgxi0-scAmiMvN-TlXvDjBp0Uh-AWz2zxwAGqsq298xeLkPRpJJJECMlZVPppr2RdKgCyrqBhGLyWIjmIx5-jWY-1XuwT7cb9NGXe6RFfmCXVX_B_0_1ribDdgLMRtGXziYbI8qxmN3tsw6BmPEsDCuofe6Zqm97JipN17tTmv-rdOHeeV9UgeiYQ0xJe6Q9psmhHBxGW6LVp_e9dWt4-aYZ24hSGf8CileysyUV0etiXPh2fVacS4HKQXry29CMP6j6gO6Ca2T3CNIYYd_aG6hVBO4Lk6ENkS4kkl7Wen5tOTI5TCD0pGAIuHIwey-DIfqPbW-ZHhQO3sBYSVtHPMSXP3hrojuR1qEnFVrVyqLABusBzlqB2mAnvSKZRCpZ9VFGUABN6ytItEXv4JDIu8eo0IvMQmWRRguaADU5pBiyQZ_5C3UEyX_QveHmDri9IXaVQz_3a9gowZfMuGj9CVwuhCq8R3ZLclacFxWRFw6byEOm2KZb6jH5qemc-V-Ci1mtcIsOdVLFQXuHkiOyZE2zISd0ckGUWihME4lg0imlSu_XI1MjWwao049bmP0VD5iqqpccIVsJuNkrSmw15AcrHqjlVhIWrD8u6e90uBqvm_l-Yfxe78_cIl-VuWTTa1qI8yw-LeNWloZCTbls5pRQr7MCm5dkZeAt1PBdnBpXTk-8VcvlDsA_hheV-QVbrdP4UTtDArx6QfxDU8PNLMpMgovTDTn6WnaJpdP-WVTSYH-78a7rp01RAmIQTl12vXuNRhPtj7jlortf8YobH2jMog2vRc4uXQpqZyWtSr-BF4vhh7QfzK6myLiEj_ciHNXqd64WzYl__hPaULy2xkwkpnD6mWQnRkoNeFGA-kt0f5J-M4JrRG3qCOdVrccmyLye-vVQyVkqfqgau6YLXd3QdpJkmA7Puu0ie1BeQBnBG4nJcWvDE1R19MdYBT7v-IDTdFBTtPxc5KerxoUy-Zn7xzvmUt6rRuk0pmBwzriAtzZctD2PI8BfoC4zhP-xpMhcNNaqCUBUQ260pWVdhqUCpkoBrskVHMMndizoMbeIeAcdAp4-lI5l-6zTO2APjygljfVHHLjpbTxs1ZA8DYpjrmzWSC07IXpK54MR258kedSamj-6IcUY4OOVVsuLvioELKt5JHwx5oADllUevxdA6K-9vddx7tuhgvkBvL1TpSp0XxDGwH3dRJDFwcDl3ah_PaOAjc33Z2IlcnXynaERtl3ysxBoPSY_4KPn5NoWQ7YHxzA-zQMKaa9fpi2VLN8Ud8redK0EKc9WwKXp-zmJbCf-KBsVCbFcrj9WUz38x-Iv-JEwFnUVpfTporFsB2eYlAPaMrXbf4Vz-Um1nfSVuq0F1V4cCPtZK6I_H-KWLbIseWZxNTJCWlmCaBe7ZQgt8ICUXqspyD9OOU6VNfr0nU7aW0itJEnvmKSfxnj3wQhrmEJ7HsX8mRHaDqAQKCr5B8YT4FOqTISRnTgDsV16ZRp43TaWH4QFpeanUD3KvmpvvfYGXUKVHlud2dUwPCr5FNM1QRFG9cgMBJn3y7ewbuixmPAIU_se3fYA1nYBtMlPpSHMGfXsqrIlMGNXmwsTs7TjG-kLzFrSA2ku5ZFX6N4wQim45hr1fBHI3GDF7IwoHKVCjXLjrkdCOGW0mV-n5uOAJxu5r_Ire3WFys0V9nlPpp9vy40PaNbXTiO0bLZu2u7LVDKAmxvvHxpUZxtW6v5lzoJjhdy1j4yAYCSgctwmH1pwhe8-wzU3JU9Rt1LFTs9t0XRUq_HXAb2kTGBMvk4OuuE1huBo75zhmFb1DVTzjr3Lpx656PZNk_frJiwupQ3qQj7b77ud_OzWgmRcLfmV2HPratlaB7pHQy6srJX-z2So9VD6TdbUUuOlSoGmK6jd1aGMNyhc2SM99TMQsQwbMEpZQ5tkexBf3Yc2TzQKON23R6xP90ctuAD976TtM2mZhV8o_7oB8jY9pyNwyf4tRUz0TPGIWBGgv3XhPugBTB5gfkRWXRvmeA2-Q38To85FnGpZib0yhVqpfS1ol9fZ6qmGQtgN5iZkXceAhYJRBwIq3jZM5-9Kc4QUO4aW4V8P7OXY66kxtcaoxXFcaug_EXomyGVhvLJ99QDE1zxTfZZ99Z7ZbAhYKQhctP43NCx3WPN4P0dP4HOG1HDhCW4wFOdWTKXQOKA1wOhuGUGyxpi6DcnMkM-vCpbWfHNzeSOKOXkBHbKycZiQ13mAv-eKpd0wg15sgkX3XdzHu8Xxc8HqDxsdJoyK0kT9lA8Y8PpF03mwhSqmOpxM4RjLL5U6HSt4FxDSsdVoTr3bzlKplWA29yVjlOU9D0xcbp9_Vkb981glTcmIhmpkP-10LD88arU_kHIkv_Oprhm-sCnNgI0RzmH71j5RxUuJDEKvj-l9A3f4lLEudcJw8ZBe_y7voD2-wNJ55hB5hYjzX45A5JCGbh7bE45bdq-hZ7a5rHekQAKMe1YO0zRzrkUagXurtqAXrZcLAq6NREGetDb8ICCJWA9fYoBWwz1mIBzn0fXUZlPRST-N7btljgD9RqiScsTA5NmGVG63cFq7JR7q0Na6eXVAKBODjcF6pMa4LIExSQq6W8CgXnfmGGTQp7p48TR0wan6nvSCOaaqty0hnELs2AkOb3otvg3T8ISPj36kApd3M5NcOrxW87LV7WEaN2Xy3aHkhxhZNMhAWHAtQpeg66rIsBat_Enqw56zTnSdjbKAAM7_mda7iQg5QEHKPSxkN4J2dAwzG-XmWTQJZhhxkAG0PDpN0sZkXRORxQV9TRBGmXWarK_GWkw2oAFFtf4H2d1KxlNiNQ6t0_6tWvN5piuPQTPhkIDmbSpbELp_sxYPdp2EBGN_08JbukeZ7P7M-eC4ps1e3mU1-l5j53tc1pYmauqc16J7ulQUe4WTMNWBBg3rBKdnR_E2wWMsirHhRHw8PZwTMmczbHVLAg6TX_RAafz-OOPaqrq2B_m-teT_-89rMWmrhIDnZMUTKPNQiInT0KPqZhZ981yZqkcKPKtJ2wYtliN6DE-GfubhjhCeNEoijF5wx6CruwB8F68SqANak21pj6LFT-gUdVI0S40PGAG87FelsPUVVrOmQJjoLgeE_zaHi684rPgknZbKW9PI-w5DhXfqqwn-8Nw3zanwa9aQ6TNzmZ_3hExa3yn7E4YrGvQFNz2EcpvBmOLl_7aU6OB_ofPFc8xGgwWm2vQQnj2XIMW15AdD9Jw9C63LIfsBd9krF1v9SzmDHVe4C2yRjGoNmaHCpXmzGcCdKKYkLRIVR6jclh5-fs5rU0L4hQC9LjQoS946Dlt731DBShTzh-pzwFn3TwmCOzTw03px_cwGXubDcbV9UP3WwJ5lbmaa9Sb2LLyQ2CE4aDrNeQvIDjnCzkWVHdHDkcTpnaYZCGjOcpf1jcK6lEDN2DKxEosgVM_sR0wg1rKTsm-i_K3Q_ByyYGooRCNv8xTd2mD2YM7AeucLEXDJyNFu5GGjommw8Pm2iq_Y0WyXkkch-PUAnlaDhunHhi0e22faVzG3jfHfy77aArXiWekmRbWwMcWesUVGTP2MMLOSwdbvF4h2Ww84U-V2ez9DHVTjTeN88C9BbAbwVbK5QSLcmAEK89GdSgss4VOI71f-mWih_oAjkMinFQuWW6K2OCrB95lp4SUBlNPOClNOChG1OoRWmbXiejGW8LPIoNK84FsccgEOtk05kjng11Wszj8JTt049ip7xgs1JeFZnazDT0WBzkabPxEEgz1KrZJj7OKqPT3yHtxgZ-NOfXg0AvdJuThwuvKsrQwkQ12AuUDDiODLZtWuBP23Z8wp-IqySHGpC5yrcZkWVBF58n7gSTXcpjsPStPYIXzxmouuRTSujRUcPE3tVgdDoh1jZLZKEOO-z2PWHom508mFbioDC6gluzv9bEv9SyJQcblMbaRR1W7CbvU1W_w6j8wqUVf_ZT3j4zY7CHoSD6AkOrSITmK1nFoivUmZ56LI7ENM34H45TskDgrwV31Jfm9zbnihQ-RTKUrAxRYwCF-5VsoBParjjuJ6qoExAEPXn1Y-yYt6QC29baQVK1lcwuMt05y--cTx0xpDwsLqUki9q6MYQvFAg0toEyW_VNuCJCo8Chsp2VHgG3eNBTfwbQ2M6ipHcldDd5OaEJZmzk6phdbFbaGo8xCJ8PUqiQr3yd5hommaM3W7JgNvUHPif0q8olUK5um-qzUCBSizSzoigdv2vsduE6acPFaHw7I1E4ycTrB1W8FyEsWlMhzofReeoQLmnH0o8IEeGrWMFdrRe5yDw5BjixK_daKBK2REC7mctNl_nx-_DAsgoBjZWYn2cTN0f9nraM0p2PibFqLcOLo-prjcdirllamEIVCSKlgQeBs9VlS5gEFMknLEzeCjkHB3ZQvyo-7VO6N4cDAnSQ_QwZLwIzXZ1Zp1vx5Tc1J8foMb6DP8QU-v4lho48Ac8Pa7PSUTQX-ta3nukBreTGlqmYveL6zBK-K53rHPiZBcn4P3iJ89xCy41LZe6IeUMMejp_65uVSzwMEo1enpzEgFrECaZwt2WezJITOfy0A3VrIdMsGwerm9qpUbOcnxfpBIjkblJHyQ_L8Gdw0uhpQHR44HA4yRKHCsKPP9-J6OP9OakZ_a7kzdhfr8DHNwBb82CG5NCAoQf_i8rD1dImQjOHixPXIITj8NZbnxiUzAYoXBNTqqRsNp4qtd2oQ7mEjTlpIr2w1vm_rTmlfy2zYwL9nRpgkkgVSvhdUJXL052VHDEtyvks3AxxmU5Bx5KqriIzPEK3aLc5whMVpUKjGNPDXC00kCeUmWLaoO3r-9rOAcWJJR6XLN9MrJLiM05E5D1OITRlXIAF4WE31ttkG1v77lpn-VvFtPdYFWfHUVY3dE8ZllQdIjo861QQqxoWgYJYKerDERrtrb_A_oCP-g-iXHNejenr5vCXx5jfOpKfJrFt5mP1w8m-lQe0Nfi_faieqwIT1YypW-DaemCGAI3-CylaoM4qlL9U_mT1qVVkaPgTwoqYeY40W39N0_q4rk3I88HRsUBlCDp6nshfF92Q5pTCnFGDyVJYsBX93qiSvMZiOus2XlNrLF5tVzXP3wwFrmaXi6fRtrJNuq-9-oQWeernrWCP8ArOu2MLcZ81KpGOrVxXmyZt_BEo2UFayEXdVsrS32X76fDPTt7Oxj0iBKWXOcFX9fk0KHWAmaljnnC9pa0qJfR7gHiHFAV3P_RW8IkJNp8QxyVkmFWaFKRAmKTfiaAspbX8qqSiARmUhObJnsWRM6Nhj81GofbF0t15g1NuyZFNm49RCm6ARybWkucUCKqvsVftiKL6uQnVzp30Nx4HZoxWCOd_Viy6cq_E26_ObCN6rHD1v-xjdYKGrtfwHyT3KyZoIBxo0i_H-krjbWpAPn4PNCeEiejKGmkl2ZZDqrap1dE_-BLXtJ1t2BpB2jzAOnyW4Am4P0ELyT37D1JTLZacrrVn9gCdCle3LxbPm3N-3UBPU0g32Knp8ldD9wYVFRY3hDfIoUH7zPm217Q810oRTysntF8TKqtHlNn3cGp1n7iv9zTgS-E2GlFBuPlRM2QtxB3uOYoFE6dl5m8Hcf5ltUeZ9etbogBg3aqcIiCmgOZQqQ9C9QEIHkHLLaaR3eLGPy4Wel1ghGin2DLSaGM-gGSe0nEJdbyj2ctO41r65Xm24uhLxB29vFtcVlJszQedMmN3oifoGwUr0U-E6mAuuN0QfA3-XIn0G7bm6_bBB1fOLN-YTfl2cj1RdEweiQL5rFV7VQ5j_51-UdNZT70PjZab7qovXoYnPmX3NQEqgqq4QilQqrkhVDEZ-oZKZ0CKNa03vESEgCXTdeWmH4AZk-jU0aHK_wyfTmKHltA4VZPDERflMDVpkmZm6BnGACnQo7QmijENqr68fr6YjbrndRTSwungUCxEoZeyqcEJUGhnfn4yJWRb82YvXFkLry-hF7iw_wzGqo4QOhRlVdOWbqMO5Kt_0EOKKWtVARQYr96Y32pzw_Shb2NwotT5xpA2kPZoET2EDdobaAtVAV8h2e7ctCN3pCD-nzd50A0udREP0hl3Hl8L-j28gsEeDETXvfC4PRuZiyJU6F_ac_Qqvu-_wNtuWn_cId5nVbf-hg6YaOi9nAKuQGnlCFMhf1RfDs-Rqegqwvhs9HrXufQUbKpe9DOM4aeW05iSANWB6a3vhaaVJkMdsDc0rrpfQHJJkMht7Mq865810g==', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6', + signature='gAAAAABoxC0_aDtrISw_zls0dyams-nhm23et1xecYaqlI8y44ih0g9FA5T3R9ueXIOX9seSrysa48qci5QTep_TNFkxcjPMbWeQxolRKeCjWk0jLpC2FdKdscfb56KfeSTklKz_CaD-VubFOUgtqg8bQfJTvrdEtKj8Q74c2-XOtHTB-0OjenFtkZMtLMu3uc009ktnOSiWIxkuaDXcvgENQlU60WswxDC_3j92V9o0XsSnXxS8ZmvfWcmYxsFAo575ybwZin6GI709AxlJ6iPkSYIyRy_Sn_O2B68S5ABs8gq0yzaDtX2Wtibqys1NooceCWvxBSjZUKKD3N3FG9Hx_GzaUyvB5DblDmqgfP3AC_VfxaXm990esMW22fQvrEmuRNJc7AF0-KSBCNjatP6eHKj7WSiyGplUFCukk1tRHxOeDi9GD6s51_jTSyADenpzvdBLoELPR0JQIUuraSBpS3aZS8ODJDUbIX8niI_RYzRCvqBDMbLi9MaI_jTdEJknhEgmZZaV-53FXEVM7LoK6BWBpocwDC0zbcA-Da2rY6y3h_4x-PD-DL_W-V0_XDqwhx6NZOJBDpGrJIKY1BU-QjjEdZeXg1hv7CmLCH9ykOr-ja8B72fGaY2sJ9Lg2dFnaEkalEnYPCOY1hWDok1o5H0YVwA3MoZPr4VuFbGKD1EEAcB10UYgY5_WRK5Zk2CYK9EMOyLMA-_DU5qMLw0qrpj7lGRe7PLM0UYBbjP3jFZX6Gy5e1RcibH2MsrbfH4SlVkc1TTak4vuBEIR7Q4q8dYCoKTPgHAWFULzFbaCwhQQtyL1_lG-OpiGGUSZE_VRj3yVKbrv4Nz1l44ah5DdlG0BCiKthdMqcVxc3Bh3VKofIN6G_rArAtZ4ZmcoPVXIUlkfSPm9efNSx1tUpZPKkFk_dtP9B0dU5gD9F3tTU73I7CtuDaIXfe5JOBegu0_kBjEXb33s1B6mnUJJld1f3c13AwcRhMimtidTdtZFp4iAaKH0hWKrC6fOMlzTmz7O7R79sl_81XTQQbIR31yojRzDSvwhRoenyRWvQQMV4PeZ8h-2ioG2l0DQ89YRjkjeUEwZyog0ZWHflw3nr8zjJ7xkliqfJpspfE0scWrCq5KmY21vYkf3EcH-HU5s_S7_vo-JwnNIlTaDJUHbEo8sl_pJAsWix3OgzBSmBPneL-dknHi4IL8NNoGYkH62mbIKVPlBqn52e9QtO7v_yFLxGrZEBC_Z7jsFQQDarKvKk5L1nmWLRUffZvNP0hEy9M93wPDVNZ7fU51jD15tpuj92gBKXIM2sM2KWXFiVqg5PhkT7FvFHii1f-cc0emUTvzlO-ZU3oV73eSiisAUjHK3CO-rWD_WCiSAy1YSSOgORY0NrpwcIY3iuwu8yKxunf2F_bYK8mZPyAiI87-KYctZA2BLRe3UVhcbdkXQqHMTbOe8_yRmm20RnsHNTAk7ZlPNUihqE4kxbK6T0Bm0rtWLx8kZHWqq_netnSDiLa8Jtxzxu6UrKOtoWi7P26FE4pGwS5vPVCJ1Z55IcOZ6kQ_I2JpZA49MFJw6YDhKVnJlBEw8D5DfRC7A2YJ1x7ZVufyrYKiew6FYPaj4hpM95SN7o2PXz-vgTvp0oM0qknmcqdtuMgQcuWR5NED6cYccQJ4DQV2Nodzn_bFokhIcqbQVeheE7Jzy2MrzF_CJ3bD2LEmTKgDeoRfH4f4APSh00c2JAqtrKGmF7yMpBYC4vTTnbjPD4shMEcwgMeQKv8rWIaoRZR68Uhd_qwhW-wLqLawd42RaMzKebvCX78epU6rMz1VAlhZzlKS1keFXp-5xXjy4JQcu_WY-GXqSv7ah8CWGItBFc2yW2vQaDfgeHxc5MZTg7Q_VJkGSIEhttIb_0na2S6UfKXczrF1aoBFCKfxirIrOs-VHvbQCyWXwUdKidKNIqexkOucVOo4MaDMMKYSX7LINIdf4WPwrsa2SBW_UpFp-jrjF-aHmykLShhIEv_nCAHGMmfPwbu3ZsARJYusP6vRL8JdVq7pigfBkcIONWRVO7aM0X4ae43bGPfIzzLkdOKIBMR7KFsAv-4THPPH3UWTUG0MN0dAQPAAd6Jbp2xe3heqTY1J84QLaPFRY66r6rmZDWt8yzFB2IqLlupMgINWWLL8e0v6BLd0C8_jc7kwHmMvaPoXlZwqVFXed47bJOFfDXgymjs9Uw2ubeb1VMydQFmftVwzFY0vFTqqAWWnHIw5udvxgCTXDv2daFOdWPfrE6wKqVb9azxmGGXsoLcigmzwapcHBIUHAKKBE8SO9G3ciUkVFnK1JQEJ8Q96TdxMbnaXsPfy_CDaNUQFTnLYatnTbNq2kr20TudmpMYbm3V6_51K-gZyBh0-ESsRtsW1xaD68FgwS2Hi4zgd5zmko4c4vh3ncQt5eWB4Zy3VPCcNSPvgEVv_1psLFVPWMhhrC7pwV0PeuEE9h-rr66lwV9cgFIJkQf1Q3NzXMOa65aNKvmjAfP40H6jDUrKW03_JH56kb3R9YwE4kDpkkSJzHUsbPLjWPUr6SOUQKT2je9oxE3ioEgtwAlnYlxf5JU_BPyj7EsgLPpe8ZIuaTn7pU_tU8fBo26MEn78g3rwaFZ7PpWn6DeMTG_hDvAaTSZ0qZ6bAqGoj1UP_XzuQOuRvdbO_jNsclKBfZPj3RQcx1c_4H51aKTrJrYLndXSzsMox2BLoNXuUYoDyIeu_J36iUid5W4M7gykJADbUZBIbag8ordczWIaIYGxJHpxqiZvluHO1ufCLYWj3r8GhNNU_BjdyCmisGVV1he4ZdRiNHNlpfAL5SSQv7QynjdrPTIwmugGfinfzq0E7-2MpEOtBxDwlZtLBQsHLracKuIjYorhTzbj2dnvCBWTdfeBnaut-x7dfKr8ReAZnfhn5-qtvJdwFfx77y3t1kUIEBFr1CTmpUh3q5SJtQvR8TeTcPJORHk31EnafeipUwT4JnqA3oEiiqXLs2wTlLAt1SOx-uwMmyMeBEOhK7FS7Tdwgr2f0K-oEaUP_3AAENamy7U975-bvrQC5NQR91rCee0_h13qvdnYG0S_OS1vswYCoq0Z2wnR6wa4nx-ZoEZmnH0YoGyIt14_gOGQ9X5TAWFNlqbbHzhsOUIrN6TM-f5HQzXF7X_V7c1rMtPR-ZlYeXu7lla81J3_eIO_XzOlD4BO2nosgagiT89GQB5Sj16Ehd_KGMPpCsvqOxg_UpPL_kQ7qJtDs8okP4YmvWjp4IHVD_CmV0kyA26B3tlwkD8IUHzlAq7Bxq3TKgnGIgxi0-scAmiMvN-TlXvDjBp0Uh-AWz2zxwAGqsq298xeLkPRpJJJECMlZVPppr2RdKgCyrqBhGLyWIjmIx5-jWY-1XuwT7cb9NGXe6RFfmCXVX_B_0_1ribDdgLMRtGXziYbI8qxmN3tsw6BmPEsDCuofe6Zqm97JipN17tTmv-rdOHeeV9UgeiYQ0xJe6Q9psmhHBxGW6LVp_e9dWt4-aYZ24hSGf8CileysyUV0etiXPh2fVacS4HKQXry29CMP6j6gO6Ca2T3CNIYYd_aG6hVBO4Lk6ENkS4kkl7Wen5tOTI5TCD0pGAIuHIwey-DIfqPbW-ZHhQO3sBYSVtHPMSXP3hrojuR1qEnFVrVyqLABusBzlqB2mAnvSKZRCpZ9VFGUABN6ytItEXv4JDIu8eo0IvMQmWRRguaADU5pBiyQZ_5C3UEyX_QveHmDri9IXaVQz_3a9gowZfMuGj9CVwuhCq8R3ZLclacFxWRFw6byEOm2KZb6jH5qemc-V-Ci1mtcIsOdVLFQXuHkiOyZE2zISd0ckGUWihME4lg0imlSu_XI1MjWwao049bmP0VD5iqqpccIVsJuNkrSmw15AcrHqjlVhIWrD8u6e90uBqvm_l-Yfxe78_cIl-VuWTTa1qI8yw-LeNWloZCTbls5pRQr7MCm5dkZeAt1PBdnBpXTk-8VcvlDsA_hheV-QVbrdP4UTtDArx6QfxDU8PNLMpMgovTDTn6WnaJpdP-WVTSYH-78a7rp01RAmIQTl12vXuNRhPtj7jlortf8YobH2jMog2vRc4uXQpqZyWtSr-BF4vhh7QfzK6myLiEj_ciHNXqd64WzYl__hPaULy2xkwkpnD6mWQnRkoNeFGA-kt0f5J-M4JrRG3qCOdVrccmyLye-vVQyVkqfqgau6YLXd3QdpJkmA7Puu0ie1BeQBnBG4nJcWvDE1R19MdYBT7v-IDTdFBTtPxc5KerxoUy-Zn7xzvmUt6rRuk0pmBwzriAtzZctD2PI8BfoC4zhP-xpMhcNNaqCUBUQ260pWVdhqUCpkoBrskVHMMndizoMbeIeAcdAp4-lI5l-6zTO2APjygljfVHHLjpbTxs1ZA8DYpjrmzWSC07IXpK54MR258kedSamj-6IcUY4OOVVsuLvioELKt5JHwx5oADllUevxdA6K-9vddx7tuhgvkBvL1TpSp0XxDGwH3dRJDFwcDl3ah_PaOAjc33Z2IlcnXynaERtl3ysxBoPSY_4KPn5NoWQ7YHxzA-zQMKaa9fpi2VLN8Ud8redK0EKc9WwKXp-zmJbCf-KBsVCbFcrj9WUz38x-Iv-JEwFnUVpfTporFsB2eYlAPaMrXbf4Vz-Um1nfSVuq0F1V4cCPtZK6I_H-KWLbIseWZxNTJCWlmCaBe7ZQgt8ICUXqspyD9OOU6VNfr0nU7aW0itJEnvmKSfxnj3wQhrmEJ7HsX8mRHaDqAQKCr5B8YT4FOqTISRnTgDsV16ZRp43TaWH4QFpeanUD3KvmpvvfYGXUKVHlud2dUwPCr5FNM1QRFG9cgMBJn3y7ewbuixmPAIU_se3fYA1nYBtMlPpSHMGfXsqrIlMGNXmwsTs7TjG-kLzFrSA2ku5ZFX6N4wQim45hr1fBHI3GDF7IwoHKVCjXLjrkdCOGW0mV-n5uOAJxu5r_Ire3WFys0V9nlPpp9vy40PaNbXTiO0bLZu2u7LVDKAmxvvHxpUZxtW6v5lzoJjhdy1j4yAYCSgctwmH1pwhe8-wzU3JU9Rt1LFTs9t0XRUq_HXAb2kTGBMvk4OuuE1huBo75zhmFb1DVTzjr3Lpx656PZNk_frJiwupQ3qQj7b77ud_OzWgmRcLfmV2HPratlaB7pHQy6srJX-z2So9VD6TdbUUuOlSoGmK6jd1aGMNyhc2SM99TMQsQwbMEpZQ5tkexBf3Yc2TzQKON23R6xP90ctuAD976TtM2mZhV8o_7oB8jY9pyNwyf4tRUz0TPGIWBGgv3XhPugBTB5gfkRWXRvmeA2-Q38To85FnGpZib0yhVqpfS1ol9fZ6qmGQtgN5iZkXceAhYJRBwIq3jZM5-9Kc4QUO4aW4V8P7OXY66kxtcaoxXFcaug_EXomyGVhvLJ99QDE1zxTfZZ99Z7ZbAhYKQhctP43NCx3WPN4P0dP4HOG1HDhCW4wFOdWTKXQOKA1wOhuGUGyxpi6DcnMkM-vCpbWfHNzeSOKOXkBHbKycZiQ13mAv-eKpd0wg15sgkX3XdzHu8Xxc8HqDxsdJoyK0kT9lA8Y8PpF03mwhSqmOpxM4RjLL5U6HSt4FxDSsdVoTr3bzlKplWA29yVjlOU9D0xcbp9_Vkb981glTcmIhmpkP-10LD88arU_kHIkv_Oprhm-sCnNgI0RzmH71j5RxUuJDEKvj-l9A3f4lLEudcJw8ZBe_y7voD2-wNJ55hB5hYjzX45A5JCGbh7bE45bdq-hZ7a5rHekQAKMe1YO0zRzrkUagXurtqAXrZcLAq6NREGetDb8ICCJWA9fYoBWwz1mIBzn0fXUZlPRST-N7btljgD9RqiScsTA5NmGVG63cFq7JR7q0Na6eXVAKBODjcF6pMa4LIExSQq6W8CgXnfmGGTQp7p48TR0wan6nvSCOaaqty0hnELs2AkOb3otvg3T8ISPj36kApd3M5NcOrxW87LV7WEaN2Xy3aHkhxhZNMhAWHAtQpeg66rIsBat_Enqw56zTnSdjbKAAM7_mda7iQg5QEHKPSxkN4J2dAwzG-XmWTQJZhhxkAG0PDpN0sZkXRORxQV9TRBGmXWarK_GWkw2oAFFtf4H2d1KxlNiNQ6t0_6tWvN5piuPQTPhkIDmbSpbELp_sxYPdp2EBGN_08JbukeZ7P7M-eC4ps1e3mU1-l5j53tc1pYmauqc16J7ulQUe4WTMNWBBg3rBKdnR_E2wWMsirHhRHw8PZwTMmczbHVLAg6TX_RAafz-OOPaqrq2B_m-teT_-89rMWmrhIDnZMUTKPNQiInT0KPqZhZ981yZqkcKPKtJ2wYtliN6DE-GfubhjhCeNEoijF5wx6CruwB8F68SqANak21pj6LFT-gUdVI0S40PGAG87FelsPUVVrOmQJjoLgeE_zaHi684rPgknZbKW9PI-w5DhXfqqwn-8Nw3zanwa9aQ6TNzmZ_3hExa3yn7E4YrGvQFNz2EcpvBmOLl_7aU6OB_ofPFc8xGgwWm2vQQnj2XIMW15AdD9Jw9C63LIfsBd9krF1v9SzmDHVe4C2yRjGoNmaHCpXmzGcCdKKYkLRIVR6jclh5-fs5rU0L4hQC9LjQoS946Dlt731DBShTzh-pzwFn3TwmCOzTw03px_cwGXubDcbV9UP3WwJ5lbmaa9Sb2LLyQ2CE4aDrNeQvIDjnCzkWVHdHDkcTpnaYZCGjOcpf1jcK6lEDN2DKxEosgVM_sR0wg1rKTsm-i_K3Q_ByyYGooRCNv8xTd2mD2YM7AeucLEXDJyNFu5GGjommw8Pm2iq_Y0WyXkkch-PUAnlaDhunHhi0e22faVzG3jfHfy77aArXiWekmRbWwMcWesUVGTP2MMLOSwdbvF4h2Ww84U-V2ez9DHVTjTeN88C9BbAbwVbK5QSLcmAEK89GdSgss4VOI71f-mWih_oAjkMinFQuWW6K2OCrB95lp4SUBlNPOClNOChG1OoRWmbXiejGW8LPIoNK84FsccgEOtk05kjng11Wszj8JTt049ip7xgs1JeFZnazDT0WBzkabPxEEgz1KrZJj7OKqPT3yHtxgZ-NOfXg0AvdJuThwuvKsrQwkQ12AuUDDiODLZtWuBP23Z8wp-IqySHGpC5yrcZkWVBF58n7gSTXcpjsPStPYIXzxmouuRTSujRUcPE3tVgdDoh1jZLZKEOO-z2PWHom508mFbioDC6gluzv9bEv9SyJQcblMbaRR1W7CbvU1W_w6j8wqUVf_ZT3j4zY7CHoSD6AkOrSITmK1nFoivUmZ56LI7ENM34H45TskDgrwV31Jfm9zbnihQ-RTKUrAxRYwCF-5VsoBParjjuJ6qoExAEPXn1Y-yYt6QC29baQVK1lcwuMt05y--cTx0xpDwsLqUki9q6MYQvFAg0toEyW_VNuCJCo8Chsp2VHgG3eNBTfwbQ2M6ipHcldDd5OaEJZmzk6phdbFbaGo8xCJ8PUqiQr3yd5hommaM3W7JgNvUHPif0q8olUK5um-qzUCBSizSzoigdv2vsduE6acPFaHw7I1E4ycTrB1W8FyEsWlMhzofReeoQLmnH0o8IEeGrWMFdrRe5yDw5BjixK_daKBK2REC7mctNl_nx-_DAsgoBjZWYn2cTN0f9nraM0p2PibFqLcOLo-prjcdirllamEIVCSKlgQeBs9VlS5gEFMknLEzeCjkHB3ZQvyo-7VO6N4cDAnSQ_QwZLwIzXZ1Zp1vx5Tc1J8foMb6DP8QU-v4lho48Ac8Pa7PSUTQX-ta3nukBreTGlqmYveL6zBK-K53rHPiZBcn4P3iJ89xCy41LZe6IeUMMejp_65uVSzwMEo1enpzEgFrECaZwt2WezJITOfy0A3VrIdMsGwerm9qpUbOcnxfpBIjkblJHyQ_L8Gdw0uhpQHR44HA4yRKHCsKPP9-J6OP9OakZ_a7kzdhfr8DHNwBb82CG5NCAoQf_i8rD1dImQjOHixPXIITj8NZbnxiUzAYoXBNTqqRsNp4qtd2oQ7mEjTlpIr2w1vm_rTmlfy2zYwL9nRpgkkgVSvhdUJXL052VHDEtyvks3AxxmU5Bx5KqriIzPEK3aLc5whMVpUKjGNPDXC00kCeUmWLaoO3r-9rOAcWJJR6XLN9MrJLiM05E5D1OITRlXIAF4WE31ttkG1v77lpn-VvFtPdYFWfHUVY3dE8ZllQdIjo861QQqxoWgYJYKerDERrtrb_A_oCP-g-iXHNejenr5vCXx5jfOpKfJrFt5mP1w8m-lQe0Nfi_faieqwIT1YypW-DaemCGAI3-CylaoM4qlL9U_mT1qVVkaPgTwoqYeY40W39N0_q4rk3I88HRsUBlCDp6nshfF92Q5pTCnFGDyVJYsBX93qiSvMZiOus2XlNrLF5tVzXP3wwFrmaXi6fRtrJNuq-9-oQWeernrWCP8ArOu2MLcZ81KpGOrVxXmyZt_BEo2UFayEXdVsrS32X76fDPTt7Oxj0iBKWXOcFX9fk0KHWAmaljnnC9pa0qJfR7gHiHFAV3P_RW8IkJNp8QxyVkmFWaFKRAmKTfiaAspbX8qqSiARmUhObJnsWRM6Nhj81GofbF0t15g1NuyZFNm49RCm6ARybWkucUCKqvsVftiKL6uQnVzp30Nx4HZoxWCOd_Viy6cq_E26_ObCN6rHD1v-xjdYKGrtfwHyT3KyZoIBxo0i_H-krjbWpAPn4PNCeEiejKGmkl2ZZDqrap1dE_-BLXtJ1t2BpB2jzAOnyW4Am4P0ELyT37D1JTLZacrrVn9gCdCle3LxbPm3N-3UBPU0g32Knp8ldD9wYVFRY3hDfIoUH7zPm217Q810oRTysntF8TKqtHlNn3cGp1n7iv9zTgS-E2GlFBuPlRM2QtxB3uOYoFE6dl5m8Hcf5ltUeZ9etbogBg3aqcIiCmgOZQqQ9C9QEIHkHLLaaR3eLGPy4Wel1ghGin2DLSaGM-gGSe0nEJdbyj2ctO41r65Xm24uhLxB29vFtcVlJszQedMmN3oifoGwUr0U-E6mAuuN0QfA3-XIn0G7bm6_bBB1fOLN-YTfl2cj1RdEweiQL5rFV7VQ5j_51-UdNZT70PjZab7qovXoYnPmX3NQEqgqq4QilQqrkhVDEZ-oZKZ0CKNa03vESEgCXTdeWmH4AZk-jU0aHK_wyfTmKHltA4VZPDERflMDVpkmZm6BnGACnQo7QmijENqr68fr6YjbrndRTSwungUCxEoZeyqcEJUGhnfn4yJWRb82YvXFkLry-hF7iw_wzGqo4QOhRlVdOWbqMO5Kt_0EOKKWtVARQYr96Y32pzw_Shb2NwotT5xpA2kPZoET2EDdobaAtVAV8h2e7ctCN3pCD-nzd50A0udREP0hl3Hl8L-j28gsEeDETXvfC4PRuZiyJU6F_ac_Qqvu-_wNtuWn_cId5nVbf-hg6YaOi9nAKuQGnlCFMhf1RfDs-Rqegqwvhs9HrXufQUbKpe9DOM4aeW05iSANWB6a3vhaaVJkMdsDc0rrpfQHJJkMht7Mq865810g==', + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6', + signature='gAAAAABoxC0_aDtrISw_zls0dyams-nhm23et1xecYaqlI8y44ih0g9FA5T3R9ueXIOX9seSrysa48qci5QTep_TNFkxcjPMbWeQxolRKeCjWk0jLpC2FdKdscfb56KfeSTklKz_CaD-VubFOUgtqg8bQfJTvrdEtKj8Q74c2-XOtHTB-0OjenFtkZMtLMu3uc009ktnOSiWIxkuaDXcvgENQlU60WswxDC_3j92V9o0XsSnXxS8ZmvfWcmYxsFAo575ybwZin6GI709AxlJ6iPkSYIyRy_Sn_O2B68S5ABs8gq0yzaDtX2Wtibqys1NooceCWvxBSjZUKKD3N3FG9Hx_GzaUyvB5DblDmqgfP3AC_VfxaXm990esMW22fQvrEmuRNJc7AF0-KSBCNjatP6eHKj7WSiyGplUFCukk1tRHxOeDi9GD6s51_jTSyADenpzvdBLoELPR0JQIUuraSBpS3aZS8ODJDUbIX8niI_RYzRCvqBDMbLi9MaI_jTdEJknhEgmZZaV-53FXEVM7LoK6BWBpocwDC0zbcA-Da2rY6y3h_4x-PD-DL_W-V0_XDqwhx6NZOJBDpGrJIKY1BU-QjjEdZeXg1hv7CmLCH9ykOr-ja8B72fGaY2sJ9Lg2dFnaEkalEnYPCOY1hWDok1o5H0YVwA3MoZPr4VuFbGKD1EEAcB10UYgY5_WRK5Zk2CYK9EMOyLMA-_DU5qMLw0qrpj7lGRe7PLM0UYBbjP3jFZX6Gy5e1RcibH2MsrbfH4SlVkc1TTak4vuBEIR7Q4q8dYCoKTPgHAWFULzFbaCwhQQtyL1_lG-OpiGGUSZE_VRj3yVKbrv4Nz1l44ah5DdlG0BCiKthdMqcVxc3Bh3VKofIN6G_rArAtZ4ZmcoPVXIUlkfSPm9efNSx1tUpZPKkFk_dtP9B0dU5gD9F3tTU73I7CtuDaIXfe5JOBegu0_kBjEXb33s1B6mnUJJld1f3c13AwcRhMimtidTdtZFp4iAaKH0hWKrC6fOMlzTmz7O7R79sl_81XTQQbIR31yojRzDSvwhRoenyRWvQQMV4PeZ8h-2ioG2l0DQ89YRjkjeUEwZyog0ZWHflw3nr8zjJ7xkliqfJpspfE0scWrCq5KmY21vYkf3EcH-HU5s_S7_vo-JwnNIlTaDJUHbEo8sl_pJAsWix3OgzBSmBPneL-dknHi4IL8NNoGYkH62mbIKVPlBqn52e9QtO7v_yFLxGrZEBC_Z7jsFQQDarKvKk5L1nmWLRUffZvNP0hEy9M93wPDVNZ7fU51jD15tpuj92gBKXIM2sM2KWXFiVqg5PhkT7FvFHii1f-cc0emUTvzlO-ZU3oV73eSiisAUjHK3CO-rWD_WCiSAy1YSSOgORY0NrpwcIY3iuwu8yKxunf2F_bYK8mZPyAiI87-KYctZA2BLRe3UVhcbdkXQqHMTbOe8_yRmm20RnsHNTAk7ZlPNUihqE4kxbK6T0Bm0rtWLx8kZHWqq_netnSDiLa8Jtxzxu6UrKOtoWi7P26FE4pGwS5vPVCJ1Z55IcOZ6kQ_I2JpZA49MFJw6YDhKVnJlBEw8D5DfRC7A2YJ1x7ZVufyrYKiew6FYPaj4hpM95SN7o2PXz-vgTvp0oM0qknmcqdtuMgQcuWR5NED6cYccQJ4DQV2Nodzn_bFokhIcqbQVeheE7Jzy2MrzF_CJ3bD2LEmTKgDeoRfH4f4APSh00c2JAqtrKGmF7yMpBYC4vTTnbjPD4shMEcwgMeQKv8rWIaoRZR68Uhd_qwhW-wLqLawd42RaMzKebvCX78epU6rMz1VAlhZzlKS1keFXp-5xXjy4JQcu_WY-GXqSv7ah8CWGItBFc2yW2vQaDfgeHxc5MZTg7Q_VJkGSIEhttIb_0na2S6UfKXczrF1aoBFCKfxirIrOs-VHvbQCyWXwUdKidKNIqexkOucVOo4MaDMMKYSX7LINIdf4WPwrsa2SBW_UpFp-jrjF-aHmykLShhIEv_nCAHGMmfPwbu3ZsARJYusP6vRL8JdVq7pigfBkcIONWRVO7aM0X4ae43bGPfIzzLkdOKIBMR7KFsAv-4THPPH3UWTUG0MN0dAQPAAd6Jbp2xe3heqTY1J84QLaPFRY66r6rmZDWt8yzFB2IqLlupMgINWWLL8e0v6BLd0C8_jc7kwHmMvaPoXlZwqVFXed47bJOFfDXgymjs9Uw2ubeb1VMydQFmftVwzFY0vFTqqAWWnHIw5udvxgCTXDv2daFOdWPfrE6wKqVb9azxmGGXsoLcigmzwapcHBIUHAKKBE8SO9G3ciUkVFnK1JQEJ8Q96TdxMbnaXsPfy_CDaNUQFTnLYatnTbNq2kr20TudmpMYbm3V6_51K-gZyBh0-ESsRtsW1xaD68FgwS2Hi4zgd5zmko4c4vh3ncQt5eWB4Zy3VPCcNSPvgEVv_1psLFVPWMhhrC7pwV0PeuEE9h-rr66lwV9cgFIJkQf1Q3NzXMOa65aNKvmjAfP40H6jDUrKW03_JH56kb3R9YwE4kDpkkSJzHUsbPLjWPUr6SOUQKT2je9oxE3ioEgtwAlnYlxf5JU_BPyj7EsgLPpe8ZIuaTn7pU_tU8fBo26MEn78g3rwaFZ7PpWn6DeMTG_hDvAaTSZ0qZ6bAqGoj1UP_XzuQOuRvdbO_jNsclKBfZPj3RQcx1c_4H51aKTrJrYLndXSzsMox2BLoNXuUYoDyIeu_J36iUid5W4M7gykJADbUZBIbag8ordczWIaIYGxJHpxqiZvluHO1ufCLYWj3r8GhNNU_BjdyCmisGVV1he4ZdRiNHNlpfAL5SSQv7QynjdrPTIwmugGfinfzq0E7-2MpEOtBxDwlZtLBQsHLracKuIjYorhTzbj2dnvCBWTdfeBnaut-x7dfKr8ReAZnfhn5-qtvJdwFfx77y3t1kUIEBFr1CTmpUh3q5SJtQvR8TeTcPJORHk31EnafeipUwT4JnqA3oEiiqXLs2wTlLAt1SOx-uwMmyMeBEOhK7FS7Tdwgr2f0K-oEaUP_3AAENamy7U975-bvrQC5NQR91rCee0_h13qvdnYG0S_OS1vswYCoq0Z2wnR6wa4nx-ZoEZmnH0YoGyIt14_gOGQ9X5TAWFNlqbbHzhsOUIrN6TM-f5HQzXF7X_V7c1rMtPR-ZlYeXu7lla81J3_eIO_XzOlD4BO2nosgagiT89GQB5Sj16Ehd_KGMPpCsvqOxg_UpPL_kQ7qJtDs8okP4YmvWjp4IHVD_CmV0kyA26B3tlwkD8IUHzlAq7Bxq3TKgnGIgxi0-scAmiMvN-TlXvDjBp0Uh-AWz2zxwAGqsq298xeLkPRpJJJECMlZVPppr2RdKgCyrqBhGLyWIjmIx5-jWY-1XuwT7cb9NGXe6RFfmCXVX_B_0_1ribDdgLMRtGXziYbI8qxmN3tsw6BmPEsDCuofe6Zqm97JipN17tTmv-rdOHeeV9UgeiYQ0xJe6Q9psmhHBxGW6LVp_e9dWt4-aYZ24hSGf8CileysyUV0etiXPh2fVacS4HKQXry29CMP6j6gO6Ca2T3CNIYYd_aG6hVBO4Lk6ENkS4kkl7Wen5tOTI5TCD0pGAIuHIwey-DIfqPbW-ZHhQO3sBYSVtHPMSXP3hrojuR1qEnFVrVyqLABusBzlqB2mAnvSKZRCpZ9VFGUABN6ytItEXv4JDIu8eo0IvMQmWRRguaADU5pBiyQZ_5C3UEyX_QveHmDri9IXaVQz_3a9gowZfMuGj9CVwuhCq8R3ZLclacFxWRFw6byEOm2KZb6jH5qemc-V-Ci1mtcIsOdVLFQXuHkiOyZE2zISd0ckGUWihME4lg0imlSu_XI1MjWwao049bmP0VD5iqqpccIVsJuNkrSmw15AcrHqjlVhIWrD8u6e90uBqvm_l-Yfxe78_cIl-VuWTTa1qI8yw-LeNWloZCTbls5pRQr7MCm5dkZeAt1PBdnBpXTk-8VcvlDsA_hheV-QVbrdP4UTtDArx6QfxDU8PNLMpMgovTDTn6WnaJpdP-WVTSYH-78a7rp01RAmIQTl12vXuNRhPtj7jlortf8YobH2jMog2vRc4uXQpqZyWtSr-BF4vhh7QfzK6myLiEj_ciHNXqd64WzYl__hPaULy2xkwkpnD6mWQnRkoNeFGA-kt0f5J-M4JrRG3qCOdVrccmyLye-vVQyVkqfqgau6YLXd3QdpJkmA7Puu0ie1BeQBnBG4nJcWvDE1R19MdYBT7v-IDTdFBTtPxc5KerxoUy-Zn7xzvmUt6rRuk0pmBwzriAtzZctD2PI8BfoC4zhP-xpMhcNNaqCUBUQ260pWVdhqUCpkoBrskVHMMndizoMbeIeAcdAp4-lI5l-6zTO2APjygljfVHHLjpbTxs1ZA8DYpjrmzWSC07IXpK54MR258kedSamj-6IcUY4OOVVsuLvioELKt5JHwx5oADllUevxdA6K-9vddx7tuhgvkBvL1TpSp0XxDGwH3dRJDFwcDl3ah_PaOAjc33Z2IlcnXynaERtl3ysxBoPSY_4KPn5NoWQ7YHxzA-zQMKaa9fpi2VLN8Ud8redK0EKc9WwKXp-zmJbCf-KBsVCbFcrj9WUz38x-Iv-JEwFnUVpfTporFsB2eYlAPaMrXbf4Vz-Um1nfSVuq0F1V4cCPtZK6I_H-KWLbIseWZxNTJCWlmCaBe7ZQgt8ICUXqspyD9OOU6VNfr0nU7aW0itJEnvmKSfxnj3wQhrmEJ7HsX8mRHaDqAQKCr5B8YT4FOqTISRnTgDsV16ZRp43TaWH4QFpeanUD3KvmpvvfYGXUKVHlud2dUwPCr5FNM1QRFG9cgMBJn3y7ewbuixmPAIU_se3fYA1nYBtMlPpSHMGfXsqrIlMGNXmwsTs7TjG-kLzFrSA2ku5ZFX6N4wQim45hr1fBHI3GDF7IwoHKVCjXLjrkdCOGW0mV-n5uOAJxu5r_Ire3WFys0V9nlPpp9vy40PaNbXTiO0bLZu2u7LVDKAmxvvHxpUZxtW6v5lzoJjhdy1j4yAYCSgctwmH1pwhe8-wzU3JU9Rt1LFTs9t0XRUq_HXAb2kTGBMvk4OuuE1huBo75zhmFb1DVTzjr3Lpx656PZNk_frJiwupQ3qQj7b77ud_OzWgmRcLfmV2HPratlaB7pHQy6srJX-z2So9VD6TdbUUuOlSoGmK6jd1aGMNyhc2SM99TMQsQwbMEpZQ5tkexBf3Yc2TzQKON23R6xP90ctuAD976TtM2mZhV8o_7oB8jY9pyNwyf4tRUz0TPGIWBGgv3XhPugBTB5gfkRWXRvmeA2-Q38To85FnGpZib0yhVqpfS1ol9fZ6qmGQtgN5iZkXceAhYJRBwIq3jZM5-9Kc4QUO4aW4V8P7OXY66kxtcaoxXFcaug_EXomyGVhvLJ99QDE1zxTfZZ99Z7ZbAhYKQhctP43NCx3WPN4P0dP4HOG1HDhCW4wFOdWTKXQOKA1wOhuGUGyxpi6DcnMkM-vCpbWfHNzeSOKOXkBHbKycZiQ13mAv-eKpd0wg15sgkX3XdzHu8Xxc8HqDxsdJoyK0kT9lA8Y8PpF03mwhSqmOpxM4RjLL5U6HSt4FxDSsdVoTr3bzlKplWA29yVjlOU9D0xcbp9_Vkb981glTcmIhmpkP-10LD88arU_kHIkv_Oprhm-sCnNgI0RzmH71j5RxUuJDEKvj-l9A3f4lLEudcJw8ZBe_y7voD2-wNJ55hB5hYjzX45A5JCGbh7bE45bdq-hZ7a5rHekQAKMe1YO0zRzrkUagXurtqAXrZcLAq6NREGetDb8ICCJWA9fYoBWwz1mIBzn0fXUZlPRST-N7btljgD9RqiScsTA5NmGVG63cFq7JR7q0Na6eXVAKBODjcF6pMa4LIExSQq6W8CgXnfmGGTQp7p48TR0wan6nvSCOaaqty0hnELs2AkOb3otvg3T8ISPj36kApd3M5NcOrxW87LV7WEaN2Xy3aHkhxhZNMhAWHAtQpeg66rIsBat_Enqw56zTnSdjbKAAM7_mda7iQg5QEHKPSxkN4J2dAwzG-XmWTQJZhhxkAG0PDpN0sZkXRORxQV9TRBGmXWarK_GWkw2oAFFtf4H2d1KxlNiNQ6t0_6tWvN5piuPQTPhkIDmbSpbELp_sxYPdp2EBGN_08JbukeZ7P7M-eC4ps1e3mU1-l5j53tc1pYmauqc16J7ulQUe4WTMNWBBg3rBKdnR_E2wWMsirHhRHw8PZwTMmczbHVLAg6TX_RAafz-OOPaqrq2B_m-teT_-89rMWmrhIDnZMUTKPNQiInT0KPqZhZ981yZqkcKPKtJ2wYtliN6DE-GfubhjhCeNEoijF5wx6CruwB8F68SqANak21pj6LFT-gUdVI0S40PGAG87FelsPUVVrOmQJjoLgeE_zaHi684rPgknZbKW9PI-w5DhXfqqwn-8Nw3zanwa9aQ6TNzmZ_3hExa3yn7E4YrGvQFNz2EcpvBmOLl_7aU6OB_ofPFc8xGgwWm2vQQnj2XIMW15AdD9Jw9C63LIfsBd9krF1v9SzmDHVe4C2yRjGoNmaHCpXmzGcCdKKYkLRIVR6jclh5-fs5rU0L4hQC9LjQoS946Dlt731DBShTzh-pzwFn3TwmCOzTw03px_cwGXubDcbV9UP3WwJ5lbmaa9Sb2LLyQ2CE4aDrNeQvIDjnCzkWVHdHDkcTpnaYZCGjOcpf1jcK6lEDN2DKxEosgVM_sR0wg1rKTsm-i_K3Q_ByyYGooRCNv8xTd2mD2YM7AeucLEXDJyNFu5GGjommw8Pm2iq_Y0WyXkkch-PUAnlaDhunHhi0e22faVzG3jfHfy77aArXiWekmRbWwMcWesUVGTP2MMLOSwdbvF4h2Ww84U-V2ez9DHVTjTeN88C9BbAbwVbK5QSLcmAEK89GdSgss4VOI71f-mWih_oAjkMinFQuWW6K2OCrB95lp4SUBlNPOClNOChG1OoRWmbXiejGW8LPIoNK84FsccgEOtk05kjng11Wszj8JTt049ip7xgs1JeFZnazDT0WBzkabPxEEgz1KrZJj7OKqPT3yHtxgZ-NOfXg0AvdJuThwuvKsrQwkQ12AuUDDiODLZtWuBP23Z8wp-IqySHGpC5yrcZkWVBF58n7gSTXcpjsPStPYIXzxmouuRTSujRUcPE3tVgdDoh1jZLZKEOO-z2PWHom508mFbioDC6gluzv9bEv9SyJQcblMbaRR1W7CbvU1W_w6j8wqUVf_ZT3j4zY7CHoSD6AkOrSITmK1nFoivUmZ56LI7ENM34H45TskDgrwV31Jfm9zbnihQ-RTKUrAxRYwCF-5VsoBParjjuJ6qoExAEPXn1Y-yYt6QC29baQVK1lcwuMt05y--cTx0xpDwsLqUki9q6MYQvFAg0toEyW_VNuCJCo8Chsp2VHgG3eNBTfwbQ2M6ipHcldDd5OaEJZmzk6phdbFbaGo8xCJ8PUqiQr3yd5hommaM3W7JgNvUHPif0q8olUK5um-qzUCBSizSzoigdv2vsduE6acPFaHw7I1E4ycTrB1W8FyEsWlMhzofReeoQLmnH0o8IEeGrWMFdrRe5yDw5BjixK_daKBK2REC7mctNl_nx-_DAsgoBjZWYn2cTN0f9nraM0p2PibFqLcOLo-prjcdirllamEIVCSKlgQeBs9VlS5gEFMknLEzeCjkHB3ZQvyo-7VO6N4cDAnSQ_QwZLwIzXZ1Zp1vx5Tc1J8foMb6DP8QU-v4lho48Ac8Pa7PSUTQX-ta3nukBreTGlqmYveL6zBK-K53rHPiZBcn4P3iJ89xCy41LZe6IeUMMejp_65uVSzwMEo1enpzEgFrECaZwt2WezJITOfy0A3VrIdMsGwerm9qpUbOcnxfpBIjkblJHyQ_L8Gdw0uhpQHR44HA4yRKHCsKPP9-J6OP9OakZ_a7kzdhfr8DHNwBb82CG5NCAoQf_i8rD1dImQjOHixPXIITj8NZbnxiUzAYoXBNTqqRsNp4qtd2oQ7mEjTlpIr2w1vm_rTmlfy2zYwL9nRpgkkgVSvhdUJXL052VHDEtyvks3AxxmU5Bx5KqriIzPEK3aLc5whMVpUKjGNPDXC00kCeUmWLaoO3r-9rOAcWJJR6XLN9MrJLiM05E5D1OITRlXIAF4WE31ttkG1v77lpn-VvFtPdYFWfHUVY3dE8ZllQdIjo861QQqxoWgYJYKerDERrtrb_A_oCP-g-iXHNejenr5vCXx5jfOpKfJrFt5mP1w8m-lQe0Nfi_faieqwIT1YypW-DaemCGAI3-CylaoM4qlL9U_mT1qVVkaPgTwoqYeY40W39N0_q4rk3I88HRsUBlCDp6nshfF92Q5pTCnFGDyVJYsBX93qiSvMZiOus2XlNrLF5tVzXP3wwFrmaXi6fRtrJNuq-9-oQWeernrWCP8ArOu2MLcZ81KpGOrVxXmyZt_BEo2UFayEXdVsrS32X76fDPTt7Oxj0iBKWXOcFX9fk0KHWAmaljnnC9pa0qJfR7gHiHFAV3P_RW8IkJNp8QxyVkmFWaFKRAmKTfiaAspbX8qqSiARmUhObJnsWRM6Nhj81GofbF0t15g1NuyZFNm49RCm6ARybWkucUCKqvsVftiKL6uQnVzp30Nx4HZoxWCOd_Viy6cq_E26_ObCN6rHD1v-xjdYKGrtfwHyT3KyZoIBxo0i_H-krjbWpAPn4PNCeEiejKGmkl2ZZDqrap1dE_-BLXtJ1t2BpB2jzAOnyW4Am4P0ELyT37D1JTLZacrrVn9gCdCle3LxbPm3N-3UBPU0g32Knp8ldD9wYVFRY3hDfIoUH7zPm217Q810oRTysntF8TKqtHlNn3cGp1n7iv9zTgS-E2GlFBuPlRM2QtxB3uOYoFE6dl5m8Hcf5ltUeZ9etbogBg3aqcIiCmgOZQqQ9C9QEIHkHLLaaR3eLGPy4Wel1ghGin2DLSaGM-gGSe0nEJdbyj2ctO41r65Xm24uhLxB29vFtcVlJszQedMmN3oifoGwUr0U-E6mAuuN0QfA3-XIn0G7bm6_bBB1fOLN-YTfl2cj1RdEweiQL5rFV7VQ5j_51-UdNZT70PjZab7qovXoYnPmX3NQEqgqq4QilQqrkhVDEZ-oZKZ0CKNa03vESEgCXTdeWmH4AZk-jU0aHK_wyfTmKHltA4VZPDERflMDVpkmZm6BnGACnQo7QmijENqr68fr6YjbrndRTSwungUCxEoZeyqcEJUGhnfn4yJWRb82YvXFkLry-hF7iw_wzGqo4QOhRlVdOWbqMO5Kt_0EOKKWtVARQYr96Y32pzw_Shb2NwotT5xpA2kPZoET2EDdobaAtVAV8h2e7ctCN3pCD-nzd50A0udREP0hl3Hl8L-j28gsEeDETXvfC4PRuZiyJU6F_ac_Qqvu-_wNtuWn_cId5nVbf-hg6YaOi9nAKuQGnlCFMhf1RfDs-Rqegqwvhs9HrXufQUbKpe9DOM4aeW05iSANWB6a3vhaaVJkMdsDc0rrpfQHJJkMht7Mq865810g==', + provider_name='openai', + ), ToolCallPart( tool_name='update_plan', args=IsStr(), @@ -2613,7 +2703,7 @@ async def test_openai_responses_thinking_without_summary(allow_model_requests: N ), ModelResponse( parts=[ - ThinkingPart(content='', id='rs_123', signature='123', provider_name='openai'), + ThinkingPart(content='', id='rs_123', signature='123', provider_name='openai', provider_details={}), TextPart(content='4', id='msg_123'), ], model_name='gpt-4o-123', @@ -2690,9 +2780,9 @@ async def test_openai_responses_thinking_with_multiple_summaries(allow_model_req ModelResponse( parts=[ ThinkingPart(content='1', id='rs_123', signature='123', provider_name='openai'), - ThinkingPart(content='2', id='rs_123'), - ThinkingPart(content='3', id='rs_123'), - ThinkingPart(content='4', id='rs_123'), + ThinkingPart(content='2', id='rs_123', signature='123', provider_name='openai'), + ThinkingPart(content='3', id='rs_123', signature='123', provider_name='openai'), + ThinkingPart(content='4', id='rs_123', signature='123', provider_name='openai'), TextPart(content='4', id='msg_123'), ], model_name='gpt-4o-123', @@ -7827,6 +7917,7 @@ async def test_openai_responses_raw_cot_only(allow_model_requests: None): timestamp=IsDatetime(), ) ], + timestamp=datetime(2025, 12, 5, 17, 15, 40, 975876, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -7843,6 +7934,7 @@ async def test_openai_responses_raw_cot_only(allow_model_requests: None): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -7891,6 +7983,7 @@ async def test_openai_responses_raw_cot_with_summary(allow_model_requests: None) timestamp=IsDatetime(), ) ], + timestamp=datetime(2025, 12, 5, 17, 15, 41, 98277, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -7908,6 +8001,7 @@ async def test_openai_responses_raw_cot_with_summary(allow_model_requests: None) timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -7958,6 +8052,7 @@ async def test_openai_responses_multiple_summaries(allow_model_requests: None): timestamp=IsDatetime(), ) ], + timestamp=datetime(2025, 12, 5, 17, 15, 41, 258551, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -7969,14 +8064,27 @@ async def test_openai_responses_multiple_summaries(allow_model_requests: None): provider_name='openai', provider_details={'raw_content': ['Raw thinking step 1']}, ), - ThinkingPart(content='Second summary', id='rs_123'), - ThinkingPart(content='Third summary', id='rs_123'), + ThinkingPart( + content='Second summary', + id='rs_123', + signature='encrypted_sig', + provider_name='openai', + provider_details={'raw_content': ['Raw thinking step 1']}, + ), + ThinkingPart( + content='Third summary', + id='rs_123', + signature='encrypted_sig', + provider_name='openai', + provider_details={'raw_content': ['Raw thinking step 1']}, + ), TextPart(content='Done', id='msg_123'), ], model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -8007,6 +8115,7 @@ async def test_openai_responses_raw_cot_stream_openrouter(allow_model_requests: timestamp=IsDatetime(), ) ], + timestamp=datetime(2025, 12, 5, 17, 15, 41, 400785, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8031,7 +8140,10 @@ async def test_openai_responses_raw_cot_stream_openrouter(allow_model_requests: timestamp=IsDatetime(), provider_name='openrouter', provider_url='https://openrouter.ai/api/v1', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime(2025, 11, 27, 17, 43, 31, tzinfo=timezone.utc), + }, provider_response_id='gen-1764265411-Fu1iEX7h5MRWiL79lb94', finish_reason='stop', run_id=IsStr(), @@ -8146,6 +8258,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), ) ], + timestamp=datetime(2025, 12, 5, 17, 15, 41, 550367, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8162,6 +8275,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -8179,6 +8293,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), ) ], + timestamp=datetime(2025, 12, 5, 17, 15, 41, 550367, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8195,6 +8310,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -8205,6 +8321,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), ) ], + timestamp=datetime(2025, 12, 5, 17, 15, 41, 554648, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8216,13 +8333,20 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: provider_name='openai', provider_details={'raw_content': ['More raw thinking']}, ), - ThinkingPart(content='Second summary', id='rs_456'), + ThinkingPart( + content='Second summary', + id='rs_456', + signature='encrypted_sig_abc', + provider_name='openai', + provider_details={'raw_content': ['More raw thinking']}, + ), TextPart(content='9', id='msg_456'), ], model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -8240,6 +8364,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), ) ], + timestamp=datetime(2025, 12, 5, 17, 15, 41, 550367, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8256,6 +8381,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -8266,6 +8392,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), ) ], + timestamp=datetime(2025, 12, 5, 17, 15, 41, 554648, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8277,13 +8404,20 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: provider_name='openai', provider_details={'raw_content': ['More raw thinking']}, ), - ThinkingPart(content='Second summary', id='rs_456'), + ThinkingPart( + content='Second summary', + id='rs_456', + signature='encrypted_sig_abc', + provider_name='openai', + provider_details={'raw_content': ['More raw thinking']}, + ), TextPart(content='9', id='msg_456'), ], model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -8294,6 +8428,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), ) ], + timestamp=datetime(2025, 12, 5, 17, 15, 41, 557492, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8310,6 +8445,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), From 8b2e59a4e3b9d2d836f3a8d0346d0fe91fbe2fbf Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Fri, 5 Dec 2025 13:59:33 -0500 Subject: [PATCH 16/25] fix test openai responses test and remove empty provider dicts --- pydantic_ai_slim/pydantic_ai/models/openai.py | 16 +++++++++----- .../pydantic_ai/models/openrouter.py | 10 ++++++--- tests/models/test_openai_responses.py | 22 +++++++++---------- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/models/openai.py b/pydantic_ai_slim/pydantic_ai/models/openai.py index d7a2712bba..a771b0659d 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -597,7 +597,7 @@ def _validate_completion(self, response: chat.ChatCompletion) -> chat.ChatComple """ return chat.ChatCompletion.model_validate(response.model_dump()) - def _process_provider_details(self, response: chat.ChatCompletion) -> dict[str, Any]: + def _process_provider_details(self, response: chat.ChatCompletion) -> dict[str, Any] | None: """Hook that response content to provider details. This method may be overridden by subclasses of `OpenAIChatModel` to apply custom mappings. @@ -654,6 +654,8 @@ def _process_response(self, response: chat.ChatCompletion | str) -> ModelRespons provider_details = self._process_provider_details(response) if response.created: # pragma: no branch + if provider_details is None: + provider_details = {} provider_details['timestamp'] = number_to_datetime(response.created) return ModelResponse( @@ -661,7 +663,7 @@ def _process_response(self, response: chat.ChatCompletion | str) -> ModelRespons usage=self._map_usage(response), model_name=response.model, timestamp=timestamp, - provider_details=provider_details, + provider_details=provider_details or None, provider_response_id=response.id, provider_name=self._provider.name, provider_url=self._provider.base_url, @@ -1212,7 +1214,7 @@ def _process_response( # noqa: C901 id=item.id, signature=signature, provider_name=self.system if (signature or provider_details) else None, - provider_details=provider_details, + provider_details=provider_details or None, ) ) elif isinstance(item, responses.ResponseOutputMessage): @@ -2042,8 +2044,10 @@ def _map_provider_details(self, chunk: ChatCompletionChunk) -> dict[str, Any] | """ provider_details = _map_provider_details(chunk.choices[0]) if self._provider_timestamp is not None: # pragma: no branch + if provider_details is None: + provider_details = {} provider_details['timestamp'] = number_to_datetime(self._provider_timestamp) - return provider_details + return provider_details or None def _map_usage(self, response: ChatCompletionChunk) -> usage.RequestUsage: return _map_usage(response, self._provider_name, self._provider_url, self.model_name) @@ -2499,7 +2503,7 @@ def _map_usage( def _map_provider_details( choice: chat_completion_chunk.Choice | chat_completion.Choice, -) -> dict[str, Any]: +) -> dict[str, Any] | None: provider_details: dict[str, Any] = {} # Add logprobs to vendor_details if available @@ -2508,7 +2512,7 @@ def _map_provider_details( if raw_finish_reason := choice.finish_reason: provider_details['finish_reason'] = raw_finish_reason - return provider_details + return provider_details or None def _split_combined_tool_call_id(combined_id: str) -> tuple[str, str | None]: diff --git a/pydantic_ai_slim/pydantic_ai/models/openrouter.py b/pydantic_ai_slim/pydantic_ai/models/openrouter.py index 48b25ec163..516ca61f76 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openrouter.py +++ b/pydantic_ai_slim/pydantic_ai/models/openrouter.py @@ -566,12 +566,16 @@ def _process_thinking(self, message: chat.ChatCompletionMessage) -> list[Thinkin return super()._process_thinking(message) @override - def _process_provider_details(self, response: chat.ChatCompletion) -> dict[str, Any]: + def _process_provider_details(self, response: chat.ChatCompletion) -> dict[str, Any] | None: assert isinstance(response, _OpenRouterChatCompletion) provider_details = super()._process_provider_details(response) - provider_details.update(_map_openrouter_provider_details(response)) - return provider_details + openrouter_details = _map_openrouter_provider_details(response) + if openrouter_details: + if provider_details is None: + provider_details = {} + provider_details.update(openrouter_details) + return provider_details or None @dataclass class _MapModelResponseContext(OpenAIChatModel._MapModelResponseContext): # type: ignore[reportPrivateUsage] diff --git a/tests/models/test_openai_responses.py b/tests/models/test_openai_responses.py index 4e0cd0b28a..e53e601777 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -2703,7 +2703,7 @@ async def test_openai_responses_thinking_without_summary(allow_model_requests: N ), ModelResponse( parts=[ - ThinkingPart(content='', id='rs_123', signature='123', provider_name='openai', provider_details={}), + ThinkingPart(content='', id='rs_123', signature='123', provider_name='openai'), TextPart(content='4', id='msg_123'), ], model_name='gpt-4o-123', @@ -7917,7 +7917,7 @@ async def test_openai_responses_raw_cot_only(allow_model_requests: None): timestamp=IsDatetime(), ) ], - timestamp=datetime(2025, 12, 5, 17, 15, 40, 975876, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -7983,7 +7983,7 @@ async def test_openai_responses_raw_cot_with_summary(allow_model_requests: None) timestamp=IsDatetime(), ) ], - timestamp=datetime(2025, 12, 5, 17, 15, 41, 98277, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8052,7 +8052,7 @@ async def test_openai_responses_multiple_summaries(allow_model_requests: None): timestamp=IsDatetime(), ) ], - timestamp=datetime(2025, 12, 5, 17, 15, 41, 258551, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8115,7 +8115,7 @@ async def test_openai_responses_raw_cot_stream_openrouter(allow_model_requests: timestamp=IsDatetime(), ) ], - timestamp=datetime(2025, 12, 5, 17, 15, 41, 400785, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8258,7 +8258,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), ) ], - timestamp=datetime(2025, 12, 5, 17, 15, 41, 550367, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8293,7 +8293,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), ) ], - timestamp=datetime(2025, 12, 5, 17, 15, 41, 550367, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8321,7 +8321,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), ) ], - timestamp=datetime(2025, 12, 5, 17, 15, 41, 554648, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8364,7 +8364,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), ) ], - timestamp=datetime(2025, 12, 5, 17, 15, 41, 550367, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8392,7 +8392,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), ) ], - timestamp=datetime(2025, 12, 5, 17, 15, 41, 554648, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -8428,7 +8428,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: timestamp=IsDatetime(), ) ], - timestamp=datetime(2025, 12, 5, 17, 15, 41, 557492, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( From a30d367c4dffd8cac2f0de17680a732f8d1c61e6 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Fri, 5 Dec 2025 14:40:23 -0500 Subject: [PATCH 17/25] add signatures --- tests/models/test_anthropic.py | 10 ++++++++++ tests/models/test_bedrock.py | 10 +++++++++- tests/models/test_google.py | 8 ++++++++ tests/models/test_mistral.py | 14 ++++++++++++-- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/tests/models/test_anthropic.py b/tests/models/test_anthropic.py index 93eff8b53a..e57de509a0 100644 --- a/tests/models/test_anthropic.py +++ b/tests/models/test_anthropic.py @@ -2183,22 +2183,32 @@ async def test_anthropic_model_thinking_part_from_other_model( ThinkingPart( content=IsStr(), id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7', + signature=IsStr(), + provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7', + signature=IsStr(), + provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7', + signature=IsStr(), + provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7', + signature=IsStr(), + provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7', + signature=IsStr(), + provider_name='openai', ), TextPart(content=IsStr(), id='msg_68c1fdbecbf081a18085a084257a9aef06da9901a3d98ab7'), ], diff --git a/tests/models/test_bedrock.py b/tests/models/test_bedrock.py index 7efd3ca492..f54c303e58 100644 --- a/tests/models/test_bedrock.py +++ b/tests/models/test_bedrock.py @@ -1243,24 +1243,32 @@ async def test_bedrock_model_thinking_part_from_other_model( ThinkingPart( content=IsStr(), id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27', - signature='gAAAAABowgAKxFTo-oXVZ9WpxX1o2XmQkqXqGTeqSbHjr1hsNXhe0QDBXDnKBMrBVbYympkJVMbAIsYJuZ8P3-DmXZVwYJR_F1cfpCbt97TxVSbG7WIbUp-H1vYpN3oA2-hlP-G76YzOGJzHQy1bWWluUC4GsPP194NpVANRnTUBQakfwhOgk9WE2Op7SyzfdHxYV5vpRPcrXRMrLZYZFUXM6D6ROZljjaZKNj9KaluIOdiTZydQnKVyZs0ffjIpNe6Cn9jJNAUH-cxKfOJ3fmUVN213tTr-PveUkAdlYwCRdtq_IlrFrr1gp6hiMgtdQXxSdtjPuoMfQEZTsI-FiAGFipYDrN5Gu_YXlqX1Lmzbb2famCXTYp6bWljYT14pCSMA-OZrJWsgj4tSahyZIgNq_E_cvHnQ-iJo1ACH0Jt22soOFBhAhSG8rLOG8O5ZkmF7sGUr1MbP56LLkz29NPgh98Zsyxp4tM33QH5XPrMC7MOfTvzj8TyhRH31CWHScQl3AJq1o3z2K3qgl6spkmWIwWLjbo4DBzFz6-wRPBm5Fv60hct1oFuYjXL-ntOBASLOAES7U3Cvb56VPex7JdmTyzb-XP7jNhYzWK-69HgGZaMhOJJmLGZhu8Xp9P6GPnXiQpyL5LvcX_FEiR6CzpkhhS54IryQx2UW7VadUMnpvwEUwtT2c9xoh6WEwt2kTDj65DyzRwFdcms3WG_B1cSe5iwBN1JAQm3ay04dSG-a5JNVqFyaW7r1NcVts3HWC2c-S9Z_Xjse548XftM_aD97KTqoiR5GxU95geXvrWI8szDSYSueSGCTI8L7bCDO-iKE4RQEmyS8ZbqMSWyQgClVQOR5CF3jPKb6hP7ofoQlPRuMyMY8AqyWGeY9bbWb-LjrSDpRTAR6af8Ip5JYr4rlcG1YqEWYT-MqiCPw3ZJqBXUICSpz9ZHQNTrYIzkJZqPg-hCqvFkOCUtvOYSDtGkAe9x1ekPqlV0IuWLxAmjqbkGH0QCaYAF90wVQUgWPkVWfQ6ULRz2sveQDZf0P8rVZw6ATEvZVnkml6VDbaH69lMyvzls7suvEZJxS5osyjrGfkt6L4nsvhZS7Nuxj2TcRxSEXxo5kULEqAO85Ivsm4j7R1Cxb2h8I4ZZZ_-DnkbWsgd7DELMI-CYtpAWLFl4K4VaMBT6mNAuud545BemUlWnQgmrde4aS7Q_W5GP11iQea9_JcJr6DMf4Y40NDr_fPVU5p7q1bnc1xtwkIpyx0uEeXHEZDR8k-5apBXScJtmelzpiy-25oJdSU5xtgVPrb77kVyJofPtujplZoqMh6MOqTdIhIMm_Goy_Wne4W39hVI01b2vwduBaCCaX6M8uACX96s454WPitX4MYAVc65UHF0BTFskEcbY5bFZpzcWb39VTfra-Ru2URvdo_66qmUd-03XzLKiMsqJHGclhaU6XBqaIo9qD8FjLVT9DOx56eh3GFvYA1dxvgbp6gyOg7bOBL0KDarT9Vmo40vGvwyCT_a2S_6Oki6uBU_3bf-jGvtum4tkN--wZkBrhOj7L8onItPoAZQXjYXrcXfVC1KR_xA0IOxYZD59G1rBxTDlvatIFwhvoISinkU-zPkKMpralHlxDicmJrBsKsy-mZWCF5qHeWF36pjE35dE9GxR28xw1Ed0pA_kOIgMKSKCiRWUYY8D1jAHKzimnj_4VTKR05kTp30pasr0IUMl2celsQMDv1D2atEJ_65CeRio5cnNGUR_Z73LJ-fqLkSjSxlE2YvtcKX7bdF6bSq3EqDtOdLVUjYl_pxRaUNMRmahQUJXGsDx7X-W9xUgQmAq09qT3lh1fhVUgdtUuuaoNY_M1s5V0E5ePuu_C6Duuz8WCcecbhrcbI3FDQSJn_XHK6ImLMYBowGRYVkBE_Rf7q7Hj4zdF-3bVE_QDce3syZNshCYK5kO8mvADptgdNVG7lEiZ9TIQPBd-XWRUrZ3XvIfGVJFVMjh_Laq8RTDyvvId7iQDuvq89hQ86hlfWteEl8HzuwpakWnogg3CCStX5CMGpYUWWkOCUu2LCH2H4EBaeCcAPLCmEoxcpKS182kYLm8-4ShRz-YOMIEmE9TL2za15I6BCBi9OhQGcLSl4BquhfBVHyxmkEN7_g102yI1Ocucux8q_HLMo5UZz0KALRQy4qmNpnLg9f4Yetj6msezjuU17Ji1ofIcadglOYy2J3Aswf58M9fCwCfB6hAHRYM2XkYzJ3nc0VosWA0er90zqKOeM1-erWC-skbupO-8nw9DA5OtnJTZOLnhGRjzXqna0E5R69wOHi3yvb3zzv2K9fLMKi11bCM_cnel9ItcFM-AYQ0AhBTZ3sTn-tpIf3IVNCvnCxMWvbO-MBmoexQnPorA0SL6n_nL49Y9Zb7UgwCyNGmhsFjIlSXu-YG-yCV1lVXBYoEPDwa2eCaMwph0QneXPHHMUs_i9PuFVI-nwfEiwU0b4tk8x3tWdkltvtzhjB8fxQxJNrk-ykNhuEYfQMQ0_MCqIRD097_gjO8q-eFUjnuiVqqoQ9_rH9QCxABdA8afoNt0hFxBwR6d57P81_XKOnApyrPx0DjsuKVTBFoCWccKX4DZuQT_PhmsFtPquNp6OPWQM5a8HzKntjz_HgFYnyS5p6n0hBGZVC_GDtFEm8JELcwuVoSLSXhI_XKnck2FIhHA5YQ4vLGOhCEEZoINkDdq3oNgm-NiP-DpG2LYetLl4ljlUpRBUizmWn4Fr3jhIt8rmQwqmFj6aMDSEM0Sgen9DsUH7H3uGK2NipvFv2Uxic5aXAKQ37EFjxPFqvKXlDl-hLnUXtkXLXBbmgCJJw6nBvm-SeIxU_eKnWHkhtdnkNZrmNFaq0OYZKk-moYSxEgzxasQNYGtkN89LqAhRTS6dIbb4nXa8ArvuHTJ_qpLFjGF3SSX98Y53cgtSdGTTmHQ6_v0BmeKCWhRd83vPrmFosif57AXyBVk0HJ5YdeueitsBCyXcJmeCntrT4zDlujwuMWK7wDO4vGMj3nIIyuJMJjtpD_auuDLmpYHqmKTHm8Ob8R2jJIwDhJIupkTldX5kHZmo6Nyh8tjeMgeEbp4Tp05CfyUTWWM16gaGkwW2Gto3sJtv0AiA_PzSN_dDziD5fRSH2Q2JTW4g03Uc9SBelL2fFiQifPSc3-mI4i8QHIswd_qPnSAnHxBW6SLJFqY-qIG6soLzt2VnH5hpVvakMfO27A82DQrcoFDFsqRb8KgLEoL5u-6NbgwKSNFjfIrLFg9IzrQI7oktylkFrc_EWL_smmL6iuT5WEYt4jBwtMvyDD6nVHzzx7jd8J3XQqjXfWuH_uTAX6cOHprzaPn05QRAluZgcBL-FSQJ3Qw7PjpoiLyd3DGL77nfl_m9cpAnpz3ojtajP7Gb-aq_xa_JIqxbnuBDBkeyN8pOQp--ZD7T2BOAgS7poVoqPFXRYIJOwKtOcrj6UdPN2yrx-44ZMTJYzwcGELnFRs32PKx8TiiF1pKSwo4NB5Z97_0k_WbyBwyNajMtRUPmEuTr9VoO7CBwe1r3U3iIZbBKCfJjiG5FQToqzku31_YAs5OIIaV4B9ifLt5PwUA4mO-7XqgO1VQQjt2cUQo3Ui3EKWEJ-ov7F3wf_byGsguBwv2qMuAQiLBqs5jxrJUxyYIJAM7B_TtUjpQnNERvHEkt9TxCN8Kc6L-MejMOfu3VPdArf38naQjvBjBAZDznV639bkIRED7-soJbGMcGEyGWUqAVs9vkFleO9S4YLNvFShwo3ujBd7SMMdAyvi851CXT5uN5SDtaxmQnUGzAXmPJ9-UoJF23lSGB26eMdnIerzFoYMCgWPHyvt949IrsUKnpjuxebqQYVSrppmhIIrD8R255bJGSscVwdbrd9iA9-gHoB3UzCr5pd3gfW9Z6ynT4dQVILqtj0KgrDOHw4AIBqmwaecTBi5BeyXJx2oF1ClqS_7AanfqNToLcAwaKXnrK4RGyrX_mXHUFX9cT-o-eGqhi0lifCcJixwb3kG2AhP1USNNsCz31m40_c7cm7JcqLbzCnz4hvbivUvON5rf6kQ8PrfrjNrZA73VVIKhgZBDHxsHa3skwQvq-JH_3QulELy1-6vL5Kq84bg3ZPQxOUtxBRuyjxEJkpgG-sED2pYsKrUPqo0Ku_ggMTQjvoGGYRBt5uMlVX4pdB1zhOe1ZjcvPb8IwnL_BdLX4NvLpN97KH9Ot45bLeVTCGpv5UH8Nnm5CzQ53wqsOUD-9u5hqrSwx89sF7h8TlN9non95r7b_oHkU1R_czZ-ZjL6EubsUx4w-rWKwVU7GYde-ie62v8jcaLhkM72O4B0UvCfY2t3GtruZ4OirX44hWfOPujFr5L6bOkVSMKONJFooIJ2RIwCw64Mczkle2zQZ1P3u1DrMS5s65h-gNTwSGw3qyQBwF58-um9ycDis6f6O0ggqubsCDlsW7Vdnk_GlETHLDQ7lR_lRG1g3kRQEhKz2iwzxQan01X021EJd4TlocJYafpp8HU_rgcJdUmcvPFgB2xysE6F1vYdUAdovDztLftb5Bad4aKueUfDs8haq9TBgosHQinvKFfazE2StHUaEAVK_BiOYrH1XsrFQlXuMwhQlRgA9L3Q663gMrnhnfcQPSNd7P5EhqbadtddoVrLOKhMD5yBJj9RiC0vamCGVr2LA7hStIPBGysTBanE3u4bT-TKe2qCOskvfR2xU8NSlai9b8d57zkuxklf7LaDnMi-xu9TOqduYFfXOn87uqjaN3_emcq0NExYcQ1fMUMcbOuGoW6qeWlWmMtANjI3VaJCa_v2JYJ4cyl4gUoboC42d2esKg_Em2XfqUkKQh4XTG673LC1ebToWGPRvFtTQM3gZ4Wh5JY4pL58VeSsf1jhINWsytNpgGckHCK11BzUUx4MABT2BuMWf-a_5DV4KYdmXHn_AKAqoZWHgE2hC2Q6DUEaKTm7AV56Cm5vo-NibALDGH1zG8ih5C3dmHvQmES7vUOVM1jPS6k7paHXEwnPFE9M-zg6XmjKjdvSZ04lauZEeCjSJPb4E_v-uWlwkdHsDcTxfj9oTjfEpX0mZxIuT_Ex7Mx2I7DUHDUQgKgZT9n1TQym9patiPO8VYzYuoXrsEeLS1Mk5N3AmQXeB89x85_Xj2plBbDOqqMpAD2uMBXwHI4kut10unkHhl3S0JtA1tE0ukxTRaitpDQveHfao0tQC8gy4JEA6M5AD7iyWOm_iuW9baElC-R_g_6s_X1t2qv4mWwd8P-h7yFm4XEZg_oJEIA40hGwSPKD1d-b9QRz7Kl734V5RvMw1ekdsvZ9dVKNcPffkGX0inTp8RgkOWFUnS0hZpxuNbte3-rGWEt6Syy4x2jaH-Zr6o667kigSt1Q3cQO_eqQtq4VWuFmYIbDzkEbIKmIHY52gh-rB5k-FMQqCs-ay5Blj_IpvfcImMtrZBrbhL89gzGNRonBZEa-9kJeu4jr2_DLzw14KJR5zVNwiGLub3jJkgYqOZZ5ee_oNchx3v68S3wHyFnZA9IIaXRZjYLMrjD699h9SZvkTHdGAwICpyOjrfYbgX_7woRp1ZWBslOamnw6mDqJAk22nb1a8cpdGNP2IjXVRtuqIB8y36bHEFjChDTxERZ2dsz7a2mp5qM2Xz75OGBM77DAjnGpU7GFXDnolAnAsU5T3dd-LLnVlVhvzyuZWg7ZdH-0WsVVCezyIsQnm3WMpdPrlUcHtT6fyY2fhJVIm1QJEES5wEiEPMRrmGQ68V-q8TWlrPan6LU5Kr8Ak0nJKhE-r5bcaemeUbIsY4a9n2YDZck9CI6VGumMccelQ61Bhs5vgQ0W4AID90TXnUtJjWrVcgdhrLCWV_kv2_YSqDDoI6TM0oJKNaoNeG2HXCxXpHy8izUvfMwHvdniW3c4BPnvMpQW83bXrMPteKk-CFXdwQ6bB2PzzXAzWTp5q6D5cLWAyPJjju4AmopBUJmRwp0tjulMCClWqMiB08y8DIWDDLAAaG7Q-de-_Q-T6tZy4LRk_c0sYOtAaNCA1HgTDSLvP4j-xeuu8DrKv5SqefP2J7LLFM_JAi1gRh_84NUvUDvBdexr9wZI8eXjnnoDvP6KTosKCLmSC_ErmtzRXfUg1mz5fNVtlKSm03tqzmfL46iKDATVuEejDtlo34djj7uBV5DUw4lDIpQY1VsO1Ozgpoz9i8sNcRKQ-K3Of-vDL6R28gLBUq0Xo3nm1hAJgjc68C57jrMlJhD8GM6AeoGnnhDTfJ2xuxsdnH6i06qFUKcuTmA8l23Ek-A3ryx8DHAIaRX40d3e5MwaUqbglufHWBGId7KBiaiFuD3LhJC0CLl23XyHf225Rd4lir9LpltmuaRLnyS0FwIGZMaRmxQ-SWB2fDVzj81SJpo9lPDsuLu_ji7AA1cx-PnTj5fVp3APeRmy9E0A2v8hCKm4C6tPuvgC7Xp6MV8epxYIsGRiTy5wlHQE0FUuOdBtBH0rmGJDf4HQJoZHjhDhOJZqkvlDtEowB1mtndHgRz-0lpQurRm-RwKvl4n0quBfWZ1GL_PmiZIO36Iyyw4BRt3c1a5Zc5ilweQcle_-ZxawS1aAXXOaknt2c6AGB5JnmrTz2dXS7A8M20uNp7Cv8RoeiCYjPa1Co3Nr_6BuQL7HFxNsyk1AXDbG2qUJljSeWG3YFkaPHxgTw7aAefXrFFL_GNPi0YtageYJq3WN6lrdQ2CB0g7QLoj9dsHlAGhm8PtUESBUBbSyJVOm1lCuGGbB7psYxOLLO3BSqnXHb0--sDiyCTKMi-80rtMiHttXC3zAxXUFQjTre3a8KNohgPWx1PTAbxf96enJ33rhBV-2ewMIROT9j-K_Esee0eWUcTmt9v0yHW-V5ij0Hopx7oaXadNQLdgBJwUDf6R9xEktHhzUkyJ0g73gjrKQz2EidorhljD9LSFMAlUuRTkUhG35crMduH9TAAEgOHXZI24CD5Fz3n2KgXKoxWHlpaLlTwBXK1xLHVCrqCqvsBo60w5FV7cmdNTBjFbDU1EKSHLopt_aMgtT_6Fg1ZT6H2p0CAvvbinLkTLop3pSVU1_itnzRHOf3ayHzMrmSN_pI_03Of_63ZuHJmRWRCd7s1PviAo-B1LcG52VTanJz0JCF1RAlPj9-2DIgJLxDgNcPI96cTqZBbLk-rwKlebrmX6d5CBg3V5pmJKkgLIj5FpTmhiXhqDHHJvu-BxfzDQl2c8QtQYF6aygihfCCluN5biEv51XKRDpC-S3sU3USofDTgcg1pznwUvVv2eL8nWywckhIHWnip7z_ptCTmyn7BEzzgRgGLA_pLG17SPRJP6laoXHG_dprfpRM7gcLJZQ2zk29W2zVEpFwWePGpnQbpPjPqcOBiQfewxwnLHEuV8yGBR7Y-SEKrc6M6v8AHYk9oLXaRu1qBKkLUKSzKQhNFtfl-h-J8Adf0W9hxYSt6QNzf1YUuE8H_w2SrUGcVnsCnIQY_xu11sJ-0d-T2oFelzeEoasMeeCDamuFQye14ps0k4cM8vXpk_7ZrVE7rQmEpW40_n1iNHwB4UINg9CnQGXH98DzBBCoGPZpA1SELOwGTcJGcBZVQ5Tfey1SRFwXWJO0QFHfDb5-_tQUj9o30MhJBGxOftnwLaFROLgq3FuSBRM9dYsdlpHe1SILQXKVIwjXcOVMFgmbDq_hMSNFlMvblX9LLBduT9cXk6JhBVcxb8-oKbvbjL7zqQHOgke3ZC6oDEvcew2YzLMiNLiyGxJcthsyDfrWbhbq9DSRE7lYq9AVeh_Zc2wZq0RFh4CJGhXtW8WobIOY8JPIkyQKD4W_mKRxchykWyrCRliFId1Tzbgzu1NKxdZLiGZchs7MRgd-c_Kk0mDAvcVqyCSw5ZnlG8qWxmgwods9KD80tww2Bvp87a9Jwf-S8_PhqqG3ggGuLLm2CH71h7v6uA7f9-aCJKnlPiyb43OU2IK-rRgJf_U6VNAs1n0-RwWlaMttgA5wcecqRUlkneFkWpJOKDXpuAR9vwfoArMnPnp0jGQDN3-OPymX4xsYY6L4k0zC6j3zz9K2wgcGFD9kliVy2qwbeAqWL37Qdnr6sEbkxusF6IiYh-POUU_8rCQX03_uw0XHroHwK4mFajchjXmOY8ykOBQCIGPwCNI446xFhqWFDytDTXq9Eu651PlEqDELIcRwQz6KYWNJNlEFi4_f4GYS8sn0wpwte5R9QuaaLjc38obGBswmh15l9PrMvrWklBnnEZpV3NWmxQViKWcuey_QG_hRfQ-8Kjhv0f4D4L-d52x89yVXeVu0wbN_GstklEGCCecqvmQi1vXDf2FKr69Md-TE-mAh9pA-72vepP3guNcHz6PqzzOQX9Sj1uNZCkB0heHrXuCunn_Elv3ZvHZ-9AE26ybqtRVxaHtYrbtX9AKVk7ud_YdFPxSq-HeavXCXOBDGxEVleN03Q01jj7xoz5MjhKrVDF7XOobW0xMLtPfJLLmEGkBtSrLFCDGo1T7T3DnEiFQzXZutM50_l0k_3DxzDKhI4s5rOeeTMjSXDaxjM52LLgwAanVnMtKEsEXFVF4b5xvu_xn5CzqW5T0TTDOFXm2Gdxj-t59bgRGmnO56K85rTGgeJyXBroTz8cS4hkgfm2fQKiDAQZ5iMJeY4iqKZJTrOYb0IueB_ez-I8XW_dibgUd-WcJNKYKf4KnZR9_Z8o4OofbCdVj2mcgunpgjbTCORNWj7IpYmkHcbIQFtXnnts_2WNf-TtE6xr-iIVkwGABYE7ugHl1BUO5yKuDmeTOijSxWQGO22dzPnGVQ4O7AuXUYBFRa6FKVEIIVyk49ggvgRFFerncqEW1s8LR9gCzMIsxH2jCOyOSqjWGdZncRqDWhF6NYgFsqs3BDGYspC1vd9KFYppnH5W7MRYb2Duoi9yb7SQhNarto9KaqqgiTdEWeOw3kSkTZxa1moEh8F3ueFWhjQXNW4I3_inDPUdw0Xcf703y7uitnAsi-235tGC36JkWMR9M9Dx1cQSnS0NWhOYjUPPrKSHW8QCY-ZAfEUSJfixJeXEEUI0YmuGlFCIrLFvtlqFjxzqJW4JPCfnB0jCC9Z07d7rwHznYBSkr_cis4gNwnPOa11060WODyso6zRSJ7Q57bPhULvgnMZHZq2hl5dygeAz-elG8XYIUmr8jwXKuVGT_hl13cNI5QHaxshgdJuTzE362jxI4c0usFIVIzwhX6KqDFtWIZ5skj8iGioS6pDkY5tTj91aRu1ZL9eQ7KSLBbPeqhZCjQJGuudUr4u7HGuz8lQR0KvuZqKGGaybbPYwzJSx9qkGwqr_RNT7RW7oDxNiPlUHEf1qvED5M5FBFt_YlTmVtLQDJHRxvx3jv-Nc9pm6tew-et17Z0lMcXypXhr138RTXZYHSwJXsHMTNNGZFHCuZsyrq-PywrzCm-i6tXstJXx79s9os_dAaYgMtYEjPNRCb29LjaNw6OL60MKAl0Fung52DEDjnxFCTp9ygM_IkmLw95r9nhdq3smfsasefn6cp3YnEG3skKDswqS2Ul8Pilfqz3JI7mVucw4zA08ICIXAxB_L8_MPXUPPrVrdcf2HHicjjFs5L7mabPyv6blX2uB0BJ8Pcsdr_qdm-JbxmEEZZnxmtaG0VPgo23-DaHHIdMnNa-4cElpS64Tqcanin5QIsd1e1jIBJcjLmGOjV0eJpawOICK6dIhgdAsgLyXT-ItiUkVc_7NrPdpe0Fag7jMtvqXlvi-JljdILhGfbT7o-rNPY2iJ32jKUIDVZTSADQRf7Psnt40y3m1Ccx6aN3JVhNrgihrfjMF4rhZkqrh7Rlzs350VVOar8RblBoycjjBh9-xyXXSp4OWebr4rK6w76HQqKoOdQZvFrBG0Y3Qfkq1tNnJyy7QA3ZZwhnVPzmvi7GeCLIZMNQLQ2A3mUvZXcmmcI2NmLBJuTHoQ5IBhmtMA9_b1qVTt-8iy0jIklazgzzUa0Zdl3IAuptdmJT7AGneTDhrR60WBnxVbbjJa-_LvOyVdEVimw6wNuUO0HIuyLo7s5MkR1D1SNShzV7PUtM2YKxUxbE1zEHkqiTIF1P5RxIhh85XAaIaJMlIxjhvtIUy--jiuzLh9HDDjDCuSMRrqOk958lSAkZnProYbHuRI12ViZ561Z4-whNCQwctuoP68FvRWLByoO2NtNSaPBC9aqNx6OWHcTTGdaip8MZLmD_xPjoq6O04HNxBsaCQeo2xqMkeoB74m_8HtZQIPHyEgW2cAnDDOPDRFspt8KN9TMgAWTf_Pa7eI1ZvWo1vZtjOUi9E9SARkpmtFNtaQP_NRLp_76h9B_piPJCdzuIl9QXbwscJOaDHIlYfeauN1j1zMGmSY1jS2UPNPF7Qfy1wUcdxLFuzGy_1YPe6i8DoMimj_c995kmHFKi9jIdBHrTz5p-pX_E01O95Wd1mzgCeQCo643zzQ10c93MASc5dgHgCjyTfT4RATHXhVrhhjnamu0xnLxIHt0qA43qDfQd23xzzp5gA0KLoQ-b9fYpo5tjD3z-A6BuVES9k9W60WN3nwxJiil6rjHSHxzq_rmoDj--EOBsKv5TcismcMk4IdBgoKWcsHGW43c5t5gmaA6c1QZPDHZWTnkHPZIsH2U1kMcsNHoWG-H-xQ65cz6cceu_ATRu26etMuEZo4ecqNSENhCQq7NlkEnWVacuW7qybowkEr2uIU-BB_wI1oHPKVupH-0ZOHsVZOgktQ5g1DWiXUVloBabeRIZJt7fDYFs5oNgXxggElnN9fK-fb8BQb9j2BraENpRQonC68YsbFQLoyefvK3WnO1GFQQg7qDqzhU9PgMU6CIYfMfuHAoFiXtaTsnykAIv7m0nckJn8nldATLqakn72ObT_rzRQXi_cKoksBvKel4sqg7FtoM9no5s9a3wT1OwRXNUZ5Jg5iYyFW9mlRV4-Pwo67XhiipGG-iXsqxlhmDQjmeJoBfOKfm3MWJccFO9hMReoCp1DDqP5wxG_1gFMhl4mHPgxQW24pRrYOO00YYdR9VVrsBdjalyjo4mK5PuWqP0O3BKTZ7-Al2P5_VyQ2MxMZAZCkHSE5tRIkq0k29sZLPM58yUwN5FkIrzop2PR_VNYNa2eY2jK-mVv7eYvwcq9LcF6JbJN79K9YyPI-dqKutPoFzFXQEijdF77VbVDQYN5v33gKMYWIyXUb_ZgBFZ9wwZkGkzK7aRR22QVhUMk-M6dZrVH365Cmnboiq_7ZqSIa49uF1qlWbCljkpXMDxF8i0YGRdx4CUSU6vfyKyMUtCb-c6ZxGztojxz72-u3SwPOEJeRNUjpgH25LHo21ORRGuDHM0p04CyxXYe6YH-qYyINgouQ58GorDnhZJfLssqXFDEV_HeQfuZp-KsEnHSMDgX7ibItCu_ETXE2ano2M0XnOjdmSPRHl1aFyQAWkHsgTsrlzucRFcDhkK1BNIGPgC4eWce4bsaf_DHP0OJW8qVEnd15Oj1r9Om2K-vL5pYCLySkxA85DSgMKNOXPsPV3wGkiJjLJqn250v5aiwAziMHrcY5ik4Fm2AvDlRXPvGqXOuQG-zJsFc05J-1TBLgT1wZ1b2mw_qihmlJt71mthNKfgjmCMtx6WVKgRGM2lhdZ6gXt_9AkBcf3Rax9inuLnPgfaOZSCNa-MMR5yVa7ql7i-NwvuupwuuTuuKGkXv_-T3EK-Ky418dDDOMTgpW8nHiUM6Y5uBu6v__N8NMYvnJmujw6dUTNMR-R6vgaXdDtzs6a4KAccwIgqQ43uhgDexj9x4OB4304dKb5PJ2HpgIlnXlhjB-JGmnQAbAIaLrEcW9V0S0PX4H_Mz4NGqaAtDTeeiw=', + signature=IsStr(), provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27', + signature=IsStr(), + provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27', + signature=IsStr(), + provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27', + signature=IsStr(), + provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27', + signature=IsStr(), + provider_name='openai', ), TextPart(content=IsStr(), id='msg_68c200091ccc8191b38e07ea231e862d0003919771fccd27'), ], diff --git a/tests/models/test_google.py b/tests/models/test_google.py index a78b9c53ca..efb0efddd5 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -2076,18 +2076,26 @@ def dummy() -> None: ... # pragma: no cover ThinkingPart( content=IsStr(), id='rs_68c1fb6c15c48196b964881266a03c8e0c14a8a9087e8689', + signature=IsStr(), + provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68c1fb6c15c48196b964881266a03c8e0c14a8a9087e8689', + signature=IsStr(), + provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68c1fb6c15c48196b964881266a03c8e0c14a8a9087e8689', + signature=IsStr(), + provider_name='openai', ), ThinkingPart( content=IsStr(), id='rs_68c1fb6c15c48196b964881266a03c8e0c14a8a9087e8689', + signature=IsStr(), + provider_name='openai', ), TextPart(content=IsStr(), id='msg_68c1fb814fdc8196aec1a46164ddf7680c14a8a9087e8689'), ], diff --git a/tests/models/test_mistral.py b/tests/models/test_mistral.py index 0d3a653b07..bdb672c0b8 100644 --- a/tests/models/test_mistral.py +++ b/tests/models/test_mistral.py @@ -2385,8 +2385,18 @@ async def test_mistral_model_thinking_part(allow_model_requests: None, openai_ap signature=IsStr(), provider_name='openai', ), - ThinkingPart(content=IsStr(), id='rs_68bb645d50f48196a0c49fd603b87f4503498c8aa840cf12'), - ThinkingPart(content=IsStr(), id='rs_68bb645d50f48196a0c49fd603b87f4503498c8aa840cf12'), + ThinkingPart( + content=IsStr(), + id='rs_68bb645d50f48196a0c49fd603b87f4503498c8aa840cf12', + signature=IsStr(), + provider_name='openai', + ), + ThinkingPart( + content=IsStr(), + id='rs_68bb645d50f48196a0c49fd603b87f4503498c8aa840cf12', + signature=IsStr(), + provider_name='openai', + ), TextPart(content=IsStr(), id='msg_68bb64663d1c8196b9c7e78e7018cc4103498c8aa840cf12'), ], usage=RequestUsage(input_tokens=13, output_tokens=1616, details={'reasoning_tokens': 1344}), From 7bf73aba821878a2b9025c9c23c557fdf4f98f3e Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Fri, 5 Dec 2025 15:58:47 -0500 Subject: [PATCH 18/25] re-add reset to signature and pd --- pydantic_ai_slim/pydantic_ai/models/openai.py | 3 ++ tests/models/test_anthropic.py | 35 +++---------------- tests/models/test_bedrock.py | 28 +++------------ tests/models/test_google.py | 28 +++------------ tests/models/test_mistral.py | 14 ++------ 5 files changed, 18 insertions(+), 90 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/models/openai.py b/pydantic_ai_slim/pydantic_ai/models/openai.py index a771b0659d..e7068e0b95 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -1207,6 +1207,9 @@ def _process_response( # noqa: C901 provider_details=provider_details or None, ) ) + # We only need to store the signature and raw_content once. + signature = None + provider_details = None elif signature or provider_details: items.append( ThinkingPart( diff --git a/tests/models/test_anthropic.py b/tests/models/test_anthropic.py index e57de509a0..62b4bc13ad 100644 --- a/tests/models/test_anthropic.py +++ b/tests/models/test_anthropic.py @@ -2180,36 +2180,11 @@ async def test_anthropic_model_thinking_part_from_other_model( signature=IsStr(), provider_name='openai', ), - ThinkingPart( - content=IsStr(), - id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7', - signature=IsStr(), - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7', - signature=IsStr(), - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7', - signature=IsStr(), - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7', - signature=IsStr(), - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7', - signature=IsStr(), - provider_name='openai', - ), + ThinkingPart(content=IsStr(), id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7'), + ThinkingPart(content=IsStr(), id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7'), + ThinkingPart(content=IsStr(), id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7'), + ThinkingPart(content=IsStr(), id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7'), + ThinkingPart(content=IsStr(), id='rs_68c1fda7b4d481a1a65f48aef6a6b85e06da9901a3d98ab7'), TextPart(content=IsStr(), id='msg_68c1fdbecbf081a18085a084257a9aef06da9901a3d98ab7'), ], usage=RequestUsage(input_tokens=23, output_tokens=2211, details={'reasoning_tokens': 1920}), diff --git a/tests/models/test_bedrock.py b/tests/models/test_bedrock.py index f54c303e58..190f5b3e52 100644 --- a/tests/models/test_bedrock.py +++ b/tests/models/test_bedrock.py @@ -1246,30 +1246,10 @@ async def test_bedrock_model_thinking_part_from_other_model( signature=IsStr(), provider_name='openai', ), - ThinkingPart( - content=IsStr(), - id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27', - signature=IsStr(), - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27', - signature=IsStr(), - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27', - signature=IsStr(), - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27', - signature=IsStr(), - provider_name='openai', - ), + ThinkingPart(content=IsStr(), id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27'), + ThinkingPart(content=IsStr(), id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27'), + ThinkingPart(content=IsStr(), id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27'), + ThinkingPart(content=IsStr(), id='rs_68c1ffe148588191812b659c6dc35ce60003919771fccd27'), TextPart(content=IsStr(), id='msg_68c200091ccc8191b38e07ea231e862d0003919771fccd27'), ], usage=RequestUsage(input_tokens=23, output_tokens=2030, details={'reasoning_tokens': 1728}), diff --git a/tests/models/test_google.py b/tests/models/test_google.py index efb0efddd5..89ef584249 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -2073,30 +2073,10 @@ def dummy() -> None: ... # pragma: no cover signature=IsStr(), provider_name='openai', ), - ThinkingPart( - content=IsStr(), - id='rs_68c1fb6c15c48196b964881266a03c8e0c14a8a9087e8689', - signature=IsStr(), - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c1fb6c15c48196b964881266a03c8e0c14a8a9087e8689', - signature=IsStr(), - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c1fb6c15c48196b964881266a03c8e0c14a8a9087e8689', - signature=IsStr(), - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c1fb6c15c48196b964881266a03c8e0c14a8a9087e8689', - signature=IsStr(), - provider_name='openai', - ), + ThinkingPart(content=IsStr(), id='rs_68c1fb6c15c48196b964881266a03c8e0c14a8a9087e8689'), + ThinkingPart(content=IsStr(), id='rs_68c1fb6c15c48196b964881266a03c8e0c14a8a9087e8689'), + ThinkingPart(content=IsStr(), id='rs_68c1fb6c15c48196b964881266a03c8e0c14a8a9087e8689'), + ThinkingPart(content=IsStr(), id='rs_68c1fb6c15c48196b964881266a03c8e0c14a8a9087e8689'), TextPart(content=IsStr(), id='msg_68c1fb814fdc8196aec1a46164ddf7680c14a8a9087e8689'), ], usage=RequestUsage(input_tokens=45, output_tokens=1719, details={'reasoning_tokens': 1408}), diff --git a/tests/models/test_mistral.py b/tests/models/test_mistral.py index bdb672c0b8..0d3a653b07 100644 --- a/tests/models/test_mistral.py +++ b/tests/models/test_mistral.py @@ -2385,18 +2385,8 @@ async def test_mistral_model_thinking_part(allow_model_requests: None, openai_ap signature=IsStr(), provider_name='openai', ), - ThinkingPart( - content=IsStr(), - id='rs_68bb645d50f48196a0c49fd603b87f4503498c8aa840cf12', - signature=IsStr(), - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68bb645d50f48196a0c49fd603b87f4503498c8aa840cf12', - signature=IsStr(), - provider_name='openai', - ), + ThinkingPart(content=IsStr(), id='rs_68bb645d50f48196a0c49fd603b87f4503498c8aa840cf12'), + ThinkingPart(content=IsStr(), id='rs_68bb645d50f48196a0c49fd603b87f4503498c8aa840cf12'), TextPart(content=IsStr(), id='msg_68bb64663d1c8196b9c7e78e7018cc4103498c8aa840cf12'), ], usage=RequestUsage(input_tokens=13, output_tokens=1616, details={'reasoning_tokens': 1344}), From 68c4eb7b3bd8421a34702a10369a575a5e42e9ef Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Fri, 5 Dec 2025 19:30:27 -0500 Subject: [PATCH 19/25] fix snapshots --- tests/models/test_openai.py | 7 +- tests/models/test_openai_responses.py | 164 ++++---------------------- 2 files changed, 26 insertions(+), 145 deletions(-) diff --git a/tests/models/test_openai.py b/tests/models/test_openai.py index 9e41522f98..5406a165e7 100644 --- a/tests/models/test_openai.py +++ b/tests/models/test_openai.py @@ -2246,12 +2246,7 @@ async def test_openai_model_thinking_part(allow_model_requests: None, openai_api signature=IsStr(), provider_name='openai', ), - ThinkingPart( - content=IsStr(), - id='rs_68c1fa166e9c81979ff56b16882744f1093f57e27128848a', - signature='gAAAAABowfofynE_bcBtlQwnphMqkyKvkV8Sr35i7mAX3iK-nK_d2usOyX9bxTqTs2rO9Q-rWy_925tvvxVDftIty6WSJYgydfLk3_2n4aNnc--vX7aUT5db_qTyH_367MTbp_Qr_Wcu_QkOwTuMfF5wU0RxF5PNqKwg1Owpteut0jDGs0haA6SHMMskH0sezDb9VXSTHaIq2EQuaB2n5nAVi6hy5Z6OCScNnC4aBzSnTbPOFi2qMGf4vZwyGpl-mPZn6_kEtuN0ov7K0_vj3MyT02QHrk7ADk1aWu1GFvQHunYJ8LPV1jqZnwP6ovVI080lTTBXEkwvvjJxSmt2UE-0JJ3rlKDXVEC6U-k6_wL95LbXc0MqrFSO_yLNOnytNnTctYSF6i5mwID994MvNhF_L7zRLllV4uf_XrTSBD_oHmcL8R9E5Po=', - provider_name='openai', - ), + ThinkingPart(content=IsStr(), id='rs_68c1fa166e9c81979ff56b16882744f1093f57e27128848a'), TextPart(content=IsStr(), id='msg_68c1fa1ec9448197b5c8f78a90999360093f57e27128848a'), ], usage=RequestUsage(input_tokens=13, output_tokens=1915, details={'reasoning_tokens': 1600}), diff --git a/tests/models/test_openai_responses.py b/tests/models/test_openai_responses.py index e53e601777..a1457c10b9 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -2218,36 +2218,11 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, signature=IsStr(), provider_name='openai', ), - ThinkingPart( - content=IsStr(), - id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de', - signature='gAAAAABoxCyzDT6i7ehEoWDBoDGMZmLcOX8TMbvBssJGa0cA0-7Dy6YfH759wsF0Dn5Auzz8Mp2geHtbVJVxKa-SF4Al-z3lq7gQG29dTf2ecfq_6bkg1gS49MbGEmaLo4FnS6_5oekdntomcOVO4mqwC7JKnCTO5Qyq8-Nm3POi0nOZm6KaEfqrmPHiJttupduQBkiqHIc8_CIfQ9LGqSxXZuAFQ0DbNow-6yya7_5oNOoLdgWti5_n9CENxTYyvG_q-2WAmioZM_rR54rWqmMbxUNNsKJls8xx593rb4u2dEpFJztVeifJNmFnDcYDDHMhvqLdSXJU4z3Yrxg8hgH9w2gD7Ygu2UDsMsiUdp5YGXKx_acJeu81-7H8Yf3XY86woskIv2o2XaegpK496fKkeiUAD8OTGWK0hjJb9KPK3hqTBfRfJzafQbIvnNTwOod3ZPyClgSXTYKsN1E_j3S6G8R0uzyA_NBc47Q-VMIUYf3jBTym3NUTMwiA95qdR1_1N-l4Yy7c9-X3UiRrVpNQ53lNuaUzdYuSq7XGHS_4ZNFwKXuG_dM7U2vhn_2dk2fkuEKZjtBYkVofStR8qlkswIAuEw4mrnt-wjG8cxrAwacoXop0R6NShjmWSrAhgqvAqwY3oR4HCPo_zaHSWjnJcRZ41LkVEcBSvtXqNpez2jYYmUkoGHgr_5gGpHpPo2j2lM0pBmPwPQ3OA8RJLEZYiQtabP7AKzZ32Lvsf35uhLRMZ6hkLtwPKgJ4tuR6E2B7xlZ6C0UoUbuI2Spou5dQsqPd6byXwHa22yViPpcpjeZOgHKK41cnK_tpL1kEe1KtodMW43d4OwHZ4LYqm8B769ob3uWnzGOMSGSrTsvci7gm00P0mwKBCh-XC1xdo448iGC7O_bvfYeBJNGsFObB3KqT7WLy04gc0gP7uWH629g151xRPzILeJUHsM_MwrFbNRqo9KbJFtGP0AQiQkO9lE-0VpWQW6ZyQLg6wByI-pPwakXJiCWxpxQF95NRjGOvwYyoU32ipX9mqEjdjQ-vTDn9vte8wPww0aPtAKqK-k0gkeBZAJYALVZNj6Oh0BUdA2t-XcMxs7Qho0V-LLgUjrmyM2ci71LgxeqO8I7LkOuGYMGYj2rFIGrzMeZOgucDhMyury4ELb50ohyYGjf5sOYavsYUwzK3NQwDZ3kjyHFSzCvgkuRgMLKxmME-4aRW8VbGLyC1f2hDuwxzL-cExk4yMh8TijVsf-bnRhHwmQKiR-SGkhrylfn-WnBQQffAdWpjscP9od0UJSPZrLZTaht7Z_15rMw9RO7vXl6PmcFw8vYciH58zUpU5vgq5_QGNvACSnnQxG8Nc9KmIYxGQyMow_ch1PBUP4yGYXR7Xwg0YiB6bwW5p_bxysCJAWBrp4sazb2Al3055Cfnmq9QXTFwFJo0jfbpqwPySuQ28TAiZah0CbCf_zdpJgz9hqM9HeRWHDwIKiR9OpxH2N8rWLqqRZTyfvRX7BfMF6P1bFVVagwhqljKZfcF7QFztlqKdYSGcsA6jdz1RT7B9CItJyKCnHgTYsFtxOr-7z8lkNNlb3xJAYmwYuSQszTR0nFnP4Inc_Ay8XVdmY-ppo6PMJztYQqZXB9wABGkzfKUl9UAIvjMrqHAw76sw28WTA3xxoVS64CM4YDs028hnVsL6euOe6VVBqpVMbrQ6OVi2FOR-vLbNAVBwbelAhbsqoZNMATg8bqlf3UMwacTkr_R1me2gDFv2BjxbjvlZUApzkl9L-CMnVPEsyb187O20chSrJhsy2tLh8SC_6_XCCnNFub3RAvD0BkNzDVZig_oC3ps_EEaPZgEdtbUb_GqaCFcbeo6X4wY7xkr1gZfTP_NHK8XyElajh_HP8T1fPmTZMh46rtXh5-54th6NQ_3jTjCeOfmLjbQKotLNOhJKlB8vXa2CsO575d2zkP2CAMGy9TU_ztUCfaGFOeFPN_xvz1vBZ7QqA-yA10tOdOm8b3oowPfMbZ2n5mvyLNG-DgUkjPGty5gyvJvyMgoqZao66fyzfLvM28eQMpOOcGAcozDFnW_vkffTU5GmPLUaG6rx74V32RVzaQKuC_nGBF8T_NfJ9NfecUw2uj21vCcUyTiIQb3Are8aZLnfsi4DyY-E7WhNnBoLsKZO1CzurCYKCPi4KYGjTr9og_MQM4frL9nez4teQDdUZnu3TkTqF9jRmeFMpZNLaRydPWCmumrCI7HSwb6PuBmsswxPi5Br_NcjszNq-c3t5_Gj8klCceJjDak7wjMuGYSK1GU34iRlNW7iUYUACE4FApDJciqJcRXE31-S_b7IsZ2xcMU4f0Qf1sWHuKKRiwG-Wx-AhXjDSH_tbhauB0P3JEAFg0eNnsRBwUvrYqzPRKkAJz0AUF_biQ-s3czpmmt77NBxh_IjIfVbfOs8QbHM1bgZqUzhS1f-cFLcrEypLHL49Iuy_qXlut79gr2XBsQ05ZIQvOtzCmjZ32b_P-d8oeGzW65rwq0HovxMWxwR7zHqoZD3KJ__a72HMcwK3-fYZBzjMjxOHlBxdzmy4_xsfUBMWxuXREypfY9cb8uuALpRJCebN4pIocB59ShZgTtApb2GVk2jheXHAMx8-7GAUO_W8mzJlaHtrdJd1QYFME1W-_bhfJkYJW70phqUcvVDjoBGHiiL6TxkYAFwCNUhJsvnIG8Ihm09t8TKmcrPx73MVG-euP6T1ZIVL5FFX4kOqSZW2gKg_cUr6xUhuey3sVNd5Qfl_q3PHNHVif93EpJ6iac1VQ6soW9MwuNpKURX_r6WWDx6kyeTXKmbE_6Boe4jSTq_BKYY_SYoZY8AIOrGmKBV6wemc7hR8ko5yfH5_T4V7rwHSPotueN02Xb7qAgizPUxwxuMvwiQoqo6PEI6V96_iRvTCso0mJ2k-EZ7e77Wo3X4A2EjH1ciljhDA2uQAh5QgGUgVI3QfGiaDFrgeQQOatOd-zqvM1j-WB0ZBpjYFR13O8N2ZqXQQ_AlWOmx60LQI79a-BIZb_UBzkpMpR-bsUlFq_CQv9o4cxGU3M9Orwsck_5a_V2Mlsicz8ThvLz2-MaoQvwnU3Zskde4SyRQlqMYSThRxSc1kUBsDDWgBWNrvpeVDxvLAmc8XVR_xMgCiRcyAvrv9kG3RseYoD--fqyx_YpoAGleoG4jA4FFkvZdE-MEN3CSuML2oOJAsMNgAG1mNzkbeJO53oe6qrL4ZnnYHQyayaxSMpi0FonMibsg6pHn8EZ1vKes2W9ljy02W8lfTxnaXewF5qX9uKTnfHM2s9MSdSasJCLagPDjA5ZtsRcwBMpZ6LgJuT6OZsvYyWONDM2y-BdUMN1iiIvJXaRIG-smszpElaZZimJUSPKhO3klT5LH0mZRWL03AnpauWNRdZNZhWJl7sum2bEulbxe7_Ir0LvN1IxUTbDX4TLTDwPc4vEpouKM278KKxo8idZlo0Sd-Azwu6CAvr0uIs0Vs6SqKWWvyC5B5ZmJwxJ_uEFphVW1WKxUxqhSHadoLF95BtwU23ayhu7GV6ZbpgkS9JBETCsYY1xZ0W_A02jv6SsSX45zEg7wJVgKl_EgWBlCw8QCxNirmpxcYvEbikYIBz1NscUBlLnGNIpGONVzrdtmBOkkikw0Goot8ixXePS0_7Jm1LavQIqhklO2SZ8Ve90UZCf0cO4NioF9S58mYFxQ5M4UAErTkbH6LOpmk9I3OhSUUgDwpYN9FWIc__JoAvfUIqvgxvvU13DUyTjdyWvcJyAd2qN_TqSQRreY2fiieLXTEDsZwMRy3qVKQIXVc8wd3hiztuO45EXMqW6ho3OhXFPiVhXUzzt6YJ4SFO5_yPLDOLQj0t4jOnjdvAOnt0gdiC8VSZaugxZTpQFSDPD-skDmj0CAZ9VUJhWNUnkRK_aiclAf2rouiJ1Ot9APUEtXlHR2ImVQSrepMEHDJz1ijCH6QUnkX1aTYt41RBZiEa09207Ow8X1BtTrhofjxAyLzVhEqg76sNiXHhP7J9QAYhxctefmDgk6ZUHqIeveNDeKKfeXrW2UzlLBl6S3xW1xnHBrHxp6wcjngqih1SG0eqfXWgJ_mEg9lOUrbDttiTJbTE7_XhZ2vfJ7Y626u0J6Iz7mGcPa3nCSgzskbBKQflfE0CqS-N-AjTirwU2_7Lb-ofMmbd-rWludoNtNwzh6BAKFVs66rHa-VrWSwoWR-2mMD1GD8WzsjCN4PvgTo5mOGlltDDkWROl5ibhJ-tLyAeZ4mtK5f_oVModXQtapyXA9GEoktjGtoFqE3BkMwk0i_P542lOJ3fNGI-sPyfaWRQXx56wxy470_0dwy_o3aSvJdetOxOi32BfEqfPN-TBNU3MkX_bt0FTMcXjOltnoGh6bgZI8tZ4RGHof9yBLhqVsW9aQ8LN8amNJg4JCsO75vjpW0nDgOk6cKeadSWjP3fBJ_BEmfFkDgLfGeZ_ILTxpzJ9r7yCGPdFoA1C5a1i4DT-3A0UD15W6cpgdfAYRF0Wt3i4UDopGFpASyM1_TpKBzig_iy8j4yM6qUwSShEQiGDdNohlrS2q0fS03Rk7EJEi9wFLB6GPvm4hqJoCes22TvIN14fjz8udTQXNMVEbanKdhMgckZ3sjmAakOe9APmpTbWJ0GNVXwGoErrwLlaptkA5BIk2ZW3OcRWykaHZBnCgf2dNb6II7Mjjguw6H5_J1oMqJFQqIlFnxK5B4nvDzQ-9-lLIub0QvWlPn3jxTkZXBO2rrhBwUUDlZ0NN6dtl79XwliYz0aOc9gnfKptmei73V0WXP8qrv4v4ISgRCjytAC72Uao_QoB86j0jdNNuJ-HUz4BGCB4k6pr9rkOwdwd0PY5OfJbDO6PxqiXNO6unt6IOaIoKEhs0rxpRA6GzyooaoLrVTYQxaSeJTa8I_pwuILBgUSu99DD7HhbQwrloBN7ststbloZhT8cN6SzQ2nBbU_LxnroDH6GTrHFPruSt-5jY-lj9GEm4AFsRwQrXgcL_VMzPThUdbYDOMouzuACn9xdz2bhKcGF20DlLA06ZdtWQfOeYHWwFbmUR1FToyVsUkH8Y_V0vzEDLxzXnVS_0xumFFUXltD9kp4guS4W-MWAFa7hDRBG701kJNQXZqRkzHKqpLNgAdUggl59qrgqLbFtTtco2jaj3dmuPBQFppJL0Jbms5I6lDayWkpqxURphQ7mHtKuodiEmK-srvX2V-X49zV3W_wjAdKQzIZH7qyYNud9QhOO6kBrzhAueZModu_lcYU6SaKZ_s_jPkHauZ6lB04rihZnkpF-vcRVOARctFnxGLOyLQ5zsMxtZ9HIm_s7sRMNQoKAVSaGbgH60Vp9P4yUaHZvwIOfC0cJOynP0PZ4hL-5vjkMwsfYI8rvoyg7woA7gbff9UCQtZG4W5nNzR_06goA9-G9c1DAA__-DxpDpaM68LfopLNJoendZ5jNUEjAmGQBhvPHce4WISmsxtXXonFbZQUlja5KAw1nrlPs7QnkECMPBnwzCC9dj5_8m6ZOieQn0RJPAL2vd-3wSJ5Hdndz1O6wuJVRjdHFAoGFq-azLkSJsRfimKwzPorGlUaaHd1KXZAtKVAjgRKhBVN5iHRgIMB573yZ-gD7syERLNECujzRQnSZydBPLAejqmLcreLecByKa5M0e_vN5cxjNEraw9hCg5UzCCrIQ06Xn2S50s9l6V5g9c3IuAE0u-7OVLh0CSqV0aKXg9UOl5E_9n1kn6FA7bYfEK9oUWP91X690oVqobM1EZlUoBdA3drz4tNAsp0zCgG9SleiPCzzFURdTGlzDPKvzk5V7EWiSZf5Mx4mLTJtABBRH-ovoSHLuj0L_mtlTTpXBfyHXV0KdljQ3XQAl_CRHr98HbliFTonvLQLfal-vWW7KRX7H0TYYhPFl0v12_IVI9eae5QvmLLxElJuMYnTuvauewwMxjLSovOsxnIKvaTTDBGclEKpXOOY2sDHpamRKxm9lJLi1Cpwz-6GLdUM1_v97xFGyrlJBqDjLap_c2UcDTPU8EcPiBakEVQdkmNBhz7d08PUze28JH226GnIS9_poHQfroLnxo8RNnOJqFgvMa3xb3Gd9lmGVMwvZuZVsELFnXshva46Zouz6QZQ8V7O9mRDPI4B1oG2eGocb_E74G9i4hWISG_CrOiWwWFPaChqfIbLqFJbxTWRpv30iqmD7IpLgr4hMBMj8MujxlI1BqhnhotOfvOksRkCtOmwpofL0l4YGiJ6cCtwD7ALgzLN4_nTVXR6ZaETLZTqpAfx7z7INvRDuzeSsMdFcWTlLPCsA5WrSCKMC_jtUUAyPktcEKJ6QdLNmhwZmE4FUNrUcjSYZim-ZNXrYC3U5SF9WbsbeQ4G0Tz31JF5ls08RRzsCBCQGf-TKz2PR_hMD-QUCFwhgJkw3xqqy0MONTtECZDHLUiiL04IyK-MbWtV9BIMa7B3g-q8plZ_Rwroj83CoMQbJWb9Ofe6RM_87NN1kXoc8muhMHGZkUgmq_WQMayrSiq_L0Pm2YsJOaGOyJ4sHHd_R6-OlJ6zR6W4qU9bmJSZvF58Z6oshhPQToUQXObEB0E78alCmrWNYSrcXuMqyhzVToGiAdyJoQlBrpjCAR8Ra8_wYx-8EWMzJaHXYG908knfMALVUE51f8J0AAjB1JmVwZbehBhxJrwzgJo3gmLgWNBPvItPgq8HZX8oXgM4d3PwlNnUF6IsPMsyHIYFfnggIKTHv3Mz1QDTRHJ-SIIGnEHtHiUZojIQJf3CUG_UNZAlVL-qqj05sjZahdueLVH2bVYe3Xa75AuN5v8hoUdbeQfDY1LcNk4yz4SLnss5owSXvK_0DM9V2y510RrHmBVLx0GAo8TtgpVd7Vle2TzNeUksWkmCbYsgMealTceOPQsuDPQ5Ie_1kBss8qiz727fst9SueE5hjHe9vmB99Y9O8W18a7TwRedJv2M5RbxOVhq89bXUBq0bbfVoJ5l9t-1YL4-YKESmj529Bcy71_yNzXs8yRJvSUOPhG9-z5aWonPQI30QhcJqtHG_vtAQE4kT5oDEpujitzwdbQYtntGemNGQKWNYV6CLpi499KfZ10jdeHSkbRTZFjX5J7mffEwBVBRHbptsizL6fGCdY3KkFNKNEKU_FRcYgPSyrzRe4koB_Q-2g2yvHBYqghqLsmTMcahnki8uBB_H-WawnjX0jJwKvP9_azFkvOzrQUBl0yCuklM8npNEFAjVVS_h-jQ6Fseb-lyvehp63MVFac__nIdrYoVnOi1Yihb0w4A7Xt4QFtxyfCHnp1re9zisS4msZm0dfb3s-VRRFQ8VeXWazEIUtDc6QhBiTVaOIZjCOrAOV-BCDhnKPKaJ2gK5R0QspQes0EMt1jpPhgqX6Bvxsj-SMyyKZBr9mkAo1pMb4eJw6sWWchEhXQGQIArBDezuQFEa8KbOFoZ8mohCSLZO3pANGJaE0iEB9Uk-y0ftAkFEbzf_lUi8VHa7hDCqLCOvc56isd9MfVFkMWEhbiSaUhACAac75qp63Y7VVRZAR46EfrrIHvTbFO7yebBTxgetKZc4umvt68EUWDfGqVluVWealK0t63CgYo3dk_bnaQTWxIP8fpIJjgchJjie8luPDR2ZzzanU_TMK8hdE-5iHokVnSHWCnJ8TOI8qrRk9YUPCQof9B3I9pH-KJjBQmgo2SurVLFv230SUdrgs7n4EzBYu9GNq9ryakhwoQRLbQsN40PZJuXL3YSBm4Uprptq5-e_r-FnLIk_OcMUOCv6Vupn9-pqWLCc-mTpJCUdduz5Ht8Ecb-plOc0owN_dzBDgdlzA3d4UpAk_2PNmeXRv6e_futRtKRaKJwY0q1-7XnxHpn8PqmQ1sBYVkLpEOeETh_FlSXwcK1ie10hcnE1H988srGMRCtwgPiU7gAGZPuiXq5aaaGEklYLxEvaSRkASWrIzoP6yqk_FUk65o1Q4hqDCMJhXNSnxaYNgRunsxbv4e3nevbeuuaYHrjyrhPizillKvwwGfckmOv9Y25BZSUXMwSVK9Ad3XA98NajHK8rVoiTRa1fjfBXUwVoce2JcVhuzk1zR_B3KixTZCJl7TUT6ajt70IQA-EsWfNtxdUrINMgm0ZjJVkG3ccM2MVQ0v85VUDwMEqcF3LRFAY1-6Rt0shEK9H2HSvRC-jHBl6xV7DQM0OEuWRvJAECkbRTPDs-XbZhqUQJRRb6XMDZsqeX9tCS1MLyMZ1IUQlRIj3d1auBzc6ICfraQA-cMcAyxofrnaRwhZGr__gns5coe8-DQ3YzNE776gzwLAg5k5M-3WEGJY-BbRtde7opCZnWZWLK9tezTy9ws-qLiIeOlRUu5xSnfwuy6icNYqvWvAN6FwAz2m8F56m7RrtigY8JKwpSk2Jkz2XknkCdv-yaFl4PIZoeRF_pmLSi5jSyP4-ze0owGzmSX0CIRMqZYSsS7D0d88U0DWFFupGK4Kg_I4TPgjByoRH8hZrOcsKvmavJktXN-beunsA06WH8opv2jya9gZkxgAiFIifJBVgEDM5bfFtvfD6N3QJE9TfcUPNGoFqhvEBYzVgQnj1IPrMWBEjBrhc9iCnCattATNc8LVlYbHZ3514DESdjISCctsU-fnKuLN-W9tOdSYEp4xi3phiLD3TLI679uQtifBlAYAPabNDe8ZiwI20jl5REQX10lHjvnPRK7mLHxt7PkOGAcd3hVH_w2KzrWdpf_-DM36G6Lq4HvBUH4BNk8zewp3qybZu_V5zZ2hALyRv7Ibl6pULmyoscJXJoFzBHGDr8rqnazTAwFTWVCwxCskGHkw5DPDGsm1T7ILIgAPEveVdLmmnOP4rXI_o0RGsi-nQxdavHPt67-YWOFYeNWiy1AlNlra5DvL-hfDfxCNgrvG6BbW8c7xEhoFvlR80wgfwPDckjd3U4RjjiiUfVsvgf9bx6x9-cIzlxwiRBzVMnlTPXOwqAsJ2H1e8-_tKTFjFkZuYpVRFCf5Dy4xFcvP2rHtHXE3G_ZGii_M5ZwlrBkfmVVO19lazSqpe67rPuobutmjt1bK_A8B2plrI01cZ_B9yOMzrVoZJebI_cs2Eam46VWfOFGTMoJwzLWmwmF4jt6elLw17Wlrv7yW6RoFzMVROMfRGksuezBufgDDKgpK_aX4jWJpldlI_pNRTycgieG9xHkWPsslTUPFFQ07yNArqB_9ERbiZv_4ljva8O2U4lSmi_CPocI_Gf899EBvd7QmlGl7ZswYlb-VrfcfHuSg-eV0QUH4KwQDvx2qBxL3ng0bxCBgiNsOFv8Kot9afWjUA4YKpvoHajsai91iOUEJ1KBfd-GGv_l3M9OoZtpnXre5twKtdCfllAuLcmH4HMAW6cPX41sFdFf2wwk4aaTic4f5_TX3-dSk6_epKwdmjjucflHtrFp6c9SJwf_aB7y7XYnoq3DvveOtT8LqPb92mIsSwvkxd0E6CVw2D0kpUsD8t3wWz59IeaSuGdqzS_7DCBsk240J2F0L-bAi1UmwtJySyEH6gGcb2wzuekUpoL1lbk8NvOFhqGMskpzAW31X5KlAIB5fMqYIechq2qgUTX0fbFbbK-WOS5BNuZzQHg5u-x7KCsd4M-i0-JQtTNyHDQ9_6GICe3RAa1au6QMk3bbuEeX6p2rkQNIaoaP4X4cayBr_0yu1Txn9PV28js9BnbryxWauTjYYSz02CGE1kN8STnQ-ebpq3WkorL8QcPw7VJFDRytkwSz_AslMaxmoCzvftC8nxZgEveO027csojiijwJ0gpDZYvyhMgNcPhPaLIEJrVSWkyMnkt7Pu3Y2YotbyxyjnySgVgUhvU4rplk9cHykR-1KIdnyrtAmWD1POJhmmtRF0wbMXWPg2zp4LPvH1LRywS1Si6lgMCGOMXRfOzbm8PYJDeM13j6e5PrX78ZsaM_n1Y3cDfew8Oy5guR6ja2TAzstADnEs9-ieIV6xIgARP4tLLi5JSMSDKlaite-kt4Os6cW6ZPm3O3rUthnWq5vHRByyhVEytS-ALARuaoZdc-yl0RvQp08jXqnqueILKWdaRWXJveMAB4XenxSGeCVffEuAm2HdhC0EVcS3rimTX4FSGFLOD2cUNXoB7ywSDnP5VTZ-hQKp-URDXx3YsCj_nXwyIYC4EIUN34i4YUh-DprUnNfJqW9Ev3sfByzjyNS7W1a1htCgXckmy0XBY6X8bNswm7w1ptgpLU76NGOuu1haWJp-LPwxXgDEkpG2tLQQsCKedet_QiBmarepWVN1j9ZIkDDwQE5hwRNrwRgHyGIXk-mNcXXF1gmr3q68XEt2VEur6grCHA0CN3dy4NRxuoS1P-vaRxLl0Dl9Iy7lIGoZaKP_MdGdiotIZdnxe08sBWUvZGdUMg0gpEAn6CegsiuQbLCqT1KuPoMNLKnh-33zrHA7Jo9SqxZ-xrRpwhj-bTeL4v9WgALcRO22E8vhFrVJZICjEBwUv6rpo584dUhoxWlwC3wNo8VRp08Hkbso018pjErTyQ7Is61euKF_OxAvYmHgyZVb_IaldqIHSelpu7EQaaFtvLJSiA3XOIpD4O-rZeimfmS6tOOYQad2TjTbrO15c6AY1OlCWsWAbUGQ_8NGmAijI39Vfcy1z5DJceiok_1_Ao2jh82tEMflNeI6DVEe01zDeZvTHimGVreOj7P7a8Turi7VbzP1VlxrgAxDWZmkPWRxIzfrFjfdMM21KtCE5M1FAqX9buLWcCO-PYmQEjb3_34_g5jOwywcmJXB2LVw5H1d0LpnoBrZSYi52lQaYM0pUombI4jqfrHuZUemB_uYWMdqogdGtyWr23TJeUeQg8BfxtVzjmyw5lbCwH62GSDbpyjzCv3Fn3WDq0qrjR_Xwmj2B9bJR0SgWZhOZm9ZudUOuq3VEZcuaDNvRtmUGysZWzRGRAp3AxolKhk_gTywGIytH25Hj0L28paw0xjmN8YunkxNVbegg8MnXw5l9G8SXNPhZJYKZ5HqI5XRsbwZgvJvSHy5V_G8Ie9YLVrbpoYkmT0j7ErSHXh4BQeS_zbFJosev3fmnxJIEyTz916SACv0s1ocw80aohgzjK8N8eDz5FJ2JQIBZz8TNSYmfFX_Uv93_ZwR0mOAJ2QkKdv5maUC6JU_SSSmDCqcMwp1u4-AA--Z0rSCXGHWWkdZ4vWhRbxFkCQs1IcuSQn2-OxNBImLxvxmhS8XDBKFfm9t8B6ed4TjupnNn6x0BWG2BtJ0yk7Y2ecj8XMQaiaG4MKRdUd6i6xOz7GwmtSA7ckNZef3_B-XA-vw7kYih6vhIf0sRdDX7IK3GVrsN9LbhmMeswEQJteavZGwDWF-piCpBMJ4LWcwsKI534unKNAPhzVPIiczSD1gM8ykZnxVWZYfX4Gd5TC96tdoQq9Z9e-d7uksaInDQr-NSo9rMPPm2quIe_GUEeqzvRHVDmaJkmP-4CeMGghGHQHozDXavc8os__2len8ZFyVAKnyHfhn6D7eo4aHnPL3J4frq7M6SLDjdvunW9OCmROtmSkXjvFwM09w95KEcroXJBkM7bsA-Z6KU-uTwADINUA4TH3K3Y7R0oRmCBtWzT_mQaIE2fgqbwyI5ZhmjelOG8QZYPCK9OtqYwNw1pHDFeHHM9EcXrux-jfccDUJ4IPdOKGOkPurJx7EJv_Ed0sh1IKaYzNRuvsUJGbVU_xyb1nef-Fic6P38JCrC7EYEzLKdtKNCFTacUn9OO3Ygf9b833fcjfG0LYWZeCINxKp1OeGsOTd6am8kwL9Dwx41BbBRHHxb2Fa_w8oneZ5f5yQmHlKvhJ7Rh6hUEYWDCUOG2njMVe0BeI9H8bxzxeWZI4RCXYa0sbEbCqk30ivJI1pdzYuuyk9cc4qUbsPdIScAcSXk7NqBlS82Lz7kDtFjrRtNOVhrjpjlKV-a9W6-rPB0U2savy6xjp-e7yPL_S1Spt10edRjtxHt-AvX3qh56EJdILHPX1MbxFol5LhH9evz_dw2Pe9gxOTYS6S58qxcxX4Nb-KfXngnxaeJ48SsKN-TKi2TWntVLsjDBLPUO1LXrFw8_ZjijdW9j0SxZkOEbnvI3uJ3jvEVxMxUojlfUh7TvKdR209jBuO2ezWcLt3CKfRG6Ak0FjcugJ8ByMucCG5mGMOB7UyWCTurM4FvTeHHAN20C16LRkZ8VyANz-Oe9YfYFO9lrofS1-3jm8UoZ5AbIjCkOCAdOdVEo8RBOh_P8wOTVaYlURHOfeXniL51czYw3UjyIkMftiVXghc5KAWhwrqOkeTPDa3b4zImVqd00u-fsVl9_-c25qR-K1UaiwEEvF0ZJK1TTjMNerCVNezaycd8KZ8ktdaqQD9bvx3okUSpKFZ_WZtgRg4oOlf7ac1ba0PUyigxms9I-9f6snYfzyefP3elvMXL4KpbcDfDcxEWrwFiQ-xDSHjHLrve-irM1DEbgNY85C4XciSOq_fMVut-s6GulegmFjJYOukwLjpLFrEEaenpEKKQlN0upzQcHmdUm1XPUuOFrevg3IMzIpYoYjpsMHtJPXEhViPcpt2uwwRH6gWGtt9wX1KFlYeES1LfdNYBgBA4myFQwz8TR3EeojBxTwtW_pIX5P_A0byfabD2BCEKDZwmgiLfSA25skSB57d2WllO8GkY0pdKBkprewSBb9rqcrRDIk-wd_hSX5NGSnlUGY2-hU0ng1erQeYamS5pYw-BUVTtka3WdDIK4Xg_-RXXg08hfdruAZT-QNBr4KhSVX1l_W-BACPuXirWu1LH12Fu1LQ7X168GjM3ncmfW1abNU6auYfJoxOYTvditijm4SHidFcLNNOYGTOe5WkNNUMKhfjPI03_ofrwmbC0XZvgrUdRPNLM4ocIb4u9W6_LuDRcxd_pnv061OvmBXLYjVQx_O5sscdftVxVj70DaT1Xt1CI51THYtlr0iA_r-xYFTYEMBvNOdz8mzQOblwbeLqnhFWvkcjBj__0K8brz9WTkKJDmq1JPTkG6h-hjPgAcyL-ayVuWJ0iLlvXObqalnNWZ41zyc5XG2uOX2roF2EMOwjZ4Io5eAnhR5ZkhxBJTm9egvFyZ-sU9ibMw4dglZ-_mESgmo6AF7UKR77czR_c6gaTUOdu_U=', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de', - signature='gAAAAABoxCyzDT6i7ehEoWDBoDGMZmLcOX8TMbvBssJGa0cA0-7Dy6YfH759wsF0Dn5Auzz8Mp2geHtbVJVxKa-SF4Al-z3lq7gQG29dTf2ecfq_6bkg1gS49MbGEmaLo4FnS6_5oekdntomcOVO4mqwC7JKnCTO5Qyq8-Nm3POi0nOZm6KaEfqrmPHiJttupduQBkiqHIc8_CIfQ9LGqSxXZuAFQ0DbNow-6yya7_5oNOoLdgWti5_n9CENxTYyvG_q-2WAmioZM_rR54rWqmMbxUNNsKJls8xx593rb4u2dEpFJztVeifJNmFnDcYDDHMhvqLdSXJU4z3Yrxg8hgH9w2gD7Ygu2UDsMsiUdp5YGXKx_acJeu81-7H8Yf3XY86woskIv2o2XaegpK496fKkeiUAD8OTGWK0hjJb9KPK3hqTBfRfJzafQbIvnNTwOod3ZPyClgSXTYKsN1E_j3S6G8R0uzyA_NBc47Q-VMIUYf3jBTym3NUTMwiA95qdR1_1N-l4Yy7c9-X3UiRrVpNQ53lNuaUzdYuSq7XGHS_4ZNFwKXuG_dM7U2vhn_2dk2fkuEKZjtBYkVofStR8qlkswIAuEw4mrnt-wjG8cxrAwacoXop0R6NShjmWSrAhgqvAqwY3oR4HCPo_zaHSWjnJcRZ41LkVEcBSvtXqNpez2jYYmUkoGHgr_5gGpHpPo2j2lM0pBmPwPQ3OA8RJLEZYiQtabP7AKzZ32Lvsf35uhLRMZ6hkLtwPKgJ4tuR6E2B7xlZ6C0UoUbuI2Spou5dQsqPd6byXwHa22yViPpcpjeZOgHKK41cnK_tpL1kEe1KtodMW43d4OwHZ4LYqm8B769ob3uWnzGOMSGSrTsvci7gm00P0mwKBCh-XC1xdo448iGC7O_bvfYeBJNGsFObB3KqT7WLy04gc0gP7uWH629g151xRPzILeJUHsM_MwrFbNRqo9KbJFtGP0AQiQkO9lE-0VpWQW6ZyQLg6wByI-pPwakXJiCWxpxQF95NRjGOvwYyoU32ipX9mqEjdjQ-vTDn9vte8wPww0aPtAKqK-k0gkeBZAJYALVZNj6Oh0BUdA2t-XcMxs7Qho0V-LLgUjrmyM2ci71LgxeqO8I7LkOuGYMGYj2rFIGrzMeZOgucDhMyury4ELb50ohyYGjf5sOYavsYUwzK3NQwDZ3kjyHFSzCvgkuRgMLKxmME-4aRW8VbGLyC1f2hDuwxzL-cExk4yMh8TijVsf-bnRhHwmQKiR-SGkhrylfn-WnBQQffAdWpjscP9od0UJSPZrLZTaht7Z_15rMw9RO7vXl6PmcFw8vYciH58zUpU5vgq5_QGNvACSnnQxG8Nc9KmIYxGQyMow_ch1PBUP4yGYXR7Xwg0YiB6bwW5p_bxysCJAWBrp4sazb2Al3055Cfnmq9QXTFwFJo0jfbpqwPySuQ28TAiZah0CbCf_zdpJgz9hqM9HeRWHDwIKiR9OpxH2N8rWLqqRZTyfvRX7BfMF6P1bFVVagwhqljKZfcF7QFztlqKdYSGcsA6jdz1RT7B9CItJyKCnHgTYsFtxOr-7z8lkNNlb3xJAYmwYuSQszTR0nFnP4Inc_Ay8XVdmY-ppo6PMJztYQqZXB9wABGkzfKUl9UAIvjMrqHAw76sw28WTA3xxoVS64CM4YDs028hnVsL6euOe6VVBqpVMbrQ6OVi2FOR-vLbNAVBwbelAhbsqoZNMATg8bqlf3UMwacTkr_R1me2gDFv2BjxbjvlZUApzkl9L-CMnVPEsyb187O20chSrJhsy2tLh8SC_6_XCCnNFub3RAvD0BkNzDVZig_oC3ps_EEaPZgEdtbUb_GqaCFcbeo6X4wY7xkr1gZfTP_NHK8XyElajh_HP8T1fPmTZMh46rtXh5-54th6NQ_3jTjCeOfmLjbQKotLNOhJKlB8vXa2CsO575d2zkP2CAMGy9TU_ztUCfaGFOeFPN_xvz1vBZ7QqA-yA10tOdOm8b3oowPfMbZ2n5mvyLNG-DgUkjPGty5gyvJvyMgoqZao66fyzfLvM28eQMpOOcGAcozDFnW_vkffTU5GmPLUaG6rx74V32RVzaQKuC_nGBF8T_NfJ9NfecUw2uj21vCcUyTiIQb3Are8aZLnfsi4DyY-E7WhNnBoLsKZO1CzurCYKCPi4KYGjTr9og_MQM4frL9nez4teQDdUZnu3TkTqF9jRmeFMpZNLaRydPWCmumrCI7HSwb6PuBmsswxPi5Br_NcjszNq-c3t5_Gj8klCceJjDak7wjMuGYSK1GU34iRlNW7iUYUACE4FApDJciqJcRXE31-S_b7IsZ2xcMU4f0Qf1sWHuKKRiwG-Wx-AhXjDSH_tbhauB0P3JEAFg0eNnsRBwUvrYqzPRKkAJz0AUF_biQ-s3czpmmt77NBxh_IjIfVbfOs8QbHM1bgZqUzhS1f-cFLcrEypLHL49Iuy_qXlut79gr2XBsQ05ZIQvOtzCmjZ32b_P-d8oeGzW65rwq0HovxMWxwR7zHqoZD3KJ__a72HMcwK3-fYZBzjMjxOHlBxdzmy4_xsfUBMWxuXREypfY9cb8uuALpRJCebN4pIocB59ShZgTtApb2GVk2jheXHAMx8-7GAUO_W8mzJlaHtrdJd1QYFME1W-_bhfJkYJW70phqUcvVDjoBGHiiL6TxkYAFwCNUhJsvnIG8Ihm09t8TKmcrPx73MVG-euP6T1ZIVL5FFX4kOqSZW2gKg_cUr6xUhuey3sVNd5Qfl_q3PHNHVif93EpJ6iac1VQ6soW9MwuNpKURX_r6WWDx6kyeTXKmbE_6Boe4jSTq_BKYY_SYoZY8AIOrGmKBV6wemc7hR8ko5yfH5_T4V7rwHSPotueN02Xb7qAgizPUxwxuMvwiQoqo6PEI6V96_iRvTCso0mJ2k-EZ7e77Wo3X4A2EjH1ciljhDA2uQAh5QgGUgVI3QfGiaDFrgeQQOatOd-zqvM1j-WB0ZBpjYFR13O8N2ZqXQQ_AlWOmx60LQI79a-BIZb_UBzkpMpR-bsUlFq_CQv9o4cxGU3M9Orwsck_5a_V2Mlsicz8ThvLz2-MaoQvwnU3Zskde4SyRQlqMYSThRxSc1kUBsDDWgBWNrvpeVDxvLAmc8XVR_xMgCiRcyAvrv9kG3RseYoD--fqyx_YpoAGleoG4jA4FFkvZdE-MEN3CSuML2oOJAsMNgAG1mNzkbeJO53oe6qrL4ZnnYHQyayaxSMpi0FonMibsg6pHn8EZ1vKes2W9ljy02W8lfTxnaXewF5qX9uKTnfHM2s9MSdSasJCLagPDjA5ZtsRcwBMpZ6LgJuT6OZsvYyWONDM2y-BdUMN1iiIvJXaRIG-smszpElaZZimJUSPKhO3klT5LH0mZRWL03AnpauWNRdZNZhWJl7sum2bEulbxe7_Ir0LvN1IxUTbDX4TLTDwPc4vEpouKM278KKxo8idZlo0Sd-Azwu6CAvr0uIs0Vs6SqKWWvyC5B5ZmJwxJ_uEFphVW1WKxUxqhSHadoLF95BtwU23ayhu7GV6ZbpgkS9JBETCsYY1xZ0W_A02jv6SsSX45zEg7wJVgKl_EgWBlCw8QCxNirmpxcYvEbikYIBz1NscUBlLnGNIpGONVzrdtmBOkkikw0Goot8ixXePS0_7Jm1LavQIqhklO2SZ8Ve90UZCf0cO4NioF9S58mYFxQ5M4UAErTkbH6LOpmk9I3OhSUUgDwpYN9FWIc__JoAvfUIqvgxvvU13DUyTjdyWvcJyAd2qN_TqSQRreY2fiieLXTEDsZwMRy3qVKQIXVc8wd3hiztuO45EXMqW6ho3OhXFPiVhXUzzt6YJ4SFO5_yPLDOLQj0t4jOnjdvAOnt0gdiC8VSZaugxZTpQFSDPD-skDmj0CAZ9VUJhWNUnkRK_aiclAf2rouiJ1Ot9APUEtXlHR2ImVQSrepMEHDJz1ijCH6QUnkX1aTYt41RBZiEa09207Ow8X1BtTrhofjxAyLzVhEqg76sNiXHhP7J9QAYhxctefmDgk6ZUHqIeveNDeKKfeXrW2UzlLBl6S3xW1xnHBrHxp6wcjngqih1SG0eqfXWgJ_mEg9lOUrbDttiTJbTE7_XhZ2vfJ7Y626u0J6Iz7mGcPa3nCSgzskbBKQflfE0CqS-N-AjTirwU2_7Lb-ofMmbd-rWludoNtNwzh6BAKFVs66rHa-VrWSwoWR-2mMD1GD8WzsjCN4PvgTo5mOGlltDDkWROl5ibhJ-tLyAeZ4mtK5f_oVModXQtapyXA9GEoktjGtoFqE3BkMwk0i_P542lOJ3fNGI-sPyfaWRQXx56wxy470_0dwy_o3aSvJdetOxOi32BfEqfPN-TBNU3MkX_bt0FTMcXjOltnoGh6bgZI8tZ4RGHof9yBLhqVsW9aQ8LN8amNJg4JCsO75vjpW0nDgOk6cKeadSWjP3fBJ_BEmfFkDgLfGeZ_ILTxpzJ9r7yCGPdFoA1C5a1i4DT-3A0UD15W6cpgdfAYRF0Wt3i4UDopGFpASyM1_TpKBzig_iy8j4yM6qUwSShEQiGDdNohlrS2q0fS03Rk7EJEi9wFLB6GPvm4hqJoCes22TvIN14fjz8udTQXNMVEbanKdhMgckZ3sjmAakOe9APmpTbWJ0GNVXwGoErrwLlaptkA5BIk2ZW3OcRWykaHZBnCgf2dNb6II7Mjjguw6H5_J1oMqJFQqIlFnxK5B4nvDzQ-9-lLIub0QvWlPn3jxTkZXBO2rrhBwUUDlZ0NN6dtl79XwliYz0aOc9gnfKptmei73V0WXP8qrv4v4ISgRCjytAC72Uao_QoB86j0jdNNuJ-HUz4BGCB4k6pr9rkOwdwd0PY5OfJbDO6PxqiXNO6unt6IOaIoKEhs0rxpRA6GzyooaoLrVTYQxaSeJTa8I_pwuILBgUSu99DD7HhbQwrloBN7ststbloZhT8cN6SzQ2nBbU_LxnroDH6GTrHFPruSt-5jY-lj9GEm4AFsRwQrXgcL_VMzPThUdbYDOMouzuACn9xdz2bhKcGF20DlLA06ZdtWQfOeYHWwFbmUR1FToyVsUkH8Y_V0vzEDLxzXnVS_0xumFFUXltD9kp4guS4W-MWAFa7hDRBG701kJNQXZqRkzHKqpLNgAdUggl59qrgqLbFtTtco2jaj3dmuPBQFppJL0Jbms5I6lDayWkpqxURphQ7mHtKuodiEmK-srvX2V-X49zV3W_wjAdKQzIZH7qyYNud9QhOO6kBrzhAueZModu_lcYU6SaKZ_s_jPkHauZ6lB04rihZnkpF-vcRVOARctFnxGLOyLQ5zsMxtZ9HIm_s7sRMNQoKAVSaGbgH60Vp9P4yUaHZvwIOfC0cJOynP0PZ4hL-5vjkMwsfYI8rvoyg7woA7gbff9UCQtZG4W5nNzR_06goA9-G9c1DAA__-DxpDpaM68LfopLNJoendZ5jNUEjAmGQBhvPHce4WISmsxtXXonFbZQUlja5KAw1nrlPs7QnkECMPBnwzCC9dj5_8m6ZOieQn0RJPAL2vd-3wSJ5Hdndz1O6wuJVRjdHFAoGFq-azLkSJsRfimKwzPorGlUaaHd1KXZAtKVAjgRKhBVN5iHRgIMB573yZ-gD7syERLNECujzRQnSZydBPLAejqmLcreLecByKa5M0e_vN5cxjNEraw9hCg5UzCCrIQ06Xn2S50s9l6V5g9c3IuAE0u-7OVLh0CSqV0aKXg9UOl5E_9n1kn6FA7bYfEK9oUWP91X690oVqobM1EZlUoBdA3drz4tNAsp0zCgG9SleiPCzzFURdTGlzDPKvzk5V7EWiSZf5Mx4mLTJtABBRH-ovoSHLuj0L_mtlTTpXBfyHXV0KdljQ3XQAl_CRHr98HbliFTonvLQLfal-vWW7KRX7H0TYYhPFl0v12_IVI9eae5QvmLLxElJuMYnTuvauewwMxjLSovOsxnIKvaTTDBGclEKpXOOY2sDHpamRKxm9lJLi1Cpwz-6GLdUM1_v97xFGyrlJBqDjLap_c2UcDTPU8EcPiBakEVQdkmNBhz7d08PUze28JH226GnIS9_poHQfroLnxo8RNnOJqFgvMa3xb3Gd9lmGVMwvZuZVsELFnXshva46Zouz6QZQ8V7O9mRDPI4B1oG2eGocb_E74G9i4hWISG_CrOiWwWFPaChqfIbLqFJbxTWRpv30iqmD7IpLgr4hMBMj8MujxlI1BqhnhotOfvOksRkCtOmwpofL0l4YGiJ6cCtwD7ALgzLN4_nTVXR6ZaETLZTqpAfx7z7INvRDuzeSsMdFcWTlLPCsA5WrSCKMC_jtUUAyPktcEKJ6QdLNmhwZmE4FUNrUcjSYZim-ZNXrYC3U5SF9WbsbeQ4G0Tz31JF5ls08RRzsCBCQGf-TKz2PR_hMD-QUCFwhgJkw3xqqy0MONTtECZDHLUiiL04IyK-MbWtV9BIMa7B3g-q8plZ_Rwroj83CoMQbJWb9Ofe6RM_87NN1kXoc8muhMHGZkUgmq_WQMayrSiq_L0Pm2YsJOaGOyJ4sHHd_R6-OlJ6zR6W4qU9bmJSZvF58Z6oshhPQToUQXObEB0E78alCmrWNYSrcXuMqyhzVToGiAdyJoQlBrpjCAR8Ra8_wYx-8EWMzJaHXYG908knfMALVUE51f8J0AAjB1JmVwZbehBhxJrwzgJo3gmLgWNBPvItPgq8HZX8oXgM4d3PwlNnUF6IsPMsyHIYFfnggIKTHv3Mz1QDTRHJ-SIIGnEHtHiUZojIQJf3CUG_UNZAlVL-qqj05sjZahdueLVH2bVYe3Xa75AuN5v8hoUdbeQfDY1LcNk4yz4SLnss5owSXvK_0DM9V2y510RrHmBVLx0GAo8TtgpVd7Vle2TzNeUksWkmCbYsgMealTceOPQsuDPQ5Ie_1kBss8qiz727fst9SueE5hjHe9vmB99Y9O8W18a7TwRedJv2M5RbxOVhq89bXUBq0bbfVoJ5l9t-1YL4-YKESmj529Bcy71_yNzXs8yRJvSUOPhG9-z5aWonPQI30QhcJqtHG_vtAQE4kT5oDEpujitzwdbQYtntGemNGQKWNYV6CLpi499KfZ10jdeHSkbRTZFjX5J7mffEwBVBRHbptsizL6fGCdY3KkFNKNEKU_FRcYgPSyrzRe4koB_Q-2g2yvHBYqghqLsmTMcahnki8uBB_H-WawnjX0jJwKvP9_azFkvOzrQUBl0yCuklM8npNEFAjVVS_h-jQ6Fseb-lyvehp63MVFac__nIdrYoVnOi1Yihb0w4A7Xt4QFtxyfCHnp1re9zisS4msZm0dfb3s-VRRFQ8VeXWazEIUtDc6QhBiTVaOIZjCOrAOV-BCDhnKPKaJ2gK5R0QspQes0EMt1jpPhgqX6Bvxsj-SMyyKZBr9mkAo1pMb4eJw6sWWchEhXQGQIArBDezuQFEa8KbOFoZ8mohCSLZO3pANGJaE0iEB9Uk-y0ftAkFEbzf_lUi8VHa7hDCqLCOvc56isd9MfVFkMWEhbiSaUhACAac75qp63Y7VVRZAR46EfrrIHvTbFO7yebBTxgetKZc4umvt68EUWDfGqVluVWealK0t63CgYo3dk_bnaQTWxIP8fpIJjgchJjie8luPDR2ZzzanU_TMK8hdE-5iHokVnSHWCnJ8TOI8qrRk9YUPCQof9B3I9pH-KJjBQmgo2SurVLFv230SUdrgs7n4EzBYu9GNq9ryakhwoQRLbQsN40PZJuXL3YSBm4Uprptq5-e_r-FnLIk_OcMUOCv6Vupn9-pqWLCc-mTpJCUdduz5Ht8Ecb-plOc0owN_dzBDgdlzA3d4UpAk_2PNmeXRv6e_futRtKRaKJwY0q1-7XnxHpn8PqmQ1sBYVkLpEOeETh_FlSXwcK1ie10hcnE1H988srGMRCtwgPiU7gAGZPuiXq5aaaGEklYLxEvaSRkASWrIzoP6yqk_FUk65o1Q4hqDCMJhXNSnxaYNgRunsxbv4e3nevbeuuaYHrjyrhPizillKvwwGfckmOv9Y25BZSUXMwSVK9Ad3XA98NajHK8rVoiTRa1fjfBXUwVoce2JcVhuzk1zR_B3KixTZCJl7TUT6ajt70IQA-EsWfNtxdUrINMgm0ZjJVkG3ccM2MVQ0v85VUDwMEqcF3LRFAY1-6Rt0shEK9H2HSvRC-jHBl6xV7DQM0OEuWRvJAECkbRTPDs-XbZhqUQJRRb6XMDZsqeX9tCS1MLyMZ1IUQlRIj3d1auBzc6ICfraQA-cMcAyxofrnaRwhZGr__gns5coe8-DQ3YzNE776gzwLAg5k5M-3WEGJY-BbRtde7opCZnWZWLK9tezTy9ws-qLiIeOlRUu5xSnfwuy6icNYqvWvAN6FwAz2m8F56m7RrtigY8JKwpSk2Jkz2XknkCdv-yaFl4PIZoeRF_pmLSi5jSyP4-ze0owGzmSX0CIRMqZYSsS7D0d88U0DWFFupGK4Kg_I4TPgjByoRH8hZrOcsKvmavJktXN-beunsA06WH8opv2jya9gZkxgAiFIifJBVgEDM5bfFtvfD6N3QJE9TfcUPNGoFqhvEBYzVgQnj1IPrMWBEjBrhc9iCnCattATNc8LVlYbHZ3514DESdjISCctsU-fnKuLN-W9tOdSYEp4xi3phiLD3TLI679uQtifBlAYAPabNDe8ZiwI20jl5REQX10lHjvnPRK7mLHxt7PkOGAcd3hVH_w2KzrWdpf_-DM36G6Lq4HvBUH4BNk8zewp3qybZu_V5zZ2hALyRv7Ibl6pULmyoscJXJoFzBHGDr8rqnazTAwFTWVCwxCskGHkw5DPDGsm1T7ILIgAPEveVdLmmnOP4rXI_o0RGsi-nQxdavHPt67-YWOFYeNWiy1AlNlra5DvL-hfDfxCNgrvG6BbW8c7xEhoFvlR80wgfwPDckjd3U4RjjiiUfVsvgf9bx6x9-cIzlxwiRBzVMnlTPXOwqAsJ2H1e8-_tKTFjFkZuYpVRFCf5Dy4xFcvP2rHtHXE3G_ZGii_M5ZwlrBkfmVVO19lazSqpe67rPuobutmjt1bK_A8B2plrI01cZ_B9yOMzrVoZJebI_cs2Eam46VWfOFGTMoJwzLWmwmF4jt6elLw17Wlrv7yW6RoFzMVROMfRGksuezBufgDDKgpK_aX4jWJpldlI_pNRTycgieG9xHkWPsslTUPFFQ07yNArqB_9ERbiZv_4ljva8O2U4lSmi_CPocI_Gf899EBvd7QmlGl7ZswYlb-VrfcfHuSg-eV0QUH4KwQDvx2qBxL3ng0bxCBgiNsOFv8Kot9afWjUA4YKpvoHajsai91iOUEJ1KBfd-GGv_l3M9OoZtpnXre5twKtdCfllAuLcmH4HMAW6cPX41sFdFf2wwk4aaTic4f5_TX3-dSk6_epKwdmjjucflHtrFp6c9SJwf_aB7y7XYnoq3DvveOtT8LqPb92mIsSwvkxd0E6CVw2D0kpUsD8t3wWz59IeaSuGdqzS_7DCBsk240J2F0L-bAi1UmwtJySyEH6gGcb2wzuekUpoL1lbk8NvOFhqGMskpzAW31X5KlAIB5fMqYIechq2qgUTX0fbFbbK-WOS5BNuZzQHg5u-x7KCsd4M-i0-JQtTNyHDQ9_6GICe3RAa1au6QMk3bbuEeX6p2rkQNIaoaP4X4cayBr_0yu1Txn9PV28js9BnbryxWauTjYYSz02CGE1kN8STnQ-ebpq3WkorL8QcPw7VJFDRytkwSz_AslMaxmoCzvftC8nxZgEveO027csojiijwJ0gpDZYvyhMgNcPhPaLIEJrVSWkyMnkt7Pu3Y2YotbyxyjnySgVgUhvU4rplk9cHykR-1KIdnyrtAmWD1POJhmmtRF0wbMXWPg2zp4LPvH1LRywS1Si6lgMCGOMXRfOzbm8PYJDeM13j6e5PrX78ZsaM_n1Y3cDfew8Oy5guR6ja2TAzstADnEs9-ieIV6xIgARP4tLLi5JSMSDKlaite-kt4Os6cW6ZPm3O3rUthnWq5vHRByyhVEytS-ALARuaoZdc-yl0RvQp08jXqnqueILKWdaRWXJveMAB4XenxSGeCVffEuAm2HdhC0EVcS3rimTX4FSGFLOD2cUNXoB7ywSDnP5VTZ-hQKp-URDXx3YsCj_nXwyIYC4EIUN34i4YUh-DprUnNfJqW9Ev3sfByzjyNS7W1a1htCgXckmy0XBY6X8bNswm7w1ptgpLU76NGOuu1haWJp-LPwxXgDEkpG2tLQQsCKedet_QiBmarepWVN1j9ZIkDDwQE5hwRNrwRgHyGIXk-mNcXXF1gmr3q68XEt2VEur6grCHA0CN3dy4NRxuoS1P-vaRxLl0Dl9Iy7lIGoZaKP_MdGdiotIZdnxe08sBWUvZGdUMg0gpEAn6CegsiuQbLCqT1KuPoMNLKnh-33zrHA7Jo9SqxZ-xrRpwhj-bTeL4v9WgALcRO22E8vhFrVJZICjEBwUv6rpo584dUhoxWlwC3wNo8VRp08Hkbso018pjErTyQ7Is61euKF_OxAvYmHgyZVb_IaldqIHSelpu7EQaaFtvLJSiA3XOIpD4O-rZeimfmS6tOOYQad2TjTbrO15c6AY1OlCWsWAbUGQ_8NGmAijI39Vfcy1z5DJceiok_1_Ao2jh82tEMflNeI6DVEe01zDeZvTHimGVreOj7P7a8Turi7VbzP1VlxrgAxDWZmkPWRxIzfrFjfdMM21KtCE5M1FAqX9buLWcCO-PYmQEjb3_34_g5jOwywcmJXB2LVw5H1d0LpnoBrZSYi52lQaYM0pUombI4jqfrHuZUemB_uYWMdqogdGtyWr23TJeUeQg8BfxtVzjmyw5lbCwH62GSDbpyjzCv3Fn3WDq0qrjR_Xwmj2B9bJR0SgWZhOZm9ZudUOuq3VEZcuaDNvRtmUGysZWzRGRAp3AxolKhk_gTywGIytH25Hj0L28paw0xjmN8YunkxNVbegg8MnXw5l9G8SXNPhZJYKZ5HqI5XRsbwZgvJvSHy5V_G8Ie9YLVrbpoYkmT0j7ErSHXh4BQeS_zbFJosev3fmnxJIEyTz916SACv0s1ocw80aohgzjK8N8eDz5FJ2JQIBZz8TNSYmfFX_Uv93_ZwR0mOAJ2QkKdv5maUC6JU_SSSmDCqcMwp1u4-AA--Z0rSCXGHWWkdZ4vWhRbxFkCQs1IcuSQn2-OxNBImLxvxmhS8XDBKFfm9t8B6ed4TjupnNn6x0BWG2BtJ0yk7Y2ecj8XMQaiaG4MKRdUd6i6xOz7GwmtSA7ckNZef3_B-XA-vw7kYih6vhIf0sRdDX7IK3GVrsN9LbhmMeswEQJteavZGwDWF-piCpBMJ4LWcwsKI534unKNAPhzVPIiczSD1gM8ykZnxVWZYfX4Gd5TC96tdoQq9Z9e-d7uksaInDQr-NSo9rMPPm2quIe_GUEeqzvRHVDmaJkmP-4CeMGghGHQHozDXavc8os__2len8ZFyVAKnyHfhn6D7eo4aHnPL3J4frq7M6SLDjdvunW9OCmROtmSkXjvFwM09w95KEcroXJBkM7bsA-Z6KU-uTwADINUA4TH3K3Y7R0oRmCBtWzT_mQaIE2fgqbwyI5ZhmjelOG8QZYPCK9OtqYwNw1pHDFeHHM9EcXrux-jfccDUJ4IPdOKGOkPurJx7EJv_Ed0sh1IKaYzNRuvsUJGbVU_xyb1nef-Fic6P38JCrC7EYEzLKdtKNCFTacUn9OO3Ygf9b833fcjfG0LYWZeCINxKp1OeGsOTd6am8kwL9Dwx41BbBRHHxb2Fa_w8oneZ5f5yQmHlKvhJ7Rh6hUEYWDCUOG2njMVe0BeI9H8bxzxeWZI4RCXYa0sbEbCqk30ivJI1pdzYuuyk9cc4qUbsPdIScAcSXk7NqBlS82Lz7kDtFjrRtNOVhrjpjlKV-a9W6-rPB0U2savy6xjp-e7yPL_S1Spt10edRjtxHt-AvX3qh56EJdILHPX1MbxFol5LhH9evz_dw2Pe9gxOTYS6S58qxcxX4Nb-KfXngnxaeJ48SsKN-TKi2TWntVLsjDBLPUO1LXrFw8_ZjijdW9j0SxZkOEbnvI3uJ3jvEVxMxUojlfUh7TvKdR209jBuO2ezWcLt3CKfRG6Ak0FjcugJ8ByMucCG5mGMOB7UyWCTurM4FvTeHHAN20C16LRkZ8VyANz-Oe9YfYFO9lrofS1-3jm8UoZ5AbIjCkOCAdOdVEo8RBOh_P8wOTVaYlURHOfeXniL51czYw3UjyIkMftiVXghc5KAWhwrqOkeTPDa3b4zImVqd00u-fsVl9_-c25qR-K1UaiwEEvF0ZJK1TTjMNerCVNezaycd8KZ8ktdaqQD9bvx3okUSpKFZ_WZtgRg4oOlf7ac1ba0PUyigxms9I-9f6snYfzyefP3elvMXL4KpbcDfDcxEWrwFiQ-xDSHjHLrve-irM1DEbgNY85C4XciSOq_fMVut-s6GulegmFjJYOukwLjpLFrEEaenpEKKQlN0upzQcHmdUm1XPUuOFrevg3IMzIpYoYjpsMHtJPXEhViPcpt2uwwRH6gWGtt9wX1KFlYeES1LfdNYBgBA4myFQwz8TR3EeojBxTwtW_pIX5P_A0byfabD2BCEKDZwmgiLfSA25skSB57d2WllO8GkY0pdKBkprewSBb9rqcrRDIk-wd_hSX5NGSnlUGY2-hU0ng1erQeYamS5pYw-BUVTtka3WdDIK4Xg_-RXXg08hfdruAZT-QNBr4KhSVX1l_W-BACPuXirWu1LH12Fu1LQ7X168GjM3ncmfW1abNU6auYfJoxOYTvditijm4SHidFcLNNOYGTOe5WkNNUMKhfjPI03_ofrwmbC0XZvgrUdRPNLM4ocIb4u9W6_LuDRcxd_pnv061OvmBXLYjVQx_O5sscdftVxVj70DaT1Xt1CI51THYtlr0iA_r-xYFTYEMBvNOdz8mzQOblwbeLqnhFWvkcjBj__0K8brz9WTkKJDmq1JPTkG6h-hjPgAcyL-ayVuWJ0iLlvXObqalnNWZ41zyc5XG2uOX2roF2EMOwjZ4Io5eAnhR5ZkhxBJTm9egvFyZ-sU9ibMw4dglZ-_mESgmo6AF7UKR77czR_c6gaTUOdu_U=', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de', - signature='gAAAAABoxCyzDT6i7ehEoWDBoDGMZmLcOX8TMbvBssJGa0cA0-7Dy6YfH759wsF0Dn5Auzz8Mp2geHtbVJVxKa-SF4Al-z3lq7gQG29dTf2ecfq_6bkg1gS49MbGEmaLo4FnS6_5oekdntomcOVO4mqwC7JKnCTO5Qyq8-Nm3POi0nOZm6KaEfqrmPHiJttupduQBkiqHIc8_CIfQ9LGqSxXZuAFQ0DbNow-6yya7_5oNOoLdgWti5_n9CENxTYyvG_q-2WAmioZM_rR54rWqmMbxUNNsKJls8xx593rb4u2dEpFJztVeifJNmFnDcYDDHMhvqLdSXJU4z3Yrxg8hgH9w2gD7Ygu2UDsMsiUdp5YGXKx_acJeu81-7H8Yf3XY86woskIv2o2XaegpK496fKkeiUAD8OTGWK0hjJb9KPK3hqTBfRfJzafQbIvnNTwOod3ZPyClgSXTYKsN1E_j3S6G8R0uzyA_NBc47Q-VMIUYf3jBTym3NUTMwiA95qdR1_1N-l4Yy7c9-X3UiRrVpNQ53lNuaUzdYuSq7XGHS_4ZNFwKXuG_dM7U2vhn_2dk2fkuEKZjtBYkVofStR8qlkswIAuEw4mrnt-wjG8cxrAwacoXop0R6NShjmWSrAhgqvAqwY3oR4HCPo_zaHSWjnJcRZ41LkVEcBSvtXqNpez2jYYmUkoGHgr_5gGpHpPo2j2lM0pBmPwPQ3OA8RJLEZYiQtabP7AKzZ32Lvsf35uhLRMZ6hkLtwPKgJ4tuR6E2B7xlZ6C0UoUbuI2Spou5dQsqPd6byXwHa22yViPpcpjeZOgHKK41cnK_tpL1kEe1KtodMW43d4OwHZ4LYqm8B769ob3uWnzGOMSGSrTsvci7gm00P0mwKBCh-XC1xdo448iGC7O_bvfYeBJNGsFObB3KqT7WLy04gc0gP7uWH629g151xRPzILeJUHsM_MwrFbNRqo9KbJFtGP0AQiQkO9lE-0VpWQW6ZyQLg6wByI-pPwakXJiCWxpxQF95NRjGOvwYyoU32ipX9mqEjdjQ-vTDn9vte8wPww0aPtAKqK-k0gkeBZAJYALVZNj6Oh0BUdA2t-XcMxs7Qho0V-LLgUjrmyM2ci71LgxeqO8I7LkOuGYMGYj2rFIGrzMeZOgucDhMyury4ELb50ohyYGjf5sOYavsYUwzK3NQwDZ3kjyHFSzCvgkuRgMLKxmME-4aRW8VbGLyC1f2hDuwxzL-cExk4yMh8TijVsf-bnRhHwmQKiR-SGkhrylfn-WnBQQffAdWpjscP9od0UJSPZrLZTaht7Z_15rMw9RO7vXl6PmcFw8vYciH58zUpU5vgq5_QGNvACSnnQxG8Nc9KmIYxGQyMow_ch1PBUP4yGYXR7Xwg0YiB6bwW5p_bxysCJAWBrp4sazb2Al3055Cfnmq9QXTFwFJo0jfbpqwPySuQ28TAiZah0CbCf_zdpJgz9hqM9HeRWHDwIKiR9OpxH2N8rWLqqRZTyfvRX7BfMF6P1bFVVagwhqljKZfcF7QFztlqKdYSGcsA6jdz1RT7B9CItJyKCnHgTYsFtxOr-7z8lkNNlb3xJAYmwYuSQszTR0nFnP4Inc_Ay8XVdmY-ppo6PMJztYQqZXB9wABGkzfKUl9UAIvjMrqHAw76sw28WTA3xxoVS64CM4YDs028hnVsL6euOe6VVBqpVMbrQ6OVi2FOR-vLbNAVBwbelAhbsqoZNMATg8bqlf3UMwacTkr_R1me2gDFv2BjxbjvlZUApzkl9L-CMnVPEsyb187O20chSrJhsy2tLh8SC_6_XCCnNFub3RAvD0BkNzDVZig_oC3ps_EEaPZgEdtbUb_GqaCFcbeo6X4wY7xkr1gZfTP_NHK8XyElajh_HP8T1fPmTZMh46rtXh5-54th6NQ_3jTjCeOfmLjbQKotLNOhJKlB8vXa2CsO575d2zkP2CAMGy9TU_ztUCfaGFOeFPN_xvz1vBZ7QqA-yA10tOdOm8b3oowPfMbZ2n5mvyLNG-DgUkjPGty5gyvJvyMgoqZao66fyzfLvM28eQMpOOcGAcozDFnW_vkffTU5GmPLUaG6rx74V32RVzaQKuC_nGBF8T_NfJ9NfecUw2uj21vCcUyTiIQb3Are8aZLnfsi4DyY-E7WhNnBoLsKZO1CzurCYKCPi4KYGjTr9og_MQM4frL9nez4teQDdUZnu3TkTqF9jRmeFMpZNLaRydPWCmumrCI7HSwb6PuBmsswxPi5Br_NcjszNq-c3t5_Gj8klCceJjDak7wjMuGYSK1GU34iRlNW7iUYUACE4FApDJciqJcRXE31-S_b7IsZ2xcMU4f0Qf1sWHuKKRiwG-Wx-AhXjDSH_tbhauB0P3JEAFg0eNnsRBwUvrYqzPRKkAJz0AUF_biQ-s3czpmmt77NBxh_IjIfVbfOs8QbHM1bgZqUzhS1f-cFLcrEypLHL49Iuy_qXlut79gr2XBsQ05ZIQvOtzCmjZ32b_P-d8oeGzW65rwq0HovxMWxwR7zHqoZD3KJ__a72HMcwK3-fYZBzjMjxOHlBxdzmy4_xsfUBMWxuXREypfY9cb8uuALpRJCebN4pIocB59ShZgTtApb2GVk2jheXHAMx8-7GAUO_W8mzJlaHtrdJd1QYFME1W-_bhfJkYJW70phqUcvVDjoBGHiiL6TxkYAFwCNUhJsvnIG8Ihm09t8TKmcrPx73MVG-euP6T1ZIVL5FFX4kOqSZW2gKg_cUr6xUhuey3sVNd5Qfl_q3PHNHVif93EpJ6iac1VQ6soW9MwuNpKURX_r6WWDx6kyeTXKmbE_6Boe4jSTq_BKYY_SYoZY8AIOrGmKBV6wemc7hR8ko5yfH5_T4V7rwHSPotueN02Xb7qAgizPUxwxuMvwiQoqo6PEI6V96_iRvTCso0mJ2k-EZ7e77Wo3X4A2EjH1ciljhDA2uQAh5QgGUgVI3QfGiaDFrgeQQOatOd-zqvM1j-WB0ZBpjYFR13O8N2ZqXQQ_AlWOmx60LQI79a-BIZb_UBzkpMpR-bsUlFq_CQv9o4cxGU3M9Orwsck_5a_V2Mlsicz8ThvLz2-MaoQvwnU3Zskde4SyRQlqMYSThRxSc1kUBsDDWgBWNrvpeVDxvLAmc8XVR_xMgCiRcyAvrv9kG3RseYoD--fqyx_YpoAGleoG4jA4FFkvZdE-MEN3CSuML2oOJAsMNgAG1mNzkbeJO53oe6qrL4ZnnYHQyayaxSMpi0FonMibsg6pHn8EZ1vKes2W9ljy02W8lfTxnaXewF5qX9uKTnfHM2s9MSdSasJCLagPDjA5ZtsRcwBMpZ6LgJuT6OZsvYyWONDM2y-BdUMN1iiIvJXaRIG-smszpElaZZimJUSPKhO3klT5LH0mZRWL03AnpauWNRdZNZhWJl7sum2bEulbxe7_Ir0LvN1IxUTbDX4TLTDwPc4vEpouKM278KKxo8idZlo0Sd-Azwu6CAvr0uIs0Vs6SqKWWvyC5B5ZmJwxJ_uEFphVW1WKxUxqhSHadoLF95BtwU23ayhu7GV6ZbpgkS9JBETCsYY1xZ0W_A02jv6SsSX45zEg7wJVgKl_EgWBlCw8QCxNirmpxcYvEbikYIBz1NscUBlLnGNIpGONVzrdtmBOkkikw0Goot8ixXePS0_7Jm1LavQIqhklO2SZ8Ve90UZCf0cO4NioF9S58mYFxQ5M4UAErTkbH6LOpmk9I3OhSUUgDwpYN9FWIc__JoAvfUIqvgxvvU13DUyTjdyWvcJyAd2qN_TqSQRreY2fiieLXTEDsZwMRy3qVKQIXVc8wd3hiztuO45EXMqW6ho3OhXFPiVhXUzzt6YJ4SFO5_yPLDOLQj0t4jOnjdvAOnt0gdiC8VSZaugxZTpQFSDPD-skDmj0CAZ9VUJhWNUnkRK_aiclAf2rouiJ1Ot9APUEtXlHR2ImVQSrepMEHDJz1ijCH6QUnkX1aTYt41RBZiEa09207Ow8X1BtTrhofjxAyLzVhEqg76sNiXHhP7J9QAYhxctefmDgk6ZUHqIeveNDeKKfeXrW2UzlLBl6S3xW1xnHBrHxp6wcjngqih1SG0eqfXWgJ_mEg9lOUrbDttiTJbTE7_XhZ2vfJ7Y626u0J6Iz7mGcPa3nCSgzskbBKQflfE0CqS-N-AjTirwU2_7Lb-ofMmbd-rWludoNtNwzh6BAKFVs66rHa-VrWSwoWR-2mMD1GD8WzsjCN4PvgTo5mOGlltDDkWROl5ibhJ-tLyAeZ4mtK5f_oVModXQtapyXA9GEoktjGtoFqE3BkMwk0i_P542lOJ3fNGI-sPyfaWRQXx56wxy470_0dwy_o3aSvJdetOxOi32BfEqfPN-TBNU3MkX_bt0FTMcXjOltnoGh6bgZI8tZ4RGHof9yBLhqVsW9aQ8LN8amNJg4JCsO75vjpW0nDgOk6cKeadSWjP3fBJ_BEmfFkDgLfGeZ_ILTxpzJ9r7yCGPdFoA1C5a1i4DT-3A0UD15W6cpgdfAYRF0Wt3i4UDopGFpASyM1_TpKBzig_iy8j4yM6qUwSShEQiGDdNohlrS2q0fS03Rk7EJEi9wFLB6GPvm4hqJoCes22TvIN14fjz8udTQXNMVEbanKdhMgckZ3sjmAakOe9APmpTbWJ0GNVXwGoErrwLlaptkA5BIk2ZW3OcRWykaHZBnCgf2dNb6II7Mjjguw6H5_J1oMqJFQqIlFnxK5B4nvDzQ-9-lLIub0QvWlPn3jxTkZXBO2rrhBwUUDlZ0NN6dtl79XwliYz0aOc9gnfKptmei73V0WXP8qrv4v4ISgRCjytAC72Uao_QoB86j0jdNNuJ-HUz4BGCB4k6pr9rkOwdwd0PY5OfJbDO6PxqiXNO6unt6IOaIoKEhs0rxpRA6GzyooaoLrVTYQxaSeJTa8I_pwuILBgUSu99DD7HhbQwrloBN7ststbloZhT8cN6SzQ2nBbU_LxnroDH6GTrHFPruSt-5jY-lj9GEm4AFsRwQrXgcL_VMzPThUdbYDOMouzuACn9xdz2bhKcGF20DlLA06ZdtWQfOeYHWwFbmUR1FToyVsUkH8Y_V0vzEDLxzXnVS_0xumFFUXltD9kp4guS4W-MWAFa7hDRBG701kJNQXZqRkzHKqpLNgAdUggl59qrgqLbFtTtco2jaj3dmuPBQFppJL0Jbms5I6lDayWkpqxURphQ7mHtKuodiEmK-srvX2V-X49zV3W_wjAdKQzIZH7qyYNud9QhOO6kBrzhAueZModu_lcYU6SaKZ_s_jPkHauZ6lB04rihZnkpF-vcRVOARctFnxGLOyLQ5zsMxtZ9HIm_s7sRMNQoKAVSaGbgH60Vp9P4yUaHZvwIOfC0cJOynP0PZ4hL-5vjkMwsfYI8rvoyg7woA7gbff9UCQtZG4W5nNzR_06goA9-G9c1DAA__-DxpDpaM68LfopLNJoendZ5jNUEjAmGQBhvPHce4WISmsxtXXonFbZQUlja5KAw1nrlPs7QnkECMPBnwzCC9dj5_8m6ZOieQn0RJPAL2vd-3wSJ5Hdndz1O6wuJVRjdHFAoGFq-azLkSJsRfimKwzPorGlUaaHd1KXZAtKVAjgRKhBVN5iHRgIMB573yZ-gD7syERLNECujzRQnSZydBPLAejqmLcreLecByKa5M0e_vN5cxjNEraw9hCg5UzCCrIQ06Xn2S50s9l6V5g9c3IuAE0u-7OVLh0CSqV0aKXg9UOl5E_9n1kn6FA7bYfEK9oUWP91X690oVqobM1EZlUoBdA3drz4tNAsp0zCgG9SleiPCzzFURdTGlzDPKvzk5V7EWiSZf5Mx4mLTJtABBRH-ovoSHLuj0L_mtlTTpXBfyHXV0KdljQ3XQAl_CRHr98HbliFTonvLQLfal-vWW7KRX7H0TYYhPFl0v12_IVI9eae5QvmLLxElJuMYnTuvauewwMxjLSovOsxnIKvaTTDBGclEKpXOOY2sDHpamRKxm9lJLi1Cpwz-6GLdUM1_v97xFGyrlJBqDjLap_c2UcDTPU8EcPiBakEVQdkmNBhz7d08PUze28JH226GnIS9_poHQfroLnxo8RNnOJqFgvMa3xb3Gd9lmGVMwvZuZVsELFnXshva46Zouz6QZQ8V7O9mRDPI4B1oG2eGocb_E74G9i4hWISG_CrOiWwWFPaChqfIbLqFJbxTWRpv30iqmD7IpLgr4hMBMj8MujxlI1BqhnhotOfvOksRkCtOmwpofL0l4YGiJ6cCtwD7ALgzLN4_nTVXR6ZaETLZTqpAfx7z7INvRDuzeSsMdFcWTlLPCsA5WrSCKMC_jtUUAyPktcEKJ6QdLNmhwZmE4FUNrUcjSYZim-ZNXrYC3U5SF9WbsbeQ4G0Tz31JF5ls08RRzsCBCQGf-TKz2PR_hMD-QUCFwhgJkw3xqqy0MONTtECZDHLUiiL04IyK-MbWtV9BIMa7B3g-q8plZ_Rwroj83CoMQbJWb9Ofe6RM_87NN1kXoc8muhMHGZkUgmq_WQMayrSiq_L0Pm2YsJOaGOyJ4sHHd_R6-OlJ6zR6W4qU9bmJSZvF58Z6oshhPQToUQXObEB0E78alCmrWNYSrcXuMqyhzVToGiAdyJoQlBrpjCAR8Ra8_wYx-8EWMzJaHXYG908knfMALVUE51f8J0AAjB1JmVwZbehBhxJrwzgJo3gmLgWNBPvItPgq8HZX8oXgM4d3PwlNnUF6IsPMsyHIYFfnggIKTHv3Mz1QDTRHJ-SIIGnEHtHiUZojIQJf3CUG_UNZAlVL-qqj05sjZahdueLVH2bVYe3Xa75AuN5v8hoUdbeQfDY1LcNk4yz4SLnss5owSXvK_0DM9V2y510RrHmBVLx0GAo8TtgpVd7Vle2TzNeUksWkmCbYsgMealTceOPQsuDPQ5Ie_1kBss8qiz727fst9SueE5hjHe9vmB99Y9O8W18a7TwRedJv2M5RbxOVhq89bXUBq0bbfVoJ5l9t-1YL4-YKESmj529Bcy71_yNzXs8yRJvSUOPhG9-z5aWonPQI30QhcJqtHG_vtAQE4kT5oDEpujitzwdbQYtntGemNGQKWNYV6CLpi499KfZ10jdeHSkbRTZFjX5J7mffEwBVBRHbptsizL6fGCdY3KkFNKNEKU_FRcYgPSyrzRe4koB_Q-2g2yvHBYqghqLsmTMcahnki8uBB_H-WawnjX0jJwKvP9_azFkvOzrQUBl0yCuklM8npNEFAjVVS_h-jQ6Fseb-lyvehp63MVFac__nIdrYoVnOi1Yihb0w4A7Xt4QFtxyfCHnp1re9zisS4msZm0dfb3s-VRRFQ8VeXWazEIUtDc6QhBiTVaOIZjCOrAOV-BCDhnKPKaJ2gK5R0QspQes0EMt1jpPhgqX6Bvxsj-SMyyKZBr9mkAo1pMb4eJw6sWWchEhXQGQIArBDezuQFEa8KbOFoZ8mohCSLZO3pANGJaE0iEB9Uk-y0ftAkFEbzf_lUi8VHa7hDCqLCOvc56isd9MfVFkMWEhbiSaUhACAac75qp63Y7VVRZAR46EfrrIHvTbFO7yebBTxgetKZc4umvt68EUWDfGqVluVWealK0t63CgYo3dk_bnaQTWxIP8fpIJjgchJjie8luPDR2ZzzanU_TMK8hdE-5iHokVnSHWCnJ8TOI8qrRk9YUPCQof9B3I9pH-KJjBQmgo2SurVLFv230SUdrgs7n4EzBYu9GNq9ryakhwoQRLbQsN40PZJuXL3YSBm4Uprptq5-e_r-FnLIk_OcMUOCv6Vupn9-pqWLCc-mTpJCUdduz5Ht8Ecb-plOc0owN_dzBDgdlzA3d4UpAk_2PNmeXRv6e_futRtKRaKJwY0q1-7XnxHpn8PqmQ1sBYVkLpEOeETh_FlSXwcK1ie10hcnE1H988srGMRCtwgPiU7gAGZPuiXq5aaaGEklYLxEvaSRkASWrIzoP6yqk_FUk65o1Q4hqDCMJhXNSnxaYNgRunsxbv4e3nevbeuuaYHrjyrhPizillKvwwGfckmOv9Y25BZSUXMwSVK9Ad3XA98NajHK8rVoiTRa1fjfBXUwVoce2JcVhuzk1zR_B3KixTZCJl7TUT6ajt70IQA-EsWfNtxdUrINMgm0ZjJVkG3ccM2MVQ0v85VUDwMEqcF3LRFAY1-6Rt0shEK9H2HSvRC-jHBl6xV7DQM0OEuWRvJAECkbRTPDs-XbZhqUQJRRb6XMDZsqeX9tCS1MLyMZ1IUQlRIj3d1auBzc6ICfraQA-cMcAyxofrnaRwhZGr__gns5coe8-DQ3YzNE776gzwLAg5k5M-3WEGJY-BbRtde7opCZnWZWLK9tezTy9ws-qLiIeOlRUu5xSnfwuy6icNYqvWvAN6FwAz2m8F56m7RrtigY8JKwpSk2Jkz2XknkCdv-yaFl4PIZoeRF_pmLSi5jSyP4-ze0owGzmSX0CIRMqZYSsS7D0d88U0DWFFupGK4Kg_I4TPgjByoRH8hZrOcsKvmavJktXN-beunsA06WH8opv2jya9gZkxgAiFIifJBVgEDM5bfFtvfD6N3QJE9TfcUPNGoFqhvEBYzVgQnj1IPrMWBEjBrhc9iCnCattATNc8LVlYbHZ3514DESdjISCctsU-fnKuLN-W9tOdSYEp4xi3phiLD3TLI679uQtifBlAYAPabNDe8ZiwI20jl5REQX10lHjvnPRK7mLHxt7PkOGAcd3hVH_w2KzrWdpf_-DM36G6Lq4HvBUH4BNk8zewp3qybZu_V5zZ2hALyRv7Ibl6pULmyoscJXJoFzBHGDr8rqnazTAwFTWVCwxCskGHkw5DPDGsm1T7ILIgAPEveVdLmmnOP4rXI_o0RGsi-nQxdavHPt67-YWOFYeNWiy1AlNlra5DvL-hfDfxCNgrvG6BbW8c7xEhoFvlR80wgfwPDckjd3U4RjjiiUfVsvgf9bx6x9-cIzlxwiRBzVMnlTPXOwqAsJ2H1e8-_tKTFjFkZuYpVRFCf5Dy4xFcvP2rHtHXE3G_ZGii_M5ZwlrBkfmVVO19lazSqpe67rPuobutmjt1bK_A8B2plrI01cZ_B9yOMzrVoZJebI_cs2Eam46VWfOFGTMoJwzLWmwmF4jt6elLw17Wlrv7yW6RoFzMVROMfRGksuezBufgDDKgpK_aX4jWJpldlI_pNRTycgieG9xHkWPsslTUPFFQ07yNArqB_9ERbiZv_4ljva8O2U4lSmi_CPocI_Gf899EBvd7QmlGl7ZswYlb-VrfcfHuSg-eV0QUH4KwQDvx2qBxL3ng0bxCBgiNsOFv8Kot9afWjUA4YKpvoHajsai91iOUEJ1KBfd-GGv_l3M9OoZtpnXre5twKtdCfllAuLcmH4HMAW6cPX41sFdFf2wwk4aaTic4f5_TX3-dSk6_epKwdmjjucflHtrFp6c9SJwf_aB7y7XYnoq3DvveOtT8LqPb92mIsSwvkxd0E6CVw2D0kpUsD8t3wWz59IeaSuGdqzS_7DCBsk240J2F0L-bAi1UmwtJySyEH6gGcb2wzuekUpoL1lbk8NvOFhqGMskpzAW31X5KlAIB5fMqYIechq2qgUTX0fbFbbK-WOS5BNuZzQHg5u-x7KCsd4M-i0-JQtTNyHDQ9_6GICe3RAa1au6QMk3bbuEeX6p2rkQNIaoaP4X4cayBr_0yu1Txn9PV28js9BnbryxWauTjYYSz02CGE1kN8STnQ-ebpq3WkorL8QcPw7VJFDRytkwSz_AslMaxmoCzvftC8nxZgEveO027csojiijwJ0gpDZYvyhMgNcPhPaLIEJrVSWkyMnkt7Pu3Y2YotbyxyjnySgVgUhvU4rplk9cHykR-1KIdnyrtAmWD1POJhmmtRF0wbMXWPg2zp4LPvH1LRywS1Si6lgMCGOMXRfOzbm8PYJDeM13j6e5PrX78ZsaM_n1Y3cDfew8Oy5guR6ja2TAzstADnEs9-ieIV6xIgARP4tLLi5JSMSDKlaite-kt4Os6cW6ZPm3O3rUthnWq5vHRByyhVEytS-ALARuaoZdc-yl0RvQp08jXqnqueILKWdaRWXJveMAB4XenxSGeCVffEuAm2HdhC0EVcS3rimTX4FSGFLOD2cUNXoB7ywSDnP5VTZ-hQKp-URDXx3YsCj_nXwyIYC4EIUN34i4YUh-DprUnNfJqW9Ev3sfByzjyNS7W1a1htCgXckmy0XBY6X8bNswm7w1ptgpLU76NGOuu1haWJp-LPwxXgDEkpG2tLQQsCKedet_QiBmarepWVN1j9ZIkDDwQE5hwRNrwRgHyGIXk-mNcXXF1gmr3q68XEt2VEur6grCHA0CN3dy4NRxuoS1P-vaRxLl0Dl9Iy7lIGoZaKP_MdGdiotIZdnxe08sBWUvZGdUMg0gpEAn6CegsiuQbLCqT1KuPoMNLKnh-33zrHA7Jo9SqxZ-xrRpwhj-bTeL4v9WgALcRO22E8vhFrVJZICjEBwUv6rpo584dUhoxWlwC3wNo8VRp08Hkbso018pjErTyQ7Is61euKF_OxAvYmHgyZVb_IaldqIHSelpu7EQaaFtvLJSiA3XOIpD4O-rZeimfmS6tOOYQad2TjTbrO15c6AY1OlCWsWAbUGQ_8NGmAijI39Vfcy1z5DJceiok_1_Ao2jh82tEMflNeI6DVEe01zDeZvTHimGVreOj7P7a8Turi7VbzP1VlxrgAxDWZmkPWRxIzfrFjfdMM21KtCE5M1FAqX9buLWcCO-PYmQEjb3_34_g5jOwywcmJXB2LVw5H1d0LpnoBrZSYi52lQaYM0pUombI4jqfrHuZUemB_uYWMdqogdGtyWr23TJeUeQg8BfxtVzjmyw5lbCwH62GSDbpyjzCv3Fn3WDq0qrjR_Xwmj2B9bJR0SgWZhOZm9ZudUOuq3VEZcuaDNvRtmUGysZWzRGRAp3AxolKhk_gTywGIytH25Hj0L28paw0xjmN8YunkxNVbegg8MnXw5l9G8SXNPhZJYKZ5HqI5XRsbwZgvJvSHy5V_G8Ie9YLVrbpoYkmT0j7ErSHXh4BQeS_zbFJosev3fmnxJIEyTz916SACv0s1ocw80aohgzjK8N8eDz5FJ2JQIBZz8TNSYmfFX_Uv93_ZwR0mOAJ2QkKdv5maUC6JU_SSSmDCqcMwp1u4-AA--Z0rSCXGHWWkdZ4vWhRbxFkCQs1IcuSQn2-OxNBImLxvxmhS8XDBKFfm9t8B6ed4TjupnNn6x0BWG2BtJ0yk7Y2ecj8XMQaiaG4MKRdUd6i6xOz7GwmtSA7ckNZef3_B-XA-vw7kYih6vhIf0sRdDX7IK3GVrsN9LbhmMeswEQJteavZGwDWF-piCpBMJ4LWcwsKI534unKNAPhzVPIiczSD1gM8ykZnxVWZYfX4Gd5TC96tdoQq9Z9e-d7uksaInDQr-NSo9rMPPm2quIe_GUEeqzvRHVDmaJkmP-4CeMGghGHQHozDXavc8os__2len8ZFyVAKnyHfhn6D7eo4aHnPL3J4frq7M6SLDjdvunW9OCmROtmSkXjvFwM09w95KEcroXJBkM7bsA-Z6KU-uTwADINUA4TH3K3Y7R0oRmCBtWzT_mQaIE2fgqbwyI5ZhmjelOG8QZYPCK9OtqYwNw1pHDFeHHM9EcXrux-jfccDUJ4IPdOKGOkPurJx7EJv_Ed0sh1IKaYzNRuvsUJGbVU_xyb1nef-Fic6P38JCrC7EYEzLKdtKNCFTacUn9OO3Ygf9b833fcjfG0LYWZeCINxKp1OeGsOTd6am8kwL9Dwx41BbBRHHxb2Fa_w8oneZ5f5yQmHlKvhJ7Rh6hUEYWDCUOG2njMVe0BeI9H8bxzxeWZI4RCXYa0sbEbCqk30ivJI1pdzYuuyk9cc4qUbsPdIScAcSXk7NqBlS82Lz7kDtFjrRtNOVhrjpjlKV-a9W6-rPB0U2savy6xjp-e7yPL_S1Spt10edRjtxHt-AvX3qh56EJdILHPX1MbxFol5LhH9evz_dw2Pe9gxOTYS6S58qxcxX4Nb-KfXngnxaeJ48SsKN-TKi2TWntVLsjDBLPUO1LXrFw8_ZjijdW9j0SxZkOEbnvI3uJ3jvEVxMxUojlfUh7TvKdR209jBuO2ezWcLt3CKfRG6Ak0FjcugJ8ByMucCG5mGMOB7UyWCTurM4FvTeHHAN20C16LRkZ8VyANz-Oe9YfYFO9lrofS1-3jm8UoZ5AbIjCkOCAdOdVEo8RBOh_P8wOTVaYlURHOfeXniL51czYw3UjyIkMftiVXghc5KAWhwrqOkeTPDa3b4zImVqd00u-fsVl9_-c25qR-K1UaiwEEvF0ZJK1TTjMNerCVNezaycd8KZ8ktdaqQD9bvx3okUSpKFZ_WZtgRg4oOlf7ac1ba0PUyigxms9I-9f6snYfzyefP3elvMXL4KpbcDfDcxEWrwFiQ-xDSHjHLrve-irM1DEbgNY85C4XciSOq_fMVut-s6GulegmFjJYOukwLjpLFrEEaenpEKKQlN0upzQcHmdUm1XPUuOFrevg3IMzIpYoYjpsMHtJPXEhViPcpt2uwwRH6gWGtt9wX1KFlYeES1LfdNYBgBA4myFQwz8TR3EeojBxTwtW_pIX5P_A0byfabD2BCEKDZwmgiLfSA25skSB57d2WllO8GkY0pdKBkprewSBb9rqcrRDIk-wd_hSX5NGSnlUGY2-hU0ng1erQeYamS5pYw-BUVTtka3WdDIK4Xg_-RXXg08hfdruAZT-QNBr4KhSVX1l_W-BACPuXirWu1LH12Fu1LQ7X168GjM3ncmfW1abNU6auYfJoxOYTvditijm4SHidFcLNNOYGTOe5WkNNUMKhfjPI03_ofrwmbC0XZvgrUdRPNLM4ocIb4u9W6_LuDRcxd_pnv061OvmBXLYjVQx_O5sscdftVxVj70DaT1Xt1CI51THYtlr0iA_r-xYFTYEMBvNOdz8mzQOblwbeLqnhFWvkcjBj__0K8brz9WTkKJDmq1JPTkG6h-hjPgAcyL-ayVuWJ0iLlvXObqalnNWZ41zyc5XG2uOX2roF2EMOwjZ4Io5eAnhR5ZkhxBJTm9egvFyZ-sU9ibMw4dglZ-_mESgmo6AF7UKR77czR_c6gaTUOdu_U=', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de', - signature='gAAAAABoxCyzDT6i7ehEoWDBoDGMZmLcOX8TMbvBssJGa0cA0-7Dy6YfH759wsF0Dn5Auzz8Mp2geHtbVJVxKa-SF4Al-z3lq7gQG29dTf2ecfq_6bkg1gS49MbGEmaLo4FnS6_5oekdntomcOVO4mqwC7JKnCTO5Qyq8-Nm3POi0nOZm6KaEfqrmPHiJttupduQBkiqHIc8_CIfQ9LGqSxXZuAFQ0DbNow-6yya7_5oNOoLdgWti5_n9CENxTYyvG_q-2WAmioZM_rR54rWqmMbxUNNsKJls8xx593rb4u2dEpFJztVeifJNmFnDcYDDHMhvqLdSXJU4z3Yrxg8hgH9w2gD7Ygu2UDsMsiUdp5YGXKx_acJeu81-7H8Yf3XY86woskIv2o2XaegpK496fKkeiUAD8OTGWK0hjJb9KPK3hqTBfRfJzafQbIvnNTwOod3ZPyClgSXTYKsN1E_j3S6G8R0uzyA_NBc47Q-VMIUYf3jBTym3NUTMwiA95qdR1_1N-l4Yy7c9-X3UiRrVpNQ53lNuaUzdYuSq7XGHS_4ZNFwKXuG_dM7U2vhn_2dk2fkuEKZjtBYkVofStR8qlkswIAuEw4mrnt-wjG8cxrAwacoXop0R6NShjmWSrAhgqvAqwY3oR4HCPo_zaHSWjnJcRZ41LkVEcBSvtXqNpez2jYYmUkoGHgr_5gGpHpPo2j2lM0pBmPwPQ3OA8RJLEZYiQtabP7AKzZ32Lvsf35uhLRMZ6hkLtwPKgJ4tuR6E2B7xlZ6C0UoUbuI2Spou5dQsqPd6byXwHa22yViPpcpjeZOgHKK41cnK_tpL1kEe1KtodMW43d4OwHZ4LYqm8B769ob3uWnzGOMSGSrTsvci7gm00P0mwKBCh-XC1xdo448iGC7O_bvfYeBJNGsFObB3KqT7WLy04gc0gP7uWH629g151xRPzILeJUHsM_MwrFbNRqo9KbJFtGP0AQiQkO9lE-0VpWQW6ZyQLg6wByI-pPwakXJiCWxpxQF95NRjGOvwYyoU32ipX9mqEjdjQ-vTDn9vte8wPww0aPtAKqK-k0gkeBZAJYALVZNj6Oh0BUdA2t-XcMxs7Qho0V-LLgUjrmyM2ci71LgxeqO8I7LkOuGYMGYj2rFIGrzMeZOgucDhMyury4ELb50ohyYGjf5sOYavsYUwzK3NQwDZ3kjyHFSzCvgkuRgMLKxmME-4aRW8VbGLyC1f2hDuwxzL-cExk4yMh8TijVsf-bnRhHwmQKiR-SGkhrylfn-WnBQQffAdWpjscP9od0UJSPZrLZTaht7Z_15rMw9RO7vXl6PmcFw8vYciH58zUpU5vgq5_QGNvACSnnQxG8Nc9KmIYxGQyMow_ch1PBUP4yGYXR7Xwg0YiB6bwW5p_bxysCJAWBrp4sazb2Al3055Cfnmq9QXTFwFJo0jfbpqwPySuQ28TAiZah0CbCf_zdpJgz9hqM9HeRWHDwIKiR9OpxH2N8rWLqqRZTyfvRX7BfMF6P1bFVVagwhqljKZfcF7QFztlqKdYSGcsA6jdz1RT7B9CItJyKCnHgTYsFtxOr-7z8lkNNlb3xJAYmwYuSQszTR0nFnP4Inc_Ay8XVdmY-ppo6PMJztYQqZXB9wABGkzfKUl9UAIvjMrqHAw76sw28WTA3xxoVS64CM4YDs028hnVsL6euOe6VVBqpVMbrQ6OVi2FOR-vLbNAVBwbelAhbsqoZNMATg8bqlf3UMwacTkr_R1me2gDFv2BjxbjvlZUApzkl9L-CMnVPEsyb187O20chSrJhsy2tLh8SC_6_XCCnNFub3RAvD0BkNzDVZig_oC3ps_EEaPZgEdtbUb_GqaCFcbeo6X4wY7xkr1gZfTP_NHK8XyElajh_HP8T1fPmTZMh46rtXh5-54th6NQ_3jTjCeOfmLjbQKotLNOhJKlB8vXa2CsO575d2zkP2CAMGy9TU_ztUCfaGFOeFPN_xvz1vBZ7QqA-yA10tOdOm8b3oowPfMbZ2n5mvyLNG-DgUkjPGty5gyvJvyMgoqZao66fyzfLvM28eQMpOOcGAcozDFnW_vkffTU5GmPLUaG6rx74V32RVzaQKuC_nGBF8T_NfJ9NfecUw2uj21vCcUyTiIQb3Are8aZLnfsi4DyY-E7WhNnBoLsKZO1CzurCYKCPi4KYGjTr9og_MQM4frL9nez4teQDdUZnu3TkTqF9jRmeFMpZNLaRydPWCmumrCI7HSwb6PuBmsswxPi5Br_NcjszNq-c3t5_Gj8klCceJjDak7wjMuGYSK1GU34iRlNW7iUYUACE4FApDJciqJcRXE31-S_b7IsZ2xcMU4f0Qf1sWHuKKRiwG-Wx-AhXjDSH_tbhauB0P3JEAFg0eNnsRBwUvrYqzPRKkAJz0AUF_biQ-s3czpmmt77NBxh_IjIfVbfOs8QbHM1bgZqUzhS1f-cFLcrEypLHL49Iuy_qXlut79gr2XBsQ05ZIQvOtzCmjZ32b_P-d8oeGzW65rwq0HovxMWxwR7zHqoZD3KJ__a72HMcwK3-fYZBzjMjxOHlBxdzmy4_xsfUBMWxuXREypfY9cb8uuALpRJCebN4pIocB59ShZgTtApb2GVk2jheXHAMx8-7GAUO_W8mzJlaHtrdJd1QYFME1W-_bhfJkYJW70phqUcvVDjoBGHiiL6TxkYAFwCNUhJsvnIG8Ihm09t8TKmcrPx73MVG-euP6T1ZIVL5FFX4kOqSZW2gKg_cUr6xUhuey3sVNd5Qfl_q3PHNHVif93EpJ6iac1VQ6soW9MwuNpKURX_r6WWDx6kyeTXKmbE_6Boe4jSTq_BKYY_SYoZY8AIOrGmKBV6wemc7hR8ko5yfH5_T4V7rwHSPotueN02Xb7qAgizPUxwxuMvwiQoqo6PEI6V96_iRvTCso0mJ2k-EZ7e77Wo3X4A2EjH1ciljhDA2uQAh5QgGUgVI3QfGiaDFrgeQQOatOd-zqvM1j-WB0ZBpjYFR13O8N2ZqXQQ_AlWOmx60LQI79a-BIZb_UBzkpMpR-bsUlFq_CQv9o4cxGU3M9Orwsck_5a_V2Mlsicz8ThvLz2-MaoQvwnU3Zskde4SyRQlqMYSThRxSc1kUBsDDWgBWNrvpeVDxvLAmc8XVR_xMgCiRcyAvrv9kG3RseYoD--fqyx_YpoAGleoG4jA4FFkvZdE-MEN3CSuML2oOJAsMNgAG1mNzkbeJO53oe6qrL4ZnnYHQyayaxSMpi0FonMibsg6pHn8EZ1vKes2W9ljy02W8lfTxnaXewF5qX9uKTnfHM2s9MSdSasJCLagPDjA5ZtsRcwBMpZ6LgJuT6OZsvYyWONDM2y-BdUMN1iiIvJXaRIG-smszpElaZZimJUSPKhO3klT5LH0mZRWL03AnpauWNRdZNZhWJl7sum2bEulbxe7_Ir0LvN1IxUTbDX4TLTDwPc4vEpouKM278KKxo8idZlo0Sd-Azwu6CAvr0uIs0Vs6SqKWWvyC5B5ZmJwxJ_uEFphVW1WKxUxqhSHadoLF95BtwU23ayhu7GV6ZbpgkS9JBETCsYY1xZ0W_A02jv6SsSX45zEg7wJVgKl_EgWBlCw8QCxNirmpxcYvEbikYIBz1NscUBlLnGNIpGONVzrdtmBOkkikw0Goot8ixXePS0_7Jm1LavQIqhklO2SZ8Ve90UZCf0cO4NioF9S58mYFxQ5M4UAErTkbH6LOpmk9I3OhSUUgDwpYN9FWIc__JoAvfUIqvgxvvU13DUyTjdyWvcJyAd2qN_TqSQRreY2fiieLXTEDsZwMRy3qVKQIXVc8wd3hiztuO45EXMqW6ho3OhXFPiVhXUzzt6YJ4SFO5_yPLDOLQj0t4jOnjdvAOnt0gdiC8VSZaugxZTpQFSDPD-skDmj0CAZ9VUJhWNUnkRK_aiclAf2rouiJ1Ot9APUEtXlHR2ImVQSrepMEHDJz1ijCH6QUnkX1aTYt41RBZiEa09207Ow8X1BtTrhofjxAyLzVhEqg76sNiXHhP7J9QAYhxctefmDgk6ZUHqIeveNDeKKfeXrW2UzlLBl6S3xW1xnHBrHxp6wcjngqih1SG0eqfXWgJ_mEg9lOUrbDttiTJbTE7_XhZ2vfJ7Y626u0J6Iz7mGcPa3nCSgzskbBKQflfE0CqS-N-AjTirwU2_7Lb-ofMmbd-rWludoNtNwzh6BAKFVs66rHa-VrWSwoWR-2mMD1GD8WzsjCN4PvgTo5mOGlltDDkWROl5ibhJ-tLyAeZ4mtK5f_oVModXQtapyXA9GEoktjGtoFqE3BkMwk0i_P542lOJ3fNGI-sPyfaWRQXx56wxy470_0dwy_o3aSvJdetOxOi32BfEqfPN-TBNU3MkX_bt0FTMcXjOltnoGh6bgZI8tZ4RGHof9yBLhqVsW9aQ8LN8amNJg4JCsO75vjpW0nDgOk6cKeadSWjP3fBJ_BEmfFkDgLfGeZ_ILTxpzJ9r7yCGPdFoA1C5a1i4DT-3A0UD15W6cpgdfAYRF0Wt3i4UDopGFpASyM1_TpKBzig_iy8j4yM6qUwSShEQiGDdNohlrS2q0fS03Rk7EJEi9wFLB6GPvm4hqJoCes22TvIN14fjz8udTQXNMVEbanKdhMgckZ3sjmAakOe9APmpTbWJ0GNVXwGoErrwLlaptkA5BIk2ZW3OcRWykaHZBnCgf2dNb6II7Mjjguw6H5_J1oMqJFQqIlFnxK5B4nvDzQ-9-lLIub0QvWlPn3jxTkZXBO2rrhBwUUDlZ0NN6dtl79XwliYz0aOc9gnfKptmei73V0WXP8qrv4v4ISgRCjytAC72Uao_QoB86j0jdNNuJ-HUz4BGCB4k6pr9rkOwdwd0PY5OfJbDO6PxqiXNO6unt6IOaIoKEhs0rxpRA6GzyooaoLrVTYQxaSeJTa8I_pwuILBgUSu99DD7HhbQwrloBN7ststbloZhT8cN6SzQ2nBbU_LxnroDH6GTrHFPruSt-5jY-lj9GEm4AFsRwQrXgcL_VMzPThUdbYDOMouzuACn9xdz2bhKcGF20DlLA06ZdtWQfOeYHWwFbmUR1FToyVsUkH8Y_V0vzEDLxzXnVS_0xumFFUXltD9kp4guS4W-MWAFa7hDRBG701kJNQXZqRkzHKqpLNgAdUggl59qrgqLbFtTtco2jaj3dmuPBQFppJL0Jbms5I6lDayWkpqxURphQ7mHtKuodiEmK-srvX2V-X49zV3W_wjAdKQzIZH7qyYNud9QhOO6kBrzhAueZModu_lcYU6SaKZ_s_jPkHauZ6lB04rihZnkpF-vcRVOARctFnxGLOyLQ5zsMxtZ9HIm_s7sRMNQoKAVSaGbgH60Vp9P4yUaHZvwIOfC0cJOynP0PZ4hL-5vjkMwsfYI8rvoyg7woA7gbff9UCQtZG4W5nNzR_06goA9-G9c1DAA__-DxpDpaM68LfopLNJoendZ5jNUEjAmGQBhvPHce4WISmsxtXXonFbZQUlja5KAw1nrlPs7QnkECMPBnwzCC9dj5_8m6ZOieQn0RJPAL2vd-3wSJ5Hdndz1O6wuJVRjdHFAoGFq-azLkSJsRfimKwzPorGlUaaHd1KXZAtKVAjgRKhBVN5iHRgIMB573yZ-gD7syERLNECujzRQnSZydBPLAejqmLcreLecByKa5M0e_vN5cxjNEraw9hCg5UzCCrIQ06Xn2S50s9l6V5g9c3IuAE0u-7OVLh0CSqV0aKXg9UOl5E_9n1kn6FA7bYfEK9oUWP91X690oVqobM1EZlUoBdA3drz4tNAsp0zCgG9SleiPCzzFURdTGlzDPKvzk5V7EWiSZf5Mx4mLTJtABBRH-ovoSHLuj0L_mtlTTpXBfyHXV0KdljQ3XQAl_CRHr98HbliFTonvLQLfal-vWW7KRX7H0TYYhPFl0v12_IVI9eae5QvmLLxElJuMYnTuvauewwMxjLSovOsxnIKvaTTDBGclEKpXOOY2sDHpamRKxm9lJLi1Cpwz-6GLdUM1_v97xFGyrlJBqDjLap_c2UcDTPU8EcPiBakEVQdkmNBhz7d08PUze28JH226GnIS9_poHQfroLnxo8RNnOJqFgvMa3xb3Gd9lmGVMwvZuZVsELFnXshva46Zouz6QZQ8V7O9mRDPI4B1oG2eGocb_E74G9i4hWISG_CrOiWwWFPaChqfIbLqFJbxTWRpv30iqmD7IpLgr4hMBMj8MujxlI1BqhnhotOfvOksRkCtOmwpofL0l4YGiJ6cCtwD7ALgzLN4_nTVXR6ZaETLZTqpAfx7z7INvRDuzeSsMdFcWTlLPCsA5WrSCKMC_jtUUAyPktcEKJ6QdLNmhwZmE4FUNrUcjSYZim-ZNXrYC3U5SF9WbsbeQ4G0Tz31JF5ls08RRzsCBCQGf-TKz2PR_hMD-QUCFwhgJkw3xqqy0MONTtECZDHLUiiL04IyK-MbWtV9BIMa7B3g-q8plZ_Rwroj83CoMQbJWb9Ofe6RM_87NN1kXoc8muhMHGZkUgmq_WQMayrSiq_L0Pm2YsJOaGOyJ4sHHd_R6-OlJ6zR6W4qU9bmJSZvF58Z6oshhPQToUQXObEB0E78alCmrWNYSrcXuMqyhzVToGiAdyJoQlBrpjCAR8Ra8_wYx-8EWMzJaHXYG908knfMALVUE51f8J0AAjB1JmVwZbehBhxJrwzgJo3gmLgWNBPvItPgq8HZX8oXgM4d3PwlNnUF6IsPMsyHIYFfnggIKTHv3Mz1QDTRHJ-SIIGnEHtHiUZojIQJf3CUG_UNZAlVL-qqj05sjZahdueLVH2bVYe3Xa75AuN5v8hoUdbeQfDY1LcNk4yz4SLnss5owSXvK_0DM9V2y510RrHmBVLx0GAo8TtgpVd7Vle2TzNeUksWkmCbYsgMealTceOPQsuDPQ5Ie_1kBss8qiz727fst9SueE5hjHe9vmB99Y9O8W18a7TwRedJv2M5RbxOVhq89bXUBq0bbfVoJ5l9t-1YL4-YKESmj529Bcy71_yNzXs8yRJvSUOPhG9-z5aWonPQI30QhcJqtHG_vtAQE4kT5oDEpujitzwdbQYtntGemNGQKWNYV6CLpi499KfZ10jdeHSkbRTZFjX5J7mffEwBVBRHbptsizL6fGCdY3KkFNKNEKU_FRcYgPSyrzRe4koB_Q-2g2yvHBYqghqLsmTMcahnki8uBB_H-WawnjX0jJwKvP9_azFkvOzrQUBl0yCuklM8npNEFAjVVS_h-jQ6Fseb-lyvehp63MVFac__nIdrYoVnOi1Yihb0w4A7Xt4QFtxyfCHnp1re9zisS4msZm0dfb3s-VRRFQ8VeXWazEIUtDc6QhBiTVaOIZjCOrAOV-BCDhnKPKaJ2gK5R0QspQes0EMt1jpPhgqX6Bvxsj-SMyyKZBr9mkAo1pMb4eJw6sWWchEhXQGQIArBDezuQFEa8KbOFoZ8mohCSLZO3pANGJaE0iEB9Uk-y0ftAkFEbzf_lUi8VHa7hDCqLCOvc56isd9MfVFkMWEhbiSaUhACAac75qp63Y7VVRZAR46EfrrIHvTbFO7yebBTxgetKZc4umvt68EUWDfGqVluVWealK0t63CgYo3dk_bnaQTWxIP8fpIJjgchJjie8luPDR2ZzzanU_TMK8hdE-5iHokVnSHWCnJ8TOI8qrRk9YUPCQof9B3I9pH-KJjBQmgo2SurVLFv230SUdrgs7n4EzBYu9GNq9ryakhwoQRLbQsN40PZJuXL3YSBm4Uprptq5-e_r-FnLIk_OcMUOCv6Vupn9-pqWLCc-mTpJCUdduz5Ht8Ecb-plOc0owN_dzBDgdlzA3d4UpAk_2PNmeXRv6e_futRtKRaKJwY0q1-7XnxHpn8PqmQ1sBYVkLpEOeETh_FlSXwcK1ie10hcnE1H988srGMRCtwgPiU7gAGZPuiXq5aaaGEklYLxEvaSRkASWrIzoP6yqk_FUk65o1Q4hqDCMJhXNSnxaYNgRunsxbv4e3nevbeuuaYHrjyrhPizillKvwwGfckmOv9Y25BZSUXMwSVK9Ad3XA98NajHK8rVoiTRa1fjfBXUwVoce2JcVhuzk1zR_B3KixTZCJl7TUT6ajt70IQA-EsWfNtxdUrINMgm0ZjJVkG3ccM2MVQ0v85VUDwMEqcF3LRFAY1-6Rt0shEK9H2HSvRC-jHBl6xV7DQM0OEuWRvJAECkbRTPDs-XbZhqUQJRRb6XMDZsqeX9tCS1MLyMZ1IUQlRIj3d1auBzc6ICfraQA-cMcAyxofrnaRwhZGr__gns5coe8-DQ3YzNE776gzwLAg5k5M-3WEGJY-BbRtde7opCZnWZWLK9tezTy9ws-qLiIeOlRUu5xSnfwuy6icNYqvWvAN6FwAz2m8F56m7RrtigY8JKwpSk2Jkz2XknkCdv-yaFl4PIZoeRF_pmLSi5jSyP4-ze0owGzmSX0CIRMqZYSsS7D0d88U0DWFFupGK4Kg_I4TPgjByoRH8hZrOcsKvmavJktXN-beunsA06WH8opv2jya9gZkxgAiFIifJBVgEDM5bfFtvfD6N3QJE9TfcUPNGoFqhvEBYzVgQnj1IPrMWBEjBrhc9iCnCattATNc8LVlYbHZ3514DESdjISCctsU-fnKuLN-W9tOdSYEp4xi3phiLD3TLI679uQtifBlAYAPabNDe8ZiwI20jl5REQX10lHjvnPRK7mLHxt7PkOGAcd3hVH_w2KzrWdpf_-DM36G6Lq4HvBUH4BNk8zewp3qybZu_V5zZ2hALyRv7Ibl6pULmyoscJXJoFzBHGDr8rqnazTAwFTWVCwxCskGHkw5DPDGsm1T7ILIgAPEveVdLmmnOP4rXI_o0RGsi-nQxdavHPt67-YWOFYeNWiy1AlNlra5DvL-hfDfxCNgrvG6BbW8c7xEhoFvlR80wgfwPDckjd3U4RjjiiUfVsvgf9bx6x9-cIzlxwiRBzVMnlTPXOwqAsJ2H1e8-_tKTFjFkZuYpVRFCf5Dy4xFcvP2rHtHXE3G_ZGii_M5ZwlrBkfmVVO19lazSqpe67rPuobutmjt1bK_A8B2plrI01cZ_B9yOMzrVoZJebI_cs2Eam46VWfOFGTMoJwzLWmwmF4jt6elLw17Wlrv7yW6RoFzMVROMfRGksuezBufgDDKgpK_aX4jWJpldlI_pNRTycgieG9xHkWPsslTUPFFQ07yNArqB_9ERbiZv_4ljva8O2U4lSmi_CPocI_Gf899EBvd7QmlGl7ZswYlb-VrfcfHuSg-eV0QUH4KwQDvx2qBxL3ng0bxCBgiNsOFv8Kot9afWjUA4YKpvoHajsai91iOUEJ1KBfd-GGv_l3M9OoZtpnXre5twKtdCfllAuLcmH4HMAW6cPX41sFdFf2wwk4aaTic4f5_TX3-dSk6_epKwdmjjucflHtrFp6c9SJwf_aB7y7XYnoq3DvveOtT8LqPb92mIsSwvkxd0E6CVw2D0kpUsD8t3wWz59IeaSuGdqzS_7DCBsk240J2F0L-bAi1UmwtJySyEH6gGcb2wzuekUpoL1lbk8NvOFhqGMskpzAW31X5KlAIB5fMqYIechq2qgUTX0fbFbbK-WOS5BNuZzQHg5u-x7KCsd4M-i0-JQtTNyHDQ9_6GICe3RAa1au6QMk3bbuEeX6p2rkQNIaoaP4X4cayBr_0yu1Txn9PV28js9BnbryxWauTjYYSz02CGE1kN8STnQ-ebpq3WkorL8QcPw7VJFDRytkwSz_AslMaxmoCzvftC8nxZgEveO027csojiijwJ0gpDZYvyhMgNcPhPaLIEJrVSWkyMnkt7Pu3Y2YotbyxyjnySgVgUhvU4rplk9cHykR-1KIdnyrtAmWD1POJhmmtRF0wbMXWPg2zp4LPvH1LRywS1Si6lgMCGOMXRfOzbm8PYJDeM13j6e5PrX78ZsaM_n1Y3cDfew8Oy5guR6ja2TAzstADnEs9-ieIV6xIgARP4tLLi5JSMSDKlaite-kt4Os6cW6ZPm3O3rUthnWq5vHRByyhVEytS-ALARuaoZdc-yl0RvQp08jXqnqueILKWdaRWXJveMAB4XenxSGeCVffEuAm2HdhC0EVcS3rimTX4FSGFLOD2cUNXoB7ywSDnP5VTZ-hQKp-URDXx3YsCj_nXwyIYC4EIUN34i4YUh-DprUnNfJqW9Ev3sfByzjyNS7W1a1htCgXckmy0XBY6X8bNswm7w1ptgpLU76NGOuu1haWJp-LPwxXgDEkpG2tLQQsCKedet_QiBmarepWVN1j9ZIkDDwQE5hwRNrwRgHyGIXk-mNcXXF1gmr3q68XEt2VEur6grCHA0CN3dy4NRxuoS1P-vaRxLl0Dl9Iy7lIGoZaKP_MdGdiotIZdnxe08sBWUvZGdUMg0gpEAn6CegsiuQbLCqT1KuPoMNLKnh-33zrHA7Jo9SqxZ-xrRpwhj-bTeL4v9WgALcRO22E8vhFrVJZICjEBwUv6rpo584dUhoxWlwC3wNo8VRp08Hkbso018pjErTyQ7Is61euKF_OxAvYmHgyZVb_IaldqIHSelpu7EQaaFtvLJSiA3XOIpD4O-rZeimfmS6tOOYQad2TjTbrO15c6AY1OlCWsWAbUGQ_8NGmAijI39Vfcy1z5DJceiok_1_Ao2jh82tEMflNeI6DVEe01zDeZvTHimGVreOj7P7a8Turi7VbzP1VlxrgAxDWZmkPWRxIzfrFjfdMM21KtCE5M1FAqX9buLWcCO-PYmQEjb3_34_g5jOwywcmJXB2LVw5H1d0LpnoBrZSYi52lQaYM0pUombI4jqfrHuZUemB_uYWMdqogdGtyWr23TJeUeQg8BfxtVzjmyw5lbCwH62GSDbpyjzCv3Fn3WDq0qrjR_Xwmj2B9bJR0SgWZhOZm9ZudUOuq3VEZcuaDNvRtmUGysZWzRGRAp3AxolKhk_gTywGIytH25Hj0L28paw0xjmN8YunkxNVbegg8MnXw5l9G8SXNPhZJYKZ5HqI5XRsbwZgvJvSHy5V_G8Ie9YLVrbpoYkmT0j7ErSHXh4BQeS_zbFJosev3fmnxJIEyTz916SACv0s1ocw80aohgzjK8N8eDz5FJ2JQIBZz8TNSYmfFX_Uv93_ZwR0mOAJ2QkKdv5maUC6JU_SSSmDCqcMwp1u4-AA--Z0rSCXGHWWkdZ4vWhRbxFkCQs1IcuSQn2-OxNBImLxvxmhS8XDBKFfm9t8B6ed4TjupnNn6x0BWG2BtJ0yk7Y2ecj8XMQaiaG4MKRdUd6i6xOz7GwmtSA7ckNZef3_B-XA-vw7kYih6vhIf0sRdDX7IK3GVrsN9LbhmMeswEQJteavZGwDWF-piCpBMJ4LWcwsKI534unKNAPhzVPIiczSD1gM8ykZnxVWZYfX4Gd5TC96tdoQq9Z9e-d7uksaInDQr-NSo9rMPPm2quIe_GUEeqzvRHVDmaJkmP-4CeMGghGHQHozDXavc8os__2len8ZFyVAKnyHfhn6D7eo4aHnPL3J4frq7M6SLDjdvunW9OCmROtmSkXjvFwM09w95KEcroXJBkM7bsA-Z6KU-uTwADINUA4TH3K3Y7R0oRmCBtWzT_mQaIE2fgqbwyI5ZhmjelOG8QZYPCK9OtqYwNw1pHDFeHHM9EcXrux-jfccDUJ4IPdOKGOkPurJx7EJv_Ed0sh1IKaYzNRuvsUJGbVU_xyb1nef-Fic6P38JCrC7EYEzLKdtKNCFTacUn9OO3Ygf9b833fcjfG0LYWZeCINxKp1OeGsOTd6am8kwL9Dwx41BbBRHHxb2Fa_w8oneZ5f5yQmHlKvhJ7Rh6hUEYWDCUOG2njMVe0BeI9H8bxzxeWZI4RCXYa0sbEbCqk30ivJI1pdzYuuyk9cc4qUbsPdIScAcSXk7NqBlS82Lz7kDtFjrRtNOVhrjpjlKV-a9W6-rPB0U2savy6xjp-e7yPL_S1Spt10edRjtxHt-AvX3qh56EJdILHPX1MbxFol5LhH9evz_dw2Pe9gxOTYS6S58qxcxX4Nb-KfXngnxaeJ48SsKN-TKi2TWntVLsjDBLPUO1LXrFw8_ZjijdW9j0SxZkOEbnvI3uJ3jvEVxMxUojlfUh7TvKdR209jBuO2ezWcLt3CKfRG6Ak0FjcugJ8ByMucCG5mGMOB7UyWCTurM4FvTeHHAN20C16LRkZ8VyANz-Oe9YfYFO9lrofS1-3jm8UoZ5AbIjCkOCAdOdVEo8RBOh_P8wOTVaYlURHOfeXniL51czYw3UjyIkMftiVXghc5KAWhwrqOkeTPDa3b4zImVqd00u-fsVl9_-c25qR-K1UaiwEEvF0ZJK1TTjMNerCVNezaycd8KZ8ktdaqQD9bvx3okUSpKFZ_WZtgRg4oOlf7ac1ba0PUyigxms9I-9f6snYfzyefP3elvMXL4KpbcDfDcxEWrwFiQ-xDSHjHLrve-irM1DEbgNY85C4XciSOq_fMVut-s6GulegmFjJYOukwLjpLFrEEaenpEKKQlN0upzQcHmdUm1XPUuOFrevg3IMzIpYoYjpsMHtJPXEhViPcpt2uwwRH6gWGtt9wX1KFlYeES1LfdNYBgBA4myFQwz8TR3EeojBxTwtW_pIX5P_A0byfabD2BCEKDZwmgiLfSA25skSB57d2WllO8GkY0pdKBkprewSBb9rqcrRDIk-wd_hSX5NGSnlUGY2-hU0ng1erQeYamS5pYw-BUVTtka3WdDIK4Xg_-RXXg08hfdruAZT-QNBr4KhSVX1l_W-BACPuXirWu1LH12Fu1LQ7X168GjM3ncmfW1abNU6auYfJoxOYTvditijm4SHidFcLNNOYGTOe5WkNNUMKhfjPI03_ofrwmbC0XZvgrUdRPNLM4ocIb4u9W6_LuDRcxd_pnv061OvmBXLYjVQx_O5sscdftVxVj70DaT1Xt1CI51THYtlr0iA_r-xYFTYEMBvNOdz8mzQOblwbeLqnhFWvkcjBj__0K8brz9WTkKJDmq1JPTkG6h-hjPgAcyL-ayVuWJ0iLlvXObqalnNWZ41zyc5XG2uOX2roF2EMOwjZ4Io5eAnhR5ZkhxBJTm9egvFyZ-sU9ibMw4dglZ-_mESgmo6AF7UKR77czR_c6gaTUOdu_U=', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de', - signature='gAAAAABoxCyzDT6i7ehEoWDBoDGMZmLcOX8TMbvBssJGa0cA0-7Dy6YfH759wsF0Dn5Auzz8Mp2geHtbVJVxKa-SF4Al-z3lq7gQG29dTf2ecfq_6bkg1gS49MbGEmaLo4FnS6_5oekdntomcOVO4mqwC7JKnCTO5Qyq8-Nm3POi0nOZm6KaEfqrmPHiJttupduQBkiqHIc8_CIfQ9LGqSxXZuAFQ0DbNow-6yya7_5oNOoLdgWti5_n9CENxTYyvG_q-2WAmioZM_rR54rWqmMbxUNNsKJls8xx593rb4u2dEpFJztVeifJNmFnDcYDDHMhvqLdSXJU4z3Yrxg8hgH9w2gD7Ygu2UDsMsiUdp5YGXKx_acJeu81-7H8Yf3XY86woskIv2o2XaegpK496fKkeiUAD8OTGWK0hjJb9KPK3hqTBfRfJzafQbIvnNTwOod3ZPyClgSXTYKsN1E_j3S6G8R0uzyA_NBc47Q-VMIUYf3jBTym3NUTMwiA95qdR1_1N-l4Yy7c9-X3UiRrVpNQ53lNuaUzdYuSq7XGHS_4ZNFwKXuG_dM7U2vhn_2dk2fkuEKZjtBYkVofStR8qlkswIAuEw4mrnt-wjG8cxrAwacoXop0R6NShjmWSrAhgqvAqwY3oR4HCPo_zaHSWjnJcRZ41LkVEcBSvtXqNpez2jYYmUkoGHgr_5gGpHpPo2j2lM0pBmPwPQ3OA8RJLEZYiQtabP7AKzZ32Lvsf35uhLRMZ6hkLtwPKgJ4tuR6E2B7xlZ6C0UoUbuI2Spou5dQsqPd6byXwHa22yViPpcpjeZOgHKK41cnK_tpL1kEe1KtodMW43d4OwHZ4LYqm8B769ob3uWnzGOMSGSrTsvci7gm00P0mwKBCh-XC1xdo448iGC7O_bvfYeBJNGsFObB3KqT7WLy04gc0gP7uWH629g151xRPzILeJUHsM_MwrFbNRqo9KbJFtGP0AQiQkO9lE-0VpWQW6ZyQLg6wByI-pPwakXJiCWxpxQF95NRjGOvwYyoU32ipX9mqEjdjQ-vTDn9vte8wPww0aPtAKqK-k0gkeBZAJYALVZNj6Oh0BUdA2t-XcMxs7Qho0V-LLgUjrmyM2ci71LgxeqO8I7LkOuGYMGYj2rFIGrzMeZOgucDhMyury4ELb50ohyYGjf5sOYavsYUwzK3NQwDZ3kjyHFSzCvgkuRgMLKxmME-4aRW8VbGLyC1f2hDuwxzL-cExk4yMh8TijVsf-bnRhHwmQKiR-SGkhrylfn-WnBQQffAdWpjscP9od0UJSPZrLZTaht7Z_15rMw9RO7vXl6PmcFw8vYciH58zUpU5vgq5_QGNvACSnnQxG8Nc9KmIYxGQyMow_ch1PBUP4yGYXR7Xwg0YiB6bwW5p_bxysCJAWBrp4sazb2Al3055Cfnmq9QXTFwFJo0jfbpqwPySuQ28TAiZah0CbCf_zdpJgz9hqM9HeRWHDwIKiR9OpxH2N8rWLqqRZTyfvRX7BfMF6P1bFVVagwhqljKZfcF7QFztlqKdYSGcsA6jdz1RT7B9CItJyKCnHgTYsFtxOr-7z8lkNNlb3xJAYmwYuSQszTR0nFnP4Inc_Ay8XVdmY-ppo6PMJztYQqZXB9wABGkzfKUl9UAIvjMrqHAw76sw28WTA3xxoVS64CM4YDs028hnVsL6euOe6VVBqpVMbrQ6OVi2FOR-vLbNAVBwbelAhbsqoZNMATg8bqlf3UMwacTkr_R1me2gDFv2BjxbjvlZUApzkl9L-CMnVPEsyb187O20chSrJhsy2tLh8SC_6_XCCnNFub3RAvD0BkNzDVZig_oC3ps_EEaPZgEdtbUb_GqaCFcbeo6X4wY7xkr1gZfTP_NHK8XyElajh_HP8T1fPmTZMh46rtXh5-54th6NQ_3jTjCeOfmLjbQKotLNOhJKlB8vXa2CsO575d2zkP2CAMGy9TU_ztUCfaGFOeFPN_xvz1vBZ7QqA-yA10tOdOm8b3oowPfMbZ2n5mvyLNG-DgUkjPGty5gyvJvyMgoqZao66fyzfLvM28eQMpOOcGAcozDFnW_vkffTU5GmPLUaG6rx74V32RVzaQKuC_nGBF8T_NfJ9NfecUw2uj21vCcUyTiIQb3Are8aZLnfsi4DyY-E7WhNnBoLsKZO1CzurCYKCPi4KYGjTr9og_MQM4frL9nez4teQDdUZnu3TkTqF9jRmeFMpZNLaRydPWCmumrCI7HSwb6PuBmsswxPi5Br_NcjszNq-c3t5_Gj8klCceJjDak7wjMuGYSK1GU34iRlNW7iUYUACE4FApDJciqJcRXE31-S_b7IsZ2xcMU4f0Qf1sWHuKKRiwG-Wx-AhXjDSH_tbhauB0P3JEAFg0eNnsRBwUvrYqzPRKkAJz0AUF_biQ-s3czpmmt77NBxh_IjIfVbfOs8QbHM1bgZqUzhS1f-cFLcrEypLHL49Iuy_qXlut79gr2XBsQ05ZIQvOtzCmjZ32b_P-d8oeGzW65rwq0HovxMWxwR7zHqoZD3KJ__a72HMcwK3-fYZBzjMjxOHlBxdzmy4_xsfUBMWxuXREypfY9cb8uuALpRJCebN4pIocB59ShZgTtApb2GVk2jheXHAMx8-7GAUO_W8mzJlaHtrdJd1QYFME1W-_bhfJkYJW70phqUcvVDjoBGHiiL6TxkYAFwCNUhJsvnIG8Ihm09t8TKmcrPx73MVG-euP6T1ZIVL5FFX4kOqSZW2gKg_cUr6xUhuey3sVNd5Qfl_q3PHNHVif93EpJ6iac1VQ6soW9MwuNpKURX_r6WWDx6kyeTXKmbE_6Boe4jSTq_BKYY_SYoZY8AIOrGmKBV6wemc7hR8ko5yfH5_T4V7rwHSPotueN02Xb7qAgizPUxwxuMvwiQoqo6PEI6V96_iRvTCso0mJ2k-EZ7e77Wo3X4A2EjH1ciljhDA2uQAh5QgGUgVI3QfGiaDFrgeQQOatOd-zqvM1j-WB0ZBpjYFR13O8N2ZqXQQ_AlWOmx60LQI79a-BIZb_UBzkpMpR-bsUlFq_CQv9o4cxGU3M9Orwsck_5a_V2Mlsicz8ThvLz2-MaoQvwnU3Zskde4SyRQlqMYSThRxSc1kUBsDDWgBWNrvpeVDxvLAmc8XVR_xMgCiRcyAvrv9kG3RseYoD--fqyx_YpoAGleoG4jA4FFkvZdE-MEN3CSuML2oOJAsMNgAG1mNzkbeJO53oe6qrL4ZnnYHQyayaxSMpi0FonMibsg6pHn8EZ1vKes2W9ljy02W8lfTxnaXewF5qX9uKTnfHM2s9MSdSasJCLagPDjA5ZtsRcwBMpZ6LgJuT6OZsvYyWONDM2y-BdUMN1iiIvJXaRIG-smszpElaZZimJUSPKhO3klT5LH0mZRWL03AnpauWNRdZNZhWJl7sum2bEulbxe7_Ir0LvN1IxUTbDX4TLTDwPc4vEpouKM278KKxo8idZlo0Sd-Azwu6CAvr0uIs0Vs6SqKWWvyC5B5ZmJwxJ_uEFphVW1WKxUxqhSHadoLF95BtwU23ayhu7GV6ZbpgkS9JBETCsYY1xZ0W_A02jv6SsSX45zEg7wJVgKl_EgWBlCw8QCxNirmpxcYvEbikYIBz1NscUBlLnGNIpGONVzrdtmBOkkikw0Goot8ixXePS0_7Jm1LavQIqhklO2SZ8Ve90UZCf0cO4NioF9S58mYFxQ5M4UAErTkbH6LOpmk9I3OhSUUgDwpYN9FWIc__JoAvfUIqvgxvvU13DUyTjdyWvcJyAd2qN_TqSQRreY2fiieLXTEDsZwMRy3qVKQIXVc8wd3hiztuO45EXMqW6ho3OhXFPiVhXUzzt6YJ4SFO5_yPLDOLQj0t4jOnjdvAOnt0gdiC8VSZaugxZTpQFSDPD-skDmj0CAZ9VUJhWNUnkRK_aiclAf2rouiJ1Ot9APUEtXlHR2ImVQSrepMEHDJz1ijCH6QUnkX1aTYt41RBZiEa09207Ow8X1BtTrhofjxAyLzVhEqg76sNiXHhP7J9QAYhxctefmDgk6ZUHqIeveNDeKKfeXrW2UzlLBl6S3xW1xnHBrHxp6wcjngqih1SG0eqfXWgJ_mEg9lOUrbDttiTJbTE7_XhZ2vfJ7Y626u0J6Iz7mGcPa3nCSgzskbBKQflfE0CqS-N-AjTirwU2_7Lb-ofMmbd-rWludoNtNwzh6BAKFVs66rHa-VrWSwoWR-2mMD1GD8WzsjCN4PvgTo5mOGlltDDkWROl5ibhJ-tLyAeZ4mtK5f_oVModXQtapyXA9GEoktjGtoFqE3BkMwk0i_P542lOJ3fNGI-sPyfaWRQXx56wxy470_0dwy_o3aSvJdetOxOi32BfEqfPN-TBNU3MkX_bt0FTMcXjOltnoGh6bgZI8tZ4RGHof9yBLhqVsW9aQ8LN8amNJg4JCsO75vjpW0nDgOk6cKeadSWjP3fBJ_BEmfFkDgLfGeZ_ILTxpzJ9r7yCGPdFoA1C5a1i4DT-3A0UD15W6cpgdfAYRF0Wt3i4UDopGFpASyM1_TpKBzig_iy8j4yM6qUwSShEQiGDdNohlrS2q0fS03Rk7EJEi9wFLB6GPvm4hqJoCes22TvIN14fjz8udTQXNMVEbanKdhMgckZ3sjmAakOe9APmpTbWJ0GNVXwGoErrwLlaptkA5BIk2ZW3OcRWykaHZBnCgf2dNb6II7Mjjguw6H5_J1oMqJFQqIlFnxK5B4nvDzQ-9-lLIub0QvWlPn3jxTkZXBO2rrhBwUUDlZ0NN6dtl79XwliYz0aOc9gnfKptmei73V0WXP8qrv4v4ISgRCjytAC72Uao_QoB86j0jdNNuJ-HUz4BGCB4k6pr9rkOwdwd0PY5OfJbDO6PxqiXNO6unt6IOaIoKEhs0rxpRA6GzyooaoLrVTYQxaSeJTa8I_pwuILBgUSu99DD7HhbQwrloBN7ststbloZhT8cN6SzQ2nBbU_LxnroDH6GTrHFPruSt-5jY-lj9GEm4AFsRwQrXgcL_VMzPThUdbYDOMouzuACn9xdz2bhKcGF20DlLA06ZdtWQfOeYHWwFbmUR1FToyVsUkH8Y_V0vzEDLxzXnVS_0xumFFUXltD9kp4guS4W-MWAFa7hDRBG701kJNQXZqRkzHKqpLNgAdUggl59qrgqLbFtTtco2jaj3dmuPBQFppJL0Jbms5I6lDayWkpqxURphQ7mHtKuodiEmK-srvX2V-X49zV3W_wjAdKQzIZH7qyYNud9QhOO6kBrzhAueZModu_lcYU6SaKZ_s_jPkHauZ6lB04rihZnkpF-vcRVOARctFnxGLOyLQ5zsMxtZ9HIm_s7sRMNQoKAVSaGbgH60Vp9P4yUaHZvwIOfC0cJOynP0PZ4hL-5vjkMwsfYI8rvoyg7woA7gbff9UCQtZG4W5nNzR_06goA9-G9c1DAA__-DxpDpaM68LfopLNJoendZ5jNUEjAmGQBhvPHce4WISmsxtXXonFbZQUlja5KAw1nrlPs7QnkECMPBnwzCC9dj5_8m6ZOieQn0RJPAL2vd-3wSJ5Hdndz1O6wuJVRjdHFAoGFq-azLkSJsRfimKwzPorGlUaaHd1KXZAtKVAjgRKhBVN5iHRgIMB573yZ-gD7syERLNECujzRQnSZydBPLAejqmLcreLecByKa5M0e_vN5cxjNEraw9hCg5UzCCrIQ06Xn2S50s9l6V5g9c3IuAE0u-7OVLh0CSqV0aKXg9UOl5E_9n1kn6FA7bYfEK9oUWP91X690oVqobM1EZlUoBdA3drz4tNAsp0zCgG9SleiPCzzFURdTGlzDPKvzk5V7EWiSZf5Mx4mLTJtABBRH-ovoSHLuj0L_mtlTTpXBfyHXV0KdljQ3XQAl_CRHr98HbliFTonvLQLfal-vWW7KRX7H0TYYhPFl0v12_IVI9eae5QvmLLxElJuMYnTuvauewwMxjLSovOsxnIKvaTTDBGclEKpXOOY2sDHpamRKxm9lJLi1Cpwz-6GLdUM1_v97xFGyrlJBqDjLap_c2UcDTPU8EcPiBakEVQdkmNBhz7d08PUze28JH226GnIS9_poHQfroLnxo8RNnOJqFgvMa3xb3Gd9lmGVMwvZuZVsELFnXshva46Zouz6QZQ8V7O9mRDPI4B1oG2eGocb_E74G9i4hWISG_CrOiWwWFPaChqfIbLqFJbxTWRpv30iqmD7IpLgr4hMBMj8MujxlI1BqhnhotOfvOksRkCtOmwpofL0l4YGiJ6cCtwD7ALgzLN4_nTVXR6ZaETLZTqpAfx7z7INvRDuzeSsMdFcWTlLPCsA5WrSCKMC_jtUUAyPktcEKJ6QdLNmhwZmE4FUNrUcjSYZim-ZNXrYC3U5SF9WbsbeQ4G0Tz31JF5ls08RRzsCBCQGf-TKz2PR_hMD-QUCFwhgJkw3xqqy0MONTtECZDHLUiiL04IyK-MbWtV9BIMa7B3g-q8plZ_Rwroj83CoMQbJWb9Ofe6RM_87NN1kXoc8muhMHGZkUgmq_WQMayrSiq_L0Pm2YsJOaGOyJ4sHHd_R6-OlJ6zR6W4qU9bmJSZvF58Z6oshhPQToUQXObEB0E78alCmrWNYSrcXuMqyhzVToGiAdyJoQlBrpjCAR8Ra8_wYx-8EWMzJaHXYG908knfMALVUE51f8J0AAjB1JmVwZbehBhxJrwzgJo3gmLgWNBPvItPgq8HZX8oXgM4d3PwlNnUF6IsPMsyHIYFfnggIKTHv3Mz1QDTRHJ-SIIGnEHtHiUZojIQJf3CUG_UNZAlVL-qqj05sjZahdueLVH2bVYe3Xa75AuN5v8hoUdbeQfDY1LcNk4yz4SLnss5owSXvK_0DM9V2y510RrHmBVLx0GAo8TtgpVd7Vle2TzNeUksWkmCbYsgMealTceOPQsuDPQ5Ie_1kBss8qiz727fst9SueE5hjHe9vmB99Y9O8W18a7TwRedJv2M5RbxOVhq89bXUBq0bbfVoJ5l9t-1YL4-YKESmj529Bcy71_yNzXs8yRJvSUOPhG9-z5aWonPQI30QhcJqtHG_vtAQE4kT5oDEpujitzwdbQYtntGemNGQKWNYV6CLpi499KfZ10jdeHSkbRTZFjX5J7mffEwBVBRHbptsizL6fGCdY3KkFNKNEKU_FRcYgPSyrzRe4koB_Q-2g2yvHBYqghqLsmTMcahnki8uBB_H-WawnjX0jJwKvP9_azFkvOzrQUBl0yCuklM8npNEFAjVVS_h-jQ6Fseb-lyvehp63MVFac__nIdrYoVnOi1Yihb0w4A7Xt4QFtxyfCHnp1re9zisS4msZm0dfb3s-VRRFQ8VeXWazEIUtDc6QhBiTVaOIZjCOrAOV-BCDhnKPKaJ2gK5R0QspQes0EMt1jpPhgqX6Bvxsj-SMyyKZBr9mkAo1pMb4eJw6sWWchEhXQGQIArBDezuQFEa8KbOFoZ8mohCSLZO3pANGJaE0iEB9Uk-y0ftAkFEbzf_lUi8VHa7hDCqLCOvc56isd9MfVFkMWEhbiSaUhACAac75qp63Y7VVRZAR46EfrrIHvTbFO7yebBTxgetKZc4umvt68EUWDfGqVluVWealK0t63CgYo3dk_bnaQTWxIP8fpIJjgchJjie8luPDR2ZzzanU_TMK8hdE-5iHokVnSHWCnJ8TOI8qrRk9YUPCQof9B3I9pH-KJjBQmgo2SurVLFv230SUdrgs7n4EzBYu9GNq9ryakhwoQRLbQsN40PZJuXL3YSBm4Uprptq5-e_r-FnLIk_OcMUOCv6Vupn9-pqWLCc-mTpJCUdduz5Ht8Ecb-plOc0owN_dzBDgdlzA3d4UpAk_2PNmeXRv6e_futRtKRaKJwY0q1-7XnxHpn8PqmQ1sBYVkLpEOeETh_FlSXwcK1ie10hcnE1H988srGMRCtwgPiU7gAGZPuiXq5aaaGEklYLxEvaSRkASWrIzoP6yqk_FUk65o1Q4hqDCMJhXNSnxaYNgRunsxbv4e3nevbeuuaYHrjyrhPizillKvwwGfckmOv9Y25BZSUXMwSVK9Ad3XA98NajHK8rVoiTRa1fjfBXUwVoce2JcVhuzk1zR_B3KixTZCJl7TUT6ajt70IQA-EsWfNtxdUrINMgm0ZjJVkG3ccM2MVQ0v85VUDwMEqcF3LRFAY1-6Rt0shEK9H2HSvRC-jHBl6xV7DQM0OEuWRvJAECkbRTPDs-XbZhqUQJRRb6XMDZsqeX9tCS1MLyMZ1IUQlRIj3d1auBzc6ICfraQA-cMcAyxofrnaRwhZGr__gns5coe8-DQ3YzNE776gzwLAg5k5M-3WEGJY-BbRtde7opCZnWZWLK9tezTy9ws-qLiIeOlRUu5xSnfwuy6icNYqvWvAN6FwAz2m8F56m7RrtigY8JKwpSk2Jkz2XknkCdv-yaFl4PIZoeRF_pmLSi5jSyP4-ze0owGzmSX0CIRMqZYSsS7D0d88U0DWFFupGK4Kg_I4TPgjByoRH8hZrOcsKvmavJktXN-beunsA06WH8opv2jya9gZkxgAiFIifJBVgEDM5bfFtvfD6N3QJE9TfcUPNGoFqhvEBYzVgQnj1IPrMWBEjBrhc9iCnCattATNc8LVlYbHZ3514DESdjISCctsU-fnKuLN-W9tOdSYEp4xi3phiLD3TLI679uQtifBlAYAPabNDe8ZiwI20jl5REQX10lHjvnPRK7mLHxt7PkOGAcd3hVH_w2KzrWdpf_-DM36G6Lq4HvBUH4BNk8zewp3qybZu_V5zZ2hALyRv7Ibl6pULmyoscJXJoFzBHGDr8rqnazTAwFTWVCwxCskGHkw5DPDGsm1T7ILIgAPEveVdLmmnOP4rXI_o0RGsi-nQxdavHPt67-YWOFYeNWiy1AlNlra5DvL-hfDfxCNgrvG6BbW8c7xEhoFvlR80wgfwPDckjd3U4RjjiiUfVsvgf9bx6x9-cIzlxwiRBzVMnlTPXOwqAsJ2H1e8-_tKTFjFkZuYpVRFCf5Dy4xFcvP2rHtHXE3G_ZGii_M5ZwlrBkfmVVO19lazSqpe67rPuobutmjt1bK_A8B2plrI01cZ_B9yOMzrVoZJebI_cs2Eam46VWfOFGTMoJwzLWmwmF4jt6elLw17Wlrv7yW6RoFzMVROMfRGksuezBufgDDKgpK_aX4jWJpldlI_pNRTycgieG9xHkWPsslTUPFFQ07yNArqB_9ERbiZv_4ljva8O2U4lSmi_CPocI_Gf899EBvd7QmlGl7ZswYlb-VrfcfHuSg-eV0QUH4KwQDvx2qBxL3ng0bxCBgiNsOFv8Kot9afWjUA4YKpvoHajsai91iOUEJ1KBfd-GGv_l3M9OoZtpnXre5twKtdCfllAuLcmH4HMAW6cPX41sFdFf2wwk4aaTic4f5_TX3-dSk6_epKwdmjjucflHtrFp6c9SJwf_aB7y7XYnoq3DvveOtT8LqPb92mIsSwvkxd0E6CVw2D0kpUsD8t3wWz59IeaSuGdqzS_7DCBsk240J2F0L-bAi1UmwtJySyEH6gGcb2wzuekUpoL1lbk8NvOFhqGMskpzAW31X5KlAIB5fMqYIechq2qgUTX0fbFbbK-WOS5BNuZzQHg5u-x7KCsd4M-i0-JQtTNyHDQ9_6GICe3RAa1au6QMk3bbuEeX6p2rkQNIaoaP4X4cayBr_0yu1Txn9PV28js9BnbryxWauTjYYSz02CGE1kN8STnQ-ebpq3WkorL8QcPw7VJFDRytkwSz_AslMaxmoCzvftC8nxZgEveO027csojiijwJ0gpDZYvyhMgNcPhPaLIEJrVSWkyMnkt7Pu3Y2YotbyxyjnySgVgUhvU4rplk9cHykR-1KIdnyrtAmWD1POJhmmtRF0wbMXWPg2zp4LPvH1LRywS1Si6lgMCGOMXRfOzbm8PYJDeM13j6e5PrX78ZsaM_n1Y3cDfew8Oy5guR6ja2TAzstADnEs9-ieIV6xIgARP4tLLi5JSMSDKlaite-kt4Os6cW6ZPm3O3rUthnWq5vHRByyhVEytS-ALARuaoZdc-yl0RvQp08jXqnqueILKWdaRWXJveMAB4XenxSGeCVffEuAm2HdhC0EVcS3rimTX4FSGFLOD2cUNXoB7ywSDnP5VTZ-hQKp-URDXx3YsCj_nXwyIYC4EIUN34i4YUh-DprUnNfJqW9Ev3sfByzjyNS7W1a1htCgXckmy0XBY6X8bNswm7w1ptgpLU76NGOuu1haWJp-LPwxXgDEkpG2tLQQsCKedet_QiBmarepWVN1j9ZIkDDwQE5hwRNrwRgHyGIXk-mNcXXF1gmr3q68XEt2VEur6grCHA0CN3dy4NRxuoS1P-vaRxLl0Dl9Iy7lIGoZaKP_MdGdiotIZdnxe08sBWUvZGdUMg0gpEAn6CegsiuQbLCqT1KuPoMNLKnh-33zrHA7Jo9SqxZ-xrRpwhj-bTeL4v9WgALcRO22E8vhFrVJZICjEBwUv6rpo584dUhoxWlwC3wNo8VRp08Hkbso018pjErTyQ7Is61euKF_OxAvYmHgyZVb_IaldqIHSelpu7EQaaFtvLJSiA3XOIpD4O-rZeimfmS6tOOYQad2TjTbrO15c6AY1OlCWsWAbUGQ_8NGmAijI39Vfcy1z5DJceiok_1_Ao2jh82tEMflNeI6DVEe01zDeZvTHimGVreOj7P7a8Turi7VbzP1VlxrgAxDWZmkPWRxIzfrFjfdMM21KtCE5M1FAqX9buLWcCO-PYmQEjb3_34_g5jOwywcmJXB2LVw5H1d0LpnoBrZSYi52lQaYM0pUombI4jqfrHuZUemB_uYWMdqogdGtyWr23TJeUeQg8BfxtVzjmyw5lbCwH62GSDbpyjzCv3Fn3WDq0qrjR_Xwmj2B9bJR0SgWZhOZm9ZudUOuq3VEZcuaDNvRtmUGysZWzRGRAp3AxolKhk_gTywGIytH25Hj0L28paw0xjmN8YunkxNVbegg8MnXw5l9G8SXNPhZJYKZ5HqI5XRsbwZgvJvSHy5V_G8Ie9YLVrbpoYkmT0j7ErSHXh4BQeS_zbFJosev3fmnxJIEyTz916SACv0s1ocw80aohgzjK8N8eDz5FJ2JQIBZz8TNSYmfFX_Uv93_ZwR0mOAJ2QkKdv5maUC6JU_SSSmDCqcMwp1u4-AA--Z0rSCXGHWWkdZ4vWhRbxFkCQs1IcuSQn2-OxNBImLxvxmhS8XDBKFfm9t8B6ed4TjupnNn6x0BWG2BtJ0yk7Y2ecj8XMQaiaG4MKRdUd6i6xOz7GwmtSA7ckNZef3_B-XA-vw7kYih6vhIf0sRdDX7IK3GVrsN9LbhmMeswEQJteavZGwDWF-piCpBMJ4LWcwsKI534unKNAPhzVPIiczSD1gM8ykZnxVWZYfX4Gd5TC96tdoQq9Z9e-d7uksaInDQr-NSo9rMPPm2quIe_GUEeqzvRHVDmaJkmP-4CeMGghGHQHozDXavc8os__2len8ZFyVAKnyHfhn6D7eo4aHnPL3J4frq7M6SLDjdvunW9OCmROtmSkXjvFwM09w95KEcroXJBkM7bsA-Z6KU-uTwADINUA4TH3K3Y7R0oRmCBtWzT_mQaIE2fgqbwyI5ZhmjelOG8QZYPCK9OtqYwNw1pHDFeHHM9EcXrux-jfccDUJ4IPdOKGOkPurJx7EJv_Ed0sh1IKaYzNRuvsUJGbVU_xyb1nef-Fic6P38JCrC7EYEzLKdtKNCFTacUn9OO3Ygf9b833fcjfG0LYWZeCINxKp1OeGsOTd6am8kwL9Dwx41BbBRHHxb2Fa_w8oneZ5f5yQmHlKvhJ7Rh6hUEYWDCUOG2njMVe0BeI9H8bxzxeWZI4RCXYa0sbEbCqk30ivJI1pdzYuuyk9cc4qUbsPdIScAcSXk7NqBlS82Lz7kDtFjrRtNOVhrjpjlKV-a9W6-rPB0U2savy6xjp-e7yPL_S1Spt10edRjtxHt-AvX3qh56EJdILHPX1MbxFol5LhH9evz_dw2Pe9gxOTYS6S58qxcxX4Nb-KfXngnxaeJ48SsKN-TKi2TWntVLsjDBLPUO1LXrFw8_ZjijdW9j0SxZkOEbnvI3uJ3jvEVxMxUojlfUh7TvKdR209jBuO2ezWcLt3CKfRG6Ak0FjcugJ8ByMucCG5mGMOB7UyWCTurM4FvTeHHAN20C16LRkZ8VyANz-Oe9YfYFO9lrofS1-3jm8UoZ5AbIjCkOCAdOdVEo8RBOh_P8wOTVaYlURHOfeXniL51czYw3UjyIkMftiVXghc5KAWhwrqOkeTPDa3b4zImVqd00u-fsVl9_-c25qR-K1UaiwEEvF0ZJK1TTjMNerCVNezaycd8KZ8ktdaqQD9bvx3okUSpKFZ_WZtgRg4oOlf7ac1ba0PUyigxms9I-9f6snYfzyefP3elvMXL4KpbcDfDcxEWrwFiQ-xDSHjHLrve-irM1DEbgNY85C4XciSOq_fMVut-s6GulegmFjJYOukwLjpLFrEEaenpEKKQlN0upzQcHmdUm1XPUuOFrevg3IMzIpYoYjpsMHtJPXEhViPcpt2uwwRH6gWGtt9wX1KFlYeES1LfdNYBgBA4myFQwz8TR3EeojBxTwtW_pIX5P_A0byfabD2BCEKDZwmgiLfSA25skSB57d2WllO8GkY0pdKBkprewSBb9rqcrRDIk-wd_hSX5NGSnlUGY2-hU0ng1erQeYamS5pYw-BUVTtka3WdDIK4Xg_-RXXg08hfdruAZT-QNBr4KhSVX1l_W-BACPuXirWu1LH12Fu1LQ7X168GjM3ncmfW1abNU6auYfJoxOYTvditijm4SHidFcLNNOYGTOe5WkNNUMKhfjPI03_ofrwmbC0XZvgrUdRPNLM4ocIb4u9W6_LuDRcxd_pnv061OvmBXLYjVQx_O5sscdftVxVj70DaT1Xt1CI51THYtlr0iA_r-xYFTYEMBvNOdz8mzQOblwbeLqnhFWvkcjBj__0K8brz9WTkKJDmq1JPTkG6h-hjPgAcyL-ayVuWJ0iLlvXObqalnNWZ41zyc5XG2uOX2roF2EMOwjZ4Io5eAnhR5ZkhxBJTm9egvFyZ-sU9ibMw4dglZ-_mESgmo6AF7UKR77czR_c6gaTUOdu_U=', - provider_name='openai', - ), + ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), + ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), + ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), + ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), + ThinkingPart(content=IsStr(), id='rs_68c42c90b950819c9e32c46d4f8326ca07460311b0c8d3de'), TextPart( content=IsStr(), id='msg_68c42cb1aaec819cb992bd92a8c7766007460311b0c8d3de', @@ -2293,30 +2268,10 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, signature=IsStr(), provider_name='openai', ), - ThinkingPart( - content=IsStr(), - id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de', - signature='gAAAAABoxCzZ6TwL-z6tYv85YPC9CwMFJRrSrWgYUyOhSFYLkdfGwRUIbrgBnmAW0qtzE-shPNPNfbUltLnBS4uU8kMuSMPxotFngVcFFnZ8qmzDUJiEf2CsnqYqH5d2RmuvIXUQTau20SjGte8vOLksGsz0sXRUQnFs7ZoT_2DSy7tKVCCN7fbvkxm2l9D-IibdvGiflbP6lGGgYWczEl3_QyEyJGhDTcL_nUk511C2hjvqI6YkEjujvYjEGMh-BdhFrJeLFL2wCbn6beWaDB2IXYVo7LqhlQUtKksY2PQ4ybBgPhERNvWWf2N-K4NxEQuv6vdB_5ni_BlUKFMabeeeI4wVr5M3HKE6cSgnM8cpi93o_rGu9uSh5fbN5zZcIYumnjkGJ-ULwku7TVtpw_Vha8bJl67qCLvRe90MaCCgJxFKp-IsxakpnNCXVrAlN70cIchPEjOWW3VKrGZ-omyQLgs3EzddhaPmSqDELbmYkxCUuRYdLvZPzhI5VvNiW_j-WGBKEMJLFz0k33oPbH3Q6Fn9HcJSruSsQ8Lc-QWQsibGoABEY_auM7LDLjbvpEYcdsP5BJOBUS8wpyOD7N5jEQL2PYPT3tsP6mvWy7csRIkwEbh1x1sXp6NL3skS6QwpqNiWalP4OQvs8jDi8Gz-NrtNvmX3RR4A0MIuX4q0Tb1VI9PilRUvOvg9hF-fk3bqIh7wW7_iD2eDoXjvI99M-UZ2QZGZlPa1O039QVGLBTi-KwrLuhh-D5q3N-3-DyXY0sjsdFzM5Qf__lVaxtRhZRKyxSONZsTt8mGatlOH4Q-MIPgCXsrLu25gWn6Jr6vt_iQ1eZG30cox98F4aU11Hp-o4tFKuHL8Kbgl9Eetpd4ggfJrTe9QxQfWfgCHAKnhjVRJOepHPEFzSRFKiHrOgATIw_x5xNRacsF_tO1WkpeBdBJhpAUozarHgPQi2A71LCcmd5Zzy7FAL6R_5QtHW-H7NE2PjqqXnf2ZMiMM-oYLHKhfu8tZu9EV7V21xKkovIGH-0OQ-lk44ww8-j3rBNXjWIwp8SO73O85PP7vzE_zJJCF8riB_rOpazJpMCaDP_HUOZq5XhcfHseiS1SownunaXj2wOmgLJ103BowC18-i83n8RVTtRQxLsiCRzMwRH3eEbEClqZ1Fqt4V6NKqICKK3kF3_R_oPtX_-7xYBpl8LGR2Ei_2hXkEIuQ8cCRz1zmuyfjLEWIbm6Rm9wgYafXIXugOqGl4lUc2NSeeJ5T_-ziLEX9-Z6LZafWo9PMvxbxpm86-e5ZqTBlsbukWWIePrKZ6BjElMcxTOUr2XYg-vMAc7QRx11Ld11DwesN_Xj62Kc0TUQRfREPp2AF0gAlYYKLvl7XKwU12Rg6UlWBfJWjX-hUvPY83B7H1saGyAv6V4RR9PODI0p8duptI4mC6u3cYPUk8pOVwFvX1PYCTM3I2yik_XG5ZyI6BIGBNAGL5SoAyMfpqYu0Da4duOIve6tQ3FWkMYnU9sSjxvS00mRJ3JscA-pNm2B_dUXBRATIAD6XVg1m19-pV6OLG58tuDtbjE7nBHUHuS2sm2gbm4PFjpGKFMS07LUSfYax19Ombld0hV_0kwaIjl-4UTcRcqqLK-Tc2E3NPwmdJuzb95-lUoAJG9Jp8UCoyXQRcZk33IGXMYtNquee5K-Oc-ajKjbbevpi6rIEOVjwKrZYwTC5ddl8FBcCBTm0NunKUzo9TkDeEIF6kce9zYdKo9GwYc8Go2S9lxbb6tlizDql2Uv_ZiTz0d5RUvShsMH6RzKiXu8eFzv5sUraMbLUtm3VtZsz9Ld0iztNIqV7q6glrqD2UuLgWxKsa7EbDRvrlBnAOP1iMRtg6ICr2YHYtlwU6R5RzKllG4LGMccZ3x6HsZL6MMaMJc8rLMTtQYqE067kCnXAIBz_-FJS0CzwCwnbh70tc-ytaiTm404Jp3CIBTlGwDwTvXUqzzNAdFRHrilKUPNgtKb6uQAyPhJZwbFIfrFevaMdOGZ9UhJoKtQtsSj1qM-dhXIkn4T_SL0o72wgb08zYSjsemhfJdbNO6jPG_GfWV6FDAhY9vNyTT8XlqgsePnALnV60AIvRZPI7mfh8D7F8SI0yZU4AJVtEHKKgStPvCuixxtjTt9nSWm-cXOItJdKYxMjVtWCmcCI9LbPolXXkewgNhmUx-b0XlY_BN9cX2j0COic5Ml6LS0BZ6ikG65a-7kIl_yofLeat8q9-4OI-lhKYOxwMhQq8yWNCBuJZCGg5n3DM_QgEQt7cqWYuTuTMTgMnRIvSefK_Q-ZSY-ZfzPcNp13-v56KgA_yUqYOHvQDu4ZuZCI3KvlO1WSO17SiqiNZvo3iaM2BrrgzOAJYcSx4TUzl7ZuFE_6LkokGlxguZH82W9dpewDyN83yLLwakOhgLfbTlMCFs8NCLzMr17eBFNX8YqP9bh88f98KtLSYr09naEesCwW3v-M-I1MUdR7oEC64ixrAWEwpSI-Jcc60oUgvLBVbwkeoQWI29NqZCS2JYGsxjXfNmhWWB3kW7_7ik5RHk3oNRWXiEQ_N_K7c97Ui1YkomyAAZv4t3zQYHwsLBmnf2DCEMBViQn2nXXjGwBxEf9KY2dlT1ihIbcPBmyzI17UrKYXvYKkfE25c_R0VjQtRSiXrlEWkBgLwRzWt18_62P00dJRAeJOEq6etGKoSh0PsrmtCGfnOf1EJhksjZPyObdHWm_yrNiX-h3myewuYT4BIanBFdUQxQvpNyvoQJIMtKH3gAh9oCJY8os-vS1Mx7h4Zh0gEdQZhIVn7KoJwqbx09F8hGokOaVXx6H9gMD5kVZkXkX56AFC78ykpMLSsolvyUhAI_qxcpTVGSgDIzfK7BzQsMd4TawOtHObxfvVr9qojhx__eQEipXplbfOVh8vjM8TFY7eb8k5EvxaU_pBuEmSagGoV0fiPUmMTzipVTMQ-cpaF6xQSVYZK3CvmUwxHfcX2r8lPPH_SyeiVFKRdqTmpIGYw8drhwc9GFgFM_N1O_iJuhjSt-8iLt9BExKYJZftIcXPYl4eGgC1yC6oUBurdmvQUOZD2tv_isd28fMNeoiWAy7HCDz57TAkJg9nJsfULk_z5ClBqz7rPP9Qq9CZrYEsz6Lggj19AXh6PmA9Skl9nUSgsqn2GvDI3I5E8YmxhlP58XrZyYKLkYLqqAMDy4tqI2eiQMe4z1OhMGpVxoEt7ACxw8-YaQTKgItzSNNskrXkRsGvWa2m9XcaZNwbZFeqek7OZ0vxLMsQJ3InnvY1lj9aMUUGukolxZEZ0KolEPOsIKhwH4iMg79yNlxeqdM2e-OoxrUyIBvBqC5uNemtqnulwarV_0K4XYtimpR2ONcwjzSO-eY9untVEmJRdw-OYEJiKJoRRNEjmr77UuJLDhPqjtxmcF2LHRTbpQ8b73Vp-mt-1okyP2yOr8Rd6LbsJuntv77VWE6Mt2JBzJpwJZab3mKd-2c6VkTswJX8p8Lf3g6m3uPwBRrvyCuuxztoxG2rDrh-3krcjDFnwU5tZjpZ3G3pq6KXbcmsX3kvJhJc6er38kO6uR9SkJUcRkbQPZ5nUKCtRZ3AkFukiT_YHtUamsUlA0nX5DI0CcrrNtu71HD7jSkwF9-P_QNX3_c9k31cSfHQ8BCMHcy7DO0vPYuzj2BiStEdTymAXfMeTFVO3wUvQf9KyuqVnKFMtFwP2DaospAJCd4TaHeDCm-uczeg1of-R2SB0f5XorCQ5MljHFk1VTHmWG3LHgCTEmAtx2KKbdMO8zXsBop6LAnFj3dNEBv1grO5lMCZRqKRo-csAJKwqXn9kuIa6GXi-NMZWBGLvxWhJpWdCeGnaFjCk-7uzPQ7PN_JhtPjeI3W-9A5bY8RvzYLrKKIEOEMGyHb-77dcYPhhLgn10-HpglS0_uJw5f0STZE60rxVXH-sb7vrpyAyBqMUh-OdoGAqR4r9dflKk-jECG0sggRuzx8jLGGfO-dNZSznD8JbaCsRDdLuHWiFSZKJswXwX5PS9rmVpYRrH-0QniMhPiMOuINwp9GvTtzSvXNIPBWtNMsY_jN_O2gIKxL-KnyoQkyUFWHN0Anuyv5pCHQk1lhfcR0alSvDLVmVVgi1tQdjsdAl19qMdfm43ViBTRLDwzP8iauhipIfCpxFjak0Ka8uFaHfEhKstcmUdxEnzIsN3SQXrPud-p0YJ3O1MsyUDjzMROP43FKMhVCSnM5PsXVvuPZKRmuEFbJyj0dwwBnSH-rk8tuK5SYoX8PIrJXyAySgj2VouGdzvkqa9WPSHU42AxDZNQT2c5pEI3gUS7VzcGCTwoznmFtmHKGOJj8HxKswzB2z0AumI_ht8zx6kehnvKK4cJfKjdJfO--2o_gzVR0DkA1HcenMD4ugxj6rWQDiJvo6cFdfkXpMfLAe4NQRLVLNv4UdIehCxCHMsF1RZJf93Z6sdxW_2PumLLcfdb2XIkouuFN0mECzZlWgM4XLUErlaaqDc8oU_gRrgHEJbjZqF7by2nHtqCjyWOZC9n7vF18iSRJES5DX71nY84a8ydPR2_KEYfHHgqF51Nz9zMo2Gv6ramAFs6lZC5rjOUR1VmpLd2pKs-sPQJpYNncwbDe8dG_NDJI1wIgs2K42eKPE4lEueCtp359ifPU58DpJA0JiB_FW3jBBh_9MphsnQjuso9S-YSaSFt4Llc_Zf0MJ3CbiEsk-IwfgsLysFQg-vJq9hHR48ZoW0kx7CaIAUgkiJg7-7m_dVNsfaUM-OSHtfryYXWrUsotLJ6OTuicPOfb_LfaYz5OoasG0o-4vdtF8e4VX6ZpR_Krje-dZaCph1XjgGLfFlRRkywl7i8IEUirHpQJaoCPmc9q61hjETcuPCEVDy-dJMwPLiNzXY1mkJI1lQQ1LL8Ke5EgtAcC-2K_5Nwh4h4bafWA44XgnisMfYDv66CzsL35i0XtZHibfLqPwdLyHqInlLPtiFyhJZifcJ_GsiQ0U4SZO3WHmvSG9AHy0YnA2jC3O4x7yj73RmroELKFvT-_CSO5LVz3qRRVdlyL0CQr3lkHUXJbFNpOz7Uek4q6MjB8Cn0xAKzt9ztcClLdAA9NkR88Dy3rOP5yPjRJJVVG6SbelsE1SnPDaKQqu2ZN1zdtGUY9AcULc2dGFb4mezcbJsC_eL3DD0LwfwcSAILDfDIrqHACR0XmI7jmF_p_PzmBhMsocLnblzKTho5ufo4htqhTEjVdFywm9WIjw1N_9PWge3i3J8mSdILp0HQ1QvbRlMt13qPyLNwAmY75m4Zw7EIlk4cyxMjcTSY02TRCC3cBKX2e6xl0DIAygChReVOxL16BT21sEgT2ps24Mljsvht-fokU3JPtj3fY8wojksHAWNv2hlF62xKrOv9h9AqM_Q9JlghHHNTrzxvT8SVeLBhEvysbhErrgtTPcgvKfMUCT1JMWolxLZUSFEFKNR9cl2GiSqMIhdTL3JvA0-etZ7ykeIbUEU0jlRZAw4a3vY1R1zW1-c6XRSNiS9VDPAfcN2OD4bXL8Hi2Un7Vc_pRyWn32kWQqQuw7v6J4RB-sr3Bkb4OzUljytF3ixqGkMIpuA-LjJwdBJ-XgR8Fj_DONbguNct7MTkMtQqWU9twa8XF_sot8iEYc1UOkZQVJvTtNclIkklJhP8VNj1aY18Y1Gtnn0fvfaOFfY4wa7HIq0U7paT2Fqb0xtY62bqNM6rRXLsAQex5HvMvHQvL_9JbQngBOD2ehk7zIAJKZWzbAKqKCgH-_v4kaGBVrciIxffYF6WnWq35pQwbsvNqQG4uJR0qhLEXfc5akEon1sL2fjxim_GFcgunyCqL28lMB8yhnzA48QESW0sotVss_GIeeftSYS74zPaHXiuSx0RoAmw90kERXPDGVCRkwTTwaW2BkshCJCx2JOSDEWVRMjxngzaoroybl9A1VzTrDEbodeq2O_kVyZfrZE58BO8DDd6ZH07m4zuiL_NKXLw23NmC4CuAN0ufn7HFtX_ow4ZJILfZI9PczBi16liV0LWrBwvadZ2Lf4o3sV65CLg1VKujttEiOhtpYjmB9zIRLfAHViz5vgTonL6H_9N4D2dXLzUWlaDPNGJNnt7EbHS64f3jSXGG1fb7LGKhNtTHqbfBJnMpmPjFQGb4ae2kKv_V_L8xgXNpQRi5I_QNTzDzfBs4avowydppTpEE1b8WNITLc7qvMa6gwpDxp2N91fIVC9wyd0k2DXaz3VbDn-2v7W72D2UPa0L00NKvIKYecd9FMpYmkEyxJfFFr7b9hKA1ZXdqlejjPJPjVYC9XTEZLEwzdeoG6yrxtYMrl7o72M37uIRNZAj1Jf0B8s0qhPaaBfUVKtKl7bd2Ub2503LZ7ZvJ_1segaIT4S8nt17hjfep3re_4rEKA2rrxMbWoLhM4qkAPZvdjyAFF1YNB7u-Uex7l4STRYSpzl4eQIMSl7N0pGlKk58Z1FxTKHsAZTkZYtj40lptma1AfcwRPViNPceCFA36XfVjaratWPYgDhcjK8nNnAhxvL7t25nPbCXazPK1D16ZkY2SwcX7sMx8QklNQdzukZwGyP51yhU8o0PT-u3xGDaXnP6Wh_o35cCIRnar6Id9h2ovViZXJRUzNa8aXedxiFp7hLScSQfIPrPBcqN45EvLjEmtLvzzxNgHY7zw6gzj5QFgv64u2fI9zAY00B9U37bHIZPQnFAhge0466vyXNENzYO3acUGo5HhyFDlcuiBCbIZ413bmfbtRbj5W1FZMY58l1plTmNljfcwQ7Kd0PUGvGEb_jwKlmyKni1HzyyUmElGHdRkyS5Yk7aja6AJOk6z12WUM5snqG-uRVkByxCXQ2KaFR6Qm-IOHMFqzrPINkjyEJgG6KyKfkF5ScVfQaThHBuMrb7ETWMnlk0L28ZszB-TLt3HfaxINsoD5pndSSqBpHB1z_2kEweik3y_PdxIchV3CyBLnmrlqBPBIarCoM8VwzForh3RzQmgNsOGkJXy3Lk0rIr3t-BE7qgXWsrDolobtH6MMFO96Taa6MYIYYYbYvzQYcDuQwD21yGTLwKAnynBDn99bGYEg65LomsJbTSKCYQRcj2Rh2AaScsq8JiHYJEGAnRkgsXNivZnioTlkI9_5XqXBJt3GKMY37YL6qIU3XJ7HapKELorbX4fH_JlOIZLIOIaU80295GZcFdx1I2La9lp_UvAtALEDJklGNvbcDG51NNn2mj_P85vIfzsVdrfX7N_AftR8t1kQx7bdbVLyP4ls_qKnXXigfNJajWtPVgwGeroQq2jtaQw6Tj2Wsi3Itmo5QNg3N_ja3erlEHEdTo8lm4XZHjbl2bAH3n_wuEdYKTt2B3jhj4ddhO8atc1fryqbRfn61YFKUnR3f5vQ1qUq79uisQi0cvHr6DQ_12FpKzFvFckAkQmbk5fcS5Ri5S4L_JtFAexj8n2f_oYuG_9CYYplOU5i1Q84MyXUZ2fZyDhRPRiyjvPJ07_IAiL2ny1btmIFtVPeQSHVwfun-m5Lba3KgnZIJ6CRFqxR-o6F8e5K78d-bAotgA5vOcfeC_fBQfaom-EX0mJyzf7_Wjgam4IA_W3PO_wGoVULHfr7mwUw2Qc-VzITtjajZvRoT-SkVREyJVnKBxHFj2cNTcTtooSxCu115KmbtePf2OwgJocB2jyPT2GK-kIVZtuGdv4Dns8m7Z7FpT7PvjCVjidQqVsJxFQUs7ZzcTXX4vdChdcVK1_OiUwCJKiYN9ZKGA_OmwQJjhnV6gutHFYanu3Gm0m5PQLIM6Pip7yXCw8-Lhq0sxFTl2f-7DeYlfrWpYJyc2wR3T2u-kHl1g52CxX5XoHCV1LsBIU75L23Igsx5_v9ZNeewK2Qh8yWwlWZ18qnXOh5ZJqJUpYtxy3sUhHMG8fe5RKVGbbJyHltosuW26yJ9eUQXqJOSj4wv0YN6a-BezPdkkCqdiUGDHllrgAi96kkeM4jES6iZV60rTgdmfOS03JL0eqCwLnH0gP9t5Xq7l0-GUKp7mrsUjgN4Utb89AVPyIDFWxfJTuFJK-g6Z1EHexEvDY4iTsuOdq9M49_zV6iL8ChB4p5l0lUOiFzIH1Qj-gNMqpU2p0H73cMd3MNeecFhMsCfRadVCO8D4UN39W2mEXDxLBlTN2f4m6aDKjLHi58zyDiJ4aga_ntZRnv56KJpWob0A-4U6_GRJI3OynwKPfb0wpAzK8Gm6Ak1OpxvD-8TmbKUKVA5m55PMoBgGbmvtrwC9Q9Exg-zdotpZ5-iWM1ssnKLXobFa2SmYJeOcGbEjh_yvRvjBRNHxWmq_sP1ohPCTce4Pt97WVQs0Kc_Peb85RqZEnCyjRfV4C3nFUkTxJhFJbmIBPG-VPJDfKEMVTtUe7xB_w55BKViE87CTrd9AAveBFKkBrL3x4bVba3SK5HLU3tOgUPMDnN6Q-waVbjTXsNPGPwJjvbDAN-xwm1V19e-gYcI9sExy4hH9fCkx7Y93e3EMo_EvPA8ZFO8C-KKKlKttqg66BlOp_WYj4GnTpurNDHjVtBQZI6FN5HGl72n7ZL0me0cbfiDkFh7mIfHJCc3EcRCp__gjeBYQaGaR3hh7hLrNeuJB_oAfW5mz-2mIgUYz7vGxRrTeo9CyNYjr5CNwd-hp06pklYw1Bmce-1ZqG87pwFGjfWaAABwqNElf9Wdhgzll31WmopAxDC12Q8pzpAiFfkWWeHsPgvx_Hfm6B50TiIn_LCi8hjTaVUkvtNxZgiKJdAdL5btiUvPwVD10EkysT4dfAEg6l9Z64sZT6oss0KlH55VrNoLOybfx9-TGJZOCB5Zf7JU0KuA1Dpfp8I8TlCOUBwybFvNbECafzsrKB8XI6cmvDtsG0NqNzifoYUPzZDv4eNQhb4QAxlWx_xjiD_G33rgZ27DfvecgVkhDUc317uWUTrWt0f4WJItv4A8P4fj2CDa4cAjfe9CCWM8oehppoxScG5nBFdeebs1m3efdBi0VlYbJTEFQC92q0Zdr7kdfo0FbR1GQ05x66u5b0qLRqqsgF6n72p8Vo_izkLs1N3HKOz9AvcoTmD_tD70rZC6SVJ0jQcKtOMre7VK7lJQJwkuuUL-TRcVYVFeKln1CDs0zpqwza1iCVw3LcUdh96iPsN3XcHrH9pqUxSEY_T6Bq8aSTHdf-iqucTB2u2zsq5BgU40_zXUqvfvQRhcHbaNl0NkdbWKVr8AA3KkoGHMe-H_FBRmyBFX2KL7F4naGngOz7crLfNoSqvPF6cBudn3Q_PPxutj_F5d3FxcfHSHizhfZ3sC39DiwyKgWMU4rUm4gsyYpnKQ90aXtF9nuLWDyNZEb1hsHiVyIoNkUx4IznUY94rrMNzlobnMyqtaic819_vgKqTo9jYA-i5JgMoTPy2DTtIZIpU_p-TggdpEActJ7qncHdQjM0mCrZGYo78NvZ0697fexOgo-dQjfUmNNKNtLp1UQiMBllHwIDZzRePAgOeisXx-E10lLdPUm6AKQcg6IYbvrPDil1_EaQyV3JXqEgNCZwXvkDIh2cnaBLUzyWsep_iupiypilShz_QWLsa467qw5dJ_Q0vR1ulAzMWokaCmTTiJQ6RL71J4WBiGAnobFDrluwJtRr4BTRNDmzDBh8_G3EKTS5mr6W1EQnFnMAqIrW_TOvKasBlQqlLVcFDlllp7X2akyW6Z23NBe7JCnYi4m1HkM0_gnHqnFbnT3cS4umAd22ugbPbo8gn0KRoFxAZK4_4JPHbz_T2itrnDcl4z6_50F-I0Ynp9nHSKnlG5x5V6IGd47vfF7sIks8Vfpq8LUKgQu2g9XHzwf-q_jmwH-eokmnUlznsJnZWnz_GnHyeEMsdQbBKDGK9rjNuMC_QZGuiaARSlSvP7hMyowcczvtuKrN7sZc5nTWPD31UV-TBzrDnzmmsKZ_3BdPebNj71vt31hatE4Mc6OJJUZ-HPPUieICZJFiYXltJBqApmSrscPjDUy9fUoD0iJudrtDu6UJ31SFMkaapXqHG2FqMOwkEk_T5wGmdZ3Y6I8QKKiI4bXRcjPexjVQUJdHnGLRZ4L7tyKU1mFJHMEIMwAer1LiYsnFLHBt3XoAQbNu7LewtB3Cd1Qzeo16USsORAgO8DYtAiu9T0yfTOMAn6lfMgEIdqdJdY5KiPC2TWro08m4pn3mhDlfIWB4XzyBsaO8JiRlF_7Dfg0UpDEnk2AN7ACqsjeUoMk5478ov9JeTPOnCDw2W3x4-w3VhTndvrAD3OrnDoxsc7OcoQjni96fsh-E72g_FKaHJVqH591bROjD5nAPTj5rseGJYDTJkAlHauG67pXgIpMLSLgTUUeplBgjDDTWPdww6dYp8yW9CJNOXCrqmAunZDJe5d0n2BmzGLiOHxiDLKT4-7XoycRXq9adUn2uWgHUooKJbs4BI9sF_28FhxsbN5E2KT4b51aZsK91802OXcSbLCF1K-HqxFNeELpvrlnYT4Cefr_gQydbzRvzSdpTSpUTLtCspJ8RZzJZzQT6x6DnOT8KVt95Sx2OsaE6zCOEBUf5EX85M3Xw630kFQPAjAXx85FxEos_Fl5NtgSssugztP0Q6dbXJTuQrsSgSb6TWsJWaC6agqNudU2lkI3lWpxcxjnYdlDisZE2CVtPXIbMc0fP81Oz9g-LybenNrYDUdIL_FvJ9FM2ZSAleLrEgMM6IyDUXBC8PXA7QP-DukpVBDGkt6GRaNqiqMFN6ceHu1IcTRy8RBucg2ahZqS9BgLlbj2xGANaeZKjzvNKBbtqawx-RkwsHludZ4I6WaLC6-fCnqE0GuK3kw8mbym6gAbfHouwbWarAdtesd3tjoa620dCNg9QwQ1Hzgs4Fd0pjsSgMFB7ahRSDy78GWbdPXZqPollN22uUgQ1zWEva_VxrPK2C05iQMPE4Cg5X8XQbxGH6GY7wuOnc23Pvh9qe6po8voXKaUAPVb3oUGgYx7lgsWZIW-2c861ip10CSjcfFm6AVrS5Iaf7m0OZvUvL52q2r5Py_LWxLbgf0ubrDXMtHbhEGXYmiRaHcmuOxoFUtaqCB6kr6970im-84hk-SiCoL_96yg6Bna4isurYJb2JQgGktUX_SjcB4TshvDDx-G4H-lUYId4AaqP1zNJ0ryUPOlQQXlKtc6s0tUfEZu5SagAE6h6iTUkCr4hJ9hLanj_mMSMJiCjBCFUYMeZ4LCxzQagyR5qWxq90n2HlHhmPy5eCj16DTBIL49ScuUqyN5x8fWt23H-B0VjTUdFEVk8FFaPsSFv0SddM9LEvrlUcA-RcMpyZ1a2ifF7N_HwvRlMslVSzW2BUZRibnB0xpeZlUbqy2CDkr10azuxJYajE6giMCnSHfiKM2EPMuFl5-sX6FiyfsTIA3CmcdoHvd83KNQbMuDRp_nDCAl6LNcj8CXPyenI56CAX5owOddnszaI3C7fEfW7MavfzLE4KlNBPYeFmQLL7w0Rw6uZfqjBKLFLNtXNDBnJW3GSWYKFB0QiAMjf_9_nfOU0w3cwgnfsdmUU0BG_9bXy-qvzYvnWs1eLfoCfruH7gt5Bvb4iGPr37EFMI8yv-df__xbRHgDxVtAd-A5kL8N8DR4U6eSsw5UH8--p3ZpLyrh9vklTf4LDr0xt62qvZjUKzcuMZjQpcBvDHmKRx55aZ8BEkKhIhsWlZJMsE5prZOz3pwT5_pAp1h9u7sw60NnWisoTdBM08hP-JD06OWB_OFPa3I0x1boTojwlzVpiVGUdNeMgpWKa9wQj6rVsEl3-UFIyrKNpgir2df5m5q9vxZ3TSKawBZUAQJnQp9aYgysMtCnUCNrZ-zaC6mojA6cBLk-g5rCcXsyd1WqkHrFwYoPAu5593tQA-ttSVSFCUQxCILqKUZx1-fw2NIchE-NUak3dAZ4RTWm6EwMGXh6rmanI2swBjkglVxw3CfmOAsL7yXEhm2tOofu5EoADa_lEdy8ihHgsCPoJiq4hxlwFXrg9y-Pww0xsrldPuFcc6AAIpPR9UrKHoEdxoDnANqi6zsBTsp-VdyaNj5nFWgpm5mxgnuWUrBGif-U5ldingoapB0hJ50--CucJyHaLHHV2m7WcVDTXiykeHhjIp8qnKBaXwoyezqmLgzIOmhrJgqBH-drr_Usl2Mtzq5lyA2if9MFtKcktldky2GXDiMlwLWSf70Jj5d2Tq8_4P0C-StEZ66V_PkVarTSrFahni4g1OqUJbxxsK7oV932wEtpHJPo6MYnkebOFGlGQlxxk6OlqoZwyP6xbJCwu1_36FuIYcl09Vy11EXK58g62eDyg9eGaAAe1mU4fTByEowy94v67qTC9otmjGlB6K3pyqsGnpWEGz5FujtRPO_ChDNN84qZRMSk5QMU3jx1t3-_0Mg48WnuWGiDDveAhZVxNz9HThbvMviECVk2E70W0nj9XEybPhNLcKQxKMekE6_3qJxUTk8Q7KJpoDysmWznz0Brg-GT6NSJG0pFFfgdNCAK_K5G9SkdnS7Pr2S7DcDIasmdvIciCzw0Lv7Z2rZR8eiica4lrrz52lwO-rD2380r-UgaLsbX5PhZDc57JSkIKnAfS5qeqxK9koKyD4UyR-6gfA2SsoRbxayLigQOk4O6bIDoJ0ECvEoyaJTohselYUhhQDuwaYQ3UVBsxyNzFxXv4i_ldHItOjckkNBLTyz0rfh0bAbqP5ROsXG7Q9OIMglRSRyDjZdlMaRVO1-lXy_zQ8AoBxuAwGOyc2CQm4zvxMjmiAyMymBdZS5w3-aa6ILoaqvhMzYTEyP8pojxTER7-swPs4J_zroRVV-USiheF9qLRr8C7WtZnzaJXYhAap3HrTtfCVMAy8bHYFjk5zYLmVYw09C04sFxQ3apXWUc6A-30D_Ix_x-Nh0LmnhBXc-BiCPdaGA-iqaCScX94nyMmCC5-26KpbcKZL9qH6ZFUez72d2gmu0oX59AgiJkLaVqmWkC2fKMc-GxO7SI-tzO8AGmi2G5vVeYHIwc2zfRhHuNn8znS7SSRKD1uzTLvJzt0Bonu6NLukVUamhLf5SYmHR3Rd9Qb6NNprHYCyJkim-szlYjso9-EhfRqt3TZtuNx7zbXIoJJ_anSIBQKXrWpLJHr4CMexa0xlnVrB_K6-RPVBfKMZWdcRc2cltFzo-w1VvqOzmK_-B_9FkVhCdObJ-aak26s2CjdzF4SmyetdbUt1U6zDx3lb2InlGz544dNY6OjjQX0X0ImPVTlFAFWFO4ONwnUp5GQmqBjYQZ7CYKqx7RZexDqbmGsW33jnf17hPsToLphEo8M6_p9-I4-PSity9OSX3Gw35Lon-myQxV9Nq_Ui9Mtql08C_Uyhdqwk2FH8wESENlRPoM8Dq044Yj0gHqwUj4xqUht8j9Hk-au6fYM_fLPRyXv9jqjT_KklnmfaeAqZOb4hHRIFBxXA9Q-1rreVfYFWVMz-FRiyf3cWd7QQdMciuMBulWeJjgOUoZK3vQIS5f4AZzwYkNOt6F96hwRtdI8bU6tKJU2afAeqNQ6xiSa85tx8_YGzMsrdKdWAPQIKe66QmQLlQP04k_EoSLH_f9dc51NZYfGF8YwzJuvclpqtAeMNguhPuGj-7V5wFMYhni7osiiPQ==', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de', - signature='gAAAAABoxCzZ6TwL-z6tYv85YPC9CwMFJRrSrWgYUyOhSFYLkdfGwRUIbrgBnmAW0qtzE-shPNPNfbUltLnBS4uU8kMuSMPxotFngVcFFnZ8qmzDUJiEf2CsnqYqH5d2RmuvIXUQTau20SjGte8vOLksGsz0sXRUQnFs7ZoT_2DSy7tKVCCN7fbvkxm2l9D-IibdvGiflbP6lGGgYWczEl3_QyEyJGhDTcL_nUk511C2hjvqI6YkEjujvYjEGMh-BdhFrJeLFL2wCbn6beWaDB2IXYVo7LqhlQUtKksY2PQ4ybBgPhERNvWWf2N-K4NxEQuv6vdB_5ni_BlUKFMabeeeI4wVr5M3HKE6cSgnM8cpi93o_rGu9uSh5fbN5zZcIYumnjkGJ-ULwku7TVtpw_Vha8bJl67qCLvRe90MaCCgJxFKp-IsxakpnNCXVrAlN70cIchPEjOWW3VKrGZ-omyQLgs3EzddhaPmSqDELbmYkxCUuRYdLvZPzhI5VvNiW_j-WGBKEMJLFz0k33oPbH3Q6Fn9HcJSruSsQ8Lc-QWQsibGoABEY_auM7LDLjbvpEYcdsP5BJOBUS8wpyOD7N5jEQL2PYPT3tsP6mvWy7csRIkwEbh1x1sXp6NL3skS6QwpqNiWalP4OQvs8jDi8Gz-NrtNvmX3RR4A0MIuX4q0Tb1VI9PilRUvOvg9hF-fk3bqIh7wW7_iD2eDoXjvI99M-UZ2QZGZlPa1O039QVGLBTi-KwrLuhh-D5q3N-3-DyXY0sjsdFzM5Qf__lVaxtRhZRKyxSONZsTt8mGatlOH4Q-MIPgCXsrLu25gWn6Jr6vt_iQ1eZG30cox98F4aU11Hp-o4tFKuHL8Kbgl9Eetpd4ggfJrTe9QxQfWfgCHAKnhjVRJOepHPEFzSRFKiHrOgATIw_x5xNRacsF_tO1WkpeBdBJhpAUozarHgPQi2A71LCcmd5Zzy7FAL6R_5QtHW-H7NE2PjqqXnf2ZMiMM-oYLHKhfu8tZu9EV7V21xKkovIGH-0OQ-lk44ww8-j3rBNXjWIwp8SO73O85PP7vzE_zJJCF8riB_rOpazJpMCaDP_HUOZq5XhcfHseiS1SownunaXj2wOmgLJ103BowC18-i83n8RVTtRQxLsiCRzMwRH3eEbEClqZ1Fqt4V6NKqICKK3kF3_R_oPtX_-7xYBpl8LGR2Ei_2hXkEIuQ8cCRz1zmuyfjLEWIbm6Rm9wgYafXIXugOqGl4lUc2NSeeJ5T_-ziLEX9-Z6LZafWo9PMvxbxpm86-e5ZqTBlsbukWWIePrKZ6BjElMcxTOUr2XYg-vMAc7QRx11Ld11DwesN_Xj62Kc0TUQRfREPp2AF0gAlYYKLvl7XKwU12Rg6UlWBfJWjX-hUvPY83B7H1saGyAv6V4RR9PODI0p8duptI4mC6u3cYPUk8pOVwFvX1PYCTM3I2yik_XG5ZyI6BIGBNAGL5SoAyMfpqYu0Da4duOIve6tQ3FWkMYnU9sSjxvS00mRJ3JscA-pNm2B_dUXBRATIAD6XVg1m19-pV6OLG58tuDtbjE7nBHUHuS2sm2gbm4PFjpGKFMS07LUSfYax19Ombld0hV_0kwaIjl-4UTcRcqqLK-Tc2E3NPwmdJuzb95-lUoAJG9Jp8UCoyXQRcZk33IGXMYtNquee5K-Oc-ajKjbbevpi6rIEOVjwKrZYwTC5ddl8FBcCBTm0NunKUzo9TkDeEIF6kce9zYdKo9GwYc8Go2S9lxbb6tlizDql2Uv_ZiTz0d5RUvShsMH6RzKiXu8eFzv5sUraMbLUtm3VtZsz9Ld0iztNIqV7q6glrqD2UuLgWxKsa7EbDRvrlBnAOP1iMRtg6ICr2YHYtlwU6R5RzKllG4LGMccZ3x6HsZL6MMaMJc8rLMTtQYqE067kCnXAIBz_-FJS0CzwCwnbh70tc-ytaiTm404Jp3CIBTlGwDwTvXUqzzNAdFRHrilKUPNgtKb6uQAyPhJZwbFIfrFevaMdOGZ9UhJoKtQtsSj1qM-dhXIkn4T_SL0o72wgb08zYSjsemhfJdbNO6jPG_GfWV6FDAhY9vNyTT8XlqgsePnALnV60AIvRZPI7mfh8D7F8SI0yZU4AJVtEHKKgStPvCuixxtjTt9nSWm-cXOItJdKYxMjVtWCmcCI9LbPolXXkewgNhmUx-b0XlY_BN9cX2j0COic5Ml6LS0BZ6ikG65a-7kIl_yofLeat8q9-4OI-lhKYOxwMhQq8yWNCBuJZCGg5n3DM_QgEQt7cqWYuTuTMTgMnRIvSefK_Q-ZSY-ZfzPcNp13-v56KgA_yUqYOHvQDu4ZuZCI3KvlO1WSO17SiqiNZvo3iaM2BrrgzOAJYcSx4TUzl7ZuFE_6LkokGlxguZH82W9dpewDyN83yLLwakOhgLfbTlMCFs8NCLzMr17eBFNX8YqP9bh88f98KtLSYr09naEesCwW3v-M-I1MUdR7oEC64ixrAWEwpSI-Jcc60oUgvLBVbwkeoQWI29NqZCS2JYGsxjXfNmhWWB3kW7_7ik5RHk3oNRWXiEQ_N_K7c97Ui1YkomyAAZv4t3zQYHwsLBmnf2DCEMBViQn2nXXjGwBxEf9KY2dlT1ihIbcPBmyzI17UrKYXvYKkfE25c_R0VjQtRSiXrlEWkBgLwRzWt18_62P00dJRAeJOEq6etGKoSh0PsrmtCGfnOf1EJhksjZPyObdHWm_yrNiX-h3myewuYT4BIanBFdUQxQvpNyvoQJIMtKH3gAh9oCJY8os-vS1Mx7h4Zh0gEdQZhIVn7KoJwqbx09F8hGokOaVXx6H9gMD5kVZkXkX56AFC78ykpMLSsolvyUhAI_qxcpTVGSgDIzfK7BzQsMd4TawOtHObxfvVr9qojhx__eQEipXplbfOVh8vjM8TFY7eb8k5EvxaU_pBuEmSagGoV0fiPUmMTzipVTMQ-cpaF6xQSVYZK3CvmUwxHfcX2r8lPPH_SyeiVFKRdqTmpIGYw8drhwc9GFgFM_N1O_iJuhjSt-8iLt9BExKYJZftIcXPYl4eGgC1yC6oUBurdmvQUOZD2tv_isd28fMNeoiWAy7HCDz57TAkJg9nJsfULk_z5ClBqz7rPP9Qq9CZrYEsz6Lggj19AXh6PmA9Skl9nUSgsqn2GvDI3I5E8YmxhlP58XrZyYKLkYLqqAMDy4tqI2eiQMe4z1OhMGpVxoEt7ACxw8-YaQTKgItzSNNskrXkRsGvWa2m9XcaZNwbZFeqek7OZ0vxLMsQJ3InnvY1lj9aMUUGukolxZEZ0KolEPOsIKhwH4iMg79yNlxeqdM2e-OoxrUyIBvBqC5uNemtqnulwarV_0K4XYtimpR2ONcwjzSO-eY9untVEmJRdw-OYEJiKJoRRNEjmr77UuJLDhPqjtxmcF2LHRTbpQ8b73Vp-mt-1okyP2yOr8Rd6LbsJuntv77VWE6Mt2JBzJpwJZab3mKd-2c6VkTswJX8p8Lf3g6m3uPwBRrvyCuuxztoxG2rDrh-3krcjDFnwU5tZjpZ3G3pq6KXbcmsX3kvJhJc6er38kO6uR9SkJUcRkbQPZ5nUKCtRZ3AkFukiT_YHtUamsUlA0nX5DI0CcrrNtu71HD7jSkwF9-P_QNX3_c9k31cSfHQ8BCMHcy7DO0vPYuzj2BiStEdTymAXfMeTFVO3wUvQf9KyuqVnKFMtFwP2DaospAJCd4TaHeDCm-uczeg1of-R2SB0f5XorCQ5MljHFk1VTHmWG3LHgCTEmAtx2KKbdMO8zXsBop6LAnFj3dNEBv1grO5lMCZRqKRo-csAJKwqXn9kuIa6GXi-NMZWBGLvxWhJpWdCeGnaFjCk-7uzPQ7PN_JhtPjeI3W-9A5bY8RvzYLrKKIEOEMGyHb-77dcYPhhLgn10-HpglS0_uJw5f0STZE60rxVXH-sb7vrpyAyBqMUh-OdoGAqR4r9dflKk-jECG0sggRuzx8jLGGfO-dNZSznD8JbaCsRDdLuHWiFSZKJswXwX5PS9rmVpYRrH-0QniMhPiMOuINwp9GvTtzSvXNIPBWtNMsY_jN_O2gIKxL-KnyoQkyUFWHN0Anuyv5pCHQk1lhfcR0alSvDLVmVVgi1tQdjsdAl19qMdfm43ViBTRLDwzP8iauhipIfCpxFjak0Ka8uFaHfEhKstcmUdxEnzIsN3SQXrPud-p0YJ3O1MsyUDjzMROP43FKMhVCSnM5PsXVvuPZKRmuEFbJyj0dwwBnSH-rk8tuK5SYoX8PIrJXyAySgj2VouGdzvkqa9WPSHU42AxDZNQT2c5pEI3gUS7VzcGCTwoznmFtmHKGOJj8HxKswzB2z0AumI_ht8zx6kehnvKK4cJfKjdJfO--2o_gzVR0DkA1HcenMD4ugxj6rWQDiJvo6cFdfkXpMfLAe4NQRLVLNv4UdIehCxCHMsF1RZJf93Z6sdxW_2PumLLcfdb2XIkouuFN0mECzZlWgM4XLUErlaaqDc8oU_gRrgHEJbjZqF7by2nHtqCjyWOZC9n7vF18iSRJES5DX71nY84a8ydPR2_KEYfHHgqF51Nz9zMo2Gv6ramAFs6lZC5rjOUR1VmpLd2pKs-sPQJpYNncwbDe8dG_NDJI1wIgs2K42eKPE4lEueCtp359ifPU58DpJA0JiB_FW3jBBh_9MphsnQjuso9S-YSaSFt4Llc_Zf0MJ3CbiEsk-IwfgsLysFQg-vJq9hHR48ZoW0kx7CaIAUgkiJg7-7m_dVNsfaUM-OSHtfryYXWrUsotLJ6OTuicPOfb_LfaYz5OoasG0o-4vdtF8e4VX6ZpR_Krje-dZaCph1XjgGLfFlRRkywl7i8IEUirHpQJaoCPmc9q61hjETcuPCEVDy-dJMwPLiNzXY1mkJI1lQQ1LL8Ke5EgtAcC-2K_5Nwh4h4bafWA44XgnisMfYDv66CzsL35i0XtZHibfLqPwdLyHqInlLPtiFyhJZifcJ_GsiQ0U4SZO3WHmvSG9AHy0YnA2jC3O4x7yj73RmroELKFvT-_CSO5LVz3qRRVdlyL0CQr3lkHUXJbFNpOz7Uek4q6MjB8Cn0xAKzt9ztcClLdAA9NkR88Dy3rOP5yPjRJJVVG6SbelsE1SnPDaKQqu2ZN1zdtGUY9AcULc2dGFb4mezcbJsC_eL3DD0LwfwcSAILDfDIrqHACR0XmI7jmF_p_PzmBhMsocLnblzKTho5ufo4htqhTEjVdFywm9WIjw1N_9PWge3i3J8mSdILp0HQ1QvbRlMt13qPyLNwAmY75m4Zw7EIlk4cyxMjcTSY02TRCC3cBKX2e6xl0DIAygChReVOxL16BT21sEgT2ps24Mljsvht-fokU3JPtj3fY8wojksHAWNv2hlF62xKrOv9h9AqM_Q9JlghHHNTrzxvT8SVeLBhEvysbhErrgtTPcgvKfMUCT1JMWolxLZUSFEFKNR9cl2GiSqMIhdTL3JvA0-etZ7ykeIbUEU0jlRZAw4a3vY1R1zW1-c6XRSNiS9VDPAfcN2OD4bXL8Hi2Un7Vc_pRyWn32kWQqQuw7v6J4RB-sr3Bkb4OzUljytF3ixqGkMIpuA-LjJwdBJ-XgR8Fj_DONbguNct7MTkMtQqWU9twa8XF_sot8iEYc1UOkZQVJvTtNclIkklJhP8VNj1aY18Y1Gtnn0fvfaOFfY4wa7HIq0U7paT2Fqb0xtY62bqNM6rRXLsAQex5HvMvHQvL_9JbQngBOD2ehk7zIAJKZWzbAKqKCgH-_v4kaGBVrciIxffYF6WnWq35pQwbsvNqQG4uJR0qhLEXfc5akEon1sL2fjxim_GFcgunyCqL28lMB8yhnzA48QESW0sotVss_GIeeftSYS74zPaHXiuSx0RoAmw90kERXPDGVCRkwTTwaW2BkshCJCx2JOSDEWVRMjxngzaoroybl9A1VzTrDEbodeq2O_kVyZfrZE58BO8DDd6ZH07m4zuiL_NKXLw23NmC4CuAN0ufn7HFtX_ow4ZJILfZI9PczBi16liV0LWrBwvadZ2Lf4o3sV65CLg1VKujttEiOhtpYjmB9zIRLfAHViz5vgTonL6H_9N4D2dXLzUWlaDPNGJNnt7EbHS64f3jSXGG1fb7LGKhNtTHqbfBJnMpmPjFQGb4ae2kKv_V_L8xgXNpQRi5I_QNTzDzfBs4avowydppTpEE1b8WNITLc7qvMa6gwpDxp2N91fIVC9wyd0k2DXaz3VbDn-2v7W72D2UPa0L00NKvIKYecd9FMpYmkEyxJfFFr7b9hKA1ZXdqlejjPJPjVYC9XTEZLEwzdeoG6yrxtYMrl7o72M37uIRNZAj1Jf0B8s0qhPaaBfUVKtKl7bd2Ub2503LZ7ZvJ_1segaIT4S8nt17hjfep3re_4rEKA2rrxMbWoLhM4qkAPZvdjyAFF1YNB7u-Uex7l4STRYSpzl4eQIMSl7N0pGlKk58Z1FxTKHsAZTkZYtj40lptma1AfcwRPViNPceCFA36XfVjaratWPYgDhcjK8nNnAhxvL7t25nPbCXazPK1D16ZkY2SwcX7sMx8QklNQdzukZwGyP51yhU8o0PT-u3xGDaXnP6Wh_o35cCIRnar6Id9h2ovViZXJRUzNa8aXedxiFp7hLScSQfIPrPBcqN45EvLjEmtLvzzxNgHY7zw6gzj5QFgv64u2fI9zAY00B9U37bHIZPQnFAhge0466vyXNENzYO3acUGo5HhyFDlcuiBCbIZ413bmfbtRbj5W1FZMY58l1plTmNljfcwQ7Kd0PUGvGEb_jwKlmyKni1HzyyUmElGHdRkyS5Yk7aja6AJOk6z12WUM5snqG-uRVkByxCXQ2KaFR6Qm-IOHMFqzrPINkjyEJgG6KyKfkF5ScVfQaThHBuMrb7ETWMnlk0L28ZszB-TLt3HfaxINsoD5pndSSqBpHB1z_2kEweik3y_PdxIchV3CyBLnmrlqBPBIarCoM8VwzForh3RzQmgNsOGkJXy3Lk0rIr3t-BE7qgXWsrDolobtH6MMFO96Taa6MYIYYYbYvzQYcDuQwD21yGTLwKAnynBDn99bGYEg65LomsJbTSKCYQRcj2Rh2AaScsq8JiHYJEGAnRkgsXNivZnioTlkI9_5XqXBJt3GKMY37YL6qIU3XJ7HapKELorbX4fH_JlOIZLIOIaU80295GZcFdx1I2La9lp_UvAtALEDJklGNvbcDG51NNn2mj_P85vIfzsVdrfX7N_AftR8t1kQx7bdbVLyP4ls_qKnXXigfNJajWtPVgwGeroQq2jtaQw6Tj2Wsi3Itmo5QNg3N_ja3erlEHEdTo8lm4XZHjbl2bAH3n_wuEdYKTt2B3jhj4ddhO8atc1fryqbRfn61YFKUnR3f5vQ1qUq79uisQi0cvHr6DQ_12FpKzFvFckAkQmbk5fcS5Ri5S4L_JtFAexj8n2f_oYuG_9CYYplOU5i1Q84MyXUZ2fZyDhRPRiyjvPJ07_IAiL2ny1btmIFtVPeQSHVwfun-m5Lba3KgnZIJ6CRFqxR-o6F8e5K78d-bAotgA5vOcfeC_fBQfaom-EX0mJyzf7_Wjgam4IA_W3PO_wGoVULHfr7mwUw2Qc-VzITtjajZvRoT-SkVREyJVnKBxHFj2cNTcTtooSxCu115KmbtePf2OwgJocB2jyPT2GK-kIVZtuGdv4Dns8m7Z7FpT7PvjCVjidQqVsJxFQUs7ZzcTXX4vdChdcVK1_OiUwCJKiYN9ZKGA_OmwQJjhnV6gutHFYanu3Gm0m5PQLIM6Pip7yXCw8-Lhq0sxFTl2f-7DeYlfrWpYJyc2wR3T2u-kHl1g52CxX5XoHCV1LsBIU75L23Igsx5_v9ZNeewK2Qh8yWwlWZ18qnXOh5ZJqJUpYtxy3sUhHMG8fe5RKVGbbJyHltosuW26yJ9eUQXqJOSj4wv0YN6a-BezPdkkCqdiUGDHllrgAi96kkeM4jES6iZV60rTgdmfOS03JL0eqCwLnH0gP9t5Xq7l0-GUKp7mrsUjgN4Utb89AVPyIDFWxfJTuFJK-g6Z1EHexEvDY4iTsuOdq9M49_zV6iL8ChB4p5l0lUOiFzIH1Qj-gNMqpU2p0H73cMd3MNeecFhMsCfRadVCO8D4UN39W2mEXDxLBlTN2f4m6aDKjLHi58zyDiJ4aga_ntZRnv56KJpWob0A-4U6_GRJI3OynwKPfb0wpAzK8Gm6Ak1OpxvD-8TmbKUKVA5m55PMoBgGbmvtrwC9Q9Exg-zdotpZ5-iWM1ssnKLXobFa2SmYJeOcGbEjh_yvRvjBRNHxWmq_sP1ohPCTce4Pt97WVQs0Kc_Peb85RqZEnCyjRfV4C3nFUkTxJhFJbmIBPG-VPJDfKEMVTtUe7xB_w55BKViE87CTrd9AAveBFKkBrL3x4bVba3SK5HLU3tOgUPMDnN6Q-waVbjTXsNPGPwJjvbDAN-xwm1V19e-gYcI9sExy4hH9fCkx7Y93e3EMo_EvPA8ZFO8C-KKKlKttqg66BlOp_WYj4GnTpurNDHjVtBQZI6FN5HGl72n7ZL0me0cbfiDkFh7mIfHJCc3EcRCp__gjeBYQaGaR3hh7hLrNeuJB_oAfW5mz-2mIgUYz7vGxRrTeo9CyNYjr5CNwd-hp06pklYw1Bmce-1ZqG87pwFGjfWaAABwqNElf9Wdhgzll31WmopAxDC12Q8pzpAiFfkWWeHsPgvx_Hfm6B50TiIn_LCi8hjTaVUkvtNxZgiKJdAdL5btiUvPwVD10EkysT4dfAEg6l9Z64sZT6oss0KlH55VrNoLOybfx9-TGJZOCB5Zf7JU0KuA1Dpfp8I8TlCOUBwybFvNbECafzsrKB8XI6cmvDtsG0NqNzifoYUPzZDv4eNQhb4QAxlWx_xjiD_G33rgZ27DfvecgVkhDUc317uWUTrWt0f4WJItv4A8P4fj2CDa4cAjfe9CCWM8oehppoxScG5nBFdeebs1m3efdBi0VlYbJTEFQC92q0Zdr7kdfo0FbR1GQ05x66u5b0qLRqqsgF6n72p8Vo_izkLs1N3HKOz9AvcoTmD_tD70rZC6SVJ0jQcKtOMre7VK7lJQJwkuuUL-TRcVYVFeKln1CDs0zpqwza1iCVw3LcUdh96iPsN3XcHrH9pqUxSEY_T6Bq8aSTHdf-iqucTB2u2zsq5BgU40_zXUqvfvQRhcHbaNl0NkdbWKVr8AA3KkoGHMe-H_FBRmyBFX2KL7F4naGngOz7crLfNoSqvPF6cBudn3Q_PPxutj_F5d3FxcfHSHizhfZ3sC39DiwyKgWMU4rUm4gsyYpnKQ90aXtF9nuLWDyNZEb1hsHiVyIoNkUx4IznUY94rrMNzlobnMyqtaic819_vgKqTo9jYA-i5JgMoTPy2DTtIZIpU_p-TggdpEActJ7qncHdQjM0mCrZGYo78NvZ0697fexOgo-dQjfUmNNKNtLp1UQiMBllHwIDZzRePAgOeisXx-E10lLdPUm6AKQcg6IYbvrPDil1_EaQyV3JXqEgNCZwXvkDIh2cnaBLUzyWsep_iupiypilShz_QWLsa467qw5dJ_Q0vR1ulAzMWokaCmTTiJQ6RL71J4WBiGAnobFDrluwJtRr4BTRNDmzDBh8_G3EKTS5mr6W1EQnFnMAqIrW_TOvKasBlQqlLVcFDlllp7X2akyW6Z23NBe7JCnYi4m1HkM0_gnHqnFbnT3cS4umAd22ugbPbo8gn0KRoFxAZK4_4JPHbz_T2itrnDcl4z6_50F-I0Ynp9nHSKnlG5x5V6IGd47vfF7sIks8Vfpq8LUKgQu2g9XHzwf-q_jmwH-eokmnUlznsJnZWnz_GnHyeEMsdQbBKDGK9rjNuMC_QZGuiaARSlSvP7hMyowcczvtuKrN7sZc5nTWPD31UV-TBzrDnzmmsKZ_3BdPebNj71vt31hatE4Mc6OJJUZ-HPPUieICZJFiYXltJBqApmSrscPjDUy9fUoD0iJudrtDu6UJ31SFMkaapXqHG2FqMOwkEk_T5wGmdZ3Y6I8QKKiI4bXRcjPexjVQUJdHnGLRZ4L7tyKU1mFJHMEIMwAer1LiYsnFLHBt3XoAQbNu7LewtB3Cd1Qzeo16USsORAgO8DYtAiu9T0yfTOMAn6lfMgEIdqdJdY5KiPC2TWro08m4pn3mhDlfIWB4XzyBsaO8JiRlF_7Dfg0UpDEnk2AN7ACqsjeUoMk5478ov9JeTPOnCDw2W3x4-w3VhTndvrAD3OrnDoxsc7OcoQjni96fsh-E72g_FKaHJVqH591bROjD5nAPTj5rseGJYDTJkAlHauG67pXgIpMLSLgTUUeplBgjDDTWPdww6dYp8yW9CJNOXCrqmAunZDJe5d0n2BmzGLiOHxiDLKT4-7XoycRXq9adUn2uWgHUooKJbs4BI9sF_28FhxsbN5E2KT4b51aZsK91802OXcSbLCF1K-HqxFNeELpvrlnYT4Cefr_gQydbzRvzSdpTSpUTLtCspJ8RZzJZzQT6x6DnOT8KVt95Sx2OsaE6zCOEBUf5EX85M3Xw630kFQPAjAXx85FxEos_Fl5NtgSssugztP0Q6dbXJTuQrsSgSb6TWsJWaC6agqNudU2lkI3lWpxcxjnYdlDisZE2CVtPXIbMc0fP81Oz9g-LybenNrYDUdIL_FvJ9FM2ZSAleLrEgMM6IyDUXBC8PXA7QP-DukpVBDGkt6GRaNqiqMFN6ceHu1IcTRy8RBucg2ahZqS9BgLlbj2xGANaeZKjzvNKBbtqawx-RkwsHludZ4I6WaLC6-fCnqE0GuK3kw8mbym6gAbfHouwbWarAdtesd3tjoa620dCNg9QwQ1Hzgs4Fd0pjsSgMFB7ahRSDy78GWbdPXZqPollN22uUgQ1zWEva_VxrPK2C05iQMPE4Cg5X8XQbxGH6GY7wuOnc23Pvh9qe6po8voXKaUAPVb3oUGgYx7lgsWZIW-2c861ip10CSjcfFm6AVrS5Iaf7m0OZvUvL52q2r5Py_LWxLbgf0ubrDXMtHbhEGXYmiRaHcmuOxoFUtaqCB6kr6970im-84hk-SiCoL_96yg6Bna4isurYJb2JQgGktUX_SjcB4TshvDDx-G4H-lUYId4AaqP1zNJ0ryUPOlQQXlKtc6s0tUfEZu5SagAE6h6iTUkCr4hJ9hLanj_mMSMJiCjBCFUYMeZ4LCxzQagyR5qWxq90n2HlHhmPy5eCj16DTBIL49ScuUqyN5x8fWt23H-B0VjTUdFEVk8FFaPsSFv0SddM9LEvrlUcA-RcMpyZ1a2ifF7N_HwvRlMslVSzW2BUZRibnB0xpeZlUbqy2CDkr10azuxJYajE6giMCnSHfiKM2EPMuFl5-sX6FiyfsTIA3CmcdoHvd83KNQbMuDRp_nDCAl6LNcj8CXPyenI56CAX5owOddnszaI3C7fEfW7MavfzLE4KlNBPYeFmQLL7w0Rw6uZfqjBKLFLNtXNDBnJW3GSWYKFB0QiAMjf_9_nfOU0w3cwgnfsdmUU0BG_9bXy-qvzYvnWs1eLfoCfruH7gt5Bvb4iGPr37EFMI8yv-df__xbRHgDxVtAd-A5kL8N8DR4U6eSsw5UH8--p3ZpLyrh9vklTf4LDr0xt62qvZjUKzcuMZjQpcBvDHmKRx55aZ8BEkKhIhsWlZJMsE5prZOz3pwT5_pAp1h9u7sw60NnWisoTdBM08hP-JD06OWB_OFPa3I0x1boTojwlzVpiVGUdNeMgpWKa9wQj6rVsEl3-UFIyrKNpgir2df5m5q9vxZ3TSKawBZUAQJnQp9aYgysMtCnUCNrZ-zaC6mojA6cBLk-g5rCcXsyd1WqkHrFwYoPAu5593tQA-ttSVSFCUQxCILqKUZx1-fw2NIchE-NUak3dAZ4RTWm6EwMGXh6rmanI2swBjkglVxw3CfmOAsL7yXEhm2tOofu5EoADa_lEdy8ihHgsCPoJiq4hxlwFXrg9y-Pww0xsrldPuFcc6AAIpPR9UrKHoEdxoDnANqi6zsBTsp-VdyaNj5nFWgpm5mxgnuWUrBGif-U5ldingoapB0hJ50--CucJyHaLHHV2m7WcVDTXiykeHhjIp8qnKBaXwoyezqmLgzIOmhrJgqBH-drr_Usl2Mtzq5lyA2if9MFtKcktldky2GXDiMlwLWSf70Jj5d2Tq8_4P0C-StEZ66V_PkVarTSrFahni4g1OqUJbxxsK7oV932wEtpHJPo6MYnkebOFGlGQlxxk6OlqoZwyP6xbJCwu1_36FuIYcl09Vy11EXK58g62eDyg9eGaAAe1mU4fTByEowy94v67qTC9otmjGlB6K3pyqsGnpWEGz5FujtRPO_ChDNN84qZRMSk5QMU3jx1t3-_0Mg48WnuWGiDDveAhZVxNz9HThbvMviECVk2E70W0nj9XEybPhNLcKQxKMekE6_3qJxUTk8Q7KJpoDysmWznz0Brg-GT6NSJG0pFFfgdNCAK_K5G9SkdnS7Pr2S7DcDIasmdvIciCzw0Lv7Z2rZR8eiica4lrrz52lwO-rD2380r-UgaLsbX5PhZDc57JSkIKnAfS5qeqxK9koKyD4UyR-6gfA2SsoRbxayLigQOk4O6bIDoJ0ECvEoyaJTohselYUhhQDuwaYQ3UVBsxyNzFxXv4i_ldHItOjckkNBLTyz0rfh0bAbqP5ROsXG7Q9OIMglRSRyDjZdlMaRVO1-lXy_zQ8AoBxuAwGOyc2CQm4zvxMjmiAyMymBdZS5w3-aa6ILoaqvhMzYTEyP8pojxTER7-swPs4J_zroRVV-USiheF9qLRr8C7WtZnzaJXYhAap3HrTtfCVMAy8bHYFjk5zYLmVYw09C04sFxQ3apXWUc6A-30D_Ix_x-Nh0LmnhBXc-BiCPdaGA-iqaCScX94nyMmCC5-26KpbcKZL9qH6ZFUez72d2gmu0oX59AgiJkLaVqmWkC2fKMc-GxO7SI-tzO8AGmi2G5vVeYHIwc2zfRhHuNn8znS7SSRKD1uzTLvJzt0Bonu6NLukVUamhLf5SYmHR3Rd9Qb6NNprHYCyJkim-szlYjso9-EhfRqt3TZtuNx7zbXIoJJ_anSIBQKXrWpLJHr4CMexa0xlnVrB_K6-RPVBfKMZWdcRc2cltFzo-w1VvqOzmK_-B_9FkVhCdObJ-aak26s2CjdzF4SmyetdbUt1U6zDx3lb2InlGz544dNY6OjjQX0X0ImPVTlFAFWFO4ONwnUp5GQmqBjYQZ7CYKqx7RZexDqbmGsW33jnf17hPsToLphEo8M6_p9-I4-PSity9OSX3Gw35Lon-myQxV9Nq_Ui9Mtql08C_Uyhdqwk2FH8wESENlRPoM8Dq044Yj0gHqwUj4xqUht8j9Hk-au6fYM_fLPRyXv9jqjT_KklnmfaeAqZOb4hHRIFBxXA9Q-1rreVfYFWVMz-FRiyf3cWd7QQdMciuMBulWeJjgOUoZK3vQIS5f4AZzwYkNOt6F96hwRtdI8bU6tKJU2afAeqNQ6xiSa85tx8_YGzMsrdKdWAPQIKe66QmQLlQP04k_EoSLH_f9dc51NZYfGF8YwzJuvclpqtAeMNguhPuGj-7V5wFMYhni7osiiPQ==', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de', - signature='gAAAAABoxCzZ6TwL-z6tYv85YPC9CwMFJRrSrWgYUyOhSFYLkdfGwRUIbrgBnmAW0qtzE-shPNPNfbUltLnBS4uU8kMuSMPxotFngVcFFnZ8qmzDUJiEf2CsnqYqH5d2RmuvIXUQTau20SjGte8vOLksGsz0sXRUQnFs7ZoT_2DSy7tKVCCN7fbvkxm2l9D-IibdvGiflbP6lGGgYWczEl3_QyEyJGhDTcL_nUk511C2hjvqI6YkEjujvYjEGMh-BdhFrJeLFL2wCbn6beWaDB2IXYVo7LqhlQUtKksY2PQ4ybBgPhERNvWWf2N-K4NxEQuv6vdB_5ni_BlUKFMabeeeI4wVr5M3HKE6cSgnM8cpi93o_rGu9uSh5fbN5zZcIYumnjkGJ-ULwku7TVtpw_Vha8bJl67qCLvRe90MaCCgJxFKp-IsxakpnNCXVrAlN70cIchPEjOWW3VKrGZ-omyQLgs3EzddhaPmSqDELbmYkxCUuRYdLvZPzhI5VvNiW_j-WGBKEMJLFz0k33oPbH3Q6Fn9HcJSruSsQ8Lc-QWQsibGoABEY_auM7LDLjbvpEYcdsP5BJOBUS8wpyOD7N5jEQL2PYPT3tsP6mvWy7csRIkwEbh1x1sXp6NL3skS6QwpqNiWalP4OQvs8jDi8Gz-NrtNvmX3RR4A0MIuX4q0Tb1VI9PilRUvOvg9hF-fk3bqIh7wW7_iD2eDoXjvI99M-UZ2QZGZlPa1O039QVGLBTi-KwrLuhh-D5q3N-3-DyXY0sjsdFzM5Qf__lVaxtRhZRKyxSONZsTt8mGatlOH4Q-MIPgCXsrLu25gWn6Jr6vt_iQ1eZG30cox98F4aU11Hp-o4tFKuHL8Kbgl9Eetpd4ggfJrTe9QxQfWfgCHAKnhjVRJOepHPEFzSRFKiHrOgATIw_x5xNRacsF_tO1WkpeBdBJhpAUozarHgPQi2A71LCcmd5Zzy7FAL6R_5QtHW-H7NE2PjqqXnf2ZMiMM-oYLHKhfu8tZu9EV7V21xKkovIGH-0OQ-lk44ww8-j3rBNXjWIwp8SO73O85PP7vzE_zJJCF8riB_rOpazJpMCaDP_HUOZq5XhcfHseiS1SownunaXj2wOmgLJ103BowC18-i83n8RVTtRQxLsiCRzMwRH3eEbEClqZ1Fqt4V6NKqICKK3kF3_R_oPtX_-7xYBpl8LGR2Ei_2hXkEIuQ8cCRz1zmuyfjLEWIbm6Rm9wgYafXIXugOqGl4lUc2NSeeJ5T_-ziLEX9-Z6LZafWo9PMvxbxpm86-e5ZqTBlsbukWWIePrKZ6BjElMcxTOUr2XYg-vMAc7QRx11Ld11DwesN_Xj62Kc0TUQRfREPp2AF0gAlYYKLvl7XKwU12Rg6UlWBfJWjX-hUvPY83B7H1saGyAv6V4RR9PODI0p8duptI4mC6u3cYPUk8pOVwFvX1PYCTM3I2yik_XG5ZyI6BIGBNAGL5SoAyMfpqYu0Da4duOIve6tQ3FWkMYnU9sSjxvS00mRJ3JscA-pNm2B_dUXBRATIAD6XVg1m19-pV6OLG58tuDtbjE7nBHUHuS2sm2gbm4PFjpGKFMS07LUSfYax19Ombld0hV_0kwaIjl-4UTcRcqqLK-Tc2E3NPwmdJuzb95-lUoAJG9Jp8UCoyXQRcZk33IGXMYtNquee5K-Oc-ajKjbbevpi6rIEOVjwKrZYwTC5ddl8FBcCBTm0NunKUzo9TkDeEIF6kce9zYdKo9GwYc8Go2S9lxbb6tlizDql2Uv_ZiTz0d5RUvShsMH6RzKiXu8eFzv5sUraMbLUtm3VtZsz9Ld0iztNIqV7q6glrqD2UuLgWxKsa7EbDRvrlBnAOP1iMRtg6ICr2YHYtlwU6R5RzKllG4LGMccZ3x6HsZL6MMaMJc8rLMTtQYqE067kCnXAIBz_-FJS0CzwCwnbh70tc-ytaiTm404Jp3CIBTlGwDwTvXUqzzNAdFRHrilKUPNgtKb6uQAyPhJZwbFIfrFevaMdOGZ9UhJoKtQtsSj1qM-dhXIkn4T_SL0o72wgb08zYSjsemhfJdbNO6jPG_GfWV6FDAhY9vNyTT8XlqgsePnALnV60AIvRZPI7mfh8D7F8SI0yZU4AJVtEHKKgStPvCuixxtjTt9nSWm-cXOItJdKYxMjVtWCmcCI9LbPolXXkewgNhmUx-b0XlY_BN9cX2j0COic5Ml6LS0BZ6ikG65a-7kIl_yofLeat8q9-4OI-lhKYOxwMhQq8yWNCBuJZCGg5n3DM_QgEQt7cqWYuTuTMTgMnRIvSefK_Q-ZSY-ZfzPcNp13-v56KgA_yUqYOHvQDu4ZuZCI3KvlO1WSO17SiqiNZvo3iaM2BrrgzOAJYcSx4TUzl7ZuFE_6LkokGlxguZH82W9dpewDyN83yLLwakOhgLfbTlMCFs8NCLzMr17eBFNX8YqP9bh88f98KtLSYr09naEesCwW3v-M-I1MUdR7oEC64ixrAWEwpSI-Jcc60oUgvLBVbwkeoQWI29NqZCS2JYGsxjXfNmhWWB3kW7_7ik5RHk3oNRWXiEQ_N_K7c97Ui1YkomyAAZv4t3zQYHwsLBmnf2DCEMBViQn2nXXjGwBxEf9KY2dlT1ihIbcPBmyzI17UrKYXvYKkfE25c_R0VjQtRSiXrlEWkBgLwRzWt18_62P00dJRAeJOEq6etGKoSh0PsrmtCGfnOf1EJhksjZPyObdHWm_yrNiX-h3myewuYT4BIanBFdUQxQvpNyvoQJIMtKH3gAh9oCJY8os-vS1Mx7h4Zh0gEdQZhIVn7KoJwqbx09F8hGokOaVXx6H9gMD5kVZkXkX56AFC78ykpMLSsolvyUhAI_qxcpTVGSgDIzfK7BzQsMd4TawOtHObxfvVr9qojhx__eQEipXplbfOVh8vjM8TFY7eb8k5EvxaU_pBuEmSagGoV0fiPUmMTzipVTMQ-cpaF6xQSVYZK3CvmUwxHfcX2r8lPPH_SyeiVFKRdqTmpIGYw8drhwc9GFgFM_N1O_iJuhjSt-8iLt9BExKYJZftIcXPYl4eGgC1yC6oUBurdmvQUOZD2tv_isd28fMNeoiWAy7HCDz57TAkJg9nJsfULk_z5ClBqz7rPP9Qq9CZrYEsz6Lggj19AXh6PmA9Skl9nUSgsqn2GvDI3I5E8YmxhlP58XrZyYKLkYLqqAMDy4tqI2eiQMe4z1OhMGpVxoEt7ACxw8-YaQTKgItzSNNskrXkRsGvWa2m9XcaZNwbZFeqek7OZ0vxLMsQJ3InnvY1lj9aMUUGukolxZEZ0KolEPOsIKhwH4iMg79yNlxeqdM2e-OoxrUyIBvBqC5uNemtqnulwarV_0K4XYtimpR2ONcwjzSO-eY9untVEmJRdw-OYEJiKJoRRNEjmr77UuJLDhPqjtxmcF2LHRTbpQ8b73Vp-mt-1okyP2yOr8Rd6LbsJuntv77VWE6Mt2JBzJpwJZab3mKd-2c6VkTswJX8p8Lf3g6m3uPwBRrvyCuuxztoxG2rDrh-3krcjDFnwU5tZjpZ3G3pq6KXbcmsX3kvJhJc6er38kO6uR9SkJUcRkbQPZ5nUKCtRZ3AkFukiT_YHtUamsUlA0nX5DI0CcrrNtu71HD7jSkwF9-P_QNX3_c9k31cSfHQ8BCMHcy7DO0vPYuzj2BiStEdTymAXfMeTFVO3wUvQf9KyuqVnKFMtFwP2DaospAJCd4TaHeDCm-uczeg1of-R2SB0f5XorCQ5MljHFk1VTHmWG3LHgCTEmAtx2KKbdMO8zXsBop6LAnFj3dNEBv1grO5lMCZRqKRo-csAJKwqXn9kuIa6GXi-NMZWBGLvxWhJpWdCeGnaFjCk-7uzPQ7PN_JhtPjeI3W-9A5bY8RvzYLrKKIEOEMGyHb-77dcYPhhLgn10-HpglS0_uJw5f0STZE60rxVXH-sb7vrpyAyBqMUh-OdoGAqR4r9dflKk-jECG0sggRuzx8jLGGfO-dNZSznD8JbaCsRDdLuHWiFSZKJswXwX5PS9rmVpYRrH-0QniMhPiMOuINwp9GvTtzSvXNIPBWtNMsY_jN_O2gIKxL-KnyoQkyUFWHN0Anuyv5pCHQk1lhfcR0alSvDLVmVVgi1tQdjsdAl19qMdfm43ViBTRLDwzP8iauhipIfCpxFjak0Ka8uFaHfEhKstcmUdxEnzIsN3SQXrPud-p0YJ3O1MsyUDjzMROP43FKMhVCSnM5PsXVvuPZKRmuEFbJyj0dwwBnSH-rk8tuK5SYoX8PIrJXyAySgj2VouGdzvkqa9WPSHU42AxDZNQT2c5pEI3gUS7VzcGCTwoznmFtmHKGOJj8HxKswzB2z0AumI_ht8zx6kehnvKK4cJfKjdJfO--2o_gzVR0DkA1HcenMD4ugxj6rWQDiJvo6cFdfkXpMfLAe4NQRLVLNv4UdIehCxCHMsF1RZJf93Z6sdxW_2PumLLcfdb2XIkouuFN0mECzZlWgM4XLUErlaaqDc8oU_gRrgHEJbjZqF7by2nHtqCjyWOZC9n7vF18iSRJES5DX71nY84a8ydPR2_KEYfHHgqF51Nz9zMo2Gv6ramAFs6lZC5rjOUR1VmpLd2pKs-sPQJpYNncwbDe8dG_NDJI1wIgs2K42eKPE4lEueCtp359ifPU58DpJA0JiB_FW3jBBh_9MphsnQjuso9S-YSaSFt4Llc_Zf0MJ3CbiEsk-IwfgsLysFQg-vJq9hHR48ZoW0kx7CaIAUgkiJg7-7m_dVNsfaUM-OSHtfryYXWrUsotLJ6OTuicPOfb_LfaYz5OoasG0o-4vdtF8e4VX6ZpR_Krje-dZaCph1XjgGLfFlRRkywl7i8IEUirHpQJaoCPmc9q61hjETcuPCEVDy-dJMwPLiNzXY1mkJI1lQQ1LL8Ke5EgtAcC-2K_5Nwh4h4bafWA44XgnisMfYDv66CzsL35i0XtZHibfLqPwdLyHqInlLPtiFyhJZifcJ_GsiQ0U4SZO3WHmvSG9AHy0YnA2jC3O4x7yj73RmroELKFvT-_CSO5LVz3qRRVdlyL0CQr3lkHUXJbFNpOz7Uek4q6MjB8Cn0xAKzt9ztcClLdAA9NkR88Dy3rOP5yPjRJJVVG6SbelsE1SnPDaKQqu2ZN1zdtGUY9AcULc2dGFb4mezcbJsC_eL3DD0LwfwcSAILDfDIrqHACR0XmI7jmF_p_PzmBhMsocLnblzKTho5ufo4htqhTEjVdFywm9WIjw1N_9PWge3i3J8mSdILp0HQ1QvbRlMt13qPyLNwAmY75m4Zw7EIlk4cyxMjcTSY02TRCC3cBKX2e6xl0DIAygChReVOxL16BT21sEgT2ps24Mljsvht-fokU3JPtj3fY8wojksHAWNv2hlF62xKrOv9h9AqM_Q9JlghHHNTrzxvT8SVeLBhEvysbhErrgtTPcgvKfMUCT1JMWolxLZUSFEFKNR9cl2GiSqMIhdTL3JvA0-etZ7ykeIbUEU0jlRZAw4a3vY1R1zW1-c6XRSNiS9VDPAfcN2OD4bXL8Hi2Un7Vc_pRyWn32kWQqQuw7v6J4RB-sr3Bkb4OzUljytF3ixqGkMIpuA-LjJwdBJ-XgR8Fj_DONbguNct7MTkMtQqWU9twa8XF_sot8iEYc1UOkZQVJvTtNclIkklJhP8VNj1aY18Y1Gtnn0fvfaOFfY4wa7HIq0U7paT2Fqb0xtY62bqNM6rRXLsAQex5HvMvHQvL_9JbQngBOD2ehk7zIAJKZWzbAKqKCgH-_v4kaGBVrciIxffYF6WnWq35pQwbsvNqQG4uJR0qhLEXfc5akEon1sL2fjxim_GFcgunyCqL28lMB8yhnzA48QESW0sotVss_GIeeftSYS74zPaHXiuSx0RoAmw90kERXPDGVCRkwTTwaW2BkshCJCx2JOSDEWVRMjxngzaoroybl9A1VzTrDEbodeq2O_kVyZfrZE58BO8DDd6ZH07m4zuiL_NKXLw23NmC4CuAN0ufn7HFtX_ow4ZJILfZI9PczBi16liV0LWrBwvadZ2Lf4o3sV65CLg1VKujttEiOhtpYjmB9zIRLfAHViz5vgTonL6H_9N4D2dXLzUWlaDPNGJNnt7EbHS64f3jSXGG1fb7LGKhNtTHqbfBJnMpmPjFQGb4ae2kKv_V_L8xgXNpQRi5I_QNTzDzfBs4avowydppTpEE1b8WNITLc7qvMa6gwpDxp2N91fIVC9wyd0k2DXaz3VbDn-2v7W72D2UPa0L00NKvIKYecd9FMpYmkEyxJfFFr7b9hKA1ZXdqlejjPJPjVYC9XTEZLEwzdeoG6yrxtYMrl7o72M37uIRNZAj1Jf0B8s0qhPaaBfUVKtKl7bd2Ub2503LZ7ZvJ_1segaIT4S8nt17hjfep3re_4rEKA2rrxMbWoLhM4qkAPZvdjyAFF1YNB7u-Uex7l4STRYSpzl4eQIMSl7N0pGlKk58Z1FxTKHsAZTkZYtj40lptma1AfcwRPViNPceCFA36XfVjaratWPYgDhcjK8nNnAhxvL7t25nPbCXazPK1D16ZkY2SwcX7sMx8QklNQdzukZwGyP51yhU8o0PT-u3xGDaXnP6Wh_o35cCIRnar6Id9h2ovViZXJRUzNa8aXedxiFp7hLScSQfIPrPBcqN45EvLjEmtLvzzxNgHY7zw6gzj5QFgv64u2fI9zAY00B9U37bHIZPQnFAhge0466vyXNENzYO3acUGo5HhyFDlcuiBCbIZ413bmfbtRbj5W1FZMY58l1plTmNljfcwQ7Kd0PUGvGEb_jwKlmyKni1HzyyUmElGHdRkyS5Yk7aja6AJOk6z12WUM5snqG-uRVkByxCXQ2KaFR6Qm-IOHMFqzrPINkjyEJgG6KyKfkF5ScVfQaThHBuMrb7ETWMnlk0L28ZszB-TLt3HfaxINsoD5pndSSqBpHB1z_2kEweik3y_PdxIchV3CyBLnmrlqBPBIarCoM8VwzForh3RzQmgNsOGkJXy3Lk0rIr3t-BE7qgXWsrDolobtH6MMFO96Taa6MYIYYYbYvzQYcDuQwD21yGTLwKAnynBDn99bGYEg65LomsJbTSKCYQRcj2Rh2AaScsq8JiHYJEGAnRkgsXNivZnioTlkI9_5XqXBJt3GKMY37YL6qIU3XJ7HapKELorbX4fH_JlOIZLIOIaU80295GZcFdx1I2La9lp_UvAtALEDJklGNvbcDG51NNn2mj_P85vIfzsVdrfX7N_AftR8t1kQx7bdbVLyP4ls_qKnXXigfNJajWtPVgwGeroQq2jtaQw6Tj2Wsi3Itmo5QNg3N_ja3erlEHEdTo8lm4XZHjbl2bAH3n_wuEdYKTt2B3jhj4ddhO8atc1fryqbRfn61YFKUnR3f5vQ1qUq79uisQi0cvHr6DQ_12FpKzFvFckAkQmbk5fcS5Ri5S4L_JtFAexj8n2f_oYuG_9CYYplOU5i1Q84MyXUZ2fZyDhRPRiyjvPJ07_IAiL2ny1btmIFtVPeQSHVwfun-m5Lba3KgnZIJ6CRFqxR-o6F8e5K78d-bAotgA5vOcfeC_fBQfaom-EX0mJyzf7_Wjgam4IA_W3PO_wGoVULHfr7mwUw2Qc-VzITtjajZvRoT-SkVREyJVnKBxHFj2cNTcTtooSxCu115KmbtePf2OwgJocB2jyPT2GK-kIVZtuGdv4Dns8m7Z7FpT7PvjCVjidQqVsJxFQUs7ZzcTXX4vdChdcVK1_OiUwCJKiYN9ZKGA_OmwQJjhnV6gutHFYanu3Gm0m5PQLIM6Pip7yXCw8-Lhq0sxFTl2f-7DeYlfrWpYJyc2wR3T2u-kHl1g52CxX5XoHCV1LsBIU75L23Igsx5_v9ZNeewK2Qh8yWwlWZ18qnXOh5ZJqJUpYtxy3sUhHMG8fe5RKVGbbJyHltosuW26yJ9eUQXqJOSj4wv0YN6a-BezPdkkCqdiUGDHllrgAi96kkeM4jES6iZV60rTgdmfOS03JL0eqCwLnH0gP9t5Xq7l0-GUKp7mrsUjgN4Utb89AVPyIDFWxfJTuFJK-g6Z1EHexEvDY4iTsuOdq9M49_zV6iL8ChB4p5l0lUOiFzIH1Qj-gNMqpU2p0H73cMd3MNeecFhMsCfRadVCO8D4UN39W2mEXDxLBlTN2f4m6aDKjLHi58zyDiJ4aga_ntZRnv56KJpWob0A-4U6_GRJI3OynwKPfb0wpAzK8Gm6Ak1OpxvD-8TmbKUKVA5m55PMoBgGbmvtrwC9Q9Exg-zdotpZ5-iWM1ssnKLXobFa2SmYJeOcGbEjh_yvRvjBRNHxWmq_sP1ohPCTce4Pt97WVQs0Kc_Peb85RqZEnCyjRfV4C3nFUkTxJhFJbmIBPG-VPJDfKEMVTtUe7xB_w55BKViE87CTrd9AAveBFKkBrL3x4bVba3SK5HLU3tOgUPMDnN6Q-waVbjTXsNPGPwJjvbDAN-xwm1V19e-gYcI9sExy4hH9fCkx7Y93e3EMo_EvPA8ZFO8C-KKKlKttqg66BlOp_WYj4GnTpurNDHjVtBQZI6FN5HGl72n7ZL0me0cbfiDkFh7mIfHJCc3EcRCp__gjeBYQaGaR3hh7hLrNeuJB_oAfW5mz-2mIgUYz7vGxRrTeo9CyNYjr5CNwd-hp06pklYw1Bmce-1ZqG87pwFGjfWaAABwqNElf9Wdhgzll31WmopAxDC12Q8pzpAiFfkWWeHsPgvx_Hfm6B50TiIn_LCi8hjTaVUkvtNxZgiKJdAdL5btiUvPwVD10EkysT4dfAEg6l9Z64sZT6oss0KlH55VrNoLOybfx9-TGJZOCB5Zf7JU0KuA1Dpfp8I8TlCOUBwybFvNbECafzsrKB8XI6cmvDtsG0NqNzifoYUPzZDv4eNQhb4QAxlWx_xjiD_G33rgZ27DfvecgVkhDUc317uWUTrWt0f4WJItv4A8P4fj2CDa4cAjfe9CCWM8oehppoxScG5nBFdeebs1m3efdBi0VlYbJTEFQC92q0Zdr7kdfo0FbR1GQ05x66u5b0qLRqqsgF6n72p8Vo_izkLs1N3HKOz9AvcoTmD_tD70rZC6SVJ0jQcKtOMre7VK7lJQJwkuuUL-TRcVYVFeKln1CDs0zpqwza1iCVw3LcUdh96iPsN3XcHrH9pqUxSEY_T6Bq8aSTHdf-iqucTB2u2zsq5BgU40_zXUqvfvQRhcHbaNl0NkdbWKVr8AA3KkoGHMe-H_FBRmyBFX2KL7F4naGngOz7crLfNoSqvPF6cBudn3Q_PPxutj_F5d3FxcfHSHizhfZ3sC39DiwyKgWMU4rUm4gsyYpnKQ90aXtF9nuLWDyNZEb1hsHiVyIoNkUx4IznUY94rrMNzlobnMyqtaic819_vgKqTo9jYA-i5JgMoTPy2DTtIZIpU_p-TggdpEActJ7qncHdQjM0mCrZGYo78NvZ0697fexOgo-dQjfUmNNKNtLp1UQiMBllHwIDZzRePAgOeisXx-E10lLdPUm6AKQcg6IYbvrPDil1_EaQyV3JXqEgNCZwXvkDIh2cnaBLUzyWsep_iupiypilShz_QWLsa467qw5dJ_Q0vR1ulAzMWokaCmTTiJQ6RL71J4WBiGAnobFDrluwJtRr4BTRNDmzDBh8_G3EKTS5mr6W1EQnFnMAqIrW_TOvKasBlQqlLVcFDlllp7X2akyW6Z23NBe7JCnYi4m1HkM0_gnHqnFbnT3cS4umAd22ugbPbo8gn0KRoFxAZK4_4JPHbz_T2itrnDcl4z6_50F-I0Ynp9nHSKnlG5x5V6IGd47vfF7sIks8Vfpq8LUKgQu2g9XHzwf-q_jmwH-eokmnUlznsJnZWnz_GnHyeEMsdQbBKDGK9rjNuMC_QZGuiaARSlSvP7hMyowcczvtuKrN7sZc5nTWPD31UV-TBzrDnzmmsKZ_3BdPebNj71vt31hatE4Mc6OJJUZ-HPPUieICZJFiYXltJBqApmSrscPjDUy9fUoD0iJudrtDu6UJ31SFMkaapXqHG2FqMOwkEk_T5wGmdZ3Y6I8QKKiI4bXRcjPexjVQUJdHnGLRZ4L7tyKU1mFJHMEIMwAer1LiYsnFLHBt3XoAQbNu7LewtB3Cd1Qzeo16USsORAgO8DYtAiu9T0yfTOMAn6lfMgEIdqdJdY5KiPC2TWro08m4pn3mhDlfIWB4XzyBsaO8JiRlF_7Dfg0UpDEnk2AN7ACqsjeUoMk5478ov9JeTPOnCDw2W3x4-w3VhTndvrAD3OrnDoxsc7OcoQjni96fsh-E72g_FKaHJVqH591bROjD5nAPTj5rseGJYDTJkAlHauG67pXgIpMLSLgTUUeplBgjDDTWPdww6dYp8yW9CJNOXCrqmAunZDJe5d0n2BmzGLiOHxiDLKT4-7XoycRXq9adUn2uWgHUooKJbs4BI9sF_28FhxsbN5E2KT4b51aZsK91802OXcSbLCF1K-HqxFNeELpvrlnYT4Cefr_gQydbzRvzSdpTSpUTLtCspJ8RZzJZzQT6x6DnOT8KVt95Sx2OsaE6zCOEBUf5EX85M3Xw630kFQPAjAXx85FxEos_Fl5NtgSssugztP0Q6dbXJTuQrsSgSb6TWsJWaC6agqNudU2lkI3lWpxcxjnYdlDisZE2CVtPXIbMc0fP81Oz9g-LybenNrYDUdIL_FvJ9FM2ZSAleLrEgMM6IyDUXBC8PXA7QP-DukpVBDGkt6GRaNqiqMFN6ceHu1IcTRy8RBucg2ahZqS9BgLlbj2xGANaeZKjzvNKBbtqawx-RkwsHludZ4I6WaLC6-fCnqE0GuK3kw8mbym6gAbfHouwbWarAdtesd3tjoa620dCNg9QwQ1Hzgs4Fd0pjsSgMFB7ahRSDy78GWbdPXZqPollN22uUgQ1zWEva_VxrPK2C05iQMPE4Cg5X8XQbxGH6GY7wuOnc23Pvh9qe6po8voXKaUAPVb3oUGgYx7lgsWZIW-2c861ip10CSjcfFm6AVrS5Iaf7m0OZvUvL52q2r5Py_LWxLbgf0ubrDXMtHbhEGXYmiRaHcmuOxoFUtaqCB6kr6970im-84hk-SiCoL_96yg6Bna4isurYJb2JQgGktUX_SjcB4TshvDDx-G4H-lUYId4AaqP1zNJ0ryUPOlQQXlKtc6s0tUfEZu5SagAE6h6iTUkCr4hJ9hLanj_mMSMJiCjBCFUYMeZ4LCxzQagyR5qWxq90n2HlHhmPy5eCj16DTBIL49ScuUqyN5x8fWt23H-B0VjTUdFEVk8FFaPsSFv0SddM9LEvrlUcA-RcMpyZ1a2ifF7N_HwvRlMslVSzW2BUZRibnB0xpeZlUbqy2CDkr10azuxJYajE6giMCnSHfiKM2EPMuFl5-sX6FiyfsTIA3CmcdoHvd83KNQbMuDRp_nDCAl6LNcj8CXPyenI56CAX5owOddnszaI3C7fEfW7MavfzLE4KlNBPYeFmQLL7w0Rw6uZfqjBKLFLNtXNDBnJW3GSWYKFB0QiAMjf_9_nfOU0w3cwgnfsdmUU0BG_9bXy-qvzYvnWs1eLfoCfruH7gt5Bvb4iGPr37EFMI8yv-df__xbRHgDxVtAd-A5kL8N8DR4U6eSsw5UH8--p3ZpLyrh9vklTf4LDr0xt62qvZjUKzcuMZjQpcBvDHmKRx55aZ8BEkKhIhsWlZJMsE5prZOz3pwT5_pAp1h9u7sw60NnWisoTdBM08hP-JD06OWB_OFPa3I0x1boTojwlzVpiVGUdNeMgpWKa9wQj6rVsEl3-UFIyrKNpgir2df5m5q9vxZ3TSKawBZUAQJnQp9aYgysMtCnUCNrZ-zaC6mojA6cBLk-g5rCcXsyd1WqkHrFwYoPAu5593tQA-ttSVSFCUQxCILqKUZx1-fw2NIchE-NUak3dAZ4RTWm6EwMGXh6rmanI2swBjkglVxw3CfmOAsL7yXEhm2tOofu5EoADa_lEdy8ihHgsCPoJiq4hxlwFXrg9y-Pww0xsrldPuFcc6AAIpPR9UrKHoEdxoDnANqi6zsBTsp-VdyaNj5nFWgpm5mxgnuWUrBGif-U5ldingoapB0hJ50--CucJyHaLHHV2m7WcVDTXiykeHhjIp8qnKBaXwoyezqmLgzIOmhrJgqBH-drr_Usl2Mtzq5lyA2if9MFtKcktldky2GXDiMlwLWSf70Jj5d2Tq8_4P0C-StEZ66V_PkVarTSrFahni4g1OqUJbxxsK7oV932wEtpHJPo6MYnkebOFGlGQlxxk6OlqoZwyP6xbJCwu1_36FuIYcl09Vy11EXK58g62eDyg9eGaAAe1mU4fTByEowy94v67qTC9otmjGlB6K3pyqsGnpWEGz5FujtRPO_ChDNN84qZRMSk5QMU3jx1t3-_0Mg48WnuWGiDDveAhZVxNz9HThbvMviECVk2E70W0nj9XEybPhNLcKQxKMekE6_3qJxUTk8Q7KJpoDysmWznz0Brg-GT6NSJG0pFFfgdNCAK_K5G9SkdnS7Pr2S7DcDIasmdvIciCzw0Lv7Z2rZR8eiica4lrrz52lwO-rD2380r-UgaLsbX5PhZDc57JSkIKnAfS5qeqxK9koKyD4UyR-6gfA2SsoRbxayLigQOk4O6bIDoJ0ECvEoyaJTohselYUhhQDuwaYQ3UVBsxyNzFxXv4i_ldHItOjckkNBLTyz0rfh0bAbqP5ROsXG7Q9OIMglRSRyDjZdlMaRVO1-lXy_zQ8AoBxuAwGOyc2CQm4zvxMjmiAyMymBdZS5w3-aa6ILoaqvhMzYTEyP8pojxTER7-swPs4J_zroRVV-USiheF9qLRr8C7WtZnzaJXYhAap3HrTtfCVMAy8bHYFjk5zYLmVYw09C04sFxQ3apXWUc6A-30D_Ix_x-Nh0LmnhBXc-BiCPdaGA-iqaCScX94nyMmCC5-26KpbcKZL9qH6ZFUez72d2gmu0oX59AgiJkLaVqmWkC2fKMc-GxO7SI-tzO8AGmi2G5vVeYHIwc2zfRhHuNn8znS7SSRKD1uzTLvJzt0Bonu6NLukVUamhLf5SYmHR3Rd9Qb6NNprHYCyJkim-szlYjso9-EhfRqt3TZtuNx7zbXIoJJ_anSIBQKXrWpLJHr4CMexa0xlnVrB_K6-RPVBfKMZWdcRc2cltFzo-w1VvqOzmK_-B_9FkVhCdObJ-aak26s2CjdzF4SmyetdbUt1U6zDx3lb2InlGz544dNY6OjjQX0X0ImPVTlFAFWFO4ONwnUp5GQmqBjYQZ7CYKqx7RZexDqbmGsW33jnf17hPsToLphEo8M6_p9-I4-PSity9OSX3Gw35Lon-myQxV9Nq_Ui9Mtql08C_Uyhdqwk2FH8wESENlRPoM8Dq044Yj0gHqwUj4xqUht8j9Hk-au6fYM_fLPRyXv9jqjT_KklnmfaeAqZOb4hHRIFBxXA9Q-1rreVfYFWVMz-FRiyf3cWd7QQdMciuMBulWeJjgOUoZK3vQIS5f4AZzwYkNOt6F96hwRtdI8bU6tKJU2afAeqNQ6xiSa85tx8_YGzMsrdKdWAPQIKe66QmQLlQP04k_EoSLH_f9dc51NZYfGF8YwzJuvclpqtAeMNguhPuGj-7V5wFMYhni7osiiPQ==', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de', - signature='gAAAAABoxCzZ6TwL-z6tYv85YPC9CwMFJRrSrWgYUyOhSFYLkdfGwRUIbrgBnmAW0qtzE-shPNPNfbUltLnBS4uU8kMuSMPxotFngVcFFnZ8qmzDUJiEf2CsnqYqH5d2RmuvIXUQTau20SjGte8vOLksGsz0sXRUQnFs7ZoT_2DSy7tKVCCN7fbvkxm2l9D-IibdvGiflbP6lGGgYWczEl3_QyEyJGhDTcL_nUk511C2hjvqI6YkEjujvYjEGMh-BdhFrJeLFL2wCbn6beWaDB2IXYVo7LqhlQUtKksY2PQ4ybBgPhERNvWWf2N-K4NxEQuv6vdB_5ni_BlUKFMabeeeI4wVr5M3HKE6cSgnM8cpi93o_rGu9uSh5fbN5zZcIYumnjkGJ-ULwku7TVtpw_Vha8bJl67qCLvRe90MaCCgJxFKp-IsxakpnNCXVrAlN70cIchPEjOWW3VKrGZ-omyQLgs3EzddhaPmSqDELbmYkxCUuRYdLvZPzhI5VvNiW_j-WGBKEMJLFz0k33oPbH3Q6Fn9HcJSruSsQ8Lc-QWQsibGoABEY_auM7LDLjbvpEYcdsP5BJOBUS8wpyOD7N5jEQL2PYPT3tsP6mvWy7csRIkwEbh1x1sXp6NL3skS6QwpqNiWalP4OQvs8jDi8Gz-NrtNvmX3RR4A0MIuX4q0Tb1VI9PilRUvOvg9hF-fk3bqIh7wW7_iD2eDoXjvI99M-UZ2QZGZlPa1O039QVGLBTi-KwrLuhh-D5q3N-3-DyXY0sjsdFzM5Qf__lVaxtRhZRKyxSONZsTt8mGatlOH4Q-MIPgCXsrLu25gWn6Jr6vt_iQ1eZG30cox98F4aU11Hp-o4tFKuHL8Kbgl9Eetpd4ggfJrTe9QxQfWfgCHAKnhjVRJOepHPEFzSRFKiHrOgATIw_x5xNRacsF_tO1WkpeBdBJhpAUozarHgPQi2A71LCcmd5Zzy7FAL6R_5QtHW-H7NE2PjqqXnf2ZMiMM-oYLHKhfu8tZu9EV7V21xKkovIGH-0OQ-lk44ww8-j3rBNXjWIwp8SO73O85PP7vzE_zJJCF8riB_rOpazJpMCaDP_HUOZq5XhcfHseiS1SownunaXj2wOmgLJ103BowC18-i83n8RVTtRQxLsiCRzMwRH3eEbEClqZ1Fqt4V6NKqICKK3kF3_R_oPtX_-7xYBpl8LGR2Ei_2hXkEIuQ8cCRz1zmuyfjLEWIbm6Rm9wgYafXIXugOqGl4lUc2NSeeJ5T_-ziLEX9-Z6LZafWo9PMvxbxpm86-e5ZqTBlsbukWWIePrKZ6BjElMcxTOUr2XYg-vMAc7QRx11Ld11DwesN_Xj62Kc0TUQRfREPp2AF0gAlYYKLvl7XKwU12Rg6UlWBfJWjX-hUvPY83B7H1saGyAv6V4RR9PODI0p8duptI4mC6u3cYPUk8pOVwFvX1PYCTM3I2yik_XG5ZyI6BIGBNAGL5SoAyMfpqYu0Da4duOIve6tQ3FWkMYnU9sSjxvS00mRJ3JscA-pNm2B_dUXBRATIAD6XVg1m19-pV6OLG58tuDtbjE7nBHUHuS2sm2gbm4PFjpGKFMS07LUSfYax19Ombld0hV_0kwaIjl-4UTcRcqqLK-Tc2E3NPwmdJuzb95-lUoAJG9Jp8UCoyXQRcZk33IGXMYtNquee5K-Oc-ajKjbbevpi6rIEOVjwKrZYwTC5ddl8FBcCBTm0NunKUzo9TkDeEIF6kce9zYdKo9GwYc8Go2S9lxbb6tlizDql2Uv_ZiTz0d5RUvShsMH6RzKiXu8eFzv5sUraMbLUtm3VtZsz9Ld0iztNIqV7q6glrqD2UuLgWxKsa7EbDRvrlBnAOP1iMRtg6ICr2YHYtlwU6R5RzKllG4LGMccZ3x6HsZL6MMaMJc8rLMTtQYqE067kCnXAIBz_-FJS0CzwCwnbh70tc-ytaiTm404Jp3CIBTlGwDwTvXUqzzNAdFRHrilKUPNgtKb6uQAyPhJZwbFIfrFevaMdOGZ9UhJoKtQtsSj1qM-dhXIkn4T_SL0o72wgb08zYSjsemhfJdbNO6jPG_GfWV6FDAhY9vNyTT8XlqgsePnALnV60AIvRZPI7mfh8D7F8SI0yZU4AJVtEHKKgStPvCuixxtjTt9nSWm-cXOItJdKYxMjVtWCmcCI9LbPolXXkewgNhmUx-b0XlY_BN9cX2j0COic5Ml6LS0BZ6ikG65a-7kIl_yofLeat8q9-4OI-lhKYOxwMhQq8yWNCBuJZCGg5n3DM_QgEQt7cqWYuTuTMTgMnRIvSefK_Q-ZSY-ZfzPcNp13-v56KgA_yUqYOHvQDu4ZuZCI3KvlO1WSO17SiqiNZvo3iaM2BrrgzOAJYcSx4TUzl7ZuFE_6LkokGlxguZH82W9dpewDyN83yLLwakOhgLfbTlMCFs8NCLzMr17eBFNX8YqP9bh88f98KtLSYr09naEesCwW3v-M-I1MUdR7oEC64ixrAWEwpSI-Jcc60oUgvLBVbwkeoQWI29NqZCS2JYGsxjXfNmhWWB3kW7_7ik5RHk3oNRWXiEQ_N_K7c97Ui1YkomyAAZv4t3zQYHwsLBmnf2DCEMBViQn2nXXjGwBxEf9KY2dlT1ihIbcPBmyzI17UrKYXvYKkfE25c_R0VjQtRSiXrlEWkBgLwRzWt18_62P00dJRAeJOEq6etGKoSh0PsrmtCGfnOf1EJhksjZPyObdHWm_yrNiX-h3myewuYT4BIanBFdUQxQvpNyvoQJIMtKH3gAh9oCJY8os-vS1Mx7h4Zh0gEdQZhIVn7KoJwqbx09F8hGokOaVXx6H9gMD5kVZkXkX56AFC78ykpMLSsolvyUhAI_qxcpTVGSgDIzfK7BzQsMd4TawOtHObxfvVr9qojhx__eQEipXplbfOVh8vjM8TFY7eb8k5EvxaU_pBuEmSagGoV0fiPUmMTzipVTMQ-cpaF6xQSVYZK3CvmUwxHfcX2r8lPPH_SyeiVFKRdqTmpIGYw8drhwc9GFgFM_N1O_iJuhjSt-8iLt9BExKYJZftIcXPYl4eGgC1yC6oUBurdmvQUOZD2tv_isd28fMNeoiWAy7HCDz57TAkJg9nJsfULk_z5ClBqz7rPP9Qq9CZrYEsz6Lggj19AXh6PmA9Skl9nUSgsqn2GvDI3I5E8YmxhlP58XrZyYKLkYLqqAMDy4tqI2eiQMe4z1OhMGpVxoEt7ACxw8-YaQTKgItzSNNskrXkRsGvWa2m9XcaZNwbZFeqek7OZ0vxLMsQJ3InnvY1lj9aMUUGukolxZEZ0KolEPOsIKhwH4iMg79yNlxeqdM2e-OoxrUyIBvBqC5uNemtqnulwarV_0K4XYtimpR2ONcwjzSO-eY9untVEmJRdw-OYEJiKJoRRNEjmr77UuJLDhPqjtxmcF2LHRTbpQ8b73Vp-mt-1okyP2yOr8Rd6LbsJuntv77VWE6Mt2JBzJpwJZab3mKd-2c6VkTswJX8p8Lf3g6m3uPwBRrvyCuuxztoxG2rDrh-3krcjDFnwU5tZjpZ3G3pq6KXbcmsX3kvJhJc6er38kO6uR9SkJUcRkbQPZ5nUKCtRZ3AkFukiT_YHtUamsUlA0nX5DI0CcrrNtu71HD7jSkwF9-P_QNX3_c9k31cSfHQ8BCMHcy7DO0vPYuzj2BiStEdTymAXfMeTFVO3wUvQf9KyuqVnKFMtFwP2DaospAJCd4TaHeDCm-uczeg1of-R2SB0f5XorCQ5MljHFk1VTHmWG3LHgCTEmAtx2KKbdMO8zXsBop6LAnFj3dNEBv1grO5lMCZRqKRo-csAJKwqXn9kuIa6GXi-NMZWBGLvxWhJpWdCeGnaFjCk-7uzPQ7PN_JhtPjeI3W-9A5bY8RvzYLrKKIEOEMGyHb-77dcYPhhLgn10-HpglS0_uJw5f0STZE60rxVXH-sb7vrpyAyBqMUh-OdoGAqR4r9dflKk-jECG0sggRuzx8jLGGfO-dNZSznD8JbaCsRDdLuHWiFSZKJswXwX5PS9rmVpYRrH-0QniMhPiMOuINwp9GvTtzSvXNIPBWtNMsY_jN_O2gIKxL-KnyoQkyUFWHN0Anuyv5pCHQk1lhfcR0alSvDLVmVVgi1tQdjsdAl19qMdfm43ViBTRLDwzP8iauhipIfCpxFjak0Ka8uFaHfEhKstcmUdxEnzIsN3SQXrPud-p0YJ3O1MsyUDjzMROP43FKMhVCSnM5PsXVvuPZKRmuEFbJyj0dwwBnSH-rk8tuK5SYoX8PIrJXyAySgj2VouGdzvkqa9WPSHU42AxDZNQT2c5pEI3gUS7VzcGCTwoznmFtmHKGOJj8HxKswzB2z0AumI_ht8zx6kehnvKK4cJfKjdJfO--2o_gzVR0DkA1HcenMD4ugxj6rWQDiJvo6cFdfkXpMfLAe4NQRLVLNv4UdIehCxCHMsF1RZJf93Z6sdxW_2PumLLcfdb2XIkouuFN0mECzZlWgM4XLUErlaaqDc8oU_gRrgHEJbjZqF7by2nHtqCjyWOZC9n7vF18iSRJES5DX71nY84a8ydPR2_KEYfHHgqF51Nz9zMo2Gv6ramAFs6lZC5rjOUR1VmpLd2pKs-sPQJpYNncwbDe8dG_NDJI1wIgs2K42eKPE4lEueCtp359ifPU58DpJA0JiB_FW3jBBh_9MphsnQjuso9S-YSaSFt4Llc_Zf0MJ3CbiEsk-IwfgsLysFQg-vJq9hHR48ZoW0kx7CaIAUgkiJg7-7m_dVNsfaUM-OSHtfryYXWrUsotLJ6OTuicPOfb_LfaYz5OoasG0o-4vdtF8e4VX6ZpR_Krje-dZaCph1XjgGLfFlRRkywl7i8IEUirHpQJaoCPmc9q61hjETcuPCEVDy-dJMwPLiNzXY1mkJI1lQQ1LL8Ke5EgtAcC-2K_5Nwh4h4bafWA44XgnisMfYDv66CzsL35i0XtZHibfLqPwdLyHqInlLPtiFyhJZifcJ_GsiQ0U4SZO3WHmvSG9AHy0YnA2jC3O4x7yj73RmroELKFvT-_CSO5LVz3qRRVdlyL0CQr3lkHUXJbFNpOz7Uek4q6MjB8Cn0xAKzt9ztcClLdAA9NkR88Dy3rOP5yPjRJJVVG6SbelsE1SnPDaKQqu2ZN1zdtGUY9AcULc2dGFb4mezcbJsC_eL3DD0LwfwcSAILDfDIrqHACR0XmI7jmF_p_PzmBhMsocLnblzKTho5ufo4htqhTEjVdFywm9WIjw1N_9PWge3i3J8mSdILp0HQ1QvbRlMt13qPyLNwAmY75m4Zw7EIlk4cyxMjcTSY02TRCC3cBKX2e6xl0DIAygChReVOxL16BT21sEgT2ps24Mljsvht-fokU3JPtj3fY8wojksHAWNv2hlF62xKrOv9h9AqM_Q9JlghHHNTrzxvT8SVeLBhEvysbhErrgtTPcgvKfMUCT1JMWolxLZUSFEFKNR9cl2GiSqMIhdTL3JvA0-etZ7ykeIbUEU0jlRZAw4a3vY1R1zW1-c6XRSNiS9VDPAfcN2OD4bXL8Hi2Un7Vc_pRyWn32kWQqQuw7v6J4RB-sr3Bkb4OzUljytF3ixqGkMIpuA-LjJwdBJ-XgR8Fj_DONbguNct7MTkMtQqWU9twa8XF_sot8iEYc1UOkZQVJvTtNclIkklJhP8VNj1aY18Y1Gtnn0fvfaOFfY4wa7HIq0U7paT2Fqb0xtY62bqNM6rRXLsAQex5HvMvHQvL_9JbQngBOD2ehk7zIAJKZWzbAKqKCgH-_v4kaGBVrciIxffYF6WnWq35pQwbsvNqQG4uJR0qhLEXfc5akEon1sL2fjxim_GFcgunyCqL28lMB8yhnzA48QESW0sotVss_GIeeftSYS74zPaHXiuSx0RoAmw90kERXPDGVCRkwTTwaW2BkshCJCx2JOSDEWVRMjxngzaoroybl9A1VzTrDEbodeq2O_kVyZfrZE58BO8DDd6ZH07m4zuiL_NKXLw23NmC4CuAN0ufn7HFtX_ow4ZJILfZI9PczBi16liV0LWrBwvadZ2Lf4o3sV65CLg1VKujttEiOhtpYjmB9zIRLfAHViz5vgTonL6H_9N4D2dXLzUWlaDPNGJNnt7EbHS64f3jSXGG1fb7LGKhNtTHqbfBJnMpmPjFQGb4ae2kKv_V_L8xgXNpQRi5I_QNTzDzfBs4avowydppTpEE1b8WNITLc7qvMa6gwpDxp2N91fIVC9wyd0k2DXaz3VbDn-2v7W72D2UPa0L00NKvIKYecd9FMpYmkEyxJfFFr7b9hKA1ZXdqlejjPJPjVYC9XTEZLEwzdeoG6yrxtYMrl7o72M37uIRNZAj1Jf0B8s0qhPaaBfUVKtKl7bd2Ub2503LZ7ZvJ_1segaIT4S8nt17hjfep3re_4rEKA2rrxMbWoLhM4qkAPZvdjyAFF1YNB7u-Uex7l4STRYSpzl4eQIMSl7N0pGlKk58Z1FxTKHsAZTkZYtj40lptma1AfcwRPViNPceCFA36XfVjaratWPYgDhcjK8nNnAhxvL7t25nPbCXazPK1D16ZkY2SwcX7sMx8QklNQdzukZwGyP51yhU8o0PT-u3xGDaXnP6Wh_o35cCIRnar6Id9h2ovViZXJRUzNa8aXedxiFp7hLScSQfIPrPBcqN45EvLjEmtLvzzxNgHY7zw6gzj5QFgv64u2fI9zAY00B9U37bHIZPQnFAhge0466vyXNENzYO3acUGo5HhyFDlcuiBCbIZ413bmfbtRbj5W1FZMY58l1plTmNljfcwQ7Kd0PUGvGEb_jwKlmyKni1HzyyUmElGHdRkyS5Yk7aja6AJOk6z12WUM5snqG-uRVkByxCXQ2KaFR6Qm-IOHMFqzrPINkjyEJgG6KyKfkF5ScVfQaThHBuMrb7ETWMnlk0L28ZszB-TLt3HfaxINsoD5pndSSqBpHB1z_2kEweik3y_PdxIchV3CyBLnmrlqBPBIarCoM8VwzForh3RzQmgNsOGkJXy3Lk0rIr3t-BE7qgXWsrDolobtH6MMFO96Taa6MYIYYYbYvzQYcDuQwD21yGTLwKAnynBDn99bGYEg65LomsJbTSKCYQRcj2Rh2AaScsq8JiHYJEGAnRkgsXNivZnioTlkI9_5XqXBJt3GKMY37YL6qIU3XJ7HapKELorbX4fH_JlOIZLIOIaU80295GZcFdx1I2La9lp_UvAtALEDJklGNvbcDG51NNn2mj_P85vIfzsVdrfX7N_AftR8t1kQx7bdbVLyP4ls_qKnXXigfNJajWtPVgwGeroQq2jtaQw6Tj2Wsi3Itmo5QNg3N_ja3erlEHEdTo8lm4XZHjbl2bAH3n_wuEdYKTt2B3jhj4ddhO8atc1fryqbRfn61YFKUnR3f5vQ1qUq79uisQi0cvHr6DQ_12FpKzFvFckAkQmbk5fcS5Ri5S4L_JtFAexj8n2f_oYuG_9CYYplOU5i1Q84MyXUZ2fZyDhRPRiyjvPJ07_IAiL2ny1btmIFtVPeQSHVwfun-m5Lba3KgnZIJ6CRFqxR-o6F8e5K78d-bAotgA5vOcfeC_fBQfaom-EX0mJyzf7_Wjgam4IA_W3PO_wGoVULHfr7mwUw2Qc-VzITtjajZvRoT-SkVREyJVnKBxHFj2cNTcTtooSxCu115KmbtePf2OwgJocB2jyPT2GK-kIVZtuGdv4Dns8m7Z7FpT7PvjCVjidQqVsJxFQUs7ZzcTXX4vdChdcVK1_OiUwCJKiYN9ZKGA_OmwQJjhnV6gutHFYanu3Gm0m5PQLIM6Pip7yXCw8-Lhq0sxFTl2f-7DeYlfrWpYJyc2wR3T2u-kHl1g52CxX5XoHCV1LsBIU75L23Igsx5_v9ZNeewK2Qh8yWwlWZ18qnXOh5ZJqJUpYtxy3sUhHMG8fe5RKVGbbJyHltosuW26yJ9eUQXqJOSj4wv0YN6a-BezPdkkCqdiUGDHllrgAi96kkeM4jES6iZV60rTgdmfOS03JL0eqCwLnH0gP9t5Xq7l0-GUKp7mrsUjgN4Utb89AVPyIDFWxfJTuFJK-g6Z1EHexEvDY4iTsuOdq9M49_zV6iL8ChB4p5l0lUOiFzIH1Qj-gNMqpU2p0H73cMd3MNeecFhMsCfRadVCO8D4UN39W2mEXDxLBlTN2f4m6aDKjLHi58zyDiJ4aga_ntZRnv56KJpWob0A-4U6_GRJI3OynwKPfb0wpAzK8Gm6Ak1OpxvD-8TmbKUKVA5m55PMoBgGbmvtrwC9Q9Exg-zdotpZ5-iWM1ssnKLXobFa2SmYJeOcGbEjh_yvRvjBRNHxWmq_sP1ohPCTce4Pt97WVQs0Kc_Peb85RqZEnCyjRfV4C3nFUkTxJhFJbmIBPG-VPJDfKEMVTtUe7xB_w55BKViE87CTrd9AAveBFKkBrL3x4bVba3SK5HLU3tOgUPMDnN6Q-waVbjTXsNPGPwJjvbDAN-xwm1V19e-gYcI9sExy4hH9fCkx7Y93e3EMo_EvPA8ZFO8C-KKKlKttqg66BlOp_WYj4GnTpurNDHjVtBQZI6FN5HGl72n7ZL0me0cbfiDkFh7mIfHJCc3EcRCp__gjeBYQaGaR3hh7hLrNeuJB_oAfW5mz-2mIgUYz7vGxRrTeo9CyNYjr5CNwd-hp06pklYw1Bmce-1ZqG87pwFGjfWaAABwqNElf9Wdhgzll31WmopAxDC12Q8pzpAiFfkWWeHsPgvx_Hfm6B50TiIn_LCi8hjTaVUkvtNxZgiKJdAdL5btiUvPwVD10EkysT4dfAEg6l9Z64sZT6oss0KlH55VrNoLOybfx9-TGJZOCB5Zf7JU0KuA1Dpfp8I8TlCOUBwybFvNbECafzsrKB8XI6cmvDtsG0NqNzifoYUPzZDv4eNQhb4QAxlWx_xjiD_G33rgZ27DfvecgVkhDUc317uWUTrWt0f4WJItv4A8P4fj2CDa4cAjfe9CCWM8oehppoxScG5nBFdeebs1m3efdBi0VlYbJTEFQC92q0Zdr7kdfo0FbR1GQ05x66u5b0qLRqqsgF6n72p8Vo_izkLs1N3HKOz9AvcoTmD_tD70rZC6SVJ0jQcKtOMre7VK7lJQJwkuuUL-TRcVYVFeKln1CDs0zpqwza1iCVw3LcUdh96iPsN3XcHrH9pqUxSEY_T6Bq8aSTHdf-iqucTB2u2zsq5BgU40_zXUqvfvQRhcHbaNl0NkdbWKVr8AA3KkoGHMe-H_FBRmyBFX2KL7F4naGngOz7crLfNoSqvPF6cBudn3Q_PPxutj_F5d3FxcfHSHizhfZ3sC39DiwyKgWMU4rUm4gsyYpnKQ90aXtF9nuLWDyNZEb1hsHiVyIoNkUx4IznUY94rrMNzlobnMyqtaic819_vgKqTo9jYA-i5JgMoTPy2DTtIZIpU_p-TggdpEActJ7qncHdQjM0mCrZGYo78NvZ0697fexOgo-dQjfUmNNKNtLp1UQiMBllHwIDZzRePAgOeisXx-E10lLdPUm6AKQcg6IYbvrPDil1_EaQyV3JXqEgNCZwXvkDIh2cnaBLUzyWsep_iupiypilShz_QWLsa467qw5dJ_Q0vR1ulAzMWokaCmTTiJQ6RL71J4WBiGAnobFDrluwJtRr4BTRNDmzDBh8_G3EKTS5mr6W1EQnFnMAqIrW_TOvKasBlQqlLVcFDlllp7X2akyW6Z23NBe7JCnYi4m1HkM0_gnHqnFbnT3cS4umAd22ugbPbo8gn0KRoFxAZK4_4JPHbz_T2itrnDcl4z6_50F-I0Ynp9nHSKnlG5x5V6IGd47vfF7sIks8Vfpq8LUKgQu2g9XHzwf-q_jmwH-eokmnUlznsJnZWnz_GnHyeEMsdQbBKDGK9rjNuMC_QZGuiaARSlSvP7hMyowcczvtuKrN7sZc5nTWPD31UV-TBzrDnzmmsKZ_3BdPebNj71vt31hatE4Mc6OJJUZ-HPPUieICZJFiYXltJBqApmSrscPjDUy9fUoD0iJudrtDu6UJ31SFMkaapXqHG2FqMOwkEk_T5wGmdZ3Y6I8QKKiI4bXRcjPexjVQUJdHnGLRZ4L7tyKU1mFJHMEIMwAer1LiYsnFLHBt3XoAQbNu7LewtB3Cd1Qzeo16USsORAgO8DYtAiu9T0yfTOMAn6lfMgEIdqdJdY5KiPC2TWro08m4pn3mhDlfIWB4XzyBsaO8JiRlF_7Dfg0UpDEnk2AN7ACqsjeUoMk5478ov9JeTPOnCDw2W3x4-w3VhTndvrAD3OrnDoxsc7OcoQjni96fsh-E72g_FKaHJVqH591bROjD5nAPTj5rseGJYDTJkAlHauG67pXgIpMLSLgTUUeplBgjDDTWPdww6dYp8yW9CJNOXCrqmAunZDJe5d0n2BmzGLiOHxiDLKT4-7XoycRXq9adUn2uWgHUooKJbs4BI9sF_28FhxsbN5E2KT4b51aZsK91802OXcSbLCF1K-HqxFNeELpvrlnYT4Cefr_gQydbzRvzSdpTSpUTLtCspJ8RZzJZzQT6x6DnOT8KVt95Sx2OsaE6zCOEBUf5EX85M3Xw630kFQPAjAXx85FxEos_Fl5NtgSssugztP0Q6dbXJTuQrsSgSb6TWsJWaC6agqNudU2lkI3lWpxcxjnYdlDisZE2CVtPXIbMc0fP81Oz9g-LybenNrYDUdIL_FvJ9FM2ZSAleLrEgMM6IyDUXBC8PXA7QP-DukpVBDGkt6GRaNqiqMFN6ceHu1IcTRy8RBucg2ahZqS9BgLlbj2xGANaeZKjzvNKBbtqawx-RkwsHludZ4I6WaLC6-fCnqE0GuK3kw8mbym6gAbfHouwbWarAdtesd3tjoa620dCNg9QwQ1Hzgs4Fd0pjsSgMFB7ahRSDy78GWbdPXZqPollN22uUgQ1zWEva_VxrPK2C05iQMPE4Cg5X8XQbxGH6GY7wuOnc23Pvh9qe6po8voXKaUAPVb3oUGgYx7lgsWZIW-2c861ip10CSjcfFm6AVrS5Iaf7m0OZvUvL52q2r5Py_LWxLbgf0ubrDXMtHbhEGXYmiRaHcmuOxoFUtaqCB6kr6970im-84hk-SiCoL_96yg6Bna4isurYJb2JQgGktUX_SjcB4TshvDDx-G4H-lUYId4AaqP1zNJ0ryUPOlQQXlKtc6s0tUfEZu5SagAE6h6iTUkCr4hJ9hLanj_mMSMJiCjBCFUYMeZ4LCxzQagyR5qWxq90n2HlHhmPy5eCj16DTBIL49ScuUqyN5x8fWt23H-B0VjTUdFEVk8FFaPsSFv0SddM9LEvrlUcA-RcMpyZ1a2ifF7N_HwvRlMslVSzW2BUZRibnB0xpeZlUbqy2CDkr10azuxJYajE6giMCnSHfiKM2EPMuFl5-sX6FiyfsTIA3CmcdoHvd83KNQbMuDRp_nDCAl6LNcj8CXPyenI56CAX5owOddnszaI3C7fEfW7MavfzLE4KlNBPYeFmQLL7w0Rw6uZfqjBKLFLNtXNDBnJW3GSWYKFB0QiAMjf_9_nfOU0w3cwgnfsdmUU0BG_9bXy-qvzYvnWs1eLfoCfruH7gt5Bvb4iGPr37EFMI8yv-df__xbRHgDxVtAd-A5kL8N8DR4U6eSsw5UH8--p3ZpLyrh9vklTf4LDr0xt62qvZjUKzcuMZjQpcBvDHmKRx55aZ8BEkKhIhsWlZJMsE5prZOz3pwT5_pAp1h9u7sw60NnWisoTdBM08hP-JD06OWB_OFPa3I0x1boTojwlzVpiVGUdNeMgpWKa9wQj6rVsEl3-UFIyrKNpgir2df5m5q9vxZ3TSKawBZUAQJnQp9aYgysMtCnUCNrZ-zaC6mojA6cBLk-g5rCcXsyd1WqkHrFwYoPAu5593tQA-ttSVSFCUQxCILqKUZx1-fw2NIchE-NUak3dAZ4RTWm6EwMGXh6rmanI2swBjkglVxw3CfmOAsL7yXEhm2tOofu5EoADa_lEdy8ihHgsCPoJiq4hxlwFXrg9y-Pww0xsrldPuFcc6AAIpPR9UrKHoEdxoDnANqi6zsBTsp-VdyaNj5nFWgpm5mxgnuWUrBGif-U5ldingoapB0hJ50--CucJyHaLHHV2m7WcVDTXiykeHhjIp8qnKBaXwoyezqmLgzIOmhrJgqBH-drr_Usl2Mtzq5lyA2if9MFtKcktldky2GXDiMlwLWSf70Jj5d2Tq8_4P0C-StEZ66V_PkVarTSrFahni4g1OqUJbxxsK7oV932wEtpHJPo6MYnkebOFGlGQlxxk6OlqoZwyP6xbJCwu1_36FuIYcl09Vy11EXK58g62eDyg9eGaAAe1mU4fTByEowy94v67qTC9otmjGlB6K3pyqsGnpWEGz5FujtRPO_ChDNN84qZRMSk5QMU3jx1t3-_0Mg48WnuWGiDDveAhZVxNz9HThbvMviECVk2E70W0nj9XEybPhNLcKQxKMekE6_3qJxUTk8Q7KJpoDysmWznz0Brg-GT6NSJG0pFFfgdNCAK_K5G9SkdnS7Pr2S7DcDIasmdvIciCzw0Lv7Z2rZR8eiica4lrrz52lwO-rD2380r-UgaLsbX5PhZDc57JSkIKnAfS5qeqxK9koKyD4UyR-6gfA2SsoRbxayLigQOk4O6bIDoJ0ECvEoyaJTohselYUhhQDuwaYQ3UVBsxyNzFxXv4i_ldHItOjckkNBLTyz0rfh0bAbqP5ROsXG7Q9OIMglRSRyDjZdlMaRVO1-lXy_zQ8AoBxuAwGOyc2CQm4zvxMjmiAyMymBdZS5w3-aa6ILoaqvhMzYTEyP8pojxTER7-swPs4J_zroRVV-USiheF9qLRr8C7WtZnzaJXYhAap3HrTtfCVMAy8bHYFjk5zYLmVYw09C04sFxQ3apXWUc6A-30D_Ix_x-Nh0LmnhBXc-BiCPdaGA-iqaCScX94nyMmCC5-26KpbcKZL9qH6ZFUez72d2gmu0oX59AgiJkLaVqmWkC2fKMc-GxO7SI-tzO8AGmi2G5vVeYHIwc2zfRhHuNn8znS7SSRKD1uzTLvJzt0Bonu6NLukVUamhLf5SYmHR3Rd9Qb6NNprHYCyJkim-szlYjso9-EhfRqt3TZtuNx7zbXIoJJ_anSIBQKXrWpLJHr4CMexa0xlnVrB_K6-RPVBfKMZWdcRc2cltFzo-w1VvqOzmK_-B_9FkVhCdObJ-aak26s2CjdzF4SmyetdbUt1U6zDx3lb2InlGz544dNY6OjjQX0X0ImPVTlFAFWFO4ONwnUp5GQmqBjYQZ7CYKqx7RZexDqbmGsW33jnf17hPsToLphEo8M6_p9-I4-PSity9OSX3Gw35Lon-myQxV9Nq_Ui9Mtql08C_Uyhdqwk2FH8wESENlRPoM8Dq044Yj0gHqwUj4xqUht8j9Hk-au6fYM_fLPRyXv9jqjT_KklnmfaeAqZOb4hHRIFBxXA9Q-1rreVfYFWVMz-FRiyf3cWd7QQdMciuMBulWeJjgOUoZK3vQIS5f4AZzwYkNOt6F96hwRtdI8bU6tKJU2afAeqNQ6xiSa85tx8_YGzMsrdKdWAPQIKe66QmQLlQP04k_EoSLH_f9dc51NZYfGF8YwzJuvclpqtAeMNguhPuGj-7V5wFMYhni7osiiPQ==', - provider_name='openai', - ), + ThinkingPart(content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de'), + ThinkingPart(content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de'), + ThinkingPart(content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de'), + ThinkingPart(content=IsStr(), id='rs_68c42cb43d3c819caf078978cc2514ea07460311b0c8d3de'), TextPart( content=IsStr(), id='msg_68c42cd36134819c800463490961f7df07460311b0c8d3de', @@ -2422,36 +2377,11 @@ async def test_openai_responses_thinking_part_from_other_model( signature=IsStr(), provider_name='openai', ), - ThinkingPart( - content=IsStr(), - id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc', - signature='gAAAAABoxC0Pe79v2UqAMj3Y1BkJi0m_G8llzMHMeav3XGlfPIsphSfHvJVzbyv5s7pvfPLs2-ECy9vhTMaN1UfI_PYmoJ17y_k_lLjvC6sK7SdFeCmdGNjbrgIcah2DJecVqDdoT8P0Aaz6COw982zu34UyGL59e5FTol9mAGvtInH9vXmmQUnGS5fGktT90wC6-MrIxBc3Og92F-e5ciGk0DAVMC90pDTyP4z_Qkj8Jv1QYKqCv4GwFO8LyUicPTbML6l39jyTfH8L86uDWMMxKNsvHEIrqgTQnsInlwnHYVbPURb93_gMtcjOpZwc2ESnjqUtMLXzs8XaKxhU2NVBAzcXL5x2kg7OI7HbS4Vl90Hx5cVwp3i8OTfpw8aRhDoxZJWptxNBKwDDEtjqLbylKQ7m2uJ8_TkK030O0fb81_W1-36qeRn-yNE5jjkKTezyHP0DlpKjCzoY3pZ0GtIj0FRDJOJJOmbHXjC8HfrwBz76tIA64sOz8P5lS1parnESooZidtVudhrYPl5hgZ25w_X5JCOXhXBUGHFaCkiEYUZTydLK9i5W2nfmriUt5wxzG4rSHSq7B2zqLi1GdKg1So2VHEPRfL2GvDVQiRM3K5TPyrjVgoxM8rhmQp65uQ9pM_qHhzWAAr5BvMFVax32yI-gtTzOn8_gC89MleQkHueUbdLxiUDjesO8yIIc2rbzg-KatRma92xVYOS_P9uxzVR8ZI2VuhRfdlrHbvvLC7Crp-Vq-vO3XyNooIl8N6USQbSSCG4m1mt2yqcaUyUZBLPLLi2_mE0g5pF2sm3PRCEYiWtT26go3tZt8_HLF9exTvjOMny_CKAL7Mx2evk40fqbrVY8su1uhqK6AP9XxfkoyZoYWlBkQ3vVSUuFC6lNc2ACGfUFSNqJtE9XKZnwkB3gzw7N5zqFStYvCAjhqqoxFh4peSUf4oEdDEncLFQbct-TFezeTpxEe7wSSMYm9d-YpV48Ne_T_aUMrFevTEnB3x2oqY6M-tokB2mOOjCVJv_QUbDbjigVmBpuOmW_NTTQmVxRIO7_c90ywoMs3KmVmJXgV3Oec7Rp0tC4DjxM3-MznjZ3ctAuO25oxRBlFE5kABPTAZHPwX2nr9HNbH1SyE4GfmzHFzs4qkFNWXMlLcsgrHQ6HsyHoa00_eA40Uy4UucVzS8pDHF3Nt4yy1pDWyRGIkIyp-ptbkSac4Ceq8Gd1CVak6X-xpqe4kdk9Db1BjyBGLo9BMBbAwT54KMwEUrmqRFjTBl4Lqp6AMtoRRDbxAWzKI4X0al1g64B9S2FFKNGm4zs0bDitII2LyON7BZe7x5Bm_agD1SbkdHbmpOtxY10eFPdtShwYPYKr3jGUOILARRxYCICiVRPRKaNvoozEqy0mQVyGREv0byUp3r5YarGhretLddtfZIqFPYcdJhoB2ar25710xMSdnmGGKze-yjxFq-DVKPN-ihWtqpdFaJG93FVAO56v_jURwNM3zIBkTjEDDU80wo6hOiCrm3vjmDN0RzdsXo17WTs_QrD80ZDMI3S5UBqgJqE1Rk8FE2FBZvgQOk9kqWwhVt2XeK7KsOO9uHEMdFthxUTzMWdmbByQBPUeHI-dJHKkbl8kDOc7ljnN80U-eI4vr66kBkg-evTcOLZILsJ0-7IXaTDCiszLae_EbdYeXEIRriHsp63skqod8golNLWT56DkZLyNt5lu8ZE8Bp4QdkSL3rcNv1GQg-sT3DI_bOyQuHZ3zP5-OeEFdrI1n13KrnuaecyDa-lYU23BlGuMBDC3Q6bld3FPcHswew-H0sYgJwry4lhi1qMCRSzQVKvfUc2V658fOqpJO_85ssiSfzkMzNnrE0G1uRPH5_LUA1bAfmoLU5SkbkajMi35nZJzLTg79rVXpUtK8l2xJAKRnobSVKzPD1HT-b1x68vDHp1jFzeGPaM9z7wAC4iwXJLFDJhI_U_uoomw1d5lb47WHuAjpj0Q8Psgk6IMKntdWb0g61GcLZ9OoRyKDkjxar6KtEIZ1cyYVxUGTHTSKKWyrKvhWM9koj8EXkMeKtX3KFleH9AtGBFhExeSPTSJcmnv6t1ZVGSclQxVELOZh-RusLdy-wL06mT-eiBeHGw1H-0S5My-Py2AowI3aBk8YyDPGVH1pCnVfXTIOdQH6idOAsF6SmQahhjxr2KvKPr5Xf3zRAMrlTw6-50HgiEBibhSSWr0fxtZ77dIlesxym_eTfS2V1VHv58Rb3NjFIpL2ayLI6AKAnq29U7RDPXgLjWF4WoNxGkmo6Cc7dWIOsekjQuAQUtJaSSObwP_2HaMwfg5QPdFgt8KkkqOGsDEhXd2Si5ikvN2OFA_dUigfQ8aevQHqv-V7n4nFG8XGWkgfSdYJWMt7Y0SxuBJz7nlsnnggqjRrEI1C5Ae_HjlXKtH9WdYygzOtFGR_iVm--LWQE48-EIeym8g5Q6jwqAbnARFiCcfHyvU2omiGdiN8G9FIVRetDqWUDmdnza2GbJJ0JvoT2O8KPVkXZt8_qWJvTFuJ4Cqkwr-n3aa4BOQQtkB1lELR5rXed2RMNbReXmalMujHSVozgilhQauc6D89CY98ks4Yce32HbUOF753_eMD__ewBxA9DK31i50MrKQVID7UvKot3BsOK4JH2ExIg9CCx-mAbEL6HatGwoiE3zhX0RCO2OHYf66jrbKJ220wTH2O6_BCkihzNKLqTVmpYpPSprwPkkMBNfQTgtEJPJWp9hPoXux4g4z0EtYymZpC4sRVxpBH5mvno2D9i09fh9LM4QT6cf1Plh-6Q3HCupQpiq65g9CmAtJDEiSoIhrxYRkuza65jjabRvkudS8rP4Wm5Qn5ZYlykXUIzC1BVSIvjZPK2OLw_vLG1_iTbsBONDeb9AqQaXiAc4oHqUDSp3RJXvjRfQFNI48eVtk_LLkDd1WNuwQtzAjLAg9UZA6JZGLn66SpFpU_F_bwfHvNWrQ88ZieRDdQcbyCDYNJuqMMq5YOZBpz-Oa0Lun5L8hhUGB_B5FTUQPiiLVIKuHPJP0qLgC2o_R3u9VNfgwnMENnP6pmmVI2mPMFJSHEuDeShRshUSzZ4JOs9fnvpKT3TlyXFOeAtcn89Gilua2ziEfBy78d4Quuik1aL1wQtnr3PBTbn2Z0JGOPZoKybk9CF1a-1K0hoEK54-jRgTrPGseSMibhGO9x-5bW5viQVORDH1L9g2kcfJur1D-04cDlzkAB6hfjuqk1pvT3S3O2UGU37CZcVF_iolUucC8snhW5uhuvSdoBXXcnF7TuwsgAKNvztnf7B3tPJTW8x5Q5PGqHmRsoilCFlbslJCGq4h6NraPfKGY0Qq48A_i9QQGOihf1BI3OJE5usPGaxe6yJTpGQt5xCNuMCI920xIfCuQUx5BmVDAjho7EPkcDHoUWF53iZHPp7RSlC0uVABjJaaOREGT3oludmKOYY4PoZGMFNU_4Qm2UlT_OQ3XXhon0dcjT9j7OffzgjOiYy1HUMGpSyFdvIotQQSfAzNirsXZtZX7sVKXDPtOwzALnhd27odnEnYHpep03mmDI58plDhffF_rnw326mggOpYGBEgFNdtQCwoOe9P73E3762lRYHl6IOidAG6oaIP8sr3TU5xXhzJ7iqSKQbD4UMwolnNjUjVCwGMsLj137JYfUgQBmiu-5HuRuyD3jcRmddrWnofPg_uv_99W9i0tLvW9pAk5YDDUm6fFruGbYGXUa85g7iYuB6cY3lArHpPvBhpgFuH8FEexXhtJVRAFsT-Z7nvI5Hfh-Dk2M-Dv7ITg7er2mCwxG0ZmPMSx2kglqF8bZTxk7EqfGVQMvtgQMZTDij5dCIK3PzpoLqwNMd44fViVc4VXNR6o_gFx-XyKY6PVCN-OtGVQB2B6f6LikWyIMaIB5Jic7zT0lMsf8n9aSgi1UQdiR9RuizqInhxoW3IcdPpbHzyYKMyfsgE-VKX15pPOiL3stMrq7gSmX4itErJBKq2yocNH4QHjoqFsndWK3VNc6rzkdcZZqhu_ZN3xW31q57PzZbNMfQ_IUCuNPwcTCHnBiQVRZQaaiXvyVBh2NcBXLEdqr3Xuh8Q2BgCo9ZiW6fdqXOgSAd5gwxGOeQ_Cr-HLQMhB8bFE2szFWttri01hxyXOnpPt6ziDw_t4bGYB9WqaEMjCe_3iUgLjniX9hwPuQVhTDHvwkTaddSQ-SVE4JJJ5-IY7_0MAy7_swITfNP_7Wd_-XrdJ-PzUgKdKs8E7QSd2hpK6Vv7SGlsEHzPxljtHLsvEOGeTxkuBhc4KktOI3ezaooG0IgpQr7d7-viS2PF2Ri6-zkoXH3fosjCc_d5DtOvbPn_hE1Pnu-rCWnilbekyGhOquEAYsErlioLhpSaP15wkFzcZIMlV1aEPlrM6WzcCJX8cdeV0Z7fL1v7R11Jhux8h7bpW5Dm5mWtwpfg23XtywAcSXB8F1GuSZXJ4CZHq6vj6lAUqS0YigZBzMZe7UdOZUIK0VFTY1Kl50eI9Sptiy5AEPhDdaUT1daa-_g4BqJtelvtpF7XvIpPvEtlrLJBjimxCJU28-QUJDaBeKa9rtQTWf-4kyY05ITG9ke7qUnC9Sc_LDkeCEnDNjzStbf2B-r-ov9f2pUTJXDKkP4TwwiZ-AlDGHoKExZLJQYsek_DHS8rzwbRsjuhnU-toirFjZ1nH83XcYh6OKaE-7EsoUXWs5z16ntWeNJpEifCh5JNZJ_XC7BeKiL2uldqu4naYwBnwrrz7v2UAxOv2KusUwC5WHjkueRjgQtgS15Uf3khMDZYxMIKJeU_27POO84uQXsAVdPs_L4yL36hqVdT69WNfJzPuKsFiGkheoxC8SdGCaeUgpPZ24KZgDE6TLVaYin1xRBm3h-HxpAo86vjvM5LnpuVAy_0iJa4r5ozxhfjzJ7fPjQSk835tjZ8hls4yftUJNpOJM0cruJT25qsQS-RD36X4EF0BSPEdFJdN-z_CQK3LfAKcNSvO8UR7T_FEFzpH58qS98DR83avQuNx54lQ5h9ICIi3fxSHs1eO7c5m7jaCV8VHL6Mjkniqf_ZW0123BZxC2AeGcucAD9iPYeXFI5ob65AcL6TA3k1J8gOX58RIdIdzW9mkwMjJNMNEWYpEbsevRuQ_APKGJVyu014wYGeueKk9jQjgt8YQyLC7bT7eQKNrhWrT4Xfib6neWmhV9NRXVB8o434srI7Cw2sJaWSbJGAKgov2m-fvSEq2zqbNKQNqguIqsw-QvubN5u5c00PUldQs0zISnVthXAWJKlmuNxVykdN5HoDkKfAthnQv2pVc4mZK34DfcEo3Xc-1Ssysg4qOzHR4zTCY1GFX9FVKvO3C_CHI27gi_3pFjq3CcgV2_LZ3_p0g9IlCy2-6WKcRzBf_8jbuLb2kw4zGK_cG06YeeAzzMqPrtmx1tEshJF0sKAWWBzYYc2RE1Sn_QOP6YSxei2TKvB3k8Xvnp7TK-28hcJIDnZIbbU_4TkuoXz_MwbNEcE2q6YMxC86WT0qc7YXxAY3Gp0sNOypZ7QDxz8kBrzo3px5j81zDq1kxF-ZEIclPuFCXJ9s4NPaXrkjFmWnTvPmVc9F2u0JmkNgl71WaC7pRar3QpD_kbEJp-zcOFzyUnteiJKnQdbTdxZal7OT2GyfNDWpfJ3wmRZHjgAihyhDeGR7bPC95eMwEfp7ggXQrCrfLuFwMtkFPq539rnmbQ2D1GoW6f4RMtkF5p9UyihUaAjP4LC69e9dH4A5InMJmDpPfExf-_PEoiSgVTXWC58pb4DXm5QcvZj-4c-NDnlbWb_YbU-skdRq6ReAjIjWMNdRUoaU3b3EpWLTqVCsN2ZZNmqp7is5oGJG8Xyswb6VlGQq4ij5ZgGRE1YVVzMnoBVObpw2lxeDPldsK6ZbmzLq2cG4glgKPi13X5ZlQGb7eVdAgp9LZehOm8kOTljE5sLGmYJJpkmKE6hiddQeG7wxRSqcEoIctTRfMruXQL4gsPXgtpaYsTR6vi_MVrFSobxf_8DmhAkbUHNcyj6H1HVm4JRA0isGBoicUxzhybBn0heWjprPfnOD9eO_YpuUXxBrlC63LBKLQmsVkqkNI2mfTSKxVnx_f1QeuhJw4Rrp7iVyvCCE83XEr2uujo9uxm62zHvu6FHlJBSpdeX11DGUkXLScUtkFaCgHw8dcBsnG7jloDKJFOOs3i-cxOe-dWqlaVti5_sUmCLxNFIBk2TjZP44qQ7pQMT-Wp7b0o28IHGkaiIebz20xiWNOSYstZwq1xYIwhnQtCnAibqxE5kc6gtZbuF06NqD1h9fROgp9jdqGyucjHXs0zlkO1sBGgkz-8VnkF97h3rtdkqWSTZweI28dYQ0GYXagSSIgXmQp0QM7pzDp_JO85NYpR3CZW29aB6gdzuSbDoFciWd2UTsQX3HTEIsGxhtRtMa4ZPHyS5tHAKSlquhLOTHMTQfi8GO_VHsj241Hk3S56jM9Czovx-5OwRB8qKFNiHwKOvliSJR1HgXBkAleRIALJ64fDz5cUgy6Mn13Loue3JcowCAIgkrnusjVLig-y95xVvbs1Ys1rUFFKy3mmVaVyYd4Qe-WBLG-pZXug1z8gLTEZkY636ssMr_wIl2Zl-ciykcbiH6S9yTY358VqZgzQBS-44sQTdT_qelrVSNMLKneMs06JSjhSJOpmogW1I_hdHMtxkkSOQxKINvyEHPFbIkUR734qjhDVUPweD3IUQdMJ995R89D5cl94H0REAU_wJxDSGwGlux1P9ul1FHsX9hGTiNU6cE_qAD8fWX5ceOBa2iCoNefiQw1Ft9xh6QYDe2lOPdpIeihKm2ABWMVJ3hGCYwg-QPhj6yrSbZ4DSxCMPfC3NQ0Zarj5VgvfHOIO_gGiE9plkknoLBM_j1VSP7prfUOXQsA4sSu8eYhkreMkSVRk2JJ4JY2u1s9zATCq4cTUcKwdhgasU-mzPJRc0PF_7JsrojJ-GphyN_vGSzv_kBtl1Oo7IIHNo4UYiMpioxeBd3UV44oL8wOgImfs3a1Fnb-fHOS0RHkn1P57V-QGQcbQOoXtSqcDLjCJEJ144_QQa9jSCRUYXVv5VEYGfEcpaeyP62FFvLkeNfonGiObjVxXM2mnqV9gXm8Tf_NE7HgbthKKN9zbfOSyHos03LDBIYqScCnENopFX6XyY_iHOZwtfRojYmlZcfbtM7AA5K47Ycx1hC7A3U3x9CjHjhLZhqcQXdFeMNyfbEMabj4ESo0vqfKOFhif_U49MwLg9Q7cquuJ7zoduXmiBrlm2hPgzzpEK_JBC9vmc3FrxbBV4fZKr2EXYevtvSrWJ2-trlF5u9WO2xC6oxCuTUVisluvCWwhy0de3tulbLHlKV8xYEh_MvJy8tyqeOS4Y5lLtTtwuA4rTVNrYp4-otD6ZPQolK9k1vGCQtuTbgUR0Ya2m7vMDd10zU79haM0C6y723o3meJ6Yf2tIqffTk6YRpDw4yFiM0xKRP1NvkMT8T-3ptVnIBz4laUp_HDoTT1EQsmKYFtgMMaqTRImxH75v7FW0MGXT1578lBSB-PW_3U4zR8NpxvuBfLrzHcWOQv1bJ5m-v3ho91V0wXM9X4qEiA0CbGw3UdrrZ80VSeEa_wU6mQFG5IUB85_AaMkKjZsqoO7rZ4T_GAn3uqVmObN59eCgERccyBogj3s3oHk8yEXIhtzIC4wwNbiNhPBVako-_6YJOU5FnYu7VXVAWBNZsTMi9XuZY9oXTQLoU8Ya_Ix8baVrArLSAEDUih5mZvtgEzn9rBRJEarsCi5VMojQk5vzDpKjz21R7sNYTaiNikeM7AKRTtEa-N7FtdO432Gf4y4BYTctIi6ftUPj5mRbDm-ul19u89mnGx6VA4h4GZ0oWRtCP72svGw7zV_I301Qcl1m9TxFRCZvqDEvbU_GaRlL1VzR_QUOixSfCMrlovCtycE_zXE_oyMSjPXzA17wklLjG-gEFT0FUcvlohTKLlQKAUOvkalRMsao_DoGOYRfd6e8LtuKfaRnat9iq2RJ8OfbZw4kLmT73kaszYaFDPufKFvXt0nIxi_ysbX28Y5zZq6KHKwLmcceFqwwmZV2ayAvYjBZqBYpPLTfvEUd0-3n00bXi0hLP8Il8D1F_2ZcrQcHyc2g-g1Z-rxl_XaFnipOWuqRxq3ocMZLZ4YpUmMMA89icLRAoU9mG24RHcMrzkPD9IGUZv3SJVdKwcbmQCD3cBZBb4PEFenDnLbx51GodWRuXniQ0bl4cTlKbTkTJfAe3MpOuUDkcM0FXfnLdq86Hye5N-ygCdFfGozi_EjxF1kNQ6ItrNb_0i9eBhMTgCFHGCVBGWamswc6tICnbQRCDnUXVnvr5qqjno4w3hlXSmlE5w6j5yv7CskyIj8-rsbKW3zZTLMDHIyRqL4xtEqcJSlk-86nfCQj9QVXB4O3W_HLuyWo5cWoTHPwKlArTHx8Ml4Vub7qsgFvEnFzGLwd9QAWnaqD7ENALvims52mSBivuiMMR90nh-jsjbOq6GhckHhWRrtDlfLNcaTVJz-a-s7Zt2Hw-afODG7EemMCtGVRDDZn1Eo0katat1aXH7GU2LCfh-FP80eajowVmMYb5lRHWavhRwpSGTBOsmRECrJHym4ImOGcnxX6VE3Dczh-WNYYjEa0Q4OY1y-S21xExqdgx3SkaOc5G4KGuKdPCh6FAqg4P8Is0QAYnwnjbZZ5mQHfy-oUg1tzbO7yPkY_LNV22NlVqkUfVa1cMMhOzGqTOODaw5ECto3kW1LrIhVieIvKDUnztMMVj6jU8jjZ-mbaOc_Db0JLD4pgEtSmWybS9TqiGk6dcJGXOjDFi3PjwDCSKgwND_0xpTE0QJnumUhlflz6R1sFsE5Nc8rV0QglWQQyseJm-h-taauAkIBzyH3C0595Jkm5LBlM7V-bxtDeFjx-LFqB1rslSSW0dhPxrO6JAB4W6wtyL32UIRTGNOrgh26yboEvUSSZjJBeAO8Tiv3BCKTep1i1d-V291rJjb7sj2o_8XWaNm4tpl04vVY49WttNCxHJ5fM1PuVzbRSoOEF2btxCklDFhp5t8u1Y9mVnJpNMmn5AiCXZZSoyPqrv_j78QUZZXj-x5xwVft5363F1LjjoZ5s3LdEoGbsMAUiwkm7Z7aSr8gmV3uzrv8WyjiJjlc-rpPTE0RHbK_Hc5L9x1HYTJXECSdwZ8Q38yg6uc5EpTut5WPyScHFiDy1ybxnBPPx0tWas7jVULTZaeoGbnkUFo6xTJLMd9Tzzl2IM2zpgL5ZP5c79zxJvUtxgVFwTVmqMQQESj-qXikjBmaXgMLUb4Kv4n9655bgjr3ZuF_rxDagbRdt-_2pgf6VqsHEsaZJHwIpxh01vmyp6ZcQxzSUmi-8faZ_RWCJ5iTpHrMAHvrlPzrerOYBG-RGl2pxJDCVYr_WyUjKbPDxWkjKopcXx0DrYu1C6Cz1-gtGCT18LqoW73MCtdcrwKUXAmLdGUPFG5UFq2vuqItkeXcB1AA2hUhO1rzWYqHnqy2fXm4xtBgXMHVK8dqiXCmWWJ81sezBMVYDUP4MvpPkHRFSLdmG3YrZr0IwT9RzyyDfGItqWheKUJ7fkv0koRczg1J92z4BbyVBzdnEQX4edyyKCYd96ruWi-lEILIFHCY-viwPOIP3wCifcKgMCNGOzaTX3raFo2_VcNfvDSC8cLQq9X0o79qCE1Jeog6jSHUrKYhGsjn8mAJcdf7VzAjNsMpXypG57SMUBz4rd5QGvw3uGTs6M_p4BhciR8o1yOlqCjgRYyxUbCukRH-Od8QDHjRogTAeMjwL_fxEOIKf0pXWw_L3SeEddEfBDGaSU0CWPtCiEpUdu8pXQ-PEPvUFljROnxSr4Q4NQAro_b0FL2Lfk7rSLVJ-mlV8HpUwggz2VC0jjriGZDTCQmLCGFtyYA4qMeL0nJyUD0gfujHGMrqjnBP_TmwUr2qHn6y0jVreD7SpX8ojSYWeO0ebFHyBu6LAJy9VLS7d9Gu5tZ9EVVDCd7MfbDozD1UTevnfxnyGT2-_3xJXnJ2fIzISqkV6vYDmvXAhMHwggCBamQ5VUb5Ri-JQyAOkH-P_d5AzM4vLH3NovPaTs41-EZ9LoA_ACgTwMdXcI6yKNhvbYfHK92GWG0k_HUoZp31nOrUY4hsvoDr1VyJHeFjH2WulFKr4hTj--htE99X95MtcYL1BYJ5KZVT92oX2m2Tauayqr_VP-iYgeiC7WWoo526r5jVWXs1ZgxtzXzylpf5f5z35G4YMC37RFlzgY9kDaeLkMMqUvQo4GbEFbLQ5rF-9zMA2NYFKC-6fUh0hvN1UziR-Co6ZhXi5KP1_3aw2sjSiEwlF3umF4zZcIKjKWtAHrFblBLnUyp79qId8ibcUQm4EHQ92CnkKtAf_e-OB-eZA9Vz8NGagOAFdyAtOFZ17MBcv049eh2izFmxKl4FctOKAEIU1HVWv8IWqmlDyQvsUlwImE-0YFl2EHPizSCLgHM2FgRe1a_k4YEJnQxONr2GUIGL2x8mDl7aBejUmYkkyrCj4Y5XDS1RO_hrmhDB9rAJtukT1PozIgqJTGNHyH_99wqT3cfG37PPWiSuGOG1Rbujp_by2zqGmJx1PjvoRSX7YO_s_apGzAARHZL9n-xFsoXqiJkqM242r7SHsMrqkYckG5IyxjTrpqDWdOSe4xxTc9snA6Bk5EjQ6kb0_VVG20g6kKua9Qy1n-6Jj3BMOaBHcrP4hKKStHySqqLCPOOrqn9hH2s0YKsxknqCVcR6kkCbLi2xD7dpBXmmc-X5MvuK9g9kGBWjfjQSPEfCnhD7b8cDbvWAKJh9vmdR9ofySSWMWQUjRJA43dOTlUpuskklOImDZqitGamjZTfLK4L-gE3wDkavF___kozI04zsB7xOFdPcyL76sUumoAQ_gHA0he0YE0gamTjbJEk6p6NnzuK7PisLkvNS3ZdKqTZ_msTrRSV0IUyypI1qMB-RZDgjWgdccbBTxa9xeoLTLZM8OIEmhsubQF_danFfla5dm8aDiU6k7QpiutDFosvkIJlt5sBbr5Qhwbp-DWyDaX1TI8cCqlDoplTZiZrzf-n65eZMKAcNL3xp0bMYWslR10All84u6IlOqbiiMqIsCFQS4A-Ff3uftu6JqNl8tC_J7H2F0D2W1rDUVYavmTevdbk3MfH6vEClLwnLsB2wQlripHxv77bwlwK5g-4LWHu5N6shsdVMsk7RwdaozdpDB23r4FAok05qbNgHhgpOgu-1MnRK9res5CoVia32tb846NNom_CRss0fLhnAqeU1A8hSZPwsDChHiz8fYCVLpVkCfEX-hgaloQ07R4QyTBXY9puuuJOuOCzhe1IANS4bS1EdGOSWBiDW_Df3q5ky5LOXCOfJjZBvAEkpnX3KJyxdE8K05P3Sj9akt0eG2buFfBLL3rEqBAvOjSWA8FkSF6b8NlLx53itZnn9yiEyL847Z6WGg-Wjs1y-hWSzBh587FAB2z8nTrIAYOQkW0dWJW9Grerc2NraD-hmK4AzTK9f8dCwWSfmc5TB24s6qNRU8Dk4hZ04wAuSQLximtJh3Gv58EABNSSZO6SS8S3SvTR3rRGRYe0Op5EnjoLvT4ZSkLaRFQxld15H3vq66hs9PZo3F3ZxNBO_oDulDXYVvOfeP-16sMfE744LGlucoZBvfeEtjE6Lqabl5jbgByNm08nluPSNGAVOQgExxHcAlL2H29yvMpo78qeqLlkOw3iHi1rEleBFQxcTOE2Ql0vh7gSjgZba0WoI2rl2nD5Bbc5rlTkSa_0-SoDl_aWnpSHLSXHr9y8S1Ryphc6-Tz5uy9lCrplcuHoiF7WUCChE4gv65yf1i0VTw0QjsnwPdnq5Z_EXAou2jLuXaWwNfhIPyyl69n2zEKrKDpDIxS44J4IB5zCA_DFrO1gcI71ibRrcPQiY7Y-H7ejlrGv1TfE1FwZwvphixyc5cVoUJYDZ3pljYH_vIjKAAWr-FC5rNeJDCkXdBwGzrB_fjvju9lNu0bH8xXbQ5xB4vGoorscYBverGCtbbgPof05Ga6uVo_W3_6EJQbJg71kriFa_6haOFWz9Q4sAAOYW1aA1mrEDJY40nG59r2VdQ7EU0X_5mqkwoQGcWddMWgZDFPIITpWOo672O9Egh8luGo8EP9zhRtFIGn2vC494VBDUyVGrKMJLLI1lpoUgGfsndA9JfVJH5J9BaKRqD-GcZh2Fojj05eyJS1Bj62AoqB15nSx1X5ouHF_SkkRBZUPYQqByCrtvcrQxA32PeFZXzc1YVltoLa75LmnhBU4PBA4-KZOaGjL1EYUSU5VcZkLdQVyEXXT7NZDZ9ZchBp5IZEMLkLDNSeguPTpJyTdodbbye-QZdGzHVG9yVH3bqTB_KsEqIaJ30sjX_zi6boK6ZC7ZeGI59ChA_W7jVIT4kHWWPp4WVVlecuKDzePIhc5vr3wUlXotk95470wDp3Jw81QNNu_jRgxJ0dWcIl0Ew41OV8YomZsud_VkXBTn-68KwYcBq-rYGwVFktGpVIOvoIspZvch8d6UhSVG9LcPjN1_TD1GAJ5EQtwSoVak2I9X3zHl0bVeyJ8qrcOQcLc-4ss_YUfY3sOxrv3WO3livMq2e40ec6osSm3EfhR6RKEgOAwnU_VBkS9remIUxsTftJ2ZefPU0ql_HnT7NmiYjO1s38dQbBI68scRYZtzlJ1Yh3uKqww8CG4Sr3s7hkXDl8yEHfQdSza_YSphJWn9TBflKcBa_t05qW2eTtgri54pqNvcDE1V6sJQqucT2xQAodfMaydGk-m2XPCTuAJ3kCgCpJdzH2Ar1eBv-7XLywrFGo9ayBY1cQBOT96XY0txWY3Ju5BPwU1JlRxgitQI8kGND3b3HTDGn-U__abQUMkyL18FPXkEsD5ZnRRvhTeQjeNpjM0TO6uPvk1Xxmnr6_8sR2s0bJKhuHxC47SIospvgW7Fl9BqlCaU1UoQIuP0c1rN1IfKk0OIsAZSMDvSLCze33-8vFyCes1hHSc0MI1zU2CR3cRt9-3TE08lQw6SsUAIM2SSvfsHBXP2Ib7AnoRby4HTrRKngGPXsNIRtMzthrGT1gj1Ey9Ka33YcEz3j1PGK5mJllRi7nrCWDJQt1C9kLcp3qPwWnkq5J3b6VSgLwvdrMSEPKrIJGhB8kugfey0fJduu5-Puw3dH6DvV3sQo7WKdim3JUz611z_oiwL_UzeL48yaDoBQbfe3LH8S6pWoXeCU-Pr2KASZGM8cZlkVKnJWTKa8ne9LdBuRiDpVwVePQ5cDmUn88SYs1KEEqguwB7te3xJ_3HxuPRHqy7gTs70trvBGl8zqVNJsnmKpS3V_E1UtMGLYQ8MFApSA3b6YcJP4j4E6aCD5lakVLGSnMoq3PUof7Kc92NZSWzNq7YfCoAzL1BJoz47MdWn50bnVy4Xa48GLvQgjEJ-MF2i1txejCCw8jpQSZqHLx_PvKT69cw9UkcEzktnd-uT7BruxwIl6mcWdc0oeOjt25zg0IxB62WVVcNHQi_PSC4_kM_cvIx6749xXi_6hyui-2L5ZNQmcd8-7-y_0gaQTaijKThaSg0QtGkWv1lFtBjxxe2_mcANoTlnJPsHOvriL_brQeBfNf0WXwRgUzfUF62hrYCw7OOqH_rbQNBJbHgyyTMhxVtxc-DoGqw9QIVIwZZC-XEl_8vk0D7r-QCW1Desu8eyXl6tDy6kfP-UkuvZv4kZT8cbihvUXmAghgfRfUzR0OK9V1zMIfVgDYPflxtYgAT67creQ7Re3R8f68cVFGT0oJ_ZpN7rYREZ-mGghxVwmNndFboo97n2aLZbBXfqCfLPqMgaE0-nCKB-CYN-PX7Z1tJcNerMllFlpyE8UTw064GPNxAx9J_ZcRPVgAAFdHOe23ajDzaeSRMRKVITIUPugxbKPTWb55fOIwgWOS31s0w9uiGFrScu_7aDvrsI8pXFXLZhSZ2qPnARC6Cz6t3DQPLc-_0W3T5q9iy00AjgTUBSJIIL0WdoU1zoUyJnDY2JZLYYQxaFp1aI9AzMmm9c56Qb_NiBUfJfyVS3I9NaJq91x8QebR4IdO49boC5oAWIERJCkOTLxQUbKy6EXtxpgO1-zhBXXDPKyhAuSj5jnRa7wvRdbKXza6stM81md-AqEvDl6Cnj-FSXdaEo8glAF_XxdgA3UpMx1EyvkuoGcEcoyEsqxc5AdOD4R6cKEdMRl04GGSI7fJp1cuWmJLQqesAjK_VAEnYYrmoQxdZLw8BR1SM13XoWSfEq9dN_uZiwME1CwkTR6mN-WxXfeg-JYDRebAY_idA3xP6lcwFBQsIRebdcRyqgmiZCMyaRJ28ZwOUmpHaqJEiccfbBL0oqO5VFNP1bAq5nsjrvXkmB-a_jAJyAliToyuKc4i-VXMiVwp1jV_outA53A8csMgLmkYHrON3ZA79psVTdnJehE5zdAaObGZt_h4U1fXGGfdzuTIZ8Nr1UlNJVHwrC5Z23DY_Dp7JNHt9TIwktbfaQieUW5IR3-x8vczQewwU3lIu9KrSESjQZSe3Xr029LQpqSe3DuyWCWrLSEun0npCWaCiskfrT3zI31957vIbKdKFD_rfUzKs1byozDw6o0K19litvEClc2PQ8gZWW347WfHIwek-9qAMsRlreFc8n9ASWW_QQxgTRnBBeC4DkuwWmuj4Cfs6xwfu9b9T15jJNYGxIsLVer38U3AS6dEgtwCjwjZ0jfQRV2o_Lr89Qsj4E_EnIbJzZGEKBOIobO-lj72l0sFG5b5_qaMhUsndRRRQo3KoNa3jTtGsBI8EkMb58uLLlqD7sdIEuJ-a-1SQwiSyb9m5P5FIlyykGPFK5okoEOxzwIZSEgdghKXGIq8SQbgkQ83kHkocq7NxBHdX61Egr0V3uEEytgcO2chYZd-WiJWFLLm5zmTeLQfUl7G5CJZwhFGRjpGpYbYGcMkRCEgATzT4jcwzH7KYBMCIXi1bskCDctAy2as0jQnc5ICFzWl76doHdMVJZSvFzFY29_vP8IuVRHSW3hCtODDxLhnvDXMPGt6dOjHN-dq3_NB9mfvHKkOEK10JDpRnvz0k6gstUZDHs28a_BEH8RTb0pXh1rcO35elGh4yDNNKUk26xXKabN3OZMVmsZxxqL_JqptdmC9cNwg7XZ-S1Ey4-6acvec5J4R6GjTcPZWluZLERc2tTSeOtQoJbCJD1shS2NvR60jahncVhdp0ynV1-ZX8oAsMxKFKiB0ZtxdVNLlk4FM2nDzwlHkjbJNlz6xXuR8M74qcWVsgEzEBWyL0INt-KlkSSTIW_JPPnULrxNfDTu20ZQScBx55So1xEURFaCHjUf5P8MV5vr4paC7h0UXlWlj2LD_j9h0T3FYugMqTZuJ_NfPpmY0DpebI-_DY_cbNz6DZEIyicaqZ6MdFZlUz4Q1bpCI6773qdFLUdKS436u4jQcQjlpSbaA0sHl-7Mmr4UWKtEIZv69KCi0XQPqCOsMSYhnteyv7rrH8tL5zNqCIkUW_hKmle5Vblbafbg8wVhaObzO4nZKks-se9yVoMZnYzykm6A9C79qdWg3bRPQ8t7nWcwo42fB6kJ_K4OiMlPklzpWmAkDbTjUeFnqdUV5XhKdZPRWfHABG1jye0AZ9TZR8cS_lutJQGx6NzNzJ2h7qaeWM97ahd1rbGqeYhC3V3El75LYabMagyR5FqKaPXAPvTXdiulOFSb5QjjtOpxjBZQKC4kH_Z_jTmFCqjZ9KHB9FIdkVqqPSZV9eWPHdh4GB1RlfnJoO1qBGXEJfsTrI4BvIGn4FFudiZmQNar57xgkDx2CL3hejyIWssU6MkmvtLqwcha7NgSa9Li6zQHd2pBrfyKUtvE17_aEL9vys-2U8o4KqKph6vSzTprKRShTAmk7hUY8Hn2I2N1frQzOO6sD8NUcGqGlLMh4rjaKQXdideiNkn74J6Wdo2-hlie99H9qpbz26SCsSE0Ucn_HTvynOg3O4HGB4uMhz-CQHsdLh-9aZjw-xLtmbfLDdUEQC8U83rsX9JysbyySFP0bZA5kUTbhN1En5_-E8sXUburEg-nAshSW6WvSvM0ZRVsA0SoaDKIR0Wq8X8hXhK9tpx6rOMmXlcLFwNefRgNvoR7aoM7sRFeBT2QL3yjuHnOV1cZ-li3Fgfb8chV5CCsqAXucplybckQ1SmtDmiGxG9u6M77ODMpU_Cgn_bwtrDwwFci1dFyBPaBhQDx08jIb5tRUoAv0oLbTbl3CTemYSjNQaqWtX_wiDjH4uW1oU89m3CE=', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc', - signature='gAAAAABoxC0Pe79v2UqAMj3Y1BkJi0m_G8llzMHMeav3XGlfPIsphSfHvJVzbyv5s7pvfPLs2-ECy9vhTMaN1UfI_PYmoJ17y_k_lLjvC6sK7SdFeCmdGNjbrgIcah2DJecVqDdoT8P0Aaz6COw982zu34UyGL59e5FTol9mAGvtInH9vXmmQUnGS5fGktT90wC6-MrIxBc3Og92F-e5ciGk0DAVMC90pDTyP4z_Qkj8Jv1QYKqCv4GwFO8LyUicPTbML6l39jyTfH8L86uDWMMxKNsvHEIrqgTQnsInlwnHYVbPURb93_gMtcjOpZwc2ESnjqUtMLXzs8XaKxhU2NVBAzcXL5x2kg7OI7HbS4Vl90Hx5cVwp3i8OTfpw8aRhDoxZJWptxNBKwDDEtjqLbylKQ7m2uJ8_TkK030O0fb81_W1-36qeRn-yNE5jjkKTezyHP0DlpKjCzoY3pZ0GtIj0FRDJOJJOmbHXjC8HfrwBz76tIA64sOz8P5lS1parnESooZidtVudhrYPl5hgZ25w_X5JCOXhXBUGHFaCkiEYUZTydLK9i5W2nfmriUt5wxzG4rSHSq7B2zqLi1GdKg1So2VHEPRfL2GvDVQiRM3K5TPyrjVgoxM8rhmQp65uQ9pM_qHhzWAAr5BvMFVax32yI-gtTzOn8_gC89MleQkHueUbdLxiUDjesO8yIIc2rbzg-KatRma92xVYOS_P9uxzVR8ZI2VuhRfdlrHbvvLC7Crp-Vq-vO3XyNooIl8N6USQbSSCG4m1mt2yqcaUyUZBLPLLi2_mE0g5pF2sm3PRCEYiWtT26go3tZt8_HLF9exTvjOMny_CKAL7Mx2evk40fqbrVY8su1uhqK6AP9XxfkoyZoYWlBkQ3vVSUuFC6lNc2ACGfUFSNqJtE9XKZnwkB3gzw7N5zqFStYvCAjhqqoxFh4peSUf4oEdDEncLFQbct-TFezeTpxEe7wSSMYm9d-YpV48Ne_T_aUMrFevTEnB3x2oqY6M-tokB2mOOjCVJv_QUbDbjigVmBpuOmW_NTTQmVxRIO7_c90ywoMs3KmVmJXgV3Oec7Rp0tC4DjxM3-MznjZ3ctAuO25oxRBlFE5kABPTAZHPwX2nr9HNbH1SyE4GfmzHFzs4qkFNWXMlLcsgrHQ6HsyHoa00_eA40Uy4UucVzS8pDHF3Nt4yy1pDWyRGIkIyp-ptbkSac4Ceq8Gd1CVak6X-xpqe4kdk9Db1BjyBGLo9BMBbAwT54KMwEUrmqRFjTBl4Lqp6AMtoRRDbxAWzKI4X0al1g64B9S2FFKNGm4zs0bDitII2LyON7BZe7x5Bm_agD1SbkdHbmpOtxY10eFPdtShwYPYKr3jGUOILARRxYCICiVRPRKaNvoozEqy0mQVyGREv0byUp3r5YarGhretLddtfZIqFPYcdJhoB2ar25710xMSdnmGGKze-yjxFq-DVKPN-ihWtqpdFaJG93FVAO56v_jURwNM3zIBkTjEDDU80wo6hOiCrm3vjmDN0RzdsXo17WTs_QrD80ZDMI3S5UBqgJqE1Rk8FE2FBZvgQOk9kqWwhVt2XeK7KsOO9uHEMdFthxUTzMWdmbByQBPUeHI-dJHKkbl8kDOc7ljnN80U-eI4vr66kBkg-evTcOLZILsJ0-7IXaTDCiszLae_EbdYeXEIRriHsp63skqod8golNLWT56DkZLyNt5lu8ZE8Bp4QdkSL3rcNv1GQg-sT3DI_bOyQuHZ3zP5-OeEFdrI1n13KrnuaecyDa-lYU23BlGuMBDC3Q6bld3FPcHswew-H0sYgJwry4lhi1qMCRSzQVKvfUc2V658fOqpJO_85ssiSfzkMzNnrE0G1uRPH5_LUA1bAfmoLU5SkbkajMi35nZJzLTg79rVXpUtK8l2xJAKRnobSVKzPD1HT-b1x68vDHp1jFzeGPaM9z7wAC4iwXJLFDJhI_U_uoomw1d5lb47WHuAjpj0Q8Psgk6IMKntdWb0g61GcLZ9OoRyKDkjxar6KtEIZ1cyYVxUGTHTSKKWyrKvhWM9koj8EXkMeKtX3KFleH9AtGBFhExeSPTSJcmnv6t1ZVGSclQxVELOZh-RusLdy-wL06mT-eiBeHGw1H-0S5My-Py2AowI3aBk8YyDPGVH1pCnVfXTIOdQH6idOAsF6SmQahhjxr2KvKPr5Xf3zRAMrlTw6-50HgiEBibhSSWr0fxtZ77dIlesxym_eTfS2V1VHv58Rb3NjFIpL2ayLI6AKAnq29U7RDPXgLjWF4WoNxGkmo6Cc7dWIOsekjQuAQUtJaSSObwP_2HaMwfg5QPdFgt8KkkqOGsDEhXd2Si5ikvN2OFA_dUigfQ8aevQHqv-V7n4nFG8XGWkgfSdYJWMt7Y0SxuBJz7nlsnnggqjRrEI1C5Ae_HjlXKtH9WdYygzOtFGR_iVm--LWQE48-EIeym8g5Q6jwqAbnARFiCcfHyvU2omiGdiN8G9FIVRetDqWUDmdnza2GbJJ0JvoT2O8KPVkXZt8_qWJvTFuJ4Cqkwr-n3aa4BOQQtkB1lELR5rXed2RMNbReXmalMujHSVozgilhQauc6D89CY98ks4Yce32HbUOF753_eMD__ewBxA9DK31i50MrKQVID7UvKot3BsOK4JH2ExIg9CCx-mAbEL6HatGwoiE3zhX0RCO2OHYf66jrbKJ220wTH2O6_BCkihzNKLqTVmpYpPSprwPkkMBNfQTgtEJPJWp9hPoXux4g4z0EtYymZpC4sRVxpBH5mvno2D9i09fh9LM4QT6cf1Plh-6Q3HCupQpiq65g9CmAtJDEiSoIhrxYRkuza65jjabRvkudS8rP4Wm5Qn5ZYlykXUIzC1BVSIvjZPK2OLw_vLG1_iTbsBONDeb9AqQaXiAc4oHqUDSp3RJXvjRfQFNI48eVtk_LLkDd1WNuwQtzAjLAg9UZA6JZGLn66SpFpU_F_bwfHvNWrQ88ZieRDdQcbyCDYNJuqMMq5YOZBpz-Oa0Lun5L8hhUGB_B5FTUQPiiLVIKuHPJP0qLgC2o_R3u9VNfgwnMENnP6pmmVI2mPMFJSHEuDeShRshUSzZ4JOs9fnvpKT3TlyXFOeAtcn89Gilua2ziEfBy78d4Quuik1aL1wQtnr3PBTbn2Z0JGOPZoKybk9CF1a-1K0hoEK54-jRgTrPGseSMibhGO9x-5bW5viQVORDH1L9g2kcfJur1D-04cDlzkAB6hfjuqk1pvT3S3O2UGU37CZcVF_iolUucC8snhW5uhuvSdoBXXcnF7TuwsgAKNvztnf7B3tPJTW8x5Q5PGqHmRsoilCFlbslJCGq4h6NraPfKGY0Qq48A_i9QQGOihf1BI3OJE5usPGaxe6yJTpGQt5xCNuMCI920xIfCuQUx5BmVDAjho7EPkcDHoUWF53iZHPp7RSlC0uVABjJaaOREGT3oludmKOYY4PoZGMFNU_4Qm2UlT_OQ3XXhon0dcjT9j7OffzgjOiYy1HUMGpSyFdvIotQQSfAzNirsXZtZX7sVKXDPtOwzALnhd27odnEnYHpep03mmDI58plDhffF_rnw326mggOpYGBEgFNdtQCwoOe9P73E3762lRYHl6IOidAG6oaIP8sr3TU5xXhzJ7iqSKQbD4UMwolnNjUjVCwGMsLj137JYfUgQBmiu-5HuRuyD3jcRmddrWnofPg_uv_99W9i0tLvW9pAk5YDDUm6fFruGbYGXUa85g7iYuB6cY3lArHpPvBhpgFuH8FEexXhtJVRAFsT-Z7nvI5Hfh-Dk2M-Dv7ITg7er2mCwxG0ZmPMSx2kglqF8bZTxk7EqfGVQMvtgQMZTDij5dCIK3PzpoLqwNMd44fViVc4VXNR6o_gFx-XyKY6PVCN-OtGVQB2B6f6LikWyIMaIB5Jic7zT0lMsf8n9aSgi1UQdiR9RuizqInhxoW3IcdPpbHzyYKMyfsgE-VKX15pPOiL3stMrq7gSmX4itErJBKq2yocNH4QHjoqFsndWK3VNc6rzkdcZZqhu_ZN3xW31q57PzZbNMfQ_IUCuNPwcTCHnBiQVRZQaaiXvyVBh2NcBXLEdqr3Xuh8Q2BgCo9ZiW6fdqXOgSAd5gwxGOeQ_Cr-HLQMhB8bFE2szFWttri01hxyXOnpPt6ziDw_t4bGYB9WqaEMjCe_3iUgLjniX9hwPuQVhTDHvwkTaddSQ-SVE4JJJ5-IY7_0MAy7_swITfNP_7Wd_-XrdJ-PzUgKdKs8E7QSd2hpK6Vv7SGlsEHzPxljtHLsvEOGeTxkuBhc4KktOI3ezaooG0IgpQr7d7-viS2PF2Ri6-zkoXH3fosjCc_d5DtOvbPn_hE1Pnu-rCWnilbekyGhOquEAYsErlioLhpSaP15wkFzcZIMlV1aEPlrM6WzcCJX8cdeV0Z7fL1v7R11Jhux8h7bpW5Dm5mWtwpfg23XtywAcSXB8F1GuSZXJ4CZHq6vj6lAUqS0YigZBzMZe7UdOZUIK0VFTY1Kl50eI9Sptiy5AEPhDdaUT1daa-_g4BqJtelvtpF7XvIpPvEtlrLJBjimxCJU28-QUJDaBeKa9rtQTWf-4kyY05ITG9ke7qUnC9Sc_LDkeCEnDNjzStbf2B-r-ov9f2pUTJXDKkP4TwwiZ-AlDGHoKExZLJQYsek_DHS8rzwbRsjuhnU-toirFjZ1nH83XcYh6OKaE-7EsoUXWs5z16ntWeNJpEifCh5JNZJ_XC7BeKiL2uldqu4naYwBnwrrz7v2UAxOv2KusUwC5WHjkueRjgQtgS15Uf3khMDZYxMIKJeU_27POO84uQXsAVdPs_L4yL36hqVdT69WNfJzPuKsFiGkheoxC8SdGCaeUgpPZ24KZgDE6TLVaYin1xRBm3h-HxpAo86vjvM5LnpuVAy_0iJa4r5ozxhfjzJ7fPjQSk835tjZ8hls4yftUJNpOJM0cruJT25qsQS-RD36X4EF0BSPEdFJdN-z_CQK3LfAKcNSvO8UR7T_FEFzpH58qS98DR83avQuNx54lQ5h9ICIi3fxSHs1eO7c5m7jaCV8VHL6Mjkniqf_ZW0123BZxC2AeGcucAD9iPYeXFI5ob65AcL6TA3k1J8gOX58RIdIdzW9mkwMjJNMNEWYpEbsevRuQ_APKGJVyu014wYGeueKk9jQjgt8YQyLC7bT7eQKNrhWrT4Xfib6neWmhV9NRXVB8o434srI7Cw2sJaWSbJGAKgov2m-fvSEq2zqbNKQNqguIqsw-QvubN5u5c00PUldQs0zISnVthXAWJKlmuNxVykdN5HoDkKfAthnQv2pVc4mZK34DfcEo3Xc-1Ssysg4qOzHR4zTCY1GFX9FVKvO3C_CHI27gi_3pFjq3CcgV2_LZ3_p0g9IlCy2-6WKcRzBf_8jbuLb2kw4zGK_cG06YeeAzzMqPrtmx1tEshJF0sKAWWBzYYc2RE1Sn_QOP6YSxei2TKvB3k8Xvnp7TK-28hcJIDnZIbbU_4TkuoXz_MwbNEcE2q6YMxC86WT0qc7YXxAY3Gp0sNOypZ7QDxz8kBrzo3px5j81zDq1kxF-ZEIclPuFCXJ9s4NPaXrkjFmWnTvPmVc9F2u0JmkNgl71WaC7pRar3QpD_kbEJp-zcOFzyUnteiJKnQdbTdxZal7OT2GyfNDWpfJ3wmRZHjgAihyhDeGR7bPC95eMwEfp7ggXQrCrfLuFwMtkFPq539rnmbQ2D1GoW6f4RMtkF5p9UyihUaAjP4LC69e9dH4A5InMJmDpPfExf-_PEoiSgVTXWC58pb4DXm5QcvZj-4c-NDnlbWb_YbU-skdRq6ReAjIjWMNdRUoaU3b3EpWLTqVCsN2ZZNmqp7is5oGJG8Xyswb6VlGQq4ij5ZgGRE1YVVzMnoBVObpw2lxeDPldsK6ZbmzLq2cG4glgKPi13X5ZlQGb7eVdAgp9LZehOm8kOTljE5sLGmYJJpkmKE6hiddQeG7wxRSqcEoIctTRfMruXQL4gsPXgtpaYsTR6vi_MVrFSobxf_8DmhAkbUHNcyj6H1HVm4JRA0isGBoicUxzhybBn0heWjprPfnOD9eO_YpuUXxBrlC63LBKLQmsVkqkNI2mfTSKxVnx_f1QeuhJw4Rrp7iVyvCCE83XEr2uujo9uxm62zHvu6FHlJBSpdeX11DGUkXLScUtkFaCgHw8dcBsnG7jloDKJFOOs3i-cxOe-dWqlaVti5_sUmCLxNFIBk2TjZP44qQ7pQMT-Wp7b0o28IHGkaiIebz20xiWNOSYstZwq1xYIwhnQtCnAibqxE5kc6gtZbuF06NqD1h9fROgp9jdqGyucjHXs0zlkO1sBGgkz-8VnkF97h3rtdkqWSTZweI28dYQ0GYXagSSIgXmQp0QM7pzDp_JO85NYpR3CZW29aB6gdzuSbDoFciWd2UTsQX3HTEIsGxhtRtMa4ZPHyS5tHAKSlquhLOTHMTQfi8GO_VHsj241Hk3S56jM9Czovx-5OwRB8qKFNiHwKOvliSJR1HgXBkAleRIALJ64fDz5cUgy6Mn13Loue3JcowCAIgkrnusjVLig-y95xVvbs1Ys1rUFFKy3mmVaVyYd4Qe-WBLG-pZXug1z8gLTEZkY636ssMr_wIl2Zl-ciykcbiH6S9yTY358VqZgzQBS-44sQTdT_qelrVSNMLKneMs06JSjhSJOpmogW1I_hdHMtxkkSOQxKINvyEHPFbIkUR734qjhDVUPweD3IUQdMJ995R89D5cl94H0REAU_wJxDSGwGlux1P9ul1FHsX9hGTiNU6cE_qAD8fWX5ceOBa2iCoNefiQw1Ft9xh6QYDe2lOPdpIeihKm2ABWMVJ3hGCYwg-QPhj6yrSbZ4DSxCMPfC3NQ0Zarj5VgvfHOIO_gGiE9plkknoLBM_j1VSP7prfUOXQsA4sSu8eYhkreMkSVRk2JJ4JY2u1s9zATCq4cTUcKwdhgasU-mzPJRc0PF_7JsrojJ-GphyN_vGSzv_kBtl1Oo7IIHNo4UYiMpioxeBd3UV44oL8wOgImfs3a1Fnb-fHOS0RHkn1P57V-QGQcbQOoXtSqcDLjCJEJ144_QQa9jSCRUYXVv5VEYGfEcpaeyP62FFvLkeNfonGiObjVxXM2mnqV9gXm8Tf_NE7HgbthKKN9zbfOSyHos03LDBIYqScCnENopFX6XyY_iHOZwtfRojYmlZcfbtM7AA5K47Ycx1hC7A3U3x9CjHjhLZhqcQXdFeMNyfbEMabj4ESo0vqfKOFhif_U49MwLg9Q7cquuJ7zoduXmiBrlm2hPgzzpEK_JBC9vmc3FrxbBV4fZKr2EXYevtvSrWJ2-trlF5u9WO2xC6oxCuTUVisluvCWwhy0de3tulbLHlKV8xYEh_MvJy8tyqeOS4Y5lLtTtwuA4rTVNrYp4-otD6ZPQolK9k1vGCQtuTbgUR0Ya2m7vMDd10zU79haM0C6y723o3meJ6Yf2tIqffTk6YRpDw4yFiM0xKRP1NvkMT8T-3ptVnIBz4laUp_HDoTT1EQsmKYFtgMMaqTRImxH75v7FW0MGXT1578lBSB-PW_3U4zR8NpxvuBfLrzHcWOQv1bJ5m-v3ho91V0wXM9X4qEiA0CbGw3UdrrZ80VSeEa_wU6mQFG5IUB85_AaMkKjZsqoO7rZ4T_GAn3uqVmObN59eCgERccyBogj3s3oHk8yEXIhtzIC4wwNbiNhPBVako-_6YJOU5FnYu7VXVAWBNZsTMi9XuZY9oXTQLoU8Ya_Ix8baVrArLSAEDUih5mZvtgEzn9rBRJEarsCi5VMojQk5vzDpKjz21R7sNYTaiNikeM7AKRTtEa-N7FtdO432Gf4y4BYTctIi6ftUPj5mRbDm-ul19u89mnGx6VA4h4GZ0oWRtCP72svGw7zV_I301Qcl1m9TxFRCZvqDEvbU_GaRlL1VzR_QUOixSfCMrlovCtycE_zXE_oyMSjPXzA17wklLjG-gEFT0FUcvlohTKLlQKAUOvkalRMsao_DoGOYRfd6e8LtuKfaRnat9iq2RJ8OfbZw4kLmT73kaszYaFDPufKFvXt0nIxi_ysbX28Y5zZq6KHKwLmcceFqwwmZV2ayAvYjBZqBYpPLTfvEUd0-3n00bXi0hLP8Il8D1F_2ZcrQcHyc2g-g1Z-rxl_XaFnipOWuqRxq3ocMZLZ4YpUmMMA89icLRAoU9mG24RHcMrzkPD9IGUZv3SJVdKwcbmQCD3cBZBb4PEFenDnLbx51GodWRuXniQ0bl4cTlKbTkTJfAe3MpOuUDkcM0FXfnLdq86Hye5N-ygCdFfGozi_EjxF1kNQ6ItrNb_0i9eBhMTgCFHGCVBGWamswc6tICnbQRCDnUXVnvr5qqjno4w3hlXSmlE5w6j5yv7CskyIj8-rsbKW3zZTLMDHIyRqL4xtEqcJSlk-86nfCQj9QVXB4O3W_HLuyWo5cWoTHPwKlArTHx8Ml4Vub7qsgFvEnFzGLwd9QAWnaqD7ENALvims52mSBivuiMMR90nh-jsjbOq6GhckHhWRrtDlfLNcaTVJz-a-s7Zt2Hw-afODG7EemMCtGVRDDZn1Eo0katat1aXH7GU2LCfh-FP80eajowVmMYb5lRHWavhRwpSGTBOsmRECrJHym4ImOGcnxX6VE3Dczh-WNYYjEa0Q4OY1y-S21xExqdgx3SkaOc5G4KGuKdPCh6FAqg4P8Is0QAYnwnjbZZ5mQHfy-oUg1tzbO7yPkY_LNV22NlVqkUfVa1cMMhOzGqTOODaw5ECto3kW1LrIhVieIvKDUnztMMVj6jU8jjZ-mbaOc_Db0JLD4pgEtSmWybS9TqiGk6dcJGXOjDFi3PjwDCSKgwND_0xpTE0QJnumUhlflz6R1sFsE5Nc8rV0QglWQQyseJm-h-taauAkIBzyH3C0595Jkm5LBlM7V-bxtDeFjx-LFqB1rslSSW0dhPxrO6JAB4W6wtyL32UIRTGNOrgh26yboEvUSSZjJBeAO8Tiv3BCKTep1i1d-V291rJjb7sj2o_8XWaNm4tpl04vVY49WttNCxHJ5fM1PuVzbRSoOEF2btxCklDFhp5t8u1Y9mVnJpNMmn5AiCXZZSoyPqrv_j78QUZZXj-x5xwVft5363F1LjjoZ5s3LdEoGbsMAUiwkm7Z7aSr8gmV3uzrv8WyjiJjlc-rpPTE0RHbK_Hc5L9x1HYTJXECSdwZ8Q38yg6uc5EpTut5WPyScHFiDy1ybxnBPPx0tWas7jVULTZaeoGbnkUFo6xTJLMd9Tzzl2IM2zpgL5ZP5c79zxJvUtxgVFwTVmqMQQESj-qXikjBmaXgMLUb4Kv4n9655bgjr3ZuF_rxDagbRdt-_2pgf6VqsHEsaZJHwIpxh01vmyp6ZcQxzSUmi-8faZ_RWCJ5iTpHrMAHvrlPzrerOYBG-RGl2pxJDCVYr_WyUjKbPDxWkjKopcXx0DrYu1C6Cz1-gtGCT18LqoW73MCtdcrwKUXAmLdGUPFG5UFq2vuqItkeXcB1AA2hUhO1rzWYqHnqy2fXm4xtBgXMHVK8dqiXCmWWJ81sezBMVYDUP4MvpPkHRFSLdmG3YrZr0IwT9RzyyDfGItqWheKUJ7fkv0koRczg1J92z4BbyVBzdnEQX4edyyKCYd96ruWi-lEILIFHCY-viwPOIP3wCifcKgMCNGOzaTX3raFo2_VcNfvDSC8cLQq9X0o79qCE1Jeog6jSHUrKYhGsjn8mAJcdf7VzAjNsMpXypG57SMUBz4rd5QGvw3uGTs6M_p4BhciR8o1yOlqCjgRYyxUbCukRH-Od8QDHjRogTAeMjwL_fxEOIKf0pXWw_L3SeEddEfBDGaSU0CWPtCiEpUdu8pXQ-PEPvUFljROnxSr4Q4NQAro_b0FL2Lfk7rSLVJ-mlV8HpUwggz2VC0jjriGZDTCQmLCGFtyYA4qMeL0nJyUD0gfujHGMrqjnBP_TmwUr2qHn6y0jVreD7SpX8ojSYWeO0ebFHyBu6LAJy9VLS7d9Gu5tZ9EVVDCd7MfbDozD1UTevnfxnyGT2-_3xJXnJ2fIzISqkV6vYDmvXAhMHwggCBamQ5VUb5Ri-JQyAOkH-P_d5AzM4vLH3NovPaTs41-EZ9LoA_ACgTwMdXcI6yKNhvbYfHK92GWG0k_HUoZp31nOrUY4hsvoDr1VyJHeFjH2WulFKr4hTj--htE99X95MtcYL1BYJ5KZVT92oX2m2Tauayqr_VP-iYgeiC7WWoo526r5jVWXs1ZgxtzXzylpf5f5z35G4YMC37RFlzgY9kDaeLkMMqUvQo4GbEFbLQ5rF-9zMA2NYFKC-6fUh0hvN1UziR-Co6ZhXi5KP1_3aw2sjSiEwlF3umF4zZcIKjKWtAHrFblBLnUyp79qId8ibcUQm4EHQ92CnkKtAf_e-OB-eZA9Vz8NGagOAFdyAtOFZ17MBcv049eh2izFmxKl4FctOKAEIU1HVWv8IWqmlDyQvsUlwImE-0YFl2EHPizSCLgHM2FgRe1a_k4YEJnQxONr2GUIGL2x8mDl7aBejUmYkkyrCj4Y5XDS1RO_hrmhDB9rAJtukT1PozIgqJTGNHyH_99wqT3cfG37PPWiSuGOG1Rbujp_by2zqGmJx1PjvoRSX7YO_s_apGzAARHZL9n-xFsoXqiJkqM242r7SHsMrqkYckG5IyxjTrpqDWdOSe4xxTc9snA6Bk5EjQ6kb0_VVG20g6kKua9Qy1n-6Jj3BMOaBHcrP4hKKStHySqqLCPOOrqn9hH2s0YKsxknqCVcR6kkCbLi2xD7dpBXmmc-X5MvuK9g9kGBWjfjQSPEfCnhD7b8cDbvWAKJh9vmdR9ofySSWMWQUjRJA43dOTlUpuskklOImDZqitGamjZTfLK4L-gE3wDkavF___kozI04zsB7xOFdPcyL76sUumoAQ_gHA0he0YE0gamTjbJEk6p6NnzuK7PisLkvNS3ZdKqTZ_msTrRSV0IUyypI1qMB-RZDgjWgdccbBTxa9xeoLTLZM8OIEmhsubQF_danFfla5dm8aDiU6k7QpiutDFosvkIJlt5sBbr5Qhwbp-DWyDaX1TI8cCqlDoplTZiZrzf-n65eZMKAcNL3xp0bMYWslR10All84u6IlOqbiiMqIsCFQS4A-Ff3uftu6JqNl8tC_J7H2F0D2W1rDUVYavmTevdbk3MfH6vEClLwnLsB2wQlripHxv77bwlwK5g-4LWHu5N6shsdVMsk7RwdaozdpDB23r4FAok05qbNgHhgpOgu-1MnRK9res5CoVia32tb846NNom_CRss0fLhnAqeU1A8hSZPwsDChHiz8fYCVLpVkCfEX-hgaloQ07R4QyTBXY9puuuJOuOCzhe1IANS4bS1EdGOSWBiDW_Df3q5ky5LOXCOfJjZBvAEkpnX3KJyxdE8K05P3Sj9akt0eG2buFfBLL3rEqBAvOjSWA8FkSF6b8NlLx53itZnn9yiEyL847Z6WGg-Wjs1y-hWSzBh587FAB2z8nTrIAYOQkW0dWJW9Grerc2NraD-hmK4AzTK9f8dCwWSfmc5TB24s6qNRU8Dk4hZ04wAuSQLximtJh3Gv58EABNSSZO6SS8S3SvTR3rRGRYe0Op5EnjoLvT4ZSkLaRFQxld15H3vq66hs9PZo3F3ZxNBO_oDulDXYVvOfeP-16sMfE744LGlucoZBvfeEtjE6Lqabl5jbgByNm08nluPSNGAVOQgExxHcAlL2H29yvMpo78qeqLlkOw3iHi1rEleBFQxcTOE2Ql0vh7gSjgZba0WoI2rl2nD5Bbc5rlTkSa_0-SoDl_aWnpSHLSXHr9y8S1Ryphc6-Tz5uy9lCrplcuHoiF7WUCChE4gv65yf1i0VTw0QjsnwPdnq5Z_EXAou2jLuXaWwNfhIPyyl69n2zEKrKDpDIxS44J4IB5zCA_DFrO1gcI71ibRrcPQiY7Y-H7ejlrGv1TfE1FwZwvphixyc5cVoUJYDZ3pljYH_vIjKAAWr-FC5rNeJDCkXdBwGzrB_fjvju9lNu0bH8xXbQ5xB4vGoorscYBverGCtbbgPof05Ga6uVo_W3_6EJQbJg71kriFa_6haOFWz9Q4sAAOYW1aA1mrEDJY40nG59r2VdQ7EU0X_5mqkwoQGcWddMWgZDFPIITpWOo672O9Egh8luGo8EP9zhRtFIGn2vC494VBDUyVGrKMJLLI1lpoUgGfsndA9JfVJH5J9BaKRqD-GcZh2Fojj05eyJS1Bj62AoqB15nSx1X5ouHF_SkkRBZUPYQqByCrtvcrQxA32PeFZXzc1YVltoLa75LmnhBU4PBA4-KZOaGjL1EYUSU5VcZkLdQVyEXXT7NZDZ9ZchBp5IZEMLkLDNSeguPTpJyTdodbbye-QZdGzHVG9yVH3bqTB_KsEqIaJ30sjX_zi6boK6ZC7ZeGI59ChA_W7jVIT4kHWWPp4WVVlecuKDzePIhc5vr3wUlXotk95470wDp3Jw81QNNu_jRgxJ0dWcIl0Ew41OV8YomZsud_VkXBTn-68KwYcBq-rYGwVFktGpVIOvoIspZvch8d6UhSVG9LcPjN1_TD1GAJ5EQtwSoVak2I9X3zHl0bVeyJ8qrcOQcLc-4ss_YUfY3sOxrv3WO3livMq2e40ec6osSm3EfhR6RKEgOAwnU_VBkS9remIUxsTftJ2ZefPU0ql_HnT7NmiYjO1s38dQbBI68scRYZtzlJ1Yh3uKqww8CG4Sr3s7hkXDl8yEHfQdSza_YSphJWn9TBflKcBa_t05qW2eTtgri54pqNvcDE1V6sJQqucT2xQAodfMaydGk-m2XPCTuAJ3kCgCpJdzH2Ar1eBv-7XLywrFGo9ayBY1cQBOT96XY0txWY3Ju5BPwU1JlRxgitQI8kGND3b3HTDGn-U__abQUMkyL18FPXkEsD5ZnRRvhTeQjeNpjM0TO6uPvk1Xxmnr6_8sR2s0bJKhuHxC47SIospvgW7Fl9BqlCaU1UoQIuP0c1rN1IfKk0OIsAZSMDvSLCze33-8vFyCes1hHSc0MI1zU2CR3cRt9-3TE08lQw6SsUAIM2SSvfsHBXP2Ib7AnoRby4HTrRKngGPXsNIRtMzthrGT1gj1Ey9Ka33YcEz3j1PGK5mJllRi7nrCWDJQt1C9kLcp3qPwWnkq5J3b6VSgLwvdrMSEPKrIJGhB8kugfey0fJduu5-Puw3dH6DvV3sQo7WKdim3JUz611z_oiwL_UzeL48yaDoBQbfe3LH8S6pWoXeCU-Pr2KASZGM8cZlkVKnJWTKa8ne9LdBuRiDpVwVePQ5cDmUn88SYs1KEEqguwB7te3xJ_3HxuPRHqy7gTs70trvBGl8zqVNJsnmKpS3V_E1UtMGLYQ8MFApSA3b6YcJP4j4E6aCD5lakVLGSnMoq3PUof7Kc92NZSWzNq7YfCoAzL1BJoz47MdWn50bnVy4Xa48GLvQgjEJ-MF2i1txejCCw8jpQSZqHLx_PvKT69cw9UkcEzktnd-uT7BruxwIl6mcWdc0oeOjt25zg0IxB62WVVcNHQi_PSC4_kM_cvIx6749xXi_6hyui-2L5ZNQmcd8-7-y_0gaQTaijKThaSg0QtGkWv1lFtBjxxe2_mcANoTlnJPsHOvriL_brQeBfNf0WXwRgUzfUF62hrYCw7OOqH_rbQNBJbHgyyTMhxVtxc-DoGqw9QIVIwZZC-XEl_8vk0D7r-QCW1Desu8eyXl6tDy6kfP-UkuvZv4kZT8cbihvUXmAghgfRfUzR0OK9V1zMIfVgDYPflxtYgAT67creQ7Re3R8f68cVFGT0oJ_ZpN7rYREZ-mGghxVwmNndFboo97n2aLZbBXfqCfLPqMgaE0-nCKB-CYN-PX7Z1tJcNerMllFlpyE8UTw064GPNxAx9J_ZcRPVgAAFdHOe23ajDzaeSRMRKVITIUPugxbKPTWb55fOIwgWOS31s0w9uiGFrScu_7aDvrsI8pXFXLZhSZ2qPnARC6Cz6t3DQPLc-_0W3T5q9iy00AjgTUBSJIIL0WdoU1zoUyJnDY2JZLYYQxaFp1aI9AzMmm9c56Qb_NiBUfJfyVS3I9NaJq91x8QebR4IdO49boC5oAWIERJCkOTLxQUbKy6EXtxpgO1-zhBXXDPKyhAuSj5jnRa7wvRdbKXza6stM81md-AqEvDl6Cnj-FSXdaEo8glAF_XxdgA3UpMx1EyvkuoGcEcoyEsqxc5AdOD4R6cKEdMRl04GGSI7fJp1cuWmJLQqesAjK_VAEnYYrmoQxdZLw8BR1SM13XoWSfEq9dN_uZiwME1CwkTR6mN-WxXfeg-JYDRebAY_idA3xP6lcwFBQsIRebdcRyqgmiZCMyaRJ28ZwOUmpHaqJEiccfbBL0oqO5VFNP1bAq5nsjrvXkmB-a_jAJyAliToyuKc4i-VXMiVwp1jV_outA53A8csMgLmkYHrON3ZA79psVTdnJehE5zdAaObGZt_h4U1fXGGfdzuTIZ8Nr1UlNJVHwrC5Z23DY_Dp7JNHt9TIwktbfaQieUW5IR3-x8vczQewwU3lIu9KrSESjQZSe3Xr029LQpqSe3DuyWCWrLSEun0npCWaCiskfrT3zI31957vIbKdKFD_rfUzKs1byozDw6o0K19litvEClc2PQ8gZWW347WfHIwek-9qAMsRlreFc8n9ASWW_QQxgTRnBBeC4DkuwWmuj4Cfs6xwfu9b9T15jJNYGxIsLVer38U3AS6dEgtwCjwjZ0jfQRV2o_Lr89Qsj4E_EnIbJzZGEKBOIobO-lj72l0sFG5b5_qaMhUsndRRRQo3KoNa3jTtGsBI8EkMb58uLLlqD7sdIEuJ-a-1SQwiSyb9m5P5FIlyykGPFK5okoEOxzwIZSEgdghKXGIq8SQbgkQ83kHkocq7NxBHdX61Egr0V3uEEytgcO2chYZd-WiJWFLLm5zmTeLQfUl7G5CJZwhFGRjpGpYbYGcMkRCEgATzT4jcwzH7KYBMCIXi1bskCDctAy2as0jQnc5ICFzWl76doHdMVJZSvFzFY29_vP8IuVRHSW3hCtODDxLhnvDXMPGt6dOjHN-dq3_NB9mfvHKkOEK10JDpRnvz0k6gstUZDHs28a_BEH8RTb0pXh1rcO35elGh4yDNNKUk26xXKabN3OZMVmsZxxqL_JqptdmC9cNwg7XZ-S1Ey4-6acvec5J4R6GjTcPZWluZLERc2tTSeOtQoJbCJD1shS2NvR60jahncVhdp0ynV1-ZX8oAsMxKFKiB0ZtxdVNLlk4FM2nDzwlHkjbJNlz6xXuR8M74qcWVsgEzEBWyL0INt-KlkSSTIW_JPPnULrxNfDTu20ZQScBx55So1xEURFaCHjUf5P8MV5vr4paC7h0UXlWlj2LD_j9h0T3FYugMqTZuJ_NfPpmY0DpebI-_DY_cbNz6DZEIyicaqZ6MdFZlUz4Q1bpCI6773qdFLUdKS436u4jQcQjlpSbaA0sHl-7Mmr4UWKtEIZv69KCi0XQPqCOsMSYhnteyv7rrH8tL5zNqCIkUW_hKmle5Vblbafbg8wVhaObzO4nZKks-se9yVoMZnYzykm6A9C79qdWg3bRPQ8t7nWcwo42fB6kJ_K4OiMlPklzpWmAkDbTjUeFnqdUV5XhKdZPRWfHABG1jye0AZ9TZR8cS_lutJQGx6NzNzJ2h7qaeWM97ahd1rbGqeYhC3V3El75LYabMagyR5FqKaPXAPvTXdiulOFSb5QjjtOpxjBZQKC4kH_Z_jTmFCqjZ9KHB9FIdkVqqPSZV9eWPHdh4GB1RlfnJoO1qBGXEJfsTrI4BvIGn4FFudiZmQNar57xgkDx2CL3hejyIWssU6MkmvtLqwcha7NgSa9Li6zQHd2pBrfyKUtvE17_aEL9vys-2U8o4KqKph6vSzTprKRShTAmk7hUY8Hn2I2N1frQzOO6sD8NUcGqGlLMh4rjaKQXdideiNkn74J6Wdo2-hlie99H9qpbz26SCsSE0Ucn_HTvynOg3O4HGB4uMhz-CQHsdLh-9aZjw-xLtmbfLDdUEQC8U83rsX9JysbyySFP0bZA5kUTbhN1En5_-E8sXUburEg-nAshSW6WvSvM0ZRVsA0SoaDKIR0Wq8X8hXhK9tpx6rOMmXlcLFwNefRgNvoR7aoM7sRFeBT2QL3yjuHnOV1cZ-li3Fgfb8chV5CCsqAXucplybckQ1SmtDmiGxG9u6M77ODMpU_Cgn_bwtrDwwFci1dFyBPaBhQDx08jIb5tRUoAv0oLbTbl3CTemYSjNQaqWtX_wiDjH4uW1oU89m3CE=', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc', - signature='gAAAAABoxC0Pe79v2UqAMj3Y1BkJi0m_G8llzMHMeav3XGlfPIsphSfHvJVzbyv5s7pvfPLs2-ECy9vhTMaN1UfI_PYmoJ17y_k_lLjvC6sK7SdFeCmdGNjbrgIcah2DJecVqDdoT8P0Aaz6COw982zu34UyGL59e5FTol9mAGvtInH9vXmmQUnGS5fGktT90wC6-MrIxBc3Og92F-e5ciGk0DAVMC90pDTyP4z_Qkj8Jv1QYKqCv4GwFO8LyUicPTbML6l39jyTfH8L86uDWMMxKNsvHEIrqgTQnsInlwnHYVbPURb93_gMtcjOpZwc2ESnjqUtMLXzs8XaKxhU2NVBAzcXL5x2kg7OI7HbS4Vl90Hx5cVwp3i8OTfpw8aRhDoxZJWptxNBKwDDEtjqLbylKQ7m2uJ8_TkK030O0fb81_W1-36qeRn-yNE5jjkKTezyHP0DlpKjCzoY3pZ0GtIj0FRDJOJJOmbHXjC8HfrwBz76tIA64sOz8P5lS1parnESooZidtVudhrYPl5hgZ25w_X5JCOXhXBUGHFaCkiEYUZTydLK9i5W2nfmriUt5wxzG4rSHSq7B2zqLi1GdKg1So2VHEPRfL2GvDVQiRM3K5TPyrjVgoxM8rhmQp65uQ9pM_qHhzWAAr5BvMFVax32yI-gtTzOn8_gC89MleQkHueUbdLxiUDjesO8yIIc2rbzg-KatRma92xVYOS_P9uxzVR8ZI2VuhRfdlrHbvvLC7Crp-Vq-vO3XyNooIl8N6USQbSSCG4m1mt2yqcaUyUZBLPLLi2_mE0g5pF2sm3PRCEYiWtT26go3tZt8_HLF9exTvjOMny_CKAL7Mx2evk40fqbrVY8su1uhqK6AP9XxfkoyZoYWlBkQ3vVSUuFC6lNc2ACGfUFSNqJtE9XKZnwkB3gzw7N5zqFStYvCAjhqqoxFh4peSUf4oEdDEncLFQbct-TFezeTpxEe7wSSMYm9d-YpV48Ne_T_aUMrFevTEnB3x2oqY6M-tokB2mOOjCVJv_QUbDbjigVmBpuOmW_NTTQmVxRIO7_c90ywoMs3KmVmJXgV3Oec7Rp0tC4DjxM3-MznjZ3ctAuO25oxRBlFE5kABPTAZHPwX2nr9HNbH1SyE4GfmzHFzs4qkFNWXMlLcsgrHQ6HsyHoa00_eA40Uy4UucVzS8pDHF3Nt4yy1pDWyRGIkIyp-ptbkSac4Ceq8Gd1CVak6X-xpqe4kdk9Db1BjyBGLo9BMBbAwT54KMwEUrmqRFjTBl4Lqp6AMtoRRDbxAWzKI4X0al1g64B9S2FFKNGm4zs0bDitII2LyON7BZe7x5Bm_agD1SbkdHbmpOtxY10eFPdtShwYPYKr3jGUOILARRxYCICiVRPRKaNvoozEqy0mQVyGREv0byUp3r5YarGhretLddtfZIqFPYcdJhoB2ar25710xMSdnmGGKze-yjxFq-DVKPN-ihWtqpdFaJG93FVAO56v_jURwNM3zIBkTjEDDU80wo6hOiCrm3vjmDN0RzdsXo17WTs_QrD80ZDMI3S5UBqgJqE1Rk8FE2FBZvgQOk9kqWwhVt2XeK7KsOO9uHEMdFthxUTzMWdmbByQBPUeHI-dJHKkbl8kDOc7ljnN80U-eI4vr66kBkg-evTcOLZILsJ0-7IXaTDCiszLae_EbdYeXEIRriHsp63skqod8golNLWT56DkZLyNt5lu8ZE8Bp4QdkSL3rcNv1GQg-sT3DI_bOyQuHZ3zP5-OeEFdrI1n13KrnuaecyDa-lYU23BlGuMBDC3Q6bld3FPcHswew-H0sYgJwry4lhi1qMCRSzQVKvfUc2V658fOqpJO_85ssiSfzkMzNnrE0G1uRPH5_LUA1bAfmoLU5SkbkajMi35nZJzLTg79rVXpUtK8l2xJAKRnobSVKzPD1HT-b1x68vDHp1jFzeGPaM9z7wAC4iwXJLFDJhI_U_uoomw1d5lb47WHuAjpj0Q8Psgk6IMKntdWb0g61GcLZ9OoRyKDkjxar6KtEIZ1cyYVxUGTHTSKKWyrKvhWM9koj8EXkMeKtX3KFleH9AtGBFhExeSPTSJcmnv6t1ZVGSclQxVELOZh-RusLdy-wL06mT-eiBeHGw1H-0S5My-Py2AowI3aBk8YyDPGVH1pCnVfXTIOdQH6idOAsF6SmQahhjxr2KvKPr5Xf3zRAMrlTw6-50HgiEBibhSSWr0fxtZ77dIlesxym_eTfS2V1VHv58Rb3NjFIpL2ayLI6AKAnq29U7RDPXgLjWF4WoNxGkmo6Cc7dWIOsekjQuAQUtJaSSObwP_2HaMwfg5QPdFgt8KkkqOGsDEhXd2Si5ikvN2OFA_dUigfQ8aevQHqv-V7n4nFG8XGWkgfSdYJWMt7Y0SxuBJz7nlsnnggqjRrEI1C5Ae_HjlXKtH9WdYygzOtFGR_iVm--LWQE48-EIeym8g5Q6jwqAbnARFiCcfHyvU2omiGdiN8G9FIVRetDqWUDmdnza2GbJJ0JvoT2O8KPVkXZt8_qWJvTFuJ4Cqkwr-n3aa4BOQQtkB1lELR5rXed2RMNbReXmalMujHSVozgilhQauc6D89CY98ks4Yce32HbUOF753_eMD__ewBxA9DK31i50MrKQVID7UvKot3BsOK4JH2ExIg9CCx-mAbEL6HatGwoiE3zhX0RCO2OHYf66jrbKJ220wTH2O6_BCkihzNKLqTVmpYpPSprwPkkMBNfQTgtEJPJWp9hPoXux4g4z0EtYymZpC4sRVxpBH5mvno2D9i09fh9LM4QT6cf1Plh-6Q3HCupQpiq65g9CmAtJDEiSoIhrxYRkuza65jjabRvkudS8rP4Wm5Qn5ZYlykXUIzC1BVSIvjZPK2OLw_vLG1_iTbsBONDeb9AqQaXiAc4oHqUDSp3RJXvjRfQFNI48eVtk_LLkDd1WNuwQtzAjLAg9UZA6JZGLn66SpFpU_F_bwfHvNWrQ88ZieRDdQcbyCDYNJuqMMq5YOZBpz-Oa0Lun5L8hhUGB_B5FTUQPiiLVIKuHPJP0qLgC2o_R3u9VNfgwnMENnP6pmmVI2mPMFJSHEuDeShRshUSzZ4JOs9fnvpKT3TlyXFOeAtcn89Gilua2ziEfBy78d4Quuik1aL1wQtnr3PBTbn2Z0JGOPZoKybk9CF1a-1K0hoEK54-jRgTrPGseSMibhGO9x-5bW5viQVORDH1L9g2kcfJur1D-04cDlzkAB6hfjuqk1pvT3S3O2UGU37CZcVF_iolUucC8snhW5uhuvSdoBXXcnF7TuwsgAKNvztnf7B3tPJTW8x5Q5PGqHmRsoilCFlbslJCGq4h6NraPfKGY0Qq48A_i9QQGOihf1BI3OJE5usPGaxe6yJTpGQt5xCNuMCI920xIfCuQUx5BmVDAjho7EPkcDHoUWF53iZHPp7RSlC0uVABjJaaOREGT3oludmKOYY4PoZGMFNU_4Qm2UlT_OQ3XXhon0dcjT9j7OffzgjOiYy1HUMGpSyFdvIotQQSfAzNirsXZtZX7sVKXDPtOwzALnhd27odnEnYHpep03mmDI58plDhffF_rnw326mggOpYGBEgFNdtQCwoOe9P73E3762lRYHl6IOidAG6oaIP8sr3TU5xXhzJ7iqSKQbD4UMwolnNjUjVCwGMsLj137JYfUgQBmiu-5HuRuyD3jcRmddrWnofPg_uv_99W9i0tLvW9pAk5YDDUm6fFruGbYGXUa85g7iYuB6cY3lArHpPvBhpgFuH8FEexXhtJVRAFsT-Z7nvI5Hfh-Dk2M-Dv7ITg7er2mCwxG0ZmPMSx2kglqF8bZTxk7EqfGVQMvtgQMZTDij5dCIK3PzpoLqwNMd44fViVc4VXNR6o_gFx-XyKY6PVCN-OtGVQB2B6f6LikWyIMaIB5Jic7zT0lMsf8n9aSgi1UQdiR9RuizqInhxoW3IcdPpbHzyYKMyfsgE-VKX15pPOiL3stMrq7gSmX4itErJBKq2yocNH4QHjoqFsndWK3VNc6rzkdcZZqhu_ZN3xW31q57PzZbNMfQ_IUCuNPwcTCHnBiQVRZQaaiXvyVBh2NcBXLEdqr3Xuh8Q2BgCo9ZiW6fdqXOgSAd5gwxGOeQ_Cr-HLQMhB8bFE2szFWttri01hxyXOnpPt6ziDw_t4bGYB9WqaEMjCe_3iUgLjniX9hwPuQVhTDHvwkTaddSQ-SVE4JJJ5-IY7_0MAy7_swITfNP_7Wd_-XrdJ-PzUgKdKs8E7QSd2hpK6Vv7SGlsEHzPxljtHLsvEOGeTxkuBhc4KktOI3ezaooG0IgpQr7d7-viS2PF2Ri6-zkoXH3fosjCc_d5DtOvbPn_hE1Pnu-rCWnilbekyGhOquEAYsErlioLhpSaP15wkFzcZIMlV1aEPlrM6WzcCJX8cdeV0Z7fL1v7R11Jhux8h7bpW5Dm5mWtwpfg23XtywAcSXB8F1GuSZXJ4CZHq6vj6lAUqS0YigZBzMZe7UdOZUIK0VFTY1Kl50eI9Sptiy5AEPhDdaUT1daa-_g4BqJtelvtpF7XvIpPvEtlrLJBjimxCJU28-QUJDaBeKa9rtQTWf-4kyY05ITG9ke7qUnC9Sc_LDkeCEnDNjzStbf2B-r-ov9f2pUTJXDKkP4TwwiZ-AlDGHoKExZLJQYsek_DHS8rzwbRsjuhnU-toirFjZ1nH83XcYh6OKaE-7EsoUXWs5z16ntWeNJpEifCh5JNZJ_XC7BeKiL2uldqu4naYwBnwrrz7v2UAxOv2KusUwC5WHjkueRjgQtgS15Uf3khMDZYxMIKJeU_27POO84uQXsAVdPs_L4yL36hqVdT69WNfJzPuKsFiGkheoxC8SdGCaeUgpPZ24KZgDE6TLVaYin1xRBm3h-HxpAo86vjvM5LnpuVAy_0iJa4r5ozxhfjzJ7fPjQSk835tjZ8hls4yftUJNpOJM0cruJT25qsQS-RD36X4EF0BSPEdFJdN-z_CQK3LfAKcNSvO8UR7T_FEFzpH58qS98DR83avQuNx54lQ5h9ICIi3fxSHs1eO7c5m7jaCV8VHL6Mjkniqf_ZW0123BZxC2AeGcucAD9iPYeXFI5ob65AcL6TA3k1J8gOX58RIdIdzW9mkwMjJNMNEWYpEbsevRuQ_APKGJVyu014wYGeueKk9jQjgt8YQyLC7bT7eQKNrhWrT4Xfib6neWmhV9NRXVB8o434srI7Cw2sJaWSbJGAKgov2m-fvSEq2zqbNKQNqguIqsw-QvubN5u5c00PUldQs0zISnVthXAWJKlmuNxVykdN5HoDkKfAthnQv2pVc4mZK34DfcEo3Xc-1Ssysg4qOzHR4zTCY1GFX9FVKvO3C_CHI27gi_3pFjq3CcgV2_LZ3_p0g9IlCy2-6WKcRzBf_8jbuLb2kw4zGK_cG06YeeAzzMqPrtmx1tEshJF0sKAWWBzYYc2RE1Sn_QOP6YSxei2TKvB3k8Xvnp7TK-28hcJIDnZIbbU_4TkuoXz_MwbNEcE2q6YMxC86WT0qc7YXxAY3Gp0sNOypZ7QDxz8kBrzo3px5j81zDq1kxF-ZEIclPuFCXJ9s4NPaXrkjFmWnTvPmVc9F2u0JmkNgl71WaC7pRar3QpD_kbEJp-zcOFzyUnteiJKnQdbTdxZal7OT2GyfNDWpfJ3wmRZHjgAihyhDeGR7bPC95eMwEfp7ggXQrCrfLuFwMtkFPq539rnmbQ2D1GoW6f4RMtkF5p9UyihUaAjP4LC69e9dH4A5InMJmDpPfExf-_PEoiSgVTXWC58pb4DXm5QcvZj-4c-NDnlbWb_YbU-skdRq6ReAjIjWMNdRUoaU3b3EpWLTqVCsN2ZZNmqp7is5oGJG8Xyswb6VlGQq4ij5ZgGRE1YVVzMnoBVObpw2lxeDPldsK6ZbmzLq2cG4glgKPi13X5ZlQGb7eVdAgp9LZehOm8kOTljE5sLGmYJJpkmKE6hiddQeG7wxRSqcEoIctTRfMruXQL4gsPXgtpaYsTR6vi_MVrFSobxf_8DmhAkbUHNcyj6H1HVm4JRA0isGBoicUxzhybBn0heWjprPfnOD9eO_YpuUXxBrlC63LBKLQmsVkqkNI2mfTSKxVnx_f1QeuhJw4Rrp7iVyvCCE83XEr2uujo9uxm62zHvu6FHlJBSpdeX11DGUkXLScUtkFaCgHw8dcBsnG7jloDKJFOOs3i-cxOe-dWqlaVti5_sUmCLxNFIBk2TjZP44qQ7pQMT-Wp7b0o28IHGkaiIebz20xiWNOSYstZwq1xYIwhnQtCnAibqxE5kc6gtZbuF06NqD1h9fROgp9jdqGyucjHXs0zlkO1sBGgkz-8VnkF97h3rtdkqWSTZweI28dYQ0GYXagSSIgXmQp0QM7pzDp_JO85NYpR3CZW29aB6gdzuSbDoFciWd2UTsQX3HTEIsGxhtRtMa4ZPHyS5tHAKSlquhLOTHMTQfi8GO_VHsj241Hk3S56jM9Czovx-5OwRB8qKFNiHwKOvliSJR1HgXBkAleRIALJ64fDz5cUgy6Mn13Loue3JcowCAIgkrnusjVLig-y95xVvbs1Ys1rUFFKy3mmVaVyYd4Qe-WBLG-pZXug1z8gLTEZkY636ssMr_wIl2Zl-ciykcbiH6S9yTY358VqZgzQBS-44sQTdT_qelrVSNMLKneMs06JSjhSJOpmogW1I_hdHMtxkkSOQxKINvyEHPFbIkUR734qjhDVUPweD3IUQdMJ995R89D5cl94H0REAU_wJxDSGwGlux1P9ul1FHsX9hGTiNU6cE_qAD8fWX5ceOBa2iCoNefiQw1Ft9xh6QYDe2lOPdpIeihKm2ABWMVJ3hGCYwg-QPhj6yrSbZ4DSxCMPfC3NQ0Zarj5VgvfHOIO_gGiE9plkknoLBM_j1VSP7prfUOXQsA4sSu8eYhkreMkSVRk2JJ4JY2u1s9zATCq4cTUcKwdhgasU-mzPJRc0PF_7JsrojJ-GphyN_vGSzv_kBtl1Oo7IIHNo4UYiMpioxeBd3UV44oL8wOgImfs3a1Fnb-fHOS0RHkn1P57V-QGQcbQOoXtSqcDLjCJEJ144_QQa9jSCRUYXVv5VEYGfEcpaeyP62FFvLkeNfonGiObjVxXM2mnqV9gXm8Tf_NE7HgbthKKN9zbfOSyHos03LDBIYqScCnENopFX6XyY_iHOZwtfRojYmlZcfbtM7AA5K47Ycx1hC7A3U3x9CjHjhLZhqcQXdFeMNyfbEMabj4ESo0vqfKOFhif_U49MwLg9Q7cquuJ7zoduXmiBrlm2hPgzzpEK_JBC9vmc3FrxbBV4fZKr2EXYevtvSrWJ2-trlF5u9WO2xC6oxCuTUVisluvCWwhy0de3tulbLHlKV8xYEh_MvJy8tyqeOS4Y5lLtTtwuA4rTVNrYp4-otD6ZPQolK9k1vGCQtuTbgUR0Ya2m7vMDd10zU79haM0C6y723o3meJ6Yf2tIqffTk6YRpDw4yFiM0xKRP1NvkMT8T-3ptVnIBz4laUp_HDoTT1EQsmKYFtgMMaqTRImxH75v7FW0MGXT1578lBSB-PW_3U4zR8NpxvuBfLrzHcWOQv1bJ5m-v3ho91V0wXM9X4qEiA0CbGw3UdrrZ80VSeEa_wU6mQFG5IUB85_AaMkKjZsqoO7rZ4T_GAn3uqVmObN59eCgERccyBogj3s3oHk8yEXIhtzIC4wwNbiNhPBVako-_6YJOU5FnYu7VXVAWBNZsTMi9XuZY9oXTQLoU8Ya_Ix8baVrArLSAEDUih5mZvtgEzn9rBRJEarsCi5VMojQk5vzDpKjz21R7sNYTaiNikeM7AKRTtEa-N7FtdO432Gf4y4BYTctIi6ftUPj5mRbDm-ul19u89mnGx6VA4h4GZ0oWRtCP72svGw7zV_I301Qcl1m9TxFRCZvqDEvbU_GaRlL1VzR_QUOixSfCMrlovCtycE_zXE_oyMSjPXzA17wklLjG-gEFT0FUcvlohTKLlQKAUOvkalRMsao_DoGOYRfd6e8LtuKfaRnat9iq2RJ8OfbZw4kLmT73kaszYaFDPufKFvXt0nIxi_ysbX28Y5zZq6KHKwLmcceFqwwmZV2ayAvYjBZqBYpPLTfvEUd0-3n00bXi0hLP8Il8D1F_2ZcrQcHyc2g-g1Z-rxl_XaFnipOWuqRxq3ocMZLZ4YpUmMMA89icLRAoU9mG24RHcMrzkPD9IGUZv3SJVdKwcbmQCD3cBZBb4PEFenDnLbx51GodWRuXniQ0bl4cTlKbTkTJfAe3MpOuUDkcM0FXfnLdq86Hye5N-ygCdFfGozi_EjxF1kNQ6ItrNb_0i9eBhMTgCFHGCVBGWamswc6tICnbQRCDnUXVnvr5qqjno4w3hlXSmlE5w6j5yv7CskyIj8-rsbKW3zZTLMDHIyRqL4xtEqcJSlk-86nfCQj9QVXB4O3W_HLuyWo5cWoTHPwKlArTHx8Ml4Vub7qsgFvEnFzGLwd9QAWnaqD7ENALvims52mSBivuiMMR90nh-jsjbOq6GhckHhWRrtDlfLNcaTVJz-a-s7Zt2Hw-afODG7EemMCtGVRDDZn1Eo0katat1aXH7GU2LCfh-FP80eajowVmMYb5lRHWavhRwpSGTBOsmRECrJHym4ImOGcnxX6VE3Dczh-WNYYjEa0Q4OY1y-S21xExqdgx3SkaOc5G4KGuKdPCh6FAqg4P8Is0QAYnwnjbZZ5mQHfy-oUg1tzbO7yPkY_LNV22NlVqkUfVa1cMMhOzGqTOODaw5ECto3kW1LrIhVieIvKDUnztMMVj6jU8jjZ-mbaOc_Db0JLD4pgEtSmWybS9TqiGk6dcJGXOjDFi3PjwDCSKgwND_0xpTE0QJnumUhlflz6R1sFsE5Nc8rV0QglWQQyseJm-h-taauAkIBzyH3C0595Jkm5LBlM7V-bxtDeFjx-LFqB1rslSSW0dhPxrO6JAB4W6wtyL32UIRTGNOrgh26yboEvUSSZjJBeAO8Tiv3BCKTep1i1d-V291rJjb7sj2o_8XWaNm4tpl04vVY49WttNCxHJ5fM1PuVzbRSoOEF2btxCklDFhp5t8u1Y9mVnJpNMmn5AiCXZZSoyPqrv_j78QUZZXj-x5xwVft5363F1LjjoZ5s3LdEoGbsMAUiwkm7Z7aSr8gmV3uzrv8WyjiJjlc-rpPTE0RHbK_Hc5L9x1HYTJXECSdwZ8Q38yg6uc5EpTut5WPyScHFiDy1ybxnBPPx0tWas7jVULTZaeoGbnkUFo6xTJLMd9Tzzl2IM2zpgL5ZP5c79zxJvUtxgVFwTVmqMQQESj-qXikjBmaXgMLUb4Kv4n9655bgjr3ZuF_rxDagbRdt-_2pgf6VqsHEsaZJHwIpxh01vmyp6ZcQxzSUmi-8faZ_RWCJ5iTpHrMAHvrlPzrerOYBG-RGl2pxJDCVYr_WyUjKbPDxWkjKopcXx0DrYu1C6Cz1-gtGCT18LqoW73MCtdcrwKUXAmLdGUPFG5UFq2vuqItkeXcB1AA2hUhO1rzWYqHnqy2fXm4xtBgXMHVK8dqiXCmWWJ81sezBMVYDUP4MvpPkHRFSLdmG3YrZr0IwT9RzyyDfGItqWheKUJ7fkv0koRczg1J92z4BbyVBzdnEQX4edyyKCYd96ruWi-lEILIFHCY-viwPOIP3wCifcKgMCNGOzaTX3raFo2_VcNfvDSC8cLQq9X0o79qCE1Jeog6jSHUrKYhGsjn8mAJcdf7VzAjNsMpXypG57SMUBz4rd5QGvw3uGTs6M_p4BhciR8o1yOlqCjgRYyxUbCukRH-Od8QDHjRogTAeMjwL_fxEOIKf0pXWw_L3SeEddEfBDGaSU0CWPtCiEpUdu8pXQ-PEPvUFljROnxSr4Q4NQAro_b0FL2Lfk7rSLVJ-mlV8HpUwggz2VC0jjriGZDTCQmLCGFtyYA4qMeL0nJyUD0gfujHGMrqjnBP_TmwUr2qHn6y0jVreD7SpX8ojSYWeO0ebFHyBu6LAJy9VLS7d9Gu5tZ9EVVDCd7MfbDozD1UTevnfxnyGT2-_3xJXnJ2fIzISqkV6vYDmvXAhMHwggCBamQ5VUb5Ri-JQyAOkH-P_d5AzM4vLH3NovPaTs41-EZ9LoA_ACgTwMdXcI6yKNhvbYfHK92GWG0k_HUoZp31nOrUY4hsvoDr1VyJHeFjH2WulFKr4hTj--htE99X95MtcYL1BYJ5KZVT92oX2m2Tauayqr_VP-iYgeiC7WWoo526r5jVWXs1ZgxtzXzylpf5f5z35G4YMC37RFlzgY9kDaeLkMMqUvQo4GbEFbLQ5rF-9zMA2NYFKC-6fUh0hvN1UziR-Co6ZhXi5KP1_3aw2sjSiEwlF3umF4zZcIKjKWtAHrFblBLnUyp79qId8ibcUQm4EHQ92CnkKtAf_e-OB-eZA9Vz8NGagOAFdyAtOFZ17MBcv049eh2izFmxKl4FctOKAEIU1HVWv8IWqmlDyQvsUlwImE-0YFl2EHPizSCLgHM2FgRe1a_k4YEJnQxONr2GUIGL2x8mDl7aBejUmYkkyrCj4Y5XDS1RO_hrmhDB9rAJtukT1PozIgqJTGNHyH_99wqT3cfG37PPWiSuGOG1Rbujp_by2zqGmJx1PjvoRSX7YO_s_apGzAARHZL9n-xFsoXqiJkqM242r7SHsMrqkYckG5IyxjTrpqDWdOSe4xxTc9snA6Bk5EjQ6kb0_VVG20g6kKua9Qy1n-6Jj3BMOaBHcrP4hKKStHySqqLCPOOrqn9hH2s0YKsxknqCVcR6kkCbLi2xD7dpBXmmc-X5MvuK9g9kGBWjfjQSPEfCnhD7b8cDbvWAKJh9vmdR9ofySSWMWQUjRJA43dOTlUpuskklOImDZqitGamjZTfLK4L-gE3wDkavF___kozI04zsB7xOFdPcyL76sUumoAQ_gHA0he0YE0gamTjbJEk6p6NnzuK7PisLkvNS3ZdKqTZ_msTrRSV0IUyypI1qMB-RZDgjWgdccbBTxa9xeoLTLZM8OIEmhsubQF_danFfla5dm8aDiU6k7QpiutDFosvkIJlt5sBbr5Qhwbp-DWyDaX1TI8cCqlDoplTZiZrzf-n65eZMKAcNL3xp0bMYWslR10All84u6IlOqbiiMqIsCFQS4A-Ff3uftu6JqNl8tC_J7H2F0D2W1rDUVYavmTevdbk3MfH6vEClLwnLsB2wQlripHxv77bwlwK5g-4LWHu5N6shsdVMsk7RwdaozdpDB23r4FAok05qbNgHhgpOgu-1MnRK9res5CoVia32tb846NNom_CRss0fLhnAqeU1A8hSZPwsDChHiz8fYCVLpVkCfEX-hgaloQ07R4QyTBXY9puuuJOuOCzhe1IANS4bS1EdGOSWBiDW_Df3q5ky5LOXCOfJjZBvAEkpnX3KJyxdE8K05P3Sj9akt0eG2buFfBLL3rEqBAvOjSWA8FkSF6b8NlLx53itZnn9yiEyL847Z6WGg-Wjs1y-hWSzBh587FAB2z8nTrIAYOQkW0dWJW9Grerc2NraD-hmK4AzTK9f8dCwWSfmc5TB24s6qNRU8Dk4hZ04wAuSQLximtJh3Gv58EABNSSZO6SS8S3SvTR3rRGRYe0Op5EnjoLvT4ZSkLaRFQxld15H3vq66hs9PZo3F3ZxNBO_oDulDXYVvOfeP-16sMfE744LGlucoZBvfeEtjE6Lqabl5jbgByNm08nluPSNGAVOQgExxHcAlL2H29yvMpo78qeqLlkOw3iHi1rEleBFQxcTOE2Ql0vh7gSjgZba0WoI2rl2nD5Bbc5rlTkSa_0-SoDl_aWnpSHLSXHr9y8S1Ryphc6-Tz5uy9lCrplcuHoiF7WUCChE4gv65yf1i0VTw0QjsnwPdnq5Z_EXAou2jLuXaWwNfhIPyyl69n2zEKrKDpDIxS44J4IB5zCA_DFrO1gcI71ibRrcPQiY7Y-H7ejlrGv1TfE1FwZwvphixyc5cVoUJYDZ3pljYH_vIjKAAWr-FC5rNeJDCkXdBwGzrB_fjvju9lNu0bH8xXbQ5xB4vGoorscYBverGCtbbgPof05Ga6uVo_W3_6EJQbJg71kriFa_6haOFWz9Q4sAAOYW1aA1mrEDJY40nG59r2VdQ7EU0X_5mqkwoQGcWddMWgZDFPIITpWOo672O9Egh8luGo8EP9zhRtFIGn2vC494VBDUyVGrKMJLLI1lpoUgGfsndA9JfVJH5J9BaKRqD-GcZh2Fojj05eyJS1Bj62AoqB15nSx1X5ouHF_SkkRBZUPYQqByCrtvcrQxA32PeFZXzc1YVltoLa75LmnhBU4PBA4-KZOaGjL1EYUSU5VcZkLdQVyEXXT7NZDZ9ZchBp5IZEMLkLDNSeguPTpJyTdodbbye-QZdGzHVG9yVH3bqTB_KsEqIaJ30sjX_zi6boK6ZC7ZeGI59ChA_W7jVIT4kHWWPp4WVVlecuKDzePIhc5vr3wUlXotk95470wDp3Jw81QNNu_jRgxJ0dWcIl0Ew41OV8YomZsud_VkXBTn-68KwYcBq-rYGwVFktGpVIOvoIspZvch8d6UhSVG9LcPjN1_TD1GAJ5EQtwSoVak2I9X3zHl0bVeyJ8qrcOQcLc-4ss_YUfY3sOxrv3WO3livMq2e40ec6osSm3EfhR6RKEgOAwnU_VBkS9remIUxsTftJ2ZefPU0ql_HnT7NmiYjO1s38dQbBI68scRYZtzlJ1Yh3uKqww8CG4Sr3s7hkXDl8yEHfQdSza_YSphJWn9TBflKcBa_t05qW2eTtgri54pqNvcDE1V6sJQqucT2xQAodfMaydGk-m2XPCTuAJ3kCgCpJdzH2Ar1eBv-7XLywrFGo9ayBY1cQBOT96XY0txWY3Ju5BPwU1JlRxgitQI8kGND3b3HTDGn-U__abQUMkyL18FPXkEsD5ZnRRvhTeQjeNpjM0TO6uPvk1Xxmnr6_8sR2s0bJKhuHxC47SIospvgW7Fl9BqlCaU1UoQIuP0c1rN1IfKk0OIsAZSMDvSLCze33-8vFyCes1hHSc0MI1zU2CR3cRt9-3TE08lQw6SsUAIM2SSvfsHBXP2Ib7AnoRby4HTrRKngGPXsNIRtMzthrGT1gj1Ey9Ka33YcEz3j1PGK5mJllRi7nrCWDJQt1C9kLcp3qPwWnkq5J3b6VSgLwvdrMSEPKrIJGhB8kugfey0fJduu5-Puw3dH6DvV3sQo7WKdim3JUz611z_oiwL_UzeL48yaDoBQbfe3LH8S6pWoXeCU-Pr2KASZGM8cZlkVKnJWTKa8ne9LdBuRiDpVwVePQ5cDmUn88SYs1KEEqguwB7te3xJ_3HxuPRHqy7gTs70trvBGl8zqVNJsnmKpS3V_E1UtMGLYQ8MFApSA3b6YcJP4j4E6aCD5lakVLGSnMoq3PUof7Kc92NZSWzNq7YfCoAzL1BJoz47MdWn50bnVy4Xa48GLvQgjEJ-MF2i1txejCCw8jpQSZqHLx_PvKT69cw9UkcEzktnd-uT7BruxwIl6mcWdc0oeOjt25zg0IxB62WVVcNHQi_PSC4_kM_cvIx6749xXi_6hyui-2L5ZNQmcd8-7-y_0gaQTaijKThaSg0QtGkWv1lFtBjxxe2_mcANoTlnJPsHOvriL_brQeBfNf0WXwRgUzfUF62hrYCw7OOqH_rbQNBJbHgyyTMhxVtxc-DoGqw9QIVIwZZC-XEl_8vk0D7r-QCW1Desu8eyXl6tDy6kfP-UkuvZv4kZT8cbihvUXmAghgfRfUzR0OK9V1zMIfVgDYPflxtYgAT67creQ7Re3R8f68cVFGT0oJ_ZpN7rYREZ-mGghxVwmNndFboo97n2aLZbBXfqCfLPqMgaE0-nCKB-CYN-PX7Z1tJcNerMllFlpyE8UTw064GPNxAx9J_ZcRPVgAAFdHOe23ajDzaeSRMRKVITIUPugxbKPTWb55fOIwgWOS31s0w9uiGFrScu_7aDvrsI8pXFXLZhSZ2qPnARC6Cz6t3DQPLc-_0W3T5q9iy00AjgTUBSJIIL0WdoU1zoUyJnDY2JZLYYQxaFp1aI9AzMmm9c56Qb_NiBUfJfyVS3I9NaJq91x8QebR4IdO49boC5oAWIERJCkOTLxQUbKy6EXtxpgO1-zhBXXDPKyhAuSj5jnRa7wvRdbKXza6stM81md-AqEvDl6Cnj-FSXdaEo8glAF_XxdgA3UpMx1EyvkuoGcEcoyEsqxc5AdOD4R6cKEdMRl04GGSI7fJp1cuWmJLQqesAjK_VAEnYYrmoQxdZLw8BR1SM13XoWSfEq9dN_uZiwME1CwkTR6mN-WxXfeg-JYDRebAY_idA3xP6lcwFBQsIRebdcRyqgmiZCMyaRJ28ZwOUmpHaqJEiccfbBL0oqO5VFNP1bAq5nsjrvXkmB-a_jAJyAliToyuKc4i-VXMiVwp1jV_outA53A8csMgLmkYHrON3ZA79psVTdnJehE5zdAaObGZt_h4U1fXGGfdzuTIZ8Nr1UlNJVHwrC5Z23DY_Dp7JNHt9TIwktbfaQieUW5IR3-x8vczQewwU3lIu9KrSESjQZSe3Xr029LQpqSe3DuyWCWrLSEun0npCWaCiskfrT3zI31957vIbKdKFD_rfUzKs1byozDw6o0K19litvEClc2PQ8gZWW347WfHIwek-9qAMsRlreFc8n9ASWW_QQxgTRnBBeC4DkuwWmuj4Cfs6xwfu9b9T15jJNYGxIsLVer38U3AS6dEgtwCjwjZ0jfQRV2o_Lr89Qsj4E_EnIbJzZGEKBOIobO-lj72l0sFG5b5_qaMhUsndRRRQo3KoNa3jTtGsBI8EkMb58uLLlqD7sdIEuJ-a-1SQwiSyb9m5P5FIlyykGPFK5okoEOxzwIZSEgdghKXGIq8SQbgkQ83kHkocq7NxBHdX61Egr0V3uEEytgcO2chYZd-WiJWFLLm5zmTeLQfUl7G5CJZwhFGRjpGpYbYGcMkRCEgATzT4jcwzH7KYBMCIXi1bskCDctAy2as0jQnc5ICFzWl76doHdMVJZSvFzFY29_vP8IuVRHSW3hCtODDxLhnvDXMPGt6dOjHN-dq3_NB9mfvHKkOEK10JDpRnvz0k6gstUZDHs28a_BEH8RTb0pXh1rcO35elGh4yDNNKUk26xXKabN3OZMVmsZxxqL_JqptdmC9cNwg7XZ-S1Ey4-6acvec5J4R6GjTcPZWluZLERc2tTSeOtQoJbCJD1shS2NvR60jahncVhdp0ynV1-ZX8oAsMxKFKiB0ZtxdVNLlk4FM2nDzwlHkjbJNlz6xXuR8M74qcWVsgEzEBWyL0INt-KlkSSTIW_JPPnULrxNfDTu20ZQScBx55So1xEURFaCHjUf5P8MV5vr4paC7h0UXlWlj2LD_j9h0T3FYugMqTZuJ_NfPpmY0DpebI-_DY_cbNz6DZEIyicaqZ6MdFZlUz4Q1bpCI6773qdFLUdKS436u4jQcQjlpSbaA0sHl-7Mmr4UWKtEIZv69KCi0XQPqCOsMSYhnteyv7rrH8tL5zNqCIkUW_hKmle5Vblbafbg8wVhaObzO4nZKks-se9yVoMZnYzykm6A9C79qdWg3bRPQ8t7nWcwo42fB6kJ_K4OiMlPklzpWmAkDbTjUeFnqdUV5XhKdZPRWfHABG1jye0AZ9TZR8cS_lutJQGx6NzNzJ2h7qaeWM97ahd1rbGqeYhC3V3El75LYabMagyR5FqKaPXAPvTXdiulOFSb5QjjtOpxjBZQKC4kH_Z_jTmFCqjZ9KHB9FIdkVqqPSZV9eWPHdh4GB1RlfnJoO1qBGXEJfsTrI4BvIGn4FFudiZmQNar57xgkDx2CL3hejyIWssU6MkmvtLqwcha7NgSa9Li6zQHd2pBrfyKUtvE17_aEL9vys-2U8o4KqKph6vSzTprKRShTAmk7hUY8Hn2I2N1frQzOO6sD8NUcGqGlLMh4rjaKQXdideiNkn74J6Wdo2-hlie99H9qpbz26SCsSE0Ucn_HTvynOg3O4HGB4uMhz-CQHsdLh-9aZjw-xLtmbfLDdUEQC8U83rsX9JysbyySFP0bZA5kUTbhN1En5_-E8sXUburEg-nAshSW6WvSvM0ZRVsA0SoaDKIR0Wq8X8hXhK9tpx6rOMmXlcLFwNefRgNvoR7aoM7sRFeBT2QL3yjuHnOV1cZ-li3Fgfb8chV5CCsqAXucplybckQ1SmtDmiGxG9u6M77ODMpU_Cgn_bwtrDwwFci1dFyBPaBhQDx08jIb5tRUoAv0oLbTbl3CTemYSjNQaqWtX_wiDjH4uW1oU89m3CE=', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc', - signature='gAAAAABoxC0Pe79v2UqAMj3Y1BkJi0m_G8llzMHMeav3XGlfPIsphSfHvJVzbyv5s7pvfPLs2-ECy9vhTMaN1UfI_PYmoJ17y_k_lLjvC6sK7SdFeCmdGNjbrgIcah2DJecVqDdoT8P0Aaz6COw982zu34UyGL59e5FTol9mAGvtInH9vXmmQUnGS5fGktT90wC6-MrIxBc3Og92F-e5ciGk0DAVMC90pDTyP4z_Qkj8Jv1QYKqCv4GwFO8LyUicPTbML6l39jyTfH8L86uDWMMxKNsvHEIrqgTQnsInlwnHYVbPURb93_gMtcjOpZwc2ESnjqUtMLXzs8XaKxhU2NVBAzcXL5x2kg7OI7HbS4Vl90Hx5cVwp3i8OTfpw8aRhDoxZJWptxNBKwDDEtjqLbylKQ7m2uJ8_TkK030O0fb81_W1-36qeRn-yNE5jjkKTezyHP0DlpKjCzoY3pZ0GtIj0FRDJOJJOmbHXjC8HfrwBz76tIA64sOz8P5lS1parnESooZidtVudhrYPl5hgZ25w_X5JCOXhXBUGHFaCkiEYUZTydLK9i5W2nfmriUt5wxzG4rSHSq7B2zqLi1GdKg1So2VHEPRfL2GvDVQiRM3K5TPyrjVgoxM8rhmQp65uQ9pM_qHhzWAAr5BvMFVax32yI-gtTzOn8_gC89MleQkHueUbdLxiUDjesO8yIIc2rbzg-KatRma92xVYOS_P9uxzVR8ZI2VuhRfdlrHbvvLC7Crp-Vq-vO3XyNooIl8N6USQbSSCG4m1mt2yqcaUyUZBLPLLi2_mE0g5pF2sm3PRCEYiWtT26go3tZt8_HLF9exTvjOMny_CKAL7Mx2evk40fqbrVY8su1uhqK6AP9XxfkoyZoYWlBkQ3vVSUuFC6lNc2ACGfUFSNqJtE9XKZnwkB3gzw7N5zqFStYvCAjhqqoxFh4peSUf4oEdDEncLFQbct-TFezeTpxEe7wSSMYm9d-YpV48Ne_T_aUMrFevTEnB3x2oqY6M-tokB2mOOjCVJv_QUbDbjigVmBpuOmW_NTTQmVxRIO7_c90ywoMs3KmVmJXgV3Oec7Rp0tC4DjxM3-MznjZ3ctAuO25oxRBlFE5kABPTAZHPwX2nr9HNbH1SyE4GfmzHFzs4qkFNWXMlLcsgrHQ6HsyHoa00_eA40Uy4UucVzS8pDHF3Nt4yy1pDWyRGIkIyp-ptbkSac4Ceq8Gd1CVak6X-xpqe4kdk9Db1BjyBGLo9BMBbAwT54KMwEUrmqRFjTBl4Lqp6AMtoRRDbxAWzKI4X0al1g64B9S2FFKNGm4zs0bDitII2LyON7BZe7x5Bm_agD1SbkdHbmpOtxY10eFPdtShwYPYKr3jGUOILARRxYCICiVRPRKaNvoozEqy0mQVyGREv0byUp3r5YarGhretLddtfZIqFPYcdJhoB2ar25710xMSdnmGGKze-yjxFq-DVKPN-ihWtqpdFaJG93FVAO56v_jURwNM3zIBkTjEDDU80wo6hOiCrm3vjmDN0RzdsXo17WTs_QrD80ZDMI3S5UBqgJqE1Rk8FE2FBZvgQOk9kqWwhVt2XeK7KsOO9uHEMdFthxUTzMWdmbByQBPUeHI-dJHKkbl8kDOc7ljnN80U-eI4vr66kBkg-evTcOLZILsJ0-7IXaTDCiszLae_EbdYeXEIRriHsp63skqod8golNLWT56DkZLyNt5lu8ZE8Bp4QdkSL3rcNv1GQg-sT3DI_bOyQuHZ3zP5-OeEFdrI1n13KrnuaecyDa-lYU23BlGuMBDC3Q6bld3FPcHswew-H0sYgJwry4lhi1qMCRSzQVKvfUc2V658fOqpJO_85ssiSfzkMzNnrE0G1uRPH5_LUA1bAfmoLU5SkbkajMi35nZJzLTg79rVXpUtK8l2xJAKRnobSVKzPD1HT-b1x68vDHp1jFzeGPaM9z7wAC4iwXJLFDJhI_U_uoomw1d5lb47WHuAjpj0Q8Psgk6IMKntdWb0g61GcLZ9OoRyKDkjxar6KtEIZ1cyYVxUGTHTSKKWyrKvhWM9koj8EXkMeKtX3KFleH9AtGBFhExeSPTSJcmnv6t1ZVGSclQxVELOZh-RusLdy-wL06mT-eiBeHGw1H-0S5My-Py2AowI3aBk8YyDPGVH1pCnVfXTIOdQH6idOAsF6SmQahhjxr2KvKPr5Xf3zRAMrlTw6-50HgiEBibhSSWr0fxtZ77dIlesxym_eTfS2V1VHv58Rb3NjFIpL2ayLI6AKAnq29U7RDPXgLjWF4WoNxGkmo6Cc7dWIOsekjQuAQUtJaSSObwP_2HaMwfg5QPdFgt8KkkqOGsDEhXd2Si5ikvN2OFA_dUigfQ8aevQHqv-V7n4nFG8XGWkgfSdYJWMt7Y0SxuBJz7nlsnnggqjRrEI1C5Ae_HjlXKtH9WdYygzOtFGR_iVm--LWQE48-EIeym8g5Q6jwqAbnARFiCcfHyvU2omiGdiN8G9FIVRetDqWUDmdnza2GbJJ0JvoT2O8KPVkXZt8_qWJvTFuJ4Cqkwr-n3aa4BOQQtkB1lELR5rXed2RMNbReXmalMujHSVozgilhQauc6D89CY98ks4Yce32HbUOF753_eMD__ewBxA9DK31i50MrKQVID7UvKot3BsOK4JH2ExIg9CCx-mAbEL6HatGwoiE3zhX0RCO2OHYf66jrbKJ220wTH2O6_BCkihzNKLqTVmpYpPSprwPkkMBNfQTgtEJPJWp9hPoXux4g4z0EtYymZpC4sRVxpBH5mvno2D9i09fh9LM4QT6cf1Plh-6Q3HCupQpiq65g9CmAtJDEiSoIhrxYRkuza65jjabRvkudS8rP4Wm5Qn5ZYlykXUIzC1BVSIvjZPK2OLw_vLG1_iTbsBONDeb9AqQaXiAc4oHqUDSp3RJXvjRfQFNI48eVtk_LLkDd1WNuwQtzAjLAg9UZA6JZGLn66SpFpU_F_bwfHvNWrQ88ZieRDdQcbyCDYNJuqMMq5YOZBpz-Oa0Lun5L8hhUGB_B5FTUQPiiLVIKuHPJP0qLgC2o_R3u9VNfgwnMENnP6pmmVI2mPMFJSHEuDeShRshUSzZ4JOs9fnvpKT3TlyXFOeAtcn89Gilua2ziEfBy78d4Quuik1aL1wQtnr3PBTbn2Z0JGOPZoKybk9CF1a-1K0hoEK54-jRgTrPGseSMibhGO9x-5bW5viQVORDH1L9g2kcfJur1D-04cDlzkAB6hfjuqk1pvT3S3O2UGU37CZcVF_iolUucC8snhW5uhuvSdoBXXcnF7TuwsgAKNvztnf7B3tPJTW8x5Q5PGqHmRsoilCFlbslJCGq4h6NraPfKGY0Qq48A_i9QQGOihf1BI3OJE5usPGaxe6yJTpGQt5xCNuMCI920xIfCuQUx5BmVDAjho7EPkcDHoUWF53iZHPp7RSlC0uVABjJaaOREGT3oludmKOYY4PoZGMFNU_4Qm2UlT_OQ3XXhon0dcjT9j7OffzgjOiYy1HUMGpSyFdvIotQQSfAzNirsXZtZX7sVKXDPtOwzALnhd27odnEnYHpep03mmDI58plDhffF_rnw326mggOpYGBEgFNdtQCwoOe9P73E3762lRYHl6IOidAG6oaIP8sr3TU5xXhzJ7iqSKQbD4UMwolnNjUjVCwGMsLj137JYfUgQBmiu-5HuRuyD3jcRmddrWnofPg_uv_99W9i0tLvW9pAk5YDDUm6fFruGbYGXUa85g7iYuB6cY3lArHpPvBhpgFuH8FEexXhtJVRAFsT-Z7nvI5Hfh-Dk2M-Dv7ITg7er2mCwxG0ZmPMSx2kglqF8bZTxk7EqfGVQMvtgQMZTDij5dCIK3PzpoLqwNMd44fViVc4VXNR6o_gFx-XyKY6PVCN-OtGVQB2B6f6LikWyIMaIB5Jic7zT0lMsf8n9aSgi1UQdiR9RuizqInhxoW3IcdPpbHzyYKMyfsgE-VKX15pPOiL3stMrq7gSmX4itErJBKq2yocNH4QHjoqFsndWK3VNc6rzkdcZZqhu_ZN3xW31q57PzZbNMfQ_IUCuNPwcTCHnBiQVRZQaaiXvyVBh2NcBXLEdqr3Xuh8Q2BgCo9ZiW6fdqXOgSAd5gwxGOeQ_Cr-HLQMhB8bFE2szFWttri01hxyXOnpPt6ziDw_t4bGYB9WqaEMjCe_3iUgLjniX9hwPuQVhTDHvwkTaddSQ-SVE4JJJ5-IY7_0MAy7_swITfNP_7Wd_-XrdJ-PzUgKdKs8E7QSd2hpK6Vv7SGlsEHzPxljtHLsvEOGeTxkuBhc4KktOI3ezaooG0IgpQr7d7-viS2PF2Ri6-zkoXH3fosjCc_d5DtOvbPn_hE1Pnu-rCWnilbekyGhOquEAYsErlioLhpSaP15wkFzcZIMlV1aEPlrM6WzcCJX8cdeV0Z7fL1v7R11Jhux8h7bpW5Dm5mWtwpfg23XtywAcSXB8F1GuSZXJ4CZHq6vj6lAUqS0YigZBzMZe7UdOZUIK0VFTY1Kl50eI9Sptiy5AEPhDdaUT1daa-_g4BqJtelvtpF7XvIpPvEtlrLJBjimxCJU28-QUJDaBeKa9rtQTWf-4kyY05ITG9ke7qUnC9Sc_LDkeCEnDNjzStbf2B-r-ov9f2pUTJXDKkP4TwwiZ-AlDGHoKExZLJQYsek_DHS8rzwbRsjuhnU-toirFjZ1nH83XcYh6OKaE-7EsoUXWs5z16ntWeNJpEifCh5JNZJ_XC7BeKiL2uldqu4naYwBnwrrz7v2UAxOv2KusUwC5WHjkueRjgQtgS15Uf3khMDZYxMIKJeU_27POO84uQXsAVdPs_L4yL36hqVdT69WNfJzPuKsFiGkheoxC8SdGCaeUgpPZ24KZgDE6TLVaYin1xRBm3h-HxpAo86vjvM5LnpuVAy_0iJa4r5ozxhfjzJ7fPjQSk835tjZ8hls4yftUJNpOJM0cruJT25qsQS-RD36X4EF0BSPEdFJdN-z_CQK3LfAKcNSvO8UR7T_FEFzpH58qS98DR83avQuNx54lQ5h9ICIi3fxSHs1eO7c5m7jaCV8VHL6Mjkniqf_ZW0123BZxC2AeGcucAD9iPYeXFI5ob65AcL6TA3k1J8gOX58RIdIdzW9mkwMjJNMNEWYpEbsevRuQ_APKGJVyu014wYGeueKk9jQjgt8YQyLC7bT7eQKNrhWrT4Xfib6neWmhV9NRXVB8o434srI7Cw2sJaWSbJGAKgov2m-fvSEq2zqbNKQNqguIqsw-QvubN5u5c00PUldQs0zISnVthXAWJKlmuNxVykdN5HoDkKfAthnQv2pVc4mZK34DfcEo3Xc-1Ssysg4qOzHR4zTCY1GFX9FVKvO3C_CHI27gi_3pFjq3CcgV2_LZ3_p0g9IlCy2-6WKcRzBf_8jbuLb2kw4zGK_cG06YeeAzzMqPrtmx1tEshJF0sKAWWBzYYc2RE1Sn_QOP6YSxei2TKvB3k8Xvnp7TK-28hcJIDnZIbbU_4TkuoXz_MwbNEcE2q6YMxC86WT0qc7YXxAY3Gp0sNOypZ7QDxz8kBrzo3px5j81zDq1kxF-ZEIclPuFCXJ9s4NPaXrkjFmWnTvPmVc9F2u0JmkNgl71WaC7pRar3QpD_kbEJp-zcOFzyUnteiJKnQdbTdxZal7OT2GyfNDWpfJ3wmRZHjgAihyhDeGR7bPC95eMwEfp7ggXQrCrfLuFwMtkFPq539rnmbQ2D1GoW6f4RMtkF5p9UyihUaAjP4LC69e9dH4A5InMJmDpPfExf-_PEoiSgVTXWC58pb4DXm5QcvZj-4c-NDnlbWb_YbU-skdRq6ReAjIjWMNdRUoaU3b3EpWLTqVCsN2ZZNmqp7is5oGJG8Xyswb6VlGQq4ij5ZgGRE1YVVzMnoBVObpw2lxeDPldsK6ZbmzLq2cG4glgKPi13X5ZlQGb7eVdAgp9LZehOm8kOTljE5sLGmYJJpkmKE6hiddQeG7wxRSqcEoIctTRfMruXQL4gsPXgtpaYsTR6vi_MVrFSobxf_8DmhAkbUHNcyj6H1HVm4JRA0isGBoicUxzhybBn0heWjprPfnOD9eO_YpuUXxBrlC63LBKLQmsVkqkNI2mfTSKxVnx_f1QeuhJw4Rrp7iVyvCCE83XEr2uujo9uxm62zHvu6FHlJBSpdeX11DGUkXLScUtkFaCgHw8dcBsnG7jloDKJFOOs3i-cxOe-dWqlaVti5_sUmCLxNFIBk2TjZP44qQ7pQMT-Wp7b0o28IHGkaiIebz20xiWNOSYstZwq1xYIwhnQtCnAibqxE5kc6gtZbuF06NqD1h9fROgp9jdqGyucjHXs0zlkO1sBGgkz-8VnkF97h3rtdkqWSTZweI28dYQ0GYXagSSIgXmQp0QM7pzDp_JO85NYpR3CZW29aB6gdzuSbDoFciWd2UTsQX3HTEIsGxhtRtMa4ZPHyS5tHAKSlquhLOTHMTQfi8GO_VHsj241Hk3S56jM9Czovx-5OwRB8qKFNiHwKOvliSJR1HgXBkAleRIALJ64fDz5cUgy6Mn13Loue3JcowCAIgkrnusjVLig-y95xVvbs1Ys1rUFFKy3mmVaVyYd4Qe-WBLG-pZXug1z8gLTEZkY636ssMr_wIl2Zl-ciykcbiH6S9yTY358VqZgzQBS-44sQTdT_qelrVSNMLKneMs06JSjhSJOpmogW1I_hdHMtxkkSOQxKINvyEHPFbIkUR734qjhDVUPweD3IUQdMJ995R89D5cl94H0REAU_wJxDSGwGlux1P9ul1FHsX9hGTiNU6cE_qAD8fWX5ceOBa2iCoNefiQw1Ft9xh6QYDe2lOPdpIeihKm2ABWMVJ3hGCYwg-QPhj6yrSbZ4DSxCMPfC3NQ0Zarj5VgvfHOIO_gGiE9plkknoLBM_j1VSP7prfUOXQsA4sSu8eYhkreMkSVRk2JJ4JY2u1s9zATCq4cTUcKwdhgasU-mzPJRc0PF_7JsrojJ-GphyN_vGSzv_kBtl1Oo7IIHNo4UYiMpioxeBd3UV44oL8wOgImfs3a1Fnb-fHOS0RHkn1P57V-QGQcbQOoXtSqcDLjCJEJ144_QQa9jSCRUYXVv5VEYGfEcpaeyP62FFvLkeNfonGiObjVxXM2mnqV9gXm8Tf_NE7HgbthKKN9zbfOSyHos03LDBIYqScCnENopFX6XyY_iHOZwtfRojYmlZcfbtM7AA5K47Ycx1hC7A3U3x9CjHjhLZhqcQXdFeMNyfbEMabj4ESo0vqfKOFhif_U49MwLg9Q7cquuJ7zoduXmiBrlm2hPgzzpEK_JBC9vmc3FrxbBV4fZKr2EXYevtvSrWJ2-trlF5u9WO2xC6oxCuTUVisluvCWwhy0de3tulbLHlKV8xYEh_MvJy8tyqeOS4Y5lLtTtwuA4rTVNrYp4-otD6ZPQolK9k1vGCQtuTbgUR0Ya2m7vMDd10zU79haM0C6y723o3meJ6Yf2tIqffTk6YRpDw4yFiM0xKRP1NvkMT8T-3ptVnIBz4laUp_HDoTT1EQsmKYFtgMMaqTRImxH75v7FW0MGXT1578lBSB-PW_3U4zR8NpxvuBfLrzHcWOQv1bJ5m-v3ho91V0wXM9X4qEiA0CbGw3UdrrZ80VSeEa_wU6mQFG5IUB85_AaMkKjZsqoO7rZ4T_GAn3uqVmObN59eCgERccyBogj3s3oHk8yEXIhtzIC4wwNbiNhPBVako-_6YJOU5FnYu7VXVAWBNZsTMi9XuZY9oXTQLoU8Ya_Ix8baVrArLSAEDUih5mZvtgEzn9rBRJEarsCi5VMojQk5vzDpKjz21R7sNYTaiNikeM7AKRTtEa-N7FtdO432Gf4y4BYTctIi6ftUPj5mRbDm-ul19u89mnGx6VA4h4GZ0oWRtCP72svGw7zV_I301Qcl1m9TxFRCZvqDEvbU_GaRlL1VzR_QUOixSfCMrlovCtycE_zXE_oyMSjPXzA17wklLjG-gEFT0FUcvlohTKLlQKAUOvkalRMsao_DoGOYRfd6e8LtuKfaRnat9iq2RJ8OfbZw4kLmT73kaszYaFDPufKFvXt0nIxi_ysbX28Y5zZq6KHKwLmcceFqwwmZV2ayAvYjBZqBYpPLTfvEUd0-3n00bXi0hLP8Il8D1F_2ZcrQcHyc2g-g1Z-rxl_XaFnipOWuqRxq3ocMZLZ4YpUmMMA89icLRAoU9mG24RHcMrzkPD9IGUZv3SJVdKwcbmQCD3cBZBb4PEFenDnLbx51GodWRuXniQ0bl4cTlKbTkTJfAe3MpOuUDkcM0FXfnLdq86Hye5N-ygCdFfGozi_EjxF1kNQ6ItrNb_0i9eBhMTgCFHGCVBGWamswc6tICnbQRCDnUXVnvr5qqjno4w3hlXSmlE5w6j5yv7CskyIj8-rsbKW3zZTLMDHIyRqL4xtEqcJSlk-86nfCQj9QVXB4O3W_HLuyWo5cWoTHPwKlArTHx8Ml4Vub7qsgFvEnFzGLwd9QAWnaqD7ENALvims52mSBivuiMMR90nh-jsjbOq6GhckHhWRrtDlfLNcaTVJz-a-s7Zt2Hw-afODG7EemMCtGVRDDZn1Eo0katat1aXH7GU2LCfh-FP80eajowVmMYb5lRHWavhRwpSGTBOsmRECrJHym4ImOGcnxX6VE3Dczh-WNYYjEa0Q4OY1y-S21xExqdgx3SkaOc5G4KGuKdPCh6FAqg4P8Is0QAYnwnjbZZ5mQHfy-oUg1tzbO7yPkY_LNV22NlVqkUfVa1cMMhOzGqTOODaw5ECto3kW1LrIhVieIvKDUnztMMVj6jU8jjZ-mbaOc_Db0JLD4pgEtSmWybS9TqiGk6dcJGXOjDFi3PjwDCSKgwND_0xpTE0QJnumUhlflz6R1sFsE5Nc8rV0QglWQQyseJm-h-taauAkIBzyH3C0595Jkm5LBlM7V-bxtDeFjx-LFqB1rslSSW0dhPxrO6JAB4W6wtyL32UIRTGNOrgh26yboEvUSSZjJBeAO8Tiv3BCKTep1i1d-V291rJjb7sj2o_8XWaNm4tpl04vVY49WttNCxHJ5fM1PuVzbRSoOEF2btxCklDFhp5t8u1Y9mVnJpNMmn5AiCXZZSoyPqrv_j78QUZZXj-x5xwVft5363F1LjjoZ5s3LdEoGbsMAUiwkm7Z7aSr8gmV3uzrv8WyjiJjlc-rpPTE0RHbK_Hc5L9x1HYTJXECSdwZ8Q38yg6uc5EpTut5WPyScHFiDy1ybxnBPPx0tWas7jVULTZaeoGbnkUFo6xTJLMd9Tzzl2IM2zpgL5ZP5c79zxJvUtxgVFwTVmqMQQESj-qXikjBmaXgMLUb4Kv4n9655bgjr3ZuF_rxDagbRdt-_2pgf6VqsHEsaZJHwIpxh01vmyp6ZcQxzSUmi-8faZ_RWCJ5iTpHrMAHvrlPzrerOYBG-RGl2pxJDCVYr_WyUjKbPDxWkjKopcXx0DrYu1C6Cz1-gtGCT18LqoW73MCtdcrwKUXAmLdGUPFG5UFq2vuqItkeXcB1AA2hUhO1rzWYqHnqy2fXm4xtBgXMHVK8dqiXCmWWJ81sezBMVYDUP4MvpPkHRFSLdmG3YrZr0IwT9RzyyDfGItqWheKUJ7fkv0koRczg1J92z4BbyVBzdnEQX4edyyKCYd96ruWi-lEILIFHCY-viwPOIP3wCifcKgMCNGOzaTX3raFo2_VcNfvDSC8cLQq9X0o79qCE1Jeog6jSHUrKYhGsjn8mAJcdf7VzAjNsMpXypG57SMUBz4rd5QGvw3uGTs6M_p4BhciR8o1yOlqCjgRYyxUbCukRH-Od8QDHjRogTAeMjwL_fxEOIKf0pXWw_L3SeEddEfBDGaSU0CWPtCiEpUdu8pXQ-PEPvUFljROnxSr4Q4NQAro_b0FL2Lfk7rSLVJ-mlV8HpUwggz2VC0jjriGZDTCQmLCGFtyYA4qMeL0nJyUD0gfujHGMrqjnBP_TmwUr2qHn6y0jVreD7SpX8ojSYWeO0ebFHyBu6LAJy9VLS7d9Gu5tZ9EVVDCd7MfbDozD1UTevnfxnyGT2-_3xJXnJ2fIzISqkV6vYDmvXAhMHwggCBamQ5VUb5Ri-JQyAOkH-P_d5AzM4vLH3NovPaTs41-EZ9LoA_ACgTwMdXcI6yKNhvbYfHK92GWG0k_HUoZp31nOrUY4hsvoDr1VyJHeFjH2WulFKr4hTj--htE99X95MtcYL1BYJ5KZVT92oX2m2Tauayqr_VP-iYgeiC7WWoo526r5jVWXs1ZgxtzXzylpf5f5z35G4YMC37RFlzgY9kDaeLkMMqUvQo4GbEFbLQ5rF-9zMA2NYFKC-6fUh0hvN1UziR-Co6ZhXi5KP1_3aw2sjSiEwlF3umF4zZcIKjKWtAHrFblBLnUyp79qId8ibcUQm4EHQ92CnkKtAf_e-OB-eZA9Vz8NGagOAFdyAtOFZ17MBcv049eh2izFmxKl4FctOKAEIU1HVWv8IWqmlDyQvsUlwImE-0YFl2EHPizSCLgHM2FgRe1a_k4YEJnQxONr2GUIGL2x8mDl7aBejUmYkkyrCj4Y5XDS1RO_hrmhDB9rAJtukT1PozIgqJTGNHyH_99wqT3cfG37PPWiSuGOG1Rbujp_by2zqGmJx1PjvoRSX7YO_s_apGzAARHZL9n-xFsoXqiJkqM242r7SHsMrqkYckG5IyxjTrpqDWdOSe4xxTc9snA6Bk5EjQ6kb0_VVG20g6kKua9Qy1n-6Jj3BMOaBHcrP4hKKStHySqqLCPOOrqn9hH2s0YKsxknqCVcR6kkCbLi2xD7dpBXmmc-X5MvuK9g9kGBWjfjQSPEfCnhD7b8cDbvWAKJh9vmdR9ofySSWMWQUjRJA43dOTlUpuskklOImDZqitGamjZTfLK4L-gE3wDkavF___kozI04zsB7xOFdPcyL76sUumoAQ_gHA0he0YE0gamTjbJEk6p6NnzuK7PisLkvNS3ZdKqTZ_msTrRSV0IUyypI1qMB-RZDgjWgdccbBTxa9xeoLTLZM8OIEmhsubQF_danFfla5dm8aDiU6k7QpiutDFosvkIJlt5sBbr5Qhwbp-DWyDaX1TI8cCqlDoplTZiZrzf-n65eZMKAcNL3xp0bMYWslR10All84u6IlOqbiiMqIsCFQS4A-Ff3uftu6JqNl8tC_J7H2F0D2W1rDUVYavmTevdbk3MfH6vEClLwnLsB2wQlripHxv77bwlwK5g-4LWHu5N6shsdVMsk7RwdaozdpDB23r4FAok05qbNgHhgpOgu-1MnRK9res5CoVia32tb846NNom_CRss0fLhnAqeU1A8hSZPwsDChHiz8fYCVLpVkCfEX-hgaloQ07R4QyTBXY9puuuJOuOCzhe1IANS4bS1EdGOSWBiDW_Df3q5ky5LOXCOfJjZBvAEkpnX3KJyxdE8K05P3Sj9akt0eG2buFfBLL3rEqBAvOjSWA8FkSF6b8NlLx53itZnn9yiEyL847Z6WGg-Wjs1y-hWSzBh587FAB2z8nTrIAYOQkW0dWJW9Grerc2NraD-hmK4AzTK9f8dCwWSfmc5TB24s6qNRU8Dk4hZ04wAuSQLximtJh3Gv58EABNSSZO6SS8S3SvTR3rRGRYe0Op5EnjoLvT4ZSkLaRFQxld15H3vq66hs9PZo3F3ZxNBO_oDulDXYVvOfeP-16sMfE744LGlucoZBvfeEtjE6Lqabl5jbgByNm08nluPSNGAVOQgExxHcAlL2H29yvMpo78qeqLlkOw3iHi1rEleBFQxcTOE2Ql0vh7gSjgZba0WoI2rl2nD5Bbc5rlTkSa_0-SoDl_aWnpSHLSXHr9y8S1Ryphc6-Tz5uy9lCrplcuHoiF7WUCChE4gv65yf1i0VTw0QjsnwPdnq5Z_EXAou2jLuXaWwNfhIPyyl69n2zEKrKDpDIxS44J4IB5zCA_DFrO1gcI71ibRrcPQiY7Y-H7ejlrGv1TfE1FwZwvphixyc5cVoUJYDZ3pljYH_vIjKAAWr-FC5rNeJDCkXdBwGzrB_fjvju9lNu0bH8xXbQ5xB4vGoorscYBverGCtbbgPof05Ga6uVo_W3_6EJQbJg71kriFa_6haOFWz9Q4sAAOYW1aA1mrEDJY40nG59r2VdQ7EU0X_5mqkwoQGcWddMWgZDFPIITpWOo672O9Egh8luGo8EP9zhRtFIGn2vC494VBDUyVGrKMJLLI1lpoUgGfsndA9JfVJH5J9BaKRqD-GcZh2Fojj05eyJS1Bj62AoqB15nSx1X5ouHF_SkkRBZUPYQqByCrtvcrQxA32PeFZXzc1YVltoLa75LmnhBU4PBA4-KZOaGjL1EYUSU5VcZkLdQVyEXXT7NZDZ9ZchBp5IZEMLkLDNSeguPTpJyTdodbbye-QZdGzHVG9yVH3bqTB_KsEqIaJ30sjX_zi6boK6ZC7ZeGI59ChA_W7jVIT4kHWWPp4WVVlecuKDzePIhc5vr3wUlXotk95470wDp3Jw81QNNu_jRgxJ0dWcIl0Ew41OV8YomZsud_VkXBTn-68KwYcBq-rYGwVFktGpVIOvoIspZvch8d6UhSVG9LcPjN1_TD1GAJ5EQtwSoVak2I9X3zHl0bVeyJ8qrcOQcLc-4ss_YUfY3sOxrv3WO3livMq2e40ec6osSm3EfhR6RKEgOAwnU_VBkS9remIUxsTftJ2ZefPU0ql_HnT7NmiYjO1s38dQbBI68scRYZtzlJ1Yh3uKqww8CG4Sr3s7hkXDl8yEHfQdSza_YSphJWn9TBflKcBa_t05qW2eTtgri54pqNvcDE1V6sJQqucT2xQAodfMaydGk-m2XPCTuAJ3kCgCpJdzH2Ar1eBv-7XLywrFGo9ayBY1cQBOT96XY0txWY3Ju5BPwU1JlRxgitQI8kGND3b3HTDGn-U__abQUMkyL18FPXkEsD5ZnRRvhTeQjeNpjM0TO6uPvk1Xxmnr6_8sR2s0bJKhuHxC47SIospvgW7Fl9BqlCaU1UoQIuP0c1rN1IfKk0OIsAZSMDvSLCze33-8vFyCes1hHSc0MI1zU2CR3cRt9-3TE08lQw6SsUAIM2SSvfsHBXP2Ib7AnoRby4HTrRKngGPXsNIRtMzthrGT1gj1Ey9Ka33YcEz3j1PGK5mJllRi7nrCWDJQt1C9kLcp3qPwWnkq5J3b6VSgLwvdrMSEPKrIJGhB8kugfey0fJduu5-Puw3dH6DvV3sQo7WKdim3JUz611z_oiwL_UzeL48yaDoBQbfe3LH8S6pWoXeCU-Pr2KASZGM8cZlkVKnJWTKa8ne9LdBuRiDpVwVePQ5cDmUn88SYs1KEEqguwB7te3xJ_3HxuPRHqy7gTs70trvBGl8zqVNJsnmKpS3V_E1UtMGLYQ8MFApSA3b6YcJP4j4E6aCD5lakVLGSnMoq3PUof7Kc92NZSWzNq7YfCoAzL1BJoz47MdWn50bnVy4Xa48GLvQgjEJ-MF2i1txejCCw8jpQSZqHLx_PvKT69cw9UkcEzktnd-uT7BruxwIl6mcWdc0oeOjt25zg0IxB62WVVcNHQi_PSC4_kM_cvIx6749xXi_6hyui-2L5ZNQmcd8-7-y_0gaQTaijKThaSg0QtGkWv1lFtBjxxe2_mcANoTlnJPsHOvriL_brQeBfNf0WXwRgUzfUF62hrYCw7OOqH_rbQNBJbHgyyTMhxVtxc-DoGqw9QIVIwZZC-XEl_8vk0D7r-QCW1Desu8eyXl6tDy6kfP-UkuvZv4kZT8cbihvUXmAghgfRfUzR0OK9V1zMIfVgDYPflxtYgAT67creQ7Re3R8f68cVFGT0oJ_ZpN7rYREZ-mGghxVwmNndFboo97n2aLZbBXfqCfLPqMgaE0-nCKB-CYN-PX7Z1tJcNerMllFlpyE8UTw064GPNxAx9J_ZcRPVgAAFdHOe23ajDzaeSRMRKVITIUPugxbKPTWb55fOIwgWOS31s0w9uiGFrScu_7aDvrsI8pXFXLZhSZ2qPnARC6Cz6t3DQPLc-_0W3T5q9iy00AjgTUBSJIIL0WdoU1zoUyJnDY2JZLYYQxaFp1aI9AzMmm9c56Qb_NiBUfJfyVS3I9NaJq91x8QebR4IdO49boC5oAWIERJCkOTLxQUbKy6EXtxpgO1-zhBXXDPKyhAuSj5jnRa7wvRdbKXza6stM81md-AqEvDl6Cnj-FSXdaEo8glAF_XxdgA3UpMx1EyvkuoGcEcoyEsqxc5AdOD4R6cKEdMRl04GGSI7fJp1cuWmJLQqesAjK_VAEnYYrmoQxdZLw8BR1SM13XoWSfEq9dN_uZiwME1CwkTR6mN-WxXfeg-JYDRebAY_idA3xP6lcwFBQsIRebdcRyqgmiZCMyaRJ28ZwOUmpHaqJEiccfbBL0oqO5VFNP1bAq5nsjrvXkmB-a_jAJyAliToyuKc4i-VXMiVwp1jV_outA53A8csMgLmkYHrON3ZA79psVTdnJehE5zdAaObGZt_h4U1fXGGfdzuTIZ8Nr1UlNJVHwrC5Z23DY_Dp7JNHt9TIwktbfaQieUW5IR3-x8vczQewwU3lIu9KrSESjQZSe3Xr029LQpqSe3DuyWCWrLSEun0npCWaCiskfrT3zI31957vIbKdKFD_rfUzKs1byozDw6o0K19litvEClc2PQ8gZWW347WfHIwek-9qAMsRlreFc8n9ASWW_QQxgTRnBBeC4DkuwWmuj4Cfs6xwfu9b9T15jJNYGxIsLVer38U3AS6dEgtwCjwjZ0jfQRV2o_Lr89Qsj4E_EnIbJzZGEKBOIobO-lj72l0sFG5b5_qaMhUsndRRRQo3KoNa3jTtGsBI8EkMb58uLLlqD7sdIEuJ-a-1SQwiSyb9m5P5FIlyykGPFK5okoEOxzwIZSEgdghKXGIq8SQbgkQ83kHkocq7NxBHdX61Egr0V3uEEytgcO2chYZd-WiJWFLLm5zmTeLQfUl7G5CJZwhFGRjpGpYbYGcMkRCEgATzT4jcwzH7KYBMCIXi1bskCDctAy2as0jQnc5ICFzWl76doHdMVJZSvFzFY29_vP8IuVRHSW3hCtODDxLhnvDXMPGt6dOjHN-dq3_NB9mfvHKkOEK10JDpRnvz0k6gstUZDHs28a_BEH8RTb0pXh1rcO35elGh4yDNNKUk26xXKabN3OZMVmsZxxqL_JqptdmC9cNwg7XZ-S1Ey4-6acvec5J4R6GjTcPZWluZLERc2tTSeOtQoJbCJD1shS2NvR60jahncVhdp0ynV1-ZX8oAsMxKFKiB0ZtxdVNLlk4FM2nDzwlHkjbJNlz6xXuR8M74qcWVsgEzEBWyL0INt-KlkSSTIW_JPPnULrxNfDTu20ZQScBx55So1xEURFaCHjUf5P8MV5vr4paC7h0UXlWlj2LD_j9h0T3FYugMqTZuJ_NfPpmY0DpebI-_DY_cbNz6DZEIyicaqZ6MdFZlUz4Q1bpCI6773qdFLUdKS436u4jQcQjlpSbaA0sHl-7Mmr4UWKtEIZv69KCi0XQPqCOsMSYhnteyv7rrH8tL5zNqCIkUW_hKmle5Vblbafbg8wVhaObzO4nZKks-se9yVoMZnYzykm6A9C79qdWg3bRPQ8t7nWcwo42fB6kJ_K4OiMlPklzpWmAkDbTjUeFnqdUV5XhKdZPRWfHABG1jye0AZ9TZR8cS_lutJQGx6NzNzJ2h7qaeWM97ahd1rbGqeYhC3V3El75LYabMagyR5FqKaPXAPvTXdiulOFSb5QjjtOpxjBZQKC4kH_Z_jTmFCqjZ9KHB9FIdkVqqPSZV9eWPHdh4GB1RlfnJoO1qBGXEJfsTrI4BvIGn4FFudiZmQNar57xgkDx2CL3hejyIWssU6MkmvtLqwcha7NgSa9Li6zQHd2pBrfyKUtvE17_aEL9vys-2U8o4KqKph6vSzTprKRShTAmk7hUY8Hn2I2N1frQzOO6sD8NUcGqGlLMh4rjaKQXdideiNkn74J6Wdo2-hlie99H9qpbz26SCsSE0Ucn_HTvynOg3O4HGB4uMhz-CQHsdLh-9aZjw-xLtmbfLDdUEQC8U83rsX9JysbyySFP0bZA5kUTbhN1En5_-E8sXUburEg-nAshSW6WvSvM0ZRVsA0SoaDKIR0Wq8X8hXhK9tpx6rOMmXlcLFwNefRgNvoR7aoM7sRFeBT2QL3yjuHnOV1cZ-li3Fgfb8chV5CCsqAXucplybckQ1SmtDmiGxG9u6M77ODMpU_Cgn_bwtrDwwFci1dFyBPaBhQDx08jIb5tRUoAv0oLbTbl3CTemYSjNQaqWtX_wiDjH4uW1oU89m3CE=', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc', - signature='gAAAAABoxC0Pe79v2UqAMj3Y1BkJi0m_G8llzMHMeav3XGlfPIsphSfHvJVzbyv5s7pvfPLs2-ECy9vhTMaN1UfI_PYmoJ17y_k_lLjvC6sK7SdFeCmdGNjbrgIcah2DJecVqDdoT8P0Aaz6COw982zu34UyGL59e5FTol9mAGvtInH9vXmmQUnGS5fGktT90wC6-MrIxBc3Og92F-e5ciGk0DAVMC90pDTyP4z_Qkj8Jv1QYKqCv4GwFO8LyUicPTbML6l39jyTfH8L86uDWMMxKNsvHEIrqgTQnsInlwnHYVbPURb93_gMtcjOpZwc2ESnjqUtMLXzs8XaKxhU2NVBAzcXL5x2kg7OI7HbS4Vl90Hx5cVwp3i8OTfpw8aRhDoxZJWptxNBKwDDEtjqLbylKQ7m2uJ8_TkK030O0fb81_W1-36qeRn-yNE5jjkKTezyHP0DlpKjCzoY3pZ0GtIj0FRDJOJJOmbHXjC8HfrwBz76tIA64sOz8P5lS1parnESooZidtVudhrYPl5hgZ25w_X5JCOXhXBUGHFaCkiEYUZTydLK9i5W2nfmriUt5wxzG4rSHSq7B2zqLi1GdKg1So2VHEPRfL2GvDVQiRM3K5TPyrjVgoxM8rhmQp65uQ9pM_qHhzWAAr5BvMFVax32yI-gtTzOn8_gC89MleQkHueUbdLxiUDjesO8yIIc2rbzg-KatRma92xVYOS_P9uxzVR8ZI2VuhRfdlrHbvvLC7Crp-Vq-vO3XyNooIl8N6USQbSSCG4m1mt2yqcaUyUZBLPLLi2_mE0g5pF2sm3PRCEYiWtT26go3tZt8_HLF9exTvjOMny_CKAL7Mx2evk40fqbrVY8su1uhqK6AP9XxfkoyZoYWlBkQ3vVSUuFC6lNc2ACGfUFSNqJtE9XKZnwkB3gzw7N5zqFStYvCAjhqqoxFh4peSUf4oEdDEncLFQbct-TFezeTpxEe7wSSMYm9d-YpV48Ne_T_aUMrFevTEnB3x2oqY6M-tokB2mOOjCVJv_QUbDbjigVmBpuOmW_NTTQmVxRIO7_c90ywoMs3KmVmJXgV3Oec7Rp0tC4DjxM3-MznjZ3ctAuO25oxRBlFE5kABPTAZHPwX2nr9HNbH1SyE4GfmzHFzs4qkFNWXMlLcsgrHQ6HsyHoa00_eA40Uy4UucVzS8pDHF3Nt4yy1pDWyRGIkIyp-ptbkSac4Ceq8Gd1CVak6X-xpqe4kdk9Db1BjyBGLo9BMBbAwT54KMwEUrmqRFjTBl4Lqp6AMtoRRDbxAWzKI4X0al1g64B9S2FFKNGm4zs0bDitII2LyON7BZe7x5Bm_agD1SbkdHbmpOtxY10eFPdtShwYPYKr3jGUOILARRxYCICiVRPRKaNvoozEqy0mQVyGREv0byUp3r5YarGhretLddtfZIqFPYcdJhoB2ar25710xMSdnmGGKze-yjxFq-DVKPN-ihWtqpdFaJG93FVAO56v_jURwNM3zIBkTjEDDU80wo6hOiCrm3vjmDN0RzdsXo17WTs_QrD80ZDMI3S5UBqgJqE1Rk8FE2FBZvgQOk9kqWwhVt2XeK7KsOO9uHEMdFthxUTzMWdmbByQBPUeHI-dJHKkbl8kDOc7ljnN80U-eI4vr66kBkg-evTcOLZILsJ0-7IXaTDCiszLae_EbdYeXEIRriHsp63skqod8golNLWT56DkZLyNt5lu8ZE8Bp4QdkSL3rcNv1GQg-sT3DI_bOyQuHZ3zP5-OeEFdrI1n13KrnuaecyDa-lYU23BlGuMBDC3Q6bld3FPcHswew-H0sYgJwry4lhi1qMCRSzQVKvfUc2V658fOqpJO_85ssiSfzkMzNnrE0G1uRPH5_LUA1bAfmoLU5SkbkajMi35nZJzLTg79rVXpUtK8l2xJAKRnobSVKzPD1HT-b1x68vDHp1jFzeGPaM9z7wAC4iwXJLFDJhI_U_uoomw1d5lb47WHuAjpj0Q8Psgk6IMKntdWb0g61GcLZ9OoRyKDkjxar6KtEIZ1cyYVxUGTHTSKKWyrKvhWM9koj8EXkMeKtX3KFleH9AtGBFhExeSPTSJcmnv6t1ZVGSclQxVELOZh-RusLdy-wL06mT-eiBeHGw1H-0S5My-Py2AowI3aBk8YyDPGVH1pCnVfXTIOdQH6idOAsF6SmQahhjxr2KvKPr5Xf3zRAMrlTw6-50HgiEBibhSSWr0fxtZ77dIlesxym_eTfS2V1VHv58Rb3NjFIpL2ayLI6AKAnq29U7RDPXgLjWF4WoNxGkmo6Cc7dWIOsekjQuAQUtJaSSObwP_2HaMwfg5QPdFgt8KkkqOGsDEhXd2Si5ikvN2OFA_dUigfQ8aevQHqv-V7n4nFG8XGWkgfSdYJWMt7Y0SxuBJz7nlsnnggqjRrEI1C5Ae_HjlXKtH9WdYygzOtFGR_iVm--LWQE48-EIeym8g5Q6jwqAbnARFiCcfHyvU2omiGdiN8G9FIVRetDqWUDmdnza2GbJJ0JvoT2O8KPVkXZt8_qWJvTFuJ4Cqkwr-n3aa4BOQQtkB1lELR5rXed2RMNbReXmalMujHSVozgilhQauc6D89CY98ks4Yce32HbUOF753_eMD__ewBxA9DK31i50MrKQVID7UvKot3BsOK4JH2ExIg9CCx-mAbEL6HatGwoiE3zhX0RCO2OHYf66jrbKJ220wTH2O6_BCkihzNKLqTVmpYpPSprwPkkMBNfQTgtEJPJWp9hPoXux4g4z0EtYymZpC4sRVxpBH5mvno2D9i09fh9LM4QT6cf1Plh-6Q3HCupQpiq65g9CmAtJDEiSoIhrxYRkuza65jjabRvkudS8rP4Wm5Qn5ZYlykXUIzC1BVSIvjZPK2OLw_vLG1_iTbsBONDeb9AqQaXiAc4oHqUDSp3RJXvjRfQFNI48eVtk_LLkDd1WNuwQtzAjLAg9UZA6JZGLn66SpFpU_F_bwfHvNWrQ88ZieRDdQcbyCDYNJuqMMq5YOZBpz-Oa0Lun5L8hhUGB_B5FTUQPiiLVIKuHPJP0qLgC2o_R3u9VNfgwnMENnP6pmmVI2mPMFJSHEuDeShRshUSzZ4JOs9fnvpKT3TlyXFOeAtcn89Gilua2ziEfBy78d4Quuik1aL1wQtnr3PBTbn2Z0JGOPZoKybk9CF1a-1K0hoEK54-jRgTrPGseSMibhGO9x-5bW5viQVORDH1L9g2kcfJur1D-04cDlzkAB6hfjuqk1pvT3S3O2UGU37CZcVF_iolUucC8snhW5uhuvSdoBXXcnF7TuwsgAKNvztnf7B3tPJTW8x5Q5PGqHmRsoilCFlbslJCGq4h6NraPfKGY0Qq48A_i9QQGOihf1BI3OJE5usPGaxe6yJTpGQt5xCNuMCI920xIfCuQUx5BmVDAjho7EPkcDHoUWF53iZHPp7RSlC0uVABjJaaOREGT3oludmKOYY4PoZGMFNU_4Qm2UlT_OQ3XXhon0dcjT9j7OffzgjOiYy1HUMGpSyFdvIotQQSfAzNirsXZtZX7sVKXDPtOwzALnhd27odnEnYHpep03mmDI58plDhffF_rnw326mggOpYGBEgFNdtQCwoOe9P73E3762lRYHl6IOidAG6oaIP8sr3TU5xXhzJ7iqSKQbD4UMwolnNjUjVCwGMsLj137JYfUgQBmiu-5HuRuyD3jcRmddrWnofPg_uv_99W9i0tLvW9pAk5YDDUm6fFruGbYGXUa85g7iYuB6cY3lArHpPvBhpgFuH8FEexXhtJVRAFsT-Z7nvI5Hfh-Dk2M-Dv7ITg7er2mCwxG0ZmPMSx2kglqF8bZTxk7EqfGVQMvtgQMZTDij5dCIK3PzpoLqwNMd44fViVc4VXNR6o_gFx-XyKY6PVCN-OtGVQB2B6f6LikWyIMaIB5Jic7zT0lMsf8n9aSgi1UQdiR9RuizqInhxoW3IcdPpbHzyYKMyfsgE-VKX15pPOiL3stMrq7gSmX4itErJBKq2yocNH4QHjoqFsndWK3VNc6rzkdcZZqhu_ZN3xW31q57PzZbNMfQ_IUCuNPwcTCHnBiQVRZQaaiXvyVBh2NcBXLEdqr3Xuh8Q2BgCo9ZiW6fdqXOgSAd5gwxGOeQ_Cr-HLQMhB8bFE2szFWttri01hxyXOnpPt6ziDw_t4bGYB9WqaEMjCe_3iUgLjniX9hwPuQVhTDHvwkTaddSQ-SVE4JJJ5-IY7_0MAy7_swITfNP_7Wd_-XrdJ-PzUgKdKs8E7QSd2hpK6Vv7SGlsEHzPxljtHLsvEOGeTxkuBhc4KktOI3ezaooG0IgpQr7d7-viS2PF2Ri6-zkoXH3fosjCc_d5DtOvbPn_hE1Pnu-rCWnilbekyGhOquEAYsErlioLhpSaP15wkFzcZIMlV1aEPlrM6WzcCJX8cdeV0Z7fL1v7R11Jhux8h7bpW5Dm5mWtwpfg23XtywAcSXB8F1GuSZXJ4CZHq6vj6lAUqS0YigZBzMZe7UdOZUIK0VFTY1Kl50eI9Sptiy5AEPhDdaUT1daa-_g4BqJtelvtpF7XvIpPvEtlrLJBjimxCJU28-QUJDaBeKa9rtQTWf-4kyY05ITG9ke7qUnC9Sc_LDkeCEnDNjzStbf2B-r-ov9f2pUTJXDKkP4TwwiZ-AlDGHoKExZLJQYsek_DHS8rzwbRsjuhnU-toirFjZ1nH83XcYh6OKaE-7EsoUXWs5z16ntWeNJpEifCh5JNZJ_XC7BeKiL2uldqu4naYwBnwrrz7v2UAxOv2KusUwC5WHjkueRjgQtgS15Uf3khMDZYxMIKJeU_27POO84uQXsAVdPs_L4yL36hqVdT69WNfJzPuKsFiGkheoxC8SdGCaeUgpPZ24KZgDE6TLVaYin1xRBm3h-HxpAo86vjvM5LnpuVAy_0iJa4r5ozxhfjzJ7fPjQSk835tjZ8hls4yftUJNpOJM0cruJT25qsQS-RD36X4EF0BSPEdFJdN-z_CQK3LfAKcNSvO8UR7T_FEFzpH58qS98DR83avQuNx54lQ5h9ICIi3fxSHs1eO7c5m7jaCV8VHL6Mjkniqf_ZW0123BZxC2AeGcucAD9iPYeXFI5ob65AcL6TA3k1J8gOX58RIdIdzW9mkwMjJNMNEWYpEbsevRuQ_APKGJVyu014wYGeueKk9jQjgt8YQyLC7bT7eQKNrhWrT4Xfib6neWmhV9NRXVB8o434srI7Cw2sJaWSbJGAKgov2m-fvSEq2zqbNKQNqguIqsw-QvubN5u5c00PUldQs0zISnVthXAWJKlmuNxVykdN5HoDkKfAthnQv2pVc4mZK34DfcEo3Xc-1Ssysg4qOzHR4zTCY1GFX9FVKvO3C_CHI27gi_3pFjq3CcgV2_LZ3_p0g9IlCy2-6WKcRzBf_8jbuLb2kw4zGK_cG06YeeAzzMqPrtmx1tEshJF0sKAWWBzYYc2RE1Sn_QOP6YSxei2TKvB3k8Xvnp7TK-28hcJIDnZIbbU_4TkuoXz_MwbNEcE2q6YMxC86WT0qc7YXxAY3Gp0sNOypZ7QDxz8kBrzo3px5j81zDq1kxF-ZEIclPuFCXJ9s4NPaXrkjFmWnTvPmVc9F2u0JmkNgl71WaC7pRar3QpD_kbEJp-zcOFzyUnteiJKnQdbTdxZal7OT2GyfNDWpfJ3wmRZHjgAihyhDeGR7bPC95eMwEfp7ggXQrCrfLuFwMtkFPq539rnmbQ2D1GoW6f4RMtkF5p9UyihUaAjP4LC69e9dH4A5InMJmDpPfExf-_PEoiSgVTXWC58pb4DXm5QcvZj-4c-NDnlbWb_YbU-skdRq6ReAjIjWMNdRUoaU3b3EpWLTqVCsN2ZZNmqp7is5oGJG8Xyswb6VlGQq4ij5ZgGRE1YVVzMnoBVObpw2lxeDPldsK6ZbmzLq2cG4glgKPi13X5ZlQGb7eVdAgp9LZehOm8kOTljE5sLGmYJJpkmKE6hiddQeG7wxRSqcEoIctTRfMruXQL4gsPXgtpaYsTR6vi_MVrFSobxf_8DmhAkbUHNcyj6H1HVm4JRA0isGBoicUxzhybBn0heWjprPfnOD9eO_YpuUXxBrlC63LBKLQmsVkqkNI2mfTSKxVnx_f1QeuhJw4Rrp7iVyvCCE83XEr2uujo9uxm62zHvu6FHlJBSpdeX11DGUkXLScUtkFaCgHw8dcBsnG7jloDKJFOOs3i-cxOe-dWqlaVti5_sUmCLxNFIBk2TjZP44qQ7pQMT-Wp7b0o28IHGkaiIebz20xiWNOSYstZwq1xYIwhnQtCnAibqxE5kc6gtZbuF06NqD1h9fROgp9jdqGyucjHXs0zlkO1sBGgkz-8VnkF97h3rtdkqWSTZweI28dYQ0GYXagSSIgXmQp0QM7pzDp_JO85NYpR3CZW29aB6gdzuSbDoFciWd2UTsQX3HTEIsGxhtRtMa4ZPHyS5tHAKSlquhLOTHMTQfi8GO_VHsj241Hk3S56jM9Czovx-5OwRB8qKFNiHwKOvliSJR1HgXBkAleRIALJ64fDz5cUgy6Mn13Loue3JcowCAIgkrnusjVLig-y95xVvbs1Ys1rUFFKy3mmVaVyYd4Qe-WBLG-pZXug1z8gLTEZkY636ssMr_wIl2Zl-ciykcbiH6S9yTY358VqZgzQBS-44sQTdT_qelrVSNMLKneMs06JSjhSJOpmogW1I_hdHMtxkkSOQxKINvyEHPFbIkUR734qjhDVUPweD3IUQdMJ995R89D5cl94H0REAU_wJxDSGwGlux1P9ul1FHsX9hGTiNU6cE_qAD8fWX5ceOBa2iCoNefiQw1Ft9xh6QYDe2lOPdpIeihKm2ABWMVJ3hGCYwg-QPhj6yrSbZ4DSxCMPfC3NQ0Zarj5VgvfHOIO_gGiE9plkknoLBM_j1VSP7prfUOXQsA4sSu8eYhkreMkSVRk2JJ4JY2u1s9zATCq4cTUcKwdhgasU-mzPJRc0PF_7JsrojJ-GphyN_vGSzv_kBtl1Oo7IIHNo4UYiMpioxeBd3UV44oL8wOgImfs3a1Fnb-fHOS0RHkn1P57V-QGQcbQOoXtSqcDLjCJEJ144_QQa9jSCRUYXVv5VEYGfEcpaeyP62FFvLkeNfonGiObjVxXM2mnqV9gXm8Tf_NE7HgbthKKN9zbfOSyHos03LDBIYqScCnENopFX6XyY_iHOZwtfRojYmlZcfbtM7AA5K47Ycx1hC7A3U3x9CjHjhLZhqcQXdFeMNyfbEMabj4ESo0vqfKOFhif_U49MwLg9Q7cquuJ7zoduXmiBrlm2hPgzzpEK_JBC9vmc3FrxbBV4fZKr2EXYevtvSrWJ2-trlF5u9WO2xC6oxCuTUVisluvCWwhy0de3tulbLHlKV8xYEh_MvJy8tyqeOS4Y5lLtTtwuA4rTVNrYp4-otD6ZPQolK9k1vGCQtuTbgUR0Ya2m7vMDd10zU79haM0C6y723o3meJ6Yf2tIqffTk6YRpDw4yFiM0xKRP1NvkMT8T-3ptVnIBz4laUp_HDoTT1EQsmKYFtgMMaqTRImxH75v7FW0MGXT1578lBSB-PW_3U4zR8NpxvuBfLrzHcWOQv1bJ5m-v3ho91V0wXM9X4qEiA0CbGw3UdrrZ80VSeEa_wU6mQFG5IUB85_AaMkKjZsqoO7rZ4T_GAn3uqVmObN59eCgERccyBogj3s3oHk8yEXIhtzIC4wwNbiNhPBVako-_6YJOU5FnYu7VXVAWBNZsTMi9XuZY9oXTQLoU8Ya_Ix8baVrArLSAEDUih5mZvtgEzn9rBRJEarsCi5VMojQk5vzDpKjz21R7sNYTaiNikeM7AKRTtEa-N7FtdO432Gf4y4BYTctIi6ftUPj5mRbDm-ul19u89mnGx6VA4h4GZ0oWRtCP72svGw7zV_I301Qcl1m9TxFRCZvqDEvbU_GaRlL1VzR_QUOixSfCMrlovCtycE_zXE_oyMSjPXzA17wklLjG-gEFT0FUcvlohTKLlQKAUOvkalRMsao_DoGOYRfd6e8LtuKfaRnat9iq2RJ8OfbZw4kLmT73kaszYaFDPufKFvXt0nIxi_ysbX28Y5zZq6KHKwLmcceFqwwmZV2ayAvYjBZqBYpPLTfvEUd0-3n00bXi0hLP8Il8D1F_2ZcrQcHyc2g-g1Z-rxl_XaFnipOWuqRxq3ocMZLZ4YpUmMMA89icLRAoU9mG24RHcMrzkPD9IGUZv3SJVdKwcbmQCD3cBZBb4PEFenDnLbx51GodWRuXniQ0bl4cTlKbTkTJfAe3MpOuUDkcM0FXfnLdq86Hye5N-ygCdFfGozi_EjxF1kNQ6ItrNb_0i9eBhMTgCFHGCVBGWamswc6tICnbQRCDnUXVnvr5qqjno4w3hlXSmlE5w6j5yv7CskyIj8-rsbKW3zZTLMDHIyRqL4xtEqcJSlk-86nfCQj9QVXB4O3W_HLuyWo5cWoTHPwKlArTHx8Ml4Vub7qsgFvEnFzGLwd9QAWnaqD7ENALvims52mSBivuiMMR90nh-jsjbOq6GhckHhWRrtDlfLNcaTVJz-a-s7Zt2Hw-afODG7EemMCtGVRDDZn1Eo0katat1aXH7GU2LCfh-FP80eajowVmMYb5lRHWavhRwpSGTBOsmRECrJHym4ImOGcnxX6VE3Dczh-WNYYjEa0Q4OY1y-S21xExqdgx3SkaOc5G4KGuKdPCh6FAqg4P8Is0QAYnwnjbZZ5mQHfy-oUg1tzbO7yPkY_LNV22NlVqkUfVa1cMMhOzGqTOODaw5ECto3kW1LrIhVieIvKDUnztMMVj6jU8jjZ-mbaOc_Db0JLD4pgEtSmWybS9TqiGk6dcJGXOjDFi3PjwDCSKgwND_0xpTE0QJnumUhlflz6R1sFsE5Nc8rV0QglWQQyseJm-h-taauAkIBzyH3C0595Jkm5LBlM7V-bxtDeFjx-LFqB1rslSSW0dhPxrO6JAB4W6wtyL32UIRTGNOrgh26yboEvUSSZjJBeAO8Tiv3BCKTep1i1d-V291rJjb7sj2o_8XWaNm4tpl04vVY49WttNCxHJ5fM1PuVzbRSoOEF2btxCklDFhp5t8u1Y9mVnJpNMmn5AiCXZZSoyPqrv_j78QUZZXj-x5xwVft5363F1LjjoZ5s3LdEoGbsMAUiwkm7Z7aSr8gmV3uzrv8WyjiJjlc-rpPTE0RHbK_Hc5L9x1HYTJXECSdwZ8Q38yg6uc5EpTut5WPyScHFiDy1ybxnBPPx0tWas7jVULTZaeoGbnkUFo6xTJLMd9Tzzl2IM2zpgL5ZP5c79zxJvUtxgVFwTVmqMQQESj-qXikjBmaXgMLUb4Kv4n9655bgjr3ZuF_rxDagbRdt-_2pgf6VqsHEsaZJHwIpxh01vmyp6ZcQxzSUmi-8faZ_RWCJ5iTpHrMAHvrlPzrerOYBG-RGl2pxJDCVYr_WyUjKbPDxWkjKopcXx0DrYu1C6Cz1-gtGCT18LqoW73MCtdcrwKUXAmLdGUPFG5UFq2vuqItkeXcB1AA2hUhO1rzWYqHnqy2fXm4xtBgXMHVK8dqiXCmWWJ81sezBMVYDUP4MvpPkHRFSLdmG3YrZr0IwT9RzyyDfGItqWheKUJ7fkv0koRczg1J92z4BbyVBzdnEQX4edyyKCYd96ruWi-lEILIFHCY-viwPOIP3wCifcKgMCNGOzaTX3raFo2_VcNfvDSC8cLQq9X0o79qCE1Jeog6jSHUrKYhGsjn8mAJcdf7VzAjNsMpXypG57SMUBz4rd5QGvw3uGTs6M_p4BhciR8o1yOlqCjgRYyxUbCukRH-Od8QDHjRogTAeMjwL_fxEOIKf0pXWw_L3SeEddEfBDGaSU0CWPtCiEpUdu8pXQ-PEPvUFljROnxSr4Q4NQAro_b0FL2Lfk7rSLVJ-mlV8HpUwggz2VC0jjriGZDTCQmLCGFtyYA4qMeL0nJyUD0gfujHGMrqjnBP_TmwUr2qHn6y0jVreD7SpX8ojSYWeO0ebFHyBu6LAJy9VLS7d9Gu5tZ9EVVDCd7MfbDozD1UTevnfxnyGT2-_3xJXnJ2fIzISqkV6vYDmvXAhMHwggCBamQ5VUb5Ri-JQyAOkH-P_d5AzM4vLH3NovPaTs41-EZ9LoA_ACgTwMdXcI6yKNhvbYfHK92GWG0k_HUoZp31nOrUY4hsvoDr1VyJHeFjH2WulFKr4hTj--htE99X95MtcYL1BYJ5KZVT92oX2m2Tauayqr_VP-iYgeiC7WWoo526r5jVWXs1ZgxtzXzylpf5f5z35G4YMC37RFlzgY9kDaeLkMMqUvQo4GbEFbLQ5rF-9zMA2NYFKC-6fUh0hvN1UziR-Co6ZhXi5KP1_3aw2sjSiEwlF3umF4zZcIKjKWtAHrFblBLnUyp79qId8ibcUQm4EHQ92CnkKtAf_e-OB-eZA9Vz8NGagOAFdyAtOFZ17MBcv049eh2izFmxKl4FctOKAEIU1HVWv8IWqmlDyQvsUlwImE-0YFl2EHPizSCLgHM2FgRe1a_k4YEJnQxONr2GUIGL2x8mDl7aBejUmYkkyrCj4Y5XDS1RO_hrmhDB9rAJtukT1PozIgqJTGNHyH_99wqT3cfG37PPWiSuGOG1Rbujp_by2zqGmJx1PjvoRSX7YO_s_apGzAARHZL9n-xFsoXqiJkqM242r7SHsMrqkYckG5IyxjTrpqDWdOSe4xxTc9snA6Bk5EjQ6kb0_VVG20g6kKua9Qy1n-6Jj3BMOaBHcrP4hKKStHySqqLCPOOrqn9hH2s0YKsxknqCVcR6kkCbLi2xD7dpBXmmc-X5MvuK9g9kGBWjfjQSPEfCnhD7b8cDbvWAKJh9vmdR9ofySSWMWQUjRJA43dOTlUpuskklOImDZqitGamjZTfLK4L-gE3wDkavF___kozI04zsB7xOFdPcyL76sUumoAQ_gHA0he0YE0gamTjbJEk6p6NnzuK7PisLkvNS3ZdKqTZ_msTrRSV0IUyypI1qMB-RZDgjWgdccbBTxa9xeoLTLZM8OIEmhsubQF_danFfla5dm8aDiU6k7QpiutDFosvkIJlt5sBbr5Qhwbp-DWyDaX1TI8cCqlDoplTZiZrzf-n65eZMKAcNL3xp0bMYWslR10All84u6IlOqbiiMqIsCFQS4A-Ff3uftu6JqNl8tC_J7H2F0D2W1rDUVYavmTevdbk3MfH6vEClLwnLsB2wQlripHxv77bwlwK5g-4LWHu5N6shsdVMsk7RwdaozdpDB23r4FAok05qbNgHhgpOgu-1MnRK9res5CoVia32tb846NNom_CRss0fLhnAqeU1A8hSZPwsDChHiz8fYCVLpVkCfEX-hgaloQ07R4QyTBXY9puuuJOuOCzhe1IANS4bS1EdGOSWBiDW_Df3q5ky5LOXCOfJjZBvAEkpnX3KJyxdE8K05P3Sj9akt0eG2buFfBLL3rEqBAvOjSWA8FkSF6b8NlLx53itZnn9yiEyL847Z6WGg-Wjs1y-hWSzBh587FAB2z8nTrIAYOQkW0dWJW9Grerc2NraD-hmK4AzTK9f8dCwWSfmc5TB24s6qNRU8Dk4hZ04wAuSQLximtJh3Gv58EABNSSZO6SS8S3SvTR3rRGRYe0Op5EnjoLvT4ZSkLaRFQxld15H3vq66hs9PZo3F3ZxNBO_oDulDXYVvOfeP-16sMfE744LGlucoZBvfeEtjE6Lqabl5jbgByNm08nluPSNGAVOQgExxHcAlL2H29yvMpo78qeqLlkOw3iHi1rEleBFQxcTOE2Ql0vh7gSjgZba0WoI2rl2nD5Bbc5rlTkSa_0-SoDl_aWnpSHLSXHr9y8S1Ryphc6-Tz5uy9lCrplcuHoiF7WUCChE4gv65yf1i0VTw0QjsnwPdnq5Z_EXAou2jLuXaWwNfhIPyyl69n2zEKrKDpDIxS44J4IB5zCA_DFrO1gcI71ibRrcPQiY7Y-H7ejlrGv1TfE1FwZwvphixyc5cVoUJYDZ3pljYH_vIjKAAWr-FC5rNeJDCkXdBwGzrB_fjvju9lNu0bH8xXbQ5xB4vGoorscYBverGCtbbgPof05Ga6uVo_W3_6EJQbJg71kriFa_6haOFWz9Q4sAAOYW1aA1mrEDJY40nG59r2VdQ7EU0X_5mqkwoQGcWddMWgZDFPIITpWOo672O9Egh8luGo8EP9zhRtFIGn2vC494VBDUyVGrKMJLLI1lpoUgGfsndA9JfVJH5J9BaKRqD-GcZh2Fojj05eyJS1Bj62AoqB15nSx1X5ouHF_SkkRBZUPYQqByCrtvcrQxA32PeFZXzc1YVltoLa75LmnhBU4PBA4-KZOaGjL1EYUSU5VcZkLdQVyEXXT7NZDZ9ZchBp5IZEMLkLDNSeguPTpJyTdodbbye-QZdGzHVG9yVH3bqTB_KsEqIaJ30sjX_zi6boK6ZC7ZeGI59ChA_W7jVIT4kHWWPp4WVVlecuKDzePIhc5vr3wUlXotk95470wDp3Jw81QNNu_jRgxJ0dWcIl0Ew41OV8YomZsud_VkXBTn-68KwYcBq-rYGwVFktGpVIOvoIspZvch8d6UhSVG9LcPjN1_TD1GAJ5EQtwSoVak2I9X3zHl0bVeyJ8qrcOQcLc-4ss_YUfY3sOxrv3WO3livMq2e40ec6osSm3EfhR6RKEgOAwnU_VBkS9remIUxsTftJ2ZefPU0ql_HnT7NmiYjO1s38dQbBI68scRYZtzlJ1Yh3uKqww8CG4Sr3s7hkXDl8yEHfQdSza_YSphJWn9TBflKcBa_t05qW2eTtgri54pqNvcDE1V6sJQqucT2xQAodfMaydGk-m2XPCTuAJ3kCgCpJdzH2Ar1eBv-7XLywrFGo9ayBY1cQBOT96XY0txWY3Ju5BPwU1JlRxgitQI8kGND3b3HTDGn-U__abQUMkyL18FPXkEsD5ZnRRvhTeQjeNpjM0TO6uPvk1Xxmnr6_8sR2s0bJKhuHxC47SIospvgW7Fl9BqlCaU1UoQIuP0c1rN1IfKk0OIsAZSMDvSLCze33-8vFyCes1hHSc0MI1zU2CR3cRt9-3TE08lQw6SsUAIM2SSvfsHBXP2Ib7AnoRby4HTrRKngGPXsNIRtMzthrGT1gj1Ey9Ka33YcEz3j1PGK5mJllRi7nrCWDJQt1C9kLcp3qPwWnkq5J3b6VSgLwvdrMSEPKrIJGhB8kugfey0fJduu5-Puw3dH6DvV3sQo7WKdim3JUz611z_oiwL_UzeL48yaDoBQbfe3LH8S6pWoXeCU-Pr2KASZGM8cZlkVKnJWTKa8ne9LdBuRiDpVwVePQ5cDmUn88SYs1KEEqguwB7te3xJ_3HxuPRHqy7gTs70trvBGl8zqVNJsnmKpS3V_E1UtMGLYQ8MFApSA3b6YcJP4j4E6aCD5lakVLGSnMoq3PUof7Kc92NZSWzNq7YfCoAzL1BJoz47MdWn50bnVy4Xa48GLvQgjEJ-MF2i1txejCCw8jpQSZqHLx_PvKT69cw9UkcEzktnd-uT7BruxwIl6mcWdc0oeOjt25zg0IxB62WVVcNHQi_PSC4_kM_cvIx6749xXi_6hyui-2L5ZNQmcd8-7-y_0gaQTaijKThaSg0QtGkWv1lFtBjxxe2_mcANoTlnJPsHOvriL_brQeBfNf0WXwRgUzfUF62hrYCw7OOqH_rbQNBJbHgyyTMhxVtxc-DoGqw9QIVIwZZC-XEl_8vk0D7r-QCW1Desu8eyXl6tDy6kfP-UkuvZv4kZT8cbihvUXmAghgfRfUzR0OK9V1zMIfVgDYPflxtYgAT67creQ7Re3R8f68cVFGT0oJ_ZpN7rYREZ-mGghxVwmNndFboo97n2aLZbBXfqCfLPqMgaE0-nCKB-CYN-PX7Z1tJcNerMllFlpyE8UTw064GPNxAx9J_ZcRPVgAAFdHOe23ajDzaeSRMRKVITIUPugxbKPTWb55fOIwgWOS31s0w9uiGFrScu_7aDvrsI8pXFXLZhSZ2qPnARC6Cz6t3DQPLc-_0W3T5q9iy00AjgTUBSJIIL0WdoU1zoUyJnDY2JZLYYQxaFp1aI9AzMmm9c56Qb_NiBUfJfyVS3I9NaJq91x8QebR4IdO49boC5oAWIERJCkOTLxQUbKy6EXtxpgO1-zhBXXDPKyhAuSj5jnRa7wvRdbKXza6stM81md-AqEvDl6Cnj-FSXdaEo8glAF_XxdgA3UpMx1EyvkuoGcEcoyEsqxc5AdOD4R6cKEdMRl04GGSI7fJp1cuWmJLQqesAjK_VAEnYYrmoQxdZLw8BR1SM13XoWSfEq9dN_uZiwME1CwkTR6mN-WxXfeg-JYDRebAY_idA3xP6lcwFBQsIRebdcRyqgmiZCMyaRJ28ZwOUmpHaqJEiccfbBL0oqO5VFNP1bAq5nsjrvXkmB-a_jAJyAliToyuKc4i-VXMiVwp1jV_outA53A8csMgLmkYHrON3ZA79psVTdnJehE5zdAaObGZt_h4U1fXGGfdzuTIZ8Nr1UlNJVHwrC5Z23DY_Dp7JNHt9TIwktbfaQieUW5IR3-x8vczQewwU3lIu9KrSESjQZSe3Xr029LQpqSe3DuyWCWrLSEun0npCWaCiskfrT3zI31957vIbKdKFD_rfUzKs1byozDw6o0K19litvEClc2PQ8gZWW347WfHIwek-9qAMsRlreFc8n9ASWW_QQxgTRnBBeC4DkuwWmuj4Cfs6xwfu9b9T15jJNYGxIsLVer38U3AS6dEgtwCjwjZ0jfQRV2o_Lr89Qsj4E_EnIbJzZGEKBOIobO-lj72l0sFG5b5_qaMhUsndRRRQo3KoNa3jTtGsBI8EkMb58uLLlqD7sdIEuJ-a-1SQwiSyb9m5P5FIlyykGPFK5okoEOxzwIZSEgdghKXGIq8SQbgkQ83kHkocq7NxBHdX61Egr0V3uEEytgcO2chYZd-WiJWFLLm5zmTeLQfUl7G5CJZwhFGRjpGpYbYGcMkRCEgATzT4jcwzH7KYBMCIXi1bskCDctAy2as0jQnc5ICFzWl76doHdMVJZSvFzFY29_vP8IuVRHSW3hCtODDxLhnvDXMPGt6dOjHN-dq3_NB9mfvHKkOEK10JDpRnvz0k6gstUZDHs28a_BEH8RTb0pXh1rcO35elGh4yDNNKUk26xXKabN3OZMVmsZxxqL_JqptdmC9cNwg7XZ-S1Ey4-6acvec5J4R6GjTcPZWluZLERc2tTSeOtQoJbCJD1shS2NvR60jahncVhdp0ynV1-ZX8oAsMxKFKiB0ZtxdVNLlk4FM2nDzwlHkjbJNlz6xXuR8M74qcWVsgEzEBWyL0INt-KlkSSTIW_JPPnULrxNfDTu20ZQScBx55So1xEURFaCHjUf5P8MV5vr4paC7h0UXlWlj2LD_j9h0T3FYugMqTZuJ_NfPpmY0DpebI-_DY_cbNz6DZEIyicaqZ6MdFZlUz4Q1bpCI6773qdFLUdKS436u4jQcQjlpSbaA0sHl-7Mmr4UWKtEIZv69KCi0XQPqCOsMSYhnteyv7rrH8tL5zNqCIkUW_hKmle5Vblbafbg8wVhaObzO4nZKks-se9yVoMZnYzykm6A9C79qdWg3bRPQ8t7nWcwo42fB6kJ_K4OiMlPklzpWmAkDbTjUeFnqdUV5XhKdZPRWfHABG1jye0AZ9TZR8cS_lutJQGx6NzNzJ2h7qaeWM97ahd1rbGqeYhC3V3El75LYabMagyR5FqKaPXAPvTXdiulOFSb5QjjtOpxjBZQKC4kH_Z_jTmFCqjZ9KHB9FIdkVqqPSZV9eWPHdh4GB1RlfnJoO1qBGXEJfsTrI4BvIGn4FFudiZmQNar57xgkDx2CL3hejyIWssU6MkmvtLqwcha7NgSa9Li6zQHd2pBrfyKUtvE17_aEL9vys-2U8o4KqKph6vSzTprKRShTAmk7hUY8Hn2I2N1frQzOO6sD8NUcGqGlLMh4rjaKQXdideiNkn74J6Wdo2-hlie99H9qpbz26SCsSE0Ucn_HTvynOg3O4HGB4uMhz-CQHsdLh-9aZjw-xLtmbfLDdUEQC8U83rsX9JysbyySFP0bZA5kUTbhN1En5_-E8sXUburEg-nAshSW6WvSvM0ZRVsA0SoaDKIR0Wq8X8hXhK9tpx6rOMmXlcLFwNefRgNvoR7aoM7sRFeBT2QL3yjuHnOV1cZ-li3Fgfb8chV5CCsqAXucplybckQ1SmtDmiGxG9u6M77ODMpU_Cgn_bwtrDwwFci1dFyBPaBhQDx08jIb5tRUoAv0oLbTbl3CTemYSjNQaqWtX_wiDjH4uW1oU89m3CE=', - provider_name='openai', - ), + ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), + ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), + ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), + ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), + ThinkingPart(content=IsStr(), id='rs_68c42ce323d48193bcf88db6278980cf0ad492c7955fc6fc'), TextPart(content=IsStr(), id='msg_68c42d0b5e5c819385352dde1f447d910ad492c7955fc6fc'), ], usage=RequestUsage(input_tokens=306, output_tokens=3134, details={'reasoning_tokens': 2496}), @@ -2588,30 +2518,10 @@ def update_plan(plan: str) -> str: signature=IsStr(), provider_name='openai', ), - ThinkingPart( - content=IsStr(), - id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6', - signature='gAAAAABoxC0_aDtrISw_zls0dyams-nhm23et1xecYaqlI8y44ih0g9FA5T3R9ueXIOX9seSrysa48qci5QTep_TNFkxcjPMbWeQxolRKeCjWk0jLpC2FdKdscfb56KfeSTklKz_CaD-VubFOUgtqg8bQfJTvrdEtKj8Q74c2-XOtHTB-0OjenFtkZMtLMu3uc009ktnOSiWIxkuaDXcvgENQlU60WswxDC_3j92V9o0XsSnXxS8ZmvfWcmYxsFAo575ybwZin6GI709AxlJ6iPkSYIyRy_Sn_O2B68S5ABs8gq0yzaDtX2Wtibqys1NooceCWvxBSjZUKKD3N3FG9Hx_GzaUyvB5DblDmqgfP3AC_VfxaXm990esMW22fQvrEmuRNJc7AF0-KSBCNjatP6eHKj7WSiyGplUFCukk1tRHxOeDi9GD6s51_jTSyADenpzvdBLoELPR0JQIUuraSBpS3aZS8ODJDUbIX8niI_RYzRCvqBDMbLi9MaI_jTdEJknhEgmZZaV-53FXEVM7LoK6BWBpocwDC0zbcA-Da2rY6y3h_4x-PD-DL_W-V0_XDqwhx6NZOJBDpGrJIKY1BU-QjjEdZeXg1hv7CmLCH9ykOr-ja8B72fGaY2sJ9Lg2dFnaEkalEnYPCOY1hWDok1o5H0YVwA3MoZPr4VuFbGKD1EEAcB10UYgY5_WRK5Zk2CYK9EMOyLMA-_DU5qMLw0qrpj7lGRe7PLM0UYBbjP3jFZX6Gy5e1RcibH2MsrbfH4SlVkc1TTak4vuBEIR7Q4q8dYCoKTPgHAWFULzFbaCwhQQtyL1_lG-OpiGGUSZE_VRj3yVKbrv4Nz1l44ah5DdlG0BCiKthdMqcVxc3Bh3VKofIN6G_rArAtZ4ZmcoPVXIUlkfSPm9efNSx1tUpZPKkFk_dtP9B0dU5gD9F3tTU73I7CtuDaIXfe5JOBegu0_kBjEXb33s1B6mnUJJld1f3c13AwcRhMimtidTdtZFp4iAaKH0hWKrC6fOMlzTmz7O7R79sl_81XTQQbIR31yojRzDSvwhRoenyRWvQQMV4PeZ8h-2ioG2l0DQ89YRjkjeUEwZyog0ZWHflw3nr8zjJ7xkliqfJpspfE0scWrCq5KmY21vYkf3EcH-HU5s_S7_vo-JwnNIlTaDJUHbEo8sl_pJAsWix3OgzBSmBPneL-dknHi4IL8NNoGYkH62mbIKVPlBqn52e9QtO7v_yFLxGrZEBC_Z7jsFQQDarKvKk5L1nmWLRUffZvNP0hEy9M93wPDVNZ7fU51jD15tpuj92gBKXIM2sM2KWXFiVqg5PhkT7FvFHii1f-cc0emUTvzlO-ZU3oV73eSiisAUjHK3CO-rWD_WCiSAy1YSSOgORY0NrpwcIY3iuwu8yKxunf2F_bYK8mZPyAiI87-KYctZA2BLRe3UVhcbdkXQqHMTbOe8_yRmm20RnsHNTAk7ZlPNUihqE4kxbK6T0Bm0rtWLx8kZHWqq_netnSDiLa8Jtxzxu6UrKOtoWi7P26FE4pGwS5vPVCJ1Z55IcOZ6kQ_I2JpZA49MFJw6YDhKVnJlBEw8D5DfRC7A2YJ1x7ZVufyrYKiew6FYPaj4hpM95SN7o2PXz-vgTvp0oM0qknmcqdtuMgQcuWR5NED6cYccQJ4DQV2Nodzn_bFokhIcqbQVeheE7Jzy2MrzF_CJ3bD2LEmTKgDeoRfH4f4APSh00c2JAqtrKGmF7yMpBYC4vTTnbjPD4shMEcwgMeQKv8rWIaoRZR68Uhd_qwhW-wLqLawd42RaMzKebvCX78epU6rMz1VAlhZzlKS1keFXp-5xXjy4JQcu_WY-GXqSv7ah8CWGItBFc2yW2vQaDfgeHxc5MZTg7Q_VJkGSIEhttIb_0na2S6UfKXczrF1aoBFCKfxirIrOs-VHvbQCyWXwUdKidKNIqexkOucVOo4MaDMMKYSX7LINIdf4WPwrsa2SBW_UpFp-jrjF-aHmykLShhIEv_nCAHGMmfPwbu3ZsARJYusP6vRL8JdVq7pigfBkcIONWRVO7aM0X4ae43bGPfIzzLkdOKIBMR7KFsAv-4THPPH3UWTUG0MN0dAQPAAd6Jbp2xe3heqTY1J84QLaPFRY66r6rmZDWt8yzFB2IqLlupMgINWWLL8e0v6BLd0C8_jc7kwHmMvaPoXlZwqVFXed47bJOFfDXgymjs9Uw2ubeb1VMydQFmftVwzFY0vFTqqAWWnHIw5udvxgCTXDv2daFOdWPfrE6wKqVb9azxmGGXsoLcigmzwapcHBIUHAKKBE8SO9G3ciUkVFnK1JQEJ8Q96TdxMbnaXsPfy_CDaNUQFTnLYatnTbNq2kr20TudmpMYbm3V6_51K-gZyBh0-ESsRtsW1xaD68FgwS2Hi4zgd5zmko4c4vh3ncQt5eWB4Zy3VPCcNSPvgEVv_1psLFVPWMhhrC7pwV0PeuEE9h-rr66lwV9cgFIJkQf1Q3NzXMOa65aNKvmjAfP40H6jDUrKW03_JH56kb3R9YwE4kDpkkSJzHUsbPLjWPUr6SOUQKT2je9oxE3ioEgtwAlnYlxf5JU_BPyj7EsgLPpe8ZIuaTn7pU_tU8fBo26MEn78g3rwaFZ7PpWn6DeMTG_hDvAaTSZ0qZ6bAqGoj1UP_XzuQOuRvdbO_jNsclKBfZPj3RQcx1c_4H51aKTrJrYLndXSzsMox2BLoNXuUYoDyIeu_J36iUid5W4M7gykJADbUZBIbag8ordczWIaIYGxJHpxqiZvluHO1ufCLYWj3r8GhNNU_BjdyCmisGVV1he4ZdRiNHNlpfAL5SSQv7QynjdrPTIwmugGfinfzq0E7-2MpEOtBxDwlZtLBQsHLracKuIjYorhTzbj2dnvCBWTdfeBnaut-x7dfKr8ReAZnfhn5-qtvJdwFfx77y3t1kUIEBFr1CTmpUh3q5SJtQvR8TeTcPJORHk31EnafeipUwT4JnqA3oEiiqXLs2wTlLAt1SOx-uwMmyMeBEOhK7FS7Tdwgr2f0K-oEaUP_3AAENamy7U975-bvrQC5NQR91rCee0_h13qvdnYG0S_OS1vswYCoq0Z2wnR6wa4nx-ZoEZmnH0YoGyIt14_gOGQ9X5TAWFNlqbbHzhsOUIrN6TM-f5HQzXF7X_V7c1rMtPR-ZlYeXu7lla81J3_eIO_XzOlD4BO2nosgagiT89GQB5Sj16Ehd_KGMPpCsvqOxg_UpPL_kQ7qJtDs8okP4YmvWjp4IHVD_CmV0kyA26B3tlwkD8IUHzlAq7Bxq3TKgnGIgxi0-scAmiMvN-TlXvDjBp0Uh-AWz2zxwAGqsq298xeLkPRpJJJECMlZVPppr2RdKgCyrqBhGLyWIjmIx5-jWY-1XuwT7cb9NGXe6RFfmCXVX_B_0_1ribDdgLMRtGXziYbI8qxmN3tsw6BmPEsDCuofe6Zqm97JipN17tTmv-rdOHeeV9UgeiYQ0xJe6Q9psmhHBxGW6LVp_e9dWt4-aYZ24hSGf8CileysyUV0etiXPh2fVacS4HKQXry29CMP6j6gO6Ca2T3CNIYYd_aG6hVBO4Lk6ENkS4kkl7Wen5tOTI5TCD0pGAIuHIwey-DIfqPbW-ZHhQO3sBYSVtHPMSXP3hrojuR1qEnFVrVyqLABusBzlqB2mAnvSKZRCpZ9VFGUABN6ytItEXv4JDIu8eo0IvMQmWRRguaADU5pBiyQZ_5C3UEyX_QveHmDri9IXaVQz_3a9gowZfMuGj9CVwuhCq8R3ZLclacFxWRFw6byEOm2KZb6jH5qemc-V-Ci1mtcIsOdVLFQXuHkiOyZE2zISd0ckGUWihME4lg0imlSu_XI1MjWwao049bmP0VD5iqqpccIVsJuNkrSmw15AcrHqjlVhIWrD8u6e90uBqvm_l-Yfxe78_cIl-VuWTTa1qI8yw-LeNWloZCTbls5pRQr7MCm5dkZeAt1PBdnBpXTk-8VcvlDsA_hheV-QVbrdP4UTtDArx6QfxDU8PNLMpMgovTDTn6WnaJpdP-WVTSYH-78a7rp01RAmIQTl12vXuNRhPtj7jlortf8YobH2jMog2vRc4uXQpqZyWtSr-BF4vhh7QfzK6myLiEj_ciHNXqd64WzYl__hPaULy2xkwkpnD6mWQnRkoNeFGA-kt0f5J-M4JrRG3qCOdVrccmyLye-vVQyVkqfqgau6YLXd3QdpJkmA7Puu0ie1BeQBnBG4nJcWvDE1R19MdYBT7v-IDTdFBTtPxc5KerxoUy-Zn7xzvmUt6rRuk0pmBwzriAtzZctD2PI8BfoC4zhP-xpMhcNNaqCUBUQ260pWVdhqUCpkoBrskVHMMndizoMbeIeAcdAp4-lI5l-6zTO2APjygljfVHHLjpbTxs1ZA8DYpjrmzWSC07IXpK54MR258kedSamj-6IcUY4OOVVsuLvioELKt5JHwx5oADllUevxdA6K-9vddx7tuhgvkBvL1TpSp0XxDGwH3dRJDFwcDl3ah_PaOAjc33Z2IlcnXynaERtl3ysxBoPSY_4KPn5NoWQ7YHxzA-zQMKaa9fpi2VLN8Ud8redK0EKc9WwKXp-zmJbCf-KBsVCbFcrj9WUz38x-Iv-JEwFnUVpfTporFsB2eYlAPaMrXbf4Vz-Um1nfSVuq0F1V4cCPtZK6I_H-KWLbIseWZxNTJCWlmCaBe7ZQgt8ICUXqspyD9OOU6VNfr0nU7aW0itJEnvmKSfxnj3wQhrmEJ7HsX8mRHaDqAQKCr5B8YT4FOqTISRnTgDsV16ZRp43TaWH4QFpeanUD3KvmpvvfYGXUKVHlud2dUwPCr5FNM1QRFG9cgMBJn3y7ewbuixmPAIU_se3fYA1nYBtMlPpSHMGfXsqrIlMGNXmwsTs7TjG-kLzFrSA2ku5ZFX6N4wQim45hr1fBHI3GDF7IwoHKVCjXLjrkdCOGW0mV-n5uOAJxu5r_Ire3WFys0V9nlPpp9vy40PaNbXTiO0bLZu2u7LVDKAmxvvHxpUZxtW6v5lzoJjhdy1j4yAYCSgctwmH1pwhe8-wzU3JU9Rt1LFTs9t0XRUq_HXAb2kTGBMvk4OuuE1huBo75zhmFb1DVTzjr3Lpx656PZNk_frJiwupQ3qQj7b77ud_OzWgmRcLfmV2HPratlaB7pHQy6srJX-z2So9VD6TdbUUuOlSoGmK6jd1aGMNyhc2SM99TMQsQwbMEpZQ5tkexBf3Yc2TzQKON23R6xP90ctuAD976TtM2mZhV8o_7oB8jY9pyNwyf4tRUz0TPGIWBGgv3XhPugBTB5gfkRWXRvmeA2-Q38To85FnGpZib0yhVqpfS1ol9fZ6qmGQtgN5iZkXceAhYJRBwIq3jZM5-9Kc4QUO4aW4V8P7OXY66kxtcaoxXFcaug_EXomyGVhvLJ99QDE1zxTfZZ99Z7ZbAhYKQhctP43NCx3WPN4P0dP4HOG1HDhCW4wFOdWTKXQOKA1wOhuGUGyxpi6DcnMkM-vCpbWfHNzeSOKOXkBHbKycZiQ13mAv-eKpd0wg15sgkX3XdzHu8Xxc8HqDxsdJoyK0kT9lA8Y8PpF03mwhSqmOpxM4RjLL5U6HSt4FxDSsdVoTr3bzlKplWA29yVjlOU9D0xcbp9_Vkb981glTcmIhmpkP-10LD88arU_kHIkv_Oprhm-sCnNgI0RzmH71j5RxUuJDEKvj-l9A3f4lLEudcJw8ZBe_y7voD2-wNJ55hB5hYjzX45A5JCGbh7bE45bdq-hZ7a5rHekQAKMe1YO0zRzrkUagXurtqAXrZcLAq6NREGetDb8ICCJWA9fYoBWwz1mIBzn0fXUZlPRST-N7btljgD9RqiScsTA5NmGVG63cFq7JR7q0Na6eXVAKBODjcF6pMa4LIExSQq6W8CgXnfmGGTQp7p48TR0wan6nvSCOaaqty0hnELs2AkOb3otvg3T8ISPj36kApd3M5NcOrxW87LV7WEaN2Xy3aHkhxhZNMhAWHAtQpeg66rIsBat_Enqw56zTnSdjbKAAM7_mda7iQg5QEHKPSxkN4J2dAwzG-XmWTQJZhhxkAG0PDpN0sZkXRORxQV9TRBGmXWarK_GWkw2oAFFtf4H2d1KxlNiNQ6t0_6tWvN5piuPQTPhkIDmbSpbELp_sxYPdp2EBGN_08JbukeZ7P7M-eC4ps1e3mU1-l5j53tc1pYmauqc16J7ulQUe4WTMNWBBg3rBKdnR_E2wWMsirHhRHw8PZwTMmczbHVLAg6TX_RAafz-OOPaqrq2B_m-teT_-89rMWmrhIDnZMUTKPNQiInT0KPqZhZ981yZqkcKPKtJ2wYtliN6DE-GfubhjhCeNEoijF5wx6CruwB8F68SqANak21pj6LFT-gUdVI0S40PGAG87FelsPUVVrOmQJjoLgeE_zaHi684rPgknZbKW9PI-w5DhXfqqwn-8Nw3zanwa9aQ6TNzmZ_3hExa3yn7E4YrGvQFNz2EcpvBmOLl_7aU6OB_ofPFc8xGgwWm2vQQnj2XIMW15AdD9Jw9C63LIfsBd9krF1v9SzmDHVe4C2yRjGoNmaHCpXmzGcCdKKYkLRIVR6jclh5-fs5rU0L4hQC9LjQoS946Dlt731DBShTzh-pzwFn3TwmCOzTw03px_cwGXubDcbV9UP3WwJ5lbmaa9Sb2LLyQ2CE4aDrNeQvIDjnCzkWVHdHDkcTpnaYZCGjOcpf1jcK6lEDN2DKxEosgVM_sR0wg1rKTsm-i_K3Q_ByyYGooRCNv8xTd2mD2YM7AeucLEXDJyNFu5GGjommw8Pm2iq_Y0WyXkkch-PUAnlaDhunHhi0e22faVzG3jfHfy77aArXiWekmRbWwMcWesUVGTP2MMLOSwdbvF4h2Ww84U-V2ez9DHVTjTeN88C9BbAbwVbK5QSLcmAEK89GdSgss4VOI71f-mWih_oAjkMinFQuWW6K2OCrB95lp4SUBlNPOClNOChG1OoRWmbXiejGW8LPIoNK84FsccgEOtk05kjng11Wszj8JTt049ip7xgs1JeFZnazDT0WBzkabPxEEgz1KrZJj7OKqPT3yHtxgZ-NOfXg0AvdJuThwuvKsrQwkQ12AuUDDiODLZtWuBP23Z8wp-IqySHGpC5yrcZkWVBF58n7gSTXcpjsPStPYIXzxmouuRTSujRUcPE3tVgdDoh1jZLZKEOO-z2PWHom508mFbioDC6gluzv9bEv9SyJQcblMbaRR1W7CbvU1W_w6j8wqUVf_ZT3j4zY7CHoSD6AkOrSITmK1nFoivUmZ56LI7ENM34H45TskDgrwV31Jfm9zbnihQ-RTKUrAxRYwCF-5VsoBParjjuJ6qoExAEPXn1Y-yYt6QC29baQVK1lcwuMt05y--cTx0xpDwsLqUki9q6MYQvFAg0toEyW_VNuCJCo8Chsp2VHgG3eNBTfwbQ2M6ipHcldDd5OaEJZmzk6phdbFbaGo8xCJ8PUqiQr3yd5hommaM3W7JgNvUHPif0q8olUK5um-qzUCBSizSzoigdv2vsduE6acPFaHw7I1E4ycTrB1W8FyEsWlMhzofReeoQLmnH0o8IEeGrWMFdrRe5yDw5BjixK_daKBK2REC7mctNl_nx-_DAsgoBjZWYn2cTN0f9nraM0p2PibFqLcOLo-prjcdirllamEIVCSKlgQeBs9VlS5gEFMknLEzeCjkHB3ZQvyo-7VO6N4cDAnSQ_QwZLwIzXZ1Zp1vx5Tc1J8foMb6DP8QU-v4lho48Ac8Pa7PSUTQX-ta3nukBreTGlqmYveL6zBK-K53rHPiZBcn4P3iJ89xCy41LZe6IeUMMejp_65uVSzwMEo1enpzEgFrECaZwt2WezJITOfy0A3VrIdMsGwerm9qpUbOcnxfpBIjkblJHyQ_L8Gdw0uhpQHR44HA4yRKHCsKPP9-J6OP9OakZ_a7kzdhfr8DHNwBb82CG5NCAoQf_i8rD1dImQjOHixPXIITj8NZbnxiUzAYoXBNTqqRsNp4qtd2oQ7mEjTlpIr2w1vm_rTmlfy2zYwL9nRpgkkgVSvhdUJXL052VHDEtyvks3AxxmU5Bx5KqriIzPEK3aLc5whMVpUKjGNPDXC00kCeUmWLaoO3r-9rOAcWJJR6XLN9MrJLiM05E5D1OITRlXIAF4WE31ttkG1v77lpn-VvFtPdYFWfHUVY3dE8ZllQdIjo861QQqxoWgYJYKerDERrtrb_A_oCP-g-iXHNejenr5vCXx5jfOpKfJrFt5mP1w8m-lQe0Nfi_faieqwIT1YypW-DaemCGAI3-CylaoM4qlL9U_mT1qVVkaPgTwoqYeY40W39N0_q4rk3I88HRsUBlCDp6nshfF92Q5pTCnFGDyVJYsBX93qiSvMZiOus2XlNrLF5tVzXP3wwFrmaXi6fRtrJNuq-9-oQWeernrWCP8ArOu2MLcZ81KpGOrVxXmyZt_BEo2UFayEXdVsrS32X76fDPTt7Oxj0iBKWXOcFX9fk0KHWAmaljnnC9pa0qJfR7gHiHFAV3P_RW8IkJNp8QxyVkmFWaFKRAmKTfiaAspbX8qqSiARmUhObJnsWRM6Nhj81GofbF0t15g1NuyZFNm49RCm6ARybWkucUCKqvsVftiKL6uQnVzp30Nx4HZoxWCOd_Viy6cq_E26_ObCN6rHD1v-xjdYKGrtfwHyT3KyZoIBxo0i_H-krjbWpAPn4PNCeEiejKGmkl2ZZDqrap1dE_-BLXtJ1t2BpB2jzAOnyW4Am4P0ELyT37D1JTLZacrrVn9gCdCle3LxbPm3N-3UBPU0g32Knp8ldD9wYVFRY3hDfIoUH7zPm217Q810oRTysntF8TKqtHlNn3cGp1n7iv9zTgS-E2GlFBuPlRM2QtxB3uOYoFE6dl5m8Hcf5ltUeZ9etbogBg3aqcIiCmgOZQqQ9C9QEIHkHLLaaR3eLGPy4Wel1ghGin2DLSaGM-gGSe0nEJdbyj2ctO41r65Xm24uhLxB29vFtcVlJszQedMmN3oifoGwUr0U-E6mAuuN0QfA3-XIn0G7bm6_bBB1fOLN-YTfl2cj1RdEweiQL5rFV7VQ5j_51-UdNZT70PjZab7qovXoYnPmX3NQEqgqq4QilQqrkhVDEZ-oZKZ0CKNa03vESEgCXTdeWmH4AZk-jU0aHK_wyfTmKHltA4VZPDERflMDVpkmZm6BnGACnQo7QmijENqr68fr6YjbrndRTSwungUCxEoZeyqcEJUGhnfn4yJWRb82YvXFkLry-hF7iw_wzGqo4QOhRlVdOWbqMO5Kt_0EOKKWtVARQYr96Y32pzw_Shb2NwotT5xpA2kPZoET2EDdobaAtVAV8h2e7ctCN3pCD-nzd50A0udREP0hl3Hl8L-j28gsEeDETXvfC4PRuZiyJU6F_ac_Qqvu-_wNtuWn_cId5nVbf-hg6YaOi9nAKuQGnlCFMhf1RfDs-Rqegqwvhs9HrXufQUbKpe9DOM4aeW05iSANWB6a3vhaaVJkMdsDc0rrpfQHJJkMht7Mq865810g==', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6', - signature='gAAAAABoxC0_aDtrISw_zls0dyams-nhm23et1xecYaqlI8y44ih0g9FA5T3R9ueXIOX9seSrysa48qci5QTep_TNFkxcjPMbWeQxolRKeCjWk0jLpC2FdKdscfb56KfeSTklKz_CaD-VubFOUgtqg8bQfJTvrdEtKj8Q74c2-XOtHTB-0OjenFtkZMtLMu3uc009ktnOSiWIxkuaDXcvgENQlU60WswxDC_3j92V9o0XsSnXxS8ZmvfWcmYxsFAo575ybwZin6GI709AxlJ6iPkSYIyRy_Sn_O2B68S5ABs8gq0yzaDtX2Wtibqys1NooceCWvxBSjZUKKD3N3FG9Hx_GzaUyvB5DblDmqgfP3AC_VfxaXm990esMW22fQvrEmuRNJc7AF0-KSBCNjatP6eHKj7WSiyGplUFCukk1tRHxOeDi9GD6s51_jTSyADenpzvdBLoELPR0JQIUuraSBpS3aZS8ODJDUbIX8niI_RYzRCvqBDMbLi9MaI_jTdEJknhEgmZZaV-53FXEVM7LoK6BWBpocwDC0zbcA-Da2rY6y3h_4x-PD-DL_W-V0_XDqwhx6NZOJBDpGrJIKY1BU-QjjEdZeXg1hv7CmLCH9ykOr-ja8B72fGaY2sJ9Lg2dFnaEkalEnYPCOY1hWDok1o5H0YVwA3MoZPr4VuFbGKD1EEAcB10UYgY5_WRK5Zk2CYK9EMOyLMA-_DU5qMLw0qrpj7lGRe7PLM0UYBbjP3jFZX6Gy5e1RcibH2MsrbfH4SlVkc1TTak4vuBEIR7Q4q8dYCoKTPgHAWFULzFbaCwhQQtyL1_lG-OpiGGUSZE_VRj3yVKbrv4Nz1l44ah5DdlG0BCiKthdMqcVxc3Bh3VKofIN6G_rArAtZ4ZmcoPVXIUlkfSPm9efNSx1tUpZPKkFk_dtP9B0dU5gD9F3tTU73I7CtuDaIXfe5JOBegu0_kBjEXb33s1B6mnUJJld1f3c13AwcRhMimtidTdtZFp4iAaKH0hWKrC6fOMlzTmz7O7R79sl_81XTQQbIR31yojRzDSvwhRoenyRWvQQMV4PeZ8h-2ioG2l0DQ89YRjkjeUEwZyog0ZWHflw3nr8zjJ7xkliqfJpspfE0scWrCq5KmY21vYkf3EcH-HU5s_S7_vo-JwnNIlTaDJUHbEo8sl_pJAsWix3OgzBSmBPneL-dknHi4IL8NNoGYkH62mbIKVPlBqn52e9QtO7v_yFLxGrZEBC_Z7jsFQQDarKvKk5L1nmWLRUffZvNP0hEy9M93wPDVNZ7fU51jD15tpuj92gBKXIM2sM2KWXFiVqg5PhkT7FvFHii1f-cc0emUTvzlO-ZU3oV73eSiisAUjHK3CO-rWD_WCiSAy1YSSOgORY0NrpwcIY3iuwu8yKxunf2F_bYK8mZPyAiI87-KYctZA2BLRe3UVhcbdkXQqHMTbOe8_yRmm20RnsHNTAk7ZlPNUihqE4kxbK6T0Bm0rtWLx8kZHWqq_netnSDiLa8Jtxzxu6UrKOtoWi7P26FE4pGwS5vPVCJ1Z55IcOZ6kQ_I2JpZA49MFJw6YDhKVnJlBEw8D5DfRC7A2YJ1x7ZVufyrYKiew6FYPaj4hpM95SN7o2PXz-vgTvp0oM0qknmcqdtuMgQcuWR5NED6cYccQJ4DQV2Nodzn_bFokhIcqbQVeheE7Jzy2MrzF_CJ3bD2LEmTKgDeoRfH4f4APSh00c2JAqtrKGmF7yMpBYC4vTTnbjPD4shMEcwgMeQKv8rWIaoRZR68Uhd_qwhW-wLqLawd42RaMzKebvCX78epU6rMz1VAlhZzlKS1keFXp-5xXjy4JQcu_WY-GXqSv7ah8CWGItBFc2yW2vQaDfgeHxc5MZTg7Q_VJkGSIEhttIb_0na2S6UfKXczrF1aoBFCKfxirIrOs-VHvbQCyWXwUdKidKNIqexkOucVOo4MaDMMKYSX7LINIdf4WPwrsa2SBW_UpFp-jrjF-aHmykLShhIEv_nCAHGMmfPwbu3ZsARJYusP6vRL8JdVq7pigfBkcIONWRVO7aM0X4ae43bGPfIzzLkdOKIBMR7KFsAv-4THPPH3UWTUG0MN0dAQPAAd6Jbp2xe3heqTY1J84QLaPFRY66r6rmZDWt8yzFB2IqLlupMgINWWLL8e0v6BLd0C8_jc7kwHmMvaPoXlZwqVFXed47bJOFfDXgymjs9Uw2ubeb1VMydQFmftVwzFY0vFTqqAWWnHIw5udvxgCTXDv2daFOdWPfrE6wKqVb9azxmGGXsoLcigmzwapcHBIUHAKKBE8SO9G3ciUkVFnK1JQEJ8Q96TdxMbnaXsPfy_CDaNUQFTnLYatnTbNq2kr20TudmpMYbm3V6_51K-gZyBh0-ESsRtsW1xaD68FgwS2Hi4zgd5zmko4c4vh3ncQt5eWB4Zy3VPCcNSPvgEVv_1psLFVPWMhhrC7pwV0PeuEE9h-rr66lwV9cgFIJkQf1Q3NzXMOa65aNKvmjAfP40H6jDUrKW03_JH56kb3R9YwE4kDpkkSJzHUsbPLjWPUr6SOUQKT2je9oxE3ioEgtwAlnYlxf5JU_BPyj7EsgLPpe8ZIuaTn7pU_tU8fBo26MEn78g3rwaFZ7PpWn6DeMTG_hDvAaTSZ0qZ6bAqGoj1UP_XzuQOuRvdbO_jNsclKBfZPj3RQcx1c_4H51aKTrJrYLndXSzsMox2BLoNXuUYoDyIeu_J36iUid5W4M7gykJADbUZBIbag8ordczWIaIYGxJHpxqiZvluHO1ufCLYWj3r8GhNNU_BjdyCmisGVV1he4ZdRiNHNlpfAL5SSQv7QynjdrPTIwmugGfinfzq0E7-2MpEOtBxDwlZtLBQsHLracKuIjYorhTzbj2dnvCBWTdfeBnaut-x7dfKr8ReAZnfhn5-qtvJdwFfx77y3t1kUIEBFr1CTmpUh3q5SJtQvR8TeTcPJORHk31EnafeipUwT4JnqA3oEiiqXLs2wTlLAt1SOx-uwMmyMeBEOhK7FS7Tdwgr2f0K-oEaUP_3AAENamy7U975-bvrQC5NQR91rCee0_h13qvdnYG0S_OS1vswYCoq0Z2wnR6wa4nx-ZoEZmnH0YoGyIt14_gOGQ9X5TAWFNlqbbHzhsOUIrN6TM-f5HQzXF7X_V7c1rMtPR-ZlYeXu7lla81J3_eIO_XzOlD4BO2nosgagiT89GQB5Sj16Ehd_KGMPpCsvqOxg_UpPL_kQ7qJtDs8okP4YmvWjp4IHVD_CmV0kyA26B3tlwkD8IUHzlAq7Bxq3TKgnGIgxi0-scAmiMvN-TlXvDjBp0Uh-AWz2zxwAGqsq298xeLkPRpJJJECMlZVPppr2RdKgCyrqBhGLyWIjmIx5-jWY-1XuwT7cb9NGXe6RFfmCXVX_B_0_1ribDdgLMRtGXziYbI8qxmN3tsw6BmPEsDCuofe6Zqm97JipN17tTmv-rdOHeeV9UgeiYQ0xJe6Q9psmhHBxGW6LVp_e9dWt4-aYZ24hSGf8CileysyUV0etiXPh2fVacS4HKQXry29CMP6j6gO6Ca2T3CNIYYd_aG6hVBO4Lk6ENkS4kkl7Wen5tOTI5TCD0pGAIuHIwey-DIfqPbW-ZHhQO3sBYSVtHPMSXP3hrojuR1qEnFVrVyqLABusBzlqB2mAnvSKZRCpZ9VFGUABN6ytItEXv4JDIu8eo0IvMQmWRRguaADU5pBiyQZ_5C3UEyX_QveHmDri9IXaVQz_3a9gowZfMuGj9CVwuhCq8R3ZLclacFxWRFw6byEOm2KZb6jH5qemc-V-Ci1mtcIsOdVLFQXuHkiOyZE2zISd0ckGUWihME4lg0imlSu_XI1MjWwao049bmP0VD5iqqpccIVsJuNkrSmw15AcrHqjlVhIWrD8u6e90uBqvm_l-Yfxe78_cIl-VuWTTa1qI8yw-LeNWloZCTbls5pRQr7MCm5dkZeAt1PBdnBpXTk-8VcvlDsA_hheV-QVbrdP4UTtDArx6QfxDU8PNLMpMgovTDTn6WnaJpdP-WVTSYH-78a7rp01RAmIQTl12vXuNRhPtj7jlortf8YobH2jMog2vRc4uXQpqZyWtSr-BF4vhh7QfzK6myLiEj_ciHNXqd64WzYl__hPaULy2xkwkpnD6mWQnRkoNeFGA-kt0f5J-M4JrRG3qCOdVrccmyLye-vVQyVkqfqgau6YLXd3QdpJkmA7Puu0ie1BeQBnBG4nJcWvDE1R19MdYBT7v-IDTdFBTtPxc5KerxoUy-Zn7xzvmUt6rRuk0pmBwzriAtzZctD2PI8BfoC4zhP-xpMhcNNaqCUBUQ260pWVdhqUCpkoBrskVHMMndizoMbeIeAcdAp4-lI5l-6zTO2APjygljfVHHLjpbTxs1ZA8DYpjrmzWSC07IXpK54MR258kedSamj-6IcUY4OOVVsuLvioELKt5JHwx5oADllUevxdA6K-9vddx7tuhgvkBvL1TpSp0XxDGwH3dRJDFwcDl3ah_PaOAjc33Z2IlcnXynaERtl3ysxBoPSY_4KPn5NoWQ7YHxzA-zQMKaa9fpi2VLN8Ud8redK0EKc9WwKXp-zmJbCf-KBsVCbFcrj9WUz38x-Iv-JEwFnUVpfTporFsB2eYlAPaMrXbf4Vz-Um1nfSVuq0F1V4cCPtZK6I_H-KWLbIseWZxNTJCWlmCaBe7ZQgt8ICUXqspyD9OOU6VNfr0nU7aW0itJEnvmKSfxnj3wQhrmEJ7HsX8mRHaDqAQKCr5B8YT4FOqTISRnTgDsV16ZRp43TaWH4QFpeanUD3KvmpvvfYGXUKVHlud2dUwPCr5FNM1QRFG9cgMBJn3y7ewbuixmPAIU_se3fYA1nYBtMlPpSHMGfXsqrIlMGNXmwsTs7TjG-kLzFrSA2ku5ZFX6N4wQim45hr1fBHI3GDF7IwoHKVCjXLjrkdCOGW0mV-n5uOAJxu5r_Ire3WFys0V9nlPpp9vy40PaNbXTiO0bLZu2u7LVDKAmxvvHxpUZxtW6v5lzoJjhdy1j4yAYCSgctwmH1pwhe8-wzU3JU9Rt1LFTs9t0XRUq_HXAb2kTGBMvk4OuuE1huBo75zhmFb1DVTzjr3Lpx656PZNk_frJiwupQ3qQj7b77ud_OzWgmRcLfmV2HPratlaB7pHQy6srJX-z2So9VD6TdbUUuOlSoGmK6jd1aGMNyhc2SM99TMQsQwbMEpZQ5tkexBf3Yc2TzQKON23R6xP90ctuAD976TtM2mZhV8o_7oB8jY9pyNwyf4tRUz0TPGIWBGgv3XhPugBTB5gfkRWXRvmeA2-Q38To85FnGpZib0yhVqpfS1ol9fZ6qmGQtgN5iZkXceAhYJRBwIq3jZM5-9Kc4QUO4aW4V8P7OXY66kxtcaoxXFcaug_EXomyGVhvLJ99QDE1zxTfZZ99Z7ZbAhYKQhctP43NCx3WPN4P0dP4HOG1HDhCW4wFOdWTKXQOKA1wOhuGUGyxpi6DcnMkM-vCpbWfHNzeSOKOXkBHbKycZiQ13mAv-eKpd0wg15sgkX3XdzHu8Xxc8HqDxsdJoyK0kT9lA8Y8PpF03mwhSqmOpxM4RjLL5U6HSt4FxDSsdVoTr3bzlKplWA29yVjlOU9D0xcbp9_Vkb981glTcmIhmpkP-10LD88arU_kHIkv_Oprhm-sCnNgI0RzmH71j5RxUuJDEKvj-l9A3f4lLEudcJw8ZBe_y7voD2-wNJ55hB5hYjzX45A5JCGbh7bE45bdq-hZ7a5rHekQAKMe1YO0zRzrkUagXurtqAXrZcLAq6NREGetDb8ICCJWA9fYoBWwz1mIBzn0fXUZlPRST-N7btljgD9RqiScsTA5NmGVG63cFq7JR7q0Na6eXVAKBODjcF6pMa4LIExSQq6W8CgXnfmGGTQp7p48TR0wan6nvSCOaaqty0hnELs2AkOb3otvg3T8ISPj36kApd3M5NcOrxW87LV7WEaN2Xy3aHkhxhZNMhAWHAtQpeg66rIsBat_Enqw56zTnSdjbKAAM7_mda7iQg5QEHKPSxkN4J2dAwzG-XmWTQJZhhxkAG0PDpN0sZkXRORxQV9TRBGmXWarK_GWkw2oAFFtf4H2d1KxlNiNQ6t0_6tWvN5piuPQTPhkIDmbSpbELp_sxYPdp2EBGN_08JbukeZ7P7M-eC4ps1e3mU1-l5j53tc1pYmauqc16J7ulQUe4WTMNWBBg3rBKdnR_E2wWMsirHhRHw8PZwTMmczbHVLAg6TX_RAafz-OOPaqrq2B_m-teT_-89rMWmrhIDnZMUTKPNQiInT0KPqZhZ981yZqkcKPKtJ2wYtliN6DE-GfubhjhCeNEoijF5wx6CruwB8F68SqANak21pj6LFT-gUdVI0S40PGAG87FelsPUVVrOmQJjoLgeE_zaHi684rPgknZbKW9PI-w5DhXfqqwn-8Nw3zanwa9aQ6TNzmZ_3hExa3yn7E4YrGvQFNz2EcpvBmOLl_7aU6OB_ofPFc8xGgwWm2vQQnj2XIMW15AdD9Jw9C63LIfsBd9krF1v9SzmDHVe4C2yRjGoNmaHCpXmzGcCdKKYkLRIVR6jclh5-fs5rU0L4hQC9LjQoS946Dlt731DBShTzh-pzwFn3TwmCOzTw03px_cwGXubDcbV9UP3WwJ5lbmaa9Sb2LLyQ2CE4aDrNeQvIDjnCzkWVHdHDkcTpnaYZCGjOcpf1jcK6lEDN2DKxEosgVM_sR0wg1rKTsm-i_K3Q_ByyYGooRCNv8xTd2mD2YM7AeucLEXDJyNFu5GGjommw8Pm2iq_Y0WyXkkch-PUAnlaDhunHhi0e22faVzG3jfHfy77aArXiWekmRbWwMcWesUVGTP2MMLOSwdbvF4h2Ww84U-V2ez9DHVTjTeN88C9BbAbwVbK5QSLcmAEK89GdSgss4VOI71f-mWih_oAjkMinFQuWW6K2OCrB95lp4SUBlNPOClNOChG1OoRWmbXiejGW8LPIoNK84FsccgEOtk05kjng11Wszj8JTt049ip7xgs1JeFZnazDT0WBzkabPxEEgz1KrZJj7OKqPT3yHtxgZ-NOfXg0AvdJuThwuvKsrQwkQ12AuUDDiODLZtWuBP23Z8wp-IqySHGpC5yrcZkWVBF58n7gSTXcpjsPStPYIXzxmouuRTSujRUcPE3tVgdDoh1jZLZKEOO-z2PWHom508mFbioDC6gluzv9bEv9SyJQcblMbaRR1W7CbvU1W_w6j8wqUVf_ZT3j4zY7CHoSD6AkOrSITmK1nFoivUmZ56LI7ENM34H45TskDgrwV31Jfm9zbnihQ-RTKUrAxRYwCF-5VsoBParjjuJ6qoExAEPXn1Y-yYt6QC29baQVK1lcwuMt05y--cTx0xpDwsLqUki9q6MYQvFAg0toEyW_VNuCJCo8Chsp2VHgG3eNBTfwbQ2M6ipHcldDd5OaEJZmzk6phdbFbaGo8xCJ8PUqiQr3yd5hommaM3W7JgNvUHPif0q8olUK5um-qzUCBSizSzoigdv2vsduE6acPFaHw7I1E4ycTrB1W8FyEsWlMhzofReeoQLmnH0o8IEeGrWMFdrRe5yDw5BjixK_daKBK2REC7mctNl_nx-_DAsgoBjZWYn2cTN0f9nraM0p2PibFqLcOLo-prjcdirllamEIVCSKlgQeBs9VlS5gEFMknLEzeCjkHB3ZQvyo-7VO6N4cDAnSQ_QwZLwIzXZ1Zp1vx5Tc1J8foMb6DP8QU-v4lho48Ac8Pa7PSUTQX-ta3nukBreTGlqmYveL6zBK-K53rHPiZBcn4P3iJ89xCy41LZe6IeUMMejp_65uVSzwMEo1enpzEgFrECaZwt2WezJITOfy0A3VrIdMsGwerm9qpUbOcnxfpBIjkblJHyQ_L8Gdw0uhpQHR44HA4yRKHCsKPP9-J6OP9OakZ_a7kzdhfr8DHNwBb82CG5NCAoQf_i8rD1dImQjOHixPXIITj8NZbnxiUzAYoXBNTqqRsNp4qtd2oQ7mEjTlpIr2w1vm_rTmlfy2zYwL9nRpgkkgVSvhdUJXL052VHDEtyvks3AxxmU5Bx5KqriIzPEK3aLc5whMVpUKjGNPDXC00kCeUmWLaoO3r-9rOAcWJJR6XLN9MrJLiM05E5D1OITRlXIAF4WE31ttkG1v77lpn-VvFtPdYFWfHUVY3dE8ZllQdIjo861QQqxoWgYJYKerDERrtrb_A_oCP-g-iXHNejenr5vCXx5jfOpKfJrFt5mP1w8m-lQe0Nfi_faieqwIT1YypW-DaemCGAI3-CylaoM4qlL9U_mT1qVVkaPgTwoqYeY40W39N0_q4rk3I88HRsUBlCDp6nshfF92Q5pTCnFGDyVJYsBX93qiSvMZiOus2XlNrLF5tVzXP3wwFrmaXi6fRtrJNuq-9-oQWeernrWCP8ArOu2MLcZ81KpGOrVxXmyZt_BEo2UFayEXdVsrS32X76fDPTt7Oxj0iBKWXOcFX9fk0KHWAmaljnnC9pa0qJfR7gHiHFAV3P_RW8IkJNp8QxyVkmFWaFKRAmKTfiaAspbX8qqSiARmUhObJnsWRM6Nhj81GofbF0t15g1NuyZFNm49RCm6ARybWkucUCKqvsVftiKL6uQnVzp30Nx4HZoxWCOd_Viy6cq_E26_ObCN6rHD1v-xjdYKGrtfwHyT3KyZoIBxo0i_H-krjbWpAPn4PNCeEiejKGmkl2ZZDqrap1dE_-BLXtJ1t2BpB2jzAOnyW4Am4P0ELyT37D1JTLZacrrVn9gCdCle3LxbPm3N-3UBPU0g32Knp8ldD9wYVFRY3hDfIoUH7zPm217Q810oRTysntF8TKqtHlNn3cGp1n7iv9zTgS-E2GlFBuPlRM2QtxB3uOYoFE6dl5m8Hcf5ltUeZ9etbogBg3aqcIiCmgOZQqQ9C9QEIHkHLLaaR3eLGPy4Wel1ghGin2DLSaGM-gGSe0nEJdbyj2ctO41r65Xm24uhLxB29vFtcVlJszQedMmN3oifoGwUr0U-E6mAuuN0QfA3-XIn0G7bm6_bBB1fOLN-YTfl2cj1RdEweiQL5rFV7VQ5j_51-UdNZT70PjZab7qovXoYnPmX3NQEqgqq4QilQqrkhVDEZ-oZKZ0CKNa03vESEgCXTdeWmH4AZk-jU0aHK_wyfTmKHltA4VZPDERflMDVpkmZm6BnGACnQo7QmijENqr68fr6YjbrndRTSwungUCxEoZeyqcEJUGhnfn4yJWRb82YvXFkLry-hF7iw_wzGqo4QOhRlVdOWbqMO5Kt_0EOKKWtVARQYr96Y32pzw_Shb2NwotT5xpA2kPZoET2EDdobaAtVAV8h2e7ctCN3pCD-nzd50A0udREP0hl3Hl8L-j28gsEeDETXvfC4PRuZiyJU6F_ac_Qqvu-_wNtuWn_cId5nVbf-hg6YaOi9nAKuQGnlCFMhf1RfDs-Rqegqwvhs9HrXufQUbKpe9DOM4aeW05iSANWB6a3vhaaVJkMdsDc0rrpfQHJJkMht7Mq865810g==', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6', - signature='gAAAAABoxC0_aDtrISw_zls0dyams-nhm23et1xecYaqlI8y44ih0g9FA5T3R9ueXIOX9seSrysa48qci5QTep_TNFkxcjPMbWeQxolRKeCjWk0jLpC2FdKdscfb56KfeSTklKz_CaD-VubFOUgtqg8bQfJTvrdEtKj8Q74c2-XOtHTB-0OjenFtkZMtLMu3uc009ktnOSiWIxkuaDXcvgENQlU60WswxDC_3j92V9o0XsSnXxS8ZmvfWcmYxsFAo575ybwZin6GI709AxlJ6iPkSYIyRy_Sn_O2B68S5ABs8gq0yzaDtX2Wtibqys1NooceCWvxBSjZUKKD3N3FG9Hx_GzaUyvB5DblDmqgfP3AC_VfxaXm990esMW22fQvrEmuRNJc7AF0-KSBCNjatP6eHKj7WSiyGplUFCukk1tRHxOeDi9GD6s51_jTSyADenpzvdBLoELPR0JQIUuraSBpS3aZS8ODJDUbIX8niI_RYzRCvqBDMbLi9MaI_jTdEJknhEgmZZaV-53FXEVM7LoK6BWBpocwDC0zbcA-Da2rY6y3h_4x-PD-DL_W-V0_XDqwhx6NZOJBDpGrJIKY1BU-QjjEdZeXg1hv7CmLCH9ykOr-ja8B72fGaY2sJ9Lg2dFnaEkalEnYPCOY1hWDok1o5H0YVwA3MoZPr4VuFbGKD1EEAcB10UYgY5_WRK5Zk2CYK9EMOyLMA-_DU5qMLw0qrpj7lGRe7PLM0UYBbjP3jFZX6Gy5e1RcibH2MsrbfH4SlVkc1TTak4vuBEIR7Q4q8dYCoKTPgHAWFULzFbaCwhQQtyL1_lG-OpiGGUSZE_VRj3yVKbrv4Nz1l44ah5DdlG0BCiKthdMqcVxc3Bh3VKofIN6G_rArAtZ4ZmcoPVXIUlkfSPm9efNSx1tUpZPKkFk_dtP9B0dU5gD9F3tTU73I7CtuDaIXfe5JOBegu0_kBjEXb33s1B6mnUJJld1f3c13AwcRhMimtidTdtZFp4iAaKH0hWKrC6fOMlzTmz7O7R79sl_81XTQQbIR31yojRzDSvwhRoenyRWvQQMV4PeZ8h-2ioG2l0DQ89YRjkjeUEwZyog0ZWHflw3nr8zjJ7xkliqfJpspfE0scWrCq5KmY21vYkf3EcH-HU5s_S7_vo-JwnNIlTaDJUHbEo8sl_pJAsWix3OgzBSmBPneL-dknHi4IL8NNoGYkH62mbIKVPlBqn52e9QtO7v_yFLxGrZEBC_Z7jsFQQDarKvKk5L1nmWLRUffZvNP0hEy9M93wPDVNZ7fU51jD15tpuj92gBKXIM2sM2KWXFiVqg5PhkT7FvFHii1f-cc0emUTvzlO-ZU3oV73eSiisAUjHK3CO-rWD_WCiSAy1YSSOgORY0NrpwcIY3iuwu8yKxunf2F_bYK8mZPyAiI87-KYctZA2BLRe3UVhcbdkXQqHMTbOe8_yRmm20RnsHNTAk7ZlPNUihqE4kxbK6T0Bm0rtWLx8kZHWqq_netnSDiLa8Jtxzxu6UrKOtoWi7P26FE4pGwS5vPVCJ1Z55IcOZ6kQ_I2JpZA49MFJw6YDhKVnJlBEw8D5DfRC7A2YJ1x7ZVufyrYKiew6FYPaj4hpM95SN7o2PXz-vgTvp0oM0qknmcqdtuMgQcuWR5NED6cYccQJ4DQV2Nodzn_bFokhIcqbQVeheE7Jzy2MrzF_CJ3bD2LEmTKgDeoRfH4f4APSh00c2JAqtrKGmF7yMpBYC4vTTnbjPD4shMEcwgMeQKv8rWIaoRZR68Uhd_qwhW-wLqLawd42RaMzKebvCX78epU6rMz1VAlhZzlKS1keFXp-5xXjy4JQcu_WY-GXqSv7ah8CWGItBFc2yW2vQaDfgeHxc5MZTg7Q_VJkGSIEhttIb_0na2S6UfKXczrF1aoBFCKfxirIrOs-VHvbQCyWXwUdKidKNIqexkOucVOo4MaDMMKYSX7LINIdf4WPwrsa2SBW_UpFp-jrjF-aHmykLShhIEv_nCAHGMmfPwbu3ZsARJYusP6vRL8JdVq7pigfBkcIONWRVO7aM0X4ae43bGPfIzzLkdOKIBMR7KFsAv-4THPPH3UWTUG0MN0dAQPAAd6Jbp2xe3heqTY1J84QLaPFRY66r6rmZDWt8yzFB2IqLlupMgINWWLL8e0v6BLd0C8_jc7kwHmMvaPoXlZwqVFXed47bJOFfDXgymjs9Uw2ubeb1VMydQFmftVwzFY0vFTqqAWWnHIw5udvxgCTXDv2daFOdWPfrE6wKqVb9azxmGGXsoLcigmzwapcHBIUHAKKBE8SO9G3ciUkVFnK1JQEJ8Q96TdxMbnaXsPfy_CDaNUQFTnLYatnTbNq2kr20TudmpMYbm3V6_51K-gZyBh0-ESsRtsW1xaD68FgwS2Hi4zgd5zmko4c4vh3ncQt5eWB4Zy3VPCcNSPvgEVv_1psLFVPWMhhrC7pwV0PeuEE9h-rr66lwV9cgFIJkQf1Q3NzXMOa65aNKvmjAfP40H6jDUrKW03_JH56kb3R9YwE4kDpkkSJzHUsbPLjWPUr6SOUQKT2je9oxE3ioEgtwAlnYlxf5JU_BPyj7EsgLPpe8ZIuaTn7pU_tU8fBo26MEn78g3rwaFZ7PpWn6DeMTG_hDvAaTSZ0qZ6bAqGoj1UP_XzuQOuRvdbO_jNsclKBfZPj3RQcx1c_4H51aKTrJrYLndXSzsMox2BLoNXuUYoDyIeu_J36iUid5W4M7gykJADbUZBIbag8ordczWIaIYGxJHpxqiZvluHO1ufCLYWj3r8GhNNU_BjdyCmisGVV1he4ZdRiNHNlpfAL5SSQv7QynjdrPTIwmugGfinfzq0E7-2MpEOtBxDwlZtLBQsHLracKuIjYorhTzbj2dnvCBWTdfeBnaut-x7dfKr8ReAZnfhn5-qtvJdwFfx77y3t1kUIEBFr1CTmpUh3q5SJtQvR8TeTcPJORHk31EnafeipUwT4JnqA3oEiiqXLs2wTlLAt1SOx-uwMmyMeBEOhK7FS7Tdwgr2f0K-oEaUP_3AAENamy7U975-bvrQC5NQR91rCee0_h13qvdnYG0S_OS1vswYCoq0Z2wnR6wa4nx-ZoEZmnH0YoGyIt14_gOGQ9X5TAWFNlqbbHzhsOUIrN6TM-f5HQzXF7X_V7c1rMtPR-ZlYeXu7lla81J3_eIO_XzOlD4BO2nosgagiT89GQB5Sj16Ehd_KGMPpCsvqOxg_UpPL_kQ7qJtDs8okP4YmvWjp4IHVD_CmV0kyA26B3tlwkD8IUHzlAq7Bxq3TKgnGIgxi0-scAmiMvN-TlXvDjBp0Uh-AWz2zxwAGqsq298xeLkPRpJJJECMlZVPppr2RdKgCyrqBhGLyWIjmIx5-jWY-1XuwT7cb9NGXe6RFfmCXVX_B_0_1ribDdgLMRtGXziYbI8qxmN3tsw6BmPEsDCuofe6Zqm97JipN17tTmv-rdOHeeV9UgeiYQ0xJe6Q9psmhHBxGW6LVp_e9dWt4-aYZ24hSGf8CileysyUV0etiXPh2fVacS4HKQXry29CMP6j6gO6Ca2T3CNIYYd_aG6hVBO4Lk6ENkS4kkl7Wen5tOTI5TCD0pGAIuHIwey-DIfqPbW-ZHhQO3sBYSVtHPMSXP3hrojuR1qEnFVrVyqLABusBzlqB2mAnvSKZRCpZ9VFGUABN6ytItEXv4JDIu8eo0IvMQmWRRguaADU5pBiyQZ_5C3UEyX_QveHmDri9IXaVQz_3a9gowZfMuGj9CVwuhCq8R3ZLclacFxWRFw6byEOm2KZb6jH5qemc-V-Ci1mtcIsOdVLFQXuHkiOyZE2zISd0ckGUWihME4lg0imlSu_XI1MjWwao049bmP0VD5iqqpccIVsJuNkrSmw15AcrHqjlVhIWrD8u6e90uBqvm_l-Yfxe78_cIl-VuWTTa1qI8yw-LeNWloZCTbls5pRQr7MCm5dkZeAt1PBdnBpXTk-8VcvlDsA_hheV-QVbrdP4UTtDArx6QfxDU8PNLMpMgovTDTn6WnaJpdP-WVTSYH-78a7rp01RAmIQTl12vXuNRhPtj7jlortf8YobH2jMog2vRc4uXQpqZyWtSr-BF4vhh7QfzK6myLiEj_ciHNXqd64WzYl__hPaULy2xkwkpnD6mWQnRkoNeFGA-kt0f5J-M4JrRG3qCOdVrccmyLye-vVQyVkqfqgau6YLXd3QdpJkmA7Puu0ie1BeQBnBG4nJcWvDE1R19MdYBT7v-IDTdFBTtPxc5KerxoUy-Zn7xzvmUt6rRuk0pmBwzriAtzZctD2PI8BfoC4zhP-xpMhcNNaqCUBUQ260pWVdhqUCpkoBrskVHMMndizoMbeIeAcdAp4-lI5l-6zTO2APjygljfVHHLjpbTxs1ZA8DYpjrmzWSC07IXpK54MR258kedSamj-6IcUY4OOVVsuLvioELKt5JHwx5oADllUevxdA6K-9vddx7tuhgvkBvL1TpSp0XxDGwH3dRJDFwcDl3ah_PaOAjc33Z2IlcnXynaERtl3ysxBoPSY_4KPn5NoWQ7YHxzA-zQMKaa9fpi2VLN8Ud8redK0EKc9WwKXp-zmJbCf-KBsVCbFcrj9WUz38x-Iv-JEwFnUVpfTporFsB2eYlAPaMrXbf4Vz-Um1nfSVuq0F1V4cCPtZK6I_H-KWLbIseWZxNTJCWlmCaBe7ZQgt8ICUXqspyD9OOU6VNfr0nU7aW0itJEnvmKSfxnj3wQhrmEJ7HsX8mRHaDqAQKCr5B8YT4FOqTISRnTgDsV16ZRp43TaWH4QFpeanUD3KvmpvvfYGXUKVHlud2dUwPCr5FNM1QRFG9cgMBJn3y7ewbuixmPAIU_se3fYA1nYBtMlPpSHMGfXsqrIlMGNXmwsTs7TjG-kLzFrSA2ku5ZFX6N4wQim45hr1fBHI3GDF7IwoHKVCjXLjrkdCOGW0mV-n5uOAJxu5r_Ire3WFys0V9nlPpp9vy40PaNbXTiO0bLZu2u7LVDKAmxvvHxpUZxtW6v5lzoJjhdy1j4yAYCSgctwmH1pwhe8-wzU3JU9Rt1LFTs9t0XRUq_HXAb2kTGBMvk4OuuE1huBo75zhmFb1DVTzjr3Lpx656PZNk_frJiwupQ3qQj7b77ud_OzWgmRcLfmV2HPratlaB7pHQy6srJX-z2So9VD6TdbUUuOlSoGmK6jd1aGMNyhc2SM99TMQsQwbMEpZQ5tkexBf3Yc2TzQKON23R6xP90ctuAD976TtM2mZhV8o_7oB8jY9pyNwyf4tRUz0TPGIWBGgv3XhPugBTB5gfkRWXRvmeA2-Q38To85FnGpZib0yhVqpfS1ol9fZ6qmGQtgN5iZkXceAhYJRBwIq3jZM5-9Kc4QUO4aW4V8P7OXY66kxtcaoxXFcaug_EXomyGVhvLJ99QDE1zxTfZZ99Z7ZbAhYKQhctP43NCx3WPN4P0dP4HOG1HDhCW4wFOdWTKXQOKA1wOhuGUGyxpi6DcnMkM-vCpbWfHNzeSOKOXkBHbKycZiQ13mAv-eKpd0wg15sgkX3XdzHu8Xxc8HqDxsdJoyK0kT9lA8Y8PpF03mwhSqmOpxM4RjLL5U6HSt4FxDSsdVoTr3bzlKplWA29yVjlOU9D0xcbp9_Vkb981glTcmIhmpkP-10LD88arU_kHIkv_Oprhm-sCnNgI0RzmH71j5RxUuJDEKvj-l9A3f4lLEudcJw8ZBe_y7voD2-wNJ55hB5hYjzX45A5JCGbh7bE45bdq-hZ7a5rHekQAKMe1YO0zRzrkUagXurtqAXrZcLAq6NREGetDb8ICCJWA9fYoBWwz1mIBzn0fXUZlPRST-N7btljgD9RqiScsTA5NmGVG63cFq7JR7q0Na6eXVAKBODjcF6pMa4LIExSQq6W8CgXnfmGGTQp7p48TR0wan6nvSCOaaqty0hnELs2AkOb3otvg3T8ISPj36kApd3M5NcOrxW87LV7WEaN2Xy3aHkhxhZNMhAWHAtQpeg66rIsBat_Enqw56zTnSdjbKAAM7_mda7iQg5QEHKPSxkN4J2dAwzG-XmWTQJZhhxkAG0PDpN0sZkXRORxQV9TRBGmXWarK_GWkw2oAFFtf4H2d1KxlNiNQ6t0_6tWvN5piuPQTPhkIDmbSpbELp_sxYPdp2EBGN_08JbukeZ7P7M-eC4ps1e3mU1-l5j53tc1pYmauqc16J7ulQUe4WTMNWBBg3rBKdnR_E2wWMsirHhRHw8PZwTMmczbHVLAg6TX_RAafz-OOPaqrq2B_m-teT_-89rMWmrhIDnZMUTKPNQiInT0KPqZhZ981yZqkcKPKtJ2wYtliN6DE-GfubhjhCeNEoijF5wx6CruwB8F68SqANak21pj6LFT-gUdVI0S40PGAG87FelsPUVVrOmQJjoLgeE_zaHi684rPgknZbKW9PI-w5DhXfqqwn-8Nw3zanwa9aQ6TNzmZ_3hExa3yn7E4YrGvQFNz2EcpvBmOLl_7aU6OB_ofPFc8xGgwWm2vQQnj2XIMW15AdD9Jw9C63LIfsBd9krF1v9SzmDHVe4C2yRjGoNmaHCpXmzGcCdKKYkLRIVR6jclh5-fs5rU0L4hQC9LjQoS946Dlt731DBShTzh-pzwFn3TwmCOzTw03px_cwGXubDcbV9UP3WwJ5lbmaa9Sb2LLyQ2CE4aDrNeQvIDjnCzkWVHdHDkcTpnaYZCGjOcpf1jcK6lEDN2DKxEosgVM_sR0wg1rKTsm-i_K3Q_ByyYGooRCNv8xTd2mD2YM7AeucLEXDJyNFu5GGjommw8Pm2iq_Y0WyXkkch-PUAnlaDhunHhi0e22faVzG3jfHfy77aArXiWekmRbWwMcWesUVGTP2MMLOSwdbvF4h2Ww84U-V2ez9DHVTjTeN88C9BbAbwVbK5QSLcmAEK89GdSgss4VOI71f-mWih_oAjkMinFQuWW6K2OCrB95lp4SUBlNPOClNOChG1OoRWmbXiejGW8LPIoNK84FsccgEOtk05kjng11Wszj8JTt049ip7xgs1JeFZnazDT0WBzkabPxEEgz1KrZJj7OKqPT3yHtxgZ-NOfXg0AvdJuThwuvKsrQwkQ12AuUDDiODLZtWuBP23Z8wp-IqySHGpC5yrcZkWVBF58n7gSTXcpjsPStPYIXzxmouuRTSujRUcPE3tVgdDoh1jZLZKEOO-z2PWHom508mFbioDC6gluzv9bEv9SyJQcblMbaRR1W7CbvU1W_w6j8wqUVf_ZT3j4zY7CHoSD6AkOrSITmK1nFoivUmZ56LI7ENM34H45TskDgrwV31Jfm9zbnihQ-RTKUrAxRYwCF-5VsoBParjjuJ6qoExAEPXn1Y-yYt6QC29baQVK1lcwuMt05y--cTx0xpDwsLqUki9q6MYQvFAg0toEyW_VNuCJCo8Chsp2VHgG3eNBTfwbQ2M6ipHcldDd5OaEJZmzk6phdbFbaGo8xCJ8PUqiQr3yd5hommaM3W7JgNvUHPif0q8olUK5um-qzUCBSizSzoigdv2vsduE6acPFaHw7I1E4ycTrB1W8FyEsWlMhzofReeoQLmnH0o8IEeGrWMFdrRe5yDw5BjixK_daKBK2REC7mctNl_nx-_DAsgoBjZWYn2cTN0f9nraM0p2PibFqLcOLo-prjcdirllamEIVCSKlgQeBs9VlS5gEFMknLEzeCjkHB3ZQvyo-7VO6N4cDAnSQ_QwZLwIzXZ1Zp1vx5Tc1J8foMb6DP8QU-v4lho48Ac8Pa7PSUTQX-ta3nukBreTGlqmYveL6zBK-K53rHPiZBcn4P3iJ89xCy41LZe6IeUMMejp_65uVSzwMEo1enpzEgFrECaZwt2WezJITOfy0A3VrIdMsGwerm9qpUbOcnxfpBIjkblJHyQ_L8Gdw0uhpQHR44HA4yRKHCsKPP9-J6OP9OakZ_a7kzdhfr8DHNwBb82CG5NCAoQf_i8rD1dImQjOHixPXIITj8NZbnxiUzAYoXBNTqqRsNp4qtd2oQ7mEjTlpIr2w1vm_rTmlfy2zYwL9nRpgkkgVSvhdUJXL052VHDEtyvks3AxxmU5Bx5KqriIzPEK3aLc5whMVpUKjGNPDXC00kCeUmWLaoO3r-9rOAcWJJR6XLN9MrJLiM05E5D1OITRlXIAF4WE31ttkG1v77lpn-VvFtPdYFWfHUVY3dE8ZllQdIjo861QQqxoWgYJYKerDERrtrb_A_oCP-g-iXHNejenr5vCXx5jfOpKfJrFt5mP1w8m-lQe0Nfi_faieqwIT1YypW-DaemCGAI3-CylaoM4qlL9U_mT1qVVkaPgTwoqYeY40W39N0_q4rk3I88HRsUBlCDp6nshfF92Q5pTCnFGDyVJYsBX93qiSvMZiOus2XlNrLF5tVzXP3wwFrmaXi6fRtrJNuq-9-oQWeernrWCP8ArOu2MLcZ81KpGOrVxXmyZt_BEo2UFayEXdVsrS32X76fDPTt7Oxj0iBKWXOcFX9fk0KHWAmaljnnC9pa0qJfR7gHiHFAV3P_RW8IkJNp8QxyVkmFWaFKRAmKTfiaAspbX8qqSiARmUhObJnsWRM6Nhj81GofbF0t15g1NuyZFNm49RCm6ARybWkucUCKqvsVftiKL6uQnVzp30Nx4HZoxWCOd_Viy6cq_E26_ObCN6rHD1v-xjdYKGrtfwHyT3KyZoIBxo0i_H-krjbWpAPn4PNCeEiejKGmkl2ZZDqrap1dE_-BLXtJ1t2BpB2jzAOnyW4Am4P0ELyT37D1JTLZacrrVn9gCdCle3LxbPm3N-3UBPU0g32Knp8ldD9wYVFRY3hDfIoUH7zPm217Q810oRTysntF8TKqtHlNn3cGp1n7iv9zTgS-E2GlFBuPlRM2QtxB3uOYoFE6dl5m8Hcf5ltUeZ9etbogBg3aqcIiCmgOZQqQ9C9QEIHkHLLaaR3eLGPy4Wel1ghGin2DLSaGM-gGSe0nEJdbyj2ctO41r65Xm24uhLxB29vFtcVlJszQedMmN3oifoGwUr0U-E6mAuuN0QfA3-XIn0G7bm6_bBB1fOLN-YTfl2cj1RdEweiQL5rFV7VQ5j_51-UdNZT70PjZab7qovXoYnPmX3NQEqgqq4QilQqrkhVDEZ-oZKZ0CKNa03vESEgCXTdeWmH4AZk-jU0aHK_wyfTmKHltA4VZPDERflMDVpkmZm6BnGACnQo7QmijENqr68fr6YjbrndRTSwungUCxEoZeyqcEJUGhnfn4yJWRb82YvXFkLry-hF7iw_wzGqo4QOhRlVdOWbqMO5Kt_0EOKKWtVARQYr96Y32pzw_Shb2NwotT5xpA2kPZoET2EDdobaAtVAV8h2e7ctCN3pCD-nzd50A0udREP0hl3Hl8L-j28gsEeDETXvfC4PRuZiyJU6F_ac_Qqvu-_wNtuWn_cId5nVbf-hg6YaOi9nAKuQGnlCFMhf1RfDs-Rqegqwvhs9HrXufQUbKpe9DOM4aeW05iSANWB6a3vhaaVJkMdsDc0rrpfQHJJkMht7Mq865810g==', - provider_name='openai', - ), - ThinkingPart( - content=IsStr(), - id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6', - signature='gAAAAABoxC0_aDtrISw_zls0dyams-nhm23et1xecYaqlI8y44ih0g9FA5T3R9ueXIOX9seSrysa48qci5QTep_TNFkxcjPMbWeQxolRKeCjWk0jLpC2FdKdscfb56KfeSTklKz_CaD-VubFOUgtqg8bQfJTvrdEtKj8Q74c2-XOtHTB-0OjenFtkZMtLMu3uc009ktnOSiWIxkuaDXcvgENQlU60WswxDC_3j92V9o0XsSnXxS8ZmvfWcmYxsFAo575ybwZin6GI709AxlJ6iPkSYIyRy_Sn_O2B68S5ABs8gq0yzaDtX2Wtibqys1NooceCWvxBSjZUKKD3N3FG9Hx_GzaUyvB5DblDmqgfP3AC_VfxaXm990esMW22fQvrEmuRNJc7AF0-KSBCNjatP6eHKj7WSiyGplUFCukk1tRHxOeDi9GD6s51_jTSyADenpzvdBLoELPR0JQIUuraSBpS3aZS8ODJDUbIX8niI_RYzRCvqBDMbLi9MaI_jTdEJknhEgmZZaV-53FXEVM7LoK6BWBpocwDC0zbcA-Da2rY6y3h_4x-PD-DL_W-V0_XDqwhx6NZOJBDpGrJIKY1BU-QjjEdZeXg1hv7CmLCH9ykOr-ja8B72fGaY2sJ9Lg2dFnaEkalEnYPCOY1hWDok1o5H0YVwA3MoZPr4VuFbGKD1EEAcB10UYgY5_WRK5Zk2CYK9EMOyLMA-_DU5qMLw0qrpj7lGRe7PLM0UYBbjP3jFZX6Gy5e1RcibH2MsrbfH4SlVkc1TTak4vuBEIR7Q4q8dYCoKTPgHAWFULzFbaCwhQQtyL1_lG-OpiGGUSZE_VRj3yVKbrv4Nz1l44ah5DdlG0BCiKthdMqcVxc3Bh3VKofIN6G_rArAtZ4ZmcoPVXIUlkfSPm9efNSx1tUpZPKkFk_dtP9B0dU5gD9F3tTU73I7CtuDaIXfe5JOBegu0_kBjEXb33s1B6mnUJJld1f3c13AwcRhMimtidTdtZFp4iAaKH0hWKrC6fOMlzTmz7O7R79sl_81XTQQbIR31yojRzDSvwhRoenyRWvQQMV4PeZ8h-2ioG2l0DQ89YRjkjeUEwZyog0ZWHflw3nr8zjJ7xkliqfJpspfE0scWrCq5KmY21vYkf3EcH-HU5s_S7_vo-JwnNIlTaDJUHbEo8sl_pJAsWix3OgzBSmBPneL-dknHi4IL8NNoGYkH62mbIKVPlBqn52e9QtO7v_yFLxGrZEBC_Z7jsFQQDarKvKk5L1nmWLRUffZvNP0hEy9M93wPDVNZ7fU51jD15tpuj92gBKXIM2sM2KWXFiVqg5PhkT7FvFHii1f-cc0emUTvzlO-ZU3oV73eSiisAUjHK3CO-rWD_WCiSAy1YSSOgORY0NrpwcIY3iuwu8yKxunf2F_bYK8mZPyAiI87-KYctZA2BLRe3UVhcbdkXQqHMTbOe8_yRmm20RnsHNTAk7ZlPNUihqE4kxbK6T0Bm0rtWLx8kZHWqq_netnSDiLa8Jtxzxu6UrKOtoWi7P26FE4pGwS5vPVCJ1Z55IcOZ6kQ_I2JpZA49MFJw6YDhKVnJlBEw8D5DfRC7A2YJ1x7ZVufyrYKiew6FYPaj4hpM95SN7o2PXz-vgTvp0oM0qknmcqdtuMgQcuWR5NED6cYccQJ4DQV2Nodzn_bFokhIcqbQVeheE7Jzy2MrzF_CJ3bD2LEmTKgDeoRfH4f4APSh00c2JAqtrKGmF7yMpBYC4vTTnbjPD4shMEcwgMeQKv8rWIaoRZR68Uhd_qwhW-wLqLawd42RaMzKebvCX78epU6rMz1VAlhZzlKS1keFXp-5xXjy4JQcu_WY-GXqSv7ah8CWGItBFc2yW2vQaDfgeHxc5MZTg7Q_VJkGSIEhttIb_0na2S6UfKXczrF1aoBFCKfxirIrOs-VHvbQCyWXwUdKidKNIqexkOucVOo4MaDMMKYSX7LINIdf4WPwrsa2SBW_UpFp-jrjF-aHmykLShhIEv_nCAHGMmfPwbu3ZsARJYusP6vRL8JdVq7pigfBkcIONWRVO7aM0X4ae43bGPfIzzLkdOKIBMR7KFsAv-4THPPH3UWTUG0MN0dAQPAAd6Jbp2xe3heqTY1J84QLaPFRY66r6rmZDWt8yzFB2IqLlupMgINWWLL8e0v6BLd0C8_jc7kwHmMvaPoXlZwqVFXed47bJOFfDXgymjs9Uw2ubeb1VMydQFmftVwzFY0vFTqqAWWnHIw5udvxgCTXDv2daFOdWPfrE6wKqVb9azxmGGXsoLcigmzwapcHBIUHAKKBE8SO9G3ciUkVFnK1JQEJ8Q96TdxMbnaXsPfy_CDaNUQFTnLYatnTbNq2kr20TudmpMYbm3V6_51K-gZyBh0-ESsRtsW1xaD68FgwS2Hi4zgd5zmko4c4vh3ncQt5eWB4Zy3VPCcNSPvgEVv_1psLFVPWMhhrC7pwV0PeuEE9h-rr66lwV9cgFIJkQf1Q3NzXMOa65aNKvmjAfP40H6jDUrKW03_JH56kb3R9YwE4kDpkkSJzHUsbPLjWPUr6SOUQKT2je9oxE3ioEgtwAlnYlxf5JU_BPyj7EsgLPpe8ZIuaTn7pU_tU8fBo26MEn78g3rwaFZ7PpWn6DeMTG_hDvAaTSZ0qZ6bAqGoj1UP_XzuQOuRvdbO_jNsclKBfZPj3RQcx1c_4H51aKTrJrYLndXSzsMox2BLoNXuUYoDyIeu_J36iUid5W4M7gykJADbUZBIbag8ordczWIaIYGxJHpxqiZvluHO1ufCLYWj3r8GhNNU_BjdyCmisGVV1he4ZdRiNHNlpfAL5SSQv7QynjdrPTIwmugGfinfzq0E7-2MpEOtBxDwlZtLBQsHLracKuIjYorhTzbj2dnvCBWTdfeBnaut-x7dfKr8ReAZnfhn5-qtvJdwFfx77y3t1kUIEBFr1CTmpUh3q5SJtQvR8TeTcPJORHk31EnafeipUwT4JnqA3oEiiqXLs2wTlLAt1SOx-uwMmyMeBEOhK7FS7Tdwgr2f0K-oEaUP_3AAENamy7U975-bvrQC5NQR91rCee0_h13qvdnYG0S_OS1vswYCoq0Z2wnR6wa4nx-ZoEZmnH0YoGyIt14_gOGQ9X5TAWFNlqbbHzhsOUIrN6TM-f5HQzXF7X_V7c1rMtPR-ZlYeXu7lla81J3_eIO_XzOlD4BO2nosgagiT89GQB5Sj16Ehd_KGMPpCsvqOxg_UpPL_kQ7qJtDs8okP4YmvWjp4IHVD_CmV0kyA26B3tlwkD8IUHzlAq7Bxq3TKgnGIgxi0-scAmiMvN-TlXvDjBp0Uh-AWz2zxwAGqsq298xeLkPRpJJJECMlZVPppr2RdKgCyrqBhGLyWIjmIx5-jWY-1XuwT7cb9NGXe6RFfmCXVX_B_0_1ribDdgLMRtGXziYbI8qxmN3tsw6BmPEsDCuofe6Zqm97JipN17tTmv-rdOHeeV9UgeiYQ0xJe6Q9psmhHBxGW6LVp_e9dWt4-aYZ24hSGf8CileysyUV0etiXPh2fVacS4HKQXry29CMP6j6gO6Ca2T3CNIYYd_aG6hVBO4Lk6ENkS4kkl7Wen5tOTI5TCD0pGAIuHIwey-DIfqPbW-ZHhQO3sBYSVtHPMSXP3hrojuR1qEnFVrVyqLABusBzlqB2mAnvSKZRCpZ9VFGUABN6ytItEXv4JDIu8eo0IvMQmWRRguaADU5pBiyQZ_5C3UEyX_QveHmDri9IXaVQz_3a9gowZfMuGj9CVwuhCq8R3ZLclacFxWRFw6byEOm2KZb6jH5qemc-V-Ci1mtcIsOdVLFQXuHkiOyZE2zISd0ckGUWihME4lg0imlSu_XI1MjWwao049bmP0VD5iqqpccIVsJuNkrSmw15AcrHqjlVhIWrD8u6e90uBqvm_l-Yfxe78_cIl-VuWTTa1qI8yw-LeNWloZCTbls5pRQr7MCm5dkZeAt1PBdnBpXTk-8VcvlDsA_hheV-QVbrdP4UTtDArx6QfxDU8PNLMpMgovTDTn6WnaJpdP-WVTSYH-78a7rp01RAmIQTl12vXuNRhPtj7jlortf8YobH2jMog2vRc4uXQpqZyWtSr-BF4vhh7QfzK6myLiEj_ciHNXqd64WzYl__hPaULy2xkwkpnD6mWQnRkoNeFGA-kt0f5J-M4JrRG3qCOdVrccmyLye-vVQyVkqfqgau6YLXd3QdpJkmA7Puu0ie1BeQBnBG4nJcWvDE1R19MdYBT7v-IDTdFBTtPxc5KerxoUy-Zn7xzvmUt6rRuk0pmBwzriAtzZctD2PI8BfoC4zhP-xpMhcNNaqCUBUQ260pWVdhqUCpkoBrskVHMMndizoMbeIeAcdAp4-lI5l-6zTO2APjygljfVHHLjpbTxs1ZA8DYpjrmzWSC07IXpK54MR258kedSamj-6IcUY4OOVVsuLvioELKt5JHwx5oADllUevxdA6K-9vddx7tuhgvkBvL1TpSp0XxDGwH3dRJDFwcDl3ah_PaOAjc33Z2IlcnXynaERtl3ysxBoPSY_4KPn5NoWQ7YHxzA-zQMKaa9fpi2VLN8Ud8redK0EKc9WwKXp-zmJbCf-KBsVCbFcrj9WUz38x-Iv-JEwFnUVpfTporFsB2eYlAPaMrXbf4Vz-Um1nfSVuq0F1V4cCPtZK6I_H-KWLbIseWZxNTJCWlmCaBe7ZQgt8ICUXqspyD9OOU6VNfr0nU7aW0itJEnvmKSfxnj3wQhrmEJ7HsX8mRHaDqAQKCr5B8YT4FOqTISRnTgDsV16ZRp43TaWH4QFpeanUD3KvmpvvfYGXUKVHlud2dUwPCr5FNM1QRFG9cgMBJn3y7ewbuixmPAIU_se3fYA1nYBtMlPpSHMGfXsqrIlMGNXmwsTs7TjG-kLzFrSA2ku5ZFX6N4wQim45hr1fBHI3GDF7IwoHKVCjXLjrkdCOGW0mV-n5uOAJxu5r_Ire3WFys0V9nlPpp9vy40PaNbXTiO0bLZu2u7LVDKAmxvvHxpUZxtW6v5lzoJjhdy1j4yAYCSgctwmH1pwhe8-wzU3JU9Rt1LFTs9t0XRUq_HXAb2kTGBMvk4OuuE1huBo75zhmFb1DVTzjr3Lpx656PZNk_frJiwupQ3qQj7b77ud_OzWgmRcLfmV2HPratlaB7pHQy6srJX-z2So9VD6TdbUUuOlSoGmK6jd1aGMNyhc2SM99TMQsQwbMEpZQ5tkexBf3Yc2TzQKON23R6xP90ctuAD976TtM2mZhV8o_7oB8jY9pyNwyf4tRUz0TPGIWBGgv3XhPugBTB5gfkRWXRvmeA2-Q38To85FnGpZib0yhVqpfS1ol9fZ6qmGQtgN5iZkXceAhYJRBwIq3jZM5-9Kc4QUO4aW4V8P7OXY66kxtcaoxXFcaug_EXomyGVhvLJ99QDE1zxTfZZ99Z7ZbAhYKQhctP43NCx3WPN4P0dP4HOG1HDhCW4wFOdWTKXQOKA1wOhuGUGyxpi6DcnMkM-vCpbWfHNzeSOKOXkBHbKycZiQ13mAv-eKpd0wg15sgkX3XdzHu8Xxc8HqDxsdJoyK0kT9lA8Y8PpF03mwhSqmOpxM4RjLL5U6HSt4FxDSsdVoTr3bzlKplWA29yVjlOU9D0xcbp9_Vkb981glTcmIhmpkP-10LD88arU_kHIkv_Oprhm-sCnNgI0RzmH71j5RxUuJDEKvj-l9A3f4lLEudcJw8ZBe_y7voD2-wNJ55hB5hYjzX45A5JCGbh7bE45bdq-hZ7a5rHekQAKMe1YO0zRzrkUagXurtqAXrZcLAq6NREGetDb8ICCJWA9fYoBWwz1mIBzn0fXUZlPRST-N7btljgD9RqiScsTA5NmGVG63cFq7JR7q0Na6eXVAKBODjcF6pMa4LIExSQq6W8CgXnfmGGTQp7p48TR0wan6nvSCOaaqty0hnELs2AkOb3otvg3T8ISPj36kApd3M5NcOrxW87LV7WEaN2Xy3aHkhxhZNMhAWHAtQpeg66rIsBat_Enqw56zTnSdjbKAAM7_mda7iQg5QEHKPSxkN4J2dAwzG-XmWTQJZhhxkAG0PDpN0sZkXRORxQV9TRBGmXWarK_GWkw2oAFFtf4H2d1KxlNiNQ6t0_6tWvN5piuPQTPhkIDmbSpbELp_sxYPdp2EBGN_08JbukeZ7P7M-eC4ps1e3mU1-l5j53tc1pYmauqc16J7ulQUe4WTMNWBBg3rBKdnR_E2wWMsirHhRHw8PZwTMmczbHVLAg6TX_RAafz-OOPaqrq2B_m-teT_-89rMWmrhIDnZMUTKPNQiInT0KPqZhZ981yZqkcKPKtJ2wYtliN6DE-GfubhjhCeNEoijF5wx6CruwB8F68SqANak21pj6LFT-gUdVI0S40PGAG87FelsPUVVrOmQJjoLgeE_zaHi684rPgknZbKW9PI-w5DhXfqqwn-8Nw3zanwa9aQ6TNzmZ_3hExa3yn7E4YrGvQFNz2EcpvBmOLl_7aU6OB_ofPFc8xGgwWm2vQQnj2XIMW15AdD9Jw9C63LIfsBd9krF1v9SzmDHVe4C2yRjGoNmaHCpXmzGcCdKKYkLRIVR6jclh5-fs5rU0L4hQC9LjQoS946Dlt731DBShTzh-pzwFn3TwmCOzTw03px_cwGXubDcbV9UP3WwJ5lbmaa9Sb2LLyQ2CE4aDrNeQvIDjnCzkWVHdHDkcTpnaYZCGjOcpf1jcK6lEDN2DKxEosgVM_sR0wg1rKTsm-i_K3Q_ByyYGooRCNv8xTd2mD2YM7AeucLEXDJyNFu5GGjommw8Pm2iq_Y0WyXkkch-PUAnlaDhunHhi0e22faVzG3jfHfy77aArXiWekmRbWwMcWesUVGTP2MMLOSwdbvF4h2Ww84U-V2ez9DHVTjTeN88C9BbAbwVbK5QSLcmAEK89GdSgss4VOI71f-mWih_oAjkMinFQuWW6K2OCrB95lp4SUBlNPOClNOChG1OoRWmbXiejGW8LPIoNK84FsccgEOtk05kjng11Wszj8JTt049ip7xgs1JeFZnazDT0WBzkabPxEEgz1KrZJj7OKqPT3yHtxgZ-NOfXg0AvdJuThwuvKsrQwkQ12AuUDDiODLZtWuBP23Z8wp-IqySHGpC5yrcZkWVBF58n7gSTXcpjsPStPYIXzxmouuRTSujRUcPE3tVgdDoh1jZLZKEOO-z2PWHom508mFbioDC6gluzv9bEv9SyJQcblMbaRR1W7CbvU1W_w6j8wqUVf_ZT3j4zY7CHoSD6AkOrSITmK1nFoivUmZ56LI7ENM34H45TskDgrwV31Jfm9zbnihQ-RTKUrAxRYwCF-5VsoBParjjuJ6qoExAEPXn1Y-yYt6QC29baQVK1lcwuMt05y--cTx0xpDwsLqUki9q6MYQvFAg0toEyW_VNuCJCo8Chsp2VHgG3eNBTfwbQ2M6ipHcldDd5OaEJZmzk6phdbFbaGo8xCJ8PUqiQr3yd5hommaM3W7JgNvUHPif0q8olUK5um-qzUCBSizSzoigdv2vsduE6acPFaHw7I1E4ycTrB1W8FyEsWlMhzofReeoQLmnH0o8IEeGrWMFdrRe5yDw5BjixK_daKBK2REC7mctNl_nx-_DAsgoBjZWYn2cTN0f9nraM0p2PibFqLcOLo-prjcdirllamEIVCSKlgQeBs9VlS5gEFMknLEzeCjkHB3ZQvyo-7VO6N4cDAnSQ_QwZLwIzXZ1Zp1vx5Tc1J8foMb6DP8QU-v4lho48Ac8Pa7PSUTQX-ta3nukBreTGlqmYveL6zBK-K53rHPiZBcn4P3iJ89xCy41LZe6IeUMMejp_65uVSzwMEo1enpzEgFrECaZwt2WezJITOfy0A3VrIdMsGwerm9qpUbOcnxfpBIjkblJHyQ_L8Gdw0uhpQHR44HA4yRKHCsKPP9-J6OP9OakZ_a7kzdhfr8DHNwBb82CG5NCAoQf_i8rD1dImQjOHixPXIITj8NZbnxiUzAYoXBNTqqRsNp4qtd2oQ7mEjTlpIr2w1vm_rTmlfy2zYwL9nRpgkkgVSvhdUJXL052VHDEtyvks3AxxmU5Bx5KqriIzPEK3aLc5whMVpUKjGNPDXC00kCeUmWLaoO3r-9rOAcWJJR6XLN9MrJLiM05E5D1OITRlXIAF4WE31ttkG1v77lpn-VvFtPdYFWfHUVY3dE8ZllQdIjo861QQqxoWgYJYKerDERrtrb_A_oCP-g-iXHNejenr5vCXx5jfOpKfJrFt5mP1w8m-lQe0Nfi_faieqwIT1YypW-DaemCGAI3-CylaoM4qlL9U_mT1qVVkaPgTwoqYeY40W39N0_q4rk3I88HRsUBlCDp6nshfF92Q5pTCnFGDyVJYsBX93qiSvMZiOus2XlNrLF5tVzXP3wwFrmaXi6fRtrJNuq-9-oQWeernrWCP8ArOu2MLcZ81KpGOrVxXmyZt_BEo2UFayEXdVsrS32X76fDPTt7Oxj0iBKWXOcFX9fk0KHWAmaljnnC9pa0qJfR7gHiHFAV3P_RW8IkJNp8QxyVkmFWaFKRAmKTfiaAspbX8qqSiARmUhObJnsWRM6Nhj81GofbF0t15g1NuyZFNm49RCm6ARybWkucUCKqvsVftiKL6uQnVzp30Nx4HZoxWCOd_Viy6cq_E26_ObCN6rHD1v-xjdYKGrtfwHyT3KyZoIBxo0i_H-krjbWpAPn4PNCeEiejKGmkl2ZZDqrap1dE_-BLXtJ1t2BpB2jzAOnyW4Am4P0ELyT37D1JTLZacrrVn9gCdCle3LxbPm3N-3UBPU0g32Knp8ldD9wYVFRY3hDfIoUH7zPm217Q810oRTysntF8TKqtHlNn3cGp1n7iv9zTgS-E2GlFBuPlRM2QtxB3uOYoFE6dl5m8Hcf5ltUeZ9etbogBg3aqcIiCmgOZQqQ9C9QEIHkHLLaaR3eLGPy4Wel1ghGin2DLSaGM-gGSe0nEJdbyj2ctO41r65Xm24uhLxB29vFtcVlJszQedMmN3oifoGwUr0U-E6mAuuN0QfA3-XIn0G7bm6_bBB1fOLN-YTfl2cj1RdEweiQL5rFV7VQ5j_51-UdNZT70PjZab7qovXoYnPmX3NQEqgqq4QilQqrkhVDEZ-oZKZ0CKNa03vESEgCXTdeWmH4AZk-jU0aHK_wyfTmKHltA4VZPDERflMDVpkmZm6BnGACnQo7QmijENqr68fr6YjbrndRTSwungUCxEoZeyqcEJUGhnfn4yJWRb82YvXFkLry-hF7iw_wzGqo4QOhRlVdOWbqMO5Kt_0EOKKWtVARQYr96Y32pzw_Shb2NwotT5xpA2kPZoET2EDdobaAtVAV8h2e7ctCN3pCD-nzd50A0udREP0hl3Hl8L-j28gsEeDETXvfC4PRuZiyJU6F_ac_Qqvu-_wNtuWn_cId5nVbf-hg6YaOi9nAKuQGnlCFMhf1RfDs-Rqegqwvhs9HrXufQUbKpe9DOM4aeW05iSANWB6a3vhaaVJkMdsDc0rrpfQHJJkMht7Mq865810g==', - provider_name='openai', - ), + ThinkingPart(content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6'), + ThinkingPart(content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6'), + ThinkingPart(content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6'), + ThinkingPart(content=IsStr(), id='rs_68c42d29124881968e24c1ca8c1fc7860e8bc41441c948f6'), ToolCallPart( tool_name='update_plan', args=IsStr(), @@ -2780,9 +2690,9 @@ async def test_openai_responses_thinking_with_multiple_summaries(allow_model_req ModelResponse( parts=[ ThinkingPart(content='1', id='rs_123', signature='123', provider_name='openai'), - ThinkingPart(content='2', id='rs_123', signature='123', provider_name='openai'), - ThinkingPart(content='3', id='rs_123', signature='123', provider_name='openai'), - ThinkingPart(content='4', id='rs_123', signature='123', provider_name='openai'), + ThinkingPart(content='2', id='rs_123'), + ThinkingPart(content='3', id='rs_123'), + ThinkingPart(content='4', id='rs_123'), TextPart(content='4', id='msg_123'), ], model_name='gpt-4o-123', @@ -8064,20 +7974,8 @@ async def test_openai_responses_multiple_summaries(allow_model_requests: None): provider_name='openai', provider_details={'raw_content': ['Raw thinking step 1']}, ), - ThinkingPart( - content='Second summary', - id='rs_123', - signature='encrypted_sig', - provider_name='openai', - provider_details={'raw_content': ['Raw thinking step 1']}, - ), - ThinkingPart( - content='Third summary', - id='rs_123', - signature='encrypted_sig', - provider_name='openai', - provider_details={'raw_content': ['Raw thinking step 1']}, - ), + ThinkingPart(content='Second summary', id='rs_123'), + ThinkingPart(content='Third summary', id='rs_123'), TextPart(content='Done', id='msg_123'), ], model_name='gpt-4o-123', @@ -8333,13 +8231,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: provider_name='openai', provider_details={'raw_content': ['More raw thinking']}, ), - ThinkingPart( - content='Second summary', - id='rs_456', - signature='encrypted_sig_abc', - provider_name='openai', - provider_details={'raw_content': ['More raw thinking']}, - ), + ThinkingPart(content='Second summary', id='rs_456'), TextPart(content='9', id='msg_456'), ], model_name='gpt-4o-123', @@ -8404,13 +8296,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: provider_name='openai', provider_details={'raw_content': ['More raw thinking']}, ), - ThinkingPart( - content='Second summary', - id='rs_456', - signature='encrypted_sig_abc', - provider_name='openai', - provider_details={'raw_content': ['More raw thinking']}, - ), + ThinkingPart(content='Second summary', id='rs_456'), TextPart(content='9', id='msg_456'), ], model_name='gpt-4o-123', From aece3db6898c99193e1916dd50b4360822a1c184 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sat, 6 Dec 2025 12:48:19 -0500 Subject: [PATCH 20/25] coverage --- tests/models/test_openai.py | 35 ++++++++++++++++++++++++++++++ tests/models/test_openrouter.py | 34 +++++++++++++++++++++++++++++ tests/test_vercel_ai.py | 38 +++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/tests/models/test_openai.py b/tests/models/test_openai.py index 5406a165e7..9af4239e05 100644 --- a/tests/models/test_openai.py +++ b/tests/models/test_openai.py @@ -203,6 +203,41 @@ async def test_request_simple_usage(allow_model_requests: None): ) +async def test_response_with_created_timestamp_but_no_provider_details(allow_model_requests: None): + class MinimalOpenAIChatModel(OpenAIChatModel): + def _process_provider_details(self, response: chat.ChatCompletion) -> dict[str, Any] | None: + return None + + c = completion_message(ChatCompletionMessage(content='world', role='assistant')) + mock_client = MockOpenAI.create_mock(c) + m = MinimalOpenAIChatModel('gpt-4o', provider=OpenAIProvider(openai_client=mock_client)) + agent = Agent(m) + + result = await agent.run('hello') + assert result.output == 'world' + assert result.all_messages() == snapshot( + [ + ModelRequest( + parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsNow(tz=timezone.utc), + run_id=IsStr(), + ), + ModelResponse( + parts=[TextPart(content='world')], + model_name='gpt-4o-123', + timestamp=IsNow(tz=timezone.utc), + provider_name='openai', + provider_details={ + 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), + }, + provider_response_id='123', + finish_reason='stop', + run_id=IsStr(), + ), + ] + ) + + async def test_openai_chat_image_detail_vendor_metadata(allow_model_requests: None): c = completion_message( ChatCompletionMessage(content='done', role='assistant'), diff --git a/tests/models/test_openrouter.py b/tests/models/test_openrouter.py index c5c1bb1d5d..c793cba302 100644 --- a/tests/models/test_openrouter.py +++ b/tests/models/test_openrouter.py @@ -341,6 +341,40 @@ async def test_openrouter_validate_error_response(openrouter_api_key: str) -> No ) +async def test_openrouter_with_provider_details_but_no_parent_details(openrouter_api_key: str) -> None: + from typing import Any + + class TestOpenRouterModel(OpenRouterModel): + def _process_provider_details(self, response: ChatCompletion) -> dict[str, Any] | None: + from pydantic_ai.models.openrouter import ( + _map_openrouter_provider_details, # pyright: ignore[reportPrivateUsage] + _OpenRouterChatCompletion, # pyright: ignore[reportPrivateUsage] + ) + + assert isinstance(response, _OpenRouterChatCompletion) + openrouter_details = _map_openrouter_provider_details(response) + return openrouter_details or None + + provider = OpenRouterProvider(api_key=openrouter_api_key) + model = TestOpenRouterModel('google/gemini-2.0-flash-exp:free', provider=provider) + + choice = Choice.model_construct( + index=0, message={'role': 'assistant', 'content': 'test'}, finish_reason='stop', native_finish_reason='stop' + ) + response = ChatCompletion.model_construct( + id='test', choices=[choice], created=1704067200, object='chat.completion', model='test', provider='TestProvider' + ) + result = model._process_response(response) # type: ignore[reportPrivateUsage] + + assert result.provider_details == snapshot( + { + 'downstream_provider': 'TestProvider', + 'finish_reason': 'stop', + 'timestamp': datetime.datetime(2024, 1, 1, 0, 0, tzinfo=datetime.timezone.utc), + } + ) + + async def test_openrouter_map_messages_reasoning(allow_model_requests: None, openrouter_api_key: str) -> None: provider = OpenRouterProvider(api_key=openrouter_api_key) model = OpenRouterModel('anthropic/claude-3.7-sonnet:thinking', provider=provider) diff --git a/tests/test_vercel_ai.py b/tests/test_vercel_ai.py index bec755f188..33a7b27269 100644 --- a/tests/test_vercel_ai.py +++ b/tests/test_vercel_ai.py @@ -2526,6 +2526,44 @@ def sync_timestamps(original: list[ModelRequest | ModelResponse], new: list[Mode assert reloaded_messages == original_messages +async def test_adapter_dump_load_roundtrip_without_timestamps(): + """Test that dump_messages and load_messages work when messages don't have timestamps.""" + original_messages = [ + ModelRequest( + parts=[ + UserPromptPart(content='User message'), + ] + ), + ModelResponse( + parts=[ + TextPart(content='Response text'), + ] + ), + ] + + for msg in original_messages: + delattr(msg, 'timestamp') + + ui_messages = VercelAIAdapter.dump_messages(original_messages) + reloaded_messages = VercelAIAdapter.load_messages(ui_messages) + + def sync_timestamps(original: list[ModelRequest | ModelResponse], new: list[ModelRequest | ModelResponse]) -> None: + for orig_msg, new_msg in zip(original, new): + for orig_part, new_part in zip(orig_msg.parts, new_msg.parts): + if hasattr(orig_part, 'timestamp') and hasattr(new_part, 'timestamp'): + new_part.timestamp = orig_part.timestamp # pyright: ignore[reportAttributeAccessIssue, reportUnknownMemberType] + if hasattr(orig_msg, 'timestamp') and hasattr(new_msg, 'timestamp'): + new_msg.timestamp = orig_msg.timestamp # pyright: ignore[reportAttributeAccessIssue] + + sync_timestamps(original_messages, reloaded_messages) + + for msg in reloaded_messages: + if hasattr(msg, 'timestamp'): + delattr(msg, 'timestamp') + + assert len(reloaded_messages) == len(original_messages) + + async def test_adapter_dump_messages_text_before_thinking(): """Test dumping messages where text precedes a thinking part.""" messages = [ From 15e3528aefca930b76ee056ef8e105d11fe49c75 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:39:12 -0500 Subject: [PATCH 21/25] coverage --- pydantic_ai_slim/pydantic_ai/models/openrouter.py | 7 ++----- tests/test_vercel_ai.py | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/models/openrouter.py b/pydantic_ai_slim/pydantic_ai/models/openrouter.py index 516ca61f76..190b788cab 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openrouter.py +++ b/pydantic_ai_slim/pydantic_ai/models/openrouter.py @@ -570,11 +570,8 @@ def _process_provider_details(self, response: chat.ChatCompletion) -> dict[str, assert isinstance(response, _OpenRouterChatCompletion) provider_details = super()._process_provider_details(response) - openrouter_details = _map_openrouter_provider_details(response) - if openrouter_details: - if provider_details is None: - provider_details = {} - provider_details.update(openrouter_details) + if openrouter_details := _map_openrouter_provider_details(response): + provider_details = {**(provider_details or {}), **openrouter_details} return provider_details or None @dataclass diff --git a/tests/test_vercel_ai.py b/tests/test_vercel_ai.py index 33a7b27269..6ef5f5c5fe 100644 --- a/tests/test_vercel_ai.py +++ b/tests/test_vercel_ai.py @@ -2516,7 +2516,7 @@ def sync_timestamps(original: list[ModelRequest | ModelResponse], new: list[Mode for orig_part, new_part in zip(orig_msg.parts, new_msg.parts): if hasattr(orig_part, 'timestamp') and hasattr(new_part, 'timestamp'): new_part.timestamp = orig_part.timestamp # pyright: ignore[reportAttributeAccessIssue, reportUnknownMemberType] - if hasattr(orig_msg, 'timestamp') and hasattr(new_msg, 'timestamp'): + if hasattr(orig_msg, 'timestamp') and hasattr(new_msg, 'timestamp'): # pragma: no branch new_msg.timestamp = orig_msg.timestamp # pyright: ignore[reportAttributeAccessIssue] # Load back to Pydantic AI format @@ -2558,7 +2558,7 @@ def sync_timestamps(original: list[ModelRequest | ModelResponse], new: list[Mode sync_timestamps(original_messages, reloaded_messages) for msg in reloaded_messages: - if hasattr(msg, 'timestamp'): + if hasattr(msg, 'timestamp'): # pragma: no branch delattr(msg, 'timestamp') assert len(reloaded_messages) == len(original_messages) From 2c4d0acf00f4ec8f5283909c072b96f8997419be Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sun, 7 Dec 2025 19:31:26 -0500 Subject: [PATCH 22/25] coverage --- tests/models/test_openrouter.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/models/test_openrouter.py b/tests/models/test_openrouter.py index c793cba302..acad3003ef 100644 --- a/tests/models/test_openrouter.py +++ b/tests/models/test_openrouter.py @@ -481,6 +481,29 @@ async def test_openrouter_streaming_reasoning(allow_model_requests: None, openro ) +async def test_openrouter_no_openrouter_details(openrouter_api_key: str) -> None: + """Test _process_provider_details when _map_openrouter_provider_details returns empty dict.""" + from unittest.mock import patch + + provider = OpenRouterProvider(api_key=openrouter_api_key) + model = OpenRouterModel('google/gemini-2.0-flash-exp:free', provider=provider) + + choice = Choice.model_construct( + index=0, message={'role': 'assistant', 'content': 'test'}, finish_reason='stop', native_finish_reason='stop' + ) + response = ChatCompletion.model_construct( + id='test', choices=[choice], created=1704067200, object='chat.completion', model='test', provider='TestProvider' + ) + + with patch('pydantic_ai.models.openrouter._map_openrouter_provider_details', return_value={}): + result = model._process_response(response) # type: ignore[reportPrivateUsage] + + # With empty openrouter_details, we should still get the parent's provider_details (timestamp + finish_reason) + assert result.provider_details == snapshot( + {'finish_reason': 'stop', 'timestamp': datetime.datetime(2024, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)} + ) + + async def test_openrouter_google_nested_schema(allow_model_requests: None, openrouter_api_key: str) -> None: """Test that nested schemas with $defs/$ref work correctly with OpenRouter + Gemini. From 454b523ed4107657cf77161fc0cad4f80b890583 Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Thu, 11 Dec 2025 09:14:59 -0500 Subject: [PATCH 23/25] address review comments --- pydantic_ai_slim/pydantic_ai/_a2a.py | 5 +---- pydantic_ai_slim/pydantic_ai/_mcp.py | 6 +++--- pydantic_ai_slim/pydantic_ai/messages.py | 2 ++ pydantic_ai_slim/pydantic_ai/models/anthropic.py | 1 - pydantic_ai_slim/pydantic_ai/models/google.py | 1 - pydantic_ai_slim/pydantic_ai/models/groq.py | 8 +++----- .../pydantic_ai/models/huggingface.py | 13 ++++++------- pydantic_ai_slim/pydantic_ai/models/mistral.py | 9 +++------ pydantic_ai_slim/pydantic_ai/models/openai.py | 15 ++++++++------- pydantic_ai_slim/pydantic_ai/models/outlines.py | 1 - .../pydantic_ai/ui/_messages_builder.py | 4 ++-- tests/models/test_google.py | 2 ++ 12 files changed, 30 insertions(+), 37 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/_a2a.py b/pydantic_ai_slim/pydantic_ai/_a2a.py index 77a07e935f..eee3832b1b 100644 --- a/pydantic_ai_slim/pydantic_ai/_a2a.py +++ b/pydantic_ai_slim/pydantic_ai/_a2a.py @@ -25,7 +25,6 @@ ToolCallPart, UserPromptPart, VideoUrl, - _utils, ) from .agent import AbstractAgent, AgentDepsT, OutputDataT @@ -201,9 +200,7 @@ def build_message_history(self, history: list[Message]) -> list[ModelMessage]: model_messages: list[ModelMessage] = [] for message in history: if message['role'] == 'user': - model_messages.append( - ModelRequest(parts=self._request_parts_from_a2a(message['parts']), timestamp=_utils.now_utc()) - ) + model_messages.append(ModelRequest(parts=self._request_parts_from_a2a(message['parts']))) else: model_messages.append(ModelResponse(parts=self._response_parts_from_a2a(message['parts']))) return model_messages diff --git a/pydantic_ai_slim/pydantic_ai/_mcp.py b/pydantic_ai_slim/pydantic_ai/_mcp.py index 2e2bd69b72..1729e4c225 100644 --- a/pydantic_ai_slim/pydantic_ai/_mcp.py +++ b/pydantic_ai_slim/pydantic_ai/_mcp.py @@ -4,7 +4,7 @@ from collections.abc import Sequence from typing import Literal -from . import _utils, exceptions, messages +from . import exceptions, messages try: from mcp import types as mcp_types @@ -44,7 +44,7 @@ def map_from_mcp_params(params: mcp_types.CreateMessageRequestParams) -> list[me # role is assistant # if there are any request parts, add a request message wrapping them if request_parts: - pai_messages.append(messages.ModelRequest(parts=request_parts, timestamp=_utils.now_utc())) + pai_messages.append(messages.ModelRequest(parts=request_parts)) request_parts = [] response_parts.append(map_from_sampling_content(content)) @@ -52,7 +52,7 @@ def map_from_mcp_params(params: mcp_types.CreateMessageRequestParams) -> list[me if response_parts: pai_messages.append(messages.ModelResponse(parts=response_parts)) if request_parts: - pai_messages.append(messages.ModelRequest(parts=request_parts, timestamp=_utils.now_utc())) + pai_messages.append(messages.ModelRequest(parts=request_parts)) return pai_messages diff --git a/pydantic_ai_slim/pydantic_ai/messages.py b/pydantic_ai_slim/pydantic_ai/messages.py index da63d436fe..e0a1da744e 100644 --- a/pydantic_ai_slim/pydantic_ai/messages.py +++ b/pydantic_ai_slim/pydantic_ai/messages.py @@ -1001,6 +1001,8 @@ class ModelRequest: _: KW_ONLY + # Default is None for backwards compatibility with old serialized messages that don't have this field. + # Using a default_factory would incorrectly fill in the current time for deserialized historical messages. timestamp: datetime | None = None """The timestamp when the request was sent to the model.""" diff --git a/pydantic_ai_slim/pydantic_ai/models/anthropic.py b/pydantic_ai_slim/pydantic_ai/models/anthropic.py index 0c0aa7e1e1..808a2f00f9 100644 --- a/pydantic_ai_slim/pydantic_ai/models/anthropic.py +++ b/pydantic_ai_slim/pydantic_ai/models/anthropic.py @@ -559,7 +559,6 @@ def _process_response(self, response: BetaMessage) -> ModelResponse: parts=items, usage=_map_usage(response, self._provider.name, self._provider.base_url, self._model_name), model_name=response.model, - timestamp=_utils.now_utc(), provider_response_id=response.id, provider_name=self._provider.name, provider_url=self._provider.base_url, diff --git a/pydantic_ai_slim/pydantic_ai/models/google.py b/pydantic_ai_slim/pydantic_ai/models/google.py index 3c05cd05f8..d05fc5f1ef 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -950,7 +950,6 @@ def _process_response_from_parts( return ModelResponse( parts=items, model_name=model_name, - timestamp=_utils.now_utc(), usage=usage, provider_response_id=vendor_id, provider_details=vendor_details, diff --git a/pydantic_ai_slim/pydantic_ai/models/groq.py b/pydantic_ai_slim/pydantic_ai/models/groq.py index 398690126f..a3d1697f4c 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -207,7 +207,6 @@ async def request( return ModelResponse( parts=[tool_call_part], model_name=e.model_name, - timestamp=_utils.now_utc(), provider_name=self._provider.name, provider_url=self.base_url, finish_reason='error', @@ -348,7 +347,6 @@ def _process_response(self, response: chat.ChatCompletion) -> ModelResponse: parts=items, usage=_map_usage(response), model_name=response.model, - timestamp=_utils.now_utc(), provider_response_id=response.id, provider_name=self._provider.name, provider_url=self.base_url, @@ -374,7 +372,7 @@ async def _process_streamed_response( _model_profile=self.profile, _provider_name=self._provider.name, _provider_url=self.base_url, - _provider_timestamp=first_chunk.created, + _provider_timestamp=number_to_datetime(first_chunk.created) if first_chunk.created else None, ) def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[chat.ChatCompletionToolParam]: @@ -528,7 +526,7 @@ class GroqStreamedResponse(StreamedResponse): _response: AsyncIterable[chat.ChatCompletionChunk] _provider_name: str _provider_url: str - _provider_timestamp: int | None = None + _provider_timestamp: datetime | None = None _timestamp: datetime = field(default_factory=_utils.now_utc) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: # noqa: C901 @@ -552,7 +550,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: provider_details_dict['finish_reason'] = raw_finish_reason self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) if self._provider_timestamp is not None: # pragma: no branch - provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) + provider_details_dict['timestamp'] = self._provider_timestamp if provider_details_dict: # pragma: no branch self.provider_details = provider_details_dict diff --git a/pydantic_ai_slim/pydantic_ai/models/huggingface.py b/pydantic_ai_slim/pydantic_ai/models/huggingface.py index a2b6630c3a..7c71139c88 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -11,7 +11,7 @@ from .. import ModelHTTPError, UnexpectedModelBehavior, _utils, usage from .._run_context import RunContext from .._thinking_part import split_content_into_text_and_thinking -from .._utils import guard_tool_call_id as _guard_tool_call_id, now_utc as _now_utc +from .._utils import guard_tool_call_id as _guard_tool_call_id from ..exceptions import UserError from ..messages import ( AudioUrl, @@ -272,8 +272,6 @@ async def _completions_create( def _process_response(self, response: ChatCompletionOutput) -> ModelResponse: """Process a non-streamed response, and prepare a message to return.""" - timestamp = _now_utc() - choice = response.choices[0] content = choice.message.content tool_calls = choice.message.tool_calls @@ -296,7 +294,6 @@ def _process_response(self, response: ChatCompletionOutput) -> ModelResponse: parts=items, usage=_map_usage(response), model_name=response.model, - timestamp=timestamp, provider_response_id=response.id, provider_name=self._provider.name, provider_url=self.base_url, @@ -322,7 +319,9 @@ async def _process_streamed_response( _response=peekable_response, _provider_name=self._provider.name, _provider_url=self.base_url, - _provider_timestamp=first_chunk.created, + _provider_timestamp=datetime.fromtimestamp(first_chunk.created, tz=timezone.utc) + if first_chunk.created + else None, ) def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[ChatCompletionInputTool]: @@ -471,7 +470,7 @@ class HuggingFaceStreamedResponse(StreamedResponse): _response: AsyncIterable[ChatCompletionStreamOutput] _provider_name: str _provider_url: str - _provider_timestamp: int | None = None + _provider_timestamp: datetime | None = None _timestamp: datetime = field(default_factory=_utils.now_utc) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: @@ -493,7 +492,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: cast(TextGenerationOutputFinishReason, raw_finish_reason), None ) if self._provider_timestamp is not None: # pragma: no branch - provider_details_dict['timestamp'] = datetime.fromtimestamp(self._provider_timestamp, tz=timezone.utc) + provider_details_dict['timestamp'] = self._provider_timestamp if provider_details_dict: # pragma: no branch self.provider_details = provider_details_dict diff --git a/pydantic_ai_slim/pydantic_ai/models/mistral.py b/pydantic_ai_slim/pydantic_ai/models/mistral.py index 3c5be3f99e..6f6c196048 100644 --- a/pydantic_ai_slim/pydantic_ai/models/mistral.py +++ b/pydantic_ai_slim/pydantic_ai/models/mistral.py @@ -348,8 +348,6 @@ def _process_response(self, response: MistralChatCompletionResponse) -> ModelRes """Process a non-streamed response, and prepare a message to return.""" assert response.choices, 'Unexpected empty response choice.' - timestamp = _now_utc() - choice = response.choices[0] content = choice.message.content tool_calls = choice.message.tool_calls @@ -376,7 +374,6 @@ def _process_response(self, response: MistralChatCompletionResponse) -> ModelRes parts=parts, usage=_map_usage(response), model_name=response.model, - timestamp=timestamp, provider_response_id=response.id, provider_name=self._provider.name, provider_url=self._provider.base_url, @@ -403,7 +400,7 @@ async def _process_streamed_response( _model_name=first_chunk.data.model, _provider_name=self._provider.name, _provider_url=self._provider.base_url, - _provider_timestamp=first_chunk.data.created, + _provider_timestamp=number_to_datetime(first_chunk.data.created) if first_chunk.data.created else None, ) @staticmethod @@ -611,7 +608,7 @@ class MistralStreamedResponse(StreamedResponse): _response: AsyncIterable[MistralCompletionEvent] _provider_name: str _provider_url: str - _provider_timestamp: int | None = None + _provider_timestamp: datetime | None = None _timestamp: datetime = field(default_factory=_now_utc) _delta_content: str = field(default='', init=False) @@ -634,7 +631,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: provider_details_dict['finish_reason'] = raw_finish_reason self.finish_reason = _FINISH_REASON_MAP.get(raw_finish_reason) if self._provider_timestamp is not None: # pragma: no branch - provider_details_dict['timestamp'] = number_to_datetime(self._provider_timestamp) + provider_details_dict['timestamp'] = self._provider_timestamp if provider_details_dict: # pragma: no branch self.provider_details = provider_details_dict diff --git a/pydantic_ai_slim/pydantic_ai/models/openai.py b/pydantic_ai_slim/pydantic_ai/models/openai.py index e7068e0b95..d62c18eb33 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -720,7 +720,7 @@ async def _process_streamed_response( _response=peekable_response, _provider_name=self._provider.name, _provider_url=self._provider.base_url, - _provider_timestamp=first_chunk.created, + _provider_timestamp=number_to_datetime(first_chunk.created) if first_chunk.created else None, ) @property @@ -1315,8 +1315,9 @@ async def _process_streamed_response( _response=peekable_response, _provider_name=self._provider.name, _provider_url=self._provider.base_url, - # type of created_at is float but it's actually a Unix timestamp in seconds - _provider_timestamp=int(first_chunk.response.created_at), + _provider_timestamp=number_to_datetime(first_chunk.response.created_at) + if first_chunk.response.created_at + else None, ) @overload @@ -1927,7 +1928,7 @@ class OpenAIStreamedResponse(StreamedResponse): _response: AsyncIterable[ChatCompletionChunk] _provider_name: str _provider_url: str - _provider_timestamp: int | None = None + _provider_timestamp: datetime | None = None _timestamp: datetime = field(default_factory=_now_utc) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: @@ -2049,7 +2050,7 @@ def _map_provider_details(self, chunk: ChatCompletionChunk) -> dict[str, Any] | if self._provider_timestamp is not None: # pragma: no branch if provider_details is None: provider_details = {} - provider_details['timestamp'] = number_to_datetime(self._provider_timestamp) + provider_details['timestamp'] = self._provider_timestamp return provider_details or None def _map_usage(self, response: ChatCompletionChunk) -> usage.RequestUsage: @@ -2093,7 +2094,7 @@ class OpenAIResponsesStreamedResponse(StreamedResponse): _response: AsyncIterable[responses.ResponseStreamEvent] _provider_name: str _provider_url: str - _provider_timestamp: int | None = None + _provider_timestamp: datetime | None = None _timestamp: datetime = field(default_factory=_now_utc) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: # noqa: C901 @@ -2110,7 +2111,7 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: provider_details['finish_reason'] = raw_finish_reason self.finish_reason = _RESPONSES_FINISH_REASON_MAP.get(raw_finish_reason) if self._provider_timestamp is not None: # pragma: no branch - provider_details['timestamp'] = number_to_datetime(self._provider_timestamp) + provider_details['timestamp'] = self._provider_timestamp self.provider_details = provider_details or None elif isinstance(chunk, responses.ResponseContentPartAddedEvent): diff --git a/pydantic_ai_slim/pydantic_ai/models/outlines.py b/pydantic_ai_slim/pydantic_ai/models/outlines.py index 9cde3e2f2c..c071426d0e 100644 --- a/pydantic_ai_slim/pydantic_ai/models/outlines.py +++ b/pydantic_ai_slim/pydantic_ai/models/outlines.py @@ -507,7 +507,6 @@ def _process_response(self, response: str) -> ModelResponse: parts=cast( list[ModelResponsePart], split_content_into_text_and_thinking(response, self.profile.thinking_tags) ), - timestamp=_utils.now_utc(), ) async def _process_streamed_response( diff --git a/pydantic_ai_slim/pydantic_ai/ui/_messages_builder.py b/pydantic_ai_slim/pydantic_ai/ui/_messages_builder.py index 5d9207c318..6a2edf1715 100644 --- a/pydantic_ai_slim/pydantic_ai/ui/_messages_builder.py +++ b/pydantic_ai_slim/pydantic_ai/ui/_messages_builder.py @@ -1,7 +1,7 @@ from dataclasses import dataclass, field from typing import cast -from pydantic_ai._utils import get_union_args, now_utc as _now_utc +from pydantic_ai._utils import get_union_args from pydantic_ai.messages import ModelMessage, ModelRequest, ModelRequestPart, ModelResponse, ModelResponsePart @@ -19,7 +19,7 @@ def add(self, part: ModelRequestPart | ModelResponsePart) -> None: if isinstance(last_message, ModelRequest): last_message.parts = [*last_message.parts, part] else: - self.messages.append(ModelRequest(parts=[part], timestamp=_now_utc())) + self.messages.append(ModelRequest(parts=[part])) else: part = cast(ModelResponsePart, part) if isinstance(last_message, ModelResponse): diff --git a/tests/models/test_google.py b/tests/models/test_google.py index 89ef584249..6d48d4e42e 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -4569,6 +4569,7 @@ def get_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4601,6 +4602,7 @@ def get_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( From e87ffed2bd14396638327c5fffcaa84f53e94b2d Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sat, 13 Dec 2025 20:27:53 -0500 Subject: [PATCH 24/25] redo snapshots --- tests/models/test_deepseek.py | 2 +- tests/models/test_openai.py | 1 + tests/models/test_openai_responses.py | 3 ++- tests/test_ag_ui.py | 9 +++----- tests/test_agent.py | 27 ++++++++++++++++++++-- tests/test_mcp.py | 3 +-- tests/test_vercel_ai.py | 33 +++++++++------------------ 7 files changed, 44 insertions(+), 34 deletions(-) diff --git a/tests/models/test_deepseek.py b/tests/models/test_deepseek.py index 204eb69daf..37c76d62b1 100644 --- a/tests/models/test_deepseek.py +++ b/tests/models/test_deepseek.py @@ -1,8 +1,8 @@ from __future__ import annotations as _annotations +from datetime import datetime, timezone import pytest -from datetime import datetime, timezone from inline_snapshot import snapshot from pydantic_ai import ( diff --git a/tests/models/test_openai.py b/tests/models/test_openai.py index 9af4239e05..b6599965bc 100644 --- a/tests/models/test_openai.py +++ b/tests/models/test_openai.py @@ -227,6 +227,7 @@ def _process_provider_details(self, response: chat.ChatCompletion) -> dict[str, model_name='gpt-4o-123', timestamp=IsNow(tz=timezone.utc), provider_name='openai', + provider_url='https://api.openai.com/v1', provider_details={ 'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), }, diff --git a/tests/models/test_openai_responses.py b/tests/models/test_openai_responses.py index a1457c10b9..16041fd003 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -1,10 +1,10 @@ import json import re from dataclasses import replace +from datetime import datetime, timezone from typing import Any, Literal, cast import pytest -from datetime import datetime, timezone from inline_snapshot import snapshot from pydantic import BaseModel from typing_extensions import TypedDict @@ -8461,6 +8461,7 @@ async def test_web_search_call_action_find_in_page(allow_model_requests: None): timestamp=IsDatetime(), provider_name='openai', provider_url='https://api.openai.com/v1', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ) diff --git a/tests/test_ag_ui.py b/tests/test_ag_ui.py index b678029abb..5cbf85fc69 100644 --- a/tests/test_ag_ui.py +++ b/tests/test_ag_ui.py @@ -6,7 +6,6 @@ import uuid from collections.abc import AsyncIterator, MutableMapping from dataclasses import dataclass -from datetime import timezone from http import HTTPStatus from typing import Any @@ -53,7 +52,7 @@ from pydantic_ai.output import OutputDataT from pydantic_ai.tools import AgentDepsT, ToolDefinition -from .conftest import IsDatetime, IsNow, IsSameStr, try_import +from .conftest import IsDatetime, IsSameStr, try_import with try_import() as imports_successful: from ag_ui.core import ( @@ -1526,8 +1525,7 @@ async def test_messages() -> None: content='User message', timestamp=IsDatetime(), ), - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[ @@ -1568,8 +1566,7 @@ async def test_messages() -> None: content='User message', timestamp=IsDatetime(), ), - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[TextPart(content='Assistant message')], diff --git a/tests/test_agent.py b/tests/test_agent.py index afb8c8a4b5..d932705a45 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -5,7 +5,7 @@ from collections import defaultdict from collections.abc import AsyncIterable, AsyncIterator, Callable from dataclasses import dataclass, replace -from datetime import timezone +from datetime import datetime, timezone from typing import Any, Generic, Literal, TypeVar, Union import httpx @@ -3057,6 +3057,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover [ ModelRequest( parts=[UserPromptPart(content='test early strategy', timestamp=IsNow(tz=timezone.utc))], + timestamp=datetime(2025, 12, 14, 1, 23, 55, 373757, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3098,6 +3099,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=datetime(2025, 12, 14, 1, 23, 55, 374266, tzinfo=timezone.utc), run_id=IsStr(), ), ] @@ -3149,6 +3151,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='test early output tools', timestamp=IsNow(tz=timezone.utc))], + timestamp=datetime(2025, 12, 14, 1, 23, 55, 499244, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3176,6 +3179,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=datetime(2025, 12, 14, 1, 23, 55, 499823, tzinfo=timezone.utc), run_id=IsStr(), ), ] @@ -3204,7 +3208,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: assert messages == snapshot( [ ModelRequest( - parts=[UserPromptPart(content='test exhaustive strategy', timestamp=IsNow(tz=timezone.utc))], + parts=[UserPromptPart(content='test multiple final results', timestamp=IsNow(tz=timezone.utc))], timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), @@ -3401,6 +3405,7 @@ def regular_tool(x: int) -> int: # pragma: no cover content='test early strategy with external tool call', timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=datetime(2025, 12, 14, 1, 23, 55, 875366, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3443,6 +3448,7 @@ def regular_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=datetime(2025, 12, 14, 1, 23, 55, 875908, tzinfo=timezone.utc), run_id=IsStr(), ), ] @@ -3494,6 +3500,7 @@ def regular_tool(x: int) -> int: content='test early strategy with deferred tool call', timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 2365, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3519,6 +3526,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 3120, tzinfo=timezone.utc), run_id=IsStr(), ), ] @@ -3550,6 +3558,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 133706, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3574,6 +3583,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 134396, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3598,6 +3608,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 134654, tzinfo=timezone.utc), run_id=IsStr(), ), ] @@ -3654,6 +3665,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover [ ModelRequest( parts=[UserPromptPart(content='test exhaustive strategy', timestamp=IsNow(tz=timezone.utc))], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 271681, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3710,6 +3722,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 272509, tzinfo=timezone.utc), run_id=IsStr(), ), ] @@ -3761,6 +3774,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='test exhaustive output tools', timestamp=IsNow(tz=timezone.utc))], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 398015, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3788,6 +3802,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 398704, tzinfo=timezone.utc), run_id=IsStr(), ), ] @@ -3839,6 +3854,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='test invalid first valid second', timestamp=IsNow(tz=timezone.utc))], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 522576, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3866,6 +3882,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 523271, tzinfo=timezone.utc), run_id=IsStr(), ), ] @@ -3918,6 +3935,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='test valid first invalid second', timestamp=IsNow(tz=timezone.utc))], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 647619, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3945,6 +3963,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 648370, tzinfo=timezone.utc), run_id=IsStr(), ), ] @@ -3997,6 +4016,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='test exhaustive with tool retry', timestamp=IsNow(tz=timezone.utc))], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 772011, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4024,6 +4044,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=datetime(2025, 12, 14, 1, 23, 56, 772697, tzinfo=timezone.utc), run_id=IsStr(), ), ] @@ -4079,6 +4100,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='test multiple final results', timestamp=IsNow(tz=timezone.utc))], + timestamp=datetime(2025, 12, 14, 1, 23, 57, 19952, tzinfo=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4113,6 +4135,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: tool_call_id='second', ), ], + timestamp=datetime(2025, 12, 14, 1, 23, 57, 20457, tzinfo=timezone.utc), run_id=IsStr(), ), ] diff --git a/tests/test_mcp.py b/tests/test_mcp.py index d021bb07c2..1de841e8f7 100644 --- a/tests/test_mcp.py +++ b/tests/test_mcp.py @@ -1635,8 +1635,7 @@ def test_map_from_mcp_params_model_request(): content=[BinaryContent(data=b'img', media_type='image/png', identifier='978ea7')], timestamp=IsNow(tz=timezone.utc), ), - ], - timestamp=IsNow(tz=timezone.utc), + ] ) ] ) diff --git a/tests/test_vercel_ai.py b/tests/test_vercel_ai.py index 6ef5f5c5fe..bfe43b00c5 100644 --- a/tests/test_vercel_ai.py +++ b/tests/test_vercel_ai.py @@ -2,7 +2,6 @@ import json from collections.abc import AsyncIterator, MutableMapping -from datetime import timezone from typing import Any, cast import pytest @@ -60,7 +59,7 @@ ) from pydantic_ai.ui.vercel_ai.response_types import BaseChunk, DataChunk -from .conftest import IsDatetime, IsNow, IsSameStr, IsStr, try_import +from .conftest import IsDatetime, IsSameStr, IsStr, try_import with try_import() as starlette_import_successful: from starlette.requests import Request @@ -185,8 +184,7 @@ async def test_run(allow_model_requests: None, openai_api_key: str): """, timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[ @@ -218,8 +216,7 @@ async def test_run(allow_model_requests: None, openai_api_key: str): content='Give me the ToCs', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[ @@ -240,8 +237,7 @@ async def test_run(allow_model_requests: None, openai_api_key: str): tool_call_id='toolu_01XX3rjFfG77h3KCbVHoYJMQ', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[ @@ -261,8 +257,7 @@ async def test_run(allow_model_requests: None, openai_api_key: str): tool_call_id='toolu_01W2yGpGQcMx7pXV2zZ4sz9g', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[ @@ -278,8 +273,7 @@ async def test_run(allow_model_requests: None, openai_api_key: str): content='How do I get FastAPI instrumentation to include the HTTP request and response', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ] ) @@ -1838,8 +1832,7 @@ async def test_adapter_load_messages(): ], timestamp=IsDatetime(), ), - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[ @@ -1855,8 +1848,7 @@ async def test_adapter_load_messages(): content='Give me the ToCs', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[ @@ -1877,8 +1869,7 @@ async def test_adapter_load_messages(): tool_call_id='toolu_01XX3rjFfG77h3KCbVHoYJMQ', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[ @@ -1898,8 +1889,7 @@ async def test_adapter_load_messages(): tool_call_id='toolu_01XX3rjFfG77h3KCbVHoY', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[ @@ -1919,8 +1909,7 @@ async def test_adapter_load_messages(): tool_call_id='toolu_01W2yGpGQcMx7pXV2zZ4sz9g', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[ From 38cb3dbc8267929839cf26ef486734f1c14ded3a Mon Sep 17 00:00:00 2001 From: David Sanchez <64162682+dsfaccini@users.noreply.github.com> Date: Sat, 13 Dec 2025 21:21:24 -0500 Subject: [PATCH 25/25] fix tests --- tests/models/test_gemini_vertex.py | 2 -- tests/test_agent.py | 48 +++++++++++++++--------------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/tests/models/test_gemini_vertex.py b/tests/models/test_gemini_vertex.py index 6471ca37ee..84175e1104 100644 --- a/tests/models/test_gemini_vertex.py +++ b/tests/models/test_gemini_vertex.py @@ -149,7 +149,6 @@ async def test_url_input( usage=IsInstance(RequestUsage), model_name='gemini-2.0-flash', timestamp=IsDatetime(), - provider_name='google-vertex', provider_url='https://us-central1-aiplatform.googleapis.com/v1/projects/pydantic-ai/locations/us-central1/publishers/google/models/', provider_details={'finish_reason': 'STOP'}, provider_response_id=IsStr(), @@ -191,7 +190,6 @@ async def test_url_input_force_download(allow_model_requests: None) -> None: # usage=IsInstance(RequestUsage), model_name='gemini-2.0-flash', timestamp=IsDatetime(), - provider_name='google-vertex', provider_url='https://us-central1-aiplatform.googleapis.com/v1/projects/pydantic-ai/locations/us-central1/publishers/google/models/', provider_details={'finish_reason': 'STOP'}, provider_response_id=IsStr(), diff --git a/tests/test_agent.py b/tests/test_agent.py index d932705a45..41b697d84e 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -5,7 +5,7 @@ from collections import defaultdict from collections.abc import AsyncIterable, AsyncIterator, Callable from dataclasses import dataclass, replace -from datetime import datetime, timezone +from datetime import timezone from typing import Any, Generic, Literal, TypeVar, Union import httpx @@ -3057,7 +3057,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover [ ModelRequest( parts=[UserPromptPart(content='test early strategy', timestamp=IsNow(tz=timezone.utc))], - timestamp=datetime(2025, 12, 14, 1, 23, 55, 373757, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3099,7 +3099,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=timezone.utc), ), ], - timestamp=datetime(2025, 12, 14, 1, 23, 55, 374266, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -3151,7 +3151,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='test early output tools', timestamp=IsNow(tz=timezone.utc))], - timestamp=datetime(2025, 12, 14, 1, 23, 55, 499244, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3179,7 +3179,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ), ], - timestamp=datetime(2025, 12, 14, 1, 23, 55, 499823, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -3405,7 +3405,7 @@ def regular_tool(x: int) -> int: # pragma: no cover content='test early strategy with external tool call', timestamp=IsNow(tz=timezone.utc) ) ], - timestamp=datetime(2025, 12, 14, 1, 23, 55, 875366, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3448,7 +3448,7 @@ def regular_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=timezone.utc), ), ], - timestamp=datetime(2025, 12, 14, 1, 23, 55, 875908, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -3500,7 +3500,7 @@ def regular_tool(x: int) -> int: content='test early strategy with deferred tool call', timestamp=IsNow(tz=timezone.utc) ) ], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 2365, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3526,7 +3526,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=timezone.utc), ) ], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 3120, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -3558,7 +3558,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=timezone.utc), ) ], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 133706, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3583,7 +3583,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=timezone.utc), ) ], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 134396, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3608,7 +3608,7 @@ def regular_tool(x: int) -> int: timestamp=IsNow(tz=timezone.utc), ) ], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 134654, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -3665,7 +3665,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover [ ModelRequest( parts=[UserPromptPart(content='test exhaustive strategy', timestamp=IsNow(tz=timezone.utc))], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 271681, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3722,7 +3722,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=timezone.utc), ), ], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 272509, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -3774,7 +3774,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='test exhaustive output tools', timestamp=IsNow(tz=timezone.utc))], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 398015, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3802,7 +3802,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ), ], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 398704, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -3854,7 +3854,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='test invalid first valid second', timestamp=IsNow(tz=timezone.utc))], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 522576, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3882,7 +3882,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ), ], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 523271, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -3935,7 +3935,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='test valid first invalid second', timestamp=IsNow(tz=timezone.utc))], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 647619, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3963,7 +3963,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ), ], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 648370, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -4016,7 +4016,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='test exhaustive with tool retry', timestamp=IsNow(tz=timezone.utc))], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 772011, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4044,7 +4044,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ), ], - timestamp=datetime(2025, 12, 14, 1, 23, 56, 772697, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -4100,7 +4100,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: [ ModelRequest( parts=[UserPromptPart(content='test multiple final results', timestamp=IsNow(tz=timezone.utc))], - timestamp=datetime(2025, 12, 14, 1, 23, 57, 19952, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4135,7 +4135,7 @@ def return_model(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: tool_call_id='second', ), ], - timestamp=datetime(2025, 12, 14, 1, 23, 57, 20457, tzinfo=timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ]