multillm-agentwrap
Agent wrapper provider for multillm - wraps chat providers with agentic capabilities.
Overview
The agentwrap provider allows you to use any chat provider (OpenAI, Google, Anthropic, etc.) with agentic capabilities including:
- Tool execution loop: Automatically executes tools and sends results back
- Conversation history management: Maintains context across tool calls
- Multi-turn interactions: Continues until task is complete or max turns reached
Installation
pip install multillm-agentwrap
Or with uv in a workspace:
uv add multillm-agentwrap
Usage
Basic Usage
import asyncio
import multillm
async def main():
client = multillm.Client()
# Wrap any chat model with agentic capabilities
async for msg in client.run("agentwrap/openai/gpt-4", "Hello!"):
if msg.type == "text":
print(msg.content)
asyncio.run(main())
With Tools
import asyncio
import multillm
# Define a custom tool
calculate_tool = multillm.Tool(
name="calculate",
description="Perform a calculation",
parameters={
"type": "object",
"properties": {
"expression": {"type": "string", "description": "Math expression"}
},
"required": ["expression"]
},
handler=lambda args: {"result": eval(args["expression"])}
)
async def main():
client = multillm.Client()
# Use with tools
async for msg in client.run(
"agentwrap/google/gemini-pro",
"What's 25 * 4?",
tools=[calculate_tool]
):
if msg.type == "text":
print(msg.content)
elif msg.type == "tool_use":
print(f" → Using tool: {msg.tool_name}")
elif msg.type == "tool_result":
print(f" ← Result: {msg.tool_result}")
asyncio.run(main())
With Options
from multillm import AgentOptions
async def main():
client = multillm.Client()
options = AgentOptions(
max_turns=5,
system_prompt="You are a helpful assistant.",
temperature=0.7
)
async for msg in client.run(
"agentwrap/anthropic/claude-3-5-sonnet-20241022",
"Explain quantum computing",
options=options
):
if msg.type == "text":
print(msg.content)
asyncio.run(main())
Supported Chat Providers
Any chat provider supported by multillm can be wrapped:
agentwrap/openai/gpt-4- OpenAI GPT-4agentwrap/openai/gpt-4-turbo- OpenAI GPT-4 Turboagentwrap/openai/gpt-3.5-turbo- OpenAI GPT-3.5 Turboagentwrap/google/gemini-pro- Google Gemini Proagentwrap/google/gemini-1.5-pro- Google Gemini 1.5 Proagentwrap/anthropic/claude-3-5-sonnet-20241022- Anthropic Claude 3.5 Sonnetagentwrap/openrouter/...- Any OpenRouter model
Model Format
The model string follows the format:
agentwrap/<chat-provider>/<model-name>
Where:
- agentwrap - The agent wrapper provider
- <chat-provider> - The chat provider to wrap (openai, google, anthropic, openrouter)
- <model-name> - The specific model from that provider
How It Works
- Receives prompt: User sends initial message
- Calls chat API: Uses the wrapped chat provider via
chat_complete() - Returns response: If no tool calls, returns text and stops
- Executes tools: If tool calls present, executes them with provided handlers
- Continues loop: Sends tool results back and gets next response
- Repeats: Steps 3-5 until no more tool calls or max turns reached
Configuration
Configure the wrapped provider via multillm config:
config = {
"openai": {"api_key": "sk-..."},
"google": {"api_key": "..."},
"agentwrap": {
"max_turns": 10 # Default max turns if not specified in options
}
}
client = multillm.Client(config)
Agent Options
All AgentOptions are supported:
from multillm import AgentOptions
options = AgentOptions(
system_prompt="Custom system prompt",
max_turns=15, # Max tool execution iterations
temperature=0.8, # Sampling temperature
max_tokens=2000, # Max tokens to generate
)
Message Types
The agent yields different message types during execution:
System Message
AgentMessage(
type="system",
content="Agentic session started",
)
Text Message
AgentMessage(
type="text",
content="The answer is 42",
raw=<original response object>
)
Tool Use Message
AgentMessage(
type="tool_use",
tool_name="calculate",
tool_input={"expression": "6*7"},
raw=<tool call object>
)
Tool Result Message
AgentMessage(
type="tool_result",
tool_name="calculate",
tool_result="42",
raw=<result dict>
)
Result Message
AgentMessage(
type="result",
content="Final answer",
)
Comparison with Native Agent Providers
AgentWrap (This Provider)
- ✅ Works with any chat provider
- ✅ Simple tool execution loop
- ✅ Full control over chat API settings
- ❌ No built-in tools (must provide custom tools)
- ❌ No file system access
- ❌ More basic agentic capabilities
Native Agent Providers (e.g., Claude)
- ✅ Advanced agentic capabilities
- ✅ Built-in tools (Bash, Read, Write, etc.)
- ✅ File system access
- ✅ Plan mode, interactive sessions
- ❌ Limited to specific providers
Use Cases
When to Use AgentWrap
- Different models: Want agentic behavior with OpenAI, Google, or other chat models
- Custom tools: Need specific tool implementations
- Simple workflows: Basic tool calling without file system access
- Cost optimization: Use cheaper chat models with agentic capabilities
When to Use Native Agents
- File operations: Need to read/write files, run commands
- Complex workflows: Multi-step tasks requiring planning
- Built-in tools: Want Bash, Read, Write, Grep, etc.
- Claude-specific: Need Claude's advanced agentic features
Limitations
- No built-in tools: Must provide all tools yourself (unlike Claude agent which has Bash, Read, Write, etc.)
- No file system access: Can't read/write files unless you implement those tools
- No interactive mode: Single-shot sessions only (no
run_interactive) - Tool handlers required: Tools must have Python handler functions
Examples
Calculator Agent
import asyncio
import multillm
calculate = multillm.Tool(
name="calculate",
description="Evaluate a mathematical expression",
parameters={
"type": "object",
"properties": {
"expression": {"type": "string"}
},
"required": ["expression"]
},
handler=lambda args: {"result": eval(args["expression"])}
)
async def main():
client = multillm.Client()
async for msg in client.run(
"agentwrap/openai/gpt-4",
"What's (125 + 75) * 3?",
tools=[calculate]
):
if msg.type == "text":
print(msg.content)
asyncio.run(main())
Multi-Tool Agent
import asyncio
import multillm
from datetime import datetime
get_time = multillm.Tool(
name="get_current_time",
description="Get the current time",
parameters={"type": "object", "properties": {}},
handler=lambda args: {"time": datetime.now().isoformat()}
)
get_weather = multillm.Tool(
name="get_weather",
description="Get weather for a location",
parameters={
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"]
},
handler=lambda args: {"temp": 72, "condition": "sunny"}
)
async def main():
client = multillm.Client()
async for msg in client.run(
"agentwrap/google/gemini-pro",
"What time is it and what's the weather in Tokyo?",
tools=[get_time, get_weather]
):
if msg.type == "text":
print(msg.content)
asyncio.run(main())
License
MIT
Contributing
Contributions welcome! Please see the main multillm repository for guidelines.
See Also
- multillm - Main library
- multillm-claude - Claude agent provider
