From 8d52d651154b9f021f3038f6b449a940e8debeb4 Mon Sep 17 00:00:00 2001 From: David <64162682+dsfaccini@users.noreply.github.com> Date: Fri, 28 Nov 2025 12:42:02 -0500 Subject: [PATCH 01/23] Clarify usage of agent factories Clarify that agents can be produced by a factory function if preferred. --- docs/agents.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/agents.md b/docs/agents.md index 0633fb88ba..a0dc22e5b1 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -57,7 +57,7 @@ print(result.output) 4. `result.output` will be a boolean indicating if the square is a winner. Pydantic performs the output validation, and it'll be typed as a `bool` since its type is derived from the `output_type` generic parameter of the agent. !!! tip "Agents are designed for reuse, like FastAPI Apps" - Agents are intended to be instantiated once (frequently as module globals) and reused throughout your application, similar to a small [FastAPI][fastapi.FastAPI] app or an [APIRouter][fastapi.APIRouter]. + Agents can be instantiated once as a module global and reused throughout your application, similar to a small [FastAPI][fastapi.FastAPI] app or an [APIRouter][fastapi.APIRouter], or be created dynamically by a factory function like `get_agent('agent-type')`, whichever you prefer. ## Running Agents From 8c6912499c63030cfc6b9e6d617822395a0a56c5 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 02/23] 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 | 23 +- 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 | 232 ++++++++--- 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 | 142 ++++++- 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 | 65 ++- 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, 1735 insertions(+), 381 deletions(-) diff --git a/docs/agents.md b/docs/agents.md index a0dc22e5b1..25180ff10b 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -321,6 +321,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ), @@ -385,6 +386,7 @@ async def main(): timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ) ), @@ -1049,6 +1051,7 @@ with capture_run_messages() as messages: # (2)! timestamp=datetime.datetime(...), ) ], + timestamp=datetime.datetime(...), run_id='...', ), ModelResponse( @@ -1073,6 +1076,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 6a14f8b350..bd82d74473 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 @@ -437,6 +437,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: @@ -469,6 +470,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 c8208ac9e6..3d945fcf4d 100644 --- a/pydantic_ai_slim/pydantic_ai/agent/__init__.py +++ b/pydantic_ai_slim/pydantic_ai/agent/__init__.py @@ -508,6 +508,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 567b61dff6..f9ba1591c8 100644 --- a/pydantic_ai_slim/pydantic_ai/agent/abstract.py +++ b/pydantic_ai_slim/pydantic_ai/agent/abstract.py @@ -1004,6 +1004,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 38e832fa2b..a27d4950ec 100644 --- a/pydantic_ai_slim/pydantic_ai/agent/wrapper.py +++ b/pydantic_ai_slim/pydantic_ai/agent/wrapper.py @@ -164,6 +164,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 ff6730f220..e4b6e46371 100644 --- a/pydantic_ai_slim/pydantic_ai/durable_exec/dbos/_agent.py +++ b/pydantic_ai_slim/pydantic_ai/durable_exec/dbos/_agent.py @@ -823,6 +823,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 8b1b6af44a..8321f789dc 100644 --- a/pydantic_ai_slim/pydantic_ai/durable_exec/prefect/_agent.py +++ b/pydantic_ai_slim/pydantic_ai/durable_exec/prefect/_agent.py @@ -768,6 +768,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 6e964c8d08..8cbfba71d0 100644 --- a/pydantic_ai_slim/pydantic_ai/durable_exec/temporal/_agent.py +++ b/pydantic_ai_slim/pydantic_ai/durable_exec/temporal/_agent.py @@ -842,6 +842,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 ac0fb0da6d..3e14133866 100644 --- a/pydantic_ai_slim/pydantic_ai/messages.py +++ b/pydantic_ai_slim/pydantic_ai/messages.py @@ -994,6 +994,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.""" @@ -1235,9 +1238,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 89290ea3ce..6930b7f814 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -491,6 +491,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: @@ -528,9 +530,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( @@ -655,6 +658,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 @@ -671,7 +675,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 64f7ddcf85..8a27d8ce18 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -320,7 +320,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: @@ -340,7 +340,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, @@ -369,8 +371,9 @@ 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_timestamp=first_chunk.created, ) def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[chat.ChatCompletionToolParam]: @@ -524,6 +527,7 @@ class GroqStreamedResponse(StreamedResponse): _response: AsyncIterable[chat.ChatCompletionChunk] _timestamp: datetime _provider_name: str + _provider_timestamp: int | None = None async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: # noqa: C901 try: @@ -542,7 +546,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 790b30bec3..dd9d2a706a 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -267,10 +267,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 @@ -285,7 +282,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( @@ -315,8 +314,9 @@ 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_timestamp=first_chunk.created, ) def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[ChatCompletionInputTool]: @@ -465,6 +465,7 @@ class HuggingFaceStreamedResponse(StreamedResponse): _response: AsyncIterable[ChatCompletionStreamOutput] _timestamp: datetime _provider_name: str + _provider_timestamp: int | None = None async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: async for chunk in self._response: @@ -479,7 +480,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 cefa28e9dc..44179c6b5d 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( @@ -397,17 +396,13 @@ 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_timestamp=first_chunk.data.created, ) @staticmethod @@ -615,6 +610,7 @@ class MistralStreamedResponse(StreamedResponse): _response: AsyncIterable[MistralCompletionEvent] _timestamp: datetime _provider_name: str + _provider_timestamp: int | None = None _delta_content: str = field(default='', init=False) @@ -632,7 +628,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 10af284ee8..8b464525ce 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -582,10 +582,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. @@ -621,12 +619,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, finish_reason=self._map_finish_reason(choice.finish_reason), @@ -672,9 +674,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 @@ -1130,7 +1133,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): @@ -1216,11 +1219,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, @@ -1230,7 +1235,7 @@ def _process_response( # noqa: C901 timestamp=timestamp, provider_name=self._provider.name, finish_reason=finish_reason, - provider_details=provider_details, + provider_details=provider_details or None, ) async def _process_streamed_response( @@ -1249,9 +1254,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 @@ -1838,6 +1845,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(): @@ -1861,7 +1869,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): @@ -1951,7 +1959,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) @@ -1990,6 +2001,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: @@ -2000,9 +2012,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 3f910d76b6..afe639c776 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openrouter.py +++ b/pydantic_ai_slim/pydantic_ai/models/openrouter.py @@ -422,7 +422,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: @@ -639,6 +640,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 f770b157af..1bc761a91e 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 @@ -239,6 +239,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( @@ -254,6 +255,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( @@ -895,6 +897,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( @@ -923,6 +926,7 @@ async def test_request_structured_response(allow_model_requests: None): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -965,6 +969,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( @@ -993,6 +998,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1021,6 +1027,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1375,6 +1382,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1416,6 +1424,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1575,6 +1584,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(), ), @@ -1612,6 +1622,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( @@ -1669,6 +1680,7 @@ async def test_anthropic_model_thinking_part(allow_model_requests: None, anthrop timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1731,6 +1743,7 @@ async def test_anthropic_model_thinking_part_redacted(allow_model_requests: None timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1777,6 +1790,7 @@ async def test_anthropic_model_thinking_part_redacted(allow_model_requests: None timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1836,6 +1850,7 @@ async def test_anthropic_model_thinking_part_redacted_stream(allow_model_request timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1979,6 +1994,7 @@ async def test_anthropic_model_thinking_part_from_other_model( timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2015,7 +2031,10 @@ async def test_anthropic_model_thinking_part_from_other_model( model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2041,6 +2060,7 @@ async def test_anthropic_model_thinking_part_from_other_model( timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2097,6 +2117,7 @@ async def test_anthropic_model_thinking_part_stream(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2507,6 +2528,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( @@ -2715,6 +2737,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( @@ -2928,6 +2951,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( @@ -3974,6 +3998,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( @@ -4055,6 +4080,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( @@ -4124,6 +4150,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( @@ -4220,6 +4247,7 @@ async def test_anthropic_web_fetch_tool_stream( timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4834,6 +4862,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( @@ -4920,6 +4949,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( @@ -5085,6 +5115,7 @@ async def test_anthropic_mcp_servers_stream(allow_model_requests: None, anthropi timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5347,6 +5378,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(), ), @@ -5414,6 +5446,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(), ), @@ -5495,6 +5528,7 @@ async def test_anthropic_code_execution_tool_stream(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6079,6 +6113,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( @@ -6092,7 +6127,10 @@ async def test_anthropic_server_tool_pass_history_to_another_provider( model_name='gpt-4.1-2025-04-14', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -6193,6 +6231,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6226,6 +6265,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6263,6 +6303,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6297,6 +6338,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6333,6 +6375,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6391,6 +6434,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6424,6 +6468,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6475,6 +6520,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 f13aaff4fb..3894cf3362 100644 --- a/tests/models/test_bedrock.py +++ b/tests/models/test_bedrock.py @@ -130,6 +130,7 @@ async def test_bedrock_model(allow_model_requests: None, bedrock_provider: Bedro timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -304,6 +305,7 @@ async def temperature(city: str, date: datetime.date) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -334,6 +336,7 @@ async def temperature(city: str, date: datetime.date) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -364,6 +367,7 @@ async def temperature(city: str, date: datetime.date) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -440,6 +444,7 @@ async def get_capital(country: str) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -470,6 +475,7 @@ async def get_capital(country: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -763,6 +769,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(), ), @@ -825,6 +832,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( @@ -853,6 +861,7 @@ async def test_bedrock_model_thinking_part_deepseek(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -886,6 +895,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( @@ -921,6 +931,7 @@ async def test_bedrock_model_thinking_part_anthropic(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -968,6 +979,7 @@ async def test_bedrock_model_thinking_part_redacted(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1004,6 +1016,7 @@ async def test_bedrock_model_thinking_part_redacted(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1062,6 +1075,7 @@ async def test_bedrock_model_thinking_part_redacted_stream( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1196,6 +1210,7 @@ async def test_bedrock_model_thinking_part_from_other_model( timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1228,7 +1243,10 @@ async def test_bedrock_model_thinking_part_from_other_model( model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1256,6 +1274,7 @@ async def test_bedrock_model_thinking_part_from_other_model( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1409,6 +1428,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 07cb6ae9b9..886d09b73d 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 @@ -118,6 +118,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( @@ -131,6 +132,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( @@ -200,6 +202,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( @@ -226,6 +229,7 @@ async def test_request_structured_response(allow_model_requests: None): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -292,6 +296,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( @@ -318,6 +323,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -345,6 +351,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -436,6 +443,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(), ), @@ -484,6 +492,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( @@ -497,7 +506,10 @@ async def test_cohere_model_thinking_part(allow_model_requests: None, co_api_key model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -519,6 +531,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 a8c0d8ceaa..4ec81579a9 100644 --- a/tests/models/test_deepseek.py +++ b/tests/models/test_deepseek.py @@ -1,5 +1,7 @@ from __future__ import annotations as _annotations +import datetime + import pytest from inline_snapshot import snapshot @@ -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( @@ -55,7 +58,10 @@ async def test_deepseek_model_thinking_part(allow_model_requests: None, deepseek model_name='deepseek-reasoner', timestamp=IsDatetime(), provider_name='deepseek', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime.datetime(2025, 4, 22, 14, 9, 11, tzinfo=datetime.timezone.utc), + }, provider_response_id='181d9669-2b3a-445e-bd13-2ebff2c378f6', finish_reason='stop', run_id=IsStr(), @@ -83,6 +89,7 @@ async def test_deepseek_model_thinking_stream(allow_model_requests: None, deepse timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -102,7 +109,10 @@ async def test_deepseek_model_thinking_stream(allow_model_requests: None, deepse model_name='deepseek-reasoner', timestamp=IsDatetime(), provider_name='deepseek', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': datetime.datetime(2025, 7, 10, 17, 41, 44, tzinfo=datetime.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 2d58fae71a..d974d1f85e 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( @@ -815,6 +818,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 0f2e51c0ce..b5a9f11313 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( @@ -581,6 +582,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( @@ -593,6 +595,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( @@ -621,6 +624,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( @@ -640,6 +644,7 @@ async def test_request_structured_response(get_gemini_client: GetGeminiClient): tool_call_id=IsStr(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -685,6 +690,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( @@ -706,6 +712,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -734,6 +741,7 @@ async def get_location(loc_name: str) -> str: tool_call_id=IsStr(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -892,6 +900,7 @@ async def bar(y: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -914,6 +923,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( @@ -933,6 +943,7 @@ async def bar(y: str) -> str: tool_call_id=IsStr(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -979,6 +990,7 @@ def get_location(loc_name: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1005,6 +1017,7 @@ def get_location(loc_name: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -1191,6 +1204,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1223,6 +1237,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1379,6 +1394,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(), ), @@ -1457,6 +1473,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( @@ -1497,7 +1514,10 @@ async def test_gemini_model_thinking_part(allow_model_requests: None, gemini_api model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': IsDatetime(), + }, provider_response_id='resp_680393ff82488191a7d0850bf0dd99a004f0817ea037a07b', finish_reason='stop', run_id=IsStr(), @@ -1517,6 +1537,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( @@ -1530,7 +1551,10 @@ async def test_gemini_model_thinking_part(allow_model_requests: None, gemini_api model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': IsDatetime(), + }, provider_response_id='resp_680393ff82488191a7d0850bf0dd99a004f0817ea037a07b', finish_reason='stop', run_id=IsStr(), @@ -1542,6 +1566,7 @@ async def test_gemini_model_thinking_part(allow_model_requests: None, gemini_api timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1614,6 +1639,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( @@ -1698,6 +1724,7 @@ async def bar() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1720,6 +1747,7 @@ async def bar() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1748,6 +1776,7 @@ async def bar() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -1780,6 +1809,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1802,6 +1832,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1830,6 +1861,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -1861,6 +1893,7 @@ def upcase(text: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1933,6 +1966,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1985,6 +2019,7 @@ class CountryLanguage(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2038,6 +2073,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2087,6 +2123,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2109,6 +2146,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2152,6 +2190,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 3ef8cd5dda..8f6428ffe7 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 @@ -61,7 +62,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: @@ -134,6 +135,7 @@ async def test_google_model(allow_model_requests: None, google_provider: GoogleP timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -199,6 +201,7 @@ async def temperature(city: str, date: datetime.date) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -226,6 +229,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( @@ -258,6 +262,7 @@ async def temperature(city: str, date: datetime.date) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -324,6 +329,7 @@ async def test_google_model_builtin_code_execution_stream( timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -564,6 +570,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( @@ -595,6 +602,7 @@ async def get_capital(country: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -626,6 +634,7 @@ async def get_capital(country: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -931,6 +940,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(), ), @@ -1004,6 +1014,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( @@ -1083,6 +1094,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( @@ -1177,6 +1189,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( @@ -1322,6 +1335,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( @@ -1427,6 +1441,7 @@ async def test_google_model_web_fetch_tool( timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1506,6 +1521,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( @@ -1631,6 +1647,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( @@ -1699,6 +1716,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( @@ -1927,6 +1945,7 @@ def dummy() -> None: ... # pragma: no cover timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1964,6 +1983,7 @@ def dummy() -> None: ... # pragma: no cover timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2015,6 +2035,7 @@ def dummy() -> None: ... # pragma: no cover timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2047,7 +2068,10 @@ def dummy() -> None: ... # pragma: no cover model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2073,6 +2097,7 @@ def dummy() -> None: ... # pragma: no cover timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2129,6 +2154,7 @@ def dummy() -> None: ... # pragma: no cover timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2325,7 +2351,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(), @@ -2367,7 +2393,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(), @@ -2420,6 +2446,7 @@ async def bar() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2444,6 +2471,7 @@ async def bar() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2474,6 +2502,7 @@ async def bar() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -2516,6 +2545,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2540,6 +2570,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2570,6 +2601,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -2602,6 +2634,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2626,6 +2659,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2690,6 +2724,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2743,6 +2778,7 @@ class CountryLanguage(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2797,6 +2833,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2843,6 +2880,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2867,6 +2905,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2911,6 +2950,7 @@ class CountryLanguage(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3116,6 +3156,7 @@ async def test_google_image_generation(allow_model_requests: None, google_provid timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3156,6 +3197,7 @@ async def test_google_image_generation(allow_model_requests: None, google_provid timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3231,6 +3273,7 @@ async def test_google_image_generation_stream(allow_model_requests: None, google timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3303,6 +3346,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( @@ -3419,6 +3463,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3453,6 +3498,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3527,6 +3573,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( @@ -4092,6 +4139,7 @@ def get_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4113,7 +4161,10 @@ def get_country() -> str: model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -4127,6 +4178,7 @@ def get_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4146,7 +4198,10 @@ def get_country() -> str: model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -4189,6 +4244,7 @@ def get_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -4267,7 +4323,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 dd3395750e..a8d085b018 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: @@ -167,29 +167,37 @@ 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_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_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(), @@ -234,7 +242,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( @@ -246,9 +255,12 @@ 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_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(), @@ -259,9 +271,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(), ), ] @@ -325,9 +338,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( @@ -340,9 +354,12 @@ 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_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(), @@ -353,9 +370,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( @@ -368,9 +386,12 @@ 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_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(), @@ -381,17 +402,21 @@ 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_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(), @@ -497,7 +522,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( @@ -509,7 +535,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_response_id='x', run_id=IsStr(), @@ -520,9 +546,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(), ), ] @@ -607,6 +634,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -615,7 +643,10 @@ async def get_image() -> BinaryContent: model_name='meta-llama/llama-4-scout-17b-16e-instruct', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -636,6 +667,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -644,7 +676,10 @@ async def get_image() -> BinaryContent: model_name='meta-llama/llama-4-scout-17b-16e-instruct', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -733,6 +768,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(), ), @@ -742,7 +778,10 @@ async def test_groq_model_instructions(allow_model_requests: None, groq_api_key: model_name='llama-3.3-70b-versatile', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -772,6 +811,7 @@ async def test_groq_model_web_search_tool(allow_model_requests: None, groq_api_k timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1010,7 +1050,10 @@ async def test_groq_model_web_search_tool(allow_model_requests: None, groq_api_k model_name='groq/compound', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -1042,6 +1085,7 @@ async def test_groq_model_web_search_tool_stream(allow_model_requests: None, gro timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1177,7 +1221,10 @@ async def test_groq_model_web_search_tool_stream(allow_model_requests: None, gro model_name='groq/compound', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -1933,6 +1980,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(), ), @@ -1942,7 +1990,10 @@ async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key model_name='deepseek-r1-distill-llama-70b', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -1959,6 +2010,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(), ), @@ -1968,7 +2020,10 @@ async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key model_name='deepseek-r1-distill-llama-70b', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -1980,6 +2035,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(), ), @@ -1989,7 +2045,10 @@ async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key model_name='deepseek-r1-distill-llama-70b', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -2023,6 +2082,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(), ), @@ -2109,7 +2169,10 @@ async def test_groq_model_thinking_part_iter(allow_model_requests: None, groq_ap model_name='deepseek-r1-distill-llama-70b', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -3366,6 +3429,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(), ), @@ -3471,7 +3535,10 @@ async def test_groq_model_thinking_part_iter(allow_model_requests: None, groq_ap model_name='deepseek-r1-distill-llama-70b', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -5312,6 +5379,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(), ), @@ -5351,6 +5419,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(), ), @@ -5369,7 +5438,10 @@ async def get_something_by_name(name: str) -> str: model_name='openai/gpt-oss-120b', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -5383,6 +5455,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(), ), @@ -5397,7 +5470,10 @@ async def get_something_by_name(name: str) -> str: model_name='openai/gpt-oss-120b', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -5433,6 +5509,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(), ), @@ -5479,6 +5556,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(), ), @@ -5495,7 +5573,10 @@ async def get_something_by_name(name: str) -> str: model_name='openai/gpt-oss-120b', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -5509,6 +5590,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 +5600,10 @@ async def get_something_by_name(name: str) -> str: model_name='openai/gpt-oss-120b', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -5560,6 +5645,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5573,7 +5659,10 @@ class CityLocation(BaseModel): model_name='openai/gpt-oss-120b', timestamp=IsDatetime(), provider_name='groq', - 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(), @@ -5603,6 +5692,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5616,7 +5706,10 @@ class CityLocation(BaseModel): model_name='openai/gpt-oss-120b', timestamp=IsDatetime(), provider_name='groq', - 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 56d74ed619..fd9198d603 100644 --- a/tests/models/test_huggingface.py +++ b/tests/models/test_huggingface.py @@ -167,9 +167,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(), ) @@ -237,9 +240,12 @@ 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_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(), ) @@ -361,6 +367,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( @@ -373,9 +380,12 @@ 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_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(), ), @@ -388,6 +398,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -400,9 +411,12 @@ 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_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(), ), @@ -415,14 +429,18 @@ 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_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(), ), @@ -640,15 +658,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(), ), @@ -709,6 +731,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(), ), @@ -718,7 +741,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(), ), @@ -807,14 +833,18 @@ 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_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(), ), @@ -827,14 +857,18 @@ 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_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(), ), @@ -925,6 +959,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( @@ -936,7 +971,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(), ), @@ -959,6 +997,7 @@ async def test_hf_model_thinking_part(allow_model_requests: None, huggingface_ap timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -970,7 +1009,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(), ), @@ -1000,6 +1042,7 @@ async def test_hf_model_thinking_part_iter(allow_model_requests: None, huggingfa timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1010,7 +1053,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 4ae21ad221..caf2a1c5bb 100644 --- a/tests/models/test_mistral.py +++ b/tests/models/test_mistral.py @@ -215,6 +215,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( @@ -230,15 +231,19 @@ 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_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(), @@ -279,45 +284,57 @@ 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_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_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_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(), @@ -426,6 +443,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( @@ -438,9 +456,12 @@ 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_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(), @@ -454,6 +475,7 @@ class CityLocation(BaseModel): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -494,6 +516,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( @@ -506,9 +529,12 @@ 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_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(), @@ -522,6 +548,7 @@ class CityLocation(BaseModel): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -559,6 +586,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( @@ -571,9 +599,12 @@ 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_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(), @@ -587,6 +618,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(), ), ] @@ -1114,6 +1146,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( @@ -1126,9 +1159,12 @@ 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_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(), @@ -1142,6 +1178,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1154,9 +1191,12 @@ 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_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(), @@ -1170,15 +1210,19 @@ 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_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(), @@ -1271,6 +1315,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( @@ -1283,9 +1328,12 @@ 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_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(), @@ -1299,6 +1347,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1311,9 +1360,12 @@ 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_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(), @@ -1327,6 +1379,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1339,9 +1392,12 @@ 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_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(), @@ -1355,6 +1411,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1418,7 +1475,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 @@ -1432,6 +1489,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( @@ -1444,9 +1502,12 @@ 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_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(), @@ -1460,15 +1521,19 @@ 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_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(), @@ -1482,6 +1547,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1532,7 +1598,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 @@ -1546,6 +1612,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( @@ -1558,9 +1625,12 @@ 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_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(), @@ -1574,15 +1644,19 @@ 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_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(), @@ -1648,7 +1722,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 @@ -1662,6 +1736,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( @@ -1674,9 +1749,12 @@ 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_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(), @@ -1690,6 +1768,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1702,9 +1781,12 @@ 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_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(), @@ -1718,15 +1800,19 @@ 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_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(), @@ -1898,6 +1984,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1906,7 +1993,10 @@ async def get_image() -> BinaryContent: model_name='pixtral-12b-latest', timestamp=IsDatetime(), provider_name='mistral', - provider_details={'finish_reason': 'tool_calls'}, + 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(), @@ -1927,6 +2017,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1939,7 +2030,10 @@ async def get_image() -> BinaryContent: model_name='pixtral-12b-latest', timestamp=IsDatetime(), provider_name='mistral', - provider_details={'finish_reason': 'stop'}, + 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(), @@ -1975,6 +2069,7 @@ async def test_image_url_input(allow_model_requests: None): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1983,7 +2078,10 @@ async def test_image_url_input(allow_model_requests: None): model_name='mistral-large-123', timestamp=IsDatetime(), provider_name='mistral', - 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(), @@ -2016,6 +2114,7 @@ async def test_image_as_binary_content_input(allow_model_requests: None): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2024,7 +2123,10 @@ async def test_image_as_binary_content_input(allow_model_requests: None): model_name='mistral-large-123', timestamp=IsDatetime(), provider_name='mistral', - 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(), @@ -2060,6 +2162,7 @@ async def test_pdf_url_input(allow_model_requests: None): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2068,7 +2171,10 @@ async def test_pdf_url_input(allow_model_requests: None): model_name='mistral-large-123', timestamp=IsDatetime(), provider_name='mistral', - 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(), @@ -2098,6 +2204,7 @@ async def test_pdf_as_binary_content_input(allow_model_requests: None): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2106,7 +2213,10 @@ async def test_pdf_as_binary_content_input(allow_model_requests: None): model_name='mistral-large-123', timestamp=IsDatetime(), provider_name='mistral', - 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(), @@ -2193,6 +2303,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(), ), @@ -2202,7 +2313,10 @@ async def test_mistral_model_instructions(allow_model_requests: None, mistral_ap model_name='mistral-large-123', timestamp=IsDatetime(), provider_name='mistral', - 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(), @@ -2222,6 +2336,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( @@ -2240,7 +2355,10 @@ async def test_mistral_model_thinking_part(allow_model_requests: None, openai_ap model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2263,6 +2381,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( @@ -2274,7 +2393,10 @@ async def test_mistral_model_thinking_part(allow_model_requests: None, openai_ap model_name='magistral-medium-latest', timestamp=IsDatetime(), provider_name='mistral', - 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(), @@ -2305,6 +2427,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( @@ -2354,7 +2477,10 @@ async def test_mistral_model_thinking_part_iter(allow_model_requests: None, mist model_name='magistral-medium-latest', timestamp=IsDatetime(), provider_name='mistral', - provider_details={'finish_reason': 'stop'}, + 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 b6c16b0f3e..6f31b3ef51 100644 --- a/tests/models/test_openai.py +++ b/tests/models/test_openai.py @@ -125,28 +125,36 @@ 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_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_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(), @@ -238,6 +246,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( @@ -249,9 +258,12 @@ 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_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(), @@ -265,6 +277,7 @@ async def test_request_structured_response(allow_model_requests: None): timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -333,6 +346,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( @@ -349,9 +363,12 @@ 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_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(), @@ -365,6 +382,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -381,9 +399,12 @@ 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_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(), @@ -397,14 +418,18 @@ 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_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(), @@ -477,7 +502,10 @@ async def test_stream_text_finish_reason(allow_model_requests: None): model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', - 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', ) @@ -892,6 +920,7 @@ async def get_image() -> ImageUrl: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -909,7 +938,10 @@ async def get_image() -> ImageUrl: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -933,6 +965,7 @@ async def get_image() -> ImageUrl: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -950,7 +983,10 @@ async def get_image() -> ImageUrl: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -979,6 +1015,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -996,7 +1033,10 @@ async def get_image() -> BinaryContent: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1017,6 +1057,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1034,7 +1075,10 @@ async def get_image() -> BinaryContent: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1240,6 +1284,7 @@ async def test_message_history_can_start_with_model_response(allow_model_request timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1257,7 +1302,10 @@ async def test_message_history_can_start_with_model_response(allow_model_request model_name='gpt-4.1-mini-2025-04-14', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2044,6 +2092,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(), ), @@ -2062,7 +2111,10 @@ async def test_openai_instructions(allow_model_requests: None, openai_api_key: s model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2093,6 +2145,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(), ), @@ -2111,7 +2164,10 @@ async def get_temperature(city: str) -> float: model_name='gpt-4.1-mini-2025-04-14', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2122,6 +2178,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(), ), @@ -2140,7 +2197,10 @@ async def get_temperature(city: str) -> float: model_name='gpt-4.1-mini-2025-04-14', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2160,6 +2220,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( @@ -2177,7 +2238,10 @@ async def test_openai_model_thinking_part(allow_model_requests: None, openai_api model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2199,6 +2263,7 @@ async def test_openai_model_thinking_part(allow_model_requests: None, openai_api timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2216,7 +2281,10 @@ async def test_openai_model_thinking_part(allow_model_requests: None, openai_api model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2481,7 +2549,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): @@ -2509,6 +2580,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2526,7 +2598,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2540,6 +2615,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2563,7 +2639,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2577,6 +2656,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -2607,6 +2687,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2626,7 +2707,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2640,6 +2724,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2657,7 +2742,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2693,6 +2781,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2712,7 +2801,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2726,6 +2818,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2743,7 +2836,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2781,6 +2877,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2800,7 +2897,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2814,6 +2914,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2835,7 +2936,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2869,6 +2973,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2888,7 +2993,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2902,6 +3010,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2919,7 +3028,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2957,6 +3069,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2976,7 +3089,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2990,6 +3106,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -3011,7 +3128,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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 fc72a48cb1..746d2c9626 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -1,3 +1,4 @@ +import datetime import json import re from dataclasses import replace @@ -248,6 +249,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -269,7 +271,10 @@ async def get_location(loc_name: str) -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 3, 27, 12, 42, 44, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_67e547c48c9481918c5c4394464ce0c60ae6111e84dd5c08', finish_reason='stop', run_id=IsStr(), @@ -289,6 +294,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -306,7 +312,10 @@ async def get_location(loc_name: str) -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 3, 27, 12, 42, 45, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_67e547c5a2f08191802a1f43620f348503a2086afed73b47', finish_reason='stop', run_id=IsStr(), @@ -336,6 +345,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -351,7 +361,10 @@ async def get_image() -> BinaryContent: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 4, 29, 20, 21, 39, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_681134d3aa3481919ca581a267db1e510fe7a5a4e2123dc3', finish_reason='stop', run_id=IsStr(), @@ -372,6 +385,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -385,7 +399,10 @@ async def get_image() -> BinaryContent: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 4, 29, 20, 21, 41, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_681134d53c48819198ce7b89db78dffd02cbfeaababb040c', finish_reason='stop', run_id=IsStr(), @@ -487,7 +504,10 @@ async def get_capital(country: str) -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 3, 27, 13, 37, 38, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_67e554a21aa88191b65876ac5e5bbe0406c52f0e511c76ed', finish_reason='stop', ) @@ -521,6 +541,7 @@ async def test_openai_responses_model_builtin_tools_web_search(allow_model_reque timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -665,7 +686,10 @@ async def test_openai_responses_model_builtin_tools_web_search(allow_model_reque model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 12, 23, 19, 54, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_0e3d55e9502941380068c4aa9a62f48195a373978ed720ac63', finish_reason='stop', run_id=IsStr(), @@ -684,6 +708,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(), ), @@ -698,7 +723,10 @@ async def test_openai_responses_model_instructions(allow_model_requests: None, o model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 4, 7, 16, 31, 57, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_67f3fdfd9fa08191a3d5825db81b8df6003bc73febb56d77', finish_reason='stop', run_id=IsStr(), @@ -721,6 +749,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(), ), @@ -762,7 +791,10 @@ async def test_openai_responses_model_web_search_tool(allow_model_requests: None model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 16, 20, 27, 26, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_028829e50fbcad090068c9c82e1e0081958ddc581008b39428', finish_reason='stop', run_id=IsStr(), @@ -781,6 +813,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(), ), @@ -822,7 +855,10 @@ async def test_openai_responses_model_web_search_tool(allow_model_requests: None model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 16, 20, 27, 39, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_028829e50fbcad090068c9c83b9fb88195b6b84a32e1fc83c0', finish_reason='stop', run_id=IsStr(), @@ -851,6 +887,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(), ), @@ -892,7 +929,10 @@ async def test_openai_responses_model_web_search_tool_with_user_location( model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 12, 23, 21, 23, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_0b385a0fdc82fd920068c4aaf3ced88197a88711e356b032c4', finish_reason='stop', run_id=IsStr(), @@ -922,6 +962,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(), ), @@ -963,7 +1004,10 @@ async def test_openai_responses_model_web_search_tool_with_invalid_region( model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 12, 23, 21, 47, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_0b4f29854724a3120068c4ab0b660081919707b95b47552782', finish_reason='stop', run_id=IsStr(), @@ -1000,6 +1044,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(), ), @@ -1047,7 +1092,10 @@ async def test_openai_responses_model_web_search_tool_stream(allow_model_request model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 16, 21, 13, 32, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_00a60507bf41223d0068c9d2fbf93481a0ba2a7796ae2cab4c', finish_reason='stop', run_id=IsStr(), @@ -1219,6 +1267,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(), ), @@ -1266,7 +1315,10 @@ async def test_openai_responses_model_web_search_tool_stream(allow_model_request model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 16, 21, 13, 57, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_00a60507bf41223d0068c9d31574d881a090c232646860a771', finish_reason='stop', run_id=IsStr(), @@ -1359,6 +1411,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1374,7 +1427,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 43, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68477f0b40a8819cb8d55594bc2c232a001fd29e2d5573f7', finish_reason='stop', run_id=IsStr(), @@ -1388,6 +1444,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1403,7 +1460,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 44, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68477f0bfda8819ea65458cd7cc389b801dc81d4bc91f560', finish_reason='stop', run_id=IsStr(), @@ -1417,6 +1477,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -1448,6 +1509,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1463,7 +1525,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 45, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68477f0d9494819ea4f123bba707c9ee0356a60c98816d6a', finish_reason='stop', run_id=IsStr(), @@ -1477,6 +1542,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1490,7 +1556,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 46, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68477f0e2b28819d9c828ef4ee526d6a03434b607c02582d', finish_reason='stop', run_id=IsStr(), @@ -1527,6 +1596,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1542,7 +1612,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 47, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68477f0f220081a1a621d6bcdc7f31a50b8591d9001d2329', finish_reason='stop', run_id=IsStr(), @@ -1556,6 +1629,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1569,7 +1643,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 47, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68477f0fde708192989000a62809c6e5020197534e39cc1f', finish_reason='stop', run_id=IsStr(), @@ -1608,6 +1685,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1623,7 +1701,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 48, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68477f10f2d081a39b3438f413b3bafc0dd57d732903c563', finish_reason='stop', run_id=IsStr(), @@ -1637,6 +1718,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1650,7 +1732,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 49, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68477f119830819da162aa6e10552035061ad97e2eef7871', finish_reason='stop', run_id=IsStr(), @@ -1685,6 +1770,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1700,7 +1786,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 6, 10, 13, 11, 46, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68482f12d63881a1830201ed101ecfbf02f8ef7f2fb42b50', finish_reason='stop', run_id=IsStr(), @@ -1714,6 +1803,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1727,7 +1817,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 6, 10, 13, 11, 55, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68482f1b556081918d64c9088a470bf0044fdb7d019d4115', finish_reason='stop', run_id=IsStr(), @@ -1766,6 +1859,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1781,7 +1875,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 6, 10, 13, 11, 57, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68482f1d38e081a1ac828acda978aa6b08e79646fe74d5ee', finish_reason='stop', run_id=IsStr(), @@ -1795,6 +1892,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1808,7 +1906,10 @@ async def get_user_country() -> str: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 6, 10, 13, 12, 8, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68482f28c1b081a1ae73cbbee012ee4906b4ab2d00d03024', finish_reason='stop', run_id=IsStr(), @@ -1917,7 +2018,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(), @@ -1926,7 +2030,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(), + ), ] ) @@ -1978,7 +2085,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(), + ), ] ) @@ -2011,6 +2121,7 @@ async def test_openai_responses_usage_without_tokens_details(allow_model_request timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2019,6 +2130,7 @@ async def test_openai_responses_usage_without_tokens_details(allow_model_request model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', + provider_details={'timestamp': datetime.datetime(2024, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -2040,6 +2152,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( @@ -2064,7 +2177,10 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 12, 14, 22, 8, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68c42c902794819cb9335264c342f65407460311b0c8d3de', finish_reason='stop', run_id=IsStr(), @@ -2085,6 +2201,7 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2108,7 +2225,10 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 12, 14, 22, 43, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68c42cb3d520819c9d28b07036e9059507460311b0c8d3de', finish_reason='stop', run_id=IsStr(), @@ -2137,6 +2257,7 @@ async def test_openai_responses_thinking_part_from_other_model( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2187,6 +2308,7 @@ async def test_openai_responses_thinking_part_from_other_model( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2208,7 +2330,10 @@ async def test_openai_responses_thinking_part_from_other_model( model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 12, 14, 23, 30, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68c42ce277ac8193ba08881bcefabaf70ad492c7955fc6fc', finish_reason='stop', run_id=IsStr(), @@ -2240,6 +2365,7 @@ async def test_openai_responses_thinking_part_iter(allow_model_requests: None, o timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2271,7 +2397,10 @@ async def test_openai_responses_thinking_part_iter(allow_model_requests: None, o model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 12, 14, 24, 15, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68c42d0fb418819dbfa579f69406b49508fbf9b1584184ff', finish_reason='stop', run_id=IsStr(), @@ -2317,6 +2446,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(), ), @@ -2343,7 +2473,10 @@ def update_plan(plan: str) -> str: model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 12, 14, 24, 40, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68c42d28772c819684459966ee2201ed0e8bc41441c948f6', finish_reason='stop', run_id=IsStr(), @@ -2357,6 +2490,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(), ), @@ -2368,7 +2502,10 @@ def update_plan(plan: str) -> str: model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 12, 14, 25, 3, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68c42d3fd6a08196bce23d6be960ff8a0e8bc41441c948f6', finish_reason='stop', run_id=IsStr(), @@ -2409,6 +2546,7 @@ async def test_openai_responses_thinking_without_summary(allow_model_requests: N timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2419,6 +2557,7 @@ async def test_openai_responses_thinking_without_summary(allow_model_requests: N model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', + provider_details={'timestamp': datetime.datetime(2024, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -2482,6 +2621,7 @@ async def test_openai_responses_thinking_with_multiple_summaries(allow_model_req timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2495,6 +2635,7 @@ async def test_openai_responses_thinking_with_multiple_summaries(allow_model_req model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', + provider_details={'timestamp': datetime.datetime(2024, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -2547,6 +2688,7 @@ async def test_openai_responses_thinking_with_modified_history(allow_model_reque timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2563,7 +2705,10 @@ async def test_openai_responses_thinking_with_modified_history(allow_model_reque model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 12, 14, 27, 43, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68c42ddf9bbc8194aa7b97304dd909cb0202c9ad459e0d23', finish_reason='stop', run_id=IsStr(), @@ -2600,6 +2745,7 @@ async def test_openai_responses_thinking_with_modified_history(allow_model_reque timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2616,7 +2762,10 @@ async def test_openai_responses_thinking_with_modified_history(allow_model_reque model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 12, 14, 27, 48, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68c42de4afcc819f995a1c59fe87c9d5051f82c608a83beb', finish_reason='stop', run_id=IsStr(), @@ -2648,6 +2797,7 @@ async def test_openai_responses_thinking_with_code_execution_tool(allow_model_re timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2700,7 +2850,10 @@ async def test_openai_responses_thinking_with_code_execution_tool(allow_model_re model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 19, 20, 17, 21, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68cdba511c7081a389e67b16621029c609b7445677780c8f', finish_reason='stop', run_id=IsStr(), @@ -2719,6 +2872,7 @@ async def test_openai_responses_thinking_with_code_execution_tool(allow_model_re timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2735,7 +2889,10 @@ async def test_openai_responses_thinking_with_code_execution_tool(allow_model_re model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 19, 20, 17, 46, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68cdba6a610481a3b4533f345bea8a7b09b7445677780c8f', finish_reason='stop', run_id=IsStr(), @@ -2773,6 +2930,7 @@ async def test_openai_responses_thinking_with_code_execution_tool_stream( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2833,7 +2991,10 @@ async def test_openai_responses_thinking_with_code_execution_tool_stream( model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 11, 22, 43, 36, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68c35098e6fc819e80fb94b25b7d031b0f2d670b80edc507', finish_reason='stop', run_id=IsStr(), @@ -3593,6 +3754,7 @@ def get_meaning_of_life() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -3608,7 +3770,10 @@ def get_meaning_of_life() -> int: model_name='gpt-4.1-2025-04-14', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 18, 18, 29, 57, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68cc4fa5603481958e2143685133fe530548824120ffcf74', finish_reason='stop', run_id=IsStr(), @@ -3622,6 +3787,7 @@ def get_meaning_of_life() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -3639,7 +3805,10 @@ def get_meaning_of_life() -> int: model_name='gpt-4.1-2025-04-14', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 18, 18, 29, 58, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68cc4fa6a8a881a187b0fe1603057bff0307c6d4d2ee5985', finish_reason='stop', run_id=IsStr(), @@ -3702,6 +3871,7 @@ async def test_openai_responses_code_execution_return_image(allow_model_requests timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -3771,7 +3941,10 @@ async def test_openai_responses_code_execution_return_image(allow_model_requests model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 19, 20, 56, 34, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68cdc382bc98819083a5b47ec92e077b0187028ba77f15f7', finish_reason='stop', run_id=IsStr(), @@ -3797,6 +3970,7 @@ async def test_openai_responses_code_execution_return_image(allow_model_requests timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -3930,7 +4104,10 @@ async def test_openai_responses_code_execution_return_image(allow_model_requests model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 19, 20, 57, 1, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68cdc39da72481909e0512fef9d646240187028ba77f15f7', finish_reason='stop', run_id=IsStr(), @@ -3974,6 +4151,7 @@ async def test_openai_responses_code_execution_return_image_stream(allow_model_r timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -4015,7 +4193,10 @@ async def test_openai_responses_code_execution_return_image_stream(allow_model_r model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 1, 20, 47, 35, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_06c1a26fd89d07f20068dd9367869c819788cb28e6f19eff9b', finish_reason='stop', run_id=IsStr(), @@ -5462,6 +5643,7 @@ async def test_openai_responses_image_generation(allow_model_requests: None, ope timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5509,7 +5691,10 @@ async def test_openai_responses_image_generation(allow_model_requests: None, ope model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 19, 20, 57, 58, tzinfo=datetime.timezone.utc), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -5534,6 +5719,7 @@ async def test_openai_responses_image_generation(allow_model_requests: None, ope timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5581,7 +5767,10 @@ async def test_openai_responses_image_generation(allow_model_requests: None, ope model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 19, 20, 59, 28, tzinfo=datetime.timezone.utc), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -5628,6 +5817,7 @@ async def test_openai_responses_image_generation_stream(allow_model_requests: No timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5673,7 +5863,10 @@ async def test_openai_responses_image_generation_stream(allow_model_requests: No model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 1, 20, 40, 2, tzinfo=datetime.timezone.utc), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -5808,6 +6001,7 @@ async def test_openai_responses_image_generation_tool_without_image_output( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5852,7 +6046,10 @@ async def test_openai_responses_image_generation_tool_without_image_output( model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 19, 23, 49, 51, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68cdec1f3290819f99d9caba8703b251079003437d26d0c0', finish_reason='stop', run_id=IsStr(), @@ -5865,6 +6062,7 @@ async def test_openai_responses_image_generation_tool_without_image_output( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -5909,7 +6107,10 @@ async def test_openai_responses_image_generation_tool_without_image_output( model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 9, 19, 23, 50, 57, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_68cdec61d0a0819fac14ed057a9946a1079003437d26d0c0', finish_reason='stop', run_id=IsStr(), @@ -5971,6 +6172,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6013,7 +6215,10 @@ class Animal(BaseModel): model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 1, 19, 38, 16, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_0360827931d9421b0068dd8328c08c81a0ba854f245883906f', finish_reason='stop', run_id=IsStr(), @@ -6026,6 +6231,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6047,7 +6253,10 @@ class Animal(BaseModel): model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 1, 19, 39, 28, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_0360827931d9421b0068dd8370a70081a09d6de822ee43bbc4', finish_reason='stop', run_id=IsStr(), @@ -6061,6 +6270,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -6086,6 +6296,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6131,7 +6342,10 @@ class Animal(BaseModel): model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 1, 19, 41, 59, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_09b7ce6df817433c0068dd8407c37881a0ad817ef3cc3a3600', finish_reason='stop', run_id=IsStr(), @@ -6159,6 +6373,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6204,7 +6419,10 @@ class Animal(BaseModel): model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 1, 19, 55, 9, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_0d14a5e3c26c21180068dd871d439081908dc36e63fab0cedf', finish_reason='stop', run_id=IsStr(), @@ -6238,6 +6456,7 @@ async def get_animal() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6259,7 +6478,10 @@ async def get_animal() -> str: model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 1, 20, 2, 36, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_0481074da98340df0068dd88dceb1481918b1d167d99bc51cd', finish_reason='stop', run_id=IsStr(), @@ -6273,6 +6495,7 @@ async def get_animal() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6309,7 +6532,10 @@ async def get_animal() -> str: model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 1, 20, 2, 56, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_0481074da98340df0068dd88f0ba04819185a168065ef28040', finish_reason='stop', run_id=IsStr(), @@ -6340,6 +6566,7 @@ async def test_openai_responses_multiple_images(allow_model_requests: None, open timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6412,7 +6639,10 @@ async def test_openai_responses_multiple_images(allow_model_requests: None, open model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 1, 19, 28, 22, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_0b6169df6e16e9690068dd80d64aec81919c65f238307673bb', finish_reason='stop', run_id=IsStr(), @@ -6443,6 +6673,7 @@ async def test_openai_responses_image_generation_jpeg(allow_model_requests: None timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6485,7 +6716,10 @@ async def test_openai_responses_image_generation_jpeg(allow_model_requests: None model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 1, 21, 28, 13, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_08acbdf1ae54befc0068dd9ced226c8197a2e974b29c565407', finish_reason='stop', run_id=IsStr(), @@ -6546,6 +6780,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -6567,7 +6802,10 @@ class CityLocation(BaseModel): model_name='gpt-5-2025-08-07', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 13, 11, 30, 47, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_001fd29e2d5573f70068ece2e6dfbc819c96557f0de72802be', finish_reason='stop', run_id=IsStr(), @@ -6581,6 +6819,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -6616,6 +6855,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(), ), @@ -6741,7 +6981,10 @@ async def test_openai_responses_model_mcp_server_tool(allow_model_requests: None model_name='o4-mini-2025-04-16', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 23, 23, 42, 57, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_0083938b3a28070e0068fabd81970881a0a1195f2cab45bd04', finish_reason='stop', run_id=IsStr(), @@ -6760,6 +7003,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(), ), @@ -6788,7 +7032,10 @@ async def test_openai_responses_model_mcp_server_tool(allow_model_requests: None model_name='o4-mini-2025-04-16', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 23, 23, 43, 25, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_0083938b3a28070e0068fabd9d414881a089cf24784f80e021', finish_reason='stop', run_id=IsStr(), @@ -6837,6 +7084,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(), ), @@ -7008,7 +7256,10 @@ async def test_openai_responses_model_mcp_server_tool_stream(allow_model_request model_name='o4-mini-2025-04-16', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 23, 21, 40, 50, tzinfo=datetime.timezone.utc), + }, provider_response_id='resp_00b9cc7a23d047270068faa0e25934819f9c3bfdec80065bc4', finish_reason='stop', run_id=IsStr(), @@ -7227,6 +7478,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(), ), @@ -7386,7 +7638,10 @@ async def test_openai_responses_model_mcp_server_tool_with_connector(allow_model model_name='o4-mini-2025-04-16', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'completed'}, + provider_details={ + 'finish_reason': 'completed', + 'timestamp': datetime.datetime(2025, 10, 23, 21, 41, 13, tzinfo=datetime.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 d6243bdfe5..2c1ccb5593 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 @@ -95,7 +96,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 4ecc3668ba..0fe093a738 100644 --- a/tests/models/test_outlines.py +++ b/tests/models/test_outlines.py @@ -322,6 +322,7 @@ async def test_request_async(llamacpp_model: OutlinesModel) -> None: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='Answer in one word.', run_id=IsStr(), ), @@ -338,6 +339,7 @@ async def test_request_async(llamacpp_model: OutlinesModel) -> None: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='Answer in one word.', run_id=IsStr(), ), @@ -349,6 +351,7 @@ async def test_request_async(llamacpp_model: OutlinesModel) -> None: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), instructions='Answer in one word.', run_id=IsStr(), ), @@ -370,6 +373,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()), @@ -400,6 +404,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()), @@ -435,6 +440,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()), @@ -466,6 +472,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()), @@ -522,6 +529,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 c912334434..62650edf32 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -178,6 +178,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( @@ -203,6 +204,7 @@ def return_model(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -221,6 +223,7 @@ def return_model(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -311,6 +314,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( @@ -329,6 +333,7 @@ def validate_output(ctx: RunContext[None], o: Foo) -> Foo: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -347,6 +352,7 @@ def validate_output(ctx: RunContext[None], o: Foo) -> Foo: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -455,6 +461,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( @@ -472,6 +479,7 @@ def return_tuple(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: tool_call_id=IsStr(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -492,6 +500,7 @@ def return_tuple(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -504,6 +513,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(), ) ) @@ -517,6 +527,7 @@ def return_tuple(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ) ) @@ -1043,6 +1054,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1067,6 +1079,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1091,6 +1104,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1130,6 +1144,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1147,6 +1162,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1322,6 +1338,7 @@ def say_world(_: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1378,6 +1395,7 @@ def call_handoff_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelRes timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1402,6 +1420,7 @@ def call_handoff_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelRes timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1416,6 +1435,7 @@ def call_handoff_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelRes timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1440,6 +1460,7 @@ def call_handoff_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelRes timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1780,6 +1801,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1816,6 +1838,7 @@ class Foo(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1881,6 +1904,7 @@ def return_foo_bar(_: list[ModelMessage], _info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1928,6 +1952,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1952,6 +1977,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2009,6 +2035,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2026,6 +2053,7 @@ def call_tool(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2056,6 +2084,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( @@ -2071,6 +2100,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( @@ -2092,6 +2122,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( @@ -2107,6 +2138,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( @@ -2118,6 +2150,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( @@ -2157,6 +2190,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( @@ -2172,6 +2206,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( @@ -2183,6 +2218,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( @@ -2221,6 +2257,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( @@ -2236,6 +2273,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( @@ -2260,6 +2298,7 @@ async def ret_a(x: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -2273,6 +2312,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( @@ -2288,6 +2328,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( @@ -2306,6 +2347,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 @@ -2313,6 +2355,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( @@ -2331,6 +2374,7 @@ async def ret_a(x: str) -> str: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -2398,6 +2442,7 @@ async def instructions(ctx: RunContext) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), instructions='New instructions', run_id=IsStr(), ), @@ -2441,7 +2486,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')], @@ -2456,6 +2502,7 @@ def test_tool() -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2511,7 +2558,8 @@ def simple_response(_messages: list[ModelMessage], _info: AgentInfo) -> ModelRes content='Hello', timestamp=IsDatetime(), ) - ] + ], + timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[TextPart(content='world')], @@ -2553,6 +2601,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.\ @@ -2590,6 +2639,7 @@ def llm(messages: list[ModelMessage], _info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2601,6 +2651,7 @@ def llm(messages: list[ModelMessage], _info: AgentInfo) -> ModelResponse: ), ModelRequest( parts=[], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2633,6 +2684,7 @@ def llm(messages: list[ModelMessage], _info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2644,6 +2696,7 @@ def llm(messages: list[ModelMessage], _info: AgentInfo) -> ModelResponse: ), ModelRequest( parts=[], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2681,6 +2734,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( @@ -2699,6 +2753,7 @@ def empty(_: list[ModelMessage], _info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2727,6 +2782,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( @@ -2745,6 +2801,7 @@ def empty(m: list[ModelMessage], _info: AgentInfo) -> ModelResponse: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3102,6 +3159,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( @@ -3158,6 +3216,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -3214,6 +3273,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( @@ -3266,6 +3326,7 @@ def deferred_tool(x: int) -> int: # pragma: no cover timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -3384,6 +3445,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( @@ -3405,6 +3467,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3433,6 +3496,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( @@ -3460,6 +3524,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( @@ -3511,6 +3576,7 @@ async def func() -> str: ), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc), part_kind='user-prompt'), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='request', ), @@ -3541,6 +3607,7 @@ async def func() -> str: ), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc), part_kind='user-prompt'), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='request', ), @@ -3554,6 +3621,7 @@ async def func() -> str: ), ModelRequest( parts=[UserPromptPart(content='World', timestamp=IsNow(tz=timezone.utc), part_kind='user-prompt')], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='request', ), @@ -3600,6 +3668,7 @@ async def func(): ), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc), part_kind='user-prompt'), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='request', ), @@ -3631,6 +3700,7 @@ async def func(): ), UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc), part_kind='user-prompt'), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='request', ), @@ -3644,6 +3714,7 @@ async def func(): ), ModelRequest( parts=[UserPromptPart(content='World', timestamp=IsNow(tz=timezone.utc), part_kind='user-prompt')], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='request', ), @@ -3699,6 +3770,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( @@ -3717,6 +3789,7 @@ async def foobar(x: str) -> str: timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3793,6 +3866,7 @@ def test_binary_content_serializable(): 'part_kind': 'user-prompt', } ], + 'timestamp': IsStr(), 'instructions': None, 'kind': 'request', 'run_id': IsStr(), @@ -3855,6 +3929,7 @@ def test_image_url_serializable_missing_media_type(): 'part_kind': 'user-prompt', } ], + 'timestamp': IsStr(), 'instructions': None, 'kind': 'request', 'run_id': IsStr(), @@ -3924,6 +3999,7 @@ def test_image_url_serializable(): 'part_kind': 'user-prompt', } ], + 'timestamp': IsStr(), 'instructions': None, 'kind': 'request', 'run_id': IsStr(), @@ -4046,6 +4122,7 @@ def get_image() -> BinaryContent: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ) ) @@ -4098,6 +4175,7 @@ def get_files(): timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ) ) @@ -4117,6 +4195,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(), ) @@ -4141,6 +4220,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(), ) @@ -4156,6 +4236,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(), ) @@ -4173,6 +4254,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(), ) @@ -4190,6 +4272,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(), ) @@ -4205,10 +4288,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(), ), @@ -4237,6 +4322,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. @@ -4253,6 +4339,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.\ @@ -4265,6 +4352,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.\ """, @@ -4293,7 +4381,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), @@ -4310,6 +4403,7 @@ class Output(BaseModel): timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -4342,6 +4436,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( @@ -4360,6 +4455,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( @@ -4378,6 +4474,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( @@ -4449,6 +4546,7 @@ def foo_tool(foo: Foo) -> int: 'part_kind': 'retry-prompt', } ], + 'timestamp': IsStr(), 'instructions': None, 'kind': 'request', 'run_id': IsStr(), @@ -4521,6 +4619,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( @@ -4555,6 +4654,7 @@ def analyze_data() -> ToolReturn: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4602,6 +4702,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( @@ -4628,6 +4729,7 @@ def analyze_data() -> ToolReturn: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4906,6 +5008,7 @@ def respond(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4924,6 +5027,7 @@ def respond(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4942,6 +5046,7 @@ def respond(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -4997,6 +5102,7 @@ async def only_if_plan_presented( timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5021,6 +5127,7 @@ async def only_if_plan_presented( timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5045,6 +5152,7 @@ async def only_if_plan_presented( timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -5309,6 +5417,7 @@ def model_function(messages: list[ModelMessage], info: AgentInfo) -> ModelRespon timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5326,6 +5435,7 @@ def model_function(messages: list[ModelMessage], info: AgentInfo) -> ModelRespon timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5383,6 +5493,7 @@ def create_file(path: str, content: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5413,6 +5524,7 @@ def create_file(path: str, content: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -5441,6 +5553,7 @@ def create_file(path: str, content: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5471,6 +5584,7 @@ def create_file(path: str, content: str) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelRequest( @@ -5488,6 +5602,7 @@ def create_file(path: str, content: str) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5518,6 +5633,7 @@ def create_file(path: str, content: str) -> str: timestamp=IsDatetime(), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5666,6 +5782,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( @@ -5703,6 +5820,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( @@ -5759,7 +5877,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?')], @@ -5772,6 +5891,7 @@ def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5793,6 +5913,7 @@ def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -5813,7 +5934,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?')], @@ -5826,6 +5948,7 @@ def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6096,6 +6219,7 @@ def roll_dice() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6114,6 +6238,7 @@ def roll_dice() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6138,6 +6263,7 @@ def roll_dice() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6154,6 +6280,7 @@ def roll_dice() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6172,6 +6299,7 @@ def roll_dice() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6196,6 +6324,7 @@ def roll_dice() -> int: timestamp=IsDatetime(), ) ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6301,6 +6430,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 1d3b9991db..dc25ec950f 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(), ), @@ -1433,7 +1434,10 @@ async def hitl_main_loop(prompt: str) -> AgentRunResult[str | DeferredToolReques model_name=IsStr(), timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1453,6 +1457,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(), ), @@ -1473,7 +1478,10 @@ async def hitl_main_loop(prompt: str) -> AgentRunResult[str | DeferredToolReques model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -1535,6 +1543,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(), ), @@ -1564,7 +1573,10 @@ def hitl_main_loop_sync(prompt: str) -> AgentRunResult[str | DeferredToolRequest model_name=IsStr(), timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1584,6 +1596,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(), ), @@ -1604,7 +1617,10 @@ def hitl_main_loop_sync(prompt: str) -> AgentRunResult[str | DeferredToolRequest model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -1642,6 +1658,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( @@ -1665,7 +1682,10 @@ async def test_dbos_agent_with_model_retry(allow_model_requests: None, dbos: DBO model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1679,6 +1699,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( @@ -1702,7 +1723,10 @@ async def test_dbos_agent_with_model_retry(allow_model_requests: None, dbos: DBO model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1716,6 +1740,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( @@ -1733,7 +1758,10 @@ async def test_dbos_agent_with_model_retry(allow_model_requests: None, dbos: DBO model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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 221ad37548..bfe26d7759 100644 --- a/tests/test_mcp.py +++ b/tests/test_mcp.py @@ -225,6 +225,7 @@ async def test_agent_with_stdio_server(allow_model_requests: None, agent: Agent) timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -248,7 +249,10 @@ async def test_agent_with_stdio_server(allow_model_requests: None, agent: Agent) model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -262,6 +266,7 @@ async def test_agent_with_stdio_server(allow_model_requests: None, agent: Agent) timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -279,7 +284,10 @@ async def test_agent_with_stdio_server(allow_model_requests: None, agent: Agent) model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRlnyjUo5wlyqvdNdM5I8vIWjo1qF', finish_reason='stop', run_id=IsStr(), @@ -394,6 +402,7 @@ async def test_tool_returning_str(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -417,7 +426,10 @@ async def test_tool_returning_str(allow_model_requests: None, agent: Agent): model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -431,6 +443,7 @@ async def test_tool_returning_str(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -452,7 +465,10 @@ async def test_tool_returning_str(allow_model_requests: None, agent: Agent): model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRlo41LxqBYgGKWgGrQn67fQacOLp', finish_reason='stop', run_id=IsStr(), @@ -474,6 +490,7 @@ async def test_tool_returning_text_resource(allow_model_requests: None, agent: A timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -497,7 +514,10 @@ async def test_tool_returning_text_resource(allow_model_requests: None, agent: A model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -511,6 +531,7 @@ async def test_tool_returning_text_resource(allow_model_requests: None, agent: A timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -528,7 +549,10 @@ async def test_tool_returning_text_resource(allow_model_requests: None, agent: A model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRmhzqXFObpYwSzREMpJvX9kbDikR', finish_reason='stop', run_id=IsStr(), @@ -550,6 +574,7 @@ async def test_tool_returning_text_resource_link(allow_model_requests: None, age timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -573,7 +598,10 @@ async def test_tool_returning_text_resource_link(allow_model_requests: None, age model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -587,6 +615,7 @@ async def test_tool_returning_text_resource_link(allow_model_requests: None, age timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -604,7 +633,10 @@ async def test_tool_returning_text_resource_link(allow_model_requests: None, age model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BwdHTIlBZWzXJPBR8VTOdC4O57ZQA', finish_reason='stop', run_id=IsStr(), @@ -628,6 +660,7 @@ async def test_tool_returning_image_resource(allow_model_requests: None, agent: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -651,7 +684,10 @@ async def test_tool_returning_image_resource(allow_model_requests: None, agent: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -666,6 +702,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( @@ -687,7 +724,10 @@ async def test_tool_returning_image_resource(allow_model_requests: None, agent: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloBGHh27w3fQKwxq4fX2cPuZJa9', finish_reason='stop', run_id=IsStr(), @@ -713,6 +753,7 @@ async def test_tool_returning_image_resource_link( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -736,7 +777,10 @@ async def test_tool_returning_image_resource_link( model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -751,6 +795,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( @@ -772,7 +817,10 @@ async def test_tool_returning_image_resource_link( model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BwdI2D2r9dvqq3pbsA0qgwKDEdTtD', finish_reason='stop', run_id=IsStr(), @@ -792,6 +840,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( @@ -817,6 +866,7 @@ async def test_tool_returning_audio_resource( ), UserPromptPart(content=['This is file 2d36ae:', audio_content], timestamp=IsDatetime()), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -855,6 +905,7 @@ async def test_tool_returning_audio_resource_link( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -893,6 +944,7 @@ async def test_tool_returning_audio_resource_link( timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -928,6 +980,7 @@ async def test_tool_returning_image(allow_model_requests: None, agent: Agent, im timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -951,7 +1004,10 @@ async def test_tool_returning_image(allow_model_requests: None, agent: Agent, im model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -972,6 +1028,7 @@ async def test_tool_returning_image(allow_model_requests: None, agent: Agent, im timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -989,7 +1046,10 @@ async def test_tool_returning_image(allow_model_requests: None, agent: Agent, im model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloJHR654fSD0fcvLWZxtKtn0pag', finish_reason='stop', run_id=IsStr(), @@ -1011,6 +1071,7 @@ async def test_tool_returning_dict(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1028,7 +1089,10 @@ async def test_tool_returning_dict(allow_model_requests: None, agent: Agent): model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1042,6 +1106,7 @@ async def test_tool_returning_dict(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1059,7 +1124,10 @@ async def test_tool_returning_dict(allow_model_requests: None, agent: Agent): model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloPczU1HSCWnreyo21DdNtdOM7L', finish_reason='stop', run_id=IsStr(), @@ -1081,6 +1149,7 @@ async def test_tool_returning_unstructured_dict(allow_model_requests: None, agen timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1102,7 +1171,10 @@ async def test_tool_returning_unstructured_dict(allow_model_requests: None, agen model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1116,6 +1188,7 @@ async def test_tool_returning_unstructured_dict(allow_model_requests: None, agen timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1133,7 +1206,10 @@ async def test_tool_returning_unstructured_dict(allow_model_requests: None, agen model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-CLbPAOYN3jPYdvYeD8JNOOXF5N554', finish_reason='stop', run_id=IsStr(), @@ -1157,6 +1233,7 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1180,7 +1257,10 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1194,6 +1274,7 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1217,7 +1298,10 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1231,6 +1315,7 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1252,7 +1337,10 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloU3MhnqNEqujs28a3ofRbs7VPF', finish_reason='stop', run_id=IsStr(), @@ -1274,6 +1362,7 @@ async def test_tool_returning_none(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1291,7 +1380,10 @@ async def test_tool_returning_none(allow_model_requests: None, agent: Agent): model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1305,6 +1397,7 @@ async def test_tool_returning_none(allow_model_requests: None, agent: Agent): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1322,7 +1415,10 @@ async def test_tool_returning_none(allow_model_requests: None, agent: Agent): model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloYWGujk8yE94gfVSsM1T1Ol2Ej', finish_reason='stop', run_id=IsStr(), @@ -1346,6 +1442,7 @@ async def test_tool_returning_multiple_items(allow_model_requests: None, agent: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1369,7 +1466,10 @@ async def test_tool_returning_multiple_items(allow_model_requests: None, agent: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1395,6 +1495,7 @@ async def test_tool_returning_multiple_items(allow_model_requests: None, agent: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1416,7 +1517,10 @@ async def test_tool_returning_multiple_items(allow_model_requests: None, agent: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - provider_details={'finish_reason': 'stop'}, + provider_details={ + 'finish_reason': 'stop', + 'timestamp': IsDatetime(), + }, provider_response_id='chatcmpl-BRloepWR5NJpTgSqFBGTSPeM1SWm8', finish_reason='stop', run_id=IsStr(), @@ -1501,7 +1605,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 d6d9617247..2189a50148 100644 --- a/tests/test_messages.py +++ b/tests/test_messages.py @@ -416,7 +416,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 0c6a46f3c0..17ddfc6f1f 100644 --- a/tests/test_streaming.py +++ b/tests/test_streaming.py @@ -1,6 +1,5 @@ from __future__ import annotations as _annotations -import datetime import json import re from collections.abc import AsyncIterable, AsyncIterator @@ -73,6 +72,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -89,6 +89,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=IsDatetime(), run_id=IsStr(), ), ] @@ -109,6 +110,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -125,6 +127,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=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -165,6 +168,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -181,6 +185,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=IsDatetime(), run_id=IsStr(), ), ] @@ -211,6 +216,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='Hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -227,6 +233,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=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -589,6 +596,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -607,6 +615,7 @@ async def ret_a(x: str) -> str: tool_call_id=IsStr(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -616,6 +625,7 @@ async def ret_a(x: str) -> str: [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -634,6 +644,7 @@ async def ret_a(x: str) -> str: tool_call_id=IsStr(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -658,6 +669,7 @@ async def ret_a(x: str) -> str: tool_call_id=IsStr(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -689,6 +701,7 @@ async def stream_structured_function( timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -698,7 +711,11 @@ async def stream_structured_function( timestamp=IsDatetime(), run_id=IsStr(), ), - ModelRequest(parts=[], run_id=IsStr()), + ModelRequest( + parts=[], + timestamp=IsDatetime(), + run_id=IsStr(), + ), ModelResponse( parts=[TextPart(content='ok here is text')], usage=RequestUsage(input_tokens=50, output_tokens=4), @@ -733,6 +750,7 @@ async def ret_a(x: str) -> str: # pragma: no cover [ ModelRequest( parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -789,6 +807,7 @@ def another_tool(y: int) -> int: # pragma: no cover [ ModelRequest( parts=[UserPromptPart(content='test early strategy', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -823,6 +842,7 @@ def another_tool(y: int) -> int: # pragma: no cover tool_call_id=IsStr(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -849,6 +869,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=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -876,6 +897,7 @@ async def sf(_: list[ModelMessage], info: AgentInfo) -> AsyncIterator[str | Delt tool_call_id=IsStr(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -918,6 +940,7 @@ def another_tool(y: int) -> int: [ ModelRequest( parts=[UserPromptPart(content='test exhaustive strategy', timestamp=IsNow(tz=timezone.utc))], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -960,6 +983,7 @@ def another_tool(y: int) -> int: timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -1006,10 +1030,11 @@ def another_tool(y: int) -> int: # pragma: no cover parts=[ UserPromptPart( content='test early strategy with final result in middle', - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), part_kind='user-prompt', ) ], + timestamp=IsDatetime(), run_id=IsStr(), kind='request', ), @@ -1042,7 +1067,7 @@ def another_tool(y: int) -> int: # pragma: no cover ], usage=RequestUsage(input_tokens=50, output_tokens=14), model_name='function::sf', - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='response', ), @@ -1052,31 +1077,32 @@ def another_tool(y: int) -> int: # pragma: no cover tool_name='final_result', content='Final result processed.', tool_call_id=IsStr(), - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), part_kind='tool-return', ), ToolReturnPart( tool_name='regular_tool', content='Tool not executed - a final result was already processed.', tool_call_id=IsStr(), - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), part_kind='tool-return', ), ToolReturnPart( tool_name='another_tool', content='Tool not executed - a final result was already processed.', tool_call_id=IsStr(), - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), part_kind='tool-return', ), RetryPromptPart( content="Unknown tool name: 'unknown_tool'. Available tools: 'final_result', 'regular_tool', 'another_tool'", tool_name='unknown_tool', tool_call_id=IsStr(), - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), part_kind='retry-prompt', ), ], + timestamp=IsDatetime(), run_id=IsStr(), kind='request', ), @@ -1139,10 +1165,11 @@ def regular_tool(x: int) -> int: # pragma: no cover parts=[ UserPromptPart( content='test early strategy with external tool call', - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), part_kind='user-prompt', ) ], + timestamp=IsDatetime(), run_id=IsStr(), kind='request', ), @@ -1162,7 +1189,7 @@ def regular_tool(x: int) -> int: # pragma: no cover ], usage=RequestUsage(input_tokens=50, output_tokens=7), model_name='function::sf', - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='response', ), @@ -1172,15 +1199,16 @@ def regular_tool(x: int) -> int: # pragma: no cover tool_name='final_result', content='Output tool not used - a final result was already processed.', tool_call_id=IsStr(), - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), ), ToolReturnPart( tool_name='regular_tool', content='Tool not executed - a final result was already processed.', tool_call_id=IsStr(), - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsDatetime(), run_id=IsStr(), kind='request', ), @@ -1228,10 +1256,11 @@ def regular_tool(x: int) -> int: parts=[ UserPromptPart( content='test early strategy with external tool call', - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), part_kind='user-prompt', ) ], + timestamp=IsDatetime(), run_id=IsStr(), kind='request', ), @@ -1246,7 +1275,7 @@ def regular_tool(x: int) -> int: ], usage=RequestUsage(input_tokens=50, output_tokens=3), model_name='function::sf', - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), kind='response', ), @@ -1256,9 +1285,10 @@ def regular_tool(x: int) -> int: tool_name='regular_tool', content=1, tool_call_id=IsStr(), - timestamp=IsNow(tz=datetime.timezone.utc), + timestamp=IsNow(tz=timezone.utc), ) ], + timestamp=IsDatetime(), run_id=IsStr(), kind='request', ), @@ -1292,6 +1322,7 @@ def regular_tool(x: int) -> int: content='test early strategy with regular tool calls', timestamp=IsNow(tz=timezone.utc) ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1308,6 +1339,7 @@ def regular_tool(x: int) -> int: tool_name='regular_tool', content=0, timestamp=IsNow(tz=timezone.utc), tool_call_id=IsStr() ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1327,6 +1359,7 @@ def regular_tool(x: int) -> int: tool_call_id=IsStr(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -1774,6 +1807,7 @@ def my_tool(ctx: RunContext[None], x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1792,6 +1826,7 @@ def my_tool(ctx: RunContext[None], x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( diff --git a/tests/test_temporal.py b/tests/test_temporal.py index 98039d9078..91697f5c4b 100644 --- a/tests/test_temporal.py +++ b/tests/test_temporal.py @@ -1827,6 +1827,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(), ), @@ -1856,7 +1859,7 @@ async def test_temporal_agent_with_hitl_tool(allow_model_requests: None, client: model_name=IsStr(), timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1876,6 +1879,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(), ), @@ -1898,7 +1902,7 @@ async def test_temporal_agent_with_hitl_tool(allow_model_requests: None, client: model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1952,6 +1956,7 @@ async def test_temporal_agent_with_model_retry(allow_model_requests: None, clien timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1975,7 +1980,7 @@ async def test_temporal_agent_with_model_retry(allow_model_requests: None, clien model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -1989,6 +1994,7 @@ async def test_temporal_agent_with_model_retry(allow_model_requests: None, clien timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2012,7 +2018,7 @@ async def test_temporal_agent_with_model_retry(allow_model_requests: None, clien model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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(), @@ -2026,6 +2032,7 @@ async def test_temporal_agent_with_model_retry(allow_model_requests: None, clien timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2043,7 +2050,7 @@ async def test_temporal_agent_with_model_retry(allow_model_requests: None, clien model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), provider_name='openai', - 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 bcdf537994..8e11d30d8b 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -1364,6 +1364,7 @@ def my_tool(ctx: RunContext[None], x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1382,6 +1383,7 @@ def my_tool(ctx: RunContext[None], x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1755,6 +1757,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1809,6 +1812,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -1848,6 +1852,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1902,6 +1907,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelRequest( @@ -1930,6 +1936,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1970,6 +1977,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -1991,6 +1999,7 @@ def buy(fruit: str): timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2067,7 +2076,8 @@ def buy(fruit: str): content='I bought a banana', timestamp=IsDatetime(), ), - ] + ], + timestamp=IsDatetime(), ), ] ) @@ -2148,6 +2158,7 @@ def bar(x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2170,6 +2181,7 @@ def bar(x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ] @@ -2201,6 +2213,7 @@ def bar(x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2223,6 +2236,7 @@ def bar(x: int) -> int: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelRequest( @@ -2240,6 +2254,7 @@ def bar(x: int) -> int: timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2387,6 +2402,7 @@ def always_fail(ctx: RunContext[None]) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2405,6 +2421,7 @@ def always_fail(ctx: RunContext[None]) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2423,6 +2440,7 @@ def always_fail(ctx: RunContext[None]) -> str: timestamp=IsDatetime(), ) ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -2441,6 +2459,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 9ac6137e8c..e849e253fb 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 de6d98995fc52622c1c5c57eb85b632ab8f6eb8a 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 03/23] 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 | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/models/test_gemini_vertex.py b/tests/models/test_gemini_vertex.py index 20e2e5e0dc..b91fb8403e 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,8 +149,10 @@ async def test_url_input( usage=IsInstance(RequestUsage), model_name='gemini-2.0-flash', timestamp=IsDatetime(), + provider_name='google-vertex', provider_details={'finish_reason': 'STOP'}, provider_response_id=IsStr(), + finish_reason='stop', run_id=IsStr(), ), ] @@ -180,6 +183,7 @@ async def test_url_input_force_download(allow_model_requests: None) -> None: # timestamp=IsDatetime(), ), ], + timestamp=IsDatetime(), run_id=IsStr(), ), ModelResponse( @@ -187,8 +191,10 @@ 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_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 8f6428ffe7..03844965c7 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -2354,6 +2354,7 @@ async def test_google_url_input( timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2396,6 +2397,7 @@ async def test_google_url_input_force_download( timestamp=IsNow(tz=timezone.utc), ), ], + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2403,9 +2405,9 @@ async def test_google_url_input_force_download( usage=IsInstance(RequestUsage), model_name='gemini-2.0-flash', timestamp=IsDatetime(), + provider_name='google-vertex', provider_details={'finish_reason': 'STOP'}, provider_response_id=IsStr(), - provider_name='google-vertex', finish_reason='stop', run_id=IsStr(), ), From 97cad0557c7d607c3c69518f543b367498615947 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 04/23] fix tests --- tests/models/test_gemini_vertex.py | 4 ---- tests/models/test_google.py | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/models/test_gemini_vertex.py b/tests/models/test_gemini_vertex.py index b91fb8403e..23598389c4 100644 --- a/tests/models/test_gemini_vertex.py +++ b/tests/models/test_gemini_vertex.py @@ -149,10 +149,8 @@ async def test_url_input( usage=IsInstance(RequestUsage), model_name='gemini-2.0-flash', timestamp=IsDatetime(), - provider_name='google-vertex', provider_details={'finish_reason': 'STOP'}, provider_response_id=IsStr(), - finish_reason='stop', run_id=IsStr(), ), ] @@ -191,10 +189,8 @@ 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_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 03844965c7..b135a51fe5 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -2363,7 +2363,7 @@ async def test_google_url_input( model_name='gemini-2.0-flash', timestamp=IsDatetime(), provider_name='google-vertex', - provider_details={'finish_reason': 'STOP'}, + provider_details={'finish_reason': 'STOP', 'timestamp': IsDatetime()}, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), @@ -2406,7 +2406,7 @@ async def test_google_url_input_force_download( model_name='gemini-2.0-flash', timestamp=IsDatetime(), provider_name='google-vertex', - provider_details={'finish_reason': 'STOP'}, + provider_details={'finish_reason': 'STOP', 'timestamp': IsDatetime()}, provider_response_id=IsStr(), finish_reason='stop', run_id=IsStr(), From e0413980689a57622c9c7747084d2d81df6a365b 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 05/23] 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 6930b7f814..d04c7dbfe5 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -676,7 +676,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 8a27d8ce18..0fc6623d1e 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -547,7 +547,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 dd9d2a706a..a510ca3cb1 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -481,7 +481,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 44179c6b5d..c3d567a3c0 100644 --- a/pydantic_ai_slim/pydantic_ai/models/mistral.py +++ b/pydantic_ai_slim/pydantic_ai/models/mistral.py @@ -629,7 +629,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 ed199ca2da41152ff79cf0780f70c2fd97767e1f 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 06/23] 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 d04c7dbfe5..596a82e48f 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -674,12 +674,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 0fc6623d1e..991a4d9b79 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -545,12 +545,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 a510ca3cb1..56b8410c02 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -479,16 +479,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 c3d567a3c0..21b291dca9 100644 --- a/pydantic_ai_slim/pydantic_ai/models/mistral.py +++ b/pydantic_ai_slim/pydantic_ai/models/mistral.py @@ -627,12 +627,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 afe639c776..65e03cb286 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openrouter.py +++ b/pydantic_ai_slim/pydantic_ai/models/openrouter.py @@ -645,7 +645,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 47af45ec0847a14faf075521d7f215365d575f94 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 07/23] 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 a8d085b018..1e37b4cb20 100644 --- a/tests/models/test_groq.py +++ b/tests/models/test_groq.py @@ -537,6 +537,7 @@ async def test_stream_structured(allow_model_requests: None): model_name='llama-3.3-70b-versatile', timestamp=IsDatetime(), provider_name='groq', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='x', run_id=IsStr(), ), @@ -5531,6 +5532,7 @@ async def get_something_by_name(name: str) -> str: model_name='openai/gpt-oss-120b', timestamp=IsDatetime(), provider_name='groq', + 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 f9efa8ac24a3153bd3082fb8be44cf80af3a2407 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 08/23] 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 596a82e48f..26efd4ddab 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -678,7 +678,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 991a4d9b79..0dcf1c2e17 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -549,7 +549,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 56b8410c02..866bc68775 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -485,7 +485,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 21b291dca9..aa2e809ee0 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['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 65e03cb286..8c94d2dd1e 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openrouter.py +++ b/pydantic_ai_slim/pydantic_ai/models/openrouter.py @@ -638,7 +638,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 7722ee94af2b99eab34948e4b970c2b168b77abc 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 09/23] 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 26efd4ddab..c3d3f840bb 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -678,8 +678,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 0dcf1c2e17..17fdfd1998 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]: 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 866bc68775..d318a3c47f 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -487,7 +487,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 aa2e809ee0..f2490d367a 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]: 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 bf1c640ab2598da1737c506e1ff3d49abcb761c1 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 10/23] 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 c3d3f840bb..a62f74617b 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -679,6 +679,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 76aad15f1b4e57bbaea6bcc749fdf5aec90d6ab6 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 11/23] - 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 | 3 +- 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, 220 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 bd82d74473..36f08053ba 100644 --- a/pydantic_ai_slim/pydantic_ai/_agent_graph.py +++ b/pydantic_ai_slim/pydantic_ai/_agent_graph.py @@ -229,7 +229,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)] @@ -273,7 +273,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 @@ -627,7 +627,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 @@ -695,7 +695,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() @@ -737,7 +737,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( @@ -772,7 +772,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) @@ -1325,8 +1325,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 f00230ee07..5a387e2335 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 f9ba1591c8..40bb14ebac 100644 --- a/pydantic_ai_slim/pydantic_ai/agent/abstract.py +++ b/pydantic_ai_slim/pydantic_ai/agent/abstract.py @@ -559,7 +559,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 3e14133866..65f5787f7a 100644 --- a/pydantic_ai_slim/pydantic_ai/messages.py +++ b/pydantic_ai_slim/pydantic_ai/messages.py @@ -994,7 +994,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 @@ -1012,7 +1012,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 ecdb9fe61f..25db377c60 100644 --- a/pydantic_ai_slim/pydantic_ai/models/anthropic.py +++ b/pydantic_ai_slim/pydantic_ai/models/anthropic.py @@ -528,6 +528,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, finish_reason=finish_reason, @@ -548,7 +549,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, ) @@ -1090,9 +1090,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 a62f74617b..876c813ad4 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -486,15 +486,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( @@ -512,7 +514,7 @@ def _process_response(self, response: GenerateContentResponse) -> ModelResponse: self._provider.name, 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, ) @@ -530,7 +532,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, @@ -655,10 +656,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 @@ -933,6 +934,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 17fdfd1998..ac2b4d7593 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -320,7 +320,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: @@ -348,7 +347,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, finish_reason=finish_reason, @@ -371,7 +370,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_timestamp=first_chunk.created, ) @@ -525,9 +523,9 @@ class GroqStreamedResponse(StreamedResponse): _model_name: GroqModelName _model_profile: ModelProfile _response: AsyncIterable[chat.ChatCompletionChunk] - _timestamp: datetime _provider_name: 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 d318a3c47f..560b5fc5bb 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -314,7 +314,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_timestamp=first_chunk.created, ) @@ -463,9 +462,9 @@ class HuggingFaceStreamedResponse(StreamedResponse): _model_name: str _model_profile: ModelProfile _response: AsyncIterable[ChatCompletionStreamOutput] - _timestamp: datetime _provider_name: 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 f2490d367a..1f7e0448b5 100644 --- a/pydantic_ai_slim/pydantic_ai/models/mistral.py +++ b/pydantic_ai_slim/pydantic_ai/models/mistral.py @@ -400,7 +400,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_timestamp=first_chunk.data.created, ) @@ -608,9 +607,9 @@ class MistralStreamedResponse(StreamedResponse): _model_name: MistralModelName _response: AsyncIterable[MistralCompletionEvent] - _timestamp: datetime _provider_name: str _provider_timestamp: int | None = None + _timestamp: datetime = field(default_factory=_now_utc) _delta_content: str = field(default='', init=False) diff --git a/pydantic_ai_slim/pydantic_ai/models/openai.py b/pydantic_ai_slim/pydantic_ai/models/openai.py index 8b464525ce..b86b0d2e99 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -674,7 +674,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, @@ -1254,7 +1253,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 @@ -1842,10 +1840,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(): @@ -1998,10 +1996,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 e2f16ffa0d..bf1c638d5c 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 @@ -505,6 +505,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( @@ -516,13 +517,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', ) @@ -542,8 +541,8 @@ class OutlinesStreamedResponse(StreamedResponse): _model_name: str _model_profile: ModelProfile _response: AsyncIterable[str] - _timestamp: datetime _provider_name: str + _timestamp: datetime = field(default_factory=_utils.now_utc) async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: async for event 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 1bc761a91e..8ba506ba27 100644 --- a/tests/models/test_anthropic.py +++ b/tests/models/test_anthropic.py @@ -2502,7 +2502,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'), ], ) @@ -4708,7 +4708,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( @@ -6174,14 +6174,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( @@ -6190,9 +6192,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 3894cf3362..b008a87388 100644 --- a/tests/models/test_bedrock.py +++ b/tests/models/test_bedrock.py @@ -811,9 +811,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')]), ], ) @@ -1329,16 +1334,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(), ), ] @@ -1458,7 +1464,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 b135a51fe5..09692479cd 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -970,9 +970,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')]), ], ) @@ -1906,7 +1911,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='')]), ], ) @@ -4313,7 +4318,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 fd9198d603..6d0ca4a010 100644 --- a/tests/models/test_huggingface.py +++ b/tests/models/test_huggingface.py @@ -892,7 +892,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 b6a52e0c25..841e81e008 100644 --- a/tests/models/test_instrumented.py +++ b/tests/models/test_instrumented.py @@ -45,7 +45,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 @@ -153,7 +153,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')]), ] @@ -364,7 +365,7 @@ async def test_instrumented_model_not_recording(): InstrumentationSettings(tracer_provider=NoOpTracerProvider(), event_logger_provider=NoOpEventLoggerProvider()), ) - 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), @@ -386,7 +387,8 @@ async def test_instrumented_model_stream(capfire: CaptureLogfire): ModelRequest( parts=[ UserPromptPart('user_prompt'), - ] + ], + timestamp=IsDatetime(), ), ] async with model.request_stream( @@ -489,7 +491,8 @@ async def test_instrumented_model_stream_break(capfire: CaptureLogfire): ModelRequest( parts=[ UserPromptPart('user_prompt'), - ] + ], + timestamp=IsDatetime(), ), ] @@ -613,6 +616,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')]), ] @@ -993,7 +997,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() @@ -1032,7 +1036,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() @@ -1058,9 +1062,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( @@ -1087,10 +1091,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( @@ -1102,9 +1118,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)]), ] @@ -1244,7 +1261,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( @@ -1272,7 +1289,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=[ @@ -1286,13 +1303,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) @@ -1466,7 +1487,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( @@ -1625,7 +1646,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() @@ -1647,7 +1670,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( @@ -1676,7 +1700,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 746d2c9626..4eafd380a9 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -1953,6 +1953,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=[ @@ -1968,6 +1969,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=[ @@ -1995,6 +1997,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=[ @@ -2010,6 +2013,7 @@ async def test_openai_previous_response_id_mixed_model_history(allow_model_reque content='what is the first secret key?', ), ], + timestamp=IsDatetime(), ), ] @@ -2047,6 +2051,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=[ @@ -2062,6 +2067,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=[ @@ -2077,6 +2083,7 @@ async def test_openai_previous_response_id_same_model_history(allow_model_reques content='what is the first secret key?', ), ], + timestamp=IsDatetime(), ), ] @@ -6743,7 +6750,8 @@ class CityLocation(BaseModel): UserPromptPart( content='What is the largest city in the user country?', ) - ] + ], + timestamp=IsDatetime(), ), ModelResponse( parts=[ @@ -6765,7 +6773,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 0fe093a738..c59a736044 100644 --- a/tests/models/test_outlines.py +++ b/tests/models/test_outlines.py @@ -548,7 +548,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=[ @@ -570,7 +571,8 @@ def test_input_format(transformers_multimodal_model: OutlinesModel, binary_image AudioUrl('https://example.com/audio.mp3'), ] ) - ] + ], + timestamp=IsDatetime(), ) ] with pytest.raises( @@ -581,14 +583,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 62650edf32..36ff2d683d 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -2415,6 +2415,7 @@ async def system_prompt(ctx: RunContext) -> str: UserPromptPart(content='How goes it?'), ], instructions='Original instructions', + timestamp=IsDatetime(), ), ] @@ -2472,7 +2473,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')]), ] @@ -2527,7 +2528,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')]), ] @@ -2545,7 +2546,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')]), ] @@ -2582,15 +2583,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?')]), ] @@ -3745,7 +3746,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]) @@ -4283,7 +4286,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( [ @@ -5650,7 +5655,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, @@ -5663,7 +5670,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!')]), ] @@ -5678,7 +5685,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')]), ] @@ -5700,7 +5707,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'), @@ -5712,7 +5719,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(), ), ] @@ -5860,7 +5868,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?')]), ] @@ -6384,7 +6392,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')]), ] @@ -6404,7 +6412,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 dadb930dd0..d48eeae93b 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 @@ -2738,7 +2738,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 2189a50148..2730dae9ce 100644 --- a/tests/test_messages.py +++ b/tests/test_messages.py @@ -499,6 +499,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 0e4500acdb89144beea0f8b7fedfefcac31427be 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 12/23] ModelRequest.timestamp=None by default for backwards compat --- pydantic_ai_slim/pydantic_ai/messages.py | 2 +- tests/models/test_openai_responses.py | 286 +++++++++++------------ tests/test_agent.py | 59 ++--- tests/test_history_processor.py | 126 ++++------ tests/test_messages.py | 2 - 5 files changed, 202 insertions(+), 273 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/messages.py b/pydantic_ai_slim/pydantic_ai/messages.py index 65f5787f7a..b1eaf88ce4 100644 --- a/pydantic_ai_slim/pydantic_ai/messages.py +++ b/pydantic_ai_slim/pydantic_ai/messages.py @@ -994,7 +994,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 4eafd380a9..28a507f460 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -1,7 +1,7 @@ -import datetime import json import re from dataclasses import replace +from datetime import datetime, timezone from typing import Any, cast import pytest @@ -49,7 +49,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: @@ -249,7 +249,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -273,7 +273,7 @@ async def get_location(loc_name: str) -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 3, 27, 12, 42, 44, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 3, 27, 12, 42, 44, tzinfo=timezone.utc), }, provider_response_id='resp_67e547c48c9481918c5c4394464ce0c60ae6111e84dd5c08', finish_reason='stop', @@ -294,7 +294,7 @@ async def get_location(loc_name: str) -> str: timestamp=IsDatetime(), ), ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -314,7 +314,7 @@ async def get_location(loc_name: str) -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 3, 27, 12, 42, 45, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 3, 27, 12, 42, 45, tzinfo=timezone.utc), }, provider_response_id='resp_67e547c5a2f08191802a1f43620f348503a2086afed73b47', finish_reason='stop', @@ -345,7 +345,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -363,7 +363,7 @@ async def get_image() -> BinaryContent: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 4, 29, 20, 21, 39, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 4, 29, 20, 21, 39, tzinfo=timezone.utc), }, provider_response_id='resp_681134d3aa3481919ca581a267db1e510fe7a5a4e2123dc3', finish_reason='stop', @@ -385,7 +385,7 @@ async def get_image() -> BinaryContent: timestamp=IsDatetime(), ), ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -401,7 +401,7 @@ async def get_image() -> BinaryContent: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 4, 29, 20, 21, 41, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 4, 29, 20, 21, 41, tzinfo=timezone.utc), }, provider_response_id='resp_681134d53c48819198ce7b89db78dffd02cbfeaababb040c', finish_reason='stop', @@ -506,7 +506,7 @@ async def get_capital(country: str) -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 3, 27, 13, 37, 38, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 3, 27, 13, 37, 38, tzinfo=timezone.utc), }, provider_response_id='resp_67e554a21aa88191b65876ac5e5bbe0406c52f0e511c76ed', finish_reason='stop', @@ -541,7 +541,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( @@ -688,7 +688,7 @@ async def test_openai_responses_model_builtin_tools_web_search(allow_model_reque provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 12, 23, 19, 54, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 12, 23, 19, 54, tzinfo=timezone.utc), }, provider_response_id='resp_0e3d55e9502941380068c4aa9a62f48195a373978ed720ac63', finish_reason='stop', @@ -708,7 +708,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(), ), @@ -725,7 +725,7 @@ async def test_openai_responses_model_instructions(allow_model_requests: None, o provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 4, 7, 16, 31, 57, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 4, 7, 16, 31, 57, tzinfo=timezone.utc), }, provider_response_id='resp_67f3fdfd9fa08191a3d5825db81b8df6003bc73febb56d77', finish_reason='stop', @@ -749,7 +749,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(), ), @@ -793,7 +793,7 @@ async def test_openai_responses_model_web_search_tool(allow_model_requests: None provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 16, 20, 27, 26, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 16, 20, 27, 26, tzinfo=timezone.utc), }, provider_response_id='resp_028829e50fbcad090068c9c82e1e0081958ddc581008b39428', finish_reason='stop', @@ -813,7 +813,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(), ), @@ -857,7 +857,7 @@ async def test_openai_responses_model_web_search_tool(allow_model_requests: None provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 16, 20, 27, 39, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 16, 20, 27, 39, tzinfo=timezone.utc), }, provider_response_id='resp_028829e50fbcad090068c9c83b9fb88195b6b84a32e1fc83c0', finish_reason='stop', @@ -887,7 +887,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(), ), @@ -931,7 +931,7 @@ async def test_openai_responses_model_web_search_tool_with_user_location( provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 12, 23, 21, 23, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 12, 23, 21, 23, tzinfo=timezone.utc), }, provider_response_id='resp_0b385a0fdc82fd920068c4aaf3ced88197a88711e356b032c4', finish_reason='stop', @@ -962,7 +962,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(), ), @@ -1006,7 +1006,7 @@ async def test_openai_responses_model_web_search_tool_with_invalid_region( provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 12, 23, 21, 47, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 12, 23, 21, 47, tzinfo=timezone.utc), }, provider_response_id='resp_0b4f29854724a3120068c4ab0b660081919707b95b47552782', finish_reason='stop', @@ -1044,7 +1044,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(), ), @@ -1094,7 +1094,7 @@ async def test_openai_responses_model_web_search_tool_stream(allow_model_request provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 16, 21, 13, 32, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 16, 21, 13, 32, tzinfo=timezone.utc), }, provider_response_id='resp_00a60507bf41223d0068c9d2fbf93481a0ba2a7796ae2cab4c', finish_reason='stop', @@ -1267,7 +1267,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 provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 16, 21, 13, 57, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 16, 21, 13, 57, tzinfo=timezone.utc), }, provider_response_id='resp_00a60507bf41223d0068c9d31574d881a090c232646860a771', finish_reason='stop', @@ -1411,7 +1411,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1429,7 +1429,7 @@ async def get_user_country() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 43, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 6, 10, 0, 40, 43, tzinfo=timezone.utc), }, provider_response_id='resp_68477f0b40a8819cb8d55594bc2c232a001fd29e2d5573f7', finish_reason='stop', @@ -1444,7 +1444,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1462,7 +1462,7 @@ async def get_user_country() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 44, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 6, 10, 0, 40, 44, tzinfo=timezone.utc), }, provider_response_id='resp_68477f0bfda8819ea65458cd7cc389b801dc81d4bc91f560', finish_reason='stop', @@ -1477,7 +1477,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -1509,7 +1509,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1527,7 +1527,7 @@ async def get_user_country() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 45, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 6, 10, 0, 40, 45, tzinfo=timezone.utc), }, provider_response_id='resp_68477f0d9494819ea4f123bba707c9ee0356a60c98816d6a', finish_reason='stop', @@ -1542,7 +1542,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1558,7 +1558,7 @@ async def get_user_country() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 46, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 6, 10, 0, 40, 46, tzinfo=timezone.utc), }, provider_response_id='resp_68477f0e2b28819d9c828ef4ee526d6a03434b607c02582d', finish_reason='stop', @@ -1596,7 +1596,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1614,7 +1614,7 @@ async def get_user_country() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 47, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 6, 10, 0, 40, 47, tzinfo=timezone.utc), }, provider_response_id='resp_68477f0f220081a1a621d6bcdc7f31a50b8591d9001d2329', finish_reason='stop', @@ -1629,7 +1629,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1645,7 +1645,7 @@ async def get_user_country() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 47, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 6, 10, 0, 40, 47, tzinfo=timezone.utc), }, provider_response_id='resp_68477f0fde708192989000a62809c6e5020197534e39cc1f', finish_reason='stop', @@ -1685,7 +1685,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1703,7 +1703,7 @@ async def get_user_country() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 48, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 6, 10, 0, 40, 48, tzinfo=timezone.utc), }, provider_response_id='resp_68477f10f2d081a39b3438f413b3bafc0dd57d732903c563', finish_reason='stop', @@ -1718,7 +1718,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1734,7 +1734,7 @@ async def get_user_country() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 6, 10, 0, 40, 49, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 6, 10, 0, 40, 49, tzinfo=timezone.utc), }, provider_response_id='resp_68477f119830819da162aa6e10552035061ad97e2eef7871', finish_reason='stop', @@ -1770,7 +1770,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1788,7 +1788,7 @@ async def get_user_country() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 6, 10, 13, 11, 46, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 6, 10, 13, 11, 46, tzinfo=timezone.utc), }, provider_response_id='resp_68482f12d63881a1830201ed101ecfbf02f8ef7f2fb42b50', finish_reason='stop', @@ -1803,7 +1803,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1819,7 +1819,7 @@ async def get_user_country() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 6, 10, 13, 11, 55, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 6, 10, 13, 11, 55, tzinfo=timezone.utc), }, provider_response_id='resp_68482f1b556081918d64c9088a470bf0044fdb7d019d4115', finish_reason='stop', @@ -1859,7 +1859,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1877,7 +1877,7 @@ async def get_user_country() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 6, 10, 13, 11, 57, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 6, 10, 13, 11, 57, tzinfo=timezone.utc), }, provider_response_id='resp_68482f1d38e081a1ac828acda978aa6b08e79646fe74d5ee', finish_reason='stop', @@ -1892,7 +1892,7 @@ async def get_user_country() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -1908,7 +1908,7 @@ async def get_user_country() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 6, 10, 13, 12, 8, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 6, 10, 13, 12, 8, tzinfo=timezone.utc), }, provider_response_id='resp_68482f28c1b081a1ae73cbbee012ee4906b4ab2d00d03024', finish_reason='stop', @@ -1953,7 +1953,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=[ @@ -1969,7 +1968,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=[ @@ -1997,7 +1995,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=[ @@ -2013,7 +2010,6 @@ async def test_openai_previous_response_id_mixed_model_history(allow_model_reque content='what is the first secret key?', ), ], - timestamp=IsDatetime(), ), ] @@ -2022,10 +2018,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(), @@ -2034,10 +2027,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())]), ] ) @@ -2051,7 +2041,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=[ @@ -2067,7 +2056,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=[ @@ -2083,7 +2071,6 @@ async def test_openai_previous_response_id_same_model_history(allow_model_reques content='what is the first secret key?', ), ], - timestamp=IsDatetime(), ), ] @@ -2092,10 +2079,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())]), ] ) @@ -2128,7 +2112,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( @@ -2137,7 +2121,7 @@ async def test_openai_responses_usage_without_tokens_details(allow_model_request model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', - provider_details={'timestamp': datetime.datetime(2024, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)}, + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -2159,7 +2143,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( @@ -2186,7 +2170,7 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 12, 14, 22, 8, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 12, 14, 22, 8, tzinfo=timezone.utc), }, provider_response_id='resp_68c42c902794819cb9335264c342f65407460311b0c8d3de', finish_reason='stop', @@ -2208,7 +2192,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( @@ -2234,7 +2218,7 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 12, 14, 22, 43, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 12, 14, 22, 43, tzinfo=timezone.utc), }, provider_response_id='resp_68c42cb3d520819c9d28b07036e9059507460311b0c8d3de', finish_reason='stop', @@ -2264,7 +2248,7 @@ async def test_openai_responses_thinking_part_from_other_model( timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2315,7 +2299,7 @@ async def test_openai_responses_thinking_part_from_other_model( timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -2339,7 +2323,7 @@ async def test_openai_responses_thinking_part_from_other_model( provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 12, 14, 23, 30, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 12, 14, 23, 30, tzinfo=timezone.utc), }, provider_response_id='resp_68c42ce277ac8193ba08881bcefabaf70ad492c7955fc6fc', finish_reason='stop', @@ -2372,7 +2356,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( @@ -2406,7 +2390,7 @@ async def test_openai_responses_thinking_part_iter(allow_model_requests: None, o provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 12, 14, 24, 15, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 12, 14, 24, 15, tzinfo=timezone.utc), }, provider_response_id='resp_68c42d0fb418819dbfa579f69406b49508fbf9b1584184ff', finish_reason='stop', @@ -2453,7 +2437,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(), ), @@ -2482,7 +2466,7 @@ def update_plan(plan: str) -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 12, 14, 24, 40, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 12, 14, 24, 40, tzinfo=timezone.utc), }, provider_response_id='resp_68c42d28772c819684459966ee2201ed0e8bc41441c948f6', finish_reason='stop', @@ -2497,7 +2481,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(), ), @@ -2511,7 +2495,7 @@ def update_plan(plan: str) -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 12, 14, 25, 3, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 12, 14, 25, 3, tzinfo=timezone.utc), }, provider_response_id='resp_68c42d3fd6a08196bce23d6be960ff8a0e8bc41441c948f6', finish_reason='stop', @@ -2553,7 +2537,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( @@ -2564,7 +2548,7 @@ async def test_openai_responses_thinking_without_summary(allow_model_requests: N model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', - provider_details={'timestamp': datetime.datetime(2024, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)}, + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -2628,7 +2612,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( @@ -2642,7 +2626,7 @@ async def test_openai_responses_thinking_with_multiple_summaries(allow_model_req model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', - provider_details={'timestamp': datetime.datetime(2024, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)}, + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -2695,7 +2679,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( @@ -2714,7 +2698,7 @@ async def test_openai_responses_thinking_with_modified_history(allow_model_reque provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 12, 14, 27, 43, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 12, 14, 27, 43, tzinfo=timezone.utc), }, provider_response_id='resp_68c42ddf9bbc8194aa7b97304dd909cb0202c9ad459e0d23', finish_reason='stop', @@ -2752,7 +2736,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( @@ -2771,7 +2755,7 @@ async def test_openai_responses_thinking_with_modified_history(allow_model_reque provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 12, 14, 27, 48, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 12, 14, 27, 48, tzinfo=timezone.utc), }, provider_response_id='resp_68c42de4afcc819f995a1c59fe87c9d5051f82c608a83beb', finish_reason='stop', @@ -2804,7 +2788,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( @@ -2859,7 +2843,7 @@ async def test_openai_responses_thinking_with_code_execution_tool(allow_model_re provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 19, 20, 17, 21, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 19, 20, 17, 21, tzinfo=timezone.utc), }, provider_response_id='resp_68cdba511c7081a389e67b16621029c609b7445677780c8f', finish_reason='stop', @@ -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( @@ -2898,7 +2882,7 @@ async def test_openai_responses_thinking_with_code_execution_tool(allow_model_re provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 19, 20, 17, 46, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 19, 20, 17, 46, tzinfo=timezone.utc), }, provider_response_id='resp_68cdba6a610481a3b4533f345bea8a7b09b7445677780c8f', finish_reason='stop', @@ -2937,7 +2921,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( @@ -3000,7 +2984,7 @@ async def test_openai_responses_thinking_with_code_execution_tool_stream( provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 11, 22, 43, 36, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 11, 22, 43, 36, tzinfo=timezone.utc), }, provider_response_id='resp_68c35098e6fc819e80fb94b25b7d031b0f2d670b80edc507', finish_reason='stop', @@ -3761,7 +3745,7 @@ def get_meaning_of_life() -> int: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3779,7 +3763,7 @@ def get_meaning_of_life() -> int: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 18, 18, 29, 57, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 18, 18, 29, 57, tzinfo=timezone.utc), }, provider_response_id='resp_68cc4fa5603481958e2143685133fe530548824120ffcf74', finish_reason='stop', @@ -3794,7 +3778,7 @@ def get_meaning_of_life() -> int: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -3814,7 +3798,7 @@ def get_meaning_of_life() -> int: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 18, 18, 29, 58, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 18, 18, 29, 58, tzinfo=timezone.utc), }, provider_response_id='resp_68cc4fa6a8a881a187b0fe1603057bff0307c6d4d2ee5985', finish_reason='stop', @@ -3878,7 +3862,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( @@ -3950,7 +3934,7 @@ async def test_openai_responses_code_execution_return_image(allow_model_requests provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 19, 20, 56, 34, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 19, 20, 56, 34, tzinfo=timezone.utc), }, provider_response_id='resp_68cdc382bc98819083a5b47ec92e077b0187028ba77f15f7', finish_reason='stop', @@ -3977,7 +3961,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( @@ -4113,7 +4097,7 @@ async def test_openai_responses_code_execution_return_image(allow_model_requests provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 19, 20, 57, 1, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 19, 20, 57, 1, tzinfo=timezone.utc), }, provider_response_id='resp_68cdc39da72481909e0512fef9d646240187028ba77f15f7', finish_reason='stop', @@ -4158,7 +4142,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( @@ -4202,7 +4186,7 @@ async def test_openai_responses_code_execution_return_image_stream(allow_model_r provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 1, 20, 47, 35, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 1, 20, 47, 35, tzinfo=timezone.utc), }, provider_response_id='resp_06c1a26fd89d07f20068dd9367869c819788cb28e6f19eff9b', finish_reason='stop', @@ -5650,7 +5634,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( @@ -5700,7 +5684,7 @@ async def test_openai_responses_image_generation(allow_model_requests: None, ope provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 19, 20, 57, 58, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 19, 20, 57, 58, tzinfo=timezone.utc), }, provider_response_id=IsStr(), finish_reason='stop', @@ -5726,7 +5710,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( @@ -5776,7 +5760,7 @@ async def test_openai_responses_image_generation(allow_model_requests: None, ope provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 19, 20, 59, 28, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 19, 20, 59, 28, tzinfo=timezone.utc), }, provider_response_id=IsStr(), finish_reason='stop', @@ -5824,7 +5808,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( @@ -5872,7 +5856,7 @@ async def test_openai_responses_image_generation_stream(allow_model_requests: No provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 1, 20, 40, 2, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 1, 20, 40, 2, tzinfo=timezone.utc), }, provider_response_id=IsStr(), finish_reason='stop', @@ -6008,7 +5992,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( @@ -6055,7 +6039,7 @@ async def test_openai_responses_image_generation_tool_without_image_output( provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 19, 23, 49, 51, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 19, 23, 49, 51, tzinfo=timezone.utc), }, provider_response_id='resp_68cdec1f3290819f99d9caba8703b251079003437d26d0c0', finish_reason='stop', @@ -6069,7 +6053,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( @@ -6116,7 +6100,7 @@ async def test_openai_responses_image_generation_tool_without_image_output( provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 9, 19, 23, 50, 57, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 9, 19, 23, 50, 57, tzinfo=timezone.utc), }, provider_response_id='resp_68cdec61d0a0819fac14ed057a9946a1079003437d26d0c0', finish_reason='stop', @@ -6179,7 +6163,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6224,7 +6208,7 @@ class Animal(BaseModel): provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 1, 19, 38, 16, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 1, 19, 38, 16, tzinfo=timezone.utc), }, provider_response_id='resp_0360827931d9421b0068dd8328c08c81a0ba854f245883906f', finish_reason='stop', @@ -6238,7 +6222,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6262,7 +6246,7 @@ class Animal(BaseModel): provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 1, 19, 39, 28, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 1, 19, 39, 28, tzinfo=timezone.utc), }, provider_response_id='resp_0360827931d9421b0068dd8370a70081a09d6de822ee43bbc4', finish_reason='stop', @@ -6277,7 +6261,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6303,7 +6287,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6351,7 +6335,7 @@ class Animal(BaseModel): provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 1, 19, 41, 59, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 1, 19, 41, 59, tzinfo=timezone.utc), }, provider_response_id='resp_09b7ce6df817433c0068dd8407c37881a0ad817ef3cc3a3600', finish_reason='stop', @@ -6380,7 +6364,7 @@ class Animal(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6428,7 +6412,7 @@ class Animal(BaseModel): provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 1, 19, 55, 9, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 1, 19, 55, 9, tzinfo=timezone.utc), }, provider_response_id='resp_0d14a5e3c26c21180068dd871d439081908dc36e63fab0cedf', finish_reason='stop', @@ -6463,7 +6447,7 @@ async def get_animal() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6487,7 +6471,7 @@ async def get_animal() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 1, 20, 2, 36, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 1, 20, 2, 36, tzinfo=timezone.utc), }, provider_response_id='resp_0481074da98340df0068dd88dceb1481918b1d167d99bc51cd', finish_reason='stop', @@ -6502,7 +6486,7 @@ async def get_animal() -> str: timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6541,7 +6525,7 @@ async def get_animal() -> str: provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 1, 20, 2, 56, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 1, 20, 2, 56, tzinfo=timezone.utc), }, provider_response_id='resp_0481074da98340df0068dd88f0ba04819185a168065ef28040', finish_reason='stop', @@ -6573,7 +6557,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( @@ -6648,7 +6632,7 @@ async def test_openai_responses_multiple_images(allow_model_requests: None, open provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 1, 19, 28, 22, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 1, 19, 28, 22, tzinfo=timezone.utc), }, provider_response_id='resp_0b6169df6e16e9690068dd80d64aec81919c65f238307673bb', finish_reason='stop', @@ -6680,7 +6664,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( @@ -6725,7 +6709,7 @@ async def test_openai_responses_image_generation_jpeg(allow_model_requests: None provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 1, 21, 28, 13, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 1, 21, 28, 13, tzinfo=timezone.utc), }, provider_response_id='resp_08acbdf1ae54befc0068dd9ced226c8197a2e974b29c565407', finish_reason='stop', @@ -6750,8 +6734,7 @@ class CityLocation(BaseModel): UserPromptPart( content='What is the largest city in the user country?', ) - ], - timestamp=IsDatetime(), + ] ), ModelResponse( parts=[ @@ -6773,8 +6756,7 @@ class CityLocation(BaseModel): content='Mexico', tool_call_id='call_ZWkVhdUjupo528U9dqgFeRkH|fc_68477f0bb8e4819cba6d781e174d77f8001fd29e2d5573f7', ) - ], - timestamp=IsDatetime(), + ] ), ] @@ -6789,7 +6771,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ModelResponse( @@ -6813,7 +6795,7 @@ class CityLocation(BaseModel): provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 13, 11, 30, 47, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 13, 11, 30, 47, tzinfo=timezone.utc), }, provider_response_id='resp_001fd29e2d5573f70068ece2e6dfbc819c96557f0de72802be', finish_reason='stop', @@ -6828,7 +6810,7 @@ class CityLocation(BaseModel): timestamp=IsDatetime(), ) ], - timestamp=IsDatetime(), + timestamp=IsNow(tz=timezone.utc), run_id=IsStr(), ), ] @@ -6864,7 +6846,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(), ), @@ -6992,7 +6974,7 @@ async def test_openai_responses_model_mcp_server_tool(allow_model_requests: None provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 23, 23, 42, 57, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 23, 23, 42, 57, tzinfo=timezone.utc), }, provider_response_id='resp_0083938b3a28070e0068fabd81970881a0a1195f2cab45bd04', finish_reason='stop', @@ -7012,7 +6994,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(), ), @@ -7043,7 +7025,7 @@ async def test_openai_responses_model_mcp_server_tool(allow_model_requests: None provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 23, 23, 43, 25, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 23, 23, 43, 25, tzinfo=timezone.utc), }, provider_response_id='resp_0083938b3a28070e0068fabd9d414881a089cf24784f80e021', finish_reason='stop', @@ -7093,7 +7075,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(), ), @@ -7267,7 +7249,7 @@ async def test_openai_responses_model_mcp_server_tool_stream(allow_model_request provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 23, 21, 40, 50, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 23, 21, 40, 50, tzinfo=timezone.utc), }, provider_response_id='resp_00b9cc7a23d047270068faa0e25934819f9c3bfdec80065bc4', finish_reason='stop', @@ -7487,7 +7469,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(), ), @@ -7649,7 +7631,7 @@ async def test_openai_responses_model_mcp_server_tool_with_connector(allow_model provider_name='openai', provider_details={ 'finish_reason': 'completed', - 'timestamp': datetime.datetime(2025, 10, 23, 21, 41, 13, tzinfo=datetime.timezone.utc), + 'timestamp': datetime(2025, 10, 23, 21, 41, 13, tzinfo=timezone.utc), }, provider_response_id='resp_0558010cf1416a490068faa0f945bc81a0b6a6dfb7391030d5', finish_reason='stop', diff --git a/tests/test_agent.py b/tests/test_agent.py index 36ff2d683d..9a44b5d083 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -2415,7 +2415,6 @@ async def system_prompt(ctx: RunContext) -> str: UserPromptPart(content='How goes it?'), ], instructions='Original instructions', - timestamp=IsDatetime(), ), ] @@ -2473,7 +2472,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')]), ] @@ -2487,8 +2486,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')], @@ -2528,7 +2526,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')]), ] @@ -2546,7 +2544,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')]), ] @@ -2559,8 +2557,7 @@ def simple_response(_messages: list[ModelMessage], _info: AgentInfo) -> ModelRes content='Hello', timestamp=IsDatetime(), ) - ], - timestamp=IsNow(tz=timezone.utc), + ] ), ModelResponse( parts=[TextPart(content='world')], @@ -2583,15 +2580,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?')]), ] @@ -3746,9 +3743,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]) @@ -4286,15 +4281,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))], @@ -5655,9 +5647,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, @@ -5670,7 +5660,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!')]), ] @@ -5685,7 +5675,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')]), ] @@ -5707,7 +5697,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'), @@ -5719,8 +5709,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(), + ] ), ] @@ -5868,7 +5857,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?')]), ] @@ -5885,8 +5874,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?')], @@ -5942,8 +5930,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?')], @@ -6392,7 +6379,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')]), ] @@ -6412,7 +6399,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 2730dae9ce..0020db4273 100644 --- a/tests/test_messages.py +++ b/tests/test_messages.py @@ -417,7 +417,6 @@ def test_pre_usage_refactor_messages_deserializable(): timestamp=IsNow(tz=timezone.utc), ) ], - timestamp=IsNow(tz=timezone.utc), ), ModelResponse( parts=[TextPart(content='Mexico City.')], @@ -499,7 +498,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 5d0eff61b86c01cdbc8e311a5c06adb1cfd1bb03 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 13/23] 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 36f08053ba..5c6677b34a 100644 --- a/pydantic_ai_slim/pydantic_ai/_agent_graph.py +++ b/pydantic_ai_slim/pydantic_ai/_agent_graph.py @@ -229,7 +229,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)] @@ -273,7 +273,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 @@ -627,7 +627,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 @@ -695,7 +695,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() @@ -737,7 +737,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( @@ -1325,7 +1325,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 54bcb924a499581649a818d76ee75df210c851f4 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 14/23] 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 184eac1453..3d996c56cf 100644 --- a/pydantic_ai_slim/pydantic_ai/_agent_graph.py +++ b/pydantic_ai_slim/pydantic_ai/_agent_graph.py @@ -452,7 +452,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: @@ -485,7 +484,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 @@ -494,6 +492,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) @@ -511,6 +510,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 3b96e640db..4c2fc45dbc 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 9f9bf06688113cda009eaeb9104ee13430341b6d 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 15/23] 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 5bfb0493ee..cefdeb0349 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -1157,8 +1157,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: @@ -1169,12 +1171,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 affd4668f0..bc6e50eddd 100644 --- a/tests/models/test_mistral.py +++ b/tests/models/test_mistral.py @@ -1995,9 +1995,9 @@ async def get_image() -> BinaryContent: provider_name='mistral', 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(), ), @@ -2032,9 +2032,9 @@ async def get_image() -> BinaryContent: provider_name='mistral', 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(), ), @@ -2463,9 +2463,9 @@ async def test_mistral_model_thinking_part_iter(allow_model_requests: None, mist provider_name='mistral', 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 95ee2b80b4..eac7245c3f 100644 --- a/tests/models/test_openai.py +++ b/tests/models/test_openai.py @@ -2231,7 +2231,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 41769719e539e461de395967684662bf5f186d26 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 16/23] 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 7b457ba4ce..af8578c465 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -2158,11 +2158,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', @@ -2207,10 +2232,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', @@ -2314,11 +2359,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}), @@ -2453,10 +2523,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(), @@ -2546,7 +2636,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', @@ -2622,9 +2712,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', @@ -7730,6 +7820,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( @@ -7745,6 +7836,7 @@ async def test_openai_responses_raw_cot_only(allow_model_requests: None): model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -7793,6 +7885,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( @@ -7809,6 +7902,7 @@ async def test_openai_responses_raw_cot_with_summary(allow_model_requests: None) model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -7859,6 +7953,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( @@ -7870,13 +7965,26 @@ 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_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -7907,6 +8015,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( @@ -7930,7 +8039,10 @@ async def test_openai_responses_raw_cot_stream_openrouter(allow_model_requests: model_name='openai/gpt-oss-20b', timestamp=IsDatetime(), provider_name='openrouter', - 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(), @@ -8045,6 +8157,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( @@ -8060,6 +8173,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -8077,6 +8191,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( @@ -8092,6 +8207,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -8102,6 +8218,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( @@ -8113,12 +8230,19 @@ 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_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -8136,6 +8260,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( @@ -8151,6 +8276,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -8161,6 +8287,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( @@ -8172,12 +8299,19 @@ 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_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), @@ -8188,6 +8322,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( @@ -8203,6 +8338,7 @@ async def capture_messages(*args: Any, **kwargs: Any) -> Any: model_name='gpt-4o-123', timestamp=IsDatetime(), provider_name='openai', + provider_details={'timestamp': datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc)}, provider_response_id='123', run_id=IsStr(), ), From 8652eb170be385e296d4fa9739db707cbc92cdae 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 17/23] 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 cefdeb0349..7a9db59ec8 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -567,7 +567,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. @@ -624,6 +624,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( @@ -631,7 +633,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, finish_reason=self._map_finish_reason(choice.finish_reason), @@ -1181,7 +1183,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): @@ -2005,8 +2007,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) @@ -2452,7 +2456,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 @@ -2461,7 +2465,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 eed381d30e..0c222090eb 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openrouter.py +++ b/pydantic_ai_slim/pydantic_ai/models/openrouter.py @@ -548,12 +548,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 af8578c465..3dfbbf0c7f 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -2636,7 +2636,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', @@ -7820,7 +7820,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( @@ -7885,7 +7885,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( @@ -7953,7 +7953,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( @@ -8015,7 +8015,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( @@ -8157,7 +8157,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( @@ -8191,7 +8191,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( @@ -8218,7 +8218,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( @@ -8260,7 +8260,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( @@ -8287,7 +8287,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( @@ -8322,7 +8322,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 e811f4ed69f58133183f1a6b012613abe5071a10 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 18/23] 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 0d6660154a..d0d4130827 100644 --- a/tests/models/test_anthropic.py +++ b/tests/models/test_anthropic.py @@ -2167,22 +2167,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 b008a87388..2f7084eb26 100644 --- a/tests/models/test_bedrock.py +++ b/tests/models/test_bedrock.py @@ -1223,24 +1223,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 09692479cd..78d91f6cfd 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -2054,18 +2054,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 bc6e50eddd..f31dc9d408 100644 --- a/tests/models/test_mistral.py +++ b/tests/models/test_mistral.py @@ -2347,8 +2347,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 a501928be6641bceffa3b933e809f29b34d2e481 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 19/23] 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 7a9db59ec8..197db7599c 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -1176,6 +1176,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 d0d4130827..b75e82fc3c 100644 --- a/tests/models/test_anthropic.py +++ b/tests/models/test_anthropic.py @@ -2164,36 +2164,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 2f7084eb26..ff2eb7e51d 100644 --- a/tests/models/test_bedrock.py +++ b/tests/models/test_bedrock.py @@ -1226,30 +1226,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 78d91f6cfd..99c324962d 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -2051,30 +2051,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 f31dc9d408..bc6e50eddd 100644 --- a/tests/models/test_mistral.py +++ b/tests/models/test_mistral.py @@ -2347,18 +2347,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 8e1670ec702cc76d23d438c1a6750a21e587b7e1 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 20/23] 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 eac7245c3f..95ee2b80b4 100644 --- a/tests/models/test_openai.py +++ b/tests/models/test_openai.py @@ -2231,12 +2231,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 3dfbbf0c7f..467c59281e 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -2158,36 +2158,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', @@ -2232,30 +2207,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', @@ -2359,36 +2314,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}), @@ -2523,30 +2453,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(), @@ -2712,9 +2622,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', @@ -7965,20 +7875,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', @@ -8230,13 +8128,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', @@ -8299,13 +8191,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 702b2162268f4472343334166b2eb93af4d4dc68 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 21/23] 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 95ee2b80b4..e1c4983d4b 100644 --- a/tests/models/test_openai.py +++ b/tests/models/test_openai.py @@ -201,6 +201,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 61085ea3cc..4d7baf74f4 100644 --- a/tests/models/test_openrouter.py +++ b/tests/models/test_openrouter.py @@ -340,6 +340,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 4c2fc45dbc..25b964e130 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 754c78230e094f2eb4cc612c4d966d5768db0681 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 22/23] 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 0c222090eb..18bfa358e3 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openrouter.py +++ b/pydantic_ai_slim/pydantic_ai/models/openrouter.py @@ -552,11 +552,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 25b964e130..8d9b4ab759 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 5327aea51b5f698eabc2faec77ae0e7c5a0b5ccb 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 23/23] 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 4d7baf74f4..b0d8f0e504 100644 --- a/tests/models/test_openrouter.py +++ b/tests/models/test_openrouter.py @@ -456,6 +456,29 @@ class FindEducationContentFilters(BaseModel): ) +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.