If you have working Claude SDK code, you almost always change one import. The yielded message shapes match; ClaudeAgentOptions, Plugin, HookMatcher, create_sdk_mcp_server — all of it works.
import asyncio
from mantis_agent import query, tool
@tool
async def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"{city}: 67°F, partly cloudy"
async def main():
async for msg in query(
prompt="What's the weather in Lagos?",
options={"model": "qwen2.5:7b", "tools": [get_weather]},
):
if msg.type == "assistant":
for block in msg.message["content"]:
if block["type"] == "text":
print(block["text"])
asyncio.run(main())setup-local installs Ollama, pulls a CPU-friendly model, and smoke-tests the install.
Install, pull a local model, and run your first tool-calling loop.
How each part of the surface works, with runnable examples.
Every exported symbol, its signature, and what it returns.