@mastra/editor 0.13.7-alpha.2 → 0.13.7-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @mastra/editor
2
2
 
3
+ ## 0.13.7-alpha.4
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed multi-tenant tool connections for Composio-backed agents. ([#19144](https://github.com/mastra-ai/mastra/pull/19144))
8
+
9
+ **Multi-tenant credential auto-resolve**
10
+
11
+ Agents that use a `caller-supplied` connection scope now let Composio pick the connected account within each tenant's user bucket, instead of pinning one shared account for every caller. This removes the need to track per-tenant account IDs yourself when building multi-tenant SaaS on top of the Agent Builder.
12
+
13
+ **Fixed account authorization**
14
+
15
+ Connecting a new account now uses Composio's supported managed-OAuth link flow, replacing a deprecated endpoint that stopped working for managed OAuth. Connections that collect custom fields (such as a Confluence subdomain) continue to work unchanged.
16
+
17
+ **Config-level connection scope**
18
+
19
+ `ComposioToolProvider` now forwards `defaultScope` to the provider, so you can set a provider's connection scope once at construction (for example `defaultScope: 'caller-supplied'`) instead of relying on per-request scope. Every connection authorized against the provider is then bucketed accordingly.
20
+
21
+ - Updated dependencies [[`fb8aea3`](https://github.com/mastra-ai/mastra/commit/fb8aea384291e77311be3a64ee1717320d5c3c73), [`4ce0163`](https://github.com/mastra-ai/mastra/commit/4ce0163dc86e675a86809685c8ce6c49f1aeb87e)]:
22
+ - @mastra/core@1.51.0-alpha.5
23
+ - @mastra/mcp@1.14.0-alpha.0
24
+
25
+ ## 0.13.7-alpha.3
26
+
27
+ ### Patch Changes
28
+
29
+ - Updated dependencies [[`a5c6337`](https://github.com/mastra-ai/mastra/commit/a5c6337d23c7686c81a32ce62f550f610543a240), [`031931a`](https://github.com/mastra-ai/mastra/commit/031931a715405fb90759b1903c9c25cbf05994af), [`eb70da9`](https://github.com/mastra-ai/mastra/commit/eb70da98e1007b18e1463d75121bc07db55f8e09), [`8b97958`](https://github.com/mastra-ai/mastra/commit/8b979589f9aa59ba67cac565949475f2ffeb4ac3), [`8410541`](https://github.com/mastra-ai/mastra/commit/84105412c60ecd3bb33a9838146f59c4b588228f), [`01b338c`](https://github.com/mastra-ai/mastra/commit/01b338c56271f0219606710e3e8b26dee27ac6c2), [`8b7361d`](https://github.com/mastra-ai/mastra/commit/8b7361d35de68b80d05d30a74e0c69e7218fd612), [`85fb642`](https://github.com/mastra-ai/mastra/commit/85fb642f4d112d0da9f39808617397f7e47fe622), [`481c112`](https://github.com/mastra-ai/mastra/commit/481c1125b752489673ec671fcb7ca80f9c86ffb1), [`c43f3a9`](https://github.com/mastra-ai/mastra/commit/c43f3a9d1efde99b38789364ba4d0ba670f430e3), [`c43f3a9`](https://github.com/mastra-ai/mastra/commit/c43f3a9d1efde99b38789364ba4d0ba670f430e3)]:
30
+ - @mastra/core@1.51.0-alpha.4
31
+ - @mastra/memory@1.23.0-alpha.3
32
+ - @mastra/mcp@1.14.0-alpha.0
33
+
3
34
  ## 0.13.7-alpha.2
4
35
 
5
36
  ### Patch Changes
package/dist/composio.cjs CHANGED
@@ -35,7 +35,8 @@ var ComposioToolProvider = class extends import_tool_provider.BaseToolProvider {
35
35
  constructor(config) {
36
36
  super({
37
37
  allowedToolkits: config.allowedToolkits,
38
- allowedTools: config.allowedTools
38
+ allowedTools: config.allowedTools,
39
+ defaultScope: config.defaultScope
39
40
  });
40
41
  this.info = {
41
42
  id: COMPOSIO_PROVIDER_ID,
@@ -120,7 +121,9 @@ var ComposioToolProvider = class extends import_tool_provider.BaseToolProvider {
120
121
  // into the API call. Mutating `params.connectedAccountId` routes
121
122
  // the call to a specific account.
122
123
  beforeExecute: ({ params }) => {
123
- params.connectedAccountId = opts.connectionId;
124
+ if (opts.scope !== "caller-supplied") {
125
+ params.connectedAccountId = opts.connectionId;
126
+ }
124
127
  return params;
125
128
  }
126
129
  };
@@ -154,12 +157,12 @@ var ComposioToolProvider = class extends import_tool_provider.BaseToolProvider {
154
157
  const { id: authConfigId, authScheme } = await this.resolveAuthConfig(opts.toolkit);
155
158
  const internalUserId = opts.connectionId || DEFAULT_INTERNAL_USER_ID;
156
159
  const initiateConfig = opts.config && Object.keys(opts.config).length > 0 && authScheme ? { authScheme, val: opts.config } : void 0;
157
- const request = await composio.connectedAccounts.initiate(internalUserId, authConfigId, {
160
+ const request = initiateConfig ? await composio.connectedAccounts.initiate(internalUserId, authConfigId, {
158
161
  allowMultiple: true,
159
- ...initiateConfig ? { config: initiateConfig } : {}
160
- });
162
+ config: initiateConfig
163
+ }) : await composio.connectedAccounts.link(internalUserId, authConfigId);
161
164
  if (!request.redirectUrl) {
162
- throw new Error(`[composio] initiate did not return a redirectUrl for toolkit "${opts.toolkit}"`);
165
+ throw new Error(`[composio] authorize did not return a redirectUrl for toolkit "${opts.toolkit}"`);
163
166
  }
164
167
  return { url: request.redirectUrl, authId: request.id };
165
168
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/composio.ts","../src/providers/composio.ts"],"sourcesContent":["export { ComposioToolProvider } from './providers/composio';\nexport type { ComposioToolProviderConfig } from './providers/composio';\n","import type {\n AuthFlowStatus,\n AuthorizeOpts,\n ConnectionField,\n ExistingConnection,\n ListConnectionsOpts,\n ListConnectionsResult,\n ListToolsOpts,\n ListToolsResult,\n ResolveToolsOpts,\n ToolProviderCapabilities,\n ToolProviderHealth,\n ToolProviderInfo,\n ToolProviderToolkit,\n} from '@mastra/core/tool-provider';\nimport { BaseToolProvider } from '@mastra/core/tool-provider';\nimport type { BaseToolProviderOptions } from '@mastra/core/tool-provider';\nimport type { ToolAction } from '@mastra/core/tools';\nimport { MASTRA_RESOURCE_ID_KEY } from '@mastra/core/request-context';\n\nimport { Composio } from '@composio/core';\nimport type {\n ConnectedAccountListResponse,\n Tool as ComposioTool,\n ToolListParams as ComposioToolListParams,\n ToolKitItem,\n} from '@composio/core';\nimport { MastraProvider } from '@composio/mastra';\nimport type { MastraToolCollection } from '@composio/mastra';\n\nexport interface ComposioToolProviderConfig extends BaseToolProviderOptions {\n /** Composio API key. */\n apiKey: string;\n}\n\nconst COMPOSIO_PROVIDER_ID = 'composio' as const;\nconst DEFAULT_INTERNAL_USER_ID = 'default';\n\n/**\n * Composio implementation of the {@link BaseToolProvider} contract.\n *\n * Discovery (`listAllToolkits`, `listAllTools`) uses the raw Composio\n * client. Runtime (`resolveToolsVNext`) uses {@link MastraProvider} so resolved\n * tools are already in `createTool()` shape; each tool gets a\n * `beforeExecute` modifier that injects\n * `connectedAccountId = connectionId`, and `outputSchema` is cleared\n * because Composio returns union schemas that Mastra's runtime rejects.\n *\n * Allowlist filtering is layered by {@link BaseToolProvider}; this class\n * never reads `allowedToolkits` / `allowedTools` directly.\n */\nexport class ComposioToolProvider extends BaseToolProvider {\n readonly info: ToolProviderInfo = {\n id: COMPOSIO_PROVIDER_ID,\n name: 'Composio',\n description: 'Access 10,000+ tools from 150+ apps via Composio',\n };\n readonly capabilities: ToolProviderCapabilities = {\n multipleConnectionsPerToolkit: true,\n batchConnectionStatus: true,\n reauthorizeReusesConnectionId: true,\n supportsRevoke: true,\n };\n\n private readonly apiKey: string;\n private rawClient: Composio | null = null;\n private mastraClient: Composio<MastraProvider> | null = null;\n\n constructor(config: ComposioToolProviderConfig) {\n super({\n allowedToolkits: config.allowedToolkits,\n allowedTools: config.allowedTools,\n });\n this.apiKey = config.apiKey;\n }\n\n // ── client cache ──────────────────────────────────────────────────────\n\n private getRawClient(): Composio {\n if (!this.rawClient) {\n this.rawClient = new Composio({ apiKey: this.apiKey });\n }\n return this.rawClient;\n }\n\n private getMastraClient(): Composio<MastraProvider> {\n if (!this.mastraClient) {\n this.mastraClient = new Composio({\n apiKey: this.apiKey,\n provider: new MastraProvider(),\n });\n }\n return this.mastraClient;\n }\n\n // ── catalog (BaseToolProvider adds allowlist filter on top) ───────────\n\n protected async listAllToolkits(): Promise<ToolProviderToolkit[]> {\n const composio = this.getRawClient();\n const toolkits: ToolKitItem[] = await composio.toolkits.get({});\n return toolkits.map(tk => ({\n slug: tk.slug,\n name: tk.name,\n description: tk.meta?.description,\n icon: tk.meta?.logo,\n }));\n }\n\n protected async listAllTools(opts: ListToolsOpts): Promise<ListToolsResult> {\n const composio = this.getRawClient();\n\n // Composio's `getRawComposioTools` query is a discriminated union — every\n // variant accepts `limit`, but the toolkits/search keys are exclusive in\n // the TS types. We build the variant we need, then cast to the union.\n //\n // When the caller doesn't scope to a specific toolkit, we fall back to\n // the admin allowlist so the SDK returns a flat list across allowed\n // toolkits in a single hop (vs. fanning out per toolkit).\n const limit = opts.perPage;\n const fallbackToolkits = this.allowedToolkits.length > 0 ? [...this.allowedToolkits] : undefined;\n const query: ComposioToolListParams = (\n opts.toolkit\n ? { toolkits: [opts.toolkit], limit, search: opts.search }\n : fallbackToolkits\n ? { toolkits: fallbackToolkits, limit, search: opts.search }\n : opts.search\n ? { search: opts.search, limit }\n : { toolkits: [] as string[], limit }\n ) as ComposioToolListParams;\n\n // Composio's SDK validates every tool's input/output schema against an\n // internal zod shape and throws on the first malformed tool — so one bad\n // toolkit can poison a multi-toolkit query. Treat validation errors as a\n // soft failure and return an empty page rather than a 500.\n let rawTools: ComposioTool[] = [];\n try {\n rawTools = await composio.tools.getRawComposioTools(query);\n } catch (err) {\n console.warn(\n `[ComposioToolProvider] listAllTools failed for query ${JSON.stringify(query)} — returning empty page`,\n err,\n );\n }\n\n const data = rawTools.map(tool => ({\n slug: tool.slug,\n name: tool.name ?? tool.slug,\n description: tool.description,\n toolkit: tool.toolkit?.slug ?? opts.toolkit ?? '',\n }));\n\n return {\n data,\n pagination: {\n page: opts.page ?? 1,\n perPage: limit,\n hasMore: limit !== undefined && rawTools.length >= limit,\n },\n };\n }\n\n // ── runtime ───────────────────────────────────────────────────────────\n\n async resolveToolsVNext(opts: ResolveToolsOpts): Promise<Record<string, ToolAction<any, any, any>>> {\n if (opts.toolSlugs.length === 0) return {};\n\n // For author-bound connections, the runtime fan-out passes the agent's\n // author id explicitly. Use it as the Composio user bucket so the pin\n // resolves for any invoker (not just the original author).\n const internalUserId =\n opts.authorId && opts.authorId.length > 0 ? opts.authorId : resolveInternalUserId(opts.requestContext);\n const composio = this.getMastraClient();\n\n const modifiers = {\n // `connectedAccountId` is not threaded through Composio's `execute`\n // option bag in @composio/mastra; the only documented per-call hook\n // is `beforeExecute`, which receives the params object that flows\n // into the API call. Mutating `params.connectedAccountId` routes\n // the call to a specific account.\n beforeExecute: ({ params }: { params: { connectedAccountId?: string; userId?: string } }) => {\n params.connectedAccountId = opts.connectionId;\n return params;\n },\n };\n\n const mastraTools = (await composio.tools.get(\n internalUserId,\n { tools: opts.toolSlugs },\n modifiers,\n )) as MastraToolCollection;\n\n const result: Record<string, ToolAction<any, any, any>> = {};\n\n for (const [key, tool] of Object.entries(mastraTools ?? {})) {\n if (!tool) continue;\n const slug = (tool as { id?: string }).id ?? key;\n\n // Composio returns union output schemas (`successful: true | false`) that\n // Mastra's runtime cannot validate; clearing avoids per-tool validation\n // errors at execute time. The property may be non-writable on some SDK\n // versions, so we swallow assignment errors.\n try {\n (tool as unknown as { outputSchema: unknown }).outputSchema = undefined;\n } catch {\n // ignore\n }\n\n const descOverride = opts.toolMeta?.[slug]?.description;\n if (descOverride) {\n try {\n (tool as unknown as { description: string }).description = descOverride;\n } catch {\n // ignore\n }\n }\n\n result[slug] = tool as ToolAction<any, any, any>;\n }\n\n return result;\n }\n\n // ── auth surface ──────────────────────────────────────────────────────\n\n async authorize(opts: AuthorizeOpts): Promise<{ url: string; authId: string }> {\n const composio = this.getRawClient();\n const { id: authConfigId, authScheme } = await this.resolveAuthConfig(opts.toolkit);\n\n // `connectionId` carries the internal user bucket for the runtime fan-out;\n // for authorize we treat it as the Composio `userId` so the new connected\n // account lands under the same bucket as the agent's resolved identity.\n const internalUserId = opts.connectionId || DEFAULT_INTERNAL_USER_ID;\n // `allowMultiple: true` — we explicitly support N connected accounts per\n // (user, auth config) and disambiguate at runtime via per-connection labels.\n // `config` carries provider-specific user-supplied fields (e.g. Confluence\n // subdomain) collected by the picker via `listConnectionFields`. Composio\n // expects a discriminated `{ authScheme, val }` shape; we cast through\n // `unknown` because our generic interface keeps it Record-shaped.\n const initiateConfig =\n opts.config && Object.keys(opts.config).length > 0 && authScheme\n ? ({ authScheme, val: opts.config } as unknown as Parameters<\n typeof composio.connectedAccounts.initiate\n >[2] extends infer O\n ? O extends { config?: infer C }\n ? C\n : never\n : never)\n : undefined;\n const request = await composio.connectedAccounts.initiate(internalUserId, authConfigId, {\n allowMultiple: true,\n ...(initiateConfig ? { config: initiateConfig } : {}),\n });\n\n if (!request.redirectUrl) {\n throw new Error(`[composio] initiate did not return a redirectUrl for toolkit \"${opts.toolkit}\"`);\n }\n\n return { url: request.redirectUrl, authId: request.id };\n }\n\n async listConnectionFields({ toolkit }: { toolkit: string }): Promise<ConnectionField[]> {\n const composio = this.getRawClient();\n const { authScheme } = await this.resolveAuthConfig(toolkit);\n if (!authScheme) {\n // Without a known auth scheme we can't query the field schema — fall\n // back to no fields rather than blocking the user.\n return [];\n }\n const fields = await composio.toolkits.getConnectedAccountInitiationFields(toolkit, authScheme, {\n requiredOnly: false,\n });\n return fields.map(f => ({\n name: f.name,\n displayName: f.displayName,\n description: f.description,\n type: coerceFieldType(f.type),\n required: f.required ?? false,\n default: f.default ?? undefined,\n }));\n }\n\n async getAuthStatus(authId: string): Promise<AuthFlowStatus> {\n const composio = this.getRawClient();\n const account = await composio.connectedAccounts.get(authId);\n switch (account.status) {\n case 'ACTIVE':\n return 'completed';\n case 'INITIALIZING':\n case 'INITIATED':\n return 'pending';\n case 'FAILED':\n case 'EXPIRED':\n case 'INACTIVE':\n return 'failed';\n default:\n return 'pending';\n }\n }\n\n async getConnectionStatus(opts: {\n items: Array<{ connectionId: string; toolkit: string }>;\n }): Promise<Record<string, { connected: boolean }>> {\n if (opts.items.length === 0) return {};\n\n const composio = this.getRawClient();\n const toolkitSlugs = Array.from(new Set(opts.items.map(i => i.toolkit)));\n\n // One SDK call per `getConnectionStatus`, regardless of N items.\n // Filter by all referenced toolkits, then bucket locally by id.\n const list: ConnectedAccountListResponse = await composio.connectedAccounts.list({\n toolkitSlugs,\n });\n\n const liveById = new Map<string, { status: string; isDisabled: boolean }>();\n for (const item of list.items) {\n liveById.set(item.id, { status: item.status, isDisabled: item.isDisabled });\n }\n\n const result: Record<string, { connected: boolean }> = {};\n for (const { connectionId } of opts.items) {\n const live = liveById.get(connectionId);\n result[connectionId] = { connected: live ? live.status === 'ACTIVE' && !live.isDisabled : false };\n }\n return result;\n }\n\n async listConnections(opts: ListConnectionsOpts): Promise<ListConnectionsResult> {\n const composio = this.getRawClient();\n const page = opts.page ?? 1;\n const perPage = clampLimit(opts.perPage);\n\n // Normalize userIds[] / userId. Empty array = no buckets to list against,\n // short-circuit to avoid an unbounded Composio response.\n const userIds = resolveUserIds(opts);\n if (userIds && userIds.length === 0) {\n return { items: [], pagination: { page, perPage, hasMore: false } };\n }\n\n // Composio SDK 0.6.x uses cursor-based pagination on the wire. We surface\n // page-based pagination to keep the Mastra contract consistent with every\n // other list API. For now we only fetch the first page (page=1); paginated\n // requests for page > 1 are a follow-up — the UI does not yet paginate.\n const list: ConnectedAccountListResponse = await composio.connectedAccounts.list({\n toolkitSlugs: [opts.toolkit],\n ...(userIds ? { userIds } : {}),\n limit: perPage,\n });\n\n // Defensive: tolerate undocumented SDK shape drift where `items` is\n // missing or `nextCursor` is `null`/`undefined`/`''`.\n const items: ExistingConnection[] = (list.items ?? []).map(account => ({\n connectionId: account.id,\n status: mapComposioStatus(account.status, account.isDisabled),\n createdAt: account.createdAt,\n // `user_id` is preserved by the Composio SDK transform via spread but\n // isn't on the typed shape. Read it via a narrow cast.\n authorId: (account as unknown as { user_id?: string }).user_id,\n }));\n\n const nextCursor = (list as { nextCursor?: string | null }).nextCursor ?? null;\n const hasMore = typeof nextCursor === 'string' && nextCursor.length > 0;\n return { items, pagination: { page, perPage, hasMore } };\n }\n\n /**\n * Revoke a Composio connected account via\n * `DELETE /api/v3/connected_accounts/:nanoid`. Composio performs a soft\n * delete and responds with `{ success: boolean }`.\n *\n * Treats a 404 (account already deleted or never existed) as success so\n * the caller can drop its local pin without an error path. A `success:\n * false` response means the provider refused the delete and is surfaced\n * as an error so the caller does not delete its local row.\n */\n async revokeConnection(connectionId: string): Promise<void> {\n const composio = this.getRawClient();\n try {\n const res = (await composio.connectedAccounts.delete(connectionId)) as { success?: boolean } | undefined;\n if (res && res.success === false) {\n throw new Error(`Composio refused to delete connected account ${connectionId} (success=false)`);\n }\n } catch (err) {\n if (isNotFoundError(err)) return;\n throw err;\n }\n }\n\n async getHealth(): Promise<ToolProviderHealth> {\n try {\n const composio = this.getRawClient();\n await composio.toolkits.get({ limit: 1 } as Parameters<typeof composio.toolkits.get>[0]);\n return { ok: true };\n } catch (err) {\n return {\n ok: false,\n message: err instanceof Error ? err.message : 'Composio SDK reachability check failed',\n };\n }\n }\n\n // ── helpers ───────────────────────────────────────────────────────────\n\n /**\n * Resolve the single ENABLED auth config for `toolkit`. Throws if zero\n * or multiple configs match — the admin must enable exactly one in the\n * Composio dashboard before agents can connect.\n */\n private async resolveAuthConfig(toolkit: string): Promise<{ id: string; authScheme?: ComposioAuthScheme }> {\n const composio = this.getRawClient();\n const response = await composio.authConfigs.list({ toolkit });\n const enabled = response.items.filter(item => item.status === 'ENABLED');\n\n if (enabled.length === 0) {\n throw new Error(\n `[composio] No ENABLED auth config for toolkit \"${toolkit}\". Enable one in the Composio dashboard.`,\n );\n }\n if (enabled.length > 1) {\n const ids = enabled.map(item => item.id).join(', ');\n throw new Error(\n `[composio] Multiple ENABLED auth configs for toolkit \"${toolkit}\" (${ids}). Keep exactly one enabled.`,\n );\n }\n return { id: enabled[0]!.id, authScheme: enabled[0]!.authScheme };\n }\n}\n\ntype ComposioAuthScheme = NonNullable<\n Awaited<ReturnType<Composio['authConfigs']['list']>>['items'][number]['authScheme']\n>;\n\n/**\n * Best-effort 404 detection across the various error shapes the Composio\n * SDK surfaces (typed error with `statusCode`, HTTP-like error with\n * `status`, or a plain message containing \"404\" / \"not found\").\n */\nfunction isNotFoundError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as { statusCode?: number; status?: number; message?: string };\n if (e.statusCode === 404 || e.status === 404) return true;\n const msg = typeof e.message === 'string' ? e.message.toLowerCase() : '';\n return msg.includes('not found') || msg.includes('404');\n}\n\n/**\n * Composio reports a free-form `type` string. Map common values to our\n * generic ConnectionField type vocabulary; everything else falls back to\n * `'string'`.\n */\nfunction coerceFieldType(type: string): 'string' | 'number' | 'boolean' {\n switch (type.toLowerCase()) {\n case 'number':\n case 'integer':\n case 'int':\n case 'float':\n return 'number';\n case 'bool':\n case 'boolean':\n return 'boolean';\n default:\n return 'string';\n }\n}\n\n/**\n * Map Composio account status + `isDisabled` to the {@link ExistingConnection}\n * status vocabulary surfaced to the picker UI.\n */\nfunction mapComposioStatus(status: string, isDisabled: boolean): ExistingConnection['status'] {\n if (isDisabled) return 'inactive';\n switch (status) {\n case 'ACTIVE':\n return 'active';\n case 'INITIALIZING':\n case 'INITIATED':\n return 'pending';\n case 'FAILED':\n case 'EXPIRED':\n return 'failed';\n case 'INACTIVE':\n return 'inactive';\n default:\n return 'pending';\n }\n}\n\n// Mirror of `MASTRA_USER_KEY` from `@mastra/server`. Inlined to avoid a\n// reverse dependency from `editor` onto `server`.\nconst MASTRA_USER_KEY = 'mastra__user';\n\n/**\n * Read the internal user id (Composio `userId`) from per-request context.\n *\n * The runtime fan-out is responsible for stamping the agent's resolved\n * author id (or `'default'`) into `requestContext` under\n * {@link MASTRA_RESOURCE_ID_KEY}.\n */\nfunction resolveInternalUserId(requestContext?: Record<string, unknown>): string {\n const resourceId = requestContext?.[MASTRA_RESOURCE_ID_KEY];\n if (typeof resourceId === 'string' && resourceId.length > 0) {\n return resourceId;\n }\n\n const user = requestContext?.[MASTRA_USER_KEY];\n if (user && typeof user === 'object' && 'id' in user) {\n const id = (user as { id: unknown }).id;\n if (typeof id === 'string' && id.length > 0) {\n return id;\n }\n }\n\n return DEFAULT_INTERNAL_USER_ID;\n}\n\n/**\n * Resolve `userIds[]` from `listConnections` opts.\n *\n * - If `userIds` is provided, use it as-is (including empty array, which\n * means \"no buckets to list against\").\n * - If `userId` is provided, normalize to `[userId]`.\n * - Otherwise fall back to the default internal user id (single-bucket).\n */\nfunction resolveUserIds(opts: ListConnectionsOpts): string[] | undefined {\n if (Array.isArray(opts.userIds)) return opts.userIds;\n if (typeof opts.userId === 'string' && opts.userId.length > 0) return [opts.userId];\n return [DEFAULT_INTERNAL_USER_ID];\n}\n\nconst DEFAULT_LIMIT = 50;\nconst MAX_LIMIT = 200;\n\nfunction clampLimit(limit: number | undefined): number {\n if (typeof limit !== 'number' || !Number.isFinite(limit) || limit <= 0) {\n return DEFAULT_LIMIT;\n }\n return Math.min(Math.floor(limit), MAX_LIMIT);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/composio.ts","../src/providers/composio.ts"],"sourcesContent":["export { ComposioToolProvider } from './providers/composio';\nexport type { ComposioToolProviderConfig } from './providers/composio';\n","import type {\n AuthFlowStatus,\n AuthorizeOpts,\n ConnectionField,\n ExistingConnection,\n ListConnectionsOpts,\n ListConnectionsResult,\n ListToolsOpts,\n ListToolsResult,\n ResolveToolsOpts,\n ToolProviderCapabilities,\n ToolProviderHealth,\n ToolProviderInfo,\n ToolProviderToolkit,\n} from '@mastra/core/tool-provider';\nimport { BaseToolProvider } from '@mastra/core/tool-provider';\nimport type { BaseToolProviderOptions } from '@mastra/core/tool-provider';\nimport type { ToolAction } from '@mastra/core/tools';\nimport { MASTRA_RESOURCE_ID_KEY } from '@mastra/core/request-context';\n\nimport { Composio } from '@composio/core';\nimport type {\n ConnectedAccountListResponse,\n Tool as ComposioTool,\n ToolListParams as ComposioToolListParams,\n ToolKitItem,\n} from '@composio/core';\nimport { MastraProvider } from '@composio/mastra';\nimport type { MastraToolCollection } from '@composio/mastra';\n\nexport interface ComposioToolProviderConfig extends BaseToolProviderOptions {\n /** Composio API key. */\n apiKey: string;\n}\n\nconst COMPOSIO_PROVIDER_ID = 'composio' as const;\nconst DEFAULT_INTERNAL_USER_ID = 'default';\n\n/**\n * Composio implementation of the {@link BaseToolProvider} contract.\n *\n * Discovery (`listAllToolkits`, `listAllTools`) uses the raw Composio\n * client. Runtime (`resolveToolsVNext`) uses {@link MastraProvider} so resolved\n * tools are already in `createTool()` shape; each tool gets a\n * `beforeExecute` modifier that injects\n * `connectedAccountId = connectionId`, and `outputSchema` is cleared\n * because Composio returns union schemas that Mastra's runtime rejects.\n *\n * Allowlist filtering is layered by {@link BaseToolProvider}; this class\n * never reads `allowedToolkits` / `allowedTools` directly.\n */\nexport class ComposioToolProvider extends BaseToolProvider {\n readonly info: ToolProviderInfo = {\n id: COMPOSIO_PROVIDER_ID,\n name: 'Composio',\n description: 'Access 10,000+ tools from 150+ apps via Composio',\n };\n readonly capabilities: ToolProviderCapabilities = {\n multipleConnectionsPerToolkit: true,\n batchConnectionStatus: true,\n reauthorizeReusesConnectionId: true,\n supportsRevoke: true,\n };\n\n private readonly apiKey: string;\n private rawClient: Composio | null = null;\n private mastraClient: Composio<MastraProvider> | null = null;\n\n constructor(config: ComposioToolProviderConfig) {\n super({\n allowedToolkits: config.allowedToolkits,\n allowedTools: config.allowedTools,\n defaultScope: config.defaultScope,\n });\n this.apiKey = config.apiKey;\n }\n\n // ── client cache ──────────────────────────────────────────────────────\n\n private getRawClient(): Composio {\n if (!this.rawClient) {\n this.rawClient = new Composio({ apiKey: this.apiKey });\n }\n return this.rawClient;\n }\n\n private getMastraClient(): Composio<MastraProvider> {\n if (!this.mastraClient) {\n this.mastraClient = new Composio({\n apiKey: this.apiKey,\n provider: new MastraProvider(),\n });\n }\n return this.mastraClient;\n }\n\n // ── catalog (BaseToolProvider adds allowlist filter on top) ───────────\n\n protected async listAllToolkits(): Promise<ToolProviderToolkit[]> {\n const composio = this.getRawClient();\n const toolkits: ToolKitItem[] = await composio.toolkits.get({});\n return toolkits.map(tk => ({\n slug: tk.slug,\n name: tk.name,\n description: tk.meta?.description,\n icon: tk.meta?.logo,\n }));\n }\n\n protected async listAllTools(opts: ListToolsOpts): Promise<ListToolsResult> {\n const composio = this.getRawClient();\n\n // Composio's `getRawComposioTools` query is a discriminated union — every\n // variant accepts `limit`, but the toolkits/search keys are exclusive in\n // the TS types. We build the variant we need, then cast to the union.\n //\n // When the caller doesn't scope to a specific toolkit, we fall back to\n // the admin allowlist so the SDK returns a flat list across allowed\n // toolkits in a single hop (vs. fanning out per toolkit).\n const limit = opts.perPage;\n const fallbackToolkits = this.allowedToolkits.length > 0 ? [...this.allowedToolkits] : undefined;\n const query: ComposioToolListParams = (\n opts.toolkit\n ? { toolkits: [opts.toolkit], limit, search: opts.search }\n : fallbackToolkits\n ? { toolkits: fallbackToolkits, limit, search: opts.search }\n : opts.search\n ? { search: opts.search, limit }\n : { toolkits: [] as string[], limit }\n ) as ComposioToolListParams;\n\n // Composio's SDK validates every tool's input/output schema against an\n // internal zod shape and throws on the first malformed tool — so one bad\n // toolkit can poison a multi-toolkit query. Treat validation errors as a\n // soft failure and return an empty page rather than a 500.\n let rawTools: ComposioTool[] = [];\n try {\n rawTools = await composio.tools.getRawComposioTools(query);\n } catch (err) {\n console.warn(\n `[ComposioToolProvider] listAllTools failed for query ${JSON.stringify(query)} — returning empty page`,\n err,\n );\n }\n\n const data = rawTools.map(tool => ({\n slug: tool.slug,\n name: tool.name ?? tool.slug,\n description: tool.description,\n toolkit: tool.toolkit?.slug ?? opts.toolkit ?? '',\n }));\n\n return {\n data,\n pagination: {\n page: opts.page ?? 1,\n perPage: limit,\n hasMore: limit !== undefined && rawTools.length >= limit,\n },\n };\n }\n\n // ── runtime ───────────────────────────────────────────────────────────\n\n async resolveToolsVNext(opts: ResolveToolsOpts): Promise<Record<string, ToolAction<any, any, any>>> {\n if (opts.toolSlugs.length === 0) return {};\n\n // For author-bound connections, the runtime fan-out passes the agent's\n // author id explicitly. Use it as the Composio user bucket so the pin\n // resolves for any invoker (not just the original author).\n const internalUserId =\n opts.authorId && opts.authorId.length > 0 ? opts.authorId : resolveInternalUserId(opts.requestContext);\n const composio = this.getMastraClient();\n\n const modifiers = {\n // `connectedAccountId` is not threaded through Composio's `execute`\n // option bag in @composio/mastra; the only documented per-call hook\n // is `beforeExecute`, which receives the params object that flows\n // into the API call. Mutating `params.connectedAccountId` routes\n // the call to a specific account.\n beforeExecute: ({ params }: { params: { connectedAccountId?: string; userId?: string } }) => {\n // Under `caller-supplied` scope the user bucket (`internalUserId`,\n // resolved from the host app's resourceId) already scopes the call to\n // the right tenant. Pinning a specific `connectedAccountId` would defeat\n // Composio's per-user-bucket auto-resolve, so we let Composio pick the\n // connected account within the bucket instead of forcing one.\n if (opts.scope !== 'caller-supplied') {\n params.connectedAccountId = opts.connectionId;\n }\n return params;\n },\n };\n\n const mastraTools = (await composio.tools.get(\n internalUserId,\n { tools: opts.toolSlugs },\n modifiers,\n )) as MastraToolCollection;\n\n const result: Record<string, ToolAction<any, any, any>> = {};\n\n for (const [key, tool] of Object.entries(mastraTools ?? {})) {\n if (!tool) continue;\n const slug = (tool as { id?: string }).id ?? key;\n\n // Composio returns union output schemas (`successful: true | false`) that\n // Mastra's runtime cannot validate; clearing avoids per-tool validation\n // errors at execute time. The property may be non-writable on some SDK\n // versions, so we swallow assignment errors.\n try {\n (tool as unknown as { outputSchema: unknown }).outputSchema = undefined;\n } catch {\n // ignore\n }\n\n const descOverride = opts.toolMeta?.[slug]?.description;\n if (descOverride) {\n try {\n (tool as unknown as { description: string }).description = descOverride;\n } catch {\n // ignore\n }\n }\n\n result[slug] = tool as ToolAction<any, any, any>;\n }\n\n return result;\n }\n\n // ── auth surface ──────────────────────────────────────────────────────\n\n async authorize(opts: AuthorizeOpts): Promise<{ url: string; authId: string }> {\n const composio = this.getRawClient();\n const { id: authConfigId, authScheme } = await this.resolveAuthConfig(opts.toolkit);\n\n // `connectionId` carries the internal user bucket for the runtime fan-out;\n // for authorize we treat it as the Composio `userId` so the new connected\n // account lands under the same bucket as the agent's resolved identity.\n const internalUserId = opts.connectionId || DEFAULT_INTERNAL_USER_ID;\n\n // `config` carries provider-specific user-supplied fields (e.g. Confluence\n // subdomain) collected by the picker via `listConnectionFields`. When it is\n // present we must use `connectedAccounts.initiate`, which accepts a\n // discriminated `{ authScheme, val }` config for programmatic account\n // creation. Composio's non-deprecated `connectedAccounts.link` (hosted\n // Connect Link) has no `config` parameter, so it cannot carry these fields.\n const initiateConfig =\n opts.config && Object.keys(opts.config).length > 0 && authScheme\n ? ({ authScheme, val: opts.config } as unknown as Parameters<\n typeof composio.connectedAccounts.initiate\n >[2] extends infer O\n ? O extends { config?: infer C }\n ? C\n : never\n : never)\n : undefined;\n\n // Prefer `link` for the Composio-managed OAuth redirect flow: `initiate`\n // is deprecated for managed OAuth. `link` allows multiple connected\n // accounts per (user, auth config) by default, so we no longer pass\n // `allowMultiple`. Fall back to `initiate` only when custom `config` fields\n // are supplied, since `link` cannot forward them.\n const request = initiateConfig\n ? await composio.connectedAccounts.initiate(internalUserId, authConfigId, {\n allowMultiple: true,\n config: initiateConfig,\n })\n : await composio.connectedAccounts.link(internalUserId, authConfigId);\n\n if (!request.redirectUrl) {\n throw new Error(`[composio] authorize did not return a redirectUrl for toolkit \"${opts.toolkit}\"`);\n }\n\n return { url: request.redirectUrl, authId: request.id };\n }\n\n async listConnectionFields({ toolkit }: { toolkit: string }): Promise<ConnectionField[]> {\n const composio = this.getRawClient();\n const { authScheme } = await this.resolveAuthConfig(toolkit);\n if (!authScheme) {\n // Without a known auth scheme we can't query the field schema — fall\n // back to no fields rather than blocking the user.\n return [];\n }\n const fields = await composio.toolkits.getConnectedAccountInitiationFields(toolkit, authScheme, {\n requiredOnly: false,\n });\n return fields.map(f => ({\n name: f.name,\n displayName: f.displayName,\n description: f.description,\n type: coerceFieldType(f.type),\n required: f.required ?? false,\n default: f.default ?? undefined,\n }));\n }\n\n async getAuthStatus(authId: string): Promise<AuthFlowStatus> {\n const composio = this.getRawClient();\n const account = await composio.connectedAccounts.get(authId);\n switch (account.status) {\n case 'ACTIVE':\n return 'completed';\n case 'INITIALIZING':\n case 'INITIATED':\n return 'pending';\n case 'FAILED':\n case 'EXPIRED':\n case 'INACTIVE':\n return 'failed';\n default:\n return 'pending';\n }\n }\n\n async getConnectionStatus(opts: {\n items: Array<{ connectionId: string; toolkit: string }>;\n }): Promise<Record<string, { connected: boolean }>> {\n if (opts.items.length === 0) return {};\n\n const composio = this.getRawClient();\n const toolkitSlugs = Array.from(new Set(opts.items.map(i => i.toolkit)));\n\n // One SDK call per `getConnectionStatus`, regardless of N items.\n // Filter by all referenced toolkits, then bucket locally by id.\n const list: ConnectedAccountListResponse = await composio.connectedAccounts.list({\n toolkitSlugs,\n });\n\n const liveById = new Map<string, { status: string; isDisabled: boolean }>();\n for (const item of list.items) {\n liveById.set(item.id, { status: item.status, isDisabled: item.isDisabled });\n }\n\n const result: Record<string, { connected: boolean }> = {};\n for (const { connectionId } of opts.items) {\n const live = liveById.get(connectionId);\n result[connectionId] = { connected: live ? live.status === 'ACTIVE' && !live.isDisabled : false };\n }\n return result;\n }\n\n async listConnections(opts: ListConnectionsOpts): Promise<ListConnectionsResult> {\n const composio = this.getRawClient();\n const page = opts.page ?? 1;\n const perPage = clampLimit(opts.perPage);\n\n // Normalize userIds[] / userId. Empty array = no buckets to list against,\n // short-circuit to avoid an unbounded Composio response.\n const userIds = resolveUserIds(opts);\n if (userIds && userIds.length === 0) {\n return { items: [], pagination: { page, perPage, hasMore: false } };\n }\n\n // Composio SDK 0.6.x uses cursor-based pagination on the wire. We surface\n // page-based pagination to keep the Mastra contract consistent with every\n // other list API. For now we only fetch the first page (page=1); paginated\n // requests for page > 1 are a follow-up — the UI does not yet paginate.\n const list: ConnectedAccountListResponse = await composio.connectedAccounts.list({\n toolkitSlugs: [opts.toolkit],\n ...(userIds ? { userIds } : {}),\n limit: perPage,\n });\n\n // Defensive: tolerate undocumented SDK shape drift where `items` is\n // missing or `nextCursor` is `null`/`undefined`/`''`.\n const items: ExistingConnection[] = (list.items ?? []).map(account => ({\n connectionId: account.id,\n status: mapComposioStatus(account.status, account.isDisabled),\n createdAt: account.createdAt,\n // `user_id` is preserved by the Composio SDK transform via spread but\n // isn't on the typed shape. Read it via a narrow cast.\n authorId: (account as unknown as { user_id?: string }).user_id,\n }));\n\n const nextCursor = (list as { nextCursor?: string | null }).nextCursor ?? null;\n const hasMore = typeof nextCursor === 'string' && nextCursor.length > 0;\n return { items, pagination: { page, perPage, hasMore } };\n }\n\n /**\n * Revoke a Composio connected account via\n * `DELETE /api/v3/connected_accounts/:nanoid`. Composio performs a soft\n * delete and responds with `{ success: boolean }`.\n *\n * Treats a 404 (account already deleted or never existed) as success so\n * the caller can drop its local pin without an error path. A `success:\n * false` response means the provider refused the delete and is surfaced\n * as an error so the caller does not delete its local row.\n */\n async revokeConnection(connectionId: string): Promise<void> {\n const composio = this.getRawClient();\n try {\n const res = (await composio.connectedAccounts.delete(connectionId)) as { success?: boolean } | undefined;\n if (res && res.success === false) {\n throw new Error(`Composio refused to delete connected account ${connectionId} (success=false)`);\n }\n } catch (err) {\n if (isNotFoundError(err)) return;\n throw err;\n }\n }\n\n async getHealth(): Promise<ToolProviderHealth> {\n try {\n const composio = this.getRawClient();\n await composio.toolkits.get({ limit: 1 } as Parameters<typeof composio.toolkits.get>[0]);\n return { ok: true };\n } catch (err) {\n return {\n ok: false,\n message: err instanceof Error ? err.message : 'Composio SDK reachability check failed',\n };\n }\n }\n\n // ── helpers ───────────────────────────────────────────────────────────\n\n /**\n * Resolve the single ENABLED auth config for `toolkit`. Throws if zero\n * or multiple configs match — the admin must enable exactly one in the\n * Composio dashboard before agents can connect.\n */\n private async resolveAuthConfig(toolkit: string): Promise<{ id: string; authScheme?: ComposioAuthScheme }> {\n const composio = this.getRawClient();\n const response = await composio.authConfigs.list({ toolkit });\n const enabled = response.items.filter(item => item.status === 'ENABLED');\n\n if (enabled.length === 0) {\n throw new Error(\n `[composio] No ENABLED auth config for toolkit \"${toolkit}\". Enable one in the Composio dashboard.`,\n );\n }\n if (enabled.length > 1) {\n const ids = enabled.map(item => item.id).join(', ');\n throw new Error(\n `[composio] Multiple ENABLED auth configs for toolkit \"${toolkit}\" (${ids}). Keep exactly one enabled.`,\n );\n }\n return { id: enabled[0]!.id, authScheme: enabled[0]!.authScheme };\n }\n}\n\ntype ComposioAuthScheme = NonNullable<\n Awaited<ReturnType<Composio['authConfigs']['list']>>['items'][number]['authScheme']\n>;\n\n/**\n * Best-effort 404 detection across the various error shapes the Composio\n * SDK surfaces (typed error with `statusCode`, HTTP-like error with\n * `status`, or a plain message containing \"404\" / \"not found\").\n */\nfunction isNotFoundError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as { statusCode?: number; status?: number; message?: string };\n if (e.statusCode === 404 || e.status === 404) return true;\n const msg = typeof e.message === 'string' ? e.message.toLowerCase() : '';\n return msg.includes('not found') || msg.includes('404');\n}\n\n/**\n * Composio reports a free-form `type` string. Map common values to our\n * generic ConnectionField type vocabulary; everything else falls back to\n * `'string'`.\n */\nfunction coerceFieldType(type: string): 'string' | 'number' | 'boolean' {\n switch (type.toLowerCase()) {\n case 'number':\n case 'integer':\n case 'int':\n case 'float':\n return 'number';\n case 'bool':\n case 'boolean':\n return 'boolean';\n default:\n return 'string';\n }\n}\n\n/**\n * Map Composio account status + `isDisabled` to the {@link ExistingConnection}\n * status vocabulary surfaced to the picker UI.\n */\nfunction mapComposioStatus(status: string, isDisabled: boolean): ExistingConnection['status'] {\n if (isDisabled) return 'inactive';\n switch (status) {\n case 'ACTIVE':\n return 'active';\n case 'INITIALIZING':\n case 'INITIATED':\n return 'pending';\n case 'FAILED':\n case 'EXPIRED':\n return 'failed';\n case 'INACTIVE':\n return 'inactive';\n default:\n return 'pending';\n }\n}\n\n// Mirror of `MASTRA_USER_KEY` from `@mastra/server`. Inlined to avoid a\n// reverse dependency from `editor` onto `server`.\nconst MASTRA_USER_KEY = 'mastra__user';\n\n/**\n * Read the internal user id (Composio `userId`) from per-request context.\n *\n * The runtime fan-out is responsible for stamping the agent's resolved\n * author id (or `'default'`) into `requestContext` under\n * {@link MASTRA_RESOURCE_ID_KEY}.\n */\nfunction resolveInternalUserId(requestContext?: Record<string, unknown>): string {\n const resourceId = requestContext?.[MASTRA_RESOURCE_ID_KEY];\n if (typeof resourceId === 'string' && resourceId.length > 0) {\n return resourceId;\n }\n\n const user = requestContext?.[MASTRA_USER_KEY];\n if (user && typeof user === 'object' && 'id' in user) {\n const id = (user as { id: unknown }).id;\n if (typeof id === 'string' && id.length > 0) {\n return id;\n }\n }\n\n return DEFAULT_INTERNAL_USER_ID;\n}\n\n/**\n * Resolve `userIds[]` from `listConnections` opts.\n *\n * - If `userIds` is provided, use it as-is (including empty array, which\n * means \"no buckets to list against\").\n * - If `userId` is provided, normalize to `[userId]`.\n * - Otherwise fall back to the default internal user id (single-bucket).\n */\nfunction resolveUserIds(opts: ListConnectionsOpts): string[] | undefined {\n if (Array.isArray(opts.userIds)) return opts.userIds;\n if (typeof opts.userId === 'string' && opts.userId.length > 0) return [opts.userId];\n return [DEFAULT_INTERNAL_USER_ID];\n}\n\nconst DEFAULT_LIMIT = 50;\nconst MAX_LIMIT = 200;\n\nfunction clampLimit(limit: number | undefined): number {\n if (typeof limit !== 'number' || !Number.isFinite(limit) || limit <= 0) {\n return DEFAULT_LIMIT;\n }\n return Math.min(Math.floor(limit), MAX_LIMIT);\n}\n"],"mappings":"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","names":[]}
package/dist/composio.js CHANGED
@@ -9,7 +9,8 @@ var ComposioToolProvider = class extends BaseToolProvider {
9
9
  constructor(config) {
10
10
  super({
11
11
  allowedToolkits: config.allowedToolkits,
12
- allowedTools: config.allowedTools
12
+ allowedTools: config.allowedTools,
13
+ defaultScope: config.defaultScope
13
14
  });
14
15
  this.info = {
15
16
  id: COMPOSIO_PROVIDER_ID,
@@ -94,7 +95,9 @@ var ComposioToolProvider = class extends BaseToolProvider {
94
95
  // into the API call. Mutating `params.connectedAccountId` routes
95
96
  // the call to a specific account.
96
97
  beforeExecute: ({ params }) => {
97
- params.connectedAccountId = opts.connectionId;
98
+ if (opts.scope !== "caller-supplied") {
99
+ params.connectedAccountId = opts.connectionId;
100
+ }
98
101
  return params;
99
102
  }
100
103
  };
@@ -128,12 +131,12 @@ var ComposioToolProvider = class extends BaseToolProvider {
128
131
  const { id: authConfigId, authScheme } = await this.resolveAuthConfig(opts.toolkit);
129
132
  const internalUserId = opts.connectionId || DEFAULT_INTERNAL_USER_ID;
130
133
  const initiateConfig = opts.config && Object.keys(opts.config).length > 0 && authScheme ? { authScheme, val: opts.config } : void 0;
131
- const request = await composio.connectedAccounts.initiate(internalUserId, authConfigId, {
134
+ const request = initiateConfig ? await composio.connectedAccounts.initiate(internalUserId, authConfigId, {
132
135
  allowMultiple: true,
133
- ...initiateConfig ? { config: initiateConfig } : {}
134
- });
136
+ config: initiateConfig
137
+ }) : await composio.connectedAccounts.link(internalUserId, authConfigId);
135
138
  if (!request.redirectUrl) {
136
- throw new Error(`[composio] initiate did not return a redirectUrl for toolkit "${opts.toolkit}"`);
139
+ throw new Error(`[composio] authorize did not return a redirectUrl for toolkit "${opts.toolkit}"`);
137
140
  }
138
141
  return { url: request.redirectUrl, authId: request.id };
139
142
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/providers/composio.ts"],"sourcesContent":["import type {\n AuthFlowStatus,\n AuthorizeOpts,\n ConnectionField,\n ExistingConnection,\n ListConnectionsOpts,\n ListConnectionsResult,\n ListToolsOpts,\n ListToolsResult,\n ResolveToolsOpts,\n ToolProviderCapabilities,\n ToolProviderHealth,\n ToolProviderInfo,\n ToolProviderToolkit,\n} from '@mastra/core/tool-provider';\nimport { BaseToolProvider } from '@mastra/core/tool-provider';\nimport type { BaseToolProviderOptions } from '@mastra/core/tool-provider';\nimport type { ToolAction } from '@mastra/core/tools';\nimport { MASTRA_RESOURCE_ID_KEY } from '@mastra/core/request-context';\n\nimport { Composio } from '@composio/core';\nimport type {\n ConnectedAccountListResponse,\n Tool as ComposioTool,\n ToolListParams as ComposioToolListParams,\n ToolKitItem,\n} from '@composio/core';\nimport { MastraProvider } from '@composio/mastra';\nimport type { MastraToolCollection } from '@composio/mastra';\n\nexport interface ComposioToolProviderConfig extends BaseToolProviderOptions {\n /** Composio API key. */\n apiKey: string;\n}\n\nconst COMPOSIO_PROVIDER_ID = 'composio' as const;\nconst DEFAULT_INTERNAL_USER_ID = 'default';\n\n/**\n * Composio implementation of the {@link BaseToolProvider} contract.\n *\n * Discovery (`listAllToolkits`, `listAllTools`) uses the raw Composio\n * client. Runtime (`resolveToolsVNext`) uses {@link MastraProvider} so resolved\n * tools are already in `createTool()` shape; each tool gets a\n * `beforeExecute` modifier that injects\n * `connectedAccountId = connectionId`, and `outputSchema` is cleared\n * because Composio returns union schemas that Mastra's runtime rejects.\n *\n * Allowlist filtering is layered by {@link BaseToolProvider}; this class\n * never reads `allowedToolkits` / `allowedTools` directly.\n */\nexport class ComposioToolProvider extends BaseToolProvider {\n readonly info: ToolProviderInfo = {\n id: COMPOSIO_PROVIDER_ID,\n name: 'Composio',\n description: 'Access 10,000+ tools from 150+ apps via Composio',\n };\n readonly capabilities: ToolProviderCapabilities = {\n multipleConnectionsPerToolkit: true,\n batchConnectionStatus: true,\n reauthorizeReusesConnectionId: true,\n supportsRevoke: true,\n };\n\n private readonly apiKey: string;\n private rawClient: Composio | null = null;\n private mastraClient: Composio<MastraProvider> | null = null;\n\n constructor(config: ComposioToolProviderConfig) {\n super({\n allowedToolkits: config.allowedToolkits,\n allowedTools: config.allowedTools,\n });\n this.apiKey = config.apiKey;\n }\n\n // ── client cache ──────────────────────────────────────────────────────\n\n private getRawClient(): Composio {\n if (!this.rawClient) {\n this.rawClient = new Composio({ apiKey: this.apiKey });\n }\n return this.rawClient;\n }\n\n private getMastraClient(): Composio<MastraProvider> {\n if (!this.mastraClient) {\n this.mastraClient = new Composio({\n apiKey: this.apiKey,\n provider: new MastraProvider(),\n });\n }\n return this.mastraClient;\n }\n\n // ── catalog (BaseToolProvider adds allowlist filter on top) ───────────\n\n protected async listAllToolkits(): Promise<ToolProviderToolkit[]> {\n const composio = this.getRawClient();\n const toolkits: ToolKitItem[] = await composio.toolkits.get({});\n return toolkits.map(tk => ({\n slug: tk.slug,\n name: tk.name,\n description: tk.meta?.description,\n icon: tk.meta?.logo,\n }));\n }\n\n protected async listAllTools(opts: ListToolsOpts): Promise<ListToolsResult> {\n const composio = this.getRawClient();\n\n // Composio's `getRawComposioTools` query is a discriminated union — every\n // variant accepts `limit`, but the toolkits/search keys are exclusive in\n // the TS types. We build the variant we need, then cast to the union.\n //\n // When the caller doesn't scope to a specific toolkit, we fall back to\n // the admin allowlist so the SDK returns a flat list across allowed\n // toolkits in a single hop (vs. fanning out per toolkit).\n const limit = opts.perPage;\n const fallbackToolkits = this.allowedToolkits.length > 0 ? [...this.allowedToolkits] : undefined;\n const query: ComposioToolListParams = (\n opts.toolkit\n ? { toolkits: [opts.toolkit], limit, search: opts.search }\n : fallbackToolkits\n ? { toolkits: fallbackToolkits, limit, search: opts.search }\n : opts.search\n ? { search: opts.search, limit }\n : { toolkits: [] as string[], limit }\n ) as ComposioToolListParams;\n\n // Composio's SDK validates every tool's input/output schema against an\n // internal zod shape and throws on the first malformed tool — so one bad\n // toolkit can poison a multi-toolkit query. Treat validation errors as a\n // soft failure and return an empty page rather than a 500.\n let rawTools: ComposioTool[] = [];\n try {\n rawTools = await composio.tools.getRawComposioTools(query);\n } catch (err) {\n console.warn(\n `[ComposioToolProvider] listAllTools failed for query ${JSON.stringify(query)} — returning empty page`,\n err,\n );\n }\n\n const data = rawTools.map(tool => ({\n slug: tool.slug,\n name: tool.name ?? tool.slug,\n description: tool.description,\n toolkit: tool.toolkit?.slug ?? opts.toolkit ?? '',\n }));\n\n return {\n data,\n pagination: {\n page: opts.page ?? 1,\n perPage: limit,\n hasMore: limit !== undefined && rawTools.length >= limit,\n },\n };\n }\n\n // ── runtime ───────────────────────────────────────────────────────────\n\n async resolveToolsVNext(opts: ResolveToolsOpts): Promise<Record<string, ToolAction<any, any, any>>> {\n if (opts.toolSlugs.length === 0) return {};\n\n // For author-bound connections, the runtime fan-out passes the agent's\n // author id explicitly. Use it as the Composio user bucket so the pin\n // resolves for any invoker (not just the original author).\n const internalUserId =\n opts.authorId && opts.authorId.length > 0 ? opts.authorId : resolveInternalUserId(opts.requestContext);\n const composio = this.getMastraClient();\n\n const modifiers = {\n // `connectedAccountId` is not threaded through Composio's `execute`\n // option bag in @composio/mastra; the only documented per-call hook\n // is `beforeExecute`, which receives the params object that flows\n // into the API call. Mutating `params.connectedAccountId` routes\n // the call to a specific account.\n beforeExecute: ({ params }: { params: { connectedAccountId?: string; userId?: string } }) => {\n params.connectedAccountId = opts.connectionId;\n return params;\n },\n };\n\n const mastraTools = (await composio.tools.get(\n internalUserId,\n { tools: opts.toolSlugs },\n modifiers,\n )) as MastraToolCollection;\n\n const result: Record<string, ToolAction<any, any, any>> = {};\n\n for (const [key, tool] of Object.entries(mastraTools ?? {})) {\n if (!tool) continue;\n const slug = (tool as { id?: string }).id ?? key;\n\n // Composio returns union output schemas (`successful: true | false`) that\n // Mastra's runtime cannot validate; clearing avoids per-tool validation\n // errors at execute time. The property may be non-writable on some SDK\n // versions, so we swallow assignment errors.\n try {\n (tool as unknown as { outputSchema: unknown }).outputSchema = undefined;\n } catch {\n // ignore\n }\n\n const descOverride = opts.toolMeta?.[slug]?.description;\n if (descOverride) {\n try {\n (tool as unknown as { description: string }).description = descOverride;\n } catch {\n // ignore\n }\n }\n\n result[slug] = tool as ToolAction<any, any, any>;\n }\n\n return result;\n }\n\n // ── auth surface ──────────────────────────────────────────────────────\n\n async authorize(opts: AuthorizeOpts): Promise<{ url: string; authId: string }> {\n const composio = this.getRawClient();\n const { id: authConfigId, authScheme } = await this.resolveAuthConfig(opts.toolkit);\n\n // `connectionId` carries the internal user bucket for the runtime fan-out;\n // for authorize we treat it as the Composio `userId` so the new connected\n // account lands under the same bucket as the agent's resolved identity.\n const internalUserId = opts.connectionId || DEFAULT_INTERNAL_USER_ID;\n // `allowMultiple: true` — we explicitly support N connected accounts per\n // (user, auth config) and disambiguate at runtime via per-connection labels.\n // `config` carries provider-specific user-supplied fields (e.g. Confluence\n // subdomain) collected by the picker via `listConnectionFields`. Composio\n // expects a discriminated `{ authScheme, val }` shape; we cast through\n // `unknown` because our generic interface keeps it Record-shaped.\n const initiateConfig =\n opts.config && Object.keys(opts.config).length > 0 && authScheme\n ? ({ authScheme, val: opts.config } as unknown as Parameters<\n typeof composio.connectedAccounts.initiate\n >[2] extends infer O\n ? O extends { config?: infer C }\n ? C\n : never\n : never)\n : undefined;\n const request = await composio.connectedAccounts.initiate(internalUserId, authConfigId, {\n allowMultiple: true,\n ...(initiateConfig ? { config: initiateConfig } : {}),\n });\n\n if (!request.redirectUrl) {\n throw new Error(`[composio] initiate did not return a redirectUrl for toolkit \"${opts.toolkit}\"`);\n }\n\n return { url: request.redirectUrl, authId: request.id };\n }\n\n async listConnectionFields({ toolkit }: { toolkit: string }): Promise<ConnectionField[]> {\n const composio = this.getRawClient();\n const { authScheme } = await this.resolveAuthConfig(toolkit);\n if (!authScheme) {\n // Without a known auth scheme we can't query the field schema — fall\n // back to no fields rather than blocking the user.\n return [];\n }\n const fields = await composio.toolkits.getConnectedAccountInitiationFields(toolkit, authScheme, {\n requiredOnly: false,\n });\n return fields.map(f => ({\n name: f.name,\n displayName: f.displayName,\n description: f.description,\n type: coerceFieldType(f.type),\n required: f.required ?? false,\n default: f.default ?? undefined,\n }));\n }\n\n async getAuthStatus(authId: string): Promise<AuthFlowStatus> {\n const composio = this.getRawClient();\n const account = await composio.connectedAccounts.get(authId);\n switch (account.status) {\n case 'ACTIVE':\n return 'completed';\n case 'INITIALIZING':\n case 'INITIATED':\n return 'pending';\n case 'FAILED':\n case 'EXPIRED':\n case 'INACTIVE':\n return 'failed';\n default:\n return 'pending';\n }\n }\n\n async getConnectionStatus(opts: {\n items: Array<{ connectionId: string; toolkit: string }>;\n }): Promise<Record<string, { connected: boolean }>> {\n if (opts.items.length === 0) return {};\n\n const composio = this.getRawClient();\n const toolkitSlugs = Array.from(new Set(opts.items.map(i => i.toolkit)));\n\n // One SDK call per `getConnectionStatus`, regardless of N items.\n // Filter by all referenced toolkits, then bucket locally by id.\n const list: ConnectedAccountListResponse = await composio.connectedAccounts.list({\n toolkitSlugs,\n });\n\n const liveById = new Map<string, { status: string; isDisabled: boolean }>();\n for (const item of list.items) {\n liveById.set(item.id, { status: item.status, isDisabled: item.isDisabled });\n }\n\n const result: Record<string, { connected: boolean }> = {};\n for (const { connectionId } of opts.items) {\n const live = liveById.get(connectionId);\n result[connectionId] = { connected: live ? live.status === 'ACTIVE' && !live.isDisabled : false };\n }\n return result;\n }\n\n async listConnections(opts: ListConnectionsOpts): Promise<ListConnectionsResult> {\n const composio = this.getRawClient();\n const page = opts.page ?? 1;\n const perPage = clampLimit(opts.perPage);\n\n // Normalize userIds[] / userId. Empty array = no buckets to list against,\n // short-circuit to avoid an unbounded Composio response.\n const userIds = resolveUserIds(opts);\n if (userIds && userIds.length === 0) {\n return { items: [], pagination: { page, perPage, hasMore: false } };\n }\n\n // Composio SDK 0.6.x uses cursor-based pagination on the wire. We surface\n // page-based pagination to keep the Mastra contract consistent with every\n // other list API. For now we only fetch the first page (page=1); paginated\n // requests for page > 1 are a follow-up — the UI does not yet paginate.\n const list: ConnectedAccountListResponse = await composio.connectedAccounts.list({\n toolkitSlugs: [opts.toolkit],\n ...(userIds ? { userIds } : {}),\n limit: perPage,\n });\n\n // Defensive: tolerate undocumented SDK shape drift where `items` is\n // missing or `nextCursor` is `null`/`undefined`/`''`.\n const items: ExistingConnection[] = (list.items ?? []).map(account => ({\n connectionId: account.id,\n status: mapComposioStatus(account.status, account.isDisabled),\n createdAt: account.createdAt,\n // `user_id` is preserved by the Composio SDK transform via spread but\n // isn't on the typed shape. Read it via a narrow cast.\n authorId: (account as unknown as { user_id?: string }).user_id,\n }));\n\n const nextCursor = (list as { nextCursor?: string | null }).nextCursor ?? null;\n const hasMore = typeof nextCursor === 'string' && nextCursor.length > 0;\n return { items, pagination: { page, perPage, hasMore } };\n }\n\n /**\n * Revoke a Composio connected account via\n * `DELETE /api/v3/connected_accounts/:nanoid`. Composio performs a soft\n * delete and responds with `{ success: boolean }`.\n *\n * Treats a 404 (account already deleted or never existed) as success so\n * the caller can drop its local pin without an error path. A `success:\n * false` response means the provider refused the delete and is surfaced\n * as an error so the caller does not delete its local row.\n */\n async revokeConnection(connectionId: string): Promise<void> {\n const composio = this.getRawClient();\n try {\n const res = (await composio.connectedAccounts.delete(connectionId)) as { success?: boolean } | undefined;\n if (res && res.success === false) {\n throw new Error(`Composio refused to delete connected account ${connectionId} (success=false)`);\n }\n } catch (err) {\n if (isNotFoundError(err)) return;\n throw err;\n }\n }\n\n async getHealth(): Promise<ToolProviderHealth> {\n try {\n const composio = this.getRawClient();\n await composio.toolkits.get({ limit: 1 } as Parameters<typeof composio.toolkits.get>[0]);\n return { ok: true };\n } catch (err) {\n return {\n ok: false,\n message: err instanceof Error ? err.message : 'Composio SDK reachability check failed',\n };\n }\n }\n\n // ── helpers ───────────────────────────────────────────────────────────\n\n /**\n * Resolve the single ENABLED auth config for `toolkit`. Throws if zero\n * or multiple configs match — the admin must enable exactly one in the\n * Composio dashboard before agents can connect.\n */\n private async resolveAuthConfig(toolkit: string): Promise<{ id: string; authScheme?: ComposioAuthScheme }> {\n const composio = this.getRawClient();\n const response = await composio.authConfigs.list({ toolkit });\n const enabled = response.items.filter(item => item.status === 'ENABLED');\n\n if (enabled.length === 0) {\n throw new Error(\n `[composio] No ENABLED auth config for toolkit \"${toolkit}\". Enable one in the Composio dashboard.`,\n );\n }\n if (enabled.length > 1) {\n const ids = enabled.map(item => item.id).join(', ');\n throw new Error(\n `[composio] Multiple ENABLED auth configs for toolkit \"${toolkit}\" (${ids}). Keep exactly one enabled.`,\n );\n }\n return { id: enabled[0]!.id, authScheme: enabled[0]!.authScheme };\n }\n}\n\ntype ComposioAuthScheme = NonNullable<\n Awaited<ReturnType<Composio['authConfigs']['list']>>['items'][number]['authScheme']\n>;\n\n/**\n * Best-effort 404 detection across the various error shapes the Composio\n * SDK surfaces (typed error with `statusCode`, HTTP-like error with\n * `status`, or a plain message containing \"404\" / \"not found\").\n */\nfunction isNotFoundError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as { statusCode?: number; status?: number; message?: string };\n if (e.statusCode === 404 || e.status === 404) return true;\n const msg = typeof e.message === 'string' ? e.message.toLowerCase() : '';\n return msg.includes('not found') || msg.includes('404');\n}\n\n/**\n * Composio reports a free-form `type` string. Map common values to our\n * generic ConnectionField type vocabulary; everything else falls back to\n * `'string'`.\n */\nfunction coerceFieldType(type: string): 'string' | 'number' | 'boolean' {\n switch (type.toLowerCase()) {\n case 'number':\n case 'integer':\n case 'int':\n case 'float':\n return 'number';\n case 'bool':\n case 'boolean':\n return 'boolean';\n default:\n return 'string';\n }\n}\n\n/**\n * Map Composio account status + `isDisabled` to the {@link ExistingConnection}\n * status vocabulary surfaced to the picker UI.\n */\nfunction mapComposioStatus(status: string, isDisabled: boolean): ExistingConnection['status'] {\n if (isDisabled) return 'inactive';\n switch (status) {\n case 'ACTIVE':\n return 'active';\n case 'INITIALIZING':\n case 'INITIATED':\n return 'pending';\n case 'FAILED':\n case 'EXPIRED':\n return 'failed';\n case 'INACTIVE':\n return 'inactive';\n default:\n return 'pending';\n }\n}\n\n// Mirror of `MASTRA_USER_KEY` from `@mastra/server`. Inlined to avoid a\n// reverse dependency from `editor` onto `server`.\nconst MASTRA_USER_KEY = 'mastra__user';\n\n/**\n * Read the internal user id (Composio `userId`) from per-request context.\n *\n * The runtime fan-out is responsible for stamping the agent's resolved\n * author id (or `'default'`) into `requestContext` under\n * {@link MASTRA_RESOURCE_ID_KEY}.\n */\nfunction resolveInternalUserId(requestContext?: Record<string, unknown>): string {\n const resourceId = requestContext?.[MASTRA_RESOURCE_ID_KEY];\n if (typeof resourceId === 'string' && resourceId.length > 0) {\n return resourceId;\n }\n\n const user = requestContext?.[MASTRA_USER_KEY];\n if (user && typeof user === 'object' && 'id' in user) {\n const id = (user as { id: unknown }).id;\n if (typeof id === 'string' && id.length > 0) {\n return id;\n }\n }\n\n return DEFAULT_INTERNAL_USER_ID;\n}\n\n/**\n * Resolve `userIds[]` from `listConnections` opts.\n *\n * - If `userIds` is provided, use it as-is (including empty array, which\n * means \"no buckets to list against\").\n * - If `userId` is provided, normalize to `[userId]`.\n * - Otherwise fall back to the default internal user id (single-bucket).\n */\nfunction resolveUserIds(opts: ListConnectionsOpts): string[] | undefined {\n if (Array.isArray(opts.userIds)) return opts.userIds;\n if (typeof opts.userId === 'string' && opts.userId.length > 0) return [opts.userId];\n return [DEFAULT_INTERNAL_USER_ID];\n}\n\nconst DEFAULT_LIMIT = 50;\nconst MAX_LIMIT = 200;\n\nfunction clampLimit(limit: number | undefined): number {\n if (typeof limit !== 'number' || !Number.isFinite(limit) || limit <= 0) {\n return DEFAULT_LIMIT;\n }\n return Math.min(Math.floor(limit), MAX_LIMIT);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/providers/composio.ts"],"sourcesContent":["import type {\n AuthFlowStatus,\n AuthorizeOpts,\n ConnectionField,\n ExistingConnection,\n ListConnectionsOpts,\n ListConnectionsResult,\n ListToolsOpts,\n ListToolsResult,\n ResolveToolsOpts,\n ToolProviderCapabilities,\n ToolProviderHealth,\n ToolProviderInfo,\n ToolProviderToolkit,\n} from '@mastra/core/tool-provider';\nimport { BaseToolProvider } from '@mastra/core/tool-provider';\nimport type { BaseToolProviderOptions } from '@mastra/core/tool-provider';\nimport type { ToolAction } from '@mastra/core/tools';\nimport { MASTRA_RESOURCE_ID_KEY } from '@mastra/core/request-context';\n\nimport { Composio } from '@composio/core';\nimport type {\n ConnectedAccountListResponse,\n Tool as ComposioTool,\n ToolListParams as ComposioToolListParams,\n ToolKitItem,\n} from '@composio/core';\nimport { MastraProvider } from '@composio/mastra';\nimport type { MastraToolCollection } from '@composio/mastra';\n\nexport interface ComposioToolProviderConfig extends BaseToolProviderOptions {\n /** Composio API key. */\n apiKey: string;\n}\n\nconst COMPOSIO_PROVIDER_ID = 'composio' as const;\nconst DEFAULT_INTERNAL_USER_ID = 'default';\n\n/**\n * Composio implementation of the {@link BaseToolProvider} contract.\n *\n * Discovery (`listAllToolkits`, `listAllTools`) uses the raw Composio\n * client. Runtime (`resolveToolsVNext`) uses {@link MastraProvider} so resolved\n * tools are already in `createTool()` shape; each tool gets a\n * `beforeExecute` modifier that injects\n * `connectedAccountId = connectionId`, and `outputSchema` is cleared\n * because Composio returns union schemas that Mastra's runtime rejects.\n *\n * Allowlist filtering is layered by {@link BaseToolProvider}; this class\n * never reads `allowedToolkits` / `allowedTools` directly.\n */\nexport class ComposioToolProvider extends BaseToolProvider {\n readonly info: ToolProviderInfo = {\n id: COMPOSIO_PROVIDER_ID,\n name: 'Composio',\n description: 'Access 10,000+ tools from 150+ apps via Composio',\n };\n readonly capabilities: ToolProviderCapabilities = {\n multipleConnectionsPerToolkit: true,\n batchConnectionStatus: true,\n reauthorizeReusesConnectionId: true,\n supportsRevoke: true,\n };\n\n private readonly apiKey: string;\n private rawClient: Composio | null = null;\n private mastraClient: Composio<MastraProvider> | null = null;\n\n constructor(config: ComposioToolProviderConfig) {\n super({\n allowedToolkits: config.allowedToolkits,\n allowedTools: config.allowedTools,\n defaultScope: config.defaultScope,\n });\n this.apiKey = config.apiKey;\n }\n\n // ── client cache ──────────────────────────────────────────────────────\n\n private getRawClient(): Composio {\n if (!this.rawClient) {\n this.rawClient = new Composio({ apiKey: this.apiKey });\n }\n return this.rawClient;\n }\n\n private getMastraClient(): Composio<MastraProvider> {\n if (!this.mastraClient) {\n this.mastraClient = new Composio({\n apiKey: this.apiKey,\n provider: new MastraProvider(),\n });\n }\n return this.mastraClient;\n }\n\n // ── catalog (BaseToolProvider adds allowlist filter on top) ───────────\n\n protected async listAllToolkits(): Promise<ToolProviderToolkit[]> {\n const composio = this.getRawClient();\n const toolkits: ToolKitItem[] = await composio.toolkits.get({});\n return toolkits.map(tk => ({\n slug: tk.slug,\n name: tk.name,\n description: tk.meta?.description,\n icon: tk.meta?.logo,\n }));\n }\n\n protected async listAllTools(opts: ListToolsOpts): Promise<ListToolsResult> {\n const composio = this.getRawClient();\n\n // Composio's `getRawComposioTools` query is a discriminated union — every\n // variant accepts `limit`, but the toolkits/search keys are exclusive in\n // the TS types. We build the variant we need, then cast to the union.\n //\n // When the caller doesn't scope to a specific toolkit, we fall back to\n // the admin allowlist so the SDK returns a flat list across allowed\n // toolkits in a single hop (vs. fanning out per toolkit).\n const limit = opts.perPage;\n const fallbackToolkits = this.allowedToolkits.length > 0 ? [...this.allowedToolkits] : undefined;\n const query: ComposioToolListParams = (\n opts.toolkit\n ? { toolkits: [opts.toolkit], limit, search: opts.search }\n : fallbackToolkits\n ? { toolkits: fallbackToolkits, limit, search: opts.search }\n : opts.search\n ? { search: opts.search, limit }\n : { toolkits: [] as string[], limit }\n ) as ComposioToolListParams;\n\n // Composio's SDK validates every tool's input/output schema against an\n // internal zod shape and throws on the first malformed tool — so one bad\n // toolkit can poison a multi-toolkit query. Treat validation errors as a\n // soft failure and return an empty page rather than a 500.\n let rawTools: ComposioTool[] = [];\n try {\n rawTools = await composio.tools.getRawComposioTools(query);\n } catch (err) {\n console.warn(\n `[ComposioToolProvider] listAllTools failed for query ${JSON.stringify(query)} — returning empty page`,\n err,\n );\n }\n\n const data = rawTools.map(tool => ({\n slug: tool.slug,\n name: tool.name ?? tool.slug,\n description: tool.description,\n toolkit: tool.toolkit?.slug ?? opts.toolkit ?? '',\n }));\n\n return {\n data,\n pagination: {\n page: opts.page ?? 1,\n perPage: limit,\n hasMore: limit !== undefined && rawTools.length >= limit,\n },\n };\n }\n\n // ── runtime ───────────────────────────────────────────────────────────\n\n async resolveToolsVNext(opts: ResolveToolsOpts): Promise<Record<string, ToolAction<any, any, any>>> {\n if (opts.toolSlugs.length === 0) return {};\n\n // For author-bound connections, the runtime fan-out passes the agent's\n // author id explicitly. Use it as the Composio user bucket so the pin\n // resolves for any invoker (not just the original author).\n const internalUserId =\n opts.authorId && opts.authorId.length > 0 ? opts.authorId : resolveInternalUserId(opts.requestContext);\n const composio = this.getMastraClient();\n\n const modifiers = {\n // `connectedAccountId` is not threaded through Composio's `execute`\n // option bag in @composio/mastra; the only documented per-call hook\n // is `beforeExecute`, which receives the params object that flows\n // into the API call. Mutating `params.connectedAccountId` routes\n // the call to a specific account.\n beforeExecute: ({ params }: { params: { connectedAccountId?: string; userId?: string } }) => {\n // Under `caller-supplied` scope the user bucket (`internalUserId`,\n // resolved from the host app's resourceId) already scopes the call to\n // the right tenant. Pinning a specific `connectedAccountId` would defeat\n // Composio's per-user-bucket auto-resolve, so we let Composio pick the\n // connected account within the bucket instead of forcing one.\n if (opts.scope !== 'caller-supplied') {\n params.connectedAccountId = opts.connectionId;\n }\n return params;\n },\n };\n\n const mastraTools = (await composio.tools.get(\n internalUserId,\n { tools: opts.toolSlugs },\n modifiers,\n )) as MastraToolCollection;\n\n const result: Record<string, ToolAction<any, any, any>> = {};\n\n for (const [key, tool] of Object.entries(mastraTools ?? {})) {\n if (!tool) continue;\n const slug = (tool as { id?: string }).id ?? key;\n\n // Composio returns union output schemas (`successful: true | false`) that\n // Mastra's runtime cannot validate; clearing avoids per-tool validation\n // errors at execute time. The property may be non-writable on some SDK\n // versions, so we swallow assignment errors.\n try {\n (tool as unknown as { outputSchema: unknown }).outputSchema = undefined;\n } catch {\n // ignore\n }\n\n const descOverride = opts.toolMeta?.[slug]?.description;\n if (descOverride) {\n try {\n (tool as unknown as { description: string }).description = descOverride;\n } catch {\n // ignore\n }\n }\n\n result[slug] = tool as ToolAction<any, any, any>;\n }\n\n return result;\n }\n\n // ── auth surface ──────────────────────────────────────────────────────\n\n async authorize(opts: AuthorizeOpts): Promise<{ url: string; authId: string }> {\n const composio = this.getRawClient();\n const { id: authConfigId, authScheme } = await this.resolveAuthConfig(opts.toolkit);\n\n // `connectionId` carries the internal user bucket for the runtime fan-out;\n // for authorize we treat it as the Composio `userId` so the new connected\n // account lands under the same bucket as the agent's resolved identity.\n const internalUserId = opts.connectionId || DEFAULT_INTERNAL_USER_ID;\n\n // `config` carries provider-specific user-supplied fields (e.g. Confluence\n // subdomain) collected by the picker via `listConnectionFields`. When it is\n // present we must use `connectedAccounts.initiate`, which accepts a\n // discriminated `{ authScheme, val }` config for programmatic account\n // creation. Composio's non-deprecated `connectedAccounts.link` (hosted\n // Connect Link) has no `config` parameter, so it cannot carry these fields.\n const initiateConfig =\n opts.config && Object.keys(opts.config).length > 0 && authScheme\n ? ({ authScheme, val: opts.config } as unknown as Parameters<\n typeof composio.connectedAccounts.initiate\n >[2] extends infer O\n ? O extends { config?: infer C }\n ? C\n : never\n : never)\n : undefined;\n\n // Prefer `link` for the Composio-managed OAuth redirect flow: `initiate`\n // is deprecated for managed OAuth. `link` allows multiple connected\n // accounts per (user, auth config) by default, so we no longer pass\n // `allowMultiple`. Fall back to `initiate` only when custom `config` fields\n // are supplied, since `link` cannot forward them.\n const request = initiateConfig\n ? await composio.connectedAccounts.initiate(internalUserId, authConfigId, {\n allowMultiple: true,\n config: initiateConfig,\n })\n : await composio.connectedAccounts.link(internalUserId, authConfigId);\n\n if (!request.redirectUrl) {\n throw new Error(`[composio] authorize did not return a redirectUrl for toolkit \"${opts.toolkit}\"`);\n }\n\n return { url: request.redirectUrl, authId: request.id };\n }\n\n async listConnectionFields({ toolkit }: { toolkit: string }): Promise<ConnectionField[]> {\n const composio = this.getRawClient();\n const { authScheme } = await this.resolveAuthConfig(toolkit);\n if (!authScheme) {\n // Without a known auth scheme we can't query the field schema — fall\n // back to no fields rather than blocking the user.\n return [];\n }\n const fields = await composio.toolkits.getConnectedAccountInitiationFields(toolkit, authScheme, {\n requiredOnly: false,\n });\n return fields.map(f => ({\n name: f.name,\n displayName: f.displayName,\n description: f.description,\n type: coerceFieldType(f.type),\n required: f.required ?? false,\n default: f.default ?? undefined,\n }));\n }\n\n async getAuthStatus(authId: string): Promise<AuthFlowStatus> {\n const composio = this.getRawClient();\n const account = await composio.connectedAccounts.get(authId);\n switch (account.status) {\n case 'ACTIVE':\n return 'completed';\n case 'INITIALIZING':\n case 'INITIATED':\n return 'pending';\n case 'FAILED':\n case 'EXPIRED':\n case 'INACTIVE':\n return 'failed';\n default:\n return 'pending';\n }\n }\n\n async getConnectionStatus(opts: {\n items: Array<{ connectionId: string; toolkit: string }>;\n }): Promise<Record<string, { connected: boolean }>> {\n if (opts.items.length === 0) return {};\n\n const composio = this.getRawClient();\n const toolkitSlugs = Array.from(new Set(opts.items.map(i => i.toolkit)));\n\n // One SDK call per `getConnectionStatus`, regardless of N items.\n // Filter by all referenced toolkits, then bucket locally by id.\n const list: ConnectedAccountListResponse = await composio.connectedAccounts.list({\n toolkitSlugs,\n });\n\n const liveById = new Map<string, { status: string; isDisabled: boolean }>();\n for (const item of list.items) {\n liveById.set(item.id, { status: item.status, isDisabled: item.isDisabled });\n }\n\n const result: Record<string, { connected: boolean }> = {};\n for (const { connectionId } of opts.items) {\n const live = liveById.get(connectionId);\n result[connectionId] = { connected: live ? live.status === 'ACTIVE' && !live.isDisabled : false };\n }\n return result;\n }\n\n async listConnections(opts: ListConnectionsOpts): Promise<ListConnectionsResult> {\n const composio = this.getRawClient();\n const page = opts.page ?? 1;\n const perPage = clampLimit(opts.perPage);\n\n // Normalize userIds[] / userId. Empty array = no buckets to list against,\n // short-circuit to avoid an unbounded Composio response.\n const userIds = resolveUserIds(opts);\n if (userIds && userIds.length === 0) {\n return { items: [], pagination: { page, perPage, hasMore: false } };\n }\n\n // Composio SDK 0.6.x uses cursor-based pagination on the wire. We surface\n // page-based pagination to keep the Mastra contract consistent with every\n // other list API. For now we only fetch the first page (page=1); paginated\n // requests for page > 1 are a follow-up — the UI does not yet paginate.\n const list: ConnectedAccountListResponse = await composio.connectedAccounts.list({\n toolkitSlugs: [opts.toolkit],\n ...(userIds ? { userIds } : {}),\n limit: perPage,\n });\n\n // Defensive: tolerate undocumented SDK shape drift where `items` is\n // missing or `nextCursor` is `null`/`undefined`/`''`.\n const items: ExistingConnection[] = (list.items ?? []).map(account => ({\n connectionId: account.id,\n status: mapComposioStatus(account.status, account.isDisabled),\n createdAt: account.createdAt,\n // `user_id` is preserved by the Composio SDK transform via spread but\n // isn't on the typed shape. Read it via a narrow cast.\n authorId: (account as unknown as { user_id?: string }).user_id,\n }));\n\n const nextCursor = (list as { nextCursor?: string | null }).nextCursor ?? null;\n const hasMore = typeof nextCursor === 'string' && nextCursor.length > 0;\n return { items, pagination: { page, perPage, hasMore } };\n }\n\n /**\n * Revoke a Composio connected account via\n * `DELETE /api/v3/connected_accounts/:nanoid`. Composio performs a soft\n * delete and responds with `{ success: boolean }`.\n *\n * Treats a 404 (account already deleted or never existed) as success so\n * the caller can drop its local pin without an error path. A `success:\n * false` response means the provider refused the delete and is surfaced\n * as an error so the caller does not delete its local row.\n */\n async revokeConnection(connectionId: string): Promise<void> {\n const composio = this.getRawClient();\n try {\n const res = (await composio.connectedAccounts.delete(connectionId)) as { success?: boolean } | undefined;\n if (res && res.success === false) {\n throw new Error(`Composio refused to delete connected account ${connectionId} (success=false)`);\n }\n } catch (err) {\n if (isNotFoundError(err)) return;\n throw err;\n }\n }\n\n async getHealth(): Promise<ToolProviderHealth> {\n try {\n const composio = this.getRawClient();\n await composio.toolkits.get({ limit: 1 } as Parameters<typeof composio.toolkits.get>[0]);\n return { ok: true };\n } catch (err) {\n return {\n ok: false,\n message: err instanceof Error ? err.message : 'Composio SDK reachability check failed',\n };\n }\n }\n\n // ── helpers ───────────────────────────────────────────────────────────\n\n /**\n * Resolve the single ENABLED auth config for `toolkit`. Throws if zero\n * or multiple configs match — the admin must enable exactly one in the\n * Composio dashboard before agents can connect.\n */\n private async resolveAuthConfig(toolkit: string): Promise<{ id: string; authScheme?: ComposioAuthScheme }> {\n const composio = this.getRawClient();\n const response = await composio.authConfigs.list({ toolkit });\n const enabled = response.items.filter(item => item.status === 'ENABLED');\n\n if (enabled.length === 0) {\n throw new Error(\n `[composio] No ENABLED auth config for toolkit \"${toolkit}\". Enable one in the Composio dashboard.`,\n );\n }\n if (enabled.length > 1) {\n const ids = enabled.map(item => item.id).join(', ');\n throw new Error(\n `[composio] Multiple ENABLED auth configs for toolkit \"${toolkit}\" (${ids}). Keep exactly one enabled.`,\n );\n }\n return { id: enabled[0]!.id, authScheme: enabled[0]!.authScheme };\n }\n}\n\ntype ComposioAuthScheme = NonNullable<\n Awaited<ReturnType<Composio['authConfigs']['list']>>['items'][number]['authScheme']\n>;\n\n/**\n * Best-effort 404 detection across the various error shapes the Composio\n * SDK surfaces (typed error with `statusCode`, HTTP-like error with\n * `status`, or a plain message containing \"404\" / \"not found\").\n */\nfunction isNotFoundError(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const e = err as { statusCode?: number; status?: number; message?: string };\n if (e.statusCode === 404 || e.status === 404) return true;\n const msg = typeof e.message === 'string' ? e.message.toLowerCase() : '';\n return msg.includes('not found') || msg.includes('404');\n}\n\n/**\n * Composio reports a free-form `type` string. Map common values to our\n * generic ConnectionField type vocabulary; everything else falls back to\n * `'string'`.\n */\nfunction coerceFieldType(type: string): 'string' | 'number' | 'boolean' {\n switch (type.toLowerCase()) {\n case 'number':\n case 'integer':\n case 'int':\n case 'float':\n return 'number';\n case 'bool':\n case 'boolean':\n return 'boolean';\n default:\n return 'string';\n }\n}\n\n/**\n * Map Composio account status + `isDisabled` to the {@link ExistingConnection}\n * status vocabulary surfaced to the picker UI.\n */\nfunction mapComposioStatus(status: string, isDisabled: boolean): ExistingConnection['status'] {\n if (isDisabled) return 'inactive';\n switch (status) {\n case 'ACTIVE':\n return 'active';\n case 'INITIALIZING':\n case 'INITIATED':\n return 'pending';\n case 'FAILED':\n case 'EXPIRED':\n return 'failed';\n case 'INACTIVE':\n return 'inactive';\n default:\n return 'pending';\n }\n}\n\n// Mirror of `MASTRA_USER_KEY` from `@mastra/server`. Inlined to avoid a\n// reverse dependency from `editor` onto `server`.\nconst MASTRA_USER_KEY = 'mastra__user';\n\n/**\n * Read the internal user id (Composio `userId`) from per-request context.\n *\n * The runtime fan-out is responsible for stamping the agent's resolved\n * author id (or `'default'`) into `requestContext` under\n * {@link MASTRA_RESOURCE_ID_KEY}.\n */\nfunction resolveInternalUserId(requestContext?: Record<string, unknown>): string {\n const resourceId = requestContext?.[MASTRA_RESOURCE_ID_KEY];\n if (typeof resourceId === 'string' && resourceId.length > 0) {\n return resourceId;\n }\n\n const user = requestContext?.[MASTRA_USER_KEY];\n if (user && typeof user === 'object' && 'id' in user) {\n const id = (user as { id: unknown }).id;\n if (typeof id === 'string' && id.length > 0) {\n return id;\n }\n }\n\n return DEFAULT_INTERNAL_USER_ID;\n}\n\n/**\n * Resolve `userIds[]` from `listConnections` opts.\n *\n * - If `userIds` is provided, use it as-is (including empty array, which\n * means \"no buckets to list against\").\n * - If `userId` is provided, normalize to `[userId]`.\n * - Otherwise fall back to the default internal user id (single-bucket).\n */\nfunction resolveUserIds(opts: ListConnectionsOpts): string[] | undefined {\n if (Array.isArray(opts.userIds)) return opts.userIds;\n if (typeof opts.userId === 'string' && opts.userId.length > 0) return [opts.userId];\n return [DEFAULT_INTERNAL_USER_ID];\n}\n\nconst DEFAULT_LIMIT = 50;\nconst MAX_LIMIT = 200;\n\nfunction clampLimit(limit: number | undefined): number {\n if (typeof limit !== 'number' || !Number.isFinite(limit) || limit <= 0) {\n return DEFAULT_LIMIT;\n }\n return Math.min(Math.floor(limit), MAX_LIMIT);\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/editor",
3
- "version": "0.13.7-alpha.2",
3
+ "version": "0.13.7-alpha.4",
4
4
  "description": "Mastra Editor for agent management and instantiation",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
@@ -75,7 +75,7 @@
75
75
  "@arcadeai/arcadejs": "^2.4.1",
76
76
  "@composio/core": "^0.6.5",
77
77
  "@composio/mastra": "^0.6.5",
78
- "@mastra/memory": "1.23.0-alpha.2",
78
+ "@mastra/memory": "1.23.0-alpha.3",
79
79
  "@mastra/schema-compat": "1.3.4-alpha.1"
80
80
  },
81
81
  "devDependencies": {
@@ -87,12 +87,12 @@
87
87
  "vitest": "4.1.9",
88
88
  "zod": "^3.25.76",
89
89
  "@internal/ai-sdk-v4": "0.0.60",
90
- "@internal/ai-sdk-v5": "0.0.60",
91
90
  "@internal/ai-v6": "0.0.60",
92
- "@mastra/core": "1.51.0-alpha.2",
93
- "@mastra/hono": "1.5.7-alpha.2",
91
+ "@internal/ai-sdk-v5": "0.0.60",
94
92
  "@mastra/libsql": "1.16.0-alpha.0",
95
- "@mastra/mcp": "1.13.1"
93
+ "@mastra/core": "1.51.0-alpha.5",
94
+ "@mastra/mcp": "1.14.0-alpha.0",
95
+ "@mastra/hono": "1.5.7-alpha.5"
96
96
  },
97
97
  "peerDependencies": {
98
98
  "@mastra/core": ">=1.34.0-0 <2.0.0-0",