ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Composio Providers API 详解:从 OpenAI 默认适配到自定义 Provider 构建

2026/9/11 22:58:05 拓冰建站 浏览量
Composio Providers API 详解:从 OpenAI 默认适配到自定义 Provider 构建 Composio Providers API 详解从 OpenAI 默认适配到自定义 Provider 构建【免费下载链接】composioComposio powers 1000 toolkits, tool search, context management, authentication, and a sandboxed workbench to help you build AI agents that turn intent into action.项目地址: https://gitcode.com/GitHub_Trending/co/composio导读Provider提供器/适配器是 Composio TypeScript SDK 的接口翻译层它将 Composio 平台上 1000 工具统一转换成特定 AI 平台OpenAI、Anthropic、LangChain 等原生可识别的工具格式并负责执行工具调用、串联鉴权与结果回传。本文以 ts/docs/api/providers.md 为核心结合 BaseProvider 源码 与 OpenAIProvider 源码系统讲解 Provider 的基类体系、默认 OpenAI Provider 的六大方法、如何自定义非 Agentic/Agentic Provider以及类型定义与 Modifier 机制。读完后你将能够初始化带 Provider 的 Composio 实例、在 Chat Completions 与 Assistants 两种模式下完整处理工具调用并针对任意 AI 框架编写属于自己的 Provider 适配器。Provider 架构总览Provider 在 Composio SDK 中承担三类职责工具格式转换把 Composio 内部的Tool对象转换为目标平台要求的工具描述如 OpenAI 的ChatCompletionTool工具执行编排通过executeTool方法统一调度鉴权、参数归一化与执行并把结果按平台要求封装平台专属集成为常见调用模式提供现成的辅助方法如handleToolCalls、waitAndHandleAssistantToolCalls并可选支持 MCP Server 响应格式转换。两类 Provider 的划分依据从 BaseProvider.ts 可以看到所有 Provider 都继承自抽象基类BaseProvider并分化为两条分支非 Agentic ProviderBaseNonAgenticProvider_isAgentic false只负责把工具格式化为目标模型 API 可识别的 schema工具循环tool loop由你的代码驱动通常需要自行调用executeToolCall/handleToolCalls等辅助方法。典型代表OpenAI、Anthropic、Google、CloudflareAgentic ProviderBaseAgenticProvider_isAgentic truewrapTool/wrapTools会额外接收一个ExecuteToolFn执行函数直接把可执行的能力烘焙进包装后的工具里工具循环由框架自身驱动。典型代表LangChain、LlamaIndex、Mastra、Vercel、OpenAI Agents。仓库 ts/packages/providers 下每个子包对应一个框架适配器composio/openai、composio/anthropic、composio/google、composio/langchain、composio/llamaindex、composio/mastra、composio/vercel、composio/openai-agents、composio/claude-agent-sdk、composio/cloudflare。在仓库根目录可用pnpm create:provider provider-name [--agentic]脚手架生成新的 Provider 包。基类与类型体系BaseComposioProviderBaseComposioProvider是组合了上述两条分支的联合类型SDK 用它做泛型推断type BaseComposioProviderTToolCollection, TTool, TMcpResponse McpServerGetResponse | BaseNonAgenticProviderTToolCollection, TTool, TMcpResponse | BaseAgenticProviderTToolCollection, TTool, TMcpResponse;注意源码中的第三个泛型参数TMcpResponse它用于可选的 MCP Server 响应格式转换见下文wrapMcpServerResponse。BaseNonAgenticProviderabstract class BaseNonAgenticProviderTToolCollection, TTool, TMcpResponse McpServerGetResponse extends BaseProviderTMcpResponse { override readonly _isAgentic false; // 把单个 Tool 包装成 Provider 专属格式 abstract wrapTool(tool: Tool): TTool; // 把一组 Tool 包装成 Provider 专属集合格式 abstract wrapTools(tools: Tool[]): TToolCollection; }BaseAgenticProviderabstract class BaseAgenticProviderTToolCollection, TTool, TMcpResponse extends BaseProviderTMcpResponse { override readonly _isAgentic true; // 额外接收 executeTool 函数用于把执行能力烘焙进包装后的工具 abstract wrapTool(tool: Tool, executeTool: ExecuteToolFn): TTool; abstract wrapTools(tools: Tool[], executeTool: ExecuteToolFn): TToolCollection; }BaseProvider 的公共能力无论哪条分支BaseProvider都提供了两个对实现者至关重要的成员源码executeTool(toolSlug, body, modifiers?)调用由核心 SDK 注入的全局执行函数与Tools类的execute方法一一对应内部负责鉴权、参数归一化与执行。若未注入执行函数会抛出ComposioGlobalExecuteToolFnNotSetError。文档建议实现 Provider 的辅助方法时一律走this.executeTool()不要自行实现执行逻辑wrapMcpServerResponse?(data)可选的 MCP URL 响应格式转换钩子当前标记为 deprecated未来将由wrapMcpServers取代。此外BaseProvider内部还实现了executeToolForTarget当执行目标是字符串userId时走直接工具 API当目标是ToolCallSessionTool Router 会话时会把执行委托给会话并拒绝混用直接执行选项——这一双目标执行模型使 Provider 既可用于普通工具也可用于 Tool Router 场景。默认的 OpenAI ProviderOpenAI Provider 是 Composio SDK 的默认 Provider随核心包一起发布无需单独安装。初始化Composio时若不指定provider则默认使用它import { Composio } from composio/core; // 默认即 OpenAI Provider const composio new Composio({ apiKey: your-api-key, });也可以显式指定import { Composio } from composio/core; import { OpenAIProvider } from composio/openai; const composio new Composio({ apiKey: your-api-key, provider: new OpenAIProvider(), });composio/openai包index.ts其实只是从核心包再导出的便利入口同时额外导出了面向 OpenAI Responses API 的OpenAIResponsesProvider见 OpenAIResponsesProvider.ts。OpenAIProvider 本身是一个BaseNonAgenticProviderOpenAiToolCollection, OpenAiTool, McpServerGetResponsename为openai用于遥测标识。它的wrapTool实现源码会把工具的slug作为函数名、description作为函数描述并对inputParameters调用deduplicateJsonSchemaRequiredArrays去重required数组后作为parameters最终包装成{ type: function, function: {...} }结构。方法速查方法输入返回适用场景wrapTool(tool)ToolOpenAI.ChatCompletionTool单个工具格式转换wrapTools(tools)Tool[]OpenAiToolCollection批量格式转换executeToolCall(userId, tool, options?, modifiers?)OpenAI 函数调用Promisestring执行单个工具调用handleToolCalls(userId, chatCompletion, options?, modifiers?)Chat CompletionChatCompletionToolMessageParam[]Chat Completions 模式handleAssistantMessage(userId, run, options?, modifiers?)Assistant runToolOutput[]Assistants 模式已弃用waitAndHandleAssistantToolCalls(userId, client, run, thread, options?, modifiers?)Assistant run threadPromiseRun非流式 AssistantswaitAndHandleAssistantStreamToolCalls(...)流式 run threadAsyncGeneratorAssistantStreamEvent流式 Assistants注源码中executeToolCall/handleToolCalls提供了重载——执行目标可以是stringuserId或ToolCallSessionTool Router 会话。另外handleAssistantMessage及两个waitAndHandleAssistant*方法在源码中标记为deprecatedAssistants API 已弃用官方建议改用 Chat Completions 或 Responses API文档保留它们用于兼容存量代码。executeToolCall执行单次工具调用const result await openaiProvider.executeToolCall( user123, toolCall, // OpenAI.ChatCompletionMessageToolCall { connectedAccountId: conn_abc123 }, // 可选指定已连接账户 { beforeExecute: ({ toolSlug, toolkitSlug, params }) params, afterExecute: ({ toolSlug, toolkitSlug, result }) result, } );底层实现源码先调用normalizeToolArguments处理 OpenAI 总是以 JSON 字符串序列化参数的问题兼容空串/对象形态的载荷再经由executeToolForTarget分发到直接工具 API 或 Tool Router 会话最终JSON.stringify(result)返回 JSON 字符串。handleToolCalls处理 Chat Completions 的工具调用const outputs await openaiProvider.handleToolCalls(user123, chatCompletion);实现要点源码只处理choices[0]当n 1时遍历所有 choice 会导致每个工具调用被重复执行、且tool_call_ids无法对应回单一助手回合遍历单个助手消息上的多个tool_callsOpenAI 默认支持并行工具调用跳过非function类型每个调用结果封装为{ role: tool, tool_call_id, content }可直接拼回下一次chat.completions.create的messages。实战Chat Completions 模式完整流程import { Composio } from composio/core; import { OpenAIProvider } from composio/openai; import OpenAI from openai; const composio new Composio({ apiKey: your-composio-api-key }); const openai new OpenAI({ apiKey: your-openai-api-key }); const openaiProvider composio.provider as OpenAIProvider; // 1. 获取已按 OpenAI 格式包装好的工具 const tools await composio.tools.get(default, { toolkits: [github], }); // tools[0] { type: function, function: { name: GITHUB_GET_REPO, ... } } // 2. 发起对话模型可能返回 tool_calls const completion await openai.chat.completions.create({ model: gpt-4, messages: [ { role: system, content: You are a helpful assistant with GitHub tools. }, { role: user, content: Find information about the Composio SDK repository }, ], tools, }); // 3. 存在工具调用时交给 Provider 执行 if (completion.choices[0].message.tool_calls) { const toolOutputs await openaiProvider.handleToolCalls( default, completion, { connectedAccountId: connected_account_123 } // 可选 ); // 4. 把工具结果拼回对话继续追问 const followupCompletion await openai.chat.completions.create({ model: gpt-4, messages: [ { role: system, content: You are a helpful assistant with GitHub tools. }, { role: user, content: Find information about the Composio SDK repository }, completion.choices[0].message, ...toolOutputs, ], tools, }); console.log(followupCompletion.choices[0].message.content); }实战OpenAI Assistants 模式非流式waitAndHandleAssistantToolCalls// 创建 assistant 时直接传入已包装的 Composio 工具 const assistant await openai.beta.assistants.create({ name: GitHub Assistant, instructions: You are a helpful assistant with GitHub tools., model: gpt-4, tools, }); const thread await openai.beta.threads.create(); await openai.beta.threads.messages.create(thread.id, { role: user, content: Find information about the Composio SDK repository, }); const run await openai.beta.threads.runs.create(thread.id, { assistant_id: assistant.id, }); // 阻塞等待 run 完成期间自动处理 requires_action 的工具调用并回传结果 const finalRun await openaiProvider.waitAndHandleAssistantToolCalls( default, openai, run, thread, { connectedAccountId: connected_account_123 } // 可选 ); const messages await openai.beta.threads.messages.list(thread.id); console.log(messages.data[0].content);底层实现源码循环轮询 run 状态queued/in_progress/requires_action处于requires_action时调用handleAssistantMessage取出工具输出并submitToolOutputs否则retrieve后等待 500ms 再查。流式waitAndHandleAssistantStreamToolCallsconst runStream await openai.beta.threads.runs.createAndStream(thread.id, { assistant_id: assistant.id, }); for await (const event of openaiProvider.waitAndHandleAssistantStreamToolCalls( default, openai, runStream, thread, { connectedAccountId: connected_account_123 } // 可选 )) { if (event.event thread.message.created) { console.log(New message created); } else if (event.event thread.message.delta) { console.log(Message update:, event.data.delta.content); } else if (event.event thread.run.requires_action) { console.log(Run requires action (tools being executed)); } else if (event.event thread.run.completed) { console.log(Run completed); } }实现源码是一个异步生成器逐事件 yield遇thread.run.requires_action时同步提交工具输出遇到completed/failed/cancelled/expired即结束随后拉取最终 run 状态兜底处理仍在等待中的requires_action。自定义 Provider非 Agentic 示例以文档中给出的 Anthropic 风格适配器为例import { BaseNonAgenticProvider, Tool } from composio/core; type AnthropicTool { name: string; description: string; parameters: Recordstring, unknown; }; type AnthropicToolCollection AnthropicTool[]; export class AnthropicProvider extends BaseNonAgenticProvider AnthropicToolCollection, AnthropicTool { // 必填provider 名称用于遥测标识 readonly name anthropic; override wrapTool(tool: Tool): AnthropicTool { return { name: tool.slug, description: tool.description || , parameters: tool.inputParameters || {}, }; } override wrapTools(tools: Tool[]): AnthropicToolCollection { return tools.map(tool this.wrapTool(tool)); } // 平台专属辅助方法借助 this.executeTool 完成执行 async handleToolUsage(userId: string, toolName: string, params: Recordstring, unknown) { const result await this.executeTool(toolName, { userId, arguments: params, }); return JSON.stringify(result); } }对照仓库中真实存在的 Anthropic Provider 实现它额外定义了AnthropicTool接口含input_schema与可选的cache_control并通过wrapMcpServerResponse把 MCP URL 响应转换为 Anthropic 的{ type: url, url, name }格式——非 Agentic Provider 可以基于executeTool自己实现executeToolCall/handleToolCalls等辅助方法真实实现可参考上文源码中的executeToolCall与handleToolCalls方法签名。使用自定义 Provider 初始化 SDKimport { Composio } from composio/core; import { AnthropicProvider } from ./providers/anthropic-provider; const composio new Composio({ apiKey: your-composio-api-key, provider: new AnthropicProvider(), }); const tools await composio.tools.get(default, { toolkits: [github], }); // 返回的工具将按 AnthropicProvider 的 wrapTool 格式输出自定义 ProviderAgentic 示例Agentic Provider 的wrapTool/wrapTools会收到ExecuteToolFn可以直接把执行函数烘焙进工具对象交给框架自行驱动工具循环。以 LangChain 风格的适配器为例import { BaseAgenticProvider, Tool, ExecuteToolFn } from composio/core; type LangchainTool { name: string; description: string; func: Function; }; type LangchainToolCollection { tools: LangchainTool[]; executor: (tool: LangchainTool, input: Recordstring, unknown) Promiseunknown; }; export class LangchainProvider extends BaseAgenticProviderLangchainToolCollection, LangchainTool { readonly name langchain; override wrapTool(tool: Tool, executeToolFn: ExecuteToolFn): LangchainTool { return { name: tool.slug, description: tool.description || , func: async (input: Recordstring, unknown) { const result await executeToolFn(tool.slug, input); return result.data; }, }; } override wrapTools(tools: Tool[], executeToolFn: ExecuteToolFn): LangchainToolCollection { const langchainTools tools.map(tool this.wrapTool(tool, executeToolFn)); return { tools: langchainTools, executor: async (tool, input) await tool.func(input), }; } }真实仓库中的 LangChain Provider 更进一步它用jsonSchemaToZodSchema把工具的 JSON Schema 转成 Zod schema构造DynamicStructuredTool实例并校验toolkit名称与inputParameters的存在性——可见格式转换 执行烘焙正是 Agentic Provider 的标准形态。其他真实 Agentic 适配器还包括 LlamaIndex、Mastra、Vercel 与 OpenAI Agents。核心类型定义以下类型均定义于核心包ExecuteToolFnOptions见 provider.types.tsModifier 类型见 modifiers.types.ts// 工具执行函数注入给 Agentic Provider 使用 type ExecuteToolFn ( toolSlug: string, input: Recordstring, unknown ) PromiseToolExecuteResponse; // 执行选项指定已连接账户或自定义认证参数 interface ExecuteToolFnOptions { connectedAccountId?: string; customAuthParams?: CustomAuthParams; customConnectionData?: CustomConnectionData; } // 执行修饰器请求/响应两阶段的钩子 interface ExecuteToolModifiers { beforeExecute?: beforeExecuteModifier; afterExecute?: afterExecuteModifier; } // Schema 转换修饰器在工具暴露给消费者之前改写其定义 type TransformToolSchemaModifier (context: { toolSlug: string; toolkitSlug: string; schema: Tool; }) Tool | PromiseTool; // 执行前钩子改写即将传入工具的参数 type beforeExecuteModifier (context: { toolSlug: string; toolkitSlug: string; params: ToolExecuteParams; }) PromiseToolExecuteParams | ToolExecuteParams; // 执行后钩子改写工具返回的结果 type afterExecuteModifier (context: { toolSlug: string; toolkitSlug: string; result: ToolExecuteResponse; }) PromiseToolExecuteResponse | ToolExecuteResponse;需要留意文档与源码的两处差异以源码为准文档中的beforeExecuteModifier/afterExecuteModifier写的是位置参数形式而 modifiers.types.ts 中的实际签名为单个 context 对象解构形式另外ExecuteToolFnOptions在源码中多了一个customConnectionData字段。Modifier 与 Schema 转换的组合用法composio.tools.get支持传入 schema 转换函数在工具被 Provider 包装之前改写工具定义例如给工具打上自定义属性// Get tools with filters const githubTools await composio.tools.getRawComposioTools({ toolkits: [github], }); // Get tools with schema transformation const tools await composio.tools.getRawComposioTools({}, (toolSlug, toolkitSlug, tool) { // Add custom properties to tool schema return { ...tool, customProperty: value }; });与 OpenAI Provider 配合的完整 Modifier 用法来自 ts/docs/providers/openai.mdconst tools await composio.tools.get( default, { toolkits: [github] }, { // 改写工具 schema例如裁剪过长的描述 modifySchema: (toolSlug, toolkitSlug, tool) { if (tool.description tool.description.length 100) { tool.description tool.description.substring(0, 100) ...; } return tool; }, // 执行前钩子记录日志、注入参数 beforeExecute: ({ toolSlug, toolkitSlug, params }) { console.log(Executing ${toolSlug} tool); return params; }, // 执行后钩子重塑返回数据 afterExecute: ({ toolSlug, toolkitSlug, result }) { if (result.successful toolSlug GITHUB_GET_REPO) { result.data { name: result.data.name, description: result.data.description, stars: result.data.stargazers_count, forks: result.data.forks_count, url: result.data.html_url, }; } return result; }, } );在 modifiers.types.ts 中ProviderOptionsTProvider会根据 Provider 是否为 Agentic 自动解析为AgenticToolOptions含执行修饰器或ToolOptions仅 schema 转换实现按 Provider 类型提供差异化的配置能力。最佳实践与实现要点综合 ts/docs/api/providers.md、ts/docs/advanced/custom-providers.md 与源码实现编写高质量 Provider 时应注意保持 Provider 职责单一每个 Provider 只适配一个具体 AI 平台/框架统一走this.executeTool()不要自行实现鉴权与执行逻辑核心注入的全局执行函数已统一处理鉴权、参数归一化与版本检查非 Agentic Provider 提供便捷辅助方法按平台惯例实现executeToolCall、handleToolCalls等真实 Anthropic 适配器即如此并透传ExecuteToolFnOptionsconnectedAccountId / customAuthParams / customConnectionData以正确处理连接账户与自定义认证Agentic Provider 注意错误传递在烘焙的execute/func中检查result.successful失败时抛出带result.error信息的异常参考 LangChain 真实实现善用泛型保证类型安全用 TypeScript 泛型参数约束工具与工具集合类型按需实现wrapMcpServerResponse当目标平台需要自定义 MCP Server 响应格式时实现之设置有意义的name该值用于遥测与调试标识优雅处理错误在辅助方法中捕获并转换工具执行错误遵循平台约定命名与结构尽量贴合目标平台的惯例如 Anthropic 的input_schema、LangChain 的 Zod schema。进阶Provider 状态、组合与真实适配器维护 Provider 状态Provider 实例可以持有自己的状态与配置例如在wrapTool中做缓存或按配置改写工具class ProviderWithContext extends BaseNonAgenticProviderMyToolCollection, MyTool { readonly name provider-with-context; private cache new Mapstring, any(); private config: any; constructor(config: any) { super(); this.config config; } override wrapTool(tool: Tool): MyTool { const customizedTool { name: tool.slug, description: this.config.addDescriptionPrefix ? [${this.config.descriptionPrefix}] ${tool.description} : tool.description, }; this.cache.set(tool.slug, customizedTool); return customizedTool; } override wrapTools(tools: Tool[]): MyToolCollection { return tools.map(tool this.wrapTool(tool)); } getTool(slug: string): MyTool | undefined { return this.cache.get(slug); } }组合已有 Provider也可以继承现成 Provider 做能力增强例如给OpenAIProvider增加调用计数与重试逻辑真实场景中可通过 ts/packages/core/test/provider/provider.test.ts 了解其行为契约import { OpenAIProvider } from composio/openai; export class EnhancedOpenAIProvider extends OpenAIProvider { private analytics { toolCalls: 0, errors: 0 }; override async executeToolCall(userId, tool, options, modifiers) { this.analytics.toolCalls; try { return await super.executeToolCall(userId, tool, options, modifiers); } catch (error) { this.analytics.errors; throw error; } } async executeWithRetry(userId, tool, options, modifiers, maxRetries 3) { let attempts 0; let lastError; while (attempts maxRetries) { try { return await this.executeToolCall(userId, tool, options, modifiers); } catch (error) { lastError error; attempts; await new Promise(resolve setTimeout(resolve, 1000 * attempts)); } } throw lastError; } }仓库中的真实 Provider 一览想深入研读完整实现可直接阅读 ts/packages/providers 下的适配器源码及其测试OpenAIopenai/src/index.ts核心实现位于 core/src/provider/OpenAIProvider.ts、openai/src/OpenAIResponsesProvider.tsAnthropicanthropic/src/index.ts含sanitize-keys.ts参数键清洗LangChainlangchain/src/index.tsLlamaIndexllamaindex/src/index.tsMastramastra/src/index.tsVercelvercel/src/index.tsGooglegoogle/src/index.tsOpenAI Agentsopenai-agents/src/index.tsCloudflarecloudflare/src/index.ts各包均带配套测试如 openai/test/openai.test.ts、anthropic/test/anthropic.test.ts覆盖包装与执行处理两条路径可作为自定义 Provider 的参考蓝本。核心层行为测试见 core/test/provider/provider.test.ts。总结Provider 是 Composio SDK 面向多框架的扩展点BaseNonAgenticProvider适合你的代码驱动工具循环的裸模型 APIOpenAI、AnthropicBaseAgenticProvider适合框架驱动工具循环的 Agent 框架LangChain、LlamaIndex、Mastra 等。默认的 OpenAI Provider 已覆盖 Chat Completions、Assistants 与流式三种主流调用模式而通过继承基类、实现wrapTool/wrapTools、复用executeTool即可在数十分钟内为任意 AI 平台编写出类型安全、可执行、可遥测的自定义适配器——这正是 Composio 1000 工具得以无缝接入各家 Agent 生态的架构基石。【免费下载链接】composioComposio powers 1000 toolkits, tool search, context management, authentication, and a sandboxed workbench to help you build AI agents that turn intent into action.项目地址: https://gitcode.com/GitHub_Trending/co/composio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考