16
16
from pydantic_ai .exceptions import ModelHTTPError , ModelRetry
17
17
from pydantic_ai .messages import (
18
18
BinaryContent ,
19
+ DocumentUrl ,
19
20
ImageUrl ,
20
21
ModelRequest ,
21
22
ModelResponse ,
@@ -123,7 +124,7 @@ def completion_message(
123
124
return MistralChatCompletionResponse (
124
125
id = '123' ,
125
126
choices = [MistralChatCompletionChoice (finish_reason = 'stop' , index = 0 , message = message )],
126
- created = 1704067200 if with_created else None , # 2024-01-01
127
+ created = 1704067200 if with_created else 0 , # 2024-01-01
127
128
model = 'mistral-large-123' ,
128
129
object = 'chat.completion' ,
129
130
usage = usage or MistralUsageInfo (prompt_tokens = 1 , completion_tokens = 1 , total_tokens = 1 ),
@@ -142,7 +143,7 @@ def chunk(
142
143
MistralCompletionResponseStreamChoice (index = index , delta = delta , finish_reason = finish_reason )
143
144
for index , delta in enumerate (delta )
144
145
],
145
- created = 1704067200 if with_created else None , # 2024-01-01
146
+ created = 1704067200 if with_created else 0 , # 2024-01-01
146
147
model = 'gpt-4' ,
147
148
object = 'chat.completion.chunk' ,
148
149
usage = MistralUsageInfo (prompt_tokens = 1 , completion_tokens = 1 , total_tokens = 1 ),
@@ -188,11 +189,13 @@ def test_init():
188
189
189
190
async def test_multiple_completions (allow_model_requests : None ):
190
191
completions = [
192
+ # First completion: created is "now" (simulate IsNow)
191
193
completion_message (
192
194
MistralAssistantMessage (content = 'world' ),
193
195
usage = MistralUsageInfo (prompt_tokens = 1 , completion_tokens = 1 , total_tokens = 1 ),
194
196
with_created = False ,
195
197
),
198
+ # Second completion: created is fixed 2024-01-01 00:00:00 UTC
196
199
completion_message (MistralAssistantMessage (content = 'hello again' )),
197
200
]
198
201
mock_client = MockMistralAI .create_mock (completions )
@@ -1909,6 +1912,87 @@ async def test_image_as_binary_content_input(allow_model_requests: None):
1909
1912
)
1910
1913
1911
1914
1915
+ async def test_pdf_url_input (allow_model_requests : None ):
1916
+ c = completion_message (MistralAssistantMessage (content = 'world' , role = 'assistant' ))
1917
+ mock_client = MockMistralAI .create_mock (c )
1918
+ m = MistralModel ('mistral-large-latest' , provider = MistralProvider (mistral_client = mock_client ))
1919
+ agent = Agent (m )
1920
+
1921
+ result = await agent .run (
1922
+ [
1923
+ 'hello' ,
1924
+ DocumentUrl (url = 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' ),
1925
+ ]
1926
+ )
1927
+ assert result .all_messages () == snapshot (
1928
+ [
1929
+ ModelRequest (
1930
+ parts = [
1931
+ UserPromptPart (
1932
+ content = [
1933
+ 'hello' ,
1934
+ DocumentUrl (url = 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' ),
1935
+ ],
1936
+ timestamp = IsDatetime (),
1937
+ )
1938
+ ]
1939
+ ),
1940
+ ModelResponse (
1941
+ parts = [TextPart (content = 'world' )],
1942
+ usage = Usage (requests = 1 , request_tokens = 1 , response_tokens = 1 , total_tokens = 1 ),
1943
+ model_name = 'mistral-large-123' ,
1944
+ timestamp = IsDatetime (),
1945
+ vendor_id = '123' ,
1946
+ ),
1947
+ ]
1948
+ )
1949
+
1950
+
1951
+ async def test_pdf_as_binary_content_input (allow_model_requests : None ):
1952
+ c = completion_message (MistralAssistantMessage (content = 'world' , role = 'assistant' ))
1953
+ mock_client = MockMistralAI .create_mock (c )
1954
+ m = MistralModel ('mistral-large-latest' , provider = MistralProvider (mistral_client = mock_client ))
1955
+ agent = Agent (m )
1956
+
1957
+ base64_content = b'%PDF-1.\r trailer<</Root<</Pages<</Kids[<</MediaBox[0 0 3 3]>>>>>>>>>'
1958
+
1959
+ result = await agent .run (['hello' , BinaryContent (data = base64_content , media_type = 'application/pdf' )])
1960
+ assert result .all_messages () == snapshot (
1961
+ [
1962
+ ModelRequest (
1963
+ parts = [
1964
+ UserPromptPart (
1965
+ content = ['hello' , BinaryContent (data = base64_content , media_type = 'application/pdf' )],
1966
+ timestamp = IsDatetime (),
1967
+ )
1968
+ ]
1969
+ ),
1970
+ ModelResponse (
1971
+ parts = [TextPart (content = 'world' )],
1972
+ usage = Usage (requests = 1 , request_tokens = 1 , response_tokens = 1 , total_tokens = 1 ),
1973
+ model_name = 'mistral-large-123' ,
1974
+ timestamp = IsDatetime (),
1975
+ vendor_id = '123' ,
1976
+ ),
1977
+ ]
1978
+ )
1979
+
1980
+
1981
+ async def test_txt_url_input (allow_model_requests : None ):
1982
+ c = completion_message (MistralAssistantMessage (content = 'world' , role = 'assistant' ))
1983
+ mock_client = MockMistralAI .create_mock (c )
1984
+ m = MistralModel ('mistral-large-latest' , provider = MistralProvider (mistral_client = mock_client ))
1985
+ agent = Agent (m )
1986
+
1987
+ with pytest .raises (RuntimeError , match = 'DocumentUrl other than PDF is not supported in Mistral.' ):
1988
+ await agent .run (
1989
+ [
1990
+ 'hello' ,
1991
+ DocumentUrl (url = 'https://examplefiles.org/files/documents/plaintext-example-file-download.txt' ),
1992
+ ]
1993
+ )
1994
+
1995
+
1912
1996
async def test_audio_as_binary_content_input (allow_model_requests : None ):
1913
1997
c = completion_message (MistralAssistantMessage (content = 'world' , role = 'assistant' ))
1914
1998
mock_client = MockMistralAI .create_mock (c )
@@ -1917,7 +2001,7 @@ async def test_audio_as_binary_content_input(allow_model_requests: None):
1917
2001
1918
2002
base64_content = b'//uQZ'
1919
2003
1920
- with pytest .raises (RuntimeError , match = 'Only image binary content is supported for Mistral.' ):
2004
+ with pytest .raises (RuntimeError , match = 'BinaryContent other than image or PDF is not supported in Mistral.' ):
1921
2005
await agent .run (['hello' , BinaryContent (data = base64_content , media_type = 'audio/wav' )])
1922
2006
1923
2007
0 commit comments