UNPKG

@composio/core

Version:

![Composio Banner](https://github.com/user-attachments/assets/9ba0e9c1-85a4-4b51-ae60-f9fe7992e819)

744 lines (732 loc) 31.6 kB
import { t as ComposioError$1 } from "./ComposioError-ChkSdxqU.mjs"; import { APIError } from "@composio/client"; import { ZodError, z as z$1 } from "zod/v3"; import * as zodToJsonSchema from "zod-to-json-schema"; //#region src/errors/ConnectedAccountsErrors.ts const ConnectedAccountErrorCodes = { CONNECTED_ACCOUNT_NOT_FOUND: "CONNECTED_ACCOUNT_NOT_FOUND", MULTIPLE_CONNECTED_ACCOUNTS: "MULTIPLE_CONNECTED_ACCOUNTS", FAILED_TO_CREATE_CONNECTED_ACCOUNT_LINK: "FAILED_TO_CREATE_CONNECTED_ACCOUNT_LINK" }; var ComposioConnectedAccountNotFoundError = class extends ComposioError$1 { constructor(message = "Connected account not found", options = {}) { super(message, { ...options, code: ConnectedAccountErrorCodes.CONNECTED_ACCOUNT_NOT_FOUND, statusCode: 404, possibleFixes: options.possibleFixes || ["Ensure the connected account exists and is active in your Composio dashboard"] }); this.name = "ComposioConnectedAccountNotFoundError"; } }; var ComposioMultipleConnectedAccountsError = class extends ComposioError$1 { constructor(message = "Multiple connected accounts found", options = {}) { super(message, { ...options, code: ConnectedAccountErrorCodes.MULTIPLE_CONNECTED_ACCOUNTS, possibleFixes: options.possibleFixes || ["Use the allowMultiple flag to allow multiple connected accounts per user for an auth config"] }); this.name = "ComposioMultipleConnectedAccountsError"; } }; var ComposioFailedToCreateConnectedAccountLink = class extends ComposioError$1 { constructor(message = "Failed to create connected account link", options = {}) { super(message, { ...options, code: ConnectedAccountErrorCodes.FAILED_TO_CREATE_CONNECTED_ACCOUNT_LINK }); this.name = "ComposioFailedToCreateConnectedAccountLink"; } }; //#endregion //#region src/errors/ToolErrors.ts const ToolErrorCodes = { TOOLSET_NOT_DEFINED: "TOOLSET_NOT_DEFINED", TOOL_NOT_FOUND: "TOOL_NOT_FOUND", INVALID_MODIFIER: "INVALID_MODIFIER", CUSTOM_TOOLS_NOT_INITIALIZED: "CUSTOM_TOOLS_NOT_INITIALIZED", TOOL_EXECUTION_ERROR: "TOOL_EXECUTION_ERROR", INVALID_EXECUTE_FUNCTION: "INVALID_EXECUTE_FUNCTION", GLOBAL_EXECUTE_TOOL_FN_NOT_SET: "GLOBAL_EXECUTE_TOOL_FN_NOT_SET", TOOL_VERSION_REQUIRED: "TOOL_VERSION_REQUIRED" }; var ComposioProviderNotDefinedError = class extends ComposioError$1 { constructor(message = "Provider not defined", options = {}) { super(message, { ...options, code: ToolErrorCodes.TOOLSET_NOT_DEFINED, possibleFixes: options.possibleFixes || ["Ensure that the provider is defined in the Composio project and passed into the tool instance"] }); this.name = "ComposioProviderNotDefinedError"; } }; var ComposioToolNotFoundError = class extends ComposioError$1 { constructor(message = "Tool not found", options = {}) { super(message, { ...options, code: ToolErrorCodes.TOOL_NOT_FOUND, possibleFixes: options.possibleFixes || ["Ensure the tool slug is correct and exists in the Composio project"] }); this.name = "ComposioToolNotFoundError"; } }; var ComposioInvalidModifierError = class extends ComposioError$1 { constructor(message = "Invalid modifier", options = {}) { super(message, { ...options, code: ToolErrorCodes.INVALID_MODIFIER, possibleFixes: options.possibleFixes || ["Ensure the modifier is a function and returns a valid result"] }); this.name = "ComposioInvalidModifierError"; } }; var ComposioCustomToolsNotInitializedError = class extends ComposioError$1 { constructor(message = "Custom tools not initialized", options = {}) { super(message, { ...options, code: ToolErrorCodes.CUSTOM_TOOLS_NOT_INITIALIZED, possibleFixes: options.possibleFixes || ["Ensure the custom tools class is initialized in the Tools instance"] }); this.name = "ComposioCustomToolsNotInitializedError"; } }; var ComposioToolExecutionError = class extends ComposioError$1 { constructor(message = "Tool execution error", options = {}) { super(message, { ...options, code: options.code || ToolErrorCodes.TOOL_EXECUTION_ERROR, cause: options.cause, possibleFixes: options.possibleFixes || ["Ensure the tool is correctly configured and the input is valid", "Ensure the userId is correct and has an active connected account for the user in case of non NoAuth toolkits"] }); this.name = "ComposioToolExecutionError"; } }; var ComposioInvalidExecuteFunctionError = class extends ComposioError$1 { constructor(message = "Invalid execute function", options = {}) { super(message, { ...options, code: ToolErrorCodes.INVALID_EXECUTE_FUNCTION, possibleFixes: options.possibleFixes || ["Ensure the execute function is a valid function and returns a valid result"] }); this.name = "ComposioInvalidExecuteFunctionError"; } }; var ComposioGlobalExecuteToolFnNotSetError = class extends ComposioError$1 { constructor(message = "Global execute tool function not set", options = {}) { super(message, { ...options, code: ToolErrorCodes.GLOBAL_EXECUTE_TOOL_FN_NOT_SET, possibleFixes: options.possibleFixes || ["Ensure the global execute tool function is set in the provider"] }); this.name = "ComposioGlobalExecuteToolFnNotSetError"; } }; /** * Error thrown when toolkit version is not specified for manual tool execution. * * This error is thrown when attempting to execute a tool manually (via `tools.execute()`) * and the resolved version is "latest" without `dangerouslySkipVersionCheck` set to true. * * **Why this error exists:** * Using "latest" version in manual execution can lead to unexpected behavior when new * toolkit versions are released, potentially breaking your application. For production * use, it's recommended to pin specific toolkit versions. * * **How to fix:** * 1. Specify a concrete version in the execute call * 2. Configure toolkit versions at SDK initialization * 3. Set toolkit version via environment variable * 4. Use dangerouslySkipVersionCheck (not recommended for production) * * @example ❌ This will throw ComposioToolVersionRequiredError if toolkitVersions is 'latest' * ```typescript * await composio.tools.execute('GITHUB_GET_REPOS', { * userId: 'default', * arguments: { owner: 'composio' } * }); * ``` * * @example ✅ Fix 1: Pass specific version in execute call * ```typescript * await composio.tools.execute('GITHUB_GET_REPOS', { * userId: 'default', * version: '20250909_00', * arguments: { owner: 'composio' } * }); * ``` * * @example ✅ Fix 2: Configure toolkit versions at SDK level * ```typescript * const composio = new Composio({ * toolkitVersions: { github: '20250909_00' } * }); * await composio.tools.execute('GITHUB_GET_REPOS', { * userId: 'default', * arguments: { owner: 'composio' } * }); * ``` * * @example ✅ Fix 3: Use environment variable * ```typescript * // Set: COMPOSIO_TOOLKIT_VERSION_GITHUB=20250909_00 * await composio.tools.execute('GITHUB_GET_REPOS', { * userId: 'default', * arguments: { owner: 'composio' } * }); * ``` * * @example ⚠️ Fix 4: Skip version check (not recommended for production) * ```typescript * await composio.tools.execute('GITHUB_GET_REPOS', { * userId: 'default', * dangerouslySkipVersionCheck: true, * arguments: { owner: 'composio' } * }); * ``` */ var ComposioToolVersionRequiredError = class extends ComposioError$1 { constructor(message = "Toolkit version not specified. For manual execution of the tool please pass a specific toolkit version", options = {}) { super(message, { ...options, code: ToolErrorCodes.TOOL_VERSION_REQUIRED, possibleFixes: options.possibleFixes || [ "Pass the toolkit version as a parameter to the execute function (\"latest\" is not supported in manual execution)", "Set the toolkit versions in the Composio config (toolkitVersions: { <toolkit-slug>: \"<toolkit-version>\" })", "Set the toolkit version in the environment variable (COMPOSIO_TOOLKIT_VERSION_<TOOLKIT_SLUG>)", "Set dangerouslySkipVersionCheck to true (this might cause unexpected behavior when new versions of the tools are released)" ] }); } }; const ERROR_CODE_HANDLERS = new Map([[1803, (msg) => new ComposioConnectedAccountNotFoundError(msg)]]); const handleToolExecutionError = (tool, actualError) => { if (actualError instanceof APIError && actualError.error) { const errorBody = actualError.error; const errorCode = errorBody?.error?.code; const errorMessage = errorBody?.error?.message; if (errorCode && ERROR_CODE_HANDLERS.has(errorCode)) return ERROR_CODE_HANDLERS.get(errorCode)(errorMessage || "An error occurred"); } return new ComposioToolExecutionError(`Error executing the tool ${tool}`, { cause: actualError, possibleFixes: ["Ensure the tool slug is correct and the input arguments for the tool is valid"] }); }; //#endregion //#region src/errors/AuthConfigErrors.ts const AuthConfigErrorCodes = { AUTH_CONFIG_NOT_FOUND: "AUTH_CONFIG_NOT_FOUND" }; var ComposioAuthConfigNotFoundError = class extends ComposioError$1 { constructor(message = "Auth config not found", options = {}) { super(message, { ...options, code: AuthConfigErrorCodes.AUTH_CONFIG_NOT_FOUND, possibleFixes: options.possibleFixes || [ "Check if the auth config exists", "Check if the auth config id is correct", "Check if the auth config is enabled" ] }); this.name = "ComposioAuthConfigNotFoundError"; } }; //#endregion //#region src/errors/ConnectionRequestErrors.ts const ConnectionRequestErrorCodes = { CONNECTION_REQUEST_TIMEOUT: "CONNECTION_REQUEST_TIMEOUT", CONNECTION_REQUEST_FAILED: "CONNECTION_REQUEST_FAILED" }; var ConnectionRequestTimeoutError = class extends ComposioError$1 { constructor(message = "Connection request timed out", options = {}) { super(message, { ...options, code: ConnectionRequestErrorCodes.CONNECTION_REQUEST_TIMEOUT }); this.name = "ConnectionRequestTimeoutError"; } }; var ConnectionRequestFailedError = class extends ComposioError$1 { constructor(message = "Connection request failed", options = {}) { super(message, { ...options, code: ConnectionRequestErrorCodes.CONNECTION_REQUEST_FAILED }); this.name = "ConnectionRequestFailedError"; } }; //#endregion //#region src/errors/ToolkitErrors.ts const ToolkitErrorCodes = { TOOLKIT_NOT_FOUND: "TOOLKIT_NOT_FOUND" }; var ComposioToolkitNotFoundError = class extends ComposioError$1 { constructor(message = "Toolkit not found", options = {}) { super(message, { ...options, code: "TOOLKIT_NOT_FOUND", possibleFixes: options.possibleFixes || ["Ensure the toolkit is correctly configured and the slug is valid"] }); this.name = "ComposioToolkitNotFoundError"; } }; var ComposioToolkitFetchError = class extends ComposioError$1 { constructor(message = "Failed to fetch toolkit", options = {}) { super(message, { ...options, code: "TOOLKIT_FETCH_ERROR", possibleFixes: options.possibleFixes || [ "Ensure the toolkit slug is valid", "Ensure you are using the correct API key", "Ensure you are using the correct API endpoint / Base URL and it is working" ] }); this.name = "ComposioToolkitFetchError"; } }; //#endregion //#region src/errors/ValidationErrors.ts /** * Represents an input validation error using Zod. */ const ValidationErrorCodes = { VALIDATION_ERROR: "VALIDATION_ERROR", JSON_SCHEMA_TO_ZOD_ERROR: "JSON_SCHEMA_TO_ZOD_ERROR" }; var ValidationError = class extends ComposioError$1 { constructor(message = "Input validation failed", options = {}) { const { cause: providedZodError, ...restOptions } = options; let zodErrorInstance; if (providedZodError instanceof ZodError) zodErrorInstance = providedZodError; else zodErrorInstance = new ZodError([{ path: [], message: "Invalid input", code: "custom" }]); const issues = zodErrorInstance.issues.map((issue) => `[${issue.code}] ${issue.path.join(".")} - ${issue.message}`); super(message, { ...restOptions, code: options.code || ValidationErrorCodes.VALIDATION_ERROR, possibleFixes: issues, cause: zodErrorInstance }); this.name = "ValidationError"; this.message = `${message}: ${this.generateUserFriendlyMessage()}`; } generateUserFriendlyMessage() { if (this.cause instanceof ZodError && this.cause.issues.length > 0) { const issue = this.cause.issues[0]; const param = issue.path.join(".") || "parameter"; if (issue.code === "invalid_type") return `The ${param} should be a ${issue.expected}, but you provided a ${issue.received}`; return issue.message; } return "Please check your input parameters"; } }; var JsonSchemaToZodError = class extends ComposioError$1 { constructor(message = "Failed to convert JSON schema to Zod schema", options = {}) { super(message, { ...options, code: options.code || ValidationErrorCodes.JSON_SCHEMA_TO_ZOD_ERROR }); } }; //#endregion //#region src/errors/SDKErrors.ts const SDKErrorCodes = { NO_API_KEY_PROVIDED: "NO_API_KEY_PROVIDED" }; var ComposioNoAPIKeyError = class extends ComposioError$1 { constructor(message = "No Composio API key provided", options = {}) { const defaultCause = "Couldn't find an API key in the params, environment variables or in the user config file"; super(message, { ...options, code: SDKErrorCodes.NO_API_KEY_PROVIDED, cause: options.cause || defaultCause, possibleFixes: options.possibleFixes || [ "Ensure you have an API key passed in the params, or in environment variable (COMPOSIO_API_KEY) or in the user config file", "To get an API key, please sign up at https://composio.dev/signup", "You can also use the Composio CLI to create a project and get an API key" ], statusCode: 401 }); this.name = "ComposioNoAPIKeyError"; } }; //#endregion //#region src/errors/TriggerErrors.ts const TriggerErrorCodes = { TRIGGER_FAILED_TO_GET_SDK_REALTIME_CREDENTIALS: "TRIGGER_FAILED_TO_GET_SDK_REALTIME_CREDENTIALS", TRIGGER_FAILED_TO_CREATE_PUSHER_CLIENT: "TRIGGER_FAILED_TO_CREATE_PUSHER_CLIENT", TRIGGER_FAILED_TO_SUBSCRIBE_TO_PUSHER_CHANNEL: "TRIGGER_FAILED_TO_SUBSCRIBE_TO_PUSHER_CHANNEL", TRIGGER_FAILED_TO_UNSUBSCRIBE_FROM_PUSHER_CHANNEL: "TRIGGER_FAILED_TO_UNSUBSCRIBE_FROM_PUSHER_CHANNEL", TRIGGER_TYPE_NOT_FOUND: "TRIGGER_TYPE_NOT_FOUND", WEBHOOK_SIGNATURE_VERIFICATION_FAILED: "WEBHOOK_SIGNATURE_VERIFICATION_FAILED", WEBHOOK_PAYLOAD_INVALID: "WEBHOOK_PAYLOAD_INVALID" }; var ComposioFailedToGetSDKRealtimeCredentialsError = class extends ComposioError$1 { constructor(message = "Failed to get SDK realtime credentials", options = {}) { super(message, { ...options, code: TriggerErrorCodes.TRIGGER_FAILED_TO_GET_SDK_REALTIME_CREDENTIALS, possibleFixes: options.possibleFixes || ["Please contact support."] }); this.name = "ComposioFailedToGetSDKRealtimeCredentialsError"; } }; var ComposioFailedToCreatePusherClientError = class extends ComposioError$1 { constructor(message = "Failed to create Pusher client", options = {}) { super(message, { ...options, code: TriggerErrorCodes.TRIGGER_FAILED_TO_CREATE_PUSHER_CLIENT, possibleFixes: options.possibleFixes || ["Please contact support."] }); this.name = "ComposioFailedToCreatePusherClientError"; } }; var ComposioFailedToSubscribeToPusherChannelError = class extends ComposioError$1 { constructor(message = "Failed to subscribe to Pusher channel", options = {}) { super(message, { ...options, code: TriggerErrorCodes.TRIGGER_FAILED_TO_SUBSCRIBE_TO_PUSHER_CHANNEL, possibleFixes: options.possibleFixes || ["Please contact support."] }); this.name = "ComposioFailedToSubscribeToPusherChannelError"; } }; var ComposioFailedToUnsubscribeFromPusherChannelError = class extends ComposioError$1 { constructor(message = "Failed to unsubscribe from Pusher channel", options = {}) { super(message, { ...options, code: TriggerErrorCodes.TRIGGER_FAILED_TO_UNSUBSCRIBE_FROM_PUSHER_CHANNEL, possibleFixes: options.possibleFixes || ["Please contact support."] }); this.name = "ComposioFailedToUnsubscribeFromPusherChannelError"; } }; var ComposioTriggerTypeNotFoundError = class extends ComposioError$1 { constructor(message = "Trigger type not found", options = {}) { super(message, { ...options, code: TriggerErrorCodes.TRIGGER_TYPE_NOT_FOUND, statusCode: 404, possibleFixes: options.possibleFixes || ["Please contact support."] }); this.name = "ComposioTriggerTypeNotFoundError"; } }; var ComposioWebhookSignatureVerificationError = class extends ComposioError$1 { constructor(message = "Webhook signature verification failed", options = {}) { super(message, { ...options, code: TriggerErrorCodes.WEBHOOK_SIGNATURE_VERIFICATION_FAILED, statusCode: 401, possibleFixes: options.possibleFixes || [ "Verify that the webhook secret is correct.", "Ensure the raw request body is passed without modifications.", "Check that the signature header value is being passed correctly." ] }); this.name = "ComposioWebhookSignatureVerificationError"; } }; var ComposioWebhookPayloadError = class extends ComposioError$1 { constructor(message = "Invalid webhook payload", options = {}) { super(message, { ...options, code: TriggerErrorCodes.WEBHOOK_PAYLOAD_INVALID, statusCode: 400, possibleFixes: options.possibleFixes || ["Ensure the webhook payload is valid JSON.", "Verify the payload structure matches the expected format."] }); this.name = "ComposioWebhookPayloadError"; } }; //#endregion //#region src/errors/RemoteFileErrors.ts const RemoteFileErrorCodes = { DOWNLOAD_FAILED: "REMOTE_FILE_DOWNLOAD_FAILED" }; /** * Error thrown when fetching a remote file from a tool router session mount fails. * Includes HTTP status, URL, and file path context for debugging. */ var RemoteFileDownloadError = class extends ComposioError$1 { constructor(message = "Failed to download remote file", options = {}) { const { statusCode, statusText, downloadUrl, mountRelativePath, filename, meta: optionsMeta, ...rest } = options; const meta = { ...optionsMeta, ...statusCode !== void 0 && { statusCode }, ...statusText && { statusText }, ...downloadUrl && { downloadUrl }, ...mountRelativePath && { mountRelativePath }, ...filename && { filename } }; super(message, { ...rest, code: RemoteFileErrorCodes.DOWNLOAD_FAILED, statusCode, meta: Object.keys(meta).length > 0 ? meta : void 0, possibleFixes: options.possibleFixes ?? [ "Verify the download URL has not expired (check expiresAt)", "Ensure the file exists at the specified mount path", "Retry the operation; presigned URLs may have transient failures" ] }); this.name = "RemoteFileDownloadError"; } }; //#endregion //#region src/types/customTool.types.ts /** * Zod schema for validating a custom tool slug. * Alphanumeric, underscores, and hyphens only. No `LOCAL_` or `COMPOSIO_` prefix. * Length is validated contextually (standalone vs extension vs toolkit) at creation time. */ const CustomToolSlugSchema = z$1.string().min(1, "slug is required").regex(/^[A-Za-z0-9_-]+$/, "slug must only contain alphanumeric characters, underscores, and hyphens").refine((s) => !s.toUpperCase().startsWith("LOCAL_"), { message: "slug must not start with \"LOCAL_\" — this prefix is reserved for internal routing." }).refine((s) => !s.toUpperCase().startsWith("COMPOSIO_"), { message: "slug must not start with \"COMPOSIO_\" — this prefix is reserved for Composio meta tools." }); /** * Zod schema for validating the string/scalar fields of createCustomTool() options. * Slug is validated separately as the first argument. * Used internally for validation — inputParams, outputParams, and execute are checked manually. */ const CreateCustomToolBaseSchema = z$1.object({ name: z$1.string().min(1, "createCustomTool: name is required"), description: z$1.string().min(1, "createCustomTool: description is required"), extendsToolkit: z$1.string().optional() }); /** * Zod schema for validating the string/scalar fields of createCustomToolkit() options. * Slug is validated separately as the first argument. */ const CreateCustomToolkitBaseSchema = z$1.object({ name: z$1.string().min(1, "createCustomToolkit: name is required"), description: z$1.string().min(1, "createCustomToolkit: description is required") }); //#endregion //#region src/models/CustomTool.ts /** * @fileoverview Factory functions for creating custom tools and toolkits. * * Usage: * ```typescript * import { experimental_createTool, experimental_createToolkit } from '@composio/core'; * * const grep = createCustomTool('GREP', { * name: 'Grep Search', * description: 'Search for patterns in files', * inputParams: z.object({ pattern: z.string() }), * execute: async (input) => ({ matches: [] }), * }); * * const devTools = createCustomToolkit('DEV_TOOLS', { * name: 'Dev Tools', * description: 'Local dev utilities', * tools: [grep], * }); * ``` */ /** Prefix applied by the backend to local tool slugs for disambiguation. */ const LOCAL_TOOL_PREFIX = "LOCAL_"; /** Maximum allowed length for the final prefixed slug. */ const MAX_SLUG_LENGTH = 60; /** * Compute the final slug length for a tool given its context. * Returns the expected length of LOCAL_[TOOLKIT_]SLUG. */ function computeFinalSlugLength(toolSlug, toolkitSlug) { return 6 + (toolkitSlug ? toolkitSlug.length + 1 : 0) + toolSlug.length; } /** * Validate that the final slug won't exceed the max length. * Called early in createCustomTool/createCustomToolkit for fast feedback. */ function validateSlugLength(toolSlug, toolkitSlug, context) { const finalLength = computeFinalSlugLength(toolSlug, toolkitSlug); if (finalLength > MAX_SLUG_LENGTH) { const prefix = LOCAL_TOOL_PREFIX + (toolkitSlug ? `${toolkitSlug.toUpperCase()}_` : ""); throw new ValidationError(`${context}: slug "${toolSlug}" is too long. With prefix "${prefix}", the final slug would be ${finalLength} characters (max ${MAX_SLUG_LENGTH}). Shorten the slug to at most ${MAX_SLUG_LENGTH - prefix.length} characters.`); } } /** * Create a custom tool for use in tool router sessions. * * The returned object is a lightweight reference containing the tool's metadata * and execute function. Pass it to `composio.create(userId, { experimental: { customTools: [...] } })` * to bind it to a session. * * Just return the result data from `execute`, or throw an error. * The SDK wraps it into the standard response format internally. * * **Slug naming:** The slug you provide is automatically prefixed with `LOCAL_` when * exposed to the agent (e.g. `'GREP'` becomes `LOCAL_GREP`). If the tool is inside a * custom toolkit, the toolkit slug is also included (e.g. `LOCAL_DEV_TOOLS_GREP`). * The `LOCAL_` prefix is reserved and cannot be used in your slug. * * @param slug - Unique tool identifier (alphanumeric, underscores, hyphens; no LOCAL_ or COMPOSIO_ prefix) * @param options - Tool definition including name, schema, and execute function * @returns A CustomTool to pass to session creation * * @example Standalone tool (no auth) * ```typescript * const grep = createCustomTool('GREP', { * name: 'Grep Search', * description: 'Search for patterns in files', * inputParams: z.object({ pattern: z.string(), path: z.string() }), * execute: async (input) => ({ matches: [] }), * }); * ``` * * @example Tool extending a Composio toolkit (inherits auth) * ```typescript * const getImportant = createCustomTool('GET_IMPORTANT_EMAILS', { * name: 'Get Important Emails', * description: 'Fetch high-priority emails', * extendsToolkit: 'gmail', * inputParams: z.object({ limit: z.number().default(10) }), * execute: async (input, ctx) => { * // Same response shape as session.execute(): { data, error, logId } * const result = await ctx.execute('GMAIL_SEARCH', { query: 'is:important' }); * return { emails: result.data }; * }, * }); * ``` */ function createCustomTool(slug, options) { const slugResult = CustomToolSlugSchema.safeParse(slug); if (!slugResult.success) throw new ValidationError(`createCustomTool: ${slugResult.error.issues[0].message}`, { cause: slugResult.error }); const validated = CreateCustomToolBaseSchema.parse(options); if (!options.inputParams) throw new ValidationError("createCustomTool: inputParams is required"); if (options.inputParams?._def?.typeName !== "ZodObject") throw new ValidationError("createCustomTool: inputParams must be a z.object() schema. Tool input parameters are always an object with named properties."); if (typeof options.execute !== "function") throw new ValidationError("createCustomTool: execute must be a function"); validateSlugLength(slug, validated.extendsToolkit, "createCustomTool"); const { inputParams, execute } = options; const paramsSchemaJson = zodToJsonSchema.default(inputParams, { name: "input" }).definitions.input; const inputSchema = { type: "object", properties: paramsSchemaJson.properties, ...paramsSchemaJson.required ? { required: paramsSchemaJson.required } : {} }; let outputSchema; if (options.outputParams) outputSchema = zodToJsonSchema.default(options.outputParams, { name: "output" }).definitions.output; return { slug: slugResult.data, name: validated.name, description: validated.description, extendsToolkit: validated.extendsToolkit, inputSchema, outputSchema, inputParams, execute }; } /** * Create a custom toolkit that groups related tools. * * Tools passed here must NOT have `extendsToolkit` set — they inherit the toolkit identity instead. * * **Slug naming:** The toolkit slug becomes part of the final tool slug exposed to the agent. * For example, a toolkit `'DEV_TOOLS'` with a tool `'GREP'` produces `LOCAL_DEV_TOOLS_GREP`. * The `LOCAL_` prefix is reserved and cannot be used in your slug. * * @param slug - Unique toolkit identifier (alphanumeric, underscores, hyphens; no LOCAL_ or COMPOSIO_ prefix) * @param options - Toolkit definition including name, description, and tools * @returns A CustomToolkit to pass to session creation * * @example * ```typescript * const devTools = createCustomToolkit('DEV_TOOLS', { * name: 'Dev Tools', * description: 'Local dev utilities', * tools: [grepTool, sedTool], * }); * ``` */ function createCustomToolkit(slug, options) { const slugResult = CustomToolSlugSchema.safeParse(slug); if (!slugResult.success) throw new ValidationError(`createCustomToolkit: ${slugResult.error.issues[0].message}`, { cause: slugResult.error }); const validated = CreateCustomToolkitBaseSchema.parse(options); if (!options.tools?.length) throw new ValidationError("createCustomToolkit: at least one tool is required"); for (const tool of options.tools) { if (tool.extendsToolkit) throw new ValidationError(`createCustomToolkit: tool "${tool.slug}" has extendsToolkit set. Tools in a custom toolkit must not use extendsToolkit — they inherit the toolkit identity instead.`); validateSlugLength(tool.slug, slug, `createCustomToolkit("${slug}")`); } return { slug: slugResult.data, name: validated.name, description: validated.description, tools: options.tools }; } /** * Serialize custom tools into the format expected by the backend session creation API. * * Maps `extendsToolkit` → `extends_toolkit` for backend. Omitted for standalone tools. * * @internal * @param tools - The custom tools to serialize * @returns Array of CustomToolDefinition for the API payload */ function serializeCustomTools(tools) { return tools.map((handle) => ({ slug: handle.slug, name: handle.name, description: handle.description, input_schema: handle.inputSchema, ...handle.outputSchema ? { output_schema: handle.outputSchema } : {}, ...handle.extendsToolkit ? { extends_toolkit: handle.extendsToolkit } : {} })); } /** * Serialize custom toolkits into the format expected by the backend session creation API. * * @internal * @param toolkits - The custom toolkits to serialize * @returns Array of CustomToolkitDefinition for the API payload */ function serializeCustomToolkits(toolkits) { return toolkits.map((tk) => ({ slug: tk.slug, name: tk.name, description: tk.description, tools: tk.tools.map((t) => ({ slug: t.slug, name: t.name, description: t.description, input_schema: t.inputSchema, ...t.outputSchema ? { output_schema: t.outputSchema } : {} })) })); } /** * Build a CustomToolsMap using the slug/original_slug mapping from the session create response. * This uses the backend's authoritative prefixed slugs instead of computing them client-side. * * @internal * @param tools - The original custom tools passed to session creation * @param toolkits - The original custom toolkits passed to session creation * @param experimental - The experimental section from the session create response * @returns Maps for O(1) lookup by both final and original slug */ function buildCustomToolsMapFromResponse(tools, toolkits, experimental) { const byFinalSlug = /* @__PURE__ */ new Map(); const byOriginalSlug = /* @__PURE__ */ new Map(); const handlesByOriginalSlug = /* @__PURE__ */ new Map(); for (const handle of tools) handlesByOriginalSlug.set(handle.slug.toUpperCase(), { handle, toolkit: handle.extendsToolkit }); if (toolkits) for (const tk of toolkits) for (const handle of tk.tools) handlesByOriginalSlug.set(handle.slug.toUpperCase(), { handle, toolkit: tk.slug }); const addEntry = (finalSlug, originalSlug, toolkit) => { const match = handlesByOriginalSlug.get(originalSlug.toUpperCase()); if (!match) return; const entry = { handle: match.handle, finalSlug, toolkit: toolkit ?? match.toolkit }; byFinalSlug.set(finalSlug, entry); byOriginalSlug.set(originalSlug.toUpperCase(), entry); }; if (experimental?.custom_tools) for (const ct of experimental.custom_tools) addEntry(ct.slug, ct.original_slug, ct.extends_toolkit); if (experimental?.custom_toolkits) for (const ctk of experimental.custom_toolkits) for (const ct of ctk.tools) addEntry(ct.slug, ct.original_slug, ctk.slug); return { byFinalSlug, byOriginalSlug, toolkits }; } //#endregion export { AuthConfigErrorCodes as A, ToolErrorCodes as B, ValidationErrorCodes as C, ConnectionRequestErrorCodes as D, ToolkitErrorCodes as E, ComposioInvalidModifierError as F, ConnectedAccountErrorCodes as G, ComposioConnectedAccountNotFoundError as H, ComposioProviderNotDefinedError as I, ComposioToolExecutionError as L, ComposioCustomToolsNotInitializedError as M, ComposioGlobalExecuteToolFnNotSetError as N, ConnectionRequestFailedError as O, ComposioInvalidExecuteFunctionError as P, ComposioToolNotFoundError as R, ValidationError as S, ComposioToolkitNotFoundError as T, ComposioFailedToCreateConnectedAccountLink as U, handleToolExecutionError as V, ComposioMultipleConnectedAccountsError as W, ComposioWebhookSignatureVerificationError as _, serializeCustomTools as a, SDKErrorCodes as b, CustomToolSlugSchema as c, ComposioFailedToCreatePusherClientError as d, ComposioFailedToGetSDKRealtimeCredentialsError as f, ComposioWebhookPayloadError as g, ComposioTriggerTypeNotFoundError as h, serializeCustomToolkits as i, ComposioAuthConfigNotFoundError as j, ConnectionRequestTimeoutError as k, RemoteFileDownloadError as l, ComposioFailedToUnsubscribeFromPusherChannelError as m, createCustomTool as n, CreateCustomToolBaseSchema as o, ComposioFailedToSubscribeToPusherChannelError as p, createCustomToolkit as r, CreateCustomToolkitBaseSchema as s, buildCustomToolsMapFromResponse as t, RemoteFileErrorCodes as u, TriggerErrorCodes as v, ComposioToolkitFetchError as w, JsonSchemaToZodError as x, ComposioNoAPIKeyError as y, ComposioToolVersionRequiredError as z };