chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:38:34 +08:00
commit 0549b088a4
2405 changed files with 810255 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
from composio import Composio
composio = Composio()
# List all auth configs
auth_configs = composio.auth_configs.list()
print(auth_configs)
# Use composio managed auth
auth_config = composio.auth_configs.create(
toolkit="github",
options={
"type": "use_composio_managed_auth",
},
)
print(auth_config)
# Use custom auth
auth_config = composio.auth_configs.create(
toolkit="notion",
options={
"name": "Notion Auth",
"type": "use_custom_auth",
"auth_scheme": "OAUTH2",
"credentials": {
"client_id": "1234567890",
"client_secret": "1234567890",
"oauth_redirect_uri": "https://backend.composio.dev/api/v3/toolkits/auth/callback",
},
},
)
print(auth_config)
# When creating an auth config, you can check for required fields
required_fields = composio.toolkits.get_auth_config_creation_fields(
toolkit="NOTION",
auth_scheme="OAUTH2",
)
print(required_fields)
# Retrieve a specific auth config
auth_config_retrieved = composio.auth_configs.get(auth_config.id)
print(auth_config_retrieved)
# Fetch required input fields for auth config
toolkit = composio.toolkits.get(slug="notion")
required_input_fields = [
field.name for field in toolkit.auth_config_details or [] if field.mode
]
print(required_input_fields)
# Update an auth config
auth_config_updated = composio.auth_configs.update(
auth_config.id,
options={
"type": "custom",
"credentials": {
"client_id": "1234567890",
"client_secret": "1234567890",
},
"tool_access_config": {
"tools_for_connected_account_creation": ["github"],
},
},
)
print(auth_config_updated)
# Enable an auth config
composio.auth_configs.enable(auth_config.id)
print("Auth config enabled")
# Disable an auth config
composio.auth_configs.disable(auth_config.id)
print("Auth config disabled")
# Delete an auth config
composio.auth_configs.delete(auth_config.id)
print("Auth config deleted")
+54
View File
@@ -0,0 +1,54 @@
from composio import Composio
from composio.types import auth_scheme
composio = Composio()
# List all connected accounts
connected_accounts = composio.connected_accounts.list()
print(connected_accounts)
# Create a new connected account (OAuth)
connection_request = composio.connected_accounts.initiate(
user_id="1234567890",
auth_config_id="1234567890",
)
print(connection_request)
# Wait for the connection to be established (OAuth)
connected_account = connection_request.wait_for_connection()
print(connected_account)
# Create a new connected account (API Key)
connection_request = composio.connected_accounts.initiate(
user_id="1234567890",
auth_config_id="1234567890",
config=auth_scheme.api_key(
options={
"api_key": "1234567890",
},
),
)
print(connection_request)
# When creating a connected account, you can check for required fields
required_fields = composio.toolkits.get_connected_account_initiation_fields(
toolkit="NOTION",
auth_scheme="API_KEY",
)
print(required_fields)
# Retrieve a specific connected account
connected_account_retrieved = composio.connected_accounts.get(connected_account.id)
print(connected_account_retrieved)
# Disable a connected account
composio.connected_accounts.disable(connected_account.id)
print("Connected account disabled")
# Enable a connected account
composio.connected_accounts.enable(connected_account.id)
print("Connected account enabled")
# Delete a connected account
composio.connected_accounts.delete(connected_account.id)
print("Connected account deleted")
+200
View File
@@ -0,0 +1,200 @@
"""
Custom Tools — local tools + proxy execute with OpenAI Agents SDK.
Shows how to create custom tools that run in-process alongside
remote Composio tools. Includes all three patterns: standalone,
extension (Gmail proxy), and custom toolkit.
Usage:
COMPOSIO_API_KEY=... OPENAI_API_KEY=... python examples/custom_tools_agent_test.py
"""
# ruff: noqa: E302, E303
import asyncio
import base64
import os
import sys
from agents import Agent, Runner
from pydantic import BaseModel, Field
from composio import Composio
from composio_openai_agents import OpenAIAgentsProvider
composio = Composio(
base_url=os.environ.get("COMPOSIO_BASE_URL"),
provider=OpenAIAgentsProvider(),
)
# ── 1. Standalone tool — slug/name/description inferred from function ──
class UserLookupInput(BaseModel):
user_id: str = Field(description="User ID (e.g. user-1)")
USERS = {
"user-1": {"name": "Alice Johnson", "email": "alice@acme.com", "role": "admin"},
"user-2": {"name": "Bob Smith", "email": "bob@acme.com", "role": "developer"},
}
@composio.experimental.tool()
def get_user(input: UserLookupInput, ctx):
"""Look up an internal user by ID. Returns name, email, and role."""
user = USERS.get(input.user_id)
if not user:
raise ValueError(f'User "{input.user_id}" not found')
return user
# ── 2. Standalone tool with overrides ──────────────────────────────────
class GreetInput(BaseModel):
name: str = Field(description="Name to greet")
style: str = Field(default="friendly", description="Greeting style")
@composio.experimental.tool(
slug="GREET_V2",
name="Greeting Generator",
description="Generate a personalized greeting message in different styles.",
)
def greet(input: GreetInput, ctx):
"""This docstring is ignored because description= is set above."""
greetings = {
"friendly": f"Hey {input.name}! Great to see you!",
"formal": f"Dear {input.name}, I hope this message finds you well.",
"casual": f"Yo {input.name}, what's up?",
}
return {"message": greetings.get(input.style, f"Hello {input.name}!")}
# ── 3. Extension tool — inherits Gmail auth via ctx.proxy_execute() ────
class DraftInput(BaseModel):
to: str = Field(description="Recipient email address")
subject: str = Field(description="Email subject")
body: str = Field(description="Email body (plain text)")
@composio.experimental.tool(extends_toolkit="gmail")
def create_draft(input: DraftInput, ctx):
"""Create a real Gmail draft. Appears in the user's drafts folder."""
raw_msg = (
f"To: {input.to}\r\nSubject: {input.subject}\r\n"
f"Content-Type: text/plain; charset=UTF-8\r\n\r\n{input.body}"
)
raw = base64.urlsafe_b64encode(raw_msg.encode()).decode().rstrip("=")
res = ctx.proxy_execute(
toolkit="gmail",
endpoint="https://gmail.googleapis.com/gmail/v1/users/me/drafts",
method="POST",
body={"message": {"raw": raw}},
)
if res["status"] != 200:
raise RuntimeError(f"Gmail API error {res['status']}")
data = res["data"]
return {"draft_id": data["id"], "to": input.to, "subject": input.subject}
# ── 4. Custom toolkit — groups related tools under one namespace ───────
role_manager = composio.experimental.Toolkit(
slug="ROLE_MANAGER",
name="Role Manager",
description="Manage user roles in the system",
)
class SetRoleInput(BaseModel):
user_id: str = Field(description="User ID")
role: str = Field(description="New role (admin, developer, viewer)")
@role_manager.tool()
def set_role(input: SetRoleInput, ctx):
"""Set a user's role. Returns confirmation."""
return {"user_id": input.user_id, "role": input.role, "updated": True}
@role_manager.tool(name="List All Roles")
def list_roles(input: UserLookupInput, ctx):
"""List available roles for a user."""
return {"roles": ["admin", "developer", "viewer"], "current": "admin"}
# ── Agent ──────────────────────────────────────────────────────────────
async def run_test(prompt, test_name):
print(f"\n{'=' * 60}")
print(f"TEST: {test_name}")
print(f"{'=' * 60}")
session = composio.create(
user_id="default",
toolkits=["gmail", "weathermap"],
manage_connections=True,
experimental={
"custom_tools": [get_user, greet, create_draft],
"custom_toolkits": [role_manager],
},
)
tools = session.tools()
agent = Agent(
name="Assistant",
instructions=(
"You are a helpful assistant. Use Composio tools to execute tasks. "
"In MULTI_EXECUTE, always pass arguments inside the arguments field."
),
model="gpt-4.1-mini",
tools=tools,
)
print(f"> {prompt}\n")
try:
result = await Runner.run(agent, prompt, max_turns=25)
print(f"\nAgent: {result.final_output}")
return True
except Exception as e:
print(f"\nERROR: {e}")
return False
async def main():
tests = [
("Look up user-2", "Standalone (inferred slug/name)"),
("Generate a formal greeting for Alice", "Standalone (overridden slug/name)"),
("Set user-1 role to developer", "Toolkit tool"),
("Look up user-1 and set their role to viewer", "Mixed local tools"),
("What is the weather in Tokyo?", "Remote (weathermap)"),
(
'Draft an email to bob@acme.com with subject "Test" and body "Hello!"',
"Gmail proxy",
),
(
"Look up user-1, draft them an email saying hi, include weather in SF",
"Mixed all",
),
]
results = []
for prompt, name in tests:
ok = await run_test(prompt, name)
results.append((name, ok))
print(f"\n{'=' * 60}")
print("RESULTS")
print(f"{'=' * 60}")
for name, ok in results:
print(f" [{'PASS' if ok else 'FAIL'}] {name}")
print(f"\n{sum(1 for _, ok in results if ok)}/{len(results)} passed")
if __name__ == "__main__":
if not os.environ.get("OPENAI_API_KEY"):
print("Error: OPENAI_API_KEY env var required")
sys.exit(1)
asyncio.run(main())
@@ -0,0 +1,189 @@
"""
Advanced examples demonstrating the ToolRouter with all configuration options.
This example shows various ways to configure tool router sessions with
different parameters matching the TypeScript implementation.
"""
from composio import Composio
# Initialize Composio SDK
composio = Composio()
def example_with_specific_toolkits():
"""Create a session with specific toolkits enabled."""
print("=== Specific Toolkits Example ===")
session = composio.tool_router.create(
user_id="user_toolkit", toolkits=["github", "slack", "linear"]
)
print(f"Session ID: {session.session_id}")
print("Available toolkits: github, slack, linear")
return session
def example_with_disabled_toolkits():
"""Create a session with specific toolkits disabled."""
print("\n=== Disabled Toolkits Example ===")
session = composio.tool_router.create(
user_id="user_disabled", toolkits={"disabled": ["linear", "jira"]}
)
print(f"Session ID: {session.session_id}")
print("Disabled toolkits: linear, jira")
return session
def example_with_connection_management_config():
"""Create a session with connection management and callback URL."""
print("\n=== Connection Management with Callback Example ===")
session = composio.tool_router.create(
user_id="user_callback",
manage_connections={
"enabled": True,
"callback_uri": "https://myapp.com/oauth/callback",
},
)
print(f"Session ID: {session.session_id}")
print("Connection management enabled with custom callback")
return session
def example_with_auth_configs():
"""Create a session with specific auth configs for toolkits."""
print("\n=== Auth Configs Example ===")
session = composio.tool_router.create(
user_id="user_auth",
toolkits=["github", "slack"],
auth_configs={"github": "ac_github_123", "slack": "ac_slack_456"},
)
print(f"Session ID: {session.session_id}")
print("Auth configs: github → ac_github_123, slack → ac_slack_456")
return session
def example_with_connected_accounts():
"""Create a session with pre-configured connected accounts."""
print("\n=== Connected Accounts Example ===")
session = composio.tool_router.create(
user_id="user_connected",
toolkits=["github", "slack"],
connected_accounts={"github": "ca_github_789", "slack": "ca_slack_012"},
)
print(f"Session ID: {session.session_id}")
print("Connected accounts: github → ca_github_789, slack → ca_slack_012")
return session
def example_with_all_parameters():
"""Create a session with all parameters configured."""
print("\n=== All Parameters Example ===")
session = composio.tool_router.create(
user_id="user_complete",
toolkits=["github", "slack", "notion"],
manage_connections={
"enabled": True,
"callback_uri": "https://myapp.com/callback",
},
auth_configs={
"github": "ac_github_xyz",
"slack": "ac_slack_abc",
"notion": "ac_notion_def",
},
connected_accounts={"github": "ca_github_111", "slack": "ca_slack_222"},
)
print(f"✓ Session ID: {session.session_id}")
print("✓ Toolkits: github, slack, notion")
print("✓ Connection management: enabled with callback")
print("✓ Auth configs: configured for 3 toolkits")
print("✓ Connected accounts: 2 pre-configured")
return session
def example_minimal_vs_maximal():
"""Compare minimal and maximal configurations."""
print("\n=== Minimal vs Maximal Example ===")
# Minimal - just user ID
minimal_session = composio.tool_router.create(user_id="user_minimal")
print(f"Minimal session: {minimal_session.session_id}")
# Maximal - all options
maximal_session = composio.tool_router.create(
user_id="user_maximal",
toolkits=["github", "slack"],
manage_connections={"enabled": True, "callback_uri": "https://app.com/cb"},
auth_configs={"github": "ac_1", "slack": "ac_2"},
connected_accounts={"github": "ca_1"},
)
print(f"Maximal session: {maximal_session.session_id}")
return minimal_session, maximal_session
def example_type_safe_configuration():
"""Demonstrate type-safe configuration using TypedDict."""
print("\n=== Type-Safe Configuration Example ===")
from composio.core.models.tool_router import (
ToolRouterManageConnectionsConfig,
ToolRouterToolkitsDisabledConfig,
)
# Type-safe toolkit config
toolkit_config: ToolRouterToolkitsDisabledConfig = {"disabled": ["linear", "asana"]}
# Type-safe connection management config
connection_config: ToolRouterManageConnectionsConfig = {
"enabled": True,
"callback_uri": "https://secure.app.com/oauth",
"infer_scopes_from_tools": False,
}
session = composio.tool_router.create(
user_id="user_typesafe",
toolkits=toolkit_config,
manage_connections=connection_config,
)
print(f"Session ID: {session.session_id}")
print("✓ Type-safe configuration applied")
return session
if __name__ == "__main__":
"""Run all advanced examples."""
print("Composio ToolRouter Advanced Examples\n")
print("=" * 60)
try:
example_with_specific_toolkits()
example_with_disabled_toolkits()
example_with_connection_management_config()
example_with_auth_configs()
example_with_connected_accounts()
example_with_all_parameters()
example_minimal_vs_maximal()
example_type_safe_configuration()
print("\n" + "=" * 60)
print("✓ All advanced examples completed successfully!")
except Exception as e:
print(f"\n✗ Error running examples: {e}")
import traceback
traceback.print_exc()
@@ -0,0 +1,187 @@
"""
Example demonstrating the use of ToolRouter in Composio SDK.
This example shows how to create a tool router session for a user,
get provider-wrapped tools, and authorize toolkits.
"""
from composio import Composio
# Initialize Composio SDK
composio = Composio()
# Example 1: Create a basic tool router session
def basic_session_example():
"""Create a basic tool router session."""
print("=== Basic Session Example ===")
user_id = "user_123"
# Create a tool router session
session = composio.tool_router.create(user_id=user_id)
print(f"Session ID: {session.session_id}")
print(f"MCP Server Type: {session.mcp.type}")
print(f"MCP Server URL: {session.mcp.url}")
# Get tools wrapped for the provider
tools = session.tools()
print(
f"Number of tools available: {len(tools) if isinstance(tools, list) else 'N/A'}"
)
return session
# Example 2: Create a session with connection management
def session_with_connections_example():
"""Create a session with connection management enabled."""
print("\n=== Session with Connection Management ===")
user_id = "user_456"
# Create a tool router session with connection management
session = composio.tool_router.create(user_id=user_id, manage_connections=True)
print(f"Session ID: {session.session_id}")
print("Connection management enabled")
# Get tools (now includes COMPOSIO_MANAGE_CONNECTIONS)
tools = session.tools()
print(
f"Number of tools available: {len(tools) if isinstance(tools, list) else 'N/A'}"
)
return session
# Example 3: Authorize a toolkit
def authorize_toolkit_example():
"""Demonstrate toolkit authorization."""
print("\n=== Authorize Toolkit Example ===")
user_id = "user_789"
# Create a session
session = composio.tool_router.create(user_id=user_id)
# Authorize GitHub toolkit for the user
try:
connection_request = session.authorize("github")
print(f"Connection Request ID: {connection_request.id}")
print(f"Connection Status: {connection_request.status}")
if connection_request.redirect_url:
print(f"Redirect URL: {connection_request.redirect_url}")
print("User should visit this URL to complete authorization")
return connection_request
except Exception as e:
print(f"Error authorizing toolkit: {e}")
return None
# Example 4: Get toolkit connection states
def get_toolkits_example():
"""Get toolkit connection states for a session."""
print("\n=== Get Toolkits Example ===")
user_id = "user_101"
# Create a session
session = composio.tool_router.create(user_id=user_id)
# Get toolkit connection states
toolkits = session.toolkits()
print(f"Current toolkits: {toolkits}")
return toolkits
# Example 5: Full workflow with advanced configuration
def full_workflow_example():
"""Complete workflow with session, tools, and authorization."""
print("\n=== Full Workflow Example ===")
user_id = "user_full"
# 1. Create session with multiple configurations
session = composio.tool_router.create(
user_id=user_id,
toolkits=["github", "slack"],
manage_connections=True,
auth_configs={"github": "ac_demo_123"},
)
print(f"✓ Created session: {session.session_id}")
# 2. Get tools for the session
tools = session.tools()
print(f"✓ Retrieved {len(tools) if isinstance(tools, list) else 'N/A'} tools")
# 3. Check toolkits
toolkits_result = session.toolkits()
print(f"✓ Current toolkits: {len(toolkits_result.items)} toolkit(s)")
# 4. Authorize a toolkit if needed
try:
connection_request = session.authorize("slack")
print("✓ Initiated authorization for Slack")
if connection_request.redirect_url:
print(f" → Redirect URL: {connection_request.redirect_url}")
except Exception as e:
print(f"✗ Authorization error: {e}")
return session
# Example 6: Using with custom modifiers
def session_with_modifiers_example():
"""Create a session and use tools with custom modifiers."""
print("\n=== Session with Modifiers Example ===")
user_id = "user_modifiers"
# Create session
session = composio.tool_router.create(user_id=user_id)
# Get tools with custom modifiers
modifiers = {
# Add any custom modifiers here
# Example: timeout, custom headers, etc.
}
tools = session.tools(modifiers=modifiers if modifiers else None)
print(
f"✓ Retrieved {len(tools) if isinstance(tools, list) else 'N/A'} tools with modifiers"
)
return session
if __name__ == "__main__":
"""Run all examples."""
print("Composio ToolRouter Examples\n")
print("=" * 50)
# Run examples
try:
basic_session_example()
session_with_connections_example()
authorize_toolkit_example()
get_toolkits_example()
full_workflow_example()
session_with_modifiers_example()
print("\n" + "=" * 50)
print("✓ All examples completed successfully!")
except Exception as e:
print(f"\n✗ Error running examples: {e}")
import traceback
traceback.print_exc()
+26
View File
@@ -0,0 +1,26 @@
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
from composio import Composio
# Create a FastAPI app
app = FastAPI()
# Create a Composio client
composio = Composio()
@app.get("/authorize/{toolkit}")
def authorize_app(toolkit: str):
# retrieve the user id from your app
user_id = ""
# retrieve the auth config id from your app
auth_config_id = ""
# initiate the connection request
connection_request = composio.connected_accounts.initiate(
user_id=user_id,
auth_config_id=auth_config_id,
)
return RedirectResponse(url=connection_request.redirect_url) # type: ignore
+34
View File
@@ -0,0 +1,34 @@
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent
from composio import Composio
composio = Composio()
mcp_config = composio.mcp.create(
name="langchain-slack-mcp",
toolkits=[{"toolkit": "slack", "auth_config_id": "<auth-config-id>"}],
)
mcp_server = mcp_config.generate(user_id="<user-id>")
client = MultiServerMCPClient(
{
"composio": {
"url": mcp_server["url"],
"transport": "streamable_http",
}
}
)
async def langchain_mcp(message: str):
tools = await client.get_tools()
agent = create_react_agent("openai:gpt-4.1", tools)
response = await agent.ainvoke({"messages": message})
return response
mcp_response = asyncio.run(langchain_mcp("Show me 20 most used slack channels"))
+106
View File
@@ -0,0 +1,106 @@
import os
from composio import (
Composio,
after_execute,
before_execute,
before_file_upload,
schema_modifier,
)
from composio.types import Tool, ToolExecuteParams, ToolExecutionResponse
composio = Composio()
@before_execute(tools=["HACKERNEWS_GET_USER"])
def before_execute_modifier(
tool: str,
toolkit: str,
params: ToolExecuteParams,
) -> ToolExecuteParams:
# Perform modifications on the request
print("before_execute_modifier", tool, toolkit)
return params
@before_file_upload(tools=["HACKERNEWS_GET_USER"])
def rewrite_upload_path(path: str, tool: str, toolkit: str) -> str:
"""Optional: same pattern as before_execute; use for per-tool file path policy."""
return path
@after_execute(tools=["HACKERNEWS_GET_USER"])
def after_execute_modifier(
tool: str,
toolkit: str,
response: ToolExecutionResponse,
) -> ToolExecutionResponse:
return {
**response,
"data": {
"karama": response["data"]["karama"],
},
}
# execute tool
response = composio.tools.execute(
user_id="default",
slug="HACKERNEWS_GET_USER",
arguments={"username": "pg"},
modifiers=[
before_execute_modifier,
rewrite_upload_path,
after_execute_modifier,
],
)
print(response)
@schema_modifier(tools=["HACKERNEWS_GET_USER"])
def modify_schema(
tool: str,
toolkit: str,
schema: Tool,
) -> Tool:
# Perform modifications on the schema
print("modify_schema", tool, toolkit)
return schema
tools = composio.tools.get(
user_id="default",
slug="HACKERNEWS_GET_USER",
modifiers=[modify_schema],
)
print(tools)
@before_execute(toolkits=["NOTION"])
def add_custom_auth(
tool: str,
toolkit: str,
params: ToolExecuteParams,
) -> ToolExecuteParams:
if params["custom_auth_params"] is None:
params["custom_auth_params"] = {"parameters": []}
params["custom_auth_params"]["parameters"].append( # type: ignore
{
"name": "x-api-key",
"value": os.getenv("NOTION_API_KEY"),
"in": "header",
}
)
return params
result = composio.tools.execute(
user_id="default",
slug="NOTION_GET_DATABASES",
arguments={},
modifiers=[
add_custom_auth,
],
)
print(result)
+47
View File
@@ -0,0 +1,47 @@
"""
Tool Router - Authorization Example
This example demonstrates how to authorize a toolkit connection
within a Tool Router session.
"""
import os
from composio import Composio
# Initialize Composio
# Set COMPOSIO_API_KEY environment variable or pass api_key parameter
api_key = os.environ.get("COMPOSIO_API_KEY")
if not api_key:
print("Error: COMPOSIO_API_KEY environment variable not set")
print("Please set it using: export COMPOSIO_API_KEY='your_api_key'")
exit(1)
composio = Composio(api_key=api_key)
# Create a tool router session
session = composio.create(
user_id="user_123",
toolkits=["github", "gmail"],
)
print(f"Session created: {session.session_id}")
# Authorize a toolkit connection
# This initiates the OAuth flow and returns a connection request
connection_request = session.authorize("github")
print(f"\nConnection Request ID: {connection_request.id}")
print(f"Status: {connection_request.status}")
print(f"Redirect URL: {connection_request.redirect_url}")
print("\nPlease visit the URL above to authorize the connection.")
# Wait for the user to complete the authorization
# This will poll the API until the connection is active or timeout occurs
try:
connected_account = connection_request.wait_for_connection()
print("\n✅ Connection successful!")
print(f"Connected Account ID: {connected_account.id}")
print(f"Status: {connected_account.status}")
except Exception as e:
print(f"\n❌ Connection failed: {e}")
@@ -0,0 +1,33 @@
import asyncio
from claude_agent_sdk import ClaudeAgentOptions, query
from composio_claude_agent_sdk import ClaudeAgentSDKProvider
from composio import Composio
composio = Composio(provider=ClaudeAgentSDKProvider())
session = composio.create(
user_id="user_123",
)
async def main():
options = ClaudeAgentOptions(
system_prompt="You are an expert Python developer",
permission_mode="bypassPermissions",
mcp_servers={
"composio": {
"type": session.mcp.type,
"url": session.mcp.url,
"headers": session.mcp.headers,
}
},
)
async for message in query(
prompt="Fetch my last email and summarize it.", options=options
):
print(message)
asyncio.run(main())
@@ -0,0 +1,32 @@
from crewai import Agent, Crew, Task
from crewai.mcp import MCPServerHTTP
from composio import Composio
composio = Composio()
session = composio.create(
user_id="user_123",
)
agent = Agent(
role="Gmail agent",
goal="helps with gmail related queries",
backstory="You are a helpful assistant that can use the tools provided to you.",
mcps=[
MCPServerHTTP(
url=session.mcp.url,
headers=session.mcp.headers,
)
],
)
# Define task
task = Task(
description=("Find the last email and summarize it."),
expected_output="A summary of the last email including sender, subject, and key points.",
agent=agent,
)
my_crew = Crew(agents=[agent], tasks=[task])
result = my_crew.kickoff()
print(result)
@@ -0,0 +1,95 @@
"""
Tool Router direct_tools session preset with OpenAI Agents.
SESSION_PRESET_DIRECT_TOOLS is a shortcut for sessions where the full allowed
tool set is known upfront. It loads all tools allowed by the filters directly
into session.tools() and the MCP tool list.
Usage:
COMPOSIO_API_KEY=... OPENAI_API_KEY=... python examples/tool_router/direct_tools_preset.py
"""
import os
from agents import Agent, Runner
from composio_openai_agents import OpenAIAgentsProvider
from pydantic import BaseModel, Field
from composio import Composio, SESSION_PRESET_DIRECT_TOOLS
def require_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"Set {name} before running this example.")
return value
composio = Composio(
api_key=require_env("COMPOSIO_API_KEY"),
base_url=os.environ.get("COMPOSIO_BASE_URL"),
provider=OpenAIAgentsProvider(),
)
require_env("OPENAI_API_KEY")
class UserNoteInput(BaseModel):
username: str = Field(description="Hacker News username, for example pg")
hn_research = composio.experimental.Toolkit(
slug="HN_RESEARCH",
name="Hacker News research",
description="Internal research notes for Hacker News users.",
)
@hn_research.tool(
slug="GET_USER_NOTE",
name="Get Hacker News user note",
description="Return an internal research note for a Hacker News username.",
)
def get_user_note(input: UserNoteInput, ctx):
username = input.username.lower()
return {
"username": input.username,
"note": (
"Paul Graham; YC co-founder and essayist."
if username == "pg"
else f"No curated internal note for {input.username}."
),
}
session = composio.create(
user_id="direct-tools-example-user",
session_preset=SESSION_PRESET_DIRECT_TOOLS,
toolkits=["hackernews"],
tools={"hackernews": {"enable": ["HACKERNEWS_GET_USER"]}},
experimental={
"custom_toolkits": [hn_research],
},
)
tools = session.tools()
tool_names = [tool.name for tool in tools]
assert "HACKERNEWS_GET_USER" in tool_names
assert "LOCAL_HN_RESEARCH_GET_USER_NOTE" in tool_names
assert "COMPOSIO_SEARCH_TOOLS" not in tool_names
print("Direct tools exposed to the agent:")
for tool in tools:
print(f"- {tool.name}")
agent = Agent(
name="Direct Tools Demo Agent",
instructions="Use the provided tools to perform the task.",
model=os.environ.get("OPENAI_MODEL", "gpt-5.5"),
tools=tools,
)
result = Runner.run_sync(
agent,
'Look up user "pg" on Hacker News and include any internal research note.',
)
print(result.final_output)
+85
View File
@@ -0,0 +1,85 @@
"""
Example demonstrating the Tool Router session files API.
Shows how to list, upload, download, and delete files in a tool router
session's virtual filesystem. Also demonstrates search and execute.
Requires COMPOSIO_API_KEY and OPENAI_API_KEY to be set.
"""
import tempfile
from pathlib import Path
from composio import Composio
from composio_openai import OpenAIProvider
def main():
composio = Composio(provider=OpenAIProvider())
# Create a session
print("Creating tool router session...")
session = composio.tool_router.create(user_id="demo_files_user")
print(f" Session ID: {session.session_id}")
# Upload a file (from bytes)
print("\nUploading file (bytes)...")
remote = session.experimental.files.upload(
b'{"hello": "world"}',
remote_path="test_data.json",
mimetype="application/json",
)
print(f" Uploaded to: {remote.mount_relative_path}")
# List files
print("\nListing files...")
result = session.experimental.files.list(path="/")
print(f" Items: {len(result.items)}")
for item in result.items:
print(f" - {item.mount_relative_path} ({item.size} bytes)")
# Download the file
print("\nDownloading file...")
downloaded = session.experimental.files.download(remote.mount_relative_path)
content = downloaded.text()
print(f" Content: {content[:80]}...")
# Upload from local file
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
f.write("Hello from local file")
local_path = f.name
try:
print("\nUploading from local path...")
remote2 = session.experimental.files.upload(local_path)
print(f" Uploaded to: {remote2.mount_relative_path}")
finally:
Path(local_path).unlink(missing_ok=True)
# List again
print("\nListing files (after 2nd upload)...")
result2 = session.experimental.files.list(path="/")
print(f" Items: {len(result2.items)}")
for item in result2.items:
print(f" - {item.mount_relative_path} ({item.size} bytes)")
# Delete
print("\nDeleting test files...")
session.experimental.files.delete(remote.mount_relative_path)
session.experimental.files.delete(remote2.mount_relative_path)
print(" Deleted.")
# Search for tools
print("\nSearching for tools...")
search_result = session.search(query="send email")
print(f" Success: {search_result.success}, Results: {len(search_result.results)}")
if search_result.results:
r = search_result.results[0]
print(
f" First result: {r.primary_tool_slugs[:3] if r.primary_tool_slugs else []}"
)
print("\nAll files API operations succeeded.")
if __name__ == "__main__":
main()
@@ -0,0 +1,48 @@
import asyncio
from langchain.agents import create_agent
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_openai.chat_models import ChatOpenAI
from composio import Composio
composio = Composio()
session = composio.create(
user_id="user_123",
)
async def main():
try:
mcp_client = MultiServerMCPClient(
{
"composio": {
"transport": "streamable_http",
"url": session.mcp.url,
"headers": session.mcp.headers,
}
}
)
tools = await mcp_client.get_tools()
agent = create_agent(
tools=tools,
model=ChatOpenAI(model="gpt-4o"),
)
result = await agent.ainvoke(
{
"messages": [
{"role": "user", "content": "Fetch my last email and summarize?"}
]
}
)
print(result)
except Exception as e:
print(e)
if __name__ == "__main__":
asyncio.run(main())
@@ -0,0 +1,33 @@
from agents import Agent, HostedMCPTool, Runner
from composio import Composio
composio = Composio()
session = composio.create(
user_id="user_123",
)
print(session.mcp)
composio_mcp = HostedMCPTool(
tool_config={
"type": "mcp",
"server_label": "tool_router",
"server_url": session.mcp.url,
"require_approval": "never",
"headers": session.mcp.headers,
}
)
agent = Agent(
name="My Agent",
instructions="You are a helpful assistant that can use the tools provided to you.",
tools=[composio_mcp],
)
result = Runner.run_sync(
starting_agent=agent,
input="Find my last email and summarize it.",
)
print(result.final_output)
+170
View File
@@ -0,0 +1,170 @@
"""
Tool Router preload with OpenAI Agents.
Shows direct tool exposure for:
1. Composio tools via preload["tools"].
2. SDK custom tools via preload=True on the custom tool or toolkit.
3. A nested custom tool override with preload=False inside a preloaded toolkit.
Usage:
COMPOSIO_API_KEY=... OPENAI_API_KEY=... python examples/tool_router/preload.py
"""
import os
from agents import Agent, Runner
from composio_openai_agents import OpenAIAgentsProvider
from pydantic import BaseModel, Field
from composio import Composio
def require_env(name: str) -> str:
value = os.environ.get(name)
if not value:
raise RuntimeError(f"Set {name} before running this example.")
return value
class UserLookupInput(BaseModel):
user_id: str = Field(description="Internal user ID, for example user-1")
class TeamSearchInput(BaseModel):
team: str = Field(description="Team name to search for")
class AccountInput(BaseModel):
user_id: str = Field(description="Internal user ID")
INTERNAL_USERS = {
"user-1": {
"id": "user-1",
"name": "Ada Lovelace",
"email": "ada@example.com",
"team": "platform",
"plan": "enterprise",
},
"user-2": {
"id": "user-2",
"name": "Grace Hopper",
"email": "grace@example.com",
"team": "developer-tools",
"plan": "startup",
},
}
composio = Composio(
api_key=require_env("COMPOSIO_API_KEY"),
base_url=os.environ.get("COMPOSIO_BASE_URL"),
provider=OpenAIAgentsProvider(),
)
require_env("OPENAI_API_KEY")
@composio.experimental.tool(
slug="LOOKUP_INTERNAL_USER",
name="Lookup internal user",
description="Look up an internal demo user profile by user ID.",
preload=True,
)
def lookup_internal_user(input: UserLookupInput, ctx):
user = INTERNAL_USERS.get(input.user_id)
if not user:
raise ValueError(f'User "{input.user_id}" not found')
return user
@composio.experimental.tool(
slug="SEARCH_INTERNAL_USERS",
name="Search internal users",
description=(
"Search demo internal users by team. This custom tool is search-only "
"because preload is not enabled."
),
)
def search_internal_users(input: TeamSearchInput, ctx):
return {
"results": [
user for user in INTERNAL_USERS.values() if user["team"] == input.team
]
}
internal_admin = composio.experimental.Toolkit(
slug="INTERNAL_ADMIN",
name="Internal admin",
description="Demo internal administration tools.",
preload=True,
)
@internal_admin.tool(
slug="GET_ACCOUNT_HEALTH",
name="Get account health",
description="Return internal account health details for a user.",
)
def get_account_health(input: AccountInput, ctx):
return {
"user_id": input.user_id,
"health": "green",
"open_incidents": 0,
"renewal_risk": "low",
}
@internal_admin.tool(
slug="GET_ACCOUNT_AUDIT_LOG",
name="Get account audit log",
description=(
"Return internal account audit events. This overrides the toolkit "
"preload default and remains search-only."
),
preload=False,
)
def get_account_audit_log(input: AccountInput, ctx):
return {
"user_id": input.user_id,
"events": ["login", "settings_viewed"],
}
session = composio.create(
user_id="preload-example-user",
toolkits=["hackernews"],
tools={"hackernews": {"enable": ["HACKERNEWS_GET_USER"]}},
preload={"tools": ["HACKERNEWS_GET_USER"]},
manage_connections=False,
experimental={
"custom_tools": [lookup_internal_user, search_internal_users],
"custom_toolkits": [internal_admin],
},
)
tools = session.tools()
tool_names = [tool.name for tool in tools]
assert "HACKERNEWS_GET_USER" in tool_names
assert "LOCAL_LOOKUP_INTERNAL_USER" in tool_names
assert "LOCAL_INTERNAL_ADMIN_GET_ACCOUNT_HEALTH" in tool_names
assert "LOCAL_SEARCH_INTERNAL_USERS" not in tool_names
assert "LOCAL_INTERNAL_ADMIN_GET_ACCOUNT_AUDIT_LOG" not in tool_names
print("Direct tools exposed to the agent:")
for tool in tools:
print(f"- {tool.name}")
agent = Agent(
name="Preload Demo Agent",
instructions="Use the provided tools to perform the task.",
model=os.environ.get("OPENAI_MODEL", "gpt-5.5"),
tools=tools,
)
prompt = (
'Look up Hacker News user "pg", then look up internal user user-1 and '
"their account health. Summarize the useful facts."
)
result = Runner.run_sync(agent, prompt)
print(result.final_output)
@@ -0,0 +1,47 @@
"""
Tool Router - Session Update Example
Demonstrates using session.update() to modify a session's configuration
after creation — e.g. adding toolkits, changing workbench settings, or
updating preload config without creating a new session.
"""
import os
from composio import Composio
composio = Composio(base_url=os.environ.get("COMPOSIO_BASE_URL"))
# Create a session with gmail only
session = composio.create(
user_id="session-update-demo",
toolkits=["gmail"],
manage_connections=False,
)
print(f"Session created: {session.session_id}")
print(f"Preload: {session.preload}")
# Update: add github toolkit, enable workbench, and preload a tool
session.update(
toolkits={"enable": ["gmail", "github"]},
workbench={"enable": True, "sandbox_size": "medium"},
preload={"tools": ["GITHUB_CREATE_AN_ISSUE"]},
)
print("\nAfter update:")
print(f"Preload: {session.preload}")
# Update: disable workbench entirely
session.update(
workbench={"enable": False},
)
print("\nAfter disabling workbench: done")
# Update: clear manage_connections by passing None
session.update(
manage_connections=None,
)
print("\nAfter clearing manage_connections: done")
@@ -0,0 +1,73 @@
"""
Tool Router - MCP (Model Context Protocol) Example with OpenAI Agents
This example demonstrates how to use Tool Router with MCP servers and OpenAI Agents provider.
The MCP server provides a standardized way to access tools across different platforms,
and OpenAI Agents provider allows you to use these tools with OpenAI's agent framework.
"""
import asyncio
import os
from agents import Agent, HostedMCPTool, Runner
from composio_openai_agents import OpenAIAgentsProvider
from composio import Composio
async def main():
# Initialize Composio with OpenAI Agents provider
# Set COMPOSIO_API_KEY environment variable or pass api_key parameter
api_key = os.environ.get("COMPOSIO_API_KEY")
if not api_key:
print("Error: COMPOSIO_API_KEY environment variable not set")
print("Please set it using: export COMPOSIO_API_KEY='your_api_key'")
return
composio = Composio(api_key=api_key, provider=OpenAIAgentsProvider())
# Create a tool router session
session = composio.create(
user_id="user_123",
toolkits=["github", "gmail"],
)
mcpTool = HostedMCPTool(
tool_config={
"type": "mcp",
"server_label": "tool_router",
"server_url": session.mcp.url,
"require_approval": "never",
"headers": session.mcp.headers,
}
)
print(f"Session created: {session.session_id}")
print(f"MCP Server URL: {session.mcp.url}")
print(f"MCP Server Type: {session.mcp.type}")
# Create an agent with the tools from tool router
agent = Agent(
name="MCP Tool Router Agent",
instructions=(
"You are a helpful assistant that can use GitHub and Gmail tools "
"through the MCP (Model Context Protocol) server. "
"Help users with their GitHub and email tasks."
),
tools=[mcpTool],
)
# Run the agent with a sample task
print("\n--- Running Agent with Tool Router Tools ---")
result = await Runner.run(
starting_agent=agent,
input=(
"List my recent GitHub repositories and tell me about them. "
"If successful, respond with a summary of what you found."
),
)
print(f"\nAgent Result: {result.final_output}")
if __name__ == "__main__":
asyncio.run(main())
+27
View File
@@ -0,0 +1,27 @@
"""
Tool Router - Toolkits Example
This example demonstrates how to retrieve available toolkits
and their connection status in a Tool Router session.
"""
from composio import Composio
composio = Composio()
# Create a tool router session
# When manage_connections is enabled, tools for managing connections are included
session = composio.create(
user_id="pg-test-37ee710c-d5be-4775-91f2-a8e06b937d9b",
manage_connections=True,
)
print(f"Session created: {session.session_id}")
print(f"MCP Server: {session.mcp.url}")
# Get available toolkits for the session
# This returns information about all toolkits available to the user
toolkits = session.toolkits()
print("\nAvailable toolkits:")
print(toolkits)
+91
View File
@@ -0,0 +1,91 @@
"""
Tool Router - OpenAI Agents Example
This example demonstrates how to use Tool Router with OpenAI Agents framework.
OpenAI Agents provides a powerful way to build AI agents that can use tools
and execute complex workflows.
"""
import asyncio
from agents import Agent, Runner
from composio_openai_agents import OpenAIAgentsProvider
from composio import Composio, after_execute, before_execute
from composio.types import ToolExecuteParams, ToolExecutionResponse
async def main():
# Initialize Composio with OpenAI Agents provider
composio = Composio(provider=OpenAIAgentsProvider())
# Create a tool router session for a specific user
# This creates an isolated session with tools for the specified toolkits
session = composio.create(
user_id="user_123",
toolkits=["gmail"],
)
# Define logging modifiers to track tool calls
# Pass empty lists to apply to all tools
@before_execute(tools=[])
def log_before_execute(
tool: str,
toolkit: str,
params: ToolExecuteParams,
) -> ToolExecuteParams:
"""Log tool execution before it runs."""
print(f"🔧 Executing tool: {toolkit}.{tool}")
print(f" Arguments: {params.get('arguments', {})}")
return params
@after_execute(tools=[])
def log_after_execute(
tool: str,
toolkit: str,
response: ToolExecutionResponse,
) -> ToolExecutionResponse:
"""Log tool execution after it completes."""
print(f"✅ Completed tool: {toolkit}.{tool}")
if "data" in response:
print(f" Response data: {response['data']}")
return response
# Get tools wrapped for OpenAI Agents with logging modifiers
# These tools are ready to be used with the OpenAI Agents framework
tools = session.tools(modifiers=[log_before_execute, log_after_execute])
print(f"\nAvailable tools: {len(tools)}")
# Create an agent with the tools from the session
agent = Agent(
name="Gmail Assistant",
instructions=(
"You are a helpful assistant that helps users manage their "
"Gmail accounts. You can check emails, "
"send messages, and perform various actions on the Gmail platform."
),
tools=tools,
)
# Define the task
task = "Fetch my last email from gmail and summarize it"
print(f"\nTask: {task}")
print("\nAgent working...\n")
# Run the agent
result = await Runner.run(
starting_agent=agent,
input=task,
)
# Print the final output
print("\n" + "=" * 50)
print("RESULT:")
print("=" * 50)
print(result.final_output)
if __name__ == "__main__":
asyncio.run(main())
+19
View File
@@ -0,0 +1,19 @@
from composio import Composio
composio = Composio()
# List all toolkits
toolkits = composio.toolkits.get()
print(toolkits)
# Get a toolkit by slug
toolkit = composio.toolkits.get(slug="github")
print(toolkit)
# List all toolkits categories
categories = composio.toolkits.list_categories()
print(categories)
# Authorize a user to a toolkit
connection_request = composio.toolkits.authorize(user_id="123", toolkit="github")
print(connection_request)
+36
View File
@@ -0,0 +1,36 @@
from composio import Composio
composio = Composio()
# Get all tools by toolkit
tools = composio.tools.get(user_id="default", toolkits=["GITHUB"])
# Get all tools by search
tools = composio.tools.get(user_id="default", search="user")
# Get all tools by toolkit and search
tools = composio.tools.get(user_id="default", toolkits=["GITHUB"], search="star")
# execute tool
response = composio.tools.execute(
user_id="default",
slug="HACKERNEWS_GET_USER",
arguments={"username": "pg"},
version="20251023_00",
)
print(response)
# execute proxy call (github)
proxy_response = composio.tools.proxy(
endpoint="/repos/composiohq/composio/issues/1",
method="GET",
connected_account_id="ac_1234", # use connected account for github
parameters=[
{
"name": "Accept",
"value": "application/vnd.github.v3+json",
"type": "header",
},
],
)
print(proxy_response)
+95
View File
@@ -0,0 +1,95 @@
from composio import Composio
composio = Composio()
# List all triggers
triggers = composio.triggers.list()
print(triggers)
# List all active triggers
active_triggers = composio.triggers.list_active()
print(active_triggers)
# List all triggers enums
trigger_enums = composio.triggers.list_enum()
print(trigger_enums)
# Get a trigger by id
trigger = composio.triggers.get_type(slug="GITHUB_COMMIT_EVENT")
print(trigger)
# Create a trigger instance
instance = composio.triggers.create(
slug="GITHUB_COMMIT_EVENT",
connected_account_id="123",
trigger_config={
"repo": "composio",
"owner": "composiohq",
},
)
print(instance)
# Or use user ID
instance = composio.triggers.create(
slug="GITHUB_COMMIT_EVENT",
user_id="user@email.com",
trigger_config={
"repo": "composio",
"owner": "composiohq",
},
)
print(instance)
# Disable a trigger instance
disabled_instance = composio.triggers.disable(trigger_id="123")
print(disabled_instance)
# Enable a trigger instance
enabled_instance = composio.triggers.enable(trigger_id="123")
print(enabled_instance)
# Delete a trigger instance
deleted_instance = composio.triggers.delete(trigger_id="123")
print(deleted_instance)
# Verify a webhook (example in Flask)
# @app.route('/webhook', methods=['POST'])
# def webhook():
# try:
# result = composio.triggers.verify_webhook(
# id=request.headers.get('webhook-id', ''),
# payload=request.get_data(as_text=True),
# signature=request.headers.get('webhook-signature', ''),
# timestamp=request.headers.get('webhook-timestamp', ''),
# secret=os.environ['COMPOSIO_WEBHOOK_SECRET'],
# )
#
# # Result contains:
# # - version: WebhookVersion (V1, V2, or V3)
# # - payload: Normalized TriggerEvent
# # - raw_payload: Original parsed payload
# print(f"Webhook version: {result['version']}")
# print(f"Trigger: {result['payload']['trigger_slug']}")
# return 'OK', 200
# except WebhookSignatureVerificationError:
# return 'Unauthorized', 401
# Subscribe to a trigger
subscription = composio.triggers.subscribe()
# Define a callback functions
@subscription.handle(toolkit="GITHUB")
def handle_github_event(data):
print(data)
@subscription.handle(toolkit="SLACK")
def handle_slack_event(data):
print(data)
subscription.wait_forever()