mirror of
https://github.com/ComposioHQ/composio.git
synced 2026-09-22 11:46:35 +08:00
style(python): clean up example file spacing
Single blank lines between definitions, noqa for E302/E303 since this is an example file not a library module. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ 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
|
||||
@@ -16,26 +17,21 @@ import sys
|
||||
|
||||
from agents import Agent, Runner
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from composio import Composio
|
||||
from composio_openai_agents import OpenAIAgentsProvider
|
||||
|
||||
composio = Composio(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."""
|
||||
@@ -43,21 +39,16 @@ def get_user(input: UserLookupInput, ctx):
|
||||
if not user:
|
||||
raise ValueError(f'User "{input.user_id}" not found')
|
||||
return user
|
||||
|
||||
|
||||
# slug = GET_USER (from function name)
|
||||
# name = Get User (humanized)
|
||||
# description = "Look up an internal user by ID..." (from docstring)
|
||||
|
||||
|
||||
# ── 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",
|
||||
@@ -71,22 +62,17 @@ def greet(input: GreetInput, ctx):
|
||||
"casual": f"Yo {input.name}, what's up?",
|
||||
}
|
||||
return {"message": greetings.get(input.style, f"Hello {input.name}!")}
|
||||
|
||||
|
||||
# slug = GREET_V2 (overridden, not GREET)
|
||||
# name = Greeting Generator (overridden, not Greet)
|
||||
# description = "Generate a personalized..." (overridden, not docstring)
|
||||
|
||||
|
||||
# ── 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."""
|
||||
@@ -106,37 +92,30 @@ def create_draft(input: DraftInput, ctx):
|
||||
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}")
|
||||
@@ -152,7 +131,6 @@ async def run_test(prompt, test_name):
|
||||
},
|
||||
)
|
||||
tools = session.tools()
|
||||
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions=(
|
||||
@@ -172,7 +150,6 @@ async def run_test(prompt, test_name):
|
||||
print(f"\nERROR: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def main():
|
||||
tests = [
|
||||
("Look up user-2", "Standalone (inferred slug/name)"),
|
||||
@@ -180,14 +157,8 @@ async def main():
|
||||
("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 (extends_toolkit)",
|
||||
),
|
||||
(
|
||||
"Look up user-1, draft them an email saying hi, include weather in SF",
|
||||
"Mixed all paths",
|
||||
),
|
||||
('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 = []
|
||||
@@ -202,7 +173,6 @@ async def main():
|
||||
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")
|
||||
|
||||
Reference in New Issue
Block a user