Eve
The eve provider adapts Composio tools for the eve agent framework. With EveProvider registered, session.tools() returns eve-native defineTools, so an eve agent gets the Tool Router meta-tools and any preloaded custom toolkits from one call. The provider also ships a (ctx, next) hook interface to intercept, allow, deny, or rewrite meta-tool calls before the model sees the result.
The eve provider is experimental and currently ships from @composio/experimental for TypeScript
projects.
Usage
eve owns the agent loop and discovers tools from files, so you register the provider on the Composio client and expose the session's tools from a file under agent/tools/.
Install
npm install @composio/core @composio/experimental eve @ai-sdk/openaiThis walkthrough uses OpenAI directly as one concrete model provider. OpenAI is only an example: you can use any model provider supported by eve by installing its AI SDK package and configuring the corresponding credential.
Configure credentials
COMPOSIO_API_KEY=xxxxxxxxx
OPENAI_API_KEY=xxxxxxxxxCOMPOSIO_API_KEY authenticates Composio tools. OPENAI_API_KEY authenticates the model call
directly with OpenAI; this setup does not route through Vercel AI Gateway.
Configure the eve model
import { openai } from '@ai-sdk/openai';
import { defineAgent } from 'eve';
export default defineAgent({
model: openai('gpt-5.4-mini'),
});To use another provider, replace @ai-sdk/openai, OPENAI_API_KEY, and openai(...) with the
equivalent package, credential, and model factory supported by eve. Passing a provider model object
calls that provider directly; an eve string model ID such as openai/gpt-5.4-mini uses Vercel AI
Gateway instead.
Register the provider and create a session
import { Composio } from '@composio/core';
import { EveProvider } from '@composio/experimental/eve';
const composio = new Composio({ provider: new EveProvider() });
export const session = composio.sessions.create('user_123', {
toolkits: ['github', 'hackernews'], // optional: scope the session to specific apps
});Expose the tools to eve
import { defineComposioTools } from '@composio/experimental/eve';
import { session } from '../session';
export default defineComposioTools(session);defineComposioTools(session) returns a step.started dynamic resolver and memoizes session.tools(). It resolves per step because the wrapped execute holds a live function eve keeps only for step-scoped tools. The fetch is cached per resolved Composio session, and transient failures are retried on the next step. For a multi-user channel, pass a resolver instead: defineComposioTools((ctx) => sessionFor(ctx.session.auth.current?.principalId)).
Your agent now has the Tool Router meta-tools (COMPOSIO_SEARCH_TOOLS, COMPOSIO_MULTI_EXECUTE_TOOL, COMPOSIO_MANAGE_CONNECTIONS) plus any preloaded custom toolkits, with auth handled in chat.
eve's defineTool takes plain JSON Schema, so EveProvider passes Composio's inputParameters
straight through. It does not convert to a zod schema, which would trip eve's dynamic-tool
normalizer.
Hooks
Pass a hooks object to the constructor to wrap the Tool Router meta-tools. Each hook is (ctx, next): await next() runs the default behavior, returning a value replaces what the model sees, and ctx.deny(reason) blocks the call. ctx.request is mutable; ctx.context is read-only.
import { EveProvider } from '@composio/experimental/eve';
const provider = new EveProvider({
hooks: {
search: (ctx, next) => {
ctx.request.args.toolkits = ['github'];
return next();
},
remoteBash: async (ctx, next) => {
if (String(ctx.request.args.command ?? '').includes('rm -rf')) {
return ctx.deny('Destructive commands are blocked.');
}
return next();
},
onAuthLink: async (ctx, next) => {
await sendConnectionLinkToUser(ctx.url);
return next();
},
},
});Available hooks, each keyed on EveProviderHooks:
| Hook | Wraps |
|---|---|
search | COMPOSIO_SEARCH_TOOLS |
manageConnections | COMPOSIO_MANAGE_CONNECTIONS |
execute | COMPOSIO_MULTI_EXECUTE_TOOL and COMPOSIO_EXECUTE_TOOL |
remoteWorkbench | COMPOSIO_REMOTE_WORKBENCH |
remoteBash | COMPOSIO_REMOTE_BASH_TOOL |
onAuthLink | Any auth link found in a result |
ctx.request carries the meta-tool's raw { slug, args }, and ctx.deny is also exported as denyEveToolCall(reason).
Require approval
Map Composio tools onto eve's durable approval flow with needsApproval. The callback receives the original Composio tool plus eve's approval context:
import { EveProvider, requireApprovalForTools } from '@composio/experimental/eve';
const provider = new EveProvider({
needsApproval: requireApprovalForTools('LOCAL_IMESSAGE_SEND'),
});When this returns true, eve pauses before execution and asks the user to approve the call. requireApprovalForTools protects both direct calls and matching entries inside COMPOSIO_MULTI_EXECUTE_TOOL. Use an exact slug allowlist for side-effecting tools rather than approving every tool in a toolkit.
Next
iMessage on eve
A full example: a custom toolkit for local iMessage plus the eve provider, on one session.
What is a session?
How sessions scope users, tools, and auth, and how to reuse them across requests.