@mastra/editor 0.10.2-alpha.1 → 0.11.0-alpha.3

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.
@@ -1,59 +1,70 @@
1
- import { ToolProvider, ToolProviderInfo, ToolProviderListResult, ToolProviderToolkit, ListToolProviderToolsOptions, ToolProviderToolInfo, ResolveToolProviderToolsOptions } from '@mastra/core/tool-provider';
1
+ import { BaseToolProvider, ToolProviderInfo, ToolProviderCapabilities, BaseToolProviderOptions, ToolProviderToolkit, ListToolsOpts, ListToolsResult, ResolveToolsOpts, AuthorizeOpts, ConnectionField, AuthFlowStatus, ListConnectionsOpts, ListConnectionsResult, ToolProviderHealth } from '@mastra/core/tool-provider';
2
2
  import { ToolAction } from '@mastra/core/tools';
3
- import { StorageToolConfig } from '@mastra/core/storage';
4
3
 
5
- interface ComposioToolProviderConfig {
6
- /** Composio API key */
4
+ interface ComposioToolProviderConfig extends BaseToolProviderOptions {
5
+ /** Composio API key. */
7
6
  apiKey: string;
8
7
  }
9
8
  /**
10
- * Composio tool provider adapter.
9
+ * Composio implementation of the {@link BaseToolProvider} contract.
11
10
  *
12
- * Uses `@composio/core` + `@composio/mastra` SDKs for both tool discovery
13
- * and runtime resolution. Both packages are optional peer dependencies and
14
- * tree-shaken if this provider class isn't imported.
11
+ * Discovery (`listAllToolkits`, `listAllTools`) uses the raw Composio
12
+ * client. Runtime (`resolveToolsVNext`) uses {@link MastraProvider} so resolved
13
+ * tools are already in `createTool()` shape; each tool gets a
14
+ * `beforeExecute` modifier that injects
15
+ * `connectedAccountId = connectionId`, and `outputSchema` is cleared
16
+ * because Composio returns union schemas that Mastra's runtime rejects.
15
17
  *
16
- * Discovery methods (`listToolkits`, `listTools`, `getToolSchema`) use the
17
- * raw Composio client (no userId required).
18
- *
19
- * Runtime method (`resolveTools`) uses the MastraProvider so returned tools are
20
- * already in Mastra's `createTool()` format.
18
+ * Allowlist filtering is layered by {@link BaseToolProvider}; this class
19
+ * never reads `allowedToolkits` / `allowedTools` directly.
21
20
  */
22
- declare class ComposioToolProvider implements ToolProvider {
21
+ declare class ComposioToolProvider extends BaseToolProvider {
23
22
  readonly info: ToolProviderInfo;
24
- private apiKey;
23
+ readonly capabilities: ToolProviderCapabilities;
24
+ private readonly apiKey;
25
25
  private rawClient;
26
26
  private mastraClient;
27
27
  constructor(config: ComposioToolProviderConfig);
28
- /**
29
- * Get or create a raw Composio client (no provider — for discovery only).
30
- */
31
28
  private getRawClient;
32
- /**
33
- * Get or create a Composio client with MastraProvider (for runtime tools).
34
- */
35
29
  private getMastraClient;
30
+ protected listAllToolkits(): Promise<ToolProviderToolkit[]>;
31
+ protected listAllTools(opts: ListToolsOpts): Promise<ListToolsResult>;
32
+ resolveToolsVNext(opts: ResolveToolsOpts): Promise<Record<string, ToolAction<any, any, any>>>;
33
+ authorize(opts: AuthorizeOpts): Promise<{
34
+ url: string;
35
+ authId: string;
36
+ }>;
37
+ listConnectionFields({ toolkit }: {
38
+ toolkit: string;
39
+ }): Promise<ConnectionField[]>;
40
+ getAuthStatus(authId: string): Promise<AuthFlowStatus>;
41
+ getConnectionStatus(opts: {
42
+ items: Array<{
43
+ connectionId: string;
44
+ toolkit: string;
45
+ }>;
46
+ }): Promise<Record<string, {
47
+ connected: boolean;
48
+ }>>;
49
+ listConnections(opts: ListConnectionsOpts): Promise<ListConnectionsResult>;
36
50
  /**
37
- * List available toolkits via `composio.toolkits.get({})`.
38
- * Returns: `ToolKitListResponse` an array of `{ slug, name, meta: { description, logo, ... } }`.
39
- */
40
- listToolkits(): Promise<ToolProviderListResult<ToolProviderToolkit>>;
41
- /**
42
- * List available tools via `composio.tools.getRawComposioTools()`.
43
- * No userId required returns raw tool definitions for UI browsing.
44
- */
45
- listTools(options?: ListToolProviderToolsOptions): Promise<ToolProviderListResult<ToolProviderToolInfo>>;
46
- /**
47
- * Get JSON schema for a specific tool via `composio.tools.getRawComposioToolBySlug()`.
51
+ * Revoke a Composio connected account via
52
+ * `DELETE /api/v3/connected_accounts/:nanoid`. Composio performs a soft
53
+ * delete and responds with `{ success: boolean }`.
54
+ *
55
+ * Treats a 404 (account already deleted or never existed) as success so
56
+ * the caller can drop its local pin without an error path. A `success:
57
+ * false` response means the provider refused the delete and is surfaced
58
+ * as an error so the caller does not delete its local row.
48
59
  */
49
- getToolSchema(toolSlug: string): Promise<Record<string, unknown> | null>;
60
+ revokeConnection(connectionId: string): Promise<void>;
61
+ getHealth(): Promise<ToolProviderHealth>;
50
62
  /**
51
- * Resolve executable tools in Mastra format via `composio.tools.get(userId, { tools: [...] })`.
52
- *
53
- * Uses MastraProvider so returned tools are `ReturnType<typeof createTool>` — compatible
54
- * with Mastra's `ToolAction` interface.
63
+ * Resolve the single ENABLED auth config for `toolkit`. Throws if zero
64
+ * or multiple configs match — the admin must enable exactly one in the
65
+ * Composio dashboard before agents can connect.
55
66
  */
56
- resolveTools(toolSlugs: string[], toolConfigs?: Record<string, StorageToolConfig>, options?: ResolveToolProviderToolsOptions): Promise<Record<string, ToolAction<unknown, unknown>>>;
67
+ private resolveAuthConfig;
57
68
  }
58
69
 
59
70
  export { ComposioToolProvider, type ComposioToolProviderConfig };
@@ -1,59 +1,70 @@
1
- import { ToolProvider, ToolProviderInfo, ToolProviderListResult, ToolProviderToolkit, ListToolProviderToolsOptions, ToolProviderToolInfo, ResolveToolProviderToolsOptions } from '@mastra/core/tool-provider';
1
+ import { BaseToolProvider, ToolProviderInfo, ToolProviderCapabilities, BaseToolProviderOptions, ToolProviderToolkit, ListToolsOpts, ListToolsResult, ResolveToolsOpts, AuthorizeOpts, ConnectionField, AuthFlowStatus, ListConnectionsOpts, ListConnectionsResult, ToolProviderHealth } from '@mastra/core/tool-provider';
2
2
  import { ToolAction } from '@mastra/core/tools';
3
- import { StorageToolConfig } from '@mastra/core/storage';
4
3
 
5
- interface ComposioToolProviderConfig {
6
- /** Composio API key */
4
+ interface ComposioToolProviderConfig extends BaseToolProviderOptions {
5
+ /** Composio API key. */
7
6
  apiKey: string;
8
7
  }
9
8
  /**
10
- * Composio tool provider adapter.
9
+ * Composio implementation of the {@link BaseToolProvider} contract.
11
10
  *
12
- * Uses `@composio/core` + `@composio/mastra` SDKs for both tool discovery
13
- * and runtime resolution. Both packages are optional peer dependencies and
14
- * tree-shaken if this provider class isn't imported.
11
+ * Discovery (`listAllToolkits`, `listAllTools`) uses the raw Composio
12
+ * client. Runtime (`resolveToolsVNext`) uses {@link MastraProvider} so resolved
13
+ * tools are already in `createTool()` shape; each tool gets a
14
+ * `beforeExecute` modifier that injects
15
+ * `connectedAccountId = connectionId`, and `outputSchema` is cleared
16
+ * because Composio returns union schemas that Mastra's runtime rejects.
15
17
  *
16
- * Discovery methods (`listToolkits`, `listTools`, `getToolSchema`) use the
17
- * raw Composio client (no userId required).
18
- *
19
- * Runtime method (`resolveTools`) uses the MastraProvider so returned tools are
20
- * already in Mastra's `createTool()` format.
18
+ * Allowlist filtering is layered by {@link BaseToolProvider}; this class
19
+ * never reads `allowedToolkits` / `allowedTools` directly.
21
20
  */
22
- declare class ComposioToolProvider implements ToolProvider {
21
+ declare class ComposioToolProvider extends BaseToolProvider {
23
22
  readonly info: ToolProviderInfo;
24
- private apiKey;
23
+ readonly capabilities: ToolProviderCapabilities;
24
+ private readonly apiKey;
25
25
  private rawClient;
26
26
  private mastraClient;
27
27
  constructor(config: ComposioToolProviderConfig);
28
- /**
29
- * Get or create a raw Composio client (no provider — for discovery only).
30
- */
31
28
  private getRawClient;
32
- /**
33
- * Get or create a Composio client with MastraProvider (for runtime tools).
34
- */
35
29
  private getMastraClient;
30
+ protected listAllToolkits(): Promise<ToolProviderToolkit[]>;
31
+ protected listAllTools(opts: ListToolsOpts): Promise<ListToolsResult>;
32
+ resolveToolsVNext(opts: ResolveToolsOpts): Promise<Record<string, ToolAction<any, any, any>>>;
33
+ authorize(opts: AuthorizeOpts): Promise<{
34
+ url: string;
35
+ authId: string;
36
+ }>;
37
+ listConnectionFields({ toolkit }: {
38
+ toolkit: string;
39
+ }): Promise<ConnectionField[]>;
40
+ getAuthStatus(authId: string): Promise<AuthFlowStatus>;
41
+ getConnectionStatus(opts: {
42
+ items: Array<{
43
+ connectionId: string;
44
+ toolkit: string;
45
+ }>;
46
+ }): Promise<Record<string, {
47
+ connected: boolean;
48
+ }>>;
49
+ listConnections(opts: ListConnectionsOpts): Promise<ListConnectionsResult>;
36
50
  /**
37
- * List available toolkits via `composio.toolkits.get({})`.
38
- * Returns: `ToolKitListResponse` an array of `{ slug, name, meta: { description, logo, ... } }`.
39
- */
40
- listToolkits(): Promise<ToolProviderListResult<ToolProviderToolkit>>;
41
- /**
42
- * List available tools via `composio.tools.getRawComposioTools()`.
43
- * No userId required returns raw tool definitions for UI browsing.
44
- */
45
- listTools(options?: ListToolProviderToolsOptions): Promise<ToolProviderListResult<ToolProviderToolInfo>>;
46
- /**
47
- * Get JSON schema for a specific tool via `composio.tools.getRawComposioToolBySlug()`.
51
+ * Revoke a Composio connected account via
52
+ * `DELETE /api/v3/connected_accounts/:nanoid`. Composio performs a soft
53
+ * delete and responds with `{ success: boolean }`.
54
+ *
55
+ * Treats a 404 (account already deleted or never existed) as success so
56
+ * the caller can drop its local pin without an error path. A `success:
57
+ * false` response means the provider refused the delete and is surfaced
58
+ * as an error so the caller does not delete its local row.
48
59
  */
49
- getToolSchema(toolSlug: string): Promise<Record<string, unknown> | null>;
60
+ revokeConnection(connectionId: string): Promise<void>;
61
+ getHealth(): Promise<ToolProviderHealth>;
50
62
  /**
51
- * Resolve executable tools in Mastra format via `composio.tools.get(userId, { tools: [...] })`.
52
- *
53
- * Uses MastraProvider so returned tools are `ReturnType<typeof createTool>` — compatible
54
- * with Mastra's `ToolAction` interface.
63
+ * Resolve the single ENABLED auth config for `toolkit`. Throws if zero
64
+ * or multiple configs match — the admin must enable exactly one in the
65
+ * Composio dashboard before agents can connect.
55
66
  */
56
- resolveTools(toolSlugs: string[], toolConfigs?: Record<string, StorageToolConfig>, options?: ResolveToolProviderToolsOptions): Promise<Record<string, ToolAction<unknown, unknown>>>;
67
+ private resolveAuthConfig;
57
68
  }
58
69
 
59
70
  export { ComposioToolProvider, type ComposioToolProviderConfig };
package/dist/composio.js CHANGED
@@ -1,30 +1,38 @@
1
1
  // src/providers/composio.ts
2
+ import { BaseToolProvider } from "@mastra/core/tool-provider";
2
3
  import { MASTRA_RESOURCE_ID_KEY } from "@mastra/core/request-context";
3
4
  import { Composio } from "@composio/core";
4
5
  import { MastraProvider } from "@composio/mastra";
5
- var ComposioToolProvider = class {
6
+ var COMPOSIO_PROVIDER_ID = "composio";
7
+ var DEFAULT_INTERNAL_USER_ID = "default";
8
+ var ComposioToolProvider = class extends BaseToolProvider {
6
9
  constructor(config) {
10
+ super({
11
+ allowedToolkits: config.allowedToolkits,
12
+ allowedTools: config.allowedTools
13
+ });
7
14
  this.info = {
8
- id: "composio",
15
+ id: COMPOSIO_PROVIDER_ID,
9
16
  name: "Composio",
10
17
  description: "Access 10,000+ tools from 150+ apps via Composio"
11
18
  };
19
+ this.capabilities = {
20
+ multipleConnectionsPerToolkit: true,
21
+ batchConnectionStatus: true,
22
+ reauthorizeReusesConnectionId: true,
23
+ supportsRevoke: true
24
+ };
12
25
  this.rawClient = null;
13
26
  this.mastraClient = null;
14
27
  this.apiKey = config.apiKey;
15
28
  }
16
- /**
17
- * Get or create a raw Composio client (no provider — for discovery only).
18
- */
29
+ // ── client cache ──────────────────────────────────────────────────────
19
30
  getRawClient() {
20
31
  if (!this.rawClient) {
21
32
  this.rawClient = new Composio({ apiKey: this.apiKey });
22
33
  }
23
34
  return this.rawClient;
24
35
  }
25
- /**
26
- * Get or create a Composio client with MastraProvider (for runtime tools).
27
- */
28
36
  getMastraClient() {
29
37
  if (!this.mastraClient) {
30
38
  this.mastraClient = new Composio({
@@ -34,85 +42,303 @@ var ComposioToolProvider = class {
34
42
  }
35
43
  return this.mastraClient;
36
44
  }
37
- /**
38
- * List available toolkits via `composio.toolkits.get({})`.
39
- * Returns: `ToolKitListResponse` — an array of `{ slug, name, meta: { description, logo, ... } }`.
40
- */
41
- async listToolkits() {
45
+ // ── catalog (BaseToolProvider adds allowlist filter on top) ───────────
46
+ async listAllToolkits() {
42
47
  const composio = this.getRawClient();
43
48
  const toolkits = await composio.toolkits.get({});
44
- const data = toolkits.map((tk) => ({
49
+ return toolkits.map((tk) => ({
45
50
  slug: tk.slug,
46
51
  name: tk.name,
47
52
  description: tk.meta?.description,
48
53
  icon: tk.meta?.logo
49
54
  }));
50
- return { data };
51
55
  }
52
- /**
53
- * List available tools via `composio.tools.getRawComposioTools()`.
54
- * No userId required — returns raw tool definitions for UI browsing.
55
- */
56
- async listTools(options) {
56
+ async listAllTools(opts) {
57
57
  const composio = this.getRawClient();
58
- const limit = options?.perPage;
59
- const query = options?.toolkit ? { toolkits: [options.toolkit], limit, search: options?.search } : options?.search ? { search: options.search, limit } : { toolkits: [], limit };
60
- const rawTools = await composio.tools.getRawComposioTools(query);
58
+ const limit = opts.perPage;
59
+ const fallbackToolkits = this.allowedToolkits.length > 0 ? [...this.allowedToolkits] : void 0;
60
+ const query = opts.toolkit ? { toolkits: [opts.toolkit], limit, search: opts.search } : fallbackToolkits ? { toolkits: fallbackToolkits, limit, search: opts.search } : opts.search ? { search: opts.search, limit } : { toolkits: [], limit };
61
+ let rawTools = [];
62
+ try {
63
+ rawTools = await composio.tools.getRawComposioTools(query);
64
+ } catch (err) {
65
+ console.warn(
66
+ `[ComposioToolProvider] listAllTools failed for query ${JSON.stringify(query)} \u2014 returning empty page`,
67
+ err
68
+ );
69
+ }
61
70
  const data = rawTools.map((tool) => ({
62
71
  slug: tool.slug,
63
72
  name: tool.name ?? tool.slug,
64
73
  description: tool.description,
65
- toolkit: tool.toolkit?.slug
74
+ toolkit: tool.toolkit?.slug ?? opts.toolkit ?? ""
66
75
  }));
67
76
  return {
68
77
  data,
69
78
  pagination: {
70
- page: options?.page ?? 1,
79
+ page: opts.page ?? 1,
71
80
  perPage: limit,
72
81
  hasMore: limit !== void 0 && rawTools.length >= limit
73
82
  }
74
83
  };
75
84
  }
85
+ // ── runtime ───────────────────────────────────────────────────────────
86
+ async resolveToolsVNext(opts) {
87
+ if (opts.toolSlugs.length === 0) return {};
88
+ const internalUserId = opts.authorId && opts.authorId.length > 0 ? opts.authorId : resolveInternalUserId(opts.requestContext);
89
+ const composio = this.getMastraClient();
90
+ const modifiers = {
91
+ // `connectedAccountId` is not threaded through Composio's `execute`
92
+ // option bag in @composio/mastra; the only documented per-call hook
93
+ // is `beforeExecute`, which receives the params object that flows
94
+ // into the API call. Mutating `params.connectedAccountId` routes
95
+ // the call to a specific account.
96
+ beforeExecute: ({ params }) => {
97
+ params.connectedAccountId = opts.connectionId;
98
+ return params;
99
+ }
100
+ };
101
+ const mastraTools = await composio.tools.get(
102
+ internalUserId,
103
+ { tools: opts.toolSlugs },
104
+ modifiers
105
+ );
106
+ const result = {};
107
+ for (const [key, tool] of Object.entries(mastraTools ?? {})) {
108
+ if (!tool) continue;
109
+ const slug = tool.id ?? key;
110
+ try {
111
+ tool.outputSchema = void 0;
112
+ } catch {
113
+ }
114
+ const descOverride = opts.toolMeta?.[slug]?.description;
115
+ if (descOverride) {
116
+ try {
117
+ tool.description = descOverride;
118
+ } catch {
119
+ }
120
+ }
121
+ result[slug] = tool;
122
+ }
123
+ return result;
124
+ }
125
+ // ── auth surface ──────────────────────────────────────────────────────
126
+ async authorize(opts) {
127
+ const composio = this.getRawClient();
128
+ const { id: authConfigId, authScheme } = await this.resolveAuthConfig(opts.toolkit);
129
+ const internalUserId = opts.connectionId || DEFAULT_INTERNAL_USER_ID;
130
+ 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, {
132
+ allowMultiple: true,
133
+ ...initiateConfig ? { config: initiateConfig } : {}
134
+ });
135
+ if (!request.redirectUrl) {
136
+ throw new Error(`[composio] initiate did not return a redirectUrl for toolkit "${opts.toolkit}"`);
137
+ }
138
+ return { url: request.redirectUrl, authId: request.id };
139
+ }
140
+ async listConnectionFields({ toolkit }) {
141
+ const composio = this.getRawClient();
142
+ const { authScheme } = await this.resolveAuthConfig(toolkit);
143
+ if (!authScheme) {
144
+ return [];
145
+ }
146
+ const fields = await composio.toolkits.getConnectedAccountInitiationFields(toolkit, authScheme, {
147
+ requiredOnly: false
148
+ });
149
+ return fields.map((f) => ({
150
+ name: f.name,
151
+ displayName: f.displayName,
152
+ description: f.description,
153
+ type: coerceFieldType(f.type),
154
+ required: f.required ?? false,
155
+ default: f.default ?? void 0
156
+ }));
157
+ }
158
+ async getAuthStatus(authId) {
159
+ const composio = this.getRawClient();
160
+ const account = await composio.connectedAccounts.get(authId);
161
+ switch (account.status) {
162
+ case "ACTIVE":
163
+ return "completed";
164
+ case "INITIALIZING":
165
+ case "INITIATED":
166
+ return "pending";
167
+ case "FAILED":
168
+ case "EXPIRED":
169
+ case "INACTIVE":
170
+ return "failed";
171
+ default:
172
+ return "pending";
173
+ }
174
+ }
175
+ async getConnectionStatus(opts) {
176
+ if (opts.items.length === 0) return {};
177
+ const composio = this.getRawClient();
178
+ const toolkitSlugs = Array.from(new Set(opts.items.map((i) => i.toolkit)));
179
+ const list = await composio.connectedAccounts.list({
180
+ toolkitSlugs
181
+ });
182
+ const liveById = /* @__PURE__ */ new Map();
183
+ for (const item of list.items) {
184
+ liveById.set(item.id, { status: item.status, isDisabled: item.isDisabled });
185
+ }
186
+ const result = {};
187
+ for (const { connectionId } of opts.items) {
188
+ const live = liveById.get(connectionId);
189
+ result[connectionId] = { connected: live ? live.status === "ACTIVE" && !live.isDisabled : false };
190
+ }
191
+ return result;
192
+ }
193
+ async listConnections(opts) {
194
+ const composio = this.getRawClient();
195
+ const page = opts.page ?? 1;
196
+ const perPage = clampLimit(opts.perPage);
197
+ const userIds = resolveUserIds(opts);
198
+ if (userIds && userIds.length === 0) {
199
+ return { items: [], pagination: { page, perPage, hasMore: false } };
200
+ }
201
+ const list = await composio.connectedAccounts.list({
202
+ toolkitSlugs: [opts.toolkit],
203
+ ...userIds ? { userIds } : {},
204
+ limit: perPage
205
+ });
206
+ const items = (list.items ?? []).map((account) => ({
207
+ connectionId: account.id,
208
+ status: mapComposioStatus(account.status, account.isDisabled),
209
+ createdAt: account.createdAt,
210
+ // `user_id` is preserved by the Composio SDK transform via spread but
211
+ // isn't on the typed shape. Read it via a narrow cast.
212
+ authorId: account.user_id
213
+ }));
214
+ const nextCursor = list.nextCursor ?? null;
215
+ const hasMore = typeof nextCursor === "string" && nextCursor.length > 0;
216
+ return { items, pagination: { page, perPage, hasMore } };
217
+ }
76
218
  /**
77
- * Get JSON schema for a specific tool via `composio.tools.getRawComposioToolBySlug()`.
219
+ * Revoke a Composio connected account via
220
+ * `DELETE /api/v3/connected_accounts/:nanoid`. Composio performs a soft
221
+ * delete and responds with `{ success: boolean }`.
222
+ *
223
+ * Treats a 404 (account already deleted or never existed) as success so
224
+ * the caller can drop its local pin without an error path. A `success:
225
+ * false` response means the provider refused the delete and is surfaced
226
+ * as an error so the caller does not delete its local row.
78
227
  */
79
- async getToolSchema(toolSlug) {
228
+ async revokeConnection(connectionId) {
229
+ const composio = this.getRawClient();
230
+ try {
231
+ const res = await composio.connectedAccounts.delete(connectionId);
232
+ if (res && res.success === false) {
233
+ throw new Error(`Composio refused to delete connected account ${connectionId} (success=false)`);
234
+ }
235
+ } catch (err) {
236
+ if (isNotFoundError(err)) return;
237
+ throw err;
238
+ }
239
+ }
240
+ async getHealth() {
80
241
  try {
81
242
  const composio = this.getRawClient();
82
- const tool = await composio.tools.getRawComposioToolBySlug(toolSlug);
83
- if (!tool) return null;
84
- return tool.inputParameters ?? {};
85
- } catch {
86
- return null;
243
+ await composio.toolkits.get({ limit: 1 });
244
+ return { ok: true };
245
+ } catch (err) {
246
+ return {
247
+ ok: false,
248
+ message: err instanceof Error ? err.message : "Composio SDK reachability check failed"
249
+ };
87
250
  }
88
251
  }
252
+ // ── helpers ───────────────────────────────────────────────────────────
89
253
  /**
90
- * Resolve executable tools in Mastra format via `composio.tools.get(userId, { tools: [...] })`.
91
- *
92
- * Uses MastraProvider so returned tools are `ReturnType<typeof createTool>` — compatible
93
- * with Mastra's `ToolAction` interface.
254
+ * Resolve the single ENABLED auth config for `toolkit`. Throws if zero
255
+ * or multiple configs match — the admin must enable exactly one in the
256
+ * Composio dashboard before agents can connect.
94
257
  */
95
- async resolveTools(toolSlugs, toolConfigs, options) {
96
- if (toolSlugs.length === 0) return {};
97
- const resourceId = options?.requestContext?.[MASTRA_RESOURCE_ID_KEY];
98
- const userId = typeof resourceId === "string" ? resourceId : options?.userId ?? "default";
99
- const composio = this.getMastraClient();
100
- const mastraTools = await composio.tools.get(userId, { tools: toolSlugs });
101
- const result = {};
102
- const entries = Object.entries(mastraTools ?? {});
103
- for (const [key, tool] of entries) {
104
- if (!tool) continue;
105
- const slug = tool.id ?? key;
106
- const descOverride = toolConfigs?.[slug]?.description;
107
- if (descOverride) {
108
- result[slug] = { ...tool, description: descOverride };
109
- } else {
110
- result[slug] = tool;
111
- }
258
+ async resolveAuthConfig(toolkit) {
259
+ const composio = this.getRawClient();
260
+ const response = await composio.authConfigs.list({ toolkit });
261
+ const enabled = response.items.filter((item) => item.status === "ENABLED");
262
+ if (enabled.length === 0) {
263
+ throw new Error(
264
+ `[composio] No ENABLED auth config for toolkit "${toolkit}". Enable one in the Composio dashboard.`
265
+ );
112
266
  }
113
- return result;
267
+ if (enabled.length > 1) {
268
+ const ids = enabled.map((item) => item.id).join(", ");
269
+ throw new Error(
270
+ `[composio] Multiple ENABLED auth configs for toolkit "${toolkit}" (${ids}). Keep exactly one enabled.`
271
+ );
272
+ }
273
+ return { id: enabled[0].id, authScheme: enabled[0].authScheme };
114
274
  }
115
275
  };
276
+ function isNotFoundError(err) {
277
+ if (!err || typeof err !== "object") return false;
278
+ const e = err;
279
+ if (e.statusCode === 404 || e.status === 404) return true;
280
+ const msg = typeof e.message === "string" ? e.message.toLowerCase() : "";
281
+ return msg.includes("not found") || msg.includes("404");
282
+ }
283
+ function coerceFieldType(type) {
284
+ switch (type.toLowerCase()) {
285
+ case "number":
286
+ case "integer":
287
+ case "int":
288
+ case "float":
289
+ return "number";
290
+ case "bool":
291
+ case "boolean":
292
+ return "boolean";
293
+ default:
294
+ return "string";
295
+ }
296
+ }
297
+ function mapComposioStatus(status, isDisabled) {
298
+ if (isDisabled) return "inactive";
299
+ switch (status) {
300
+ case "ACTIVE":
301
+ return "active";
302
+ case "INITIALIZING":
303
+ case "INITIATED":
304
+ return "pending";
305
+ case "FAILED":
306
+ case "EXPIRED":
307
+ return "failed";
308
+ case "INACTIVE":
309
+ return "inactive";
310
+ default:
311
+ return "pending";
312
+ }
313
+ }
314
+ var MASTRA_USER_KEY = "mastra__user";
315
+ function resolveInternalUserId(requestContext) {
316
+ const resourceId = requestContext?.[MASTRA_RESOURCE_ID_KEY];
317
+ if (typeof resourceId === "string" && resourceId.length > 0) {
318
+ return resourceId;
319
+ }
320
+ const user = requestContext?.[MASTRA_USER_KEY];
321
+ if (user && typeof user === "object" && "id" in user) {
322
+ const id = user.id;
323
+ if (typeof id === "string" && id.length > 0) {
324
+ return id;
325
+ }
326
+ }
327
+ return DEFAULT_INTERNAL_USER_ID;
328
+ }
329
+ function resolveUserIds(opts) {
330
+ if (Array.isArray(opts.userIds)) return opts.userIds;
331
+ if (typeof opts.userId === "string" && opts.userId.length > 0) return [opts.userId];
332
+ return [DEFAULT_INTERNAL_USER_ID];
333
+ }
334
+ var DEFAULT_LIMIT = 50;
335
+ var MAX_LIMIT = 200;
336
+ function clampLimit(limit) {
337
+ if (typeof limit !== "number" || !Number.isFinite(limit) || limit <= 0) {
338
+ return DEFAULT_LIMIT;
339
+ }
340
+ return Math.min(Math.floor(limit), MAX_LIMIT);
341
+ }
116
342
  export {
117
343
  ComposioToolProvider
118
344
  };