From ec1629dc2904c90d82e621e02c073416266a5d97 Mon Sep 17 00:00:00 2001 From: fatelei Date: Sun, 27 Jul 2025 22:17:36 +0800 Subject: [PATCH] feat: Add id and finish_reason to ModelResponse --- pydantic_ai_slim/pydantic_ai/messages.py | 36 +++++- .../pydantic_ai/models/anthropic.py | 2 +- .../pydantic_ai/models/bedrock.py | 2 +- .../pydantic_ai/models/function.py | 2 + pydantic_ai_slim/pydantic_ai/models/gemini.py | 11 +- pydantic_ai_slim/pydantic_ai/models/google.py | 8 +- pydantic_ai_slim/pydantic_ai/models/groq.py | 2 +- .../pydantic_ai/models/huggingface.py | 2 +- .../pydantic_ai/models/mistral.py | 2 +- pydantic_ai_slim/pydantic_ai/models/openai.py | 5 +- pydantic_ai_slim/pydantic_ai/models/test.py | 31 ++++- tests/graph/test_mermaid.py | 14 ++- .../test_known_model_names.yaml | 2 +- tests/models/test_anthropic.py | 38 +++--- tests/models/test_cohere.py | 4 +- tests/models/test_deepseek.py | 4 +- tests/models/test_fallback.py | 1 + tests/models/test_gemini.py | 51 +++++--- tests/models/test_gemini_vertex.py | 4 +- tests/models/test_google.py | 4 +- tests/models/test_groq.py | 24 ++-- tests/models/test_huggingface.py | 24 ++-- tests/models/test_mistral.py | 48 ++++---- tests/models/test_openai.py | 114 +++++++++++++----- tests/models/test_openai_responses.py | 36 +++--- tests/test_agent.py | 3 +- tests/test_mcp.py | 92 ++++++++++---- 27 files changed, 375 insertions(+), 191 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/messages.py b/pydantic_ai_slim/pydantic_ai/messages.py index 51e63eea5..f4dbb52a6 100644 --- a/pydantic_ai_slim/pydantic_ai/messages.py +++ b/pydantic_ai_slim/pydantic_ai/messages.py @@ -789,8 +789,40 @@ class ModelResponse: For OpenAI models, this may include 'logprobs', 'finish_reason', etc. """ - vendor_id: str | None = None - """Vendor ID as specified by the model provider. This can be used to track the specific request to the model.""" + id: str | None = None + """Unique identifier for the model response, e.g. as returned by the model provider (OpenAI, etc).""" + + finish_reason: str | None = None + """The reason the model finished generating this response, e.g. 'stop', 'length', etc.""" + + @property + def vendor_id(self) -> str | None: + """Vendor ID as specified by the model provider. This can be used to track the specific request to the model. + + This is deprecated, use `id` instead. + """ + import warnings + + warnings.warn('vendor_id is deprecated, use id instead', DeprecationWarning, stacklevel=2) + return self.id + + @vendor_id.setter + def vendor_id(self, value: str | None) -> None: + """Set the vendor ID. + + This is deprecated, use `id` instead. + """ + import warnings + + warnings.warn('vendor_id is deprecated, use id instead', DeprecationWarning, stacklevel=2) + self.id = value + + def __post_init__(self) -> None: + """Ensure vendor_details contains finish_reason for backward compatibility.""" + if self.finish_reason and self.vendor_details is None: + self.vendor_details = {} + if self.finish_reason and self.vendor_details is not None: + self.vendor_details['finish_reason'] = self.finish_reason def otel_events(self, settings: InstrumentationSettings) -> list[Event]: """Return OpenTelemetry events for the response.""" diff --git a/pydantic_ai_slim/pydantic_ai/models/anthropic.py b/pydantic_ai_slim/pydantic_ai/models/anthropic.py index 02f9111c2..2a42784ee 100644 --- a/pydantic_ai_slim/pydantic_ai/models/anthropic.py +++ b/pydantic_ai_slim/pydantic_ai/models/anthropic.py @@ -282,7 +282,7 @@ def _process_response(self, response: BetaMessage) -> ModelResponse: ) ) - return ModelResponse(items, usage=_map_usage(response), model_name=response.model, vendor_id=response.id) + return ModelResponse(items, usage=_map_usage(response), model_name=response.model, id=response.id) async def _process_streamed_response(self, response: AsyncStream[BetaRawMessageStreamEvent]) -> StreamedResponse: peekable_response = _utils.PeekableAsyncStream(response) diff --git a/pydantic_ai_slim/pydantic_ai/models/bedrock.py b/pydantic_ai_slim/pydantic_ai/models/bedrock.py index b63ed4e1f..cd51195ec 100644 --- a/pydantic_ai_slim/pydantic_ai/models/bedrock.py +++ b/pydantic_ai_slim/pydantic_ai/models/bedrock.py @@ -296,7 +296,7 @@ async def _process_response(self, response: ConverseResponseTypeDef) -> ModelRes total_tokens=response['usage']['totalTokens'], ) vendor_id = response.get('ResponseMetadata', {}).get('RequestId', None) - return ModelResponse(items, usage=u, model_name=self.model_name, vendor_id=vendor_id) + return ModelResponse(items, usage=u, model_name=self.model_name, id=vendor_id) @overload async def _messages_create( diff --git a/pydantic_ai_slim/pydantic_ai/models/function.py b/pydantic_ai_slim/pydantic_ai/models/function.py index c48873f04..4b3453e27 100644 --- a/pydantic_ai_slim/pydantic_ai/models/function.py +++ b/pydantic_ai_slim/pydantic_ai/models/function.py @@ -137,6 +137,8 @@ async def request( if not response.usage.has_values(): # pragma: no branch response.usage = _estimate_usage(chain(messages, [response])) response.usage.requests = 1 + response.id = getattr(response, 'id', None) + response.finish_reason = getattr(response, 'finish_reason', None) return response @asynccontextmanager diff --git a/pydantic_ai_slim/pydantic_ai/models/gemini.py b/pydantic_ai_slim/pydantic_ai/models/gemini.py index 4ac07f8ad..b86c72590 100644 --- a/pydantic_ai_slim/pydantic_ai/models/gemini.py +++ b/pydantic_ai_slim/pydantic_ai/models/gemini.py @@ -273,15 +273,16 @@ def _process_response(self, response: _GeminiResponse) -> ModelResponse: parts = response['candidates'][0]['content']['parts'] vendor_id = response.get('vendor_id', None) finish_reason = response['candidates'][0].get('finish_reason') + vendor_details = {} if finish_reason: - vendor_details = {'finish_reason': finish_reason} + vendor_details['finish_reason'] = finish_reason usage = _metadata_as_usage(response) usage.requests = 1 return _process_response_from_parts( parts, response.get('model_version', self._model_name), usage, - vendor_id=vendor_id, + id=vendor_id, vendor_details=vendor_details, ) @@ -662,7 +663,7 @@ def _process_response_from_parts( parts: Sequence[_GeminiPartUnion], model_name: GeminiModelName, usage: usage.Usage, - vendor_id: str | None, + id: str | None, vendor_details: dict[str, Any] | None = None, ) -> ModelResponse: items: list[ModelResponsePart] = [] @@ -680,9 +681,7 @@ def _process_response_from_parts( raise UnexpectedModelBehavior( f'Unsupported response from Gemini, expected all parts to be function calls or text, got: {part!r}' ) - return ModelResponse( - parts=items, usage=usage, model_name=model_name, vendor_id=vendor_id, vendor_details=vendor_details - ) + return ModelResponse(parts=items, usage=usage, model_name=model_name, id=id, vendor_details=vendor_details) class _GeminiFunctionCall(TypedDict): diff --git a/pydantic_ai_slim/pydantic_ai/models/google.py b/pydantic_ai_slim/pydantic_ai/models/google.py index 082f5ba56..25f2c87a7 100644 --- a/pydantic_ai_slim/pydantic_ai/models/google.py +++ b/pydantic_ai_slim/pydantic_ai/models/google.py @@ -322,7 +322,7 @@ def _process_response(self, response: GenerateContentResponse) -> ModelResponse: usage = _metadata_as_usage(response) usage.requests = 1 return _process_response_from_parts( - parts, response.model_version or self._model_name, usage, vendor_id=vendor_id, vendor_details=vendor_details + parts, response.model_version or self._model_name, usage, id=vendor_id, vendor_details=vendor_details ) async def _process_streamed_response(self, response: AsyncIterator[GenerateContentResponse]) -> StreamedResponse: @@ -506,7 +506,7 @@ def _process_response_from_parts( parts: list[Part], model_name: GoogleModelName, usage: usage.Usage, - vendor_id: str | None, + id: str | None, vendor_details: dict[str, Any] | None = None, ) -> ModelResponse: items: list[ModelResponsePart] = [] @@ -526,9 +526,7 @@ def _process_response_from_parts( raise UnexpectedModelBehavior( f'Unsupported response from Gemini, expected all parts to be function calls or text, got: {part!r}' ) - return ModelResponse( - parts=items, model_name=model_name, usage=usage, vendor_id=vendor_id, vendor_details=vendor_details - ) + return ModelResponse(parts=items, model_name=model_name, usage=usage, id=id, vendor_details=vendor_details) def _function_declaration_from_tool(tool: ToolDefinition) -> FunctionDeclarationDict: diff --git a/pydantic_ai_slim/pydantic_ai/models/groq.py b/pydantic_ai_slim/pydantic_ai/models/groq.py index ffca84b44..4d1117e7b 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -266,7 +266,7 @@ def _process_response(self, response: chat.ChatCompletion) -> ModelResponse: for c in choice.message.tool_calls: items.append(ToolCallPart(tool_name=c.function.name, args=c.function.arguments, tool_call_id=c.id)) return ModelResponse( - items, usage=_map_usage(response), model_name=response.model, timestamp=timestamp, vendor_id=response.id + items, usage=_map_usage(response), model_name=response.model, timestamp=timestamp, id=response.id ) async def _process_streamed_response(self, response: AsyncStream[chat.ChatCompletionChunk]) -> GroqStreamedResponse: diff --git a/pydantic_ai_slim/pydantic_ai/models/huggingface.py b/pydantic_ai_slim/pydantic_ai/models/huggingface.py index 4b3c2ff40..6e9acbf4f 100644 --- a/pydantic_ai_slim/pydantic_ai/models/huggingface.py +++ b/pydantic_ai_slim/pydantic_ai/models/huggingface.py @@ -253,7 +253,7 @@ def _process_response(self, response: ChatCompletionOutput) -> ModelResponse: usage=_map_usage(response), model_name=response.model, timestamp=timestamp, - vendor_id=response.id, + id=response.id, ) async def _process_streamed_response(self, response: AsyncIterable[ChatCompletionStreamOutput]) -> StreamedResponse: diff --git a/pydantic_ai_slim/pydantic_ai/models/mistral.py b/pydantic_ai_slim/pydantic_ai/models/mistral.py index ca73558bc..a957c6086 100644 --- a/pydantic_ai_slim/pydantic_ai/models/mistral.py +++ b/pydantic_ai_slim/pydantic_ai/models/mistral.py @@ -341,7 +341,7 @@ def _process_response(self, response: MistralChatCompletionResponse) -> ModelRes parts.append(tool) return ModelResponse( - parts, usage=_map_usage(response), model_name=response.model, timestamp=timestamp, vendor_id=response.id + parts, usage=_map_usage(response), model_name=response.model, timestamp=timestamp, id=response.id ) async def _process_streamed_response( diff --git a/pydantic_ai_slim/pydantic_ai/models/openai.py b/pydantic_ai_slim/pydantic_ai/models/openai.py index 35dca2e03..23ca11869 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -419,7 +419,8 @@ def _process_response(self, response: chat.ChatCompletion | str) -> ModelRespons model_name=response.model, timestamp=timestamp, vendor_details=vendor_details, - vendor_id=response.id, + id=response.id, + finish_reason=choice.finish_reason, ) async def _process_streamed_response(self, response: AsyncStream[ChatCompletionChunk]) -> OpenAIStreamedResponse: @@ -706,7 +707,7 @@ def _process_response(self, response: responses.Response) -> ModelResponse: items, usage=_map_usage(response), model_name=response.model, - vendor_id=response.id, + id=response.id, timestamp=timestamp, ) diff --git a/pydantic_ai_slim/pydantic_ai/models/test.py b/pydantic_ai_slim/pydantic_ai/models/test.py index eebe00d44..aa97d6092 100644 --- a/pydantic_ai_slim/pydantic_ai/models/test.py +++ b/pydantic_ai_slim/pydantic_ai/models/test.py @@ -227,23 +227,44 @@ def _request( output[part.tool_name] = part.content if output: return ModelResponse( - parts=[TextPart(pydantic_core.to_json(output).decode())], model_name=self._model_name + parts=[TextPart(pydantic_core.to_json(output).decode())], + model_name=self._model_name, + id=None, + finish_reason=None, ) else: - return ModelResponse(parts=[TextPart('success (no tool calls)')], model_name=self._model_name) + return ModelResponse( + parts=[TextPart('success (no tool calls)')], + model_name=self._model_name, + id=None, + finish_reason=None, + ) else: - return ModelResponse(parts=[TextPart(response_text)], model_name=self._model_name) + return ModelResponse( + parts=[TextPart(response_text)], + model_name=self._model_name, + id=None, + finish_reason=None, + ) else: assert output_tools, 'No output tools provided' custom_output_args = output_wrapper.value output_tool = output_tools[self.seed % len(output_tools)] if custom_output_args is not None: return ModelResponse( - parts=[ToolCallPart(output_tool.name, custom_output_args)], model_name=self._model_name + parts=[ToolCallPart(output_tool.name, custom_output_args)], + model_name=self._model_name, + id=None, + finish_reason=None, ) else: response_args = self.gen_tool_args(output_tool) - return ModelResponse(parts=[ToolCallPart(output_tool.name, response_args)], model_name=self._model_name) + return ModelResponse( + parts=[ToolCallPart(output_tool.name, response_args)], + model_name=self._model_name, + id=None, + finish_reason=None, + ) @dataclass diff --git a/tests/graph/test_mermaid.py b/tests/graph/test_mermaid.py index d2706740d..debad4676 100644 --- a/tests/graph/test_mermaid.py +++ b/tests/graph/test_mermaid.py @@ -276,7 +276,9 @@ def get_jpg(request: httpx.Request) -> httpx.Response: graph1.name = None img = graph1.mermaid_image(start_node=Foo(), httpx_client=httpx_with_handler(get_jpg)) assert graph1.name == 'graph1' - assert img == snapshot(b'---\ntitle: graph1\n---\nstateDiagram-v2\n [*] --> Foo\n Foo --> Bar\n Bar --> [*]') + assert img == snapshot( + b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xe2\x01\xd8ICC_PROFILE\x00\x01\x01\x00\x00\x01\xc8\x00\x00\x00\x00\x040\x00\x00mntrRGB XYZ \x07\xe0\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00acsp\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\xf6\xd6\x00\x01\x00\x00\x00\x00\xd3-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\tdesc\x00\x00\x00\xf0\x00\x00\x00$rXYZ\x00\x00\x01\x14\x00\x00\x00\x14gXYZ\x00\x00\x01(\x00\x00\x00\x14bXYZ\x00\x00\x01<\x00\x00\x00\x14wtpt\x00\x00\x01P\x00\x00\x00\x14rTRC\x00\x00\x01d\x00\x00\x00(gTRC\x00\x00\x01d\x00\x00\x00(bTRC\x00\x00\x01d\x00\x00\x00(cprt\x00\x00\x01\x8c\x00\x00\x00\x11{]\xf8\x9b\xe9o\xa3\x1e\x82_\xbcs\xcf\xbaw\x193\xb3v\xdef\xecc\x97\x9f\x8f\x9d\xbf:\xfa\xc7\xd8\xc3\xb3\xed_g~\x0f\xc7h\xbb\xc9\x14\x9a\x86\xe5Pn\x17\x01\x0b\x83\x99\x0b\xdc\xd6\xb5\xb0\x87\x0f}\xb5\xad\x19#\xa6\xe2\xec\x120T\xdcc\xdb\x06|\xf3\xe8\xb8\xff\x006\xac4\x04D@DD\x04D@DD\x15\xe8\xcf\xb6\x08\xf9c\xd1q\xf2g\xee\xbf\xda\xac%^\x03\xf6\xc1\x1f\xfa\\z\xbf;>\xb5a\xa0""\x02" ""\x02"\xe1,\xd1\xc0\xc0\xe9\x1e\xd8\xda\\\x1b\x97\x9c\x0c\x92\x00\x1f\xa4\x92\x00\xf9\xca\n\xf8\x0f\xb6\x10\x9f\xea\xb0\xff\x006\xacE^\x01\xf6\xc1\x13\xd3\xf9.\x07\x98\xcf\xddg\xd4\xac\x08\xa6\x8ev\x97F\xf6\xc8\xd0\xe2\xdc\xb0\xe4d\x12\x08\xfd \x82\x0f\xe8A\xcd\x11\x10\x11\x11\x01\x11G\xb5\xd5\xe6\xa6\xcba\xdfF\xf1\x15]EL\x14\x91\xca\xe6\xee\xe5\x99%k\x0b\xf0z\x12\xd6\x92@=\t\x00\x1e\x8a\xf4Q8\x95E\x11\xbeD\x85a\xde-\x14w\xfbMe\xb2\xe1\x03jhk!|\x13\xc2\xff\x00\'\xb1\xc0\x87\x0f\xd6\n\xaf\xdf\xa1\xac\xd3\x9d\xd5\x14\xcf\xab\x94\xfb\xe9\xaag\x92G\xb8\xfc\xa5\xc5\xcb\x8f\xa0\x1a\x7f\xf1l\x7f\xe3w\xf1]\xfc\xdb\x0f\xb7>\x1f\x94^\x1a\xa0\x1f\xc6\xcfl\x97\xb0\xe1\xbb\xccc\xf0\xfeQ\xd6\xb8=\xfb\xd1\xfev\xfef\xff\x00.\xf1\x9f\xb0sq\x9d\xff\x00?\xbb[\xe3g\xb4Q\xd8-4v\xcb|\r\xa6\xa1\xa3\x85\x90A\x0b<\x98\xc6\x80\x1a?P\n\xb9\xf68\xd3]\xe3\x9f\xe1\x10s\xf6\xec\xe6\xe5\xdb\xb6\xe78\xces\x8c\xfa\x97g\xa0\x1a\x7f\xf1l\x7f\xe3w\xf1Nm\x85\xdb\x9f\x0f\xf4^\x16r*\xcd\x9a\x1a\xcd\x01\xddOL\xfa9G\xbd\x9a\x9ay#{O\xca\x08r\x96hk\xcdM\xea\xc3\xcc\xacp\x92\xae\x9e\xa2zI%kq\xcc1J\xe6\x07\xe0t\x05\xc1\xa0\x90:\x02H\x1d\x168\xbb\x18\xa9\x1fH\x1d\xca\x90H\xd8\x9b\xb8\xbd\xa5\xe4\xc8pGE.\x96\x0b\x9f\x15\xf5\x1f\x19\xaa\xee\x9a\xabQi\x97\xe9ic\xa0\xb4\xd2Zn\xb2\xd1GB\x05\xbe\x1a\x93Q##pl\xc5\xd2L\xef\x85\x0en\xd6\x00\x02\x8f\xd5\xbe\xe8\xf9\xaf\xb1f\xcb\xaf\xce\x18\xfd\xe4\xb8\xfd+[\xf5\xeeP\xae\x07\xea\xab\x8e\xba\xe0\xce\x85\xd4w\x86\x86]n\xd6:*\xda\xac7h2\xc9\x0b\x1c\xe7\x01\xea\x04\x92q\xea\xca\x9a\xf0\xc7\xef%\xc7\xe9Z\xdf\xafr\xd3\x12o\xb3\xcc\xf7\xc7\xaa\xf4\xfdR\xf4D^RE\x10\xe2w\xde[w\xd2\xb4_\\\xd5/Q^$\xd3I6\x9c\x8ef1\xd26\x92\xb6\x96\xaa@\xc0I\x11\xb2f\x97\xbb\x03\xa9\xc3r\xef\xd4\xbavi\xb65\x1ca1\xbd\x87q\xa0\x82\xebo\xa9\xa2\xaa\x8f\x9bKS\x13\xa1\x96<\x91\xb9\x8e\x048du\x19\x04\xf9,M/\xa6\xad\xba3MZ\xb4\xfd\x9a\x9b\xb9\xda-T\xb1QQ\xd3\xf3\x1c\xfeT1\xb01\x8d\xdc\xe2\\p\xd6\x81\x92I>\xb2W\xa3\x14\xac\x9e&K\x13\xdb$ohs^\xc3\x90\xe0|\x88>\xb0\xb9.\xfbj\xc5]\xdc{=\xe8\x0b\xae\xa5\xa9\xbeUXL\x95uUl\xaf\xa9\xa7\x15\xd5\r\xa2\xa8\xa9a\x05\xb3KH$\x10I -i\xde\xe8\xc9\xc8\x07+\xb3X\xf0\x13Ck\xdb\xe5M\xde\xf5f\x96j\xea\xc8\x1bKZi\xae\x154\xb1\xd7D\xdc\xed\x8e\xa68\xa4k\'h\xc9\x00J\xd7\x0ct\xf2V\x02*d\xa7\xa8\xbb\xae\x9a\x9a\x1a*h\xa9\xe9\xe2d\x10D\xc1\x1cqF\xd0\xd6\xb1\xa0`4\x01\xd0\x00:as\xe1\x8f\xdeK\x8f\xd2\xb5\xbf^\xe5\xf94\xac\xa7\x89\xf2\xca\xf6\xc7\x1b\x1a\\\xe7\xbc\xe04\x0f2O\xa8.\xee\x1bSI\x0e\x9c\x92i\x18\xe8\xdbW[UU\x1b^\x08&7\xcc\xe70\xe0\xf5\x19n\x1d\xfa\xd3\x1bL\t\xe3\x1e\xab\xd3\xbaR\xa4D^R\xc2" \x8dTp\xd7KUL\xf9_b\xa3\x0fy.v\xc8\xf6\x02O\x99\xc0\xc0\xca\xea\xf6-\xd2\x9f\x88\xe9\xbfa\xfe*T\x8b\xa3\x9ccF\xea\xe7\xc6SyS\xbe\x81X}\x9bM\xb3\xc3a\xf0\xefG\xbb\xcfv\xdcvs{\xce\xdd\xf8\xcf\x9e\xde\x99S\x8fb\xdd)\xf8\x8e\x9b\xf6\x1f\xe2\xbc`G\xb6\x08\x8c\x9c\xfa.:g\xf3\xb5a\xa79\xc7\xed\xcf\x8c\x97\x9e\xb4j\x9b\x86\xba^\x96fK\x1d\x8a\x8c\xbd\x849\xa5\xf1\xef\x00\x8f#\x83\x91\x9f\x9dIQ\x16u\xe2W\x89\xads3\xc4\xbc\xc8\x88\x8b4\x08\x88\x80\x88\x88+\xd0~\xd8\x022\x7f\x93\x03\xa6\xee\x9fu\xfc\x9f\xfe\xab\tW`\xfd\xb0\x84\x7fU\xc7\xab\xf3\xb5b ""\x02" ""\x02"\xc1\xbe[\xa6\xbbY\xea\xe9)\xebf\xb6\xd4\xcb\x19lU\x94\xf8/\x81\xff\x00\x15\xe0\x1e\x87\x07\x07i\x04\x1c`\x82\t\x08! }\xb0\x87\xaf\xf3\\t\xff\x00\xbbV"\xd1q\xda\xa7Z\x9e7\x9d\x124\x83=\x97{\xaf\xa3\x9c\xbc\xbb\xc3wsy\xbe!\xe7\xbb\x93\xca\xfb.\xcf\xf9\xa9o\x0cmQ\xbb\x8b3e\x1b\xd9IOM\x1c\x866\x9f \xe7<\x1d\xce\xc63\x80\x06s\x85\xf9\xdd\xb5\'\xe5eO\xeeT\xff\x00\xe8^\x9c_\x04\xcf\xd0\x17%\xebf\x88\xddLxG\xb3<\xd2\x81{\x15\x0fd\x8fO|bOJ\xbc;\xc2\xbcC\xb9\xc1\x9e\xef\xbf~\xdd\xbbv\xe7?\x1b\x1b\xb1\xd38\xe8\xa5\x1d\xdbR~VT\xfe\xe5O\xfe\x85\xea\xa2f\xfd\xb1\xfdc\xd8\xcd//\xbej[4n\xaa\xf1qyl@\xbd\xf4\x95\x14\xd1\xc6dh\xf3\rs\x00\xda\xecg\x19\x04g\x19S\x9bm\xc2\x1b\xb5\xba\x96\xba\x99\xc5\xd4\xf512h\xdcF\tk\x80#\xff\x00\x05F&\xf8\'\xff\x00d\xac\xbe\x19~\r\xb4\x9f\xd14\x9fR\xc5\xcd\xb4SL\xe1\xe7\xb4D\xde\xdaE\xbc\xb8/\x13x\xbc\xa4\xa8\x88\xbc\xd0Q\x9e\'~\r\xb5g\xd15\x7fR\xf5&Q\x9e\'~\r\xb5g\xd15\x7fR\xf5\xbe\xcf\xd3Q\xc6<\xd3\x1b\xe1\x8b\x17\xc13\xf4\x05\xf3\xaa\x87JYn<7\xe2Um7\x06\xaf7MY\xe9\x0e\xa0\xee\xfa\xf6\xde\xc8"m\x1b\xc5l\xe1\x93\xf3b\x9b\xbd\x11\t\xc1-dN\'f\x00r\xfa+\x17\xc13\xf4\x05AX{?q\x0fJ[/\xf6;/\x14\xad\xb6\xfd=v\xb9\\+\xcccKo\xad\x80U\xcf$\xafk\'uYf\xe6\x99\x08\x0e1\x11\xd3;WN5\x13T\xc6\x9d}^\xac\xa2lj\xce3\xdc\xf4\xed\xabB\xd1\xd85E\x8a\xe4.\x96FW\x0b\x8c\x96\x9b\x85\xea\xb6\xe1\x86\xc6\x1b,T4@\xfd\xfc\xfe^\xdfy\x8cc\xaa\x94z\x03u\xfc\xad\xae\xfd\xd2\x9b\xff\x00\x9ag\xc2\xed\xc7\xdf\xd8\xcb\xde\xe7R\xf6\xc5M+\xdeCZ\xd6\x12I\xf5\x0c/C\x870\xba\x9f\x87\xba^\'\x8d\xafe\xae\x95\xae\x07\xd4DM\x05`E\xc3\xb7T}\x8e\xeb|\xad\xbbQ\x9f\x7fG$p\xc7\x14\xc3\xfa/\xd8\xc0\\\xdf\x95\xb9\x00\x82C\x81\x07\nb\xb9\xf1\xf1h\x9a2S7\xd6\xff\x00.\xb4E\xa2\xc2".\x00DD\x04DA_\x02}\xb0\x04|_F\x07\xcb\xe7\xde\xff\x00b\xb0Uz1\xed\x81>\xf7>\x8b\x8f\x97?u\xfe\xc5a ""\x02" ""\x02" \xafA\xfb`H\xc9\xc7\xa2\xe0\xe3=>\xeb\xf9\x15\x84\xab\xc0\x0f\xb6\x0c\x9c\x1cz.\x06q\xf9\xda\xb0\xd0\x11\x11\x01\x11\x10\x11\x11\x01`\xdf%\xb8Ag\xab\x96\xd5\x045W(\xe3/\x82\x9e\xa1\xe5\x8c\x99\xe3\xa8ap\xf7\xbb\xb1\x8d\xd8;s\x9c\x1c`\xe7(o\x16x\xb3\xa7x-\xa2\xea\xb5>\xa6\xa9|4\x10\xb9\xb1G\x14\x0c\xdf5L\xce\xce\xc8\xa2g\xc6{\xb0zy`\x12H\x00\x94\x14(\xedo\xa0\xbd::\xa7\x9bVk\xbc\x18Y\xfd\x1c\xe4\xff\x00\xb5m{\\:\xb5\xcd8!\xc3\xa8!LM\xa6\xe3S\xdbf\xe2/\xb3`\x98\xc7s\xdf\xdf\xf3\xde\xb0\xfe\xed\xdd\xb7\xff\x00K\xde\xec\xdb\xf1\x7fV2\xa7\x1d\x93]\x05O\x17\xb8\xfdYd\xdat\xa4\xb7\xdaFS:\x1f\x82uki\xcf}-\xc7BK\xcb\t#\xe6\\\xfd\xa7W\xd3A\xe0G\x8d\xda\xdb\xd1-\xbc\xaf\x0f\xdd\x0fz\xe5yr\xfb\xd6\xdd\xd8\xdb\xd3\x18\xc7\xcd\xeaW\xb7\x0f\xb8}`\xe1n\x91\xb7\xe9\x9d3o\x8e\xd9g\xa1f\xc8\xa1gRO\x9b\x9e\xe7\x1e\xaes\x8eIq\xeaI^\xbf(r\x87>\x8a#$S\x96-\xa2\xf5U\x9a\xda$H\x88\xbcu\x04D@DD\x04D@DD\x04D@DD\x1f\xff\xd9' + ) def test_image_png(httpx_with_handler: HttpxWithHandler): @@ -306,7 +308,9 @@ def get_png(request: httpx.Request) -> httpx.Response: scale=3, httpx_client=httpx_with_handler(get_png), ) - assert img == snapshot(b'stateDiagram-v2\n [*] --> Foo\n Foo --> Bar\n Bar --> [*]') + assert img == snapshot( + b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01,\x00\x00\x02X\x08\x02\x00\x00\x00WDLh\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00 \x00IDATx\x9c\xed\xddy|\x1bw\x9d\xff\xf1\xcfwF3\xbalK\xb2|;\xb6s\x1fm\xe9\x996=\xe8\x16\x96v{Qz\xd0\xa5\x1c\x85R\x8er\xb5,?\x16~\x1c\x0b}\xec\x8f\x1f\xb0e\x17\xba\xfc\xa0\xd0\xb2\xb0\xd0\xd2\x83\xe3\x07\x14\xcaQ\n\xb4\x85^\xd0\xa6mz\xc6I\x9d8vb\xf9>d\xdd\x1a\x8d\xe6\xbb\x7f\xc8\xb1e\xc7qmY\xf2g&y?\xff\x92d\xcd\xf8\x9b(\xaf\x8c\xf4\x9d\xd1\x8c\x08\xad=\x85\x00\x80\x8f\xc2=\x00\x80\xa3\x1d"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98\xb9\xb8\x07\x00\xa5\xc8\x1b\xe9|.+\xf3\xa6\xb4L"\x12\x8aK\xa8.Us\xab\xba\x97{h\xb0d\x88\xd0I\xf2\xb9\x8c\x11\x1f3\x92\x13V.;\xef\x13\x14\xcd\xa3\xfb\x83zuX\xd5<+>:(\x91\xc07\xeb\x1d\xc12\x8d\xf4\xc4\x80\x11\x1f]\xe4\xf3\xf5\xea:o\xa8Eqi\x15\x1e\x17\x94\x01\xb6\x84\x0e\x90\x89\x0e\xa5\xc7\xfb\x96\xb4\x88\x11\x1f5\x12c\xde\xdaU\x9e@C\xc5\xc6\x05\xe5\xa1zC-\xdcc\x80\x85$\x87\xf7e\'\x87J[\xd6L\xc7\xac\x9c\xa1\xfb\x83\xe5\x1e\x14\x94\x13fGm-\x16\xd9e$\xc6\x97\xb3\x06#1\x16\x8b\xec*\xdf\x88\xa0\xfc\x10\xa1}%\x86\xba\xf3\xd9\xe4\xf2\xd7\x93\xcf&\x13C\xdd\xe5\x18\x11T\x04"\xb4\xa9\xf4D\x7f.9Q\xae\xb5\xe5\x92\x13\xe9\x89\x81r\xad\r\xca\x0b\x11\xdaQ\xde\xc8d\xca\xddLf\xa2?o\xa4\xcb\xbbN(\x0bDhGK\x9d\x0b]\xecj\'\xfa+\xb1ZX&Dh;f6\x95KMVb\xcd\xb9d\xd4\xcc\xa6*\xb1fX\x0eDh;\xd9\xd8H\xe5V\xbe\xf8\xdd\xfd\xb0b\x10\xa1\xed\x98\xe9x\xe5V\x9e\xab\xe4\xca\xa14\x88\xd0^\xac|\xce2\xe7?.\xb4<\xeb\xcfe,3W\xb9\xf5C\t\x10\xa1\xbd\xe4+\xff\x99-\x9f\xc3\x1c\xa9\xbd B{\x91V\xbe\xe2\xbf"_\xf1_\x01K\x82\x08\xede%"\xac\xfc\xaf\x80%A\x846#*\xfe\x8a\x08\x05/\xba\xbd\xe0\xf5\xb0\x17E\xad\xf87\x00E\xe5\x7f\x05,\t"\xb4\x97\x15\xf8\x1a\xee\nt\x0eK\x82\x08\xedE\xd1\xdc\x95}G*\x84\xa2\xb9+\xb8~X:Dh/B(\x9a\xb7\xa6r\xeb\xd7|A!D\xe5\xd6\x0f%@\x84\xb6\xa3\xf9\x02\x0e]9\x94\x06\x11\xda\x8e^\x15\x12\x8aZ\x895\x0b\xd5\xa5\xfbC\x95X3,\x07"\xb4\x1d\xa1\xa8\x9ePs%\xd6\xec\t6c\xff\x84\r\xe1%\xb1#wMC\xd9w$(.\xdd]S_\xdeuBY B;\x12B\xf8\x1b\xd6\x94w\x95\xfe\x86\xb5\x98\x92\xb1\'DhS\x9a\xb7\xda\x1bn+\xd7\xda|\xf5\x1d.\x8f\xbf\\k\x83\xf2B\x84\xf6\xe5\t4\xb8k\xcap\xea^w\xa0\xd1]\x1d.\xc7\x88\xa0"p\xf2_[\xd3|\x01\xa1\xb8\xcct\xac\xe45x\xc3m\xde\xcaL\xf3@\xb9\xe04\xf8v\xe7\t4\xa8\x9a\'1\xb4\x97\xa4\xb5\xa4\x05\x85\xa2\xfa\x1b\xd7i\xde\xea\x8a\r\r\xca\x03[B\x07P5\xb7\xbb\xa6^(j>\x97YL\x8aB\xd5<\xc1&\x7f\xc3\x1a\x17\xae\x94\xe6\x04\xb8*\x93\x93H)\xcdt\xdcHN\xe4\x92\xd1\xc2\x95\t\x8b\t\xd5\xa5\xf9\x82zU\xc8\xe5\xa9\xc6D\xa8\x83 B\xa7\xb2\xf2f\xde\xc8$\x06v\x13QU\xf3&U\xf7(*>\\8\x12^6\xa7RT\x17\x1d\xfc>\x84\xaa\xb9Q\xa0sa\x17\x05\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10\xa1MI)\xa5\x94\xf6\\\x1b\x94\x17"\xb4)!D66"\xad\xfc\xf2W%\xad|66"\x84(\xc7\xb8\xa0\xfc\x10\xa1}\xe9\xfe`\xbc\x7f\xb7e\x1a\xcbY\x89e\x1a\xf1\xfe\xdd\xba?X\xbeqA\x99!B\xfbR\\\xba\xe6\x0f\xc6\xfav\x9a\x99dik03\xc9X\xdfN\xcd\x1fT\\z\xb9G\x07e\x83\x08m\xcd\x13l"\xa1\xc4\xfbw\x1b\x89\x89\xa5.\x9b\x8d\x8f\xc5\xfbw\x93P<\xc1\xa6\xca\x8c\x0e\xca\x03\x11\xda\x9a\x10\x8a\xaf\xae\x9dH&\x87\xbb\xd3\xe3\x91E.%\xa5L\x8fGR#=D\xd2W\xd7.\x04^e[\xc3\xcbcw\xba?\xe8\xf2V\x13Q&:\x98\x18\xdc#-k\xe1\xe7K\xcbJ\x0c\xee\xc9D\x07\x89\xc8\xe5\xad\xc1\xa7A\xfbC\x84\x0e\xe0\xab\xeb \x12D\x94KM\xc6"\x9d\x0bL\xd5X\xa6\x11\x8bt\x9a\xe9\x18\x11\x91\x10\xfe\xfa\x8e\x15\x1d(\x94\x04\x11:\x80\xaa\xb9=\xc1\xc6\xc2m+\x97\x89E:\xcdl\xea\xd0\xa7\x99\xd9T,\xd2i\xe52\x85\xbb\x9e@\x13\xe6c\x1c\x01\x11:\x83\'\xd8,T\xadp[\xe6\xcdx\xff.#\x19-~\x82\x91\x98\x88\xf7\xef\x92y\xb3pW\xa8\x9a\'\x84\xf9\x18gP\xbd\xa1\x16\xee1\xc0\xab\x13B(\x9a\x9eK\xce\xcc\x91\x16n\xe7\xb3I"")\xd3\xe3}\xc5\xcf\xf77\xacq\xe9^\x86\x81\xc2\xd2aK\xe8\x18\xba?T\x98\xa1\x99\x96\x9d\x1c\x9a\xba\x11\x1b.~\x1c\xf31\xce\x82\x08\x9ddz\x86fA\xc2W\xd7\xbe2\xe3\x81\xb2@\x84N\xa2jnw\xa0a\xe1\xe7x\x82\x8d\xaa\xe6^\xa9\x11A\x19 B\x87\xf1\x86Z\xa6gh\x0e%T\xcd\x13l^\xd9\x11\xc1r!B\x87\x11\x8a\xe2\x0b\xaf:\xdcO}\xe16\xa1\xe05u\x18\xbc`\xce\xa3W\xd5\xaan\xff\xa1\x8f\xbb\xbc\xd5zU\x88cD\xb0,\x88\xd0\x91\xfc\xf5\xab\x0fyL\xf8\xeap|\x8c#!BGRu\xcf\x9c\x19\x1aw\xa0\x01\xf31\x0e\x85\x08\x9d\xca\x1bj\x11\x8aZ\xb8-T\x17\x0e\xbap.D\xe8TBQ=\x07\xc3\xf3\x04[0\x1f\xe3\\.\xee\x01\x1c9\xa4n\x08_\x86\xb4<\xb9\xcapb\x98\xc5p7\x12M\xeaD\xe4\x0eHRFW\xe6\x97\x92\xa9RN\x95)\x8f0ptxy \xc2\xe5\x92\xc2\x12\xf5Q\x11\x9aT\xfc\xcb:\x19Li|\xad\x85\x12\x96\xfc\xbd\xfb\xe5\x93I\xb7\x1c\x0f\xc8\x91\x80\xc0\xfb\xa9\xe5A\x84\xcb"\xeb&\x94\x96Q\xe1\x9a\xf9\xa2mmMuk}\xfd\x91zj3)eddd<\x16\'"\xe1\xcf\n\xff\xb0l\x1a\x93\x03a\x1a\xc5\xae\x91\xd2!\xc2\xd2\x89\xd5\xfdJm\xbcp\xfb-\x7f\xff\xba\xe3\xd6\xad\xdd\xd4\xde\x16\xaa\xae~\xb5\xe5\x1co"\x1e\xdf\xbd\xff\xc0K{\xbb\x7f\xfa\xd0\x9f\x85\x96\x17\xed\xc3\xd2\x9f\x96\xbd\x98\x19*\x91\x08\xad=\x85{\x0c\xce\xb4\xee\x80\x12H\x11QK]\xf8s\xd7\xbek}k+\xf7\x80\x18t\xf5\xf5}\xe9\xf6;\xfbG\xc7\x88HN\xfa\xe5\xde\xc3\x1e\xca\x03\x0b\xc0\xf7\tK\xb2jP\t\'\x88\xe8\xc2\xd3\xb7}\xe1}\xefi\x08\x1d\xa5\xdf\x1b\n\xd7\xd4\\x\xfa\xe9\xd1xbO_DxrR5)V\xc5=(\xe7\xc1G\xea\xa5\xf3e\x94\x86I":fu\xc7\xc7\xae\xba\xd2\xad\x1f\xf6p\xea\xa3\x81[\xd7>v\xd5\x95\xc7\xacYMDJ\xc3$y3\xdc#r\x1eD\xb8d\xa2u\x98\x88\xdc\xba\xfe\xd9k\xae>R\'`\x96D\x08\xf1\x99w\xbe\xc3\xad\xebDD-#\xdc\xc3q\x1eD\xb8D\xba!\xaa\xd3Dt\xfd\x9b/k\x08aJpJcm\xe8\x83\x97]BDJ EZ\x8e{8\x0e\x83\x08\x97(\x90$"]s\x9d\xbf\xed4\xee\xa1\xd8\xcb\xc5g\x9e\xe1\xd64"\xa2@\x82{,\x0e\x83\x08\x97\xc8\x9b!\xa2\xcd\x1d\xf8\xbe\xc2<\xd6\x15\xa6\x88\xbdY\xee\x818\x0c"\\"\xcd$\xa2u\xad\x98R\x9e\xc7\xfaU-D$t\x93{ \x0e\x83\x08\x97F\xb8\xf2D\xd4\xd1\xd4\xc8=\x10;\xeahn""r!\xc2\xa5A\x84K$$\x11\xa9\xf8\xca\xc2|4\xb5\xf0\xd5*\\\x12xi\xf0\x8f\t\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x0b\xc2\xac\xa8\xc7\x7f;v\xfb\x17\xf6/i\x91-\xa7V}\xfc\x96\r\x15\x1b\x11\xf0\xc3\x96\x10\x80\x19\xb6\x84<9\xd2\x9f\x1d\xe9\xcb\x8e\x0f\x1a\x81z\xad\xaeY\xaf_\xe5\xdepB\xd5\xb6\x0bB\xb8\xce\xd4\xcaC\x84\xce\xd3\xb5#\xfe\xc3/\x1f\x18\xdc?\xeb\x92\x0f\x89X\xaa\xb7\x93\x9e}x\xf2\x81\xbb\x86\xde\xf1\xa9\xb6\xb3.\x0e\x1f\xba`6c\xdd\xfb\xed\xfe\x07\x7f2\xeb\xeae#}\xc6H\x9f\xd1\xb9=\xf1\xc8\xbdc\x7f\xf9\xc5\xe8G\xbf\xbe\xce\xebW+\xff\x87\x80\x19\x88\xd0av<<\xf1\xedO\xf7\x14n\xd7\xd4\xbaN<\'\xb0\xe6\x18_ \xac\x8d\x0e\xe4v>\x19{\xee\x91\xc9\\V\xde\xf9\xa5\xfd\xc1:\xfd\xd8m\xd5\xc5\x0bZ\x96\xfc\xda\x87\xbb\xf6\xbd\x9c*\xdc\xddtr\xd5\xa6\xadU\xab7\xfb\x92\xb1\xfcH_\xf6\xcf\xbf\x18\x8d\x8d\x9b{^H\xde\xfa\xa9\xee\x8f}c\xbd\xa2`{\xb8r\x10\xa1\x93X\x96\xbc\xef\xbf\x87\n\xb7O\xbf \xf4\xd6\x8f\xaf\xf2\x07f^\xc1\xd7_Yw\xefm\xfd\xbf\xfb\xc1P>Ow|\xb1\xf7_\xef\xd9\xe2\xab\x9e\xd9\xa6=\xf3`\xb4P`M\xad\xeb=7\xb6\x1f{F\xa0x\xcdg\\\x1c\xfe\xcau\xafDGr\x9d\xdb\x13\x7f\xb8k\xe8\x82w5\xad\xe0\x1f\xebh\x87\x89\x19\'y\xe6\xc1h_W\x9a\x88\x9a\xd7x\xae\xf9\\Gq\x81\x05\x97\xbc\xaf\xb9u\x9d\x87\x88&\x86s\x8f\xde7:\xfd\xb8e\xc9\xdf\xdd1U\xef\x9boh\x9dS \x11\xd5\xb5\xe8o\xfe\xc8\xd4\xa5\xa6\x1e\xb8{\xc4\xc8X\x15\xfe\xa3\xc0\x0cD\xe8$;\xfe\x12-\xdc8\xeb\x92Z\x976\xcf;F\x97Kl\xbb\xa0\xb6p\xfb\xe9?E\xa7\x1f\xef\xef\xce\x14\xea\xad\n\xa8\xa7\x9d7\xff\x05\x86\xb7\xbe!\xe8\xabQ\x89(\x115_~2^\x99?\x01\xcc\x03oGy\xc4\xc6r7_\xdf\xb5\x98g^|m\xd3\xa6S\xa6>\xdd\r\xf5NM\xc6l<\xb1\xeap\xcf\xdfp\xe2\xd41\x00\x07v\xa7L\xc3r\xe9\n\x11\r\xed\xcf\x14\x1e\\\x7fB\xd5\xbc\xf5\x12\x91KW\xd6\x1d\xe7\x7f\xf1\x89\x18\x11\xf5u\xa5O:g\xee\xd6\x12*\x04\x11\xf20\xb2\xb2s\xfb\xa2.+}\xce\x153\x97\xfb\x1b\xec\x9dj\xa9e\xad\xe7p\xcfo\xec\x98\xfaQ>OcC\xb9\xc667\x11\r\x1d\x98\xaa\xb7\xa9\xe3\xb0\x0b\x12Qc\xbb\xfb\xc5\'\x88\x88F"\xb8\xda\xee\xca\xc1\xdbQ\xc7\x18\xee\xcb\x1a\xd9\xa9K\xff\xb9\xbd\x87\xdd\x8b\xe0/\x9a\x8cI\xc5\xa6\x02\x1e>\xb8?\xc3\xeb_\xe8\x15\xf7\x1c\xdc9\x91N\xe4\xcb1dX\x14l\ty\xd4\xb5\xe8\xffv\xef\xb1KZd|p*$\x8fo\xa1\x90\x14Ehn\x91\xcbJ"2\x8d\xa9\xf9\x95\xb1\xc1\\\xe1\x86\xaa-\xb4\xac\xe6\x9ez\xa7\x9a301\xb3r\xb0%t\x0c\xcd=\xb5\x99\xca\xa4\x16*\xc4\xb2d\xee\xe0\x063P\xaf\x1f\\v\xaa.#\xbb\xd0&nz\xc1`\x9dV\x8e!\xc3\xa2 B\xc7(\xde\x00\xa6\xe2\x87m)Y\xf4\xa3\xda\xa6\xa9\x08\xbd\x8b{\x9f\x99IN\xfd4\xdc\xb2\xd0\x81oP^\x88\xd01\xeaZ\xdd\xea\xc1\x8f{\x91\xee\xf4\xe1\x9e6x\xf0G\x8dmn\x97kj\x03X\xdf\xea.\xdc\x18\xd8\x97Y\xe0W\x0c\xf4L\xfd4\xdc\xec.\xcf\xa0a\x11\x10\xa1c\xb8=\xca\xda\xd7L\xed~\xd8\xfd\xccagVw\xefH\x16n\xd4\xb5\xcel\xcd6\x9c0\xf5\xa5\xc4=\xcf\'\xb3\x87\xd9\x11\x9f\xcdX{_\x98Z\xb6\xbe\x19oGW\x0e"t\x92\x93\xff>X\xb8\xf1\xc4o\xc6r\xd9yZ\xcae\xad\'~3V\xb8\xbd\xf5\r\xc1\xe9\xc77m\xad\t\x84]\x85\xcf\x93\x7f\xfd\xdd\xf8\xbc+\x7f\xe2\xb7c\x85O\x9b\x8dm\xee5\xc7.\xea\x0b\xc7P\x16\x88\xd0I\xb6\x9d_\xeb\xadV\x89h$b\xfc\xe8k}s~*\xa5\xbc\xe7\xab\x07F"\x06\x11\xad>\xc6w\xd6%3_\xa4pi\xe2\xec\xcb\xea\n\xb7\x7fu[\x7f\xdf\x9e\xb9\xeff\x0ft\xa5\xef\xfb\xce@\xe1\xf6\x9b?\xd2\\\xd8\xc5\x0f+\x03\xbb(\x9c\xa4:\xe8z\xcf\x8d\xed\xdf\xfe\xdf\xfb\xa4\xa4G\x7f566`\xbc\xf6\xb2puP#\xa2\xe8\xb0\xf1\xe8}c\xaf<\x9b "U\x13W^\xdf2\xe7\x9b\x81\x17\xbf\xbbq\xf73\xf1\xae\xe7\x92\x89\xc9\xfc\xbf_\xf7\xcayoo\xdcp\xa2\x8f\x84b\xe6\xac\xae\x1d\x89\x87~:R\xd8\x0c\x1e{z\xf5I\xaf\x9f\xff\xb86\xa8\x10D\xe80\'\xfe]\xf0\xa37\xaf\xfb\xfe\x17z\xe3\x13\xe6\xce\xa7\xe2;\x9f\x9a{\x90g\xc7\x16\xdf5\xff\xd2\xde\xb6\xc1;\xe7q\x97\xae\xfc\xd3\xd7\xd7\xfd\xe0\xff\xee\x7f\xe6\xc1h:i\xdd\xf7\xdd\x819OP5q\xf1\xb5\x8d\x17\xe2\xfb\x13+\x0e\x11:\xcfqg\xd6|\xf1g\xc7\xfc\xf9\xff\x8f\xecxd\xb2gg\x8a\x88\x02aWc\x87\'\xdc\xa4wl\xf6\x9dsE\xdd\xe1\x8e\x0eu{\xd5\x0f~y\xcd\xae\xa7c\x8f\xdc;\xf6\xd2_c\xe9\xa4\xa5j\xa2\xb1\xcd]\xd7\xe2nls\x9f~Q\xa8}#N*\xc5\x00\x11\xae\xa8\xb3.\x0e\xcf\xfb\x9d\xf7\xa5\xf2U\xa9\x17]\xdbt\xd1\xb5\xa5l\xb56o\xad\xd9\xbc\xb5f\xf9c\x80r\xc1\xe7o\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88pi\xa4\xa5\x10Q:kp\x0f\xc4\x8e\n\x7f-\x85\xbf"X<\xfc}-\x8d0U"\xda\x1b\x89p\x0f\xc4\x8e\xba\xfa"DD&\xce\xa3\xb94\x88pid\xceED{\xfb\x10\xe1<\xf6\xf6\xf5\x11\x91@\x84K\x84\x08\x97(\xe9!\xa2}\x03\x83\x96\x85\x0bJ\xcfb\xe6\xf3=\x83CDd%<\xdccq\x18D\xb8D\x93\xd5RR\xde\xb2~\xfd\xd8\x13\xdcC\xb1\x97_=\xfa\x98\x94RJ\x12\x93\xd5\xdccq\x18D\xb8DyU\x8e\xd5\x10\xd1w\x7f\xfd\x9b\xa1\xf1\t\xee\xd1\xd8E\xff\xe8\xe8\xf7\x7fs?\x11\xd1h\x9001\xb3D\xf8\xfbZ\xba\xfezi\t#g\xdet\xe7\xddRJ\xee\xd1\xf0\x93R~\xf9\x8e\xbbr\xa6)-!\x07\xcap\xa5\x8d\xa3\x8d\xea\r\xb5p\x8f\xc1i,\x85\xb2\x9a\x08%F\xa2\xd1\xe1h\xf4\xe4M\x1b]\xd3\xd7\x92?\xfa\xa4\xb3\xd9\xff\xfc\xc9\xcf\xb6w\xee""\xd9\xddL\xe9\xb9\x97d\x83W\x85\x08K\x92qKI\xa2:\xbd7\xd2\xff\xf0\xb3;6\xb4\xb56\x84\x8e\xc6\x0bk\xbe\xd8\xdd\xfd\xe9[\xff\xeb\xc5\xbd\xddDdE\xeah\xech\xfcKX>\x11Z{\n\xf7\x18\x1c\xabvR\xe9\x18"!\x89h]k\xcb\xa9[6\x9f\xbae\xd3\x96\xd5\xab\x8f\xec\r\xa3\x99\xcf\xbf\xbc\xaf\xe7\xe9\x9d\xbb\x9e\xea\xec\xdc70HD$\x85\xb5\xaf\x89\xa2\xb8\xdcZ\x89\x10\xe1\xb2H_Z\xe9\x18\x14\xde\x99\x03h|n\xf7\xbaU\xads.U}\xc4\x90R\xee\xed\x8b\xa4\xb2\xd9\x99G\xd2\xba\xd5\xd3,\xd2\xd8-Q:DX\x0eu\x13"\x90$\x7fZ\xb8\x8e\x96\x9d\x872\xa7P\xca+\xa3~\xbc\x05]>\x1c\xdcP\x0e\xa3!9\x1a""K5\x85\x9e\x97j~e~\xad\xcc\x9b\xc9\xe1n"\xf27\xac\x15\xea\n\xbd\x94"\xafJC\x15y\xfc\xcb)\x1b\xfcU\x96\x93\xc8\xbb(\xedZ\xb1w\xa2\xd2\xcc\x99#y""\xafW\xb8\xb4\x95\xfa\xb5td\xbe\xd5\xe6\x83\xfd\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x846%\xa5\x94R\xdasmP^\x88\xd0\xa6\x84\x10\xd9\xd8\x88\xb4\xf2\xcb_\x95\xb4\xf2\xd9\xd8\x88\x10\xa2\x1c\xe3\x82\xf2C\x84\xf6\xa5\xfb\x83\xf1\xfe\xdd\x96i,g%\x96i\xc4\xfbw\xeb\xfe`\xf9\xc6\x05e\x86\x08\xedKq\xe9\x9a?\x18\xeb\xdbif\x92\xa5\xad\xc1\xcc$c};5\x7fPq\xe9\xe5\x1e\x1d\x94\r"\xb45O\xb0\x89\x84\x12\xef\xdfm$&\x96\xbal6>\x16\xef\xdfMB\xf1\x04\x9b*3:(\x0fDhkB(\xbe\xbav"\x99\x1c\xeeN\x8fG\x16\xb9\x94\x942=\x1eI\x8d\xf4\x10I_]\xbb\x10x\x95m\r/\x8f\xdd\xe9\xfe\xa0\xcb[MD\x99\xe8`bp\x8f\xb4\xac\x85\x9f/-+1\xb8\'\x13\x1d$"\x97\xb7\x06\x9f\x06\xed\x0f\x11:\x80\xaf\xae\x83H\x10Q.5\x19\x8bt.0Uc\x99F,\xd2i\xa6cDDB\xf8\xeb;Vt\xa0P\x12D\xe8\x00\xaa\xe6\xf6\x04\x1b\x0b\xb7\xad\\&\x16\xe94\xb3\xa9C\x9fffS\xb1H\xa7\x95\xcb\x14\xeez\x02M\x98\x8fq\x04D\xe8\x0c\x9e`\xb3P\xb5\xc2m\x997\xe3\xfd\xbb\x8cd\xb4\xf8\tFb"\xde\xbfK\xe6\xcd\xc2]\xa1j\x9e\x10\xe6c\x9cA\xf5\x86Z\xb8\xc7\x00\xafN\x08\xa1hz.93GZ\xb8\x9d\xcf&\x89\x88\xa4L\x8f\xf7\x15?\xdf\xdf\xb0\xc6\xa5{\x19\x06\nK\x87-\xa1c\xe8\xfePa\x86fZvrh\xeaFl\xb8\xf8q\xcc\xc78\x0b"t\x92\xe9\x19\x9a\x05\t_]\xfb\xca\x8c\x07\xca\x02\x11:\x89\xaa\xb9\xdd\x81\x86\x85\x9f\xe3\t6\xaa\x9a{\xa5F\x04e\x80\x08\x1d\xc6\x1bj\x99\x9e\xa19\x94P5O\xb0yeG\x04\xcb\x85\x08\x1dF(\x8a/\xbc\xeap?\xf5\x85\xdb\x84\x82\xd7\xd4a\xf0\x829\x8f^U\xab\xba\xfd\x87>\xee\xf2V\xebU!\x8e\x11\xc1\xb2 BG\xf2\xd7\xaf>\xe41\xe1\xab\xc3\xf11\x8e\x84\x08\x1dI\xd5=sfh\xdc\x81\x06\xcc\xc78\x14"t*o\xa8E(j\xe1\xb6P]8\xe8\xc2\xb9\x10\xa1S\tE\xf5\x1c\x0c\xcf\x13l\xc1|\x8cs\xb9\xb8\x07pd\x92\xaaI\x9aI\xaeW\xf9\xda\xd12\xe9^ONQ\x89HopKu\x9eC\xba\xcb\xc9T(\xe7\x12y\xfc\x83)?\xfc\x9d\x96\x957-\xc2\x93\x14\x8a+Ze\xf3\x9b\x16\xd8R8@t`e~\x9d4T\x19\xad\x92\xe3\x01\x91\xc2\x81\xa9e\x83\x08\xcb\xc4\x9f\x12\xcd\xa3\xa2&=\xfd@}0\xd0\\W\xc7:\xa6r\x1a\x18\x1d\x1d\x89N\n=/\x1a&\xa9a\xd2\x8ay\xa9\xbf\x9e\x90b9 \xc2r\xa8\x1fW\xdaF\n7\xaf\xbe\xe0\x1f\x8e\xe9h\xdf\xd8\xdeV\xe3\x9fgW\x9e\xa3\xc5\x92\xc9\xdd\xbd\x07^\xee\xe9\xb9\xe7\x0f\x7fRj\xd2T\xb3\xdf:PO#\xb5\xdc\xe3r<\x11Z{\n\xf7\x18\x1cn\xd5\xa0\xd20ID\x1b\xdaZ?\xfb\xae\xab[\xeb\xeb\xb9\x07Tq\xfb\x87\x87n\xba\xe3\xee=\x91~"\xb2\x86\x82\x14i\xe4\x1e\x91\xb3\xe1\xfb\x84\xcb\xd30\xa64O\x10\xd1\x95\xaf?\xe7\xc6k\xaf9\xf2\xb6~\xf3\n\xf8\xab.>\xeb\x8cT&\xd3\xd9\xd3+\xaa22\xafP\x12\xefKK\x87y\xedep\x1bJ\xeb(\x11\x9dq\xdc\xb1\xd7]z\t\xf7hV\xda\x07.{\xd3\xa9[6\x11\x91\xd2:B\xfa\xb2\xceP|\x94C\x84\xcb\xd02B\x82\x02~\xff\'\xde~\x15\xf7Px|\xf2\xedo\xad\xf6yI\x10\xb5\x8cp\x8f\xc5\xc1\x10a\xa9\\\xa6\x12J\x10\xd1\xa7\xde\xf9\xf6j\x9f\x8f{4<\x82\xd5\xd5\x1f\x7f\xdbUD\xa4\x84\x12\xa4\x9a\xdc\xc3q*DX\xaa`\x9c\x88\x1aB\xa1\xad\x9b7q\x0f\x85\xd3Y\xaf9.\x1c\xa8!A\x14Hp\x8f\xc5\xa9\x10a\xa9\xfc\x19"Z\xdb\x82o\xd0\xd2\x9a\xc2_\x82?\xc3=\x10\xa7B\x84%\x12Zn\xe6\xdf\xdf\xd1mms3\x11\x91\x9e\xe3\x1e\x88S!\xc2R\xe9&\x11\xadiF\x84\x07\xff\'\xd2\xf1\x99\xb0D\x88\xb0DRXD\xa4k8\xe4\x88d\x8c\x0f\xe5\xf29Yx\xe4\x95g\x13\xb7|r\xdf\xe7\xee\xd8\xa4\xaa\x82i\x98PA\x88\x90YMX\xfb\xf8-\x1b\x0e}\xdc\xcc\xc9\xdd\xcf&\x1e\xb8s\xb0s{\x82\x88\xfa\xba\xd2O\xff)\xba\xed\xfc\x10\xc7\x18\xa1\xb201cS.M\x1c\xbb\xad\xfa\xfa\xaf\xaek\xdb0u\xd5\xb1\xe7\x1f\x8dr\x0f\n*\x02[B[\xd3=\xca\xe6\xad\xd5\x07\xba\xd2D4\x12\x99\xff\xf2c\x96%w\xfc9\xfa\xb7\xdfO\x8c\x0f\x18\xf1\xa8\x99\x984C\rzS\x87\xa7e\xad\xfb\xf4\x0bj[\xd7\xcds\xe5\xc0\x81\xde\xcc\x8do\xe9$\xa2cN\xab\xfe_\xdf\\?6d\xfc\xe2[\xfd\xfb^N\x8eF\x8c7\xbe\xb7\xe9M\xef\xc7\x19\x8dW\x14"\xb4\xbb`\x83V\xb8\xe1r\xcd\xf3\x810:l|\xebS\xfbzv\xa6\x8a\x1f\x1c>\x90\x1d>\x90}\xe11\xfa\xfd\x0f\x87O8\xbb\xe6\xdd\x9f\xef\xa8\n\xccz\xa15m\xea\x1dP6me\xd3\xf9\x9b?\xb2g\xf8@\xb6\xf0H*\x9e\xaf\xd8\x1f\x05\xe6\x87\x08\xed\xae\x7fo\xbapc\xce\xfc\r\x11\x99\x86u\xcb\'\xbb{wM=\xe1\xf8\xb3j\xb6\x9cZ\xdd\xb4\xc6\x13\x1b7\xfb\xf7\xa6\x1f\xbfo,\x11\xcb?\xffh\xecg\xdf\x88\xbc\xfb\xf3\x1d\xc5\x0b\xba\x0e\xbe\xec\xb9\xac\xf5\xe0OF\x0b\x056\xb6\xb93\x19\x9cE\x9b\x01"\xb4\xb5\xc8\xde\xf4\xf6?N\x10\x91\xe6\x16oxK\xfd\x9c\x9f\xeext\xb2P\xa0\xee\x16\x9f\xb8u\xc3\x9c\xdd\x89\xa7\x9d\x1f\xfa\xf7\xeb\xba\xb2i\xeb\xf1\xdf\x8c\xbf\xf6\xd2\xf0\xfa\xe3\xab\xa6\x7f$\x0e\xce\xb2\xe6r\xf2\xaf\xf7\x8f\x1d{F\xcdU\xff\xd4\xd2\xbc\x06\x97\xbc\xe6\x81\x89\x19;\xb2,\xb9\xff\x95\xd4\xfd?\x1c\xfa\xea\x07\xbb\x8c\xac$\xa27\xbe\xa79\xd4\xa8\xcfy\xda\xf8\xa0\xd1\xba\xce\x13\x08\xbbN;\xbf\xf6\xd0\x1d\xfa\xed\x1b}[\xcf\r\x16nw\xbf4\xeb\xfd\xaar0\xc2\xb1\xfe\xec\xc4P\xee\xda\xcf\xb7\xa3@F\xd8\x122\x1b\xed7\xde\xbfm\xc7\x02O\xa8o\xd5\xdf\xf4\xfe\xe6\xd3/\xac=\xf4G\xe7\xbf\xa3\xf1\xfcw4.\xb0\xec\xeac\xfc\x8f\xffz\x9c\x88\x06\xf6\xa5\xe7}\x82\x91\x95g_Z\x1b\x08kK\x1f8\x94\r\xb6\x84\xb6\x16j\xd0N=/\xe4\xf6\xa9\xb9l)\x9f\xd64\xf7\xd4\x16o|\xe8\xb0\x17\x0f<\xe1\xec\xc02\x06\x08e\x80-!3_\x8dz\xee[\xe7~\xd8\xcb$\xad\xd8Xnb8\xd7\xfdr\xf2w\xb7\x0f\x11Qm\x93~\xdd\x97V\xaf;n\x9e\x83H\x8d\x8c\xf5\xec\xc3\xd1g\x1e\x8a\x8e\r\x18\xb1\x89\\l\xcc\x94r\xees\xa4u\xc8C\x07\xb5\xac\xf5\x94\xe7O\x02\xa5B\x84\xcc|U\xea%\xef=\xec~\xb9x\xd4\xfc\xc5\xb7"\x8f\xdd7>>h\xfc\xbf\x8f\xee\xf9\xc4m\x1b\xda7\xfa\x8a\x9f\xf0\xc8\xbd\xa3\xf7\xde\xda\x9f\x98,}\xbfBM-\xfe\r0\xc3\x0b`k\xd5A\xd75\xff\xd2\x11\x9f0\x9f\x7f4\x96NZ\xf7\xdf>\xf4\x81/\xaf\x99\xfe\xe9S\x7f\x18\xbf\xf3\xa6\x03\x85\xdb\rm\xees\xdfV\xdf\xbcz\xd6\xfcJ\xe7S\xb1\xc2\x86t\x01\xaa\x86\x8f$\xcc\x10\xa1\x03\x9c}y\xdd\xf3\x8f\xc6\x88\xe8\x85\xc7&\xb3\xe9\xbc\xdb\xab\x16fP\x7fy\xdb@\xe1\t[\xdf\x10\xbc\xf6\xc6\x0e\xdd37\xa7\xb1\xc1,\xc7xai\xf0\xbf\xa0\x03\xac\xd92\xf5\x16\xd4\xc8\xca\xc1\x9eL\xe1v\xd7\x8eD\xe1@6\xdd-\xde\xf9\x99\xf6C\x0b$\xa2T\x0c\xd7\x91w\x00D\xe8\x00J\xd17\x98\x0ccj\x8a\xa5\xbf{\xaa\xc6\xf5\'T\xf9\xaa\xd5y\x17\xec\xd99\xff\x9e\t\xb0\x15D\xe8\x00}]3\xbb\xdaC\xf5S\xbb\xec\x8d\x83\x87\x98\x1d\xae\xc0\xe8\xb0\xf1\xdc_\xf0\xc5\x0b\x07@\x84vg\x9a\xf2\x97\xb7\r\x16n7\xaf\xf1\x84\x9b\xa7v\xac\xd7\xb7N}\xd1>::\xff>\xc0\x9f~#R8\xda\xa6\xf0m}\xb0-Dhk\xa9\x98\xf9\xdf7\xf6\xec}1Y\xb8{\xd15\x8dBL\xbd5\xado\x9b\x8ap\xef\x0b\xc9\x97\x9e\x88\x15/ed\xac\xdb\xbf\xd8\xbb\xfd\x8f\xd1\xcb>\xd8Txd\xe8@6\x9f?\xec\xaeB\xe0\x85\xd9Qf\xb1\xb1\xdc\xcd\xd7w\xcd\xfb#\xd3\xa4\xde\x9d\xc9\xe9\xad\xd9\xe9\x17\x86\x8a\x0f^[\xb5\xde\xb3\xe9\xe4\xaa\xdd\xcf&\xa4\xa4[>\xb1\xf7\xdc\xb75l<\xc9\xaf{]\xc3\x072\x0f\xfdt$\xb27s\xeay\xc1s\xae\xa8/lE\'Gr?\xf8?\xbd\xa7_T\xdb\xdc\xe1\xc6\xb9j\xec\x06\x1123\xb2\xb2p\x02\x8b\x05\xa8.\xfa\x87w4^\xfe\xa1Y\xfb\xf4\x85\x10\xef\xfaL\xdb\xd7?\xb6w$b\xe4\xf3\xf4\xc0]\xc3\x0f\xdc5\xf3\xd3\xcd[\xab\xaf\xfet\xbb\xafJ=\xfe\xb5\x81\x17\x1e\x9b$\xa2\'\x1f\x98x\xf2\x81\x89\xcb?\xd4r\xd1\xbb\x17:\xdc\x14V\x1e"\xb4/\xaf_Y\xb5\xc1\xbb\xf1\xe4\xaa3/\xacmh\x9f\xe7\xe0\xb2\x86v\xcf\xe7\xee\xd8\xfc\xf3oE\xba_LF\x87s\x89X\xde[\xadn8\xa1\xea\xe4\xd7\x07\xcf\xbc8Tx\xe3\xfa\xae\xcf\xb6\xdd\xf3\x1f\xf4\xfc#\x93\xf9<\xd56h\xed\x1b\xf1m\t\xdbA\x84<\xce\xba8|\xd6\xc5\xe1\xe5\xaf\xc7W\xad\xbe\xf3\xd3\xed\x0bt\xd3\xda9\x0fV\x07]\xdf}\xf2\xa4\xe5\xffv(\x0bL\xcc\x000C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84%\x12$\x88\xc8\xc4\xf9\xe5\x89\xf2\x85\xbf\x84R\xae\xe7\r\x84\x08\x97\xc1T\x89h\xff\xe0\xab\\\x82\xf3h\xd038DD\xd2\xc4\xe93K\x84\x08Ke\xba\x88hO\xa4\x9f{\x1c\xfc\xf6\x1c\xe8#"\xca!\xc2\x12!\xc2\x12\xc9\x94\x87\x88\xf6\xf4E\xb8\x07\xc2\xaf\xab\xaf\x8f\x88(\x85K\\\x94\x08\x11\x96HF\xab\x88hxb\xe2\xa9\x9d\xbb\xb8\xc7\xc2\xe9\x89\x17_\x1a\x9b\x8c\x11\x11\xc5\xaa\xb9\xc7\xe2T\x88\xb0D"\xed\x91I\x0f\x11\xfd\xc7=?\x8e%S\x8bX\xe2\x08\x14M$\xbez\xcfO\x88H&\xbc\x94\xc6\x96\xb0D\x88\xb0t2ROD\x93\x89\xc4\xcd?\xfe\t\xf7Xx|\xe5\xce{\x12\xe94\x11\xc9\xbe\x06\xee\xb18\x98\xea\r\xb5p\x8f\xc1\xb1\x0cM\xaa\xa6\xf0g\x0f\x0c\x8f\xa42\x99\xad\x9b7q\x0fhE}\xeb\xe7\xf7>\xfc\xecsDd\r\x05i<\xc8=\x1c\x07C\x84\xcb\x13\xf3SuJ\xe8fgO\xef\xc3\xcf\xec8n\xdd\xda\xda\x9a#\xff\xa3\xd1+\x07\xfa>y\xcb\xad\xdb;w\x11\x91\x8c\xf9\xa8\xb7\x99Hp\x0f\xca\xc1Dh\xed)\xdccp8\xc5\x12k\xfaE IDB\xd0\xc6\xb6\xb6\xad[6\x9f\xb6e\xd3\xa6\xf6vE9r\xde\xed[\x96\xd5\xd9\xdb\xbb\xbds\xf7\xd3\x9d\xbb^)\xec\x93 \x92\x93~\xb9\xaf\x85\xac#\xe7\x8f\xc9\x02\x11\x96I\xe3\xa8\xd2:V\xfc@\x95\xcf\xbb\xb6\xe5\xc8y\x97\xb17\xd2\x9fL\xa7\x8b\x1f\xb1"u4T\x86K,\x02",\x1b\xe9\xce*\xad#T\x93\x14G\xf4\x86A\xe6\x05\xc5}V_\x830t\xee\xb1\x1c!p\x94C\xd9\x88\xac[v\xaf""\xcb\x9b\x11\xbaA\xbaI\xae\xca\x1eO)-+;9DD\xee@\xa3\xa8\xf4[_S!\xc3%\r]\xa4=\x84\x8f\x80e\x85\x08\xcbO\xa4=\x94\x9e\xe7\x12\xf3e\'\xcd\\z\xff\x01"\xd2\xdbC\xc2\xa5\xad\xc0oD{\x95pD\xbfs\x02p\x02D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003D\x08\xc0\x0c\x11\x020C\x84\x00\xcc\x10!\x003DhSRJ#\x19-\xd7\xda\x8cdTJY\xae\xb5Ay!B\x9b\x12B(\xaa+9\xbco\x99\xf1Hi%\x87\xf7)\xaaK\x08Q\xbe\xd1A9!B\xfbry\xaa\x88(\xde\xbf\xdb\xca\x9b\xa5\xad\xc1\xca\x9b\xf1\xfe\xddD\xa2\xb0*\xb0\'Dhk\xdep[\xdeH\xc7\xfav\xe6\x8d\xccR\x97\xcd\x1b\x99\xc2\x82\xde\xf0\xaa\xca\x8c\x0e\xca\x03\x11\xda\x9a\xa2\xba\xbc\xb5\xad2\x9f\x8bE:s\xa9\xd8\xe2\x17\xcc\xa5b\xb1H\xa7\xcc\xe7\xbc\xb5\xad\x8a\xea\xaa\xe4\x18a\xb9\x10\xa1\xdd\xb9k\xeaU\xddK\xd2J\x0cve&\x87\x16\xb3H&:\x94\x18\xec"i\xa9\xba\xd7]S_\xf91\xc2\xb2 B\xbb\x13B\xf8\xea:\n\xb7\xd3c}\xc9\x91\x9e\x05\xa6j\xa4\x94\xc9\x91\x9e\xf4x_\xe1\xae\xaf\xbe\x03\xf31\xf6\x87\x08\x1d\xc0\xe5\xf1\xeb\xd5\xe1\xc2m\xa9\x128\'\x00\x00\x07\xbdIDAT#>\x96\x18xEZ\xf9C\x9fV\x98\x861\xe2c\x85\xbbzu\x9d\xcb\xed_\xd9\x91B)\x10\xa13xkW\tE-\xdc63\x89X_g>7k\xaa&\x9f\xcb\xc4#\x9d\xf9l\xb2pW(\xaa\xb7\xb6\x95c\xa4\xb0d\x88\xd0\x19\n34\xd3w-3\x1b\xeb\xeb43\x89\xc2\xddB\x96\x96iL?\x01\xf31\x0e\x82\x08\x1dC\xaf\xaeSu\xef\xcc}i%\x87\xbb\x0b7\x93\xc3\xdd$\xad\xe9\x9f\xa8n\x9f^]\xc70D(\t"t\x8c\xe2\x19\x9a\x85\xf9\xebWc>\xc6A\x10\xa1\x93\xb8<\xfeW\xdd\xc4M\xed\xd2\x00\xe7@\x84\x0e\xe3\xadm\x9d\x9e\xa19\x94P\\\x9eP\xcb\xca\x8e\x08\x96\x0b\x11:\x8c\xa2\xba\xbc\xb5\x87=\x0c\xcd\x1b\xc6|\x8c\xf3 B\xe7q\xd7\xd4\xa9n\xdf\xa1\x8f\xabn\x9f\x1b\xf31\x0e\x84\x08\x1di\xde\x19\x1a\x7f\xfdj\x8e\xb1\xc0r!BGr\xb9}s\x0e\nu\xd74`>\xc6\xa1\x10\xa1S\x15\xcf\xd0\x08E\xf5\xd6b>\xc6\xa9\x10\xa1\x83\xe9\xd5S\x1bC\xbd\xa6\x81{,P:\xcc\xa49\x89\x957s\xc9\t#1\x917R\xc5\xc7pg\xa3\x03\xd9\xe8\x80PT\xd5\xed\xd3\xfd!\xcd\x1f\xc2\x1c\xa9\x83\x88\xd0\xdaS\xb8\xc7\x00\xaf.od\xd2\xe3\x91\\j\xb1\xa7~\xd2\xfcAo\xa8U\xd5=\x15\x1e\x17\x94\x01\xfe\xbf\xb4;i\xe5Sc}F|tIK\xe5\x92\xd1\\2\xea\xae\xa9_x\xe7>\xd8\x01"\xb4\xb5|.\x9b\x18\xdcc\xe5\x96|\x82\x99\x82ll$\x97\x8eW5\xadW5w\xb9\x87\x06e\x83\x08\xed\xcb\xcc\xa6\x12\x03]\xd2\x9a{\xaa\xb5\xe3NZ\xb3\xed\xec\xcd\xaf9yMk{}Sk\x88\x88\x06\xfa\xc6#\xfbG_x\xa6{\xfbc\xbb^z\xae\xa7\xf8\xc9V.\x13\xef\xdfU\xd5\xb4\xc15\xdf\xfe}\xb0\x03|&\xb4)\xcb4b}\x9ds\n<\xe3u\xc7|\xe0\xe3o|\xcd\xc9k\x17X\xf0\x85g\xba\xbf\xf3\xb5_\xff\xed\x91\xce\xe2\x07\x85\xea\xaai=Fqi\x15\x1b/\x94\x0e\x11\xdaT,\xd2\x99\xcf\xa6\xa6\xef\x06\x82\xfe\xaf\xfc\xd7u\xa7\x9e\xb9i\x91\x8b?\xf9h\xe7g>\xf4\xbd\xc9hr\xfa\x11\xd5\xed\xafi\xdd\\\x81\x91\xc2r\xa9^\x1cto?\xe9\xf1H.91}\xb7\xa5-\xfc\xfd_~r\xf3q\xed\x8b_\xc3\xaa\x8e\xfas\xdfx\xca_\xfe\xf0|<\x96.<"\xf39"\xd2\xbc\xd5\x15\x18/,\x0bv\xd6\xdbN\xdeHg\xa2\x83\xd3w=\x1e\xed\x1b?\xbc\xbe\xb5}\xc9Gf\xb7\xb6\xd7\xfd\xe7\x0f>\xec\xf1\xcc\xbc\x05\xcdL\x0c\xe4\x8dt\xf9F\n\xe5\x81-\xa1\xed$\x87\xf6\x15\x9f-\xe6S_z\xdb\x99\xaf;\xf6\xd0\xa7\xc5\x92\xc9\x07\x9ez\xfa\xc9\x9d\x9d\xcf\xef\xd9\xdb;8\xd8ZW\xa7ks?\xf2\xd5\xd6\xd5\xd4\x04\xfc\x8f=\xf4\xd2\xf4#\xf9\\\xd6}\xf0\xc4m`\x13\xf8Lh/\x85\x93\xdeO\xdf=\xef\x92Sn\xba\xf5\xfds\x9e\xb3\x7fp\xf0\xee?>\xf8\xc8s\xcf\xe7\xf33\xe7\x95q\xb9\xd4\xd7\x9dx\xc2[\xcf{C{c\xe3\x9c\xe7\x7f\xe2\xfd\xb7=|\xffs\xd3wkV\x1d\x8b\x9d\xf8\xb6\x82-\xa1\xbdd\xa2C\xd3\xa7-$\xa2o\xdeuCU\xf5\xac\xefFt\xf6\xf6\xfe\xf37\xbf\xddu 2\xe7\x14\xc0\x96%\xbb\xfb\x07\xfe\xb4\xfd\x99\x137\xae\xaf\x0b\x06\x8b\x7f\xf4\x9a\x93\xd7\xdc\xf3\xbd\x87\xa6\xef\nE\xd5\xbc5\x95\xfcC\xc0\xd2\xe03\xa1\xbd\x14\x1f\x98\xb6\xed\xec\xcdM-\xb5\xc5?\x8d\x8c\x8c~\xf6\xb6\xef\xa5\xb3\xc6|\x8b\x12\x11\xa5\xb2\xd9\xcf~\xe7{\x83c\xe3\xc5\x0f6\xaf\no-\x9aV-\xe3e\x0f\xa1,\x10\xa1\x8d\xe4sY+\x97\x9d\xbe{\xfe\xa5\xa7\xcey\xc2Mw\xde\x9dL\xcf\x9aY\x91$\xe7l\x12\x13\xa9\xf4\xbf\xddy\xf7\x9c\x05\xcf\xbft\xeb\xf4m+\x97)\xfe\xcc\t\xec\x10\xa1\x8d\xe4\x8dT\xf1\xdd\xd3\xce\xdeR|\xb7\xab\xafo\xf7\xfe\x03\xd3w%IIR\x90\x10BH9+\xc5\xce\x9e\xde\xee\xfe\x81\xe2e\xb7\xcd^\x95\x99\x9d\xf5\x8b\x80\x17"\xb4\x11+Wt\nm\x9f\xbb\xb9u\xd6{\xd1\xa7w\xed\x9e\xbe-\xa5$I\x82\xa6N.z\xe8YF\xb7w\xce:bf\xce\x1e\x8e\xc2>C\xb0\tDh#\xb2\xe8,\xda\xc1\xda\xb9\xd7\xd6\xed\x1b\x1a.\xbe;\'\xfa\x96+N\xda\xb8\xa1\xf8\x91T2\xf3\xfb_m\x9f\xf9\x15>\x1c\xb3f/8v\xd4^\xa4\x94\xd3G\xae\x19Y\xd3\xed\xd1O>}VQ\x9b\xda\xdb\x9a\xeb\xc2\xaf\x1c\xe8Ke\xe6\x9ex\xa6>\x14\xbc\xe1\xca\xcb/\xd8\xb6m\xce\xe3\xb7\x7f\xfb\x81\'\x1e~y\xfa\xae7\xd4\x8csu\xdb\n\xbeEa/\xd2\xb2\xa2\xbd\xcfO_v\xd7\xe3\xd1~\xf6\xe7\x7fm^5\xf7\xcbG\x96e\xfd\xed\xe5\x9d\x0f>\xfd\xecd2ID\xc1*\xffy\xa7\x9dz\xea\xe6M\x8a2\xf7\xad\xcd\x81\x9e\x91\xab\xce\xfdB63\xb5w^(j\xa0\xfdxq\xc8\xd3\x80\x11"\xb4\x9dLt0=\x1e\x99\xbe\xdb\xb1\xb6\xf1\xbb?\xff\xe7p})\xef!\xc7Gc\xef\xbd\xfc\xab\xfb\xf7\xcd\xec\xe5\xf7\x86Wy\x02s\xbf\xeb\x04\xbc\xf0?\xa2\xedx\x82M\xc5\xd3\xa4\xbd\xddC\xd7\xfd\xe3\xcd\xc5{\xf9\x16)\x16M\xbe\xef\x8a\xaf\x15\x17\xa8\xea^\x14hC\x88\xd0\x8e\xfc\rk\x8a\xef\xf6\xec\x19\xbc\xe1\xeaoF\'\x12\x8b_\xc3\xc4X\xfc\x86\xab\xbf\xd9\xdb=\xb4\xc0j\xc1&01cG\x8aKST-\x97\x9a9\xfesh`\xe2\x97?zLJ\xb9\xf9\xb86M[\xe8l\xb1\xe9T\xf6\xce\xdb\xfe\xf8\x99\x0f\x7f\xaf\xafw\xd6I\xbb}u\xed\x9a/p\xf8\xe5\x80\r>\x13\xdaWr\xa4\xf7\xd0\xb3\xdfW\xd5x\xaf|\xe7\xdfm=s\xd3\xf1\xa7\xac\xf5W\xcd\xbckM\xc4\xd3/>\xbbo\xfbc\xbb~~\xf7\xa3\x89\xd8\xdc\xf7\xae\xee@\xa3/|\xd8\x8bl\x03/DhkFb<9\xd2s\xb8\xe3\xad\xd7on\r\x84\xfcD49\x91\xd8\xb3\xab\x7f\xfeU\x08\xc5_\xbfZ\xaf\nUv\xa0\xb0\x0c\x88\xd0\xee\xccl*9\xbc\xaf\xb4\xcbQ\xa8\xba\xd7\xdf\xb0\x06{\x05m\x0e\x9f\t\xedNqi\x9e@\x83\xa2jf&IE_8\\\x98P]\xbep\x9b\xbf\xbeCQq\xea{\xbb\xc3\x05a\x9c\xc1]S\xef\xae\xa97\x12\x13Fr\xa2\xf8\xe4\xdc\x87\xd2\xabj5\x7fP\xf7\xe3\xfd\xa7c B\'\xd1\xabBzUHZy#\x1953\t\xcb\xcc\xd2\xc1\xafP(.\xb7\xcbS\xa5\xfbC8\x1a\xc6q\x10\xa1\xf3\x08EuW\x87q"\xed#\x06\xfe\xd7\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98!B\x00f\x88\x10\x80\x19"\x04`\x86\x08\x01\x98\xfd\x0f\xe2\x0b\x9fxKo\xdc\xa7\x00\x00\x00\x00IEND\xaeB`\x82' + ) def test_image_bad(httpx_with_handler: HttpxWithHandler): @@ -366,7 +370,7 @@ def get_jpg(request: httpx.Request) -> httpx.Response: path = tmp_path / 'graph.jpg' graph1.mermaid_save(path, start_node=Foo(), httpx_client=httpx_with_handler(get_jpg)) assert path.read_bytes() == snapshot( - b'---\ntitle: graph1\n---\nstateDiagram-v2\n [*] --> Foo\n Foo --> Bar\n Bar --> [*]' + b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xe2\x01\xd8ICC_PROFILE\x00\x01\x01\x00\x00\x01\xc8\x00\x00\x00\x00\x040\x00\x00mntrRGB XYZ \x07\xe0\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00acsp\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\xf6\xd6\x00\x01\x00\x00\x00\x00\xd3-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\tdesc\x00\x00\x00\xf0\x00\x00\x00$rXYZ\x00\x00\x01\x14\x00\x00\x00\x14gXYZ\x00\x00\x01(\x00\x00\x00\x14bXYZ\x00\x00\x01<\x00\x00\x00\x14wtpt\x00\x00\x01P\x00\x00\x00\x14rTRC\x00\x00\x01d\x00\x00\x00(gTRC\x00\x00\x01d\x00\x00\x00(bTRC\x00\x00\x01d\x00\x00\x00(cprt\x00\x00\x01\x8c\x00\x00\x00\x11{]\xf8\x9b\xe9o\xa3\x1e\x82_\xbcs\xcf\xbaw\x193\xb3v\xdef\xecc\x97\x9f\x8f\x9d\xbf:\xfa\xc7\xd8\xc3\xb3\xed_g~\x0f\xc7h\xbb\xc9\x14\x9a\x86\xe5Pn\x17\x01\x0b\x83\x99\x0b\xdc\xd6\xb5\xb0\x87\x0f}\xb5\xad\x19#\xa6\xe2\xec\x120T\xdcc\xdb\x06|\xf3\xe8\xb8\xff\x006\xac4\x04D@DD\x04D@DD\x15\xe8\xcf\xb6\x08\xf9c\xd1q\xf2g\xee\xbf\xda\xac%^\x03\xf6\xc1\x1f\xfa\\z\xbf;>\xb5a\xa0""\x02" ""\x02"\xe1,\xd1\xc0\xc0\xe9\x1e\xd8\xda\\\x1b\x97\x9c\x0c\x92\x00\x1f\xa4\x92\x00\xf9\xca\n\xf8\x0f\xb6\x10\x9f\xea\xb0\xff\x006\xacE^\x01\xf6\xc1\x13\xd3\xf9.\x07\x98\xcf\xddg\xd4\xac\x08\xa6\x8ev\x97F\xf6\xc8\xd0\xe2\xdc\xb0\xe4d\x12\x08\xfd \x82\x0f\xe8A\xcd\x11\x10\x11\x11\x01\x11G\xb5\xd5\xe6\xa6\xcba\xdfF\xf1\x15]EL\x14\x91\xca\xe6\xee\xe5\x99%k\x0b\xf0z\x12\xd6\x92@=\t\x00\x1e\x8a\xf4Q8\x95E\x11\xbeD\x85a\xde-\x14w\xfbMe\xb2\xe1\x03jhk!|\x13\xc2\xff\x00\'\xb1\xc0\x87\x0f\xd6\n\xaf\xdf\xa1\xac\xd3\x9d\xd5\x14\xcf\xab\x94\xfb\xe9\xaag\x92G\xb8\xfc\xa5\xc5\xcb\x8f\xa0\x1a\x7f\xf1l\x7f\xe3w\xf1]\xfc\xdb\x0f\xb7>\x1f\x94^\x1a\xa0\x1f\xc6\xcfl\x97\xb0\xe1\xbb\xccc\xf0\xfeQ\xd6\xb8=\xfb\xd1\xfev\xfef\xff\x00.\xf1\x9f\xb0sq\x9d\xff\x00?\xbb[\xe3g\xb4Q\xd8-4v\xcb|\r\xa6\xa1\xa3\x85\x90A\x0b<\x98\xc6\x80\x1a?P\n\xb9\xf68\xd3]\xe3\x9f\xe1\x10s\xf6\xec\xe6\xe5\xdb\xb6\xe78\xces\x8c\xfa\x97g\xa0\x1a\x7f\xf1l\x7f\xe3w\xf1Nm\x85\xdb\x9f\x0f\xf4^\x16r*\xcd\x9a\x1a\xcd\x01\xddOL\xfa9G\xbd\x9a\x9ay#{O\xca\x08r\x96hk\xcdM\xea\xc3\xcc\xacp\x92\xae\x9e\xa2zI%kq\xcc1J\xe6\x07\xe0t\x05\xc1\xa0\x90:\x02H\x1d\x168\xbb\x18\xa9\x1fH\x1d\xca\x90H\xd8\x9b\xb8\xbd\xa5\xe4\xc8pGE.\x96\x0b\x9f\x15\xf5\x1f\x19\xaa\xee\x9a\xabQi\x97\xe9ic\xa0\xb4\xd2Zn\xb2\xd1GB\x05\xbe\x1a\x93Q##pl\xc5\xd2L\xef\x85\x0en\xd6\x00\x02\x8f\xd5\xbe\xe8\xf9\xaf\xb1f\xcb\xaf\xce\x18\xfd\xe4\xb8\xfd+[\xf5\xeeP\xae\x07\xea\xab\x8e\xba\xe0\xce\x85\xd4w\x86\x86]n\xd6:*\xda\xac7h2\xc9\x0b\x1c\xe7\x01\xea\x04\x92q\xea\xca\x9a\xf0\xc7\xef%\xc7\xe9Z\xdf\xafr\xd3\x12o\xb3\xcc\xf7\xc7\xaa\xf4\xfdR\xf4D^RE\x10\xe2w\xde[w\xd2\xb4_\\\xd5/Q^$\xd3I6\x9c\x8ef1\xd26\x92\xb6\x96\xaa@\xc0I\x11\xb2f\x97\xbb\x03\xa9\xc3r\xef\xd4\xbavi\xb65\x1ca1\xbd\x87q\xa0\x82\xebo\xa9\xa2\xaa\x8f\x9bKS\x13\xa1\x96<\x91\xb9\x8e\x048du\x19\x04\xf9,M/\xa6\xad\xba3MZ\xb4\xfd\x9a\x9b\xb9\xda-T\xb1QQ\xd3\xf3\x1c\xfeT1\xb01\x8d\xdc\xe2\\p\xd6\x81\x92I>\xb2W\xa3\x14\xac\x9e&K\x13\xdb$ohs^\xc3\x90\xe0|\x88>\xb0\xb9.\xfbj\xc5]\xdc{=\xe8\x0b\xae\xa5\xa9\xbeUXL\x95uUl\xaf\xa9\xa7\x15\xd5\r\xa2\xa8\xa9a\x05\xb3KH$\x10I -i\xde\xe8\xc9\xc8\x07+\xb3X\xf0\x13Ck\xdb\xe5M\xde\xf5f\x96j\xea\xc8\x1bKZi\xae\x154\xb1\xd7D\xdc\xed\x8e\xa68\xa4k\'h\xc9\x00J\xd7\x0ct\xf2V\x02*d\xa7\xa8\xbb\xae\x9a\x9a\x1a*h\xa9\xe9\xe2d\x10D\xc1\x1cqF\xd0\xd6\xb1\xa0`4\x01\xd0\x00:as\xe1\x8f\xdeK\x8f\xd2\xb5\xbf^\xe5\xf94\xac\xa7\x89\xf2\xca\xf6\xc7\x1b\x1a\\\xe7\xbc\xe04\x0f2O\xa8.\xee\x1bSI\x0e\x9c\x92i\x18\xe8\xdbW[UU\x1b^\x08&7\xcc\xe70\xe0\xf5\x19n\x1d\xfa\xd3\x1bL\t\xe3\x1e\xab\xd3\xbaR\xa4D^R\xc2" \x8dTp\xd7KUL\xf9_b\xa3\x0fy.v\xc8\xf6\x02O\x99\xc0\xc0\xca\xea\xf6-\xd2\x9f\x88\xe9\xbfa\xfe*T\x8b\xa3\x9ccF\xea\xe7\xc6SyS\xbe\x81X}\x9bM\xb3\xc3a\xf0\xefG\xbb\xcfv\xdcvs{\xce\xdd\xf8\xcf\x9e\xde\x99S\x8fb\xdd)\xf8\x8e\x9b\xf6\x1f\xe2\xbc`G\xb6\x08\x8c\x9c\xfa.:g\xf3\xb5a\xa79\xc7\xed\xcf\x8c\x97\x9e\xb4j\x9b\x86\xba^\x96fK\x1d\x8a\x8c\xbd\x849\xa5\xf1\xef\x00\x8f#\x83\x91\x9f\x9dIQ\x16u\xe2W\x89\xads3\xc4\xbc\xc8\x88\x8b4\x08\x88\x80\x88\x88+\xd0~\xd8\x022\x7f\x93\x03\xa6\xee\x9fu\xfc\x9f\xfe\xab\tW`\xfd\xb0\x84\x7fU\xc7\xab\xf3\xb5b ""\x02" ""\x02"\xc1\xbe[\xa6\xbbY\xea\xe9)\xebf\xb6\xd4\xcb\x19lU\x94\xf8/\x81\xff\x00\x15\xe0\x1e\x87\x07\x07i\x04\x1c`\x82\t\x08! }\xb0\x87\xaf\xf3\\t\xff\x00\xbbV"\xd1q\xda\xa7Z\x9e7\x9d\x124\x83=\x97{\xaf\xa3\x9c\xbc\xbb\xc3wsy\xbe!\xe7\xbb\x93\xca\xfb.\xcf\xf9\xa9o\x0cmQ\xbb\x8b3e\x1b\xd9IOM\x1c\x866\x9f \xe7<\x1d\xce\xc63\x80\x06s\x85\xf9\xdd\xb5\'\xe5eO\xeeT\xff\x00\xe8^\x9c_\x04\xcf\xd0\x17%\xebf\x88\xddLxG\xb3<\xd2\x81{\x15\x0fd\x8fO|bOJ\xbc;\xc2\xbcC\xb9\xc1\x9e\xef\xbf~\xdd\xbbv\xe7?\x1b\x1b\xb1\xd38\xe8\xa5\x1d\xdbR~VT\xfe\xe5O\xfe\x85\xea\xa2f\xfd\xb1\xfdc\xd8\xcd//\xbej[4n\xaa\xf1qyl@\xbd\xf4\x95\x14\xd1\xc6dh\xf3\rs\x00\xda\xecg\x19\x04g\x19S\x9bm\xc2\x1b\xb5\xba\x96\xba\x99\xc5\xd4\xf512h\xdcF\tk\x80#\xff\x00\x05F&\xf8\'\xff\x00d\xac\xbe\x19~\r\xb4\x9f\xd14\x9fR\xc5\xcd\xb4SL\xe1\xe7\xb4D\xde\xdaE\xbc\xb8/\x13x\xbc\xa4\xa8\x88\xbc\xd0Q\x9e\'~\r\xb5g\xd15\x7fR\xf5&Q\x9e\'~\r\xb5g\xd15\x7fR\xf5\xbe\xcf\xd3Q\xc6<\xd3\x1b\xe1\x8b\x17\xc13\xf4\x05\xf3\xaa\x87JYn<7\xe2Um7\x06\xaf7MY\xe9\x0e\xa0\xee\xfa\xf6\xde\xc8"m\x1b\xc5l\xe1\x93\xf3b\x9b\xbd\x11\t\xc1-dN\'f\x00r\xfa+\x17\xc13\xf4\x05AX{?q\x0fJ[/\xf6;/\x14\xad\xb6\xfd=v\xb9\\+\xcccKo\xad\x80U\xcf$\xafk\'uYf\xe6\x99\x08\x0e1\x11\xd3;WN5\x13T\xc6\x9d}^\xac\xa2lj\xce3\xdc\xf4\xed\xabB\xd1\xd85E\x8a\xe4.\x96FW\x0b\x8c\x96\x9b\x85\xea\xb6\xe1\x86\xc6\x1b,T4@\xfd\xfc\xfe^\xdfy\x8cc\xaa\x94z\x03u\xfc\xad\xae\xfd\xd2\x9b\xff\x00\x9ag\xc2\xed\xc7\xdf\xd8\xcb\xde\xe7R\xf6\xc5M+\xdeCZ\xd6\x12I\xf5\x0c/C\x870\xba\x9f\x87\xba^\'\x8d\xafe\xae\x95\xae\x07\xd4DM\x05`E\xc3\xb7T}\x8e\xeb|\xad\xbbQ\x9f\x7fG$p\xc7\x14\xc3\xfa/\xd8\xc0\\\xdf\x95\xb9\x00\x82C\x81\x07\nb\xb9\xf1\xf1h\x9a2S7\xd6\xff\x00.\xb4E\xa2\xc2".\x00DD\x04DA_\x02}\xb0\x04|_F\x07\xcb\xe7\xde\xff\x00b\xb0Uz1\xed\x81>\xf7>\x8b\x8f\x97?u\xfe\xc5a ""\x02" ""\x02" \xafA\xfb`H\xc9\xc7\xa2\xe0\xe3=>\xeb\xf9\x15\x84\xab\xc0\x0f\xb6\x0c\x9c\x1cz.\x06q\xf9\xda\xb0\xd0\x11\x11\x01\x11\x10\x11\x11\x01`\xdf%\xb8Ag\xab\x96\xd5\x045W(\xe3/\x82\x9e\xa1\xe5\x8c\x99\xe3\xa8ap\xf7\xbb\xb1\x8d\xd8;s\x9c\x1c`\xe7(o\x16x\xb3\xa7x-\xa2\xea\xb5>\xa6\xa9|4\x10\xb9\xb1G\x14\x0c\xdf5L\xce\xce\xc8\xa2g\xc6{\xb0zy`\x12H\x00\x94\x14(\xedo\xa0\xbd::\xa7\x9bVk\xbc\x18Y\xfd\x1c\xe4\xff\x00\xb5m{\\:\xb5\xcd8!\xc3\xa8!LM\xa6\xe3S\xdbf\xe2/\xb3`\x98\xc7s\xdf\xdf\xf3\xde\xb0\xfe\xed\xdd\xb7\xff\x00K\xde\xec\xdb\xf1\x7fV2\xa7\x1d\x93]\x05O\x17\xb8\xfdYd\xdat\xa4\xb7\xdaFS:\x1f\x82uki\xcf}-\xc7BK\xcb\t#\xe6\\\xfd\xa7W\xd3A\xe0G\x8d\xda\xdb\xd1-\xbc\xaf\x0f\xdd\x0fz\xe5yr\xfb\xd6\xdd\xd8\xdb\xd3\x18\xc7\xcd\xeaW\xb7\x0f\xb8}`\xe1n\x91\xb7\xe9\x9d3o\x8e\xd9g\xa1f\xc8\xa1gRO\x9b\x9e\xe7\x1e\xaes\x8eIq\xeaI^\xbf(r\x87>\x8a#$S\x96-\xa2\xf5U\x9a\xda$H\x88\xbcu\x04D@DD\x04D@DD\x04D@DD\x1f\xff\xd9' ) @@ -381,7 +385,9 @@ def get_png(request: httpx.Request) -> httpx.Response: graph1.name = None graph1.mermaid_save(str(path2), title=None, start_node=Foo(), httpx_client=httpx_with_handler(get_png)) assert graph1.name == 'graph1' - assert path2.read_bytes() == snapshot(b'stateDiagram-v2\n [*] --> Foo\n Foo --> Bar\n Bar --> [*]') + assert path2.read_bytes() == snapshot( + b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00<\x00\x00\x01\x12\x08\x06\x00\x00\x00\xa1-\xb6\x80\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x0e\xdcIDATx\x9c\xed\x9d}t\x94\xd5\x9d\xc7\xbf\xf7\x99\xd7df2y!\x90\x19\x02\x04\x92,\x90\x90\x84\x99\x18\xc1\n.k\x84Ju\x11k\xad\xa7\xeb9Z\xedQD^\n\xb2\xf6h\xb7\x1e\xd1c\xa1vi\x83\x116\x14[\xbbp\xe0\xe0K\xb5\xc0R\x05]%-\x89\x16df\xa0Y\x90\x98 A\xa2\x03\xc9\x10\xc8;yf\xe6\xb9\xfb\xc7$\xa9\x81\x92y\x92\x99{'N\xee\xe7\x9c\x9c\xc3\xcc\xfc\xees\x7f_\x9e\xe7\xde\xe7\xde;\xf7\xf9\x0e \x10\x08\x04\x02\xc1\x88\x81\xf0\xac\xcc\xe1p\xa4K\x924#\x18\x0c\xe6I\x92\xd4J\x089\xeer\xb9jx\xe6\xc0M\xb0\xc3\xe1\xd8)I\xd2\xed\x94R\x89\x10b\xa4\x94\x06\x08!A\x00\x17\x14Ey\xd2\xe3\xf1\xec\xe5\x91\x07s\xc1v\xbb=\xd1f\xb3\x9d\xa7\x94\xea\t!\x86\xeb\x84\xb5QJ\xb7\xba\xdd\xee'Y\xe7\xa3a]Annn;!$\x91\x10\xa2\x1d$\xcc\x00\xa0\xc4f\xb3\x8d\xf3z\xbd\xef\xb0\xccGbyp\xa7\xd3\xf9>\x00\x9d\x9aXB\x88\x8e\x10\xf2@aa\xe1l\x9691\x13\xect:\xe7\x02\x98D\x08\x19J\x1d\x16\xadV\xbb\x8eUN`)\x98R:\x13\xc0\xb8a\x14\x9d\xc7 \x9d~\x98\t\x96$\xe9\x16BH\xd2P\xcb\x11B\xda\x9cNg!\x9b\xac\xd8\x9e\xe1\xe00\x8b2\xbds\xb0\xec\xb4\xaa(\xa5]C-D)\xb5\xb8\xdd\xee\xbf\xb1I\x89\xa1`B\xc81BH\xcb0\x8aV1H\xa7\x1ff\x82].W\x15\xa5\xb4v\x88\xc5\xba\t!L\x07\x1fL\xef\xc3n\xb7\xfb6\x00\xaa.kJ\xa9\x1f\xc0o].\xd7a\x9691\x15\x0c\x00^\xaf7\x1d@k\xaf\xa0\xeb\xd1\x06\xa0\xcc\xe5r\xadd\x9d\x0f\xb7\xc9\x83\xd3\xe9\xdc\x01\xe0\x0e\x84\xdaw\xdf\xe4A\xa1\x94z\x15Ey\xe2\xd8\xb1cL\x87\x94}p\x9d\x1e\x16\x14\x14\xa4h4\x9a\"B\xc8fB\xc8>J\xe96\x8f\xc7s\x92g\x0e1\xc1\xe9t\xbe\xebt:o\x8fE\xdd\xcc\xdb\xf0HC\x08\xe6\x81\xa2(-\x94\xd2@,\xea\x8e\x89`B\x88\x9eR\xca\xb5\xc3\xecc\xb0U\x08f\x10B\xcc\x84\x10\xe6\xab-\xff\x08\xd1\x86\xe3\x9dQ'8&m\x98R\xda\x10\x0c\x06\xe5X\xd4\x1d\xab^:K\xab\xd5\xeacQ\xb7\xb8\xa4y\xd0\xfb\x15\x8b\x12\x8b\xbac\xd5\x865\xb1\xba\xbaF\xdd\xd02&gX\x92\xa4\xd4\x98\xd5\x1d\x8bJcI\xac\xdaps \x10\x18U\xb3\xa5t\x9dN'.i\x1e\xc4Jp\xab,\xcb\xc3\xfd\xee)\"b%\xd8\xaa\xd7\xeb\xc5|\x98\x07Bp\xbc#\x04\xc7;\xb1\x12\xdc6\xdanKI\xe2\xb6\xc4\x89X\t\xf6\xf9\xfd\xfe\xd13y\x000FL\x1e8\x11\xab\xf9\xf0%\x00\xa3g\x89\x87\x10\x922\xda\x96x\xfc\xb2,\xc7d\x996V\x82uz\xbd~\xf4,\xd3\xc6\x92\x98\xb4#EQ\xce(\x8a\x12\x97_\xa6i\x1d\x0e\xc7m\xd7T*I\x93\xaf\xfe2\xad\xa0\xa0 \xc5\xe1p\xdc\xc28\x1f\xe6\x82\x03\x84\x10Kqqq\xf9Uu\x05\x83\xc1`\x7f\xa7\xe5t:st:\xdd\x1f$I\xfa\x98q>\xec\xdb\xb0\xdb\xed\xfe#\xa54\xcf\xe9t\x1e\xc8\xc9\xc9\xe9\xdb!\xaf\xd1h4\x12B\xcf3\xddF\x08qQJ\xd7\xb9\\\xae\xc1\xf6cF\x05.;i\n\n\n\xa6\xe8\xf5\xfaS\x94\xd2\xb3\x8a\xa2\xcc\x97$\xa9\x02\xc0K\x94\xd2\\I\x92\xca\x00\xfc\x8f\xcb\xe5\xba\x9bG.\\\xa6hMMM\x97\xecv\xbb\x8e\x10r7!\xe4\xc1\xde\x91\xd6\r\x92$\xad\xa0\x94\xfaeY\xfeNSSS\x1b\x8f\\\xb8\xed\x95\xca\xc9\xc91X\xad\xd6:\x00\x13\xbe\xfe\xbe\xa2(\xcfx<\x9e\x17x\xe5\xc1\xed>\\__\xdf\x03\xe0\xea\xfd\xd0\x9fK\x92\xf4\"\xaf\x1c\xc0\xeb\x92\xee\xc3\xeb\xf5\x9e\xb2\xd9ls\t!S\x10:\xbb\xf7\xba\xdd\xeez\x9e9p\x1fi\xf9\xfd\xfeGi\x88\x8f<\x1e\xcf\x07\xbc\xeb\x1fR\x1b._Q7\x1b\x12-\"\x84dDRi\xcd\xb9=+RLY\x7f\xceL-\x1a\xf6\xe3:\x14h\x05\xa4/\x0c\n\x8e.)\xcf\xfeBm9U\x82\x7f\xbd\xfa\\\x829\xd1\x7f\xd8\x92\xa2\x9bd\x1d\xa37$&i\xaf\xf7X,7t\x06\t\xe7\xcftw\x06\xe4\xe0\xa5\xd6f\xf9\x95G\xd7g?\xaf\xa6\\X\xc1oln2w_\xec\xfa\xbf\x92;\xc6N\x1c;)!&;`\xc3Q\xf5\xd6\xf9\x8e\x9e\xce`\xf9}Od\xfeG\xb8\xd8\xb0m\xf8rc\xc7\xa1\x92;\xc6N\x1a\xa9b\x01`\xce=\x19f\xa2!\xcb+\x9e\xfc\xec\x9ep\xb1\x83\n._Q7\xdb\x94\xa2\xcb\x1c;)!\xaa\t\xb2`fiZ\x92F\xaf}&\\\xdc\xe0gX\xa2E\xc9\xe9\xfa\xc4h&\xc6\x8a\xe4\xb1z\xc8\x9d\xca\x8cpq\x83\n&\x84d\x98\xac\xdao\x84`I\"\xd0\xe8\xe1\xff\xcd\x9a\xda1\x83\xc6\xf1Kid \x04\xc7;Bp\xbc#\x04\xc7;QY\x97^\xb9\xf2^\x1c8\xf0\x87\xeb~~\xe0@\x1d\xb2\xb2r\xa2QU\xc4Dm!~\xca\x94\xe9X\xbb\xf6\xbf\xfe\xe1g\xe3\xc6\x8d\x8fV5\x11\x135\xc1&\x93\x19\xb3f15Y\x89\n\\\xdbpGG\x07\x9ez\xea!\xdcz\xebd8\x1c\x16|\xff\xfb7\xe1\xb5\xd7~3\xe4\x98H\xe0*x\xf9\xf2\xc5hl\xfc\x1c/\xbd\xf4&>\xfc\xb0\x01\xf3\xe7\xdf\x8dg\x9f}\x0c55G\x87\x14\x13\t\xdc\x04WU\xbd\x87\x8f?\xfe\x00k\xd7V\xa0\xa0\xe0\x06\xa4\xa4\xa4\xe1\x91G~\x82\x9bn*EE\xc5\x0b\xaac\"%jm\xb8\xa6\xe6\x13L\x9dz\xed\x1a\x81\xd9l\x85\xcbu\x19\xb5\xb550\x9b\xad\xc8\xc9\xc9\x1b\xf0\xf9\xf4\xe9\x0e\xec\xdb\xb7\x0b\x00T\xc5D\n\xf3^Z\x92B+\xc1>\xdfy$&\x9a\xaf\xf9<1\xd1\x8c\xce\xce6\xd51\x91\xc2\xad\x976\x9b\x93\xd0\xd9\xd9~\xcd\xfb\x9d\x9d\xed\x187.SuL\xa4pk\xc3\xf9\xf9\xc5\xe8\xecl\xc3\xa7\x9f\x1e\x1f\xf0~M\xcd\x11\xe4\xe6\xe6\xab\x8e\x89\x14n\x82\xe7\xccY\x80\xec\xec<<\xff\xfc2\xd4\xd4\xb8\xe0\xf35\xe1\xe5\x97\xd7\xe2\xe8\xd1Cx\xf0\xc1U\xaac\"\x85\x9b`\xadV\x8b\xf2\xf27a\xb5\xa6\xe2\xbe\xfbfc\xc1\x82\x1c\x1c>|\x10\x15\x15{Q\\|\xb3\xea\x98\x88\xf3\x88\xc6A\xca\xcb\xdfT\x15\x97\x93\x93\x87-[\x06\xf7\xebT\x13\x13\t\xa3n\xb6$\x04\xc7;Bp\xbc#\x04\xc7;Bp\xbc3\xf8\xb7\x87 \xde\x8e\xd6\xc0\x90\xedVc\x81\x12\xa4\x08\xca\xd0-\xf9\xd5T\xdf`q\x83\x9fa\xbfr\xbc\xadY\xfeF\x08\xbe\xdc,\xc3`\x92\xc2n\x92\x19T\xf0\xf2\xcd\xfft\xb8\xb3\xd5\x7f\xeeB\xc3\xc8\xd7|\xec\xfd\x8b\xed\xc1\x9e\xe0s\xe1\xe2\xc2\xb6a\xed\x97\xe4[G\xdf\xf55\x9e?3rEW\xbf}! \xcb\xc1\x17\x1f\xdb\x90\xbb'\\\xac\xaa\x8d*\xe5+\xea\x0c\xba\x04Ri\xb6\xea&\xa6\xd8\x8c\x16S\xb2\xd6\x12\x95L#@o\x94\xf0\xe5g]\xbe+\x9d\x81\xf3\x97\x9b\xe5\xdf\xad\xdc\x98\xbbQM\xb9!\xed\xcc\xd9\xf8\xe3\xd3%ZB\x1d\x14\xd4>\xecL\x01\x9c\xfa\xea\xbd\xfb\xd3\xcc\x93\x0f\xa7'\xe5\x0e{\xdb!\x81t\x99\x826hI\xf0\x93\xa5eS\xbf\x8c$\x1f\xe6\x08\xe7R\x8e\x08\xc1<\x10\xce\xa5\x1c\x11\xce\xa5\xf1\x8e\x10\x1c\xef\x08\xe7R\x1e\x08\xe7R\x8e\x08\xe7R\x1e\x08\xe7R\x8e\x08\xe7\xd2xG8\x97\xf2@8\x97rD8\x97rB8\x97\xf2B\x08\x8ew\x84\xe0xG8\x97rB8\x97\xf2B8\x97rB8\x97\xf2B8\x97\xf2@8\x97rD8\x97\xc6;\xc2\xb94\xca\x08\xe7\xd2^\x84s\xa9p.e\x84p.e\x85p.\r!\x9cKY#\x9cK\xc3\xb1y\xd5g\xd3\x15*\x15*\x94\x8e\x97$\x0ckg|\xc4\xce\xa5\x04\xcd\xa0\xe4\xd4\xf2\x8d\xd9\x07\t\x08\x1dZ\xd1!\xf0\xca\xcf>\xdf\x94\x9c\xae_\xac3hR\xc6L0&\x06zb2\xe1\x01\xa5\xf0\x9f?\xd3%w\xb5\x05Z\xbb\xdb\x03\x0b\x96\x97\xe5\x9eP[V\xb5\xe0]\xffyn{\x9a\xdd\xf0=\xe7\xb7\xd3G\x8c\xc9eOW\x10\x1f\xee\xfc\xea\xa26\x81\xdc\xf1\x83U\x13\x0e\xab)\xa3\xaa\ro}\xfa\xf4\x13\x96T\xdd]#I,\x00\x18\x125\xf8\xf6\xc3\x99i\x17\xcf\xf6T\xab-\xa3\xb2\xd3\"k\x8aJ\xd3\x92T\x04rG\xd2\x10L\xbb)9\xf8\xf2\x8f\xebV\xab\x8a\x0f\x17\xb0iYcZ0HS\x12\xcc1\x99I\xaa\"9]\xaf\xd7\x9b4\xff\xa2&6\xfc\x19\xd6wg\xe8\x8d\x12\xf3A}$$\x98\xb5 T\xdd\xa3E\xa3n\xc5C\x08\x8ew\x84\xe0xG\x08\x8ew\xa2&x\xfb\xf6rL\x9dJ\xfa\xff\xf2\xf2tX\xb80\x0fO?\xfd0\xea\xeaT\x8f\xed\x99\x13\xf5\xe1\xd3\x96-\xfb\x90\x98hB \xe0\x87\xcbU\x85?\xfdi\x17*+\xf7a\xd7\xae\x8fF\x84]k\xd4\x05\x17\x17\xdf\x8c\xa4\xa4d\x00\xc0\xcd7\xcf\xc7\xfc\xf9\xdf\xc5\xe2\xc53q\xe4H\xe5\x88\x10\xcc\xbc\r\xf7\xb9\x18\x9aL\x7f_+\xa8\xaf?\x89u\xebVc\xd1\xa2\xa2~w\xd2\xd7_\x7fe@\xb99sl\xd8\xb1c\x13~\xf8\xc3\xf9\x98:\x95\xc0\xef\x8f\xce\xe8\x96\xd9\x8c\xc0\xef\xf7\xe3\xd4\xa9\xe3\xf8\xfd\xef\x7f\x85\xfc|'\xe6\xcd\xfbN\xffg/\xbe\xf8\xefhll\xc0\xb3\xcfn\x06!\x04\r\rux\xee\xb9\xc71~\xfc$\xcc\x99\xb3\x00\x00\xa0\xd7\x1b\xf1\xd6[\xafb\xd6\xac[\xb1d\xc9\xd3\xd0j\xa3\x93j\xd4\x05\x97\x94\xa4\x0cxm2%\xe1\x97\xbf\xdc>\xe0\x0co\xd8\xb0\x13\x1d\x1dm\x18?~\x12\x00`\xd6\xacy\xd8\xbd{\x1b\x0e\x1d\xda\xdf/\x98\x10\x02\xab5\rO=\xb5!\xaa\xf91\xeb\xb4\xfa8xp\x1f\x96-[\x8c\x8d\x1b\xdf\xc0\xc2\x85\xf7\x02\xa1\xd5J\xec\xdc\xb9\x19\x87\x0e\xedG]\xdd\tP\x1aZ*\xca\xcc\x9c<\xe0X\xf9\xf9\xceh\xa7\xc7\xb6\xd3B\xef\xd9kiiBY\xd9O\xb1p\xe1\xbdP\x14\x05\xcb\x96-\x86,\xf7`\xd5\xaa\x17p\xe3\x8d\xff\x0c\x8b\xc5\x8a\x07\x1e\xb8\xf5\x9ac\x19\x0c\xc6h\xa7\xc7g\xe01m\xdaL\x9c=[\x8f\xce\xcev\x9c8\xe1\x81\xcbU\x855k~\x81\xd2\xd2E\xb0X\xac\x00\x80\xf6\xf6\xcb_\x13\xd6\xaf\x7f\x02\xf3\xe6\xdd\t\xafW\xf5\x0fc\r\x9b\xa8\x0b~\xec\xb1;\x07\xbc\xbe\xf1\xc6y\xf8\xf9\xcf\x7f\x87{\xeey\x08\x00\x90\x91\x91\x89\r\x1bv\xa2\xa2\xe2\x05\x94\x94\xa4 ''\x1f\xeb\xd7\xbf\n\x9f\xef\x02\x96.]\x84E\x8b\x8a\xb0w\xef\xf1\xeb\x1c=r\xc2\xaeKoZ]\x97\x9f`\xd1~t\xd7\xca\xac\x11\xb9j\t\x00\x17\xcet\xa3\xfam\xaf\xeb\xd1\xf5\xd97\x84\x8b\x15\xb3\xa5xG\x08\x8ew\x84\xe0xG\x08\x8ew\x84\xe0\xab\x91a\xf4\xcaW\x94\x98\xb8\xaa\xa8\xa5\xbb#\x00\x10\xa2\xca\x080\xac\xe0\xd5e\x99\x974Z\xe2\xebn\x8f\xc9#\n\xaah\xf5\xf9e\xb9+xPMlX\xc1\x04\x84R\xd0_{>\xf0]\xfb\x13\x1b#\x80`\x80\xe2\xd3\x8f[\xa4\xe5*}-U\xb5\xe1%\xeb\xb2\xcb\xda.\xc8;]\xef\xf9F\xd4i\xbe\xd2\x19\xc0\xff\xfew\xe3%@R\xfd3\x1fC\xda\xb6T\xf1d\xddzK\xaa\xfe_\x8df\xad\xcd6%1U\x8e\xd1\xb6%P\xda\xdd\xf8YWGWk\xe0\xa2\xdcA\xee^\xb1i\xf2)\xb5E\x87\xbc1m\xcb\xca\x93\xb9~\xa2\x9b\x19\x842QC\xa4amL\x8b\xd4\xb9\x94B\xba\x00\xa2\x9c\\Q\x96\xf3\x97\xa1nL\x8b\t\xc2\xb9\x94#B0\x0f\x84s)G\x84si\xbc#\x04\xc7;\xc2\xb9\x94\x07\xc2\xb9\x94#\xc2\xb9\x94\x07\xc2\xb9\x94#\xc2\xb94\xde\x11\xce\xa5<\x10\xce\xa5\x1c\x11\xce\xa5\x9c\x10\xce\xa5\xbc\x10\x82\xe3\x1d!8\xde\x11\xce\xa5\x9c\x10\xce\xa5\xbc\x10\xce\xa5\x9c\x10\xce\xa5\xbc\x10\xce\xa5<\x10\xce\xa5\x1c\x11\xce\xa5\xf1\x8ep.\x8d2\xa3\xd2\xb94i\xb49\x97\xbe-\x9cK\xafr.\xa5\x94\xeeu\xbb\xdd\xdf\xe5\x91\x0b7\xe7R\x9b\xcdf \x84,\xbe\xda\xb9\x14\xc0\x15Y\x96\xef\x14\xce\xa5\x8c\x10\xce\xa5,\x19\xd5\xce\xa5\x8a\xa2|3\x9cK\x87[\x8f\xc3\xe1\xb8]\x92\xa4\x87\x01\xdc\x05@\x87\xd04\xf1,\xa5t\x1b\x80W=\x1e\xcfY.\x89\xb0\xae\xa0\xb0\xb0p\x86N\xa7\xdb\x03`\xca`q\x94\xd2\xadn\xb7\xfbq\x00LW3\x99\n.**\xca\xd7j\xb5\x7f\x01\x90:vl\x06\xee\xbf\xff\x11\xcc\x9d[\n\x93)dWs\xe6L=\xf6\xecy\r\xfb\xf7\xef\x01\xa5\x14\x94\xd2\xd7\xddn\xf7\xbf\xb1\xdc\xe1\xc3\xac\xd3*..\xd6I\x92T\r\xc0\x9e\x9b;\x1dee\xaf\"?\xbf\x08z\xfd\xdf\x87\xd0))\xa9\x98=\xfb\x16de\xe5\xa0\xba\xfa (\xa53l6[\xab\xd7\xeb\xfd+\xab\xbc\x98\t\xb6\xd9l\x8f\x13B\xee\xb7Z\x93\xb1a\xc3o\x91\x9c\x1c\xb2\xaci\xf1\xf6\xa0\xde\xd3\x86\xb6f\x19Iizh\xb4\x04\x13'N\x86\xd1\x98\x00\x97\xeb\xaf\x000\xcbd2U\xb4\xb4\xb4\xf4\xb0\xc8\x8b\x99`\xbb\xdd^\x01\xc0\xb6z\xf53\xc8\xcb+\x04\x00\x1c\xd9\xd7\x84O\xdemF\xd3\xd9n|U\xdf\x85zO\x1b\xd2\xecF\x98\x93u\xc8\xcb+\xc4\x91#Uhi\xf1\x19\r\x06\xc3I\xaf\xd7;<+\xe600\xb9-\x15\x17\x17[\x018\x8dF#\xe6\xce-\x05\x00\x9c\xf9[;N\x1f\x0b\x8d\x1e)\r=y#w\x07\xf1\xd1\xee\xf3\x08\xfaC\xafKKC\x8eL\x84\x90\xf9,\xf2\x02+\xc1\x8a\xa2d\x01\x80\xdd>\xa1\xdf\x16\xca[\xdf\t\xf4\x8a%\xa4\xb7\xaf\xa4\xc0\x95\x8e .7\x85\xae\xde\xc9\x93s\xfbb\xc6\xb3\xc8\x0b\x0c\x05K\xe8\xb5\x88\xea\xa7\xef\xdf_{\xaf\xef\t+I{M\x1a:\x16y\x81\x95`I\x92\x1a\x01\xe0\xdc\xb9\x06\xc8rh%\xc7\x9e\x9b\x08\xf4\xde\x07\xfb.iB\x00\xa3Y\x03\xeb\x98\x90\xbe\xd3\xa7k{\xdf'\x8d,\xf2\x02+\xc1\x1e\x8f\xa7\x19\xc0\tY\x96Q]\x1dz\xca5k\x86\x05\x13\xa6\x85\xd4\xd6\x9e\x00\xa5\xf42!\xe4\rVy1\xbb-y\xbd\xde\xa3v\xbb\xfd\xf6\xf6\xf6\xb6\xcc\xe3\xc7\x8fb\xe6\xcc\x12X,I0Y\xb5\x187)\x01i\xe3\x8d\xd0\x19B\x17\xd8;\xef\xfc\x11\x9b6\xfd\x02\x8a\xa2\x80\x10\xf2#\x97\xcbu\x94U^,\xa7\x87\xd4f\xb3U\x13B~p\xf1bsBe\xe5\x01$'\xa7\"++\x1b\x92\x14\x12\xea\xf35a\xeb\xd62\xec\xd8\xf1\n\x14E\x01\xa5\xf45\xb7\xdb\xbd\x96aN\xdc&\x0f\xbb\x01d\x0f\x16\x17\x17\x93\x87\xaf\xd7\xd3;=|\x08\xc0\xe2XN\x0f\x05\x02\x81@ \x18A\xfc?\"\xe4^6T`n\xbf\x00\x00\x00\x00IEND\xaeB`\x82" + ) def test_save_pdf_known(tmp_path: Path, httpx_with_handler: HttpxWithHandler): diff --git a/tests/models/cassettes/test_model_names/test_known_model_names.yaml b/tests/models/cassettes/test_model_names/test_known_model_names.yaml index 4fc94b146..a187d35a8 100644 --- a/tests/models/cassettes/test_model_names/test_known_model_names.yaml +++ b/tests/models/cassettes/test_model_names/test_known_model_names.yaml @@ -5,7 +5,7 @@ interactions: accept: - '*/*' accept-encoding: - - gzip, deflate + - gzip, deflate, br connection: - keep-alive host: diff --git a/tests/models/test_anthropic.py b/tests/models/test_anthropic.py index 77857e882..ae9684adb 100644 --- a/tests/models/test_anthropic.py +++ b/tests/models/test_anthropic.py @@ -199,7 +199,7 @@ async def test_sync_request_text_response(allow_model_requests: None): ), model_name='claude-3-5-haiku-123', timestamp=IsNow(tz=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest(parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))]), ModelResponse( @@ -213,7 +213,7 @@ async def test_sync_request_text_response(allow_model_requests: None): ), model_name='claude-3-5-haiku-123', timestamp=IsNow(tz=timezone.utc), - vendor_id='123', + id='123', ), ] ) @@ -304,7 +304,7 @@ async def test_request_structured_response(allow_model_requests: None): ), model_name='claude-3-5-haiku-123', timestamp=IsNow(tz=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -374,7 +374,7 @@ async def get_location(loc_name: str) -> str: ), model_name='claude-3-5-haiku-123', timestamp=IsNow(tz=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -403,7 +403,7 @@ async def get_location(loc_name: str) -> str: ), model_name='claude-3-5-haiku-123', timestamp=IsNow(tz=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -426,7 +426,7 @@ async def get_location(loc_name: str) -> str: ), model_name='claude-3-5-haiku-123', timestamp=IsNow(tz=timezone.utc), - vendor_id='123', + id='123', ), ] ) @@ -775,7 +775,7 @@ async def get_image() -> BinaryContent: ), model_name='claude-3-5-sonnet-20241022', timestamp=IsDatetime(), - vendor_id='msg_01CC59GmUmYXKCV26rHfr32m', + id='msg_01CC59GmUmYXKCV26rHfr32m', ), ModelRequest( parts=[ @@ -814,7 +814,7 @@ async def get_image() -> BinaryContent: ), model_name='claude-3-5-sonnet-20241022', timestamp=IsDatetime(), - vendor_id='msg_014MJqSsWD1pUC23Vvi57LoY', + id='msg_014MJqSsWD1pUC23Vvi57LoY', ), ] ) @@ -947,7 +947,7 @@ def simple_instructions(): ), model_name='claude-3-opus-20240229', timestamp=IsDatetime(), - vendor_id='msg_01BznVNBje2zyfpCfNQCD5en', + id='msg_01BznVNBje2zyfpCfNQCD5en', ), ] ) @@ -984,7 +984,7 @@ async def test_anthropic_model_thinking_part(allow_model_requests: None, anthrop ), model_name='claude-3-7-sonnet-20250219', timestamp=IsDatetime(), - vendor_id='msg_01FWiSVNCRHvHUYU21BRandY', + id='msg_01FWiSVNCRHvHUYU21BRandY', ), ] ) @@ -1012,7 +1012,7 @@ async def test_anthropic_model_thinking_part(allow_model_requests: None, anthrop ), model_name='claude-3-7-sonnet-20250219', timestamp=IsDatetime(), - vendor_id=IsStr(), + id=IsStr(), ), ModelRequest( parts=[ @@ -1055,7 +1055,7 @@ async def test_anthropic_model_thinking_part(allow_model_requests: None, anthrop ), model_name='claude-3-7-sonnet-20250219', timestamp=IsDatetime(), - vendor_id=IsStr(), + id=IsStr(), ), ] ) @@ -1400,7 +1400,7 @@ async def get_user_country() -> str: ), model_name='claude-3-5-sonnet-20241022', timestamp=IsDatetime(), - vendor_id='msg_01EnfsDTixCmHjqvk9QarBj4', + id='msg_01EnfsDTixCmHjqvk9QarBj4', ), ModelRequest( parts=[ @@ -1434,7 +1434,7 @@ async def get_user_country() -> str: ), model_name='claude-3-5-sonnet-20241022', timestamp=IsDatetime(), - vendor_id='msg_01Hbm5BtKzfVtWs8Eb7rCNNx', + id='msg_01Hbm5BtKzfVtWs8Eb7rCNNx', ), ModelRequest( parts=[ @@ -1500,7 +1500,7 @@ async def get_user_country() -> str: ), model_name='claude-3-5-sonnet-20241022', timestamp=IsDatetime(), - vendor_id='msg_014NE4yfV1Yz2vLAJzapxxef', + id='msg_014NE4yfV1Yz2vLAJzapxxef', ), ModelRequest( parts=[ @@ -1532,7 +1532,7 @@ async def get_user_country() -> str: ), model_name='claude-3-5-sonnet-20241022', timestamp=IsDatetime(), - vendor_id='msg_0193srwo7TCx49h97wDwc7K7', + id='msg_0193srwo7TCx49h97wDwc7K7', ), ] ) @@ -1591,7 +1591,7 @@ async def get_user_country() -> str: ), model_name='claude-3-5-sonnet-20241022', timestamp=IsDatetime(), - vendor_id='msg_014CpBKzioMqUyLWrMihpvsz', + id='msg_014CpBKzioMqUyLWrMihpvsz', ), ModelRequest( parts=[ @@ -1626,7 +1626,7 @@ async def get_user_country() -> str: ), model_name='claude-3-5-sonnet-20241022', timestamp=IsDatetime(), - vendor_id='msg_014JeWCouH6DpdqzMTaBdkpJ', + id='msg_014JeWCouH6DpdqzMTaBdkpJ', ), ] ) @@ -1685,7 +1685,7 @@ class CountryLanguage(BaseModel): ), model_name='claude-3-5-sonnet-20241022', timestamp=IsDatetime(), - vendor_id='msg_013ttUi3HCcKt7PkJpoWs5FT', + id='msg_013ttUi3HCcKt7PkJpoWs5FT', ), ] ) diff --git a/tests/models/test_cohere.py b/tests/models/test_cohere.py index c69a8ab26..4d363e53f 100644 --- a/tests/models/test_cohere.py +++ b/tests/models/test_cohere.py @@ -455,7 +455,7 @@ async def test_cohere_model_thinking_part(allow_model_requests: None, co_api_key ), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), - vendor_id='resp_680739f4ad748191bd11096967c37c8b048efc3f8b2a068e', + id='resp_680739f4ad748191bd11096967c37c8b048efc3f8b2a068e', ), ] ) @@ -484,7 +484,7 @@ async def test_cohere_model_thinking_part(allow_model_requests: None, co_api_key ), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), - vendor_id='resp_680739f4ad748191bd11096967c37c8b048efc3f8b2a068e', + id='resp_680739f4ad748191bd11096967c37c8b048efc3f8b2a068e', ), ModelRequest( parts=[ diff --git a/tests/models/test_deepseek.py b/tests/models/test_deepseek.py index 64c73aea1..d2632976b 100644 --- a/tests/models/test_deepseek.py +++ b/tests/models/test_deepseek.py @@ -58,7 +58,9 @@ async def test_deepseek_model_thinking_part(allow_model_requests: None, deepseek ), model_name='deepseek-reasoner', timestamp=IsDatetime(), - vendor_id='181d9669-2b3a-445e-bd13-2ebff2c378f6', + vendor_details={'finish_reason': 'stop'}, + id='181d9669-2b3a-445e-bd13-2ebff2c378f6', + finish_reason='stop', ), ] ) diff --git a/tests/models/test_fallback.py b/tests/models/test_fallback.py index 89709d4a2..694678675 100644 --- a/tests/models/test_fallback.py +++ b/tests/models/test_fallback.py @@ -277,6 +277,7 @@ def test_all_failed_instrumented(capfire: CaptureLogfire) -> None: 'logfire.span_type': 'span', 'logfire.msg': 'chat fallback:function:failure_response:,function:failure_response:', 'logfire.level_num': 17, + 'gen_ai.response.model': 'fallback:function:failure_response:,function:failure_response:', }, 'events': [ { diff --git a/tests/models/test_gemini.py b/tests/models/test_gemini.py index 0b95bedeb..0551f9511 100644 --- a/tests/models/test_gemini.py +++ b/tests/models/test_gemini.py @@ -773,7 +773,30 @@ def handler(_: httpx.Request): with pytest.raises(ModelHTTPError) as exc_info: await agent.run('Hello') - assert str(exc_info.value) == snapshot('status_code: 401, model_name: gemini-1.5-flash, body: invalid request') + assert str(exc_info.value) == snapshot("""\ +status_code: 400, model_name: gemini-1.5-flash, body: { + "error": { + "code": 400, + "message": "API key not valid. Please pass a valid API key.", + "status": "INVALID_ARGUMENT", + "details": [ + { + "@type": "type.googleapis.com/google.rpc.ErrorInfo", + "reason": "API_KEY_INVALID", + "domain": "googleapis.com", + "metadata": { + "service": "generativelanguage.googleapis.com" + } + }, + { + "@type": "type.googleapis.com/google.rpc.LocalizedMessage", + "locale": "en-US", + "message": "API key not valid. Please pass a valid API key." + } + ] + } +} +""") async def test_stream_text(get_gemini_client: GetGeminiClient): @@ -1476,7 +1499,7 @@ async def test_gemini_model_thinking_part(allow_model_requests: None, gemini_api ), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), - vendor_id='resp_680393ff82488191a7d0850bf0dd99a004f0817ea037a07b', + id='resp_680393ff82488191a7d0850bf0dd99a004f0817ea037a07b', ), ] ) @@ -1507,7 +1530,7 @@ async def test_gemini_model_thinking_part(allow_model_requests: None, gemini_api ), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), - vendor_id='resp_680393ff82488191a7d0850bf0dd99a004f0817ea037a07b', + id='resp_680393ff82488191a7d0850bf0dd99a004f0817ea037a07b', ), ModelRequest( parts=[ @@ -1687,7 +1710,7 @@ async def bar() -> str: model_name='gemini-2.0-flash', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ModelRequest( parts=[ @@ -1717,7 +1740,7 @@ async def bar() -> str: model_name='gemini-2.0-flash', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ModelRequest( parts=[ @@ -1772,7 +1795,7 @@ async def get_user_country() -> str: model_name='gemini-2.0-flash', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ModelRequest( parts=[ @@ -1802,7 +1825,7 @@ async def get_user_country() -> str: model_name='gemini-2.0-flash', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ModelRequest( parts=[ @@ -1864,7 +1887,7 @@ def upcase(text: str) -> str: model_name='models/gemini-2.5-pro-preview-05-06', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id='TT9IaNfGN_DmqtsPzKnE4AE', + id='TT9IaNfGN_DmqtsPzKnE4AE', ), ] ) @@ -1934,7 +1957,7 @@ class CityLocation(BaseModel): model_name='gemini-2.0-flash', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ] ) @@ -1993,7 +2016,7 @@ class CountryLanguage(BaseModel): model_name='gemini-2.0-flash', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ] ) @@ -2045,7 +2068,7 @@ class CityLocation(BaseModel): model_name='gemini-2.0-flash', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ] ) @@ -2099,7 +2122,7 @@ async def get_user_country() -> str: model_name='models/gemini-2.5-pro-preview-05-06', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ModelRequest( parts=[ @@ -2130,7 +2153,7 @@ async def get_user_country() -> str: model_name='models/gemini-2.5-pro-preview-05-06', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ] ) @@ -2186,7 +2209,7 @@ class CountryLanguage(BaseModel): model_name='gemini-2.0-flash', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ] ) diff --git a/tests/models/test_gemini_vertex.py b/tests/models/test_gemini_vertex.py index c437dfb1d..50edfddf7 100644 --- a/tests/models/test_gemini_vertex.py +++ b/tests/models/test_gemini_vertex.py @@ -146,7 +146,7 @@ async def test_url_input( model_name='gemini-2.0-flash', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ] ) @@ -183,7 +183,7 @@ async def test_url_input_force_download(allow_model_requests: None) -> None: # model_name='gemini-2.0-flash', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ] ) diff --git a/tests/models/test_google.py b/tests/models/test_google.py index 7e1f372bc..29d8cf6da 100644 --- a/tests/models/test_google.py +++ b/tests/models/test_google.py @@ -796,7 +796,7 @@ async def test_google_url_input( model_name='gemini-2.0-flash', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ] ) @@ -833,7 +833,7 @@ async def test_google_url_input_force_download(allow_model_requests: None) -> No model_name='gemini-2.0-flash', timestamp=IsDatetime(), vendor_details={'finish_reason': 'STOP'}, - vendor_id=IsStr(), + id=IsStr(), ), ] ) diff --git a/tests/models/test_groq.py b/tests/models/test_groq.py index 4c5de38ee..0b39f009d 100644 --- a/tests/models/test_groq.py +++ b/tests/models/test_groq.py @@ -155,7 +155,7 @@ async def test_request_simple_success(allow_model_requests: None): usage=Usage(requests=1), model_name='llama-3.3-70b-versatile-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest(parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))]), ModelResponse( @@ -163,7 +163,7 @@ async def test_request_simple_success(allow_model_requests: None): usage=Usage(requests=1), model_name='llama-3.3-70b-versatile-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ] ) @@ -216,7 +216,7 @@ async def test_request_structured_response(allow_model_requests: None): usage=Usage(requests=1), model_name='llama-3.3-70b-versatile-123', timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -304,7 +304,7 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1, request_tokens=2, response_tokens=1, total_tokens=3), model_name='llama-3.3-70b-versatile-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -327,7 +327,7 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1, request_tokens=3, response_tokens=2, total_tokens=6), model_name='llama-3.3-70b-versatile-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -344,7 +344,7 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1), model_name='llama-3.3-70b-versatile-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ] ) @@ -582,7 +582,7 @@ async def get_image() -> BinaryContent: usage=Usage(requests=1, request_tokens=192, response_tokens=8, total_tokens=200), model_name='meta-llama/llama-4-scout-17b-16e-instruct', timestamp=IsDatetime(), - vendor_id='chatcmpl-3c327c89-e9f5-4aac-a5d5-190e6f6f25c9', + id='chatcmpl-3c327c89-e9f5-4aac-a5d5-190e6f6f25c9', ), ModelRequest( parts=[ @@ -606,7 +606,7 @@ async def get_image() -> BinaryContent: usage=Usage(requests=1, request_tokens=2552, response_tokens=11, total_tokens=2563), model_name='meta-llama/llama-4-scout-17b-16e-instruct', timestamp=IsDatetime(), - vendor_id='chatcmpl-82dfad42-6a28-4089-82c3-c8633f626c0d', + id='chatcmpl-82dfad42-6a28-4089-82c3-c8633f626c0d', ), ] ) @@ -684,7 +684,7 @@ async def test_groq_model_instructions(allow_model_requests: None, groq_api_key: usage=Usage(requests=1, request_tokens=48, response_tokens=8, total_tokens=56), model_name='llama-3.3-70b-versatile', timestamp=IsDatetime(), - vendor_id='chatcmpl-7586b6a9-fb4b-4ec7-86a0-59f0a77844cf', + id='chatcmpl-7586b6a9-fb4b-4ec7-86a0-59f0a77844cf', ), ] ) @@ -764,7 +764,7 @@ async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key usage=Usage(requests=1, request_tokens=21, response_tokens=1414, total_tokens=1435), model_name='deepseek-r1-distill-llama-70b', timestamp=IsDatetime(), - vendor_id=IsStr(), + id=IsStr(), ), ] ) @@ -785,7 +785,7 @@ async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key usage=Usage(requests=1, request_tokens=21, response_tokens=1414, total_tokens=1435), model_name='deepseek-r1-distill-llama-70b', timestamp=IsDatetime(), - vendor_id=IsStr(), + id=IsStr(), ), ModelRequest( parts=[ @@ -902,7 +902,7 @@ async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key usage=Usage(requests=1, request_tokens=524, response_tokens=1590, total_tokens=2114), model_name='deepseek-r1-distill-llama-70b', timestamp=IsDatetime(), - vendor_id=IsStr(), + id=IsStr(), ), ] ) diff --git a/tests/models/test_huggingface.py b/tests/models/test_huggingface.py index b7351d574..a553ef547 100644 --- a/tests/models/test_huggingface.py +++ b/tests/models/test_huggingface.py @@ -169,7 +169,7 @@ async def test_simple_completion(allow_model_requests: None, huggingface_api_key usage=Usage(requests=1, request_tokens=30, response_tokens=29, total_tokens=59), model_name='Qwen/Qwen2.5-72B-Instruct-fast', timestamp=datetime(2025, 7, 8, 13, 42, 33, tzinfo=timezone.utc), - vendor_id='chatcmpl-d445c0d473a84791af2acf356cc00df7', + id='chatcmpl-d445c0d473a84791af2acf356cc00df7', ) @@ -235,7 +235,7 @@ async def test_request_structured_response( usage=Usage(requests=1), model_name='hf-model', timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc), - vendor_id='123', + id='123', ) @@ -366,7 +366,7 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=2), model_name='hf-model', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -389,7 +389,7 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1, request_tokens=2, response_tokens=1, total_tokens=3), model_name='hf-model', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -406,7 +406,7 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1), model_name='hf-model', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ] ) @@ -653,7 +653,7 @@ async def test_image_url_input(allow_model_requests: None, huggingface_api_key: usage=Usage(requests=1, request_tokens=269, response_tokens=15, total_tokens=284), model_name='Qwen/Qwen2.5-VL-72B-Instruct', timestamp=datetime(2025, 7, 8, 14, 4, 39, tzinfo=timezone.utc), - vendor_id='chatcmpl-49aa100effab4ca28514d5ccc00d7944', + id='chatcmpl-49aa100effab4ca28514d5ccc00d7944', ), ] ) @@ -719,7 +719,7 @@ def simple_instructions(ctx: RunContext): usage=Usage(requests=1, request_tokens=26, response_tokens=2, total_tokens=28), model_name='Qwen/Qwen2.5-72B-Instruct-fast', timestamp=IsDatetime(), - vendor_id='chatcmpl-b3936940372c481b8d886e596dc75524', + id='chatcmpl-b3936940372c481b8d886e596dc75524', ), ] ) @@ -811,7 +811,7 @@ def response_validator(value: str) -> str: usage=Usage(requests=1), model_name='hf-model', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -828,7 +828,7 @@ def response_validator(value: str) -> str: usage=Usage(requests=1), model_name='hf-model', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ] ) @@ -958,7 +958,7 @@ async def test_hf_model_thinking_part(allow_model_requests: None, huggingface_ap usage=Usage(requests=1, request_tokens=15, response_tokens=1090, total_tokens=1105), model_name='Qwen/Qwen3-235B-A22B', timestamp=IsDatetime(), - vendor_id='chatcmpl-957db61fe60d4440bcfe1f11f2c5b4b9', + id='chatcmpl-957db61fe60d4440bcfe1f11f2c5b4b9', ), ] ) @@ -981,7 +981,7 @@ async def test_hf_model_thinking_part(allow_model_requests: None, huggingface_ap usage=Usage(requests=1, request_tokens=15, response_tokens=1090, total_tokens=1105), model_name='Qwen/Qwen3-235B-A22B', timestamp=IsDatetime(), - vendor_id='chatcmpl-957db61fe60d4440bcfe1f11f2c5b4b9', + id='chatcmpl-957db61fe60d4440bcfe1f11f2c5b4b9', ), ModelRequest( parts=[ @@ -999,7 +999,7 @@ async def test_hf_model_thinking_part(allow_model_requests: None, huggingface_ap usage=Usage(requests=1, request_tokens=691, response_tokens=1860, total_tokens=2551), model_name='Qwen/Qwen3-235B-A22B', timestamp=IsDatetime(), - vendor_id='chatcmpl-35fdec1307634f94a39f7e26f52e12a7', + id='chatcmpl-35fdec1307634f94a39f7e26f52e12a7', ), ] ) diff --git a/tests/models/test_mistral.py b/tests/models/test_mistral.py index 673695972..f409e64f4 100644 --- a/tests/models/test_mistral.py +++ b/tests/models/test_mistral.py @@ -222,7 +222,7 @@ async def test_multiple_completions(allow_model_requests: None): usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=IsNow(tz=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest(parts=[UserPromptPart(content='hello again', timestamp=IsNow(tz=timezone.utc))]), ModelResponse( @@ -230,7 +230,7 @@ async def test_multiple_completions(allow_model_requests: None): usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ] ) @@ -275,7 +275,7 @@ async def test_three_completions(allow_model_requests: None): usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest(parts=[UserPromptPart(content='hello again', timestamp=IsNow(tz=timezone.utc))]), ModelResponse( @@ -283,7 +283,7 @@ async def test_three_completions(allow_model_requests: None): usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest(parts=[UserPromptPart(content='final message', timestamp=IsNow(tz=timezone.utc))]), ModelResponse( @@ -291,7 +291,7 @@ async def test_three_completions(allow_model_requests: None): usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ] ) @@ -410,7 +410,7 @@ class CityLocation(BaseModel): usage=Usage(requests=1, request_tokens=1, response_tokens=2, total_tokens=3), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -471,7 +471,7 @@ class CityLocation(BaseModel): usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -531,7 +531,7 @@ async def test_request_output_type_with_arguments_str_response(allow_model_reque usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -1099,7 +1099,7 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1, request_tokens=2, response_tokens=1, total_tokens=3), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -1122,7 +1122,7 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1, request_tokens=3, response_tokens=2, total_tokens=6), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -1139,7 +1139,7 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ] ) @@ -1242,7 +1242,7 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1, request_tokens=2, response_tokens=1, total_tokens=3), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -1265,7 +1265,7 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1, request_tokens=3, response_tokens=2, total_tokens=6), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -1288,7 +1288,7 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1, request_tokens=2, response_tokens=1, total_tokens=3), model_name='mistral-large-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + id='123', ), ModelRequest( parts=[ @@ -1807,7 +1807,7 @@ async def get_image() -> BinaryContent: usage=Usage(requests=1, request_tokens=65, response_tokens=16, total_tokens=81), model_name='pixtral-12b-latest', timestamp=IsDatetime(), - vendor_id='fce6d16a4e5940edb24ae16dd0369947', + id='fce6d16a4e5940edb24ae16dd0369947', ), ModelRequest( parts=[ @@ -1835,7 +1835,7 @@ async def get_image() -> BinaryContent: usage=Usage(requests=1, request_tokens=2931, response_tokens=70, total_tokens=3001), model_name='pixtral-12b-latest', timestamp=IsDatetime(), - vendor_id='26e7de193646460e8904f8e604a60dc1', + id='26e7de193646460e8904f8e604a60dc1', ), ] ) @@ -1873,7 +1873,7 @@ async def test_image_url_input(allow_model_requests: None): usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=IsDatetime(), - vendor_id='123', + id='123', ), ] ) @@ -1906,7 +1906,7 @@ async def test_image_as_binary_content_input(allow_model_requests: None): usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=IsDatetime(), - vendor_id='123', + id='123', ), ] ) @@ -1942,7 +1942,7 @@ async def test_pdf_url_input(allow_model_requests: None): usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=IsDatetime(), - vendor_id='123', + id='123', ), ] ) @@ -1972,7 +1972,7 @@ async def test_pdf_as_binary_content_input(allow_model_requests: None): usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=IsDatetime(), - vendor_id='123', + id='123', ), ] ) @@ -2048,7 +2048,7 @@ async def test_mistral_model_instructions(allow_model_requests: None, mistral_ap usage=Usage(requests=1, request_tokens=1, response_tokens=1, total_tokens=1), model_name='mistral-large-123', timestamp=IsDatetime(), - vendor_id='123', + id='123', ), ] ) @@ -2080,7 +2080,7 @@ async def test_mistral_model_thinking_part(allow_model_requests: None, openai_ap ), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), - vendor_id='resp_68079acebbfc819189ec20e1e5bf525d0493b22e4095129c', + id='resp_68079acebbfc819189ec20e1e5bf525d0493b22e4095129c', ), ] ) @@ -2143,7 +2143,7 @@ async def test_mistral_model_thinking_part(allow_model_requests: None, openai_ap ), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), - vendor_id='resp_68079acebbfc819189ec20e1e5bf525d0493b22e4095129c', + id='resp_68079acebbfc819189ec20e1e5bf525d0493b22e4095129c', ), ModelRequest( parts=[ @@ -2158,7 +2158,7 @@ async def test_mistral_model_thinking_part(allow_model_requests: None, openai_ap usage=Usage(requests=1, request_tokens=1036, response_tokens=691, total_tokens=1727), model_name='mistral-large-latest', timestamp=IsDatetime(), - vendor_id='a088e80a476e44edaaa959a1ff08f358', + id='a088e80a476e44edaaa959a1ff08f358', ), ] ) diff --git a/tests/models/test_openai.py b/tests/models/test_openai.py index 880c70eff..f343a3f03 100644 --- a/tests/models/test_openai.py +++ b/tests/models/test_openai.py @@ -188,7 +188,9 @@ async def test_request_simple_success(allow_model_requests: None): usage=Usage(requests=1), model_name='gpt-4o-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + vendor_details={'finish_reason': 'stop'}, + id='123', + finish_reason='stop', ), ModelRequest(parts=[UserPromptPart(content='hello', timestamp=IsNow(tz=timezone.utc))]), ModelResponse( @@ -196,7 +198,9 @@ async def test_request_simple_success(allow_model_requests: None): usage=Usage(requests=1), model_name='gpt-4o-123', timestamp=datetime(2024, 1, 1, 0, 0, tzinfo=timezone.utc), - vendor_id='123', + vendor_details={'finish_reason': 'stop'}, + id='123', + finish_reason='stop', ), ] ) @@ -268,7 +272,9 @@ async def test_request_structured_response(allow_model_requests: None): usage=Usage(requests=1), model_name='gpt-4o-123', timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc), - vendor_id='123', + vendor_details={'finish_reason': 'stop'}, + id='123', + finish_reason='stop', ), ModelRequest( parts=[ @@ -360,7 +366,9 @@ async def get_location(loc_name: str) -> str: ), model_name='gpt-4o-123', timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc), - vendor_id='123', + vendor_details={'finish_reason': 'stop'}, + id='123', + finish_reason='stop', ), ModelRequest( parts=[ @@ -385,7 +393,9 @@ async def get_location(loc_name: str) -> str: ), model_name='gpt-4o-123', timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc), - vendor_id='123', + vendor_details={'finish_reason': 'stop'}, + id='123', + finish_reason='stop', ), ModelRequest( parts=[ @@ -402,7 +412,9 @@ async def get_location(loc_name: str) -> str: usage=Usage(requests=1), model_name='gpt-4o-123', timestamp=datetime(2024, 1, 1, tzinfo=timezone.utc), - vendor_id='123', + vendor_details={'finish_reason': 'stop'}, + id='123', + finish_reason='stop', ), ] ) @@ -834,7 +846,9 @@ async def get_image() -> ImageUrl: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRmTHlrARTzAHK1na9s80xDlQGYPX', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BRmTHlrARTzAHK1na9s80xDlQGYPX', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -872,7 +886,9 @@ async def get_image() -> ImageUrl: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRmTI0Y2zmkGw27kLarhsmiFQTGxR', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BRmTI0Y2zmkGw27kLarhsmiFQTGxR', + finish_reason='stop', ), ] ) @@ -917,7 +933,9 @@ async def get_image() -> BinaryContent: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRlkLhPc87BdohVobEJJCGq3rUAG2', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BRlkLhPc87BdohVobEJJCGq3rUAG2', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -953,7 +971,9 @@ async def get_image() -> BinaryContent: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRlkORPA5rXMV3uzcOcgK4eQFKCVW', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BRlkORPA5rXMV3uzcOcgK4eQFKCVW', + finish_reason='stop', ), ] ) @@ -1598,7 +1618,9 @@ async def test_openai_instructions(allow_model_requests: None, openai_api_key: s ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BJjf61mLb9z5H45ClJzbx0UWKwjo1', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BJjf61mLb9z5H45ClJzbx0UWKwjo1', + finish_reason='stop', ), ] ) @@ -1645,7 +1667,9 @@ async def get_temperature(city: str) -> float: ), model_name='gpt-4.1-mini-2025-04-14', timestamp=IsDatetime(), - vendor_id='chatcmpl-BMxEwRA0p0gJ52oKS7806KAlfMhqq', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BMxEwRA0p0gJ52oKS7806KAlfMhqq', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -1672,7 +1696,9 @@ async def get_temperature(city: str) -> float: ), model_name='gpt-4.1-mini-2025-04-14', timestamp=IsDatetime(), - vendor_id='chatcmpl-BMxEx6B8JEj6oDC45MOWKp0phg8UP', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BMxEx6B8JEj6oDC45MOWKp0phg8UP', + finish_reason='stop', ), ] ) @@ -1704,7 +1730,7 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, ), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), - vendor_id='resp_68034835d12481919c80a7fd8dbe6f7e08c845d2be9bcdd8', + id='resp_68034835d12481919c80a7fd8dbe6f7e08c845d2be9bcdd8', ), ] ) @@ -1732,7 +1758,7 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, ), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), - vendor_id='resp_68034835d12481919c80a7fd8dbe6f7e08c845d2be9bcdd8', + id='resp_68034835d12481919c80a7fd8dbe6f7e08c845d2be9bcdd8', ), ModelRequest( parts=[ @@ -1757,7 +1783,7 @@ async def test_openai_responses_model_thinking_part(allow_model_requests: None, ), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), - vendor_id='resp_6803484f19a88191b9ea975d7cfbbe8408c845d2be9bcdd8', + id='resp_6803484f19a88191b9ea975d7cfbbe8408c845d2be9bcdd8', ), ] ) @@ -1790,7 +1816,7 @@ async def test_openai_model_thinking_part(allow_model_requests: None, openai_api ), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), - vendor_id='resp_680797310bbc8191971fff5a405113940ed3ec3064b5efac', + id='resp_680797310bbc8191971fff5a405113940ed3ec3064b5efac', ), ] ) @@ -1819,7 +1845,7 @@ async def test_openai_model_thinking_part(allow_model_requests: None, openai_api ), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), - vendor_id='resp_680797310bbc8191971fff5a405113940ed3ec3064b5efac', + id='resp_680797310bbc8191971fff5a405113940ed3ec3064b5efac', ), ModelRequest( parts=[ @@ -1846,7 +1872,9 @@ async def test_openai_model_thinking_part(allow_model_requests: None, openai_api ), model_name='o3-mini-2025-01-31', timestamp=IsDatetime(), - vendor_id='chatcmpl-BP7ocN6qxho4C1UzUJWnU5tPJno55', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BP7ocN6qxho4C1UzUJWnU5tPJno55', + finish_reason='stop', ), ] ) @@ -2109,7 +2137,9 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BSXk0dWkG4hfPt0lph4oFO35iT73I', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BSXk0dWkG4hfPt0lph4oFO35iT73I', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -2144,7 +2174,9 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BSXk1xGHYzbhXgUkSutK08bdoNv5s', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BSXk1xGHYzbhXgUkSutK08bdoNv5s', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -2205,7 +2237,9 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BgeDFS85bfHosRFEEAvq8reaCPCZ8', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BgeDFS85bfHosRFEEAvq8reaCPCZ8', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -2234,7 +2268,9 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BgeDGX9eDyVrEI56aP2vtIHahBzFH', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BgeDGX9eDyVrEI56aP2vtIHahBzFH', + finish_reason='stop', ), ] ) @@ -2288,7 +2324,9 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BSXjyBwGuZrtuuSzNCeaWMpGv2MZ3', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BSXjyBwGuZrtuuSzNCeaWMpGv2MZ3', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -2317,7 +2355,9 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BSXjzYGu67dhTy5r8KmjJvQ4HhDVO', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BSXjzYGu67dhTy5r8KmjJvQ4HhDVO', + finish_reason='stop', ), ] ) @@ -2373,7 +2413,9 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-Bgg5utuCSXMQ38j0n2qgfdQKcR9VD', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-Bgg5utuCSXMQ38j0n2qgfdQKcR9VD', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -2406,7 +2448,9 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-Bgg5vrxUtCDlvgMreoxYxPaKxANmd', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-Bgg5vrxUtCDlvgMreoxYxPaKxANmd', + finish_reason='stop', ), ] ) @@ -2465,7 +2509,9 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-Bgh27PeOaFW6qmF04qC5uI2H9mviw', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-Bgh27PeOaFW6qmF04qC5uI2H9mviw', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -2501,7 +2547,9 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-Bgh28advCSFhGHPnzUevVS6g6Uwg0', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-Bgh28advCSFhGHPnzUevVS6g6Uwg0', + finish_reason='stop', ), ] ) @@ -2564,7 +2612,9 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-Bgh2AW2NXGgMc7iS639MJXNRgtatR', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-Bgh2AW2NXGgMc7iS639MJXNRgtatR', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -2604,7 +2654,9 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-Bgh2BthuopRnSqCuUgMbBnOqgkDHC', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-Bgh2BthuopRnSqCuUgMbBnOqgkDHC', + finish_reason='stop', ), ] ) diff --git a/tests/models/test_openai_responses.py b/tests/models/test_openai_responses.py index 30e98d70f..c17507f62 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -198,7 +198,7 @@ async def get_location(loc_name: str) -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_67e547c48c9481918c5c4394464ce0c60ae6111e84dd5c08', + id='resp_67e547c48c9481918c5c4394464ce0c60ae6111e84dd5c08', ), ModelRequest( parts=[ @@ -234,7 +234,7 @@ async def get_location(loc_name: str) -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_67e547c5a2f08191802a1f43620f348503a2086afed73b47', + id='resp_67e547c5a2f08191802a1f43620f348503a2086afed73b47', ), ] ) @@ -272,7 +272,7 @@ async def get_image() -> BinaryContent: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_681134d3aa3481919ca581a267db1e510fe7a5a4e2123dc3', + id='resp_681134d3aa3481919ca581a267db1e510fe7a5a4e2123dc3', ), ModelRequest( parts=[ @@ -301,7 +301,7 @@ async def get_image() -> BinaryContent: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_681134d53c48819198ce7b89db78dffd02cbfeaababb040c', + id='resp_681134d53c48819198ce7b89db78dffd02cbfeaababb040c', ), ] ) @@ -437,7 +437,7 @@ async def test_openai_responses_model_builtin_tools(allow_model_requests: None, ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_67ebcbb93728819197f923ff16e98bce04f5055a2a33abc3', + id='resp_67ebcbb93728819197f923ff16e98bce04f5055a2a33abc3', ), ] ) @@ -465,7 +465,7 @@ async def test_openai_responses_model_instructions(allow_model_requests: None, o ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_67f3fdfd9fa08191a3d5825db81b8df6003bc73febb56d77', + id='resp_67f3fdfd9fa08191a3d5825db81b8df6003bc73febb56d77', ), ] ) @@ -558,7 +558,7 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_68477f0b40a8819cb8d55594bc2c232a001fd29e2d5573f7', + id='resp_68477f0b40a8819cb8d55594bc2c232a001fd29e2d5573f7', ), ModelRequest( parts=[ @@ -586,7 +586,7 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_68477f0bfda8819ea65458cd7cc389b801dc81d4bc91f560', + id='resp_68477f0bfda8819ea65458cd7cc389b801dc81d4bc91f560', ), ModelRequest( parts=[ @@ -640,7 +640,7 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_68477f0d9494819ea4f123bba707c9ee0356a60c98816d6a', + id='resp_68477f0d9494819ea4f123bba707c9ee0356a60c98816d6a', ), ModelRequest( parts=[ @@ -662,7 +662,7 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_68477f0e2b28819d9c828ef4ee526d6a03434b607c02582d', + id='resp_68477f0e2b28819d9c828ef4ee526d6a03434b607c02582d', ), ] ) @@ -707,7 +707,7 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_68477f0f220081a1a621d6bcdc7f31a50b8591d9001d2329', + id='resp_68477f0f220081a1a621d6bcdc7f31a50b8591d9001d2329', ), ModelRequest( parts=[ @@ -729,7 +729,7 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_68477f0fde708192989000a62809c6e5020197534e39cc1f', + id='resp_68477f0fde708192989000a62809c6e5020197534e39cc1f', ), ] ) @@ -776,7 +776,7 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_68477f10f2d081a39b3438f413b3bafc0dd57d732903c563', + id='resp_68477f10f2d081a39b3438f413b3bafc0dd57d732903c563', ), ModelRequest( parts=[ @@ -802,7 +802,7 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_68477f119830819da162aa6e10552035061ad97e2eef7871', + id='resp_68477f119830819da162aa6e10552035061ad97e2eef7871', ), ] ) @@ -852,7 +852,7 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_68482f12d63881a1830201ed101ecfbf02f8ef7f2fb42b50', + id='resp_68482f12d63881a1830201ed101ecfbf02f8ef7f2fb42b50', ), ModelRequest( parts=[ @@ -881,7 +881,7 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_68482f1b556081918d64c9088a470bf0044fdb7d019d4115', + id='resp_68482f1b556081918d64c9088a470bf0044fdb7d019d4115', ), ] ) @@ -935,7 +935,7 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_68482f1d38e081a1ac828acda978aa6b08e79646fe74d5ee', + id='resp_68482f1d38e081a1ac828acda978aa6b08e79646fe74d5ee', ), ModelRequest( parts=[ @@ -968,7 +968,7 @@ async def get_user_country() -> str: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='resp_68482f28c1b081a1ae73cbbee012ee4906b4ab2d00d03024', + id='resp_68482f28c1b081a1ae73cbbee012ee4906b4ab2d00d03024', ), ] ) diff --git a/tests/test_agent.py b/tests/test_agent.py index a5a9285d5..e30acbec2 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -2963,10 +2963,11 @@ def test_binary_content_all_messages_json(): 'details': None, }, 'model_name': 'test', - 'vendor_id': None, 'timestamp': IsStr(), 'kind': 'response', 'vendor_details': None, + 'id': None, + 'finish_reason': None, }, ] ) diff --git a/tests/test_mcp.py b/tests/test_mcp.py index 1021b3151..a760a2847 100644 --- a/tests/test_mcp.py +++ b/tests/test_mcp.py @@ -216,7 +216,9 @@ async def test_agent_with_stdio_server(allow_model_requests: None, agent: Agent) ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRlnvvqIPFofAtKqtQKMWZkgXhzlT', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BRlnvvqIPFofAtKqtQKMWZkgXhzlT', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -245,7 +247,9 @@ async def test_agent_with_stdio_server(allow_model_requests: None, agent: Agent) ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRlnyjUo5wlyqvdNdM5I8vIWjo1qF', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BRlnyjUo5wlyqvdNdM5I8vIWjo1qF', + finish_reason='stop', ), ] ) @@ -352,7 +356,9 @@ async def test_tool_returning_str(allow_model_requests: None, agent: Agent): ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRlo3e1Ud2lnvkddMilmwC7LAemiy', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BRlo3e1Ud2lnvkddMilmwC7LAemiy', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -385,7 +391,9 @@ async def test_tool_returning_str(allow_model_requests: None, agent: Agent): ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRlo41LxqBYgGKWgGrQn67fQacOLp', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BRlo41LxqBYgGKWgGrQn67fQacOLp', + finish_reason='stop', ), ] ) @@ -429,7 +437,9 @@ async def test_tool_returning_text_resource(allow_model_requests: None, agent: A ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRmhyweJVYonarb7s9ckIMSHf2vHo', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BRmhyweJVYonarb7s9ckIMSHf2vHo', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -458,7 +468,9 @@ async def test_tool_returning_text_resource(allow_model_requests: None, agent: A ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRmhzqXFObpYwSzREMpJvX9kbDikR', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BRmhzqXFObpYwSzREMpJvX9kbDikR', + finish_reason='stop', ), ] ) @@ -502,7 +514,9 @@ async def test_tool_returning_text_resource_link(allow_model_requests: None, age ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BwdHSFe0EykAOpf0LWZzsWAodIQzb', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BwdHSFe0EykAOpf0LWZzsWAodIQzb', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -531,7 +545,9 @@ async def test_tool_returning_text_resource_link(allow_model_requests: None, age ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BwdHTIlBZWzXJPBR8VTOdC4O57ZQA', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BwdHTIlBZWzXJPBR8VTOdC4O57ZQA', + finish_reason='stop', ), ] ) @@ -577,7 +593,9 @@ async def test_tool_returning_image_resource(allow_model_requests: None, agent: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRlo7KYJVXuNZ5lLLdYcKZDsX2CHb', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BRlo7KYJVXuNZ5lLLdYcKZDsX2CHb', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -611,7 +629,9 @@ async def test_tool_returning_image_resource(allow_model_requests: None, agent: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRloBGHh27w3fQKwxq4fX2cPuZJa9', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BRloBGHh27w3fQKwxq4fX2cPuZJa9', + finish_reason='stop', ), ] ) @@ -659,7 +679,9 @@ async def test_tool_returning_image_resource_link( ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BwdHygYePH1mZgHo2Xxzib0Y7sId7', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BwdHygYePH1mZgHo2Xxzib0Y7sId7', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -693,7 +715,9 @@ async def test_tool_returning_image_resource_link( ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BwdI2D2r9dvqq3pbsA0qgwKDEdTtD', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BwdI2D2r9dvqq3pbsA0qgwKDEdTtD', + finish_reason='stop', ), ] ) @@ -855,7 +879,9 @@ async def test_tool_returning_image(allow_model_requests: None, agent: Agent, im ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRloGQJWIX0Qk7gtNzF4s2Fez0O29', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BRloGQJWIX0Qk7gtNzF4s2Fez0O29', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -891,7 +917,9 @@ async def test_tool_returning_image(allow_model_requests: None, agent: Agent, im ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRloJHR654fSD0fcvLWZxtKtn0pag', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BRloJHR654fSD0fcvLWZxtKtn0pag', + finish_reason='stop', ), ] ) @@ -929,7 +957,9 @@ async def test_tool_returning_dict(allow_model_requests: None, agent: Agent): ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRloOs7Bb2tq8wJyy9Rv7SQ7L65a7', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BRloOs7Bb2tq8wJyy9Rv7SQ7L65a7', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -958,7 +988,9 @@ async def test_tool_returning_dict(allow_model_requests: None, agent: Agent): ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRloPczU1HSCWnreyo21DdNtdOM7L', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BRloPczU1HSCWnreyo21DdNtdOM7L', + finish_reason='stop', ), ] ) @@ -1004,7 +1036,9 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRloSNg7aGSp1rXDkhInjMIUHKd7A', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BRloSNg7aGSp1rXDkhInjMIUHKd7A', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -1039,7 +1073,9 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRloTvSkFeX4DZKQLqfH9KbQkWlpt', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BRloTvSkFeX4DZKQLqfH9KbQkWlpt', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -1072,7 +1108,9 @@ async def test_tool_returning_error(allow_model_requests: None, agent: Agent): ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRloU3MhnqNEqujs28a3ofRbs7VPF', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BRloU3MhnqNEqujs28a3ofRbs7VPF', + finish_reason='stop', ), ] ) @@ -1110,7 +1148,9 @@ async def test_tool_returning_none(allow_model_requests: None, agent: Agent): ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRloX2RokWc9j9PAXAuNXGR73WNqY', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BRloX2RokWc9j9PAXAuNXGR73WNqY', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -1139,7 +1179,9 @@ async def test_tool_returning_none(allow_model_requests: None, agent: Agent): ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRloYWGujk8yE94gfVSsM1T1Ol2Ej', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BRloYWGujk8yE94gfVSsM1T1Ol2Ej', + finish_reason='stop', ), ] ) @@ -1185,7 +1227,9 @@ async def test_tool_returning_multiple_items(allow_model_requests: None, agent: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRlobKLgm6vf79c9O8sloZaYx3coC', + vendor_details={'finish_reason': 'tool_calls'}, + id='chatcmpl-BRlobKLgm6vf79c9O8sloZaYx3coC', + finish_reason='tool_calls', ), ModelRequest( parts=[ @@ -1230,7 +1274,9 @@ async def test_tool_returning_multiple_items(allow_model_requests: None, agent: ), model_name='gpt-4o-2024-08-06', timestamp=IsDatetime(), - vendor_id='chatcmpl-BRloepWR5NJpTgSqFBGTSPeM1SWm8', + vendor_details={'finish_reason': 'stop'}, + id='chatcmpl-BRloepWR5NJpTgSqFBGTSPeM1SWm8', + finish_reason='stop', ), ] )