Experimental

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/openai

This 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

.env.local
COMPOSIO_API_KEY=xxxxxxxxx
OPENAI_API_KEY=xxxxxxxxx

COMPOSIO_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

agent/agent.ts
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

agent/session.ts
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

agent/tools/composio.ts
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:

HookWraps
searchCOMPOSIO_SEARCH_TOOLS
manageConnectionsCOMPOSIO_MANAGE_CONNECTIONS
executeCOMPOSIO_MULTI_EXECUTE_TOOL and COMPOSIO_EXECUTE_TOOL
remoteWorkbenchCOMPOSIO_REMOTE_WORKBENCH
remoteBashCOMPOSIO_REMOTE_BASH_TOOL
onAuthLinkAny 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.