Sessions vs Direct Execution
Sessions give your agent meta tools. The agent discovers which app tools to use, authenticates users, and executes tools at runtime through these meta tools.
Direct execution gives your code specific tool schemas. You decide which tools to fetch, manage auth yourself, and call tools.execute() directly.
Use sessions unless you need full control over which tools are available and when they run.
| Sessions | Direct execution | |
|---|---|---|
| Discovery | Agent finds tools at runtime and resolves dependencies automatically (e.g., if a tool needs an ID from another API, the agent finds that tool, runs it, and continues) | You select all tools upfront and need to account for any dependencies between them |
| Context cost | Only meta tools in context, app tools loaded on demand | Every tool schema you select is loaded upfront |
| Guidance | Search returns recommended steps and common pitfalls alongside schemas | You get tool schemas only |
| Memory | Meta tools share context across calls, storing discovered IDs and relationships | You manage state between calls |
| Auth | In-chat: agent prompts the user to connect when needed. Also supports manual | You build the auth flow with connect links |
| Workbench | Built in, large responses offloaded automatically | Not available |
| Human approval | You configure approval rules on the session. Harder to intercept individual calls since tools are discovered dynamically | You intercept before each call in your code |
| Latency | Multiple LLM turns (search, then execute) | Single call |
Sessions are configurable. You can enable or disable specific toolkits, set auth configs for white-labeled OAuth, and pin specific connected accounts. See Configuring Sessions for the full list.
Sessions
composio.create() returns meta tools:
from composio import Composio
from composio_openai import OpenAIProvider
composio = Composio(provider=OpenAIProvider())
session = composio.create(user_id="user_123")
tools = session.tools()
# Returns meta tools like COMPOSIO_SEARCH_TOOLS, COMPOSIO_MANAGE_CONNECTIONS,
# COMPOSIO_MULTI_EXECUTE_TOOL, COMPOSIO_REMOTE_WORKBENCH, etc.import { Composio } from '@composio/core';
import { OpenAIProvider } from '@composio/openai';
const composio = new Composio({
apiKey: process.env.COMPOSIO_API_KEY,
provider: new OpenAIProvider(),
});
const session = await composio.create("user_123");
const tools = await session.tools();
// Returns meta tools like COMPOSIO_SEARCH_TOOLS, COMPOSIO_MANAGE_CONNECTIONS,
// COMPOSIO_MULTI_EXECUTE_TOOL, COMPOSIO_REMOTE_WORKBENCH, etc.The agent discovers app tools through COMPOSIO_SEARCH_TOOLS:
User: "Create a GitHub issue for the login bug"
> Agent calls COMPOSIO_SEARCH_TOOLS({ query: "create github issue" })
Returns: GITHUB_CREATE_ISSUE schema + connection status
> Agent calls COMPOSIO_MANAGE_CONNECTIONS({ toolkits: ["github"] })
Returns: confirms connected (or auth link if not)
> Agent calls COMPOSIO_MULTI_EXECUTE_TOOL({ tool: "GITHUB_CREATE_ISSUE", args: {...} })
Returns: issue details
Agent: "Created issue #42 on your-org/your-repo"session.tools() returns meta tools (COMPOSIO_SEARCH_TOOLS, etc.), not app tools (GMAIL_SEND_EMAIL, etc.). The agent discovers app tools at runtime through search. For app tools directly, use direct execution.
Configuration
Restrict toolkits, set auth configs, pin connected accounts:
session = composio.create(
user_id="user_123",
toolkits=["github", "gmail"],
auth_configs={"github": "ac_my_config"},
connected_accounts={"gmail": "ca_work"},
)const session = await composio.create("user_123", {
toolkits: ["github", "gmail"],
authConfigs: { github: "ac_my_config" },
connectedAccounts: { gmail: "ca_work" },
});See Configuring Sessions for details.
Direct execution
Fetch tools by slug or toolkit. Pass them to your LLM or call tools.execute() without one.
from composio import Composio
from composio_openai import OpenAIProvider
composio = Composio(provider=OpenAIProvider())
# Fetch specific tools
tools = composio.tools.get(
user_id="user_123",
tools=["GITHUB_CREATE_ISSUE", "GITHUB_LIST_ISSUES"]
)
# Or by toolkit
tools = composio.tools.get(
user_id="user_123",
toolkits=["github"],
limit=50
)
# Execute without an LLM
result = composio.tools.execute(
"GITHUB_CREATE_ISSUE",
user_id="user_123",
arguments={"owner": "my-org", "repo": "my-repo", "title": "Fix login bug"}
)import { Composio } from '@composio/core';
import { OpenAIProvider } from '@composio/openai';
const composio = new Composio({
apiKey: process.env.COMPOSIO_API_KEY,
provider: new OpenAIProvider(),
});
// Fetch specific tools
const tools = await composio.tools.get("user_123", {
tools: ["GITHUB_CREATE_ISSUE", "GITHUB_LIST_ISSUES"],
});
// Or by toolkit
const allTools = await composio.tools.get("user_123", {
toolkits: ["github"],
limit: 50,
});
// Execute without an LLM
const result = await composio.tools.execute("GITHUB_CREATE_ISSUE", {
userId: "user_123",
arguments: { owner: "my-org", repo: "my-repo", title: "Fix login bug" },
});tools.get() returns 20 tools by default. When fetching from multiple toolkits (e.g., toolkits=["gmail", "github", "tavily"]), the limit may cut off tools from later toolkits. Increase limit or fetch each toolkit separately.
With direct execution, you manage auth configs, connect links, and toolkit versioning yourself.
Migrating
See the migration guide. Auth configs and connected accounts carry over.