ts/packages/providers/README.md
This directory contains various providers that implement the Composio SDK for different platforms and frameworks. Each provider provides a way to interact with the Composio Platform using the specific platform's conventions and requirements.
Composio SDK supports two types of providers, each with different modifier capabilities:
These providers only support schema modifiers for transforming tool schemas. They are suitable for simple integrations like OpenAI, Anthropic, etc.
Example implementation:
import { BaseNonAgenticProvider } from '@composio/core';
import type { Tool, SchemaModifiersParams } from '@composio/core';
export class NonAgenticProvider extends BaseNonAgenticProvider {
async wrapTool(toolSlug: string, tool: Tool, modifiers?: SchemaModifiersParams): Promise<Tool> {
// Apply schema modifiers if provided
if (modifiers?.schema) {
return modifiers.schema(toolSlug, tool);
}
return tool;
}
async getTools(): Promise<Tool[]> {
// Fetch tools from Composio API
const response = await this.client.getTools();
return response.data;
}
async getToolBySlug(slug: string, modifiers?: SchemaModifiersParams): Promise<Tool> {
// Fetch tool from Composio API
const response = await this.client.getToolBySlug(slug);
// Apply schema modifiers if provided
return this.wrapTool(slug, response.data, modifiers);
}
}
These providers support full modifier capabilities, making them suitable for complex integrations like Vercel, Langchain, etc. They support:
TransformToolSchemaModifierbeforeExecute: Transform input parameters before executionafterExecute: Transform output after executionbeforeExecute: Transform input parametersafterExecute: Transform outputExample implementation:
import { BaseAgenticProvider } from '@composio/core';
import type { Tool, ModifiersParams, ToolExecuteParams, ToolExecuteResponse } from '@composio/core';
export class AgenticProvider extends BaseAgenticProvider {
async wrapTool(toolSlug: string, tool: Tool, modifiers?: ModifiersParams): Promise<Tool> {
let wrappedTool = tool;
// Apply schema modifiers if provided
if (modifiers?.schema) {
wrappedTool = modifiers.schema(toolSlug, wrappedTool);
}
return wrappedTool;
}
async getTools(modifiers?: ModifiersParams): Promise<Tool[]> {
// Fetch tools from Composio API
const response = await this.client.getTools();
// Apply modifiers to each tool
return Promise.all(response.data.map(tool => this.wrapTool(tool.slug, tool, modifiers)));
}
async getToolBySlug(slug: string, modifiers?: ModifiersParams): Promise<Tool> {
// Fetch tool from Composio API
const response = await this.client.getToolBySlug(slug);
// Apply modifiers
return this.wrapTool(slug, response.data, modifiers);
}
async executeTool(
tool: Tool,
params: ToolExecuteParams,
modifiers?: ModifiersParams
): Promise<ToolExecuteResponse> {
let executeParams = params;
// Apply beforeExecute modifier if provided
if (modifiers?.beforeExecute) {
executeParams = modifiers.beforeExecute(tool.slug, executeParams);
}
// Execute the tool
const response = await this.client.executeTool(tool.slug, executeParams);
// Apply afterExecute modifier if provided
if (modifiers?.afterExecute) {
return modifiers.afterExecute(tool.slug, response.data);
}
return response.data;
}
}
To create a new provider, you can use the provided script:
# Create a non-agentic provider (default)
pnpm run create-provider <your-provider-name>
# Create an agentic provider
pnpm run create-provider <your-provider-name> --agentic
The script will create a new provider with the following structure:
<provider-name>/
├── src/
│ └── index.ts # Provider implementation
├── package.json # Package configuration
├── tsconfig.json # TypeScript configuration
├── tsup.config.ts # Build configuration
└── README.md # Provider documentation
Each provider must implement the following methods:
class NonAgenticProvider extends BaseNonAgenticProvider {
// Wrap a tool with schema modifiers
async wrapTool(toolSlug: string, tool: Tool, modifiers?: SchemaModifiersParams): Promise<Tool>;
// Get all available tools
async getTools(modifiers?: SchemaModifiersParams): Promise<Tool[]>;
// Get a specific tool by slug
async getToolBySlug(slug: string, modifiers?: SchemaModifiersParams): Promise<Tool>;
}
class AgenticProvider extends BaseAgenticProvider {
// Wrap a tool with modifiers
async wrapTool(toolSlug: string, tool: Tool, modifiers?: ModifiersParams): Promise<Tool>;
// Get all available tools
async getTools(modifiers?: ModifiersParams): Promise<Tool[]>;
// Get a specific tool by slug
async getToolBySlug(slug: string, modifiers?: ModifiersParams): Promise<Tool>;
// Execute a tool with modifiers
async executeTool(
tool: Tool,
params: ToolExecuteParams,
modifiers?: ModifiersParams
): Promise<ToolExecuteResponse>;
}
type SchemaModifiersParams = {
schema?: TransformToolSchemaModifier;
};
type TransformToolSchemaModifier = (toolSlug: string, tool: Tool) => Tool;
type ModifiersParams = {
schema?: TransformToolSchemaModifier;
beforeExecute?: beforeExecuteModifier;
afterExecute?: afterExecuteModifier;
};
type beforeExecuteModifier = (toolSlug: string, params: ToolExecuteParams) => ToolExecuteParams;
type afterExecuteModifier = (
toolSlug: string,
response: ToolExecuteResponse
) => ToolExecuteResponse;
Here's a complete example of a non-agentic provider implementation:
import { BaseNonAgenticProvider } from '@composio/core';
import type { Tool, SchemaModifiersParams } from '@composio/core';
export class OpenAIProvider extends BaseNonAgenticProvider {
async wrapTool(toolSlug: string, tool: Tool, modifiers?: SchemaModifiersParams): Promise<Tool> {
// Apply schema modifiers if provided
if (modifiers?.schema) {
return modifiers.schema(toolSlug, tool);
}
return tool;
}
async getTools(modifiers?: SchemaModifiersParams): Promise<Tool[]> {
// Fetch tools from Composio API
const response = await this.client.getTools();
// Apply modifiers to each tool
return Promise.all(response.data.map(tool => this.wrapTool(tool.slug, tool, modifiers)));
}
async getToolBySlug(slug: string, modifiers?: SchemaModifiersParams): Promise<Tool> {
// Fetch tool from Composio API
const response = await this.client.getToolBySlug(slug);
// Apply modifiers
return this.wrapTool(slug, response.data, modifiers);
}
}
And here's a complete example of an agentic provider implementation:
import { BaseAgenticProvider } from '@composio/core';
import type { Tool, ModifiersParams, ToolExecuteParams, ToolExecuteResponse } from '@composio/core';
export class VercelProvider extends BaseAgenticProvider {
async wrapTool(toolSlug: string, tool: Tool, modifiers?: ModifiersParams): Promise<Tool> {
let wrappedTool = tool;
// Apply schema modifiers if provided
if (modifiers?.schema) {
wrappedTool = modifiers.schema(toolSlug, wrappedTool);
}
return wrappedTool;
}
async getTools(modifiers?: ModifiersParams): Promise<Tool[]> {
// Fetch tools from Composio API
const response = await this.client.getTools();
// Apply modifiers to each tool
return Promise.all(response.data.map(tool => this.wrapTool(tool.slug, tool, modifiers)));
}
async getToolBySlug(slug: string, modifiers?: ModifiersParams): Promise<Tool> {
// Fetch tool from Composio API
const response = await this.client.getToolBySlug(slug);
// Apply modifiers
return this.wrapTool(slug, response.data, modifiers);
}
async executeTool(
tool: Tool,
params: ToolExecuteParams,
modifiers?: ModifiersParams
): Promise<ToolExecuteResponse> {
let executeParams = params;
// Apply beforeExecute modifier if provided
if (modifiers?.beforeExecute) {
executeParams = modifiers.beforeExecute(tool.slug, executeParams);
}
// Execute the tool
const response = await this.client.executeTool(tool.slug, executeParams);
// Apply afterExecute modifier if provided
if (modifiers?.afterExecute) {
return modifiers.afterExecute(tool.slug, response.data);
}
return response.data;
}
}
import { Composio } from '@composio/core';
import { OpenAIProvider } from '@composio/openai-provider';
import type { Tool } from '@composio/core';
const composio = new Composio({
apiKey: process.env.COMPOSIO_API_KEY,
provider: new OpenAIProvider(),
});
// Get a tool with schema modifiers
const tool = await composio.getToolBySlug('HACKERNEWS_SEARCH_POSTS', {
schema: (toolSlug: string, tool: Tool) => ({
...tool,
description: 'Search HackerNews posts with improved description',
inputParameters: {
...tool.inputParameters,
limit: {
type: 'number',
description: 'Maximum number of posts to return',
},
},
}),
});
import { Composio } from '@composio/core';
import { VercelProvider } from '@composio/vercel-provider';
import type { Tool, ToolExecuteParams, ToolExecuteResponse } from '@composio/core';
const composio = new Composio({
apiKey: process.env.COMPOSIO_API_KEY,
provider: new VercelProvider(),
});
// Get a tool with full modifier support
const tool = await composio.getToolBySlug('HACKERNEWS_SEARCH_POSTS', {
// Schema modifier
schema: (toolSlug: string, tool: Tool) => ({
...tool,
description: 'Search HackerNews posts with improved description',
inputParameters: {
...tool.inputParameters,
limit: {
type: 'number',
description: 'Maximum number of posts to return',
},
},
}),
// Execution modifiers
beforeExecute: (toolSlug: string, params: ToolExecuteParams) => ({
...params,
arguments: {
...params.arguments,
limit: Math.min((params.arguments?.limit as number) || 10, 100),
},
}),
afterExecute: (toolSlug: string, response: ToolExecuteResponse) => ({
...response,
data: {
...response.data,
posts: (response.data?.posts as any[]).map(post => ({
...post,
url: post.url || `https://news.ycombinator.com/item?id=${post.id}`,
})),
},
}),
});
// Execute the tool with execution modifiers
const result = await composio.provider.executeTool(
tool,
{
arguments: { query: 'AI', limit: 20 },
},
{
beforeExecute: (toolSlug: string, params: ToolExecuteParams) => ({
...params,
arguments: {
...params.arguments,
limit: Math.min((params.arguments?.limit as number) || 10, 100),
},
}),
afterExecute: (toolSlug: string, response: ToolExecuteResponse) => ({
...response,
data: {
...response.data,
posts: (response.data?.posts as any[]).map(post => ({
...post,
url: post.url || `https://news.ycombinator.com/item?id=${post.id}`,
})),
},
}),
}
);