@mastra/editor 0.13.8 → 0.13.9

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