Skip to content

Commit fd6fc04

Browse files
committed
feat: update extra code
1 parent 53079a4 commit fd6fc04

31 files changed

+2540
-27
lines changed

examples/async_chat_with_image_no_streaming.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
async def main():
1212
api_key = os.environ["MISTRAL_API_KEY"]
13-
model = "pixtral-12b"
13+
model = "pixtral-12b-2409"
1414
client = Mistral(api_key=api_key)
1515

1616
chat_response = await client.chat.complete_async(
@@ -21,7 +21,7 @@ async def main():
2121
{"type": "text", "text": "What's in this image?"},
2222
{
2323
"type": "image_url",
24-
"image_url": "https://cms.mistral.ai/assets/af26a11d-0793-439f-a06e-7694b24b8270",
24+
"image_url": "https://cms.mistral.ai/assets/a64b3821-3a4c-4d4d-b718-d653f3eb7a5e.png?",
2525
},
2626
]
2727
)

examples/async_chat_with_streaming.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ async def main():
2020
UserMessage(content="What is the best French cheese?give the best 50")
2121
],
2222
)
23+
assert response
2324
async for chunk in response:
2425
if chunk.data.choices[0].delta.content is not None:
2526
print(chunk.data.choices[0].delta.content, end="")

examples/async_conversation_run.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env python
2+
import asyncio
3+
import os
4+
5+
from mistralai import Mistral
6+
from mistralai.extra.run.context import RunContext
7+
from mistralai.types import BaseModel
8+
9+
MODEL = "mistral-medium-latest"
10+
11+
12+
def math_question_generator(question_num: int):
13+
"""Random generator of mathematical question
14+
15+
Args:
16+
question_num (int): the number of the question that will be returned, should be between 1-100
17+
"""
18+
return (
19+
"solve the following differential equation: `y'' + 3y' + 2y = 0`"
20+
if question_num % 2 == 0
21+
else "solve the following differential equation: `y'' - 4y' + 4y = e^x`"
22+
)
23+
24+
25+
async def main():
26+
api_key = os.environ["MISTRAL_API_KEY"]
27+
client = Mistral(api_key=api_key)
28+
29+
class Explanation(BaseModel):
30+
explanation: str
31+
output: str
32+
33+
class MathDemonstration(BaseModel):
34+
steps: list[Explanation]
35+
final_answer: str
36+
37+
async with RunContext(model=MODEL, output_format=MathDemonstration) as run_ctx:
38+
# register a new function that can be executed on the client side
39+
run_ctx.register_func(math_question_generator)
40+
run_result = await client.beta.conversations.run_async(
41+
run_ctx=run_ctx,
42+
instructions="Use the code interpreter to help you when asked mathematical questions.",
43+
inputs=[
44+
{"role": "user", "content": "hey"},
45+
{"role": "assistant", "content": "hello"},
46+
{"role": "user", "content": "Request a math question and answer it."},
47+
],
48+
tools=[{"type": "code_interpreter"}],
49+
)
50+
print("All run entries:")
51+
for entry in run_result.output_entries:
52+
print(f"{entry}")
53+
print(f"Final model: {run_result.output_as_model}")
54+
55+
56+
if __name__ == "__main__":
57+
asyncio.run(main())
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env python
2+
import asyncio
3+
import os
4+
import random
5+
6+
from mistralai import Mistral
7+
from mistralai.extra.run.context import RunContext
8+
from mcp import StdioServerParameters
9+
from mistralai.extra.mcp.stdio import (
10+
MCPClientSTDIO,
11+
)
12+
from pathlib import Path
13+
14+
from mistralai.types import BaseModel
15+
16+
cwd = Path(__file__).parent
17+
MODEL = "mistral-medium-latest"
18+
19+
20+
async def main() -> None:
21+
api_key = os.environ["MISTRAL_API_KEY"]
22+
client = Mistral(api_key=api_key)
23+
24+
# Create a mcp server has a tool to return the weather based on the location
25+
server_params = StdioServerParameters(
26+
command="python",
27+
args=[str((cwd / "mcp_servers/stdio_server.py").resolve())],
28+
env=None,
29+
)
30+
31+
weather_agent = client.beta.agents.create(
32+
model=MODEL,
33+
name="weather teller",
34+
instructions="You are able to tell the weather.",
35+
description="",
36+
)
37+
38+
class WeatherResult(BaseModel):
39+
user: str
40+
location: str
41+
temperature: float
42+
43+
async with RunContext(
44+
agent_id=weather_agent.id,
45+
output_format=WeatherResult,
46+
continue_on_fn_error=True,
47+
) as run_ctx:
48+
# Add location function to the run context
49+
@run_ctx.register_func
50+
def get_location(name: str) -> str:
51+
"""function to get location of a user.
52+
53+
Args:
54+
name: name of the user.
55+
"""
56+
return random.choice(["New York", "London", "Paris", "Tokyo", "Sydney"])
57+
58+
# Add mcp client to the run context
59+
mcp_client = MCPClientSTDIO(stdio_params=server_params)
60+
await run_ctx.register_mcp_client(mcp_client=mcp_client)
61+
62+
run_result = await client.beta.conversations.run_async(
63+
run_ctx=run_ctx,
64+
inputs="Tell me the weather in John's location currently.",
65+
)
66+
67+
print("All run entries:")
68+
for entry in run_result.output_entries:
69+
print(f"{entry}")
70+
print()
71+
print(f"Final model: {run_result.output_as_model}")
72+
73+
74+
if __name__ == "__main__":
75+
asyncio.run(main())
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env python
2+
import asyncio
3+
import os
4+
5+
from mistralai import Mistral
6+
from mistralai.extra.run.context import RunContext
7+
8+
from mistralai.extra.mcp.sse import (
9+
MCPClientSSE,
10+
SSEServerParams,
11+
)
12+
from pathlib import Path
13+
14+
cwd = Path(__file__).parent
15+
MODEL = "mistral-medium-latest"
16+
17+
# Use an official remote mcp server
18+
# you can find some at:
19+
# - https://mcpservers.org/remote-mcp-servers
20+
# this one does not require auth: https://remote.mcpservers.org/edgeone-pages/mcp
21+
22+
23+
async def main():
24+
api_key = os.environ["MISTRAL_API_KEY"]
25+
client = Mistral(api_key=api_key)
26+
27+
server_url = "https://mcp.semgrep.ai/sse"
28+
mcp_client = MCPClientSSE(sse_params=SSEServerParams(url=server_url, timeout=100))
29+
30+
async with RunContext(
31+
model=MODEL,
32+
) as run_ctx:
33+
# Add mcp client to the run context
34+
await run_ctx.register_mcp_client(mcp_client=mcp_client)
35+
36+
run_result = await client.beta.conversations.run_async(
37+
run_ctx=run_ctx,
38+
inputs="Can you write a hello_world.py and check for security vulnerabilities",
39+
)
40+
41+
print("All run entries:")
42+
for entry in run_result.output_entries:
43+
print(f"{entry}")
44+
print()
45+
print(f"Final Response: {run_result.output_as_text}")
46+
47+
48+
if __name__ == "__main__":
49+
asyncio.run(main())
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#!/usr/bin/env python
2+
import asyncio
3+
from http.server import BaseHTTPRequestHandler, HTTPServer
4+
import os
5+
import threading
6+
import webbrowser
7+
8+
from mistralai import Mistral
9+
from mistralai.extra.run.context import RunContext
10+
11+
from mistralai.extra.mcp.sse import (
12+
MCPClientSSE,
13+
SSEServerParams,
14+
)
15+
from mistralai.extra.mcp.auth import build_oauth_params
16+
17+
MODEL = "mistral-medium-latest"
18+
19+
CALLBACK_PORT = 16010
20+
21+
22+
# Use an official remote mcp server
23+
# you can find some at:
24+
# - https://mcpservers.org/remote-mcp-servers
25+
# - https://support.anthropic.com/en/articles/11176164-pre-built-integrations-using-remote-mcp
26+
# this one has auth: https://mcp.linear.app/sse
27+
28+
29+
def run_callback_server(callback_func):
30+
auth_response: dict = {"url": ""}
31+
32+
class OAuthCallbackHandler(BaseHTTPRequestHandler):
33+
server_version = "HTTP"
34+
code = None
35+
36+
def do_GET(self):
37+
if "/callback" in self.path:
38+
try:
39+
auth_response["url"] = self.path
40+
self.send_response(200)
41+
self.send_header("Content-type", "text/html")
42+
self.end_headers()
43+
callback_func()
44+
response_html = "<html><body><p>You may now close this window.</p></body></html>"
45+
self.wfile.write(response_html.encode())
46+
threading.Thread(target=httpd.shutdown).start()
47+
except Exception:
48+
self.send_response(500)
49+
self.end_headers()
50+
51+
server_address = ("localhost", CALLBACK_PORT)
52+
httpd = HTTPServer(server_address, OAuthCallbackHandler)
53+
threading.Thread(target=httpd.serve_forever).start()
54+
redirect_url = f"http://localhost:{CALLBACK_PORT}/oauth/callback"
55+
return httpd, redirect_url, auth_response
56+
57+
58+
async def main():
59+
api_key = os.environ["MISTRAL_API_KEY"]
60+
client = Mistral(api_key=api_key)
61+
62+
server_url = "https://mcp.linear.app/sse"
63+
64+
# set-up the client
65+
mcp_client = MCPClientSSE(
66+
sse_params=SSEServerParams(
67+
url=server_url,
68+
)
69+
)
70+
71+
callback_event = asyncio.Event()
72+
event_loop = asyncio.get_event_loop()
73+
74+
# check if auth is required
75+
if await mcp_client.requires_auth():
76+
# let's login
77+
httpd, redirect_url, auth_response = run_callback_server(
78+
callback_func=lambda: event_loop.call_soon_threadsafe(callback_event.set)
79+
)
80+
try:
81+
# First create the required oauth config, this means fetching the server metadata and registering a client
82+
oauth_params = await build_oauth_params(
83+
mcp_client.base_url, redirect_url=redirect_url
84+
)
85+
mcp_client.set_oauth_params(oauth_params=oauth_params)
86+
login_url, state = await mcp_client.get_auth_url_and_state(redirect_url)
87+
88+
# The oauth params like client_id, client_secret would generally be saved in some persistent storage.
89+
# The oauth state and token would be saved in a user session.
90+
91+
# wait for the user to complete the authentication process
92+
print("Please go to this URL and authorize the application:", login_url)
93+
webbrowser.open(login_url, new=2)
94+
await callback_event.wait()
95+
96+
# in a real app this would be your oauth2 callback route you would get the code from the query params,
97+
# verify the state, and then get the token
98+
# Here we recreate a new client with the saved params which and exchange the code for a token
99+
mcp_client = MCPClientSSE(
100+
sse_params=SSEServerParams(
101+
url=server_url,
102+
),
103+
oauth_params=oauth_params,
104+
)
105+
106+
token = await mcp_client.get_token_from_auth_response(
107+
auth_response["url"], redirect_url=redirect_url, state=state
108+
)
109+
mcp_client.set_auth_token(token)
110+
111+
except Exception as e:
112+
print(f"Error during authentication: {e}")
113+
finally:
114+
httpd.shutdown()
115+
httpd.server_close()
116+
117+
# Now it's possible to make a query to the mcp server as we would do without authentication
118+
async with RunContext(
119+
model=MODEL,
120+
) as run_ctx:
121+
# Add mcp client to the run context
122+
await run_ctx.register_mcp_client(mcp_client=mcp_client)
123+
124+
run_result = await client.beta.conversations.run_async(
125+
run_ctx=run_ctx,
126+
inputs="Tell me which projects do I have in my workspace?",
127+
)
128+
129+
print(f"Final Response: {run_result.output_as_text}")
130+
131+
132+
if __name__ == "__main__":
133+
asyncio.run(main())

0 commit comments

Comments
 (0)