@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/CHANGELOG.md +17 -0
- package/dist/arcade.cjs +645 -292
- package/dist/arcade.cjs.map +1 -1
- package/dist/arcade.d.cts +47 -46
- package/dist/arcade.d.cts.map +1 -0
- package/dist/arcade.d.ts +47 -46
- package/dist/arcade.d.ts.map +1 -0
- package/dist/arcade.js +642 -263
- package/dist/arcade.js.map +1 -1
- package/dist/composio.cjs +336 -361
- package/dist/composio.cjs.map +1 -1
- package/dist/composio.d.cts +52 -51
- package/dist/composio.d.cts.map +1 -0
- package/dist/composio.d.ts +52 -51
- package/dist/composio.d.ts.map +1 -0
- package/dist/composio.js +330 -329
- package/dist/composio.js.map +1 -1
- package/dist/ee/index.cjs +199 -191
- package/dist/ee/index.cjs.map +1 -1
- package/dist/ee/index.d.cts +47 -44
- package/dist/ee/index.d.cts.map +1 -0
- package/dist/ee/index.d.ts +47 -44
- package/dist/ee/index.d.ts.map +1 -0
- package/dist/ee/index.js +180 -158
- package/dist/ee/index.js.map +1 -1
- package/dist/index.cjs +2459 -3145
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +461 -478
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +461 -478
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2442 -2797
- package/dist/index.js.map +1 -1
- package/dist/storage/index.cjs +24 -35
- package/dist/storage/index.d.cts +2 -1
- package/dist/storage/index.d.ts +2 -1
- package/dist/storage/index.js +2 -14
- package/package.json +11 -11
- package/dist/storage/index.cjs.map +0 -1
- package/dist/storage/index.js.map +0 -1
package/dist/composio.js.map
CHANGED
|
@@ -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 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":[]}
|
|
1
|
+
{"version":3,"file":"composio.js","names":[],"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 BaseToolProviderOptions,\n} from '@mastra/core/tool-provider';\nimport { BaseToolProvider } 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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"}
|
package/dist/ee/index.cjs
CHANGED
|
@@ -1,175 +1,185 @@
|
|
|
1
|
-
"
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
9
|
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
19
18
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
//#endregion
|
|
24
|
+
let _mastra_memory = require("@mastra/memory");
|
|
25
|
+
let _mastra_core_agent = require("@mastra/core/agent");
|
|
26
|
+
let _mastra_core_workspace = require("@mastra/core/workspace");
|
|
27
|
+
let _mastra_core_processors = require("@mastra/core/processors");
|
|
28
|
+
let _mastra_core_agent_builder_ee = require("@mastra/core/agent-builder/ee");
|
|
29
|
+
let path = require("path");
|
|
30
|
+
path = __toESM(path, 1);
|
|
31
|
+
let url = require("url");
|
|
32
|
+
//#region src/ee/agent-builder.ts
|
|
33
|
+
/**
|
|
34
|
+
* Concrete implementation of the Agent Builder EE feature.
|
|
35
|
+
* Instantiated by MastraEditor.resolveBuilder() when builder config is enabled.
|
|
36
|
+
*
|
|
37
|
+
* The constructor performs fail-fast validation of the admin's model policy
|
|
38
|
+
* (Phase 4) so misconfiguration is caught at boot, not at first request.
|
|
39
|
+
*
|
|
40
|
+
* Feature toggles use **default-on semantics**: omitted keys resolve to
|
|
41
|
+
* `true`. Admins opt out by setting a key to `false`. The resolved features
|
|
42
|
+
* are computed once in the constructor (after validation) and returned
|
|
43
|
+
* verbatim by {@link getFeatures} so all downstream consumers (server route,
|
|
44
|
+
* UI hooks, policy derivation) see the same effective values.
|
|
45
|
+
*/
|
|
40
46
|
var EditorAgentBuilder = class {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
enabled,
|
|
125
|
-
pickerVisible,
|
|
126
|
-
allowed,
|
|
127
|
-
default: defaultModel
|
|
128
|
-
});
|
|
129
|
-
if (!active) return;
|
|
130
|
-
if (explicitModel === false && defaultModel === void 0) {
|
|
131
|
-
throw new Error(
|
|
132
|
-
"Agent Builder model policy is active in locked mode but no default was set. Set `editor.builder.configuration.agent.models.default`, or remove `editor.builder.features.agent.model = false` to allow end-users to pick a model."
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
if (defaultModel !== void 0 && allowed !== void 0 && allowed.length > 0) {
|
|
136
|
-
if (!(0, import_ee.isModelAllowed)(allowed, defaultModel)) {
|
|
137
|
-
throw new Error(
|
|
138
|
-
"Agent Builder default model is not in the allowlist. Either add it to `editor.builder.configuration.agent.models.allowed` or change `editor.builder.configuration.agent.models.default`."
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
47
|
+
constructor(options) {
|
|
48
|
+
this.modelPolicyWarnings = [];
|
|
49
|
+
this.browserConfigWarnings = [];
|
|
50
|
+
const source = options ?? {};
|
|
51
|
+
this.options = {
|
|
52
|
+
...source,
|
|
53
|
+
features: source.features ? {
|
|
54
|
+
...source.features,
|
|
55
|
+
agent: source.features.agent ? { ...source.features.agent } : void 0
|
|
56
|
+
} : void 0
|
|
57
|
+
};
|
|
58
|
+
this.validateModelPolicy();
|
|
59
|
+
this.validateBrowserConfig();
|
|
60
|
+
this.resolvedFeatures = { agent: (0, _mastra_core_agent_builder_ee.resolveAgentFeatures)(this.options.features?.agent, { hasBrowserConfig: this.hasValidBrowserConfig() }) };
|
|
61
|
+
}
|
|
62
|
+
get enabled() {
|
|
63
|
+
return this.options.enabled !== false;
|
|
64
|
+
}
|
|
65
|
+
getFeatures() {
|
|
66
|
+
return this.resolvedFeatures;
|
|
67
|
+
}
|
|
68
|
+
getConfiguration() {
|
|
69
|
+
return this.options.configuration;
|
|
70
|
+
}
|
|
71
|
+
getRegistries() {
|
|
72
|
+
return this.options.registries;
|
|
73
|
+
}
|
|
74
|
+
getModelPolicyWarnings() {
|
|
75
|
+
return [...this.modelPolicyWarnings, ...this.browserConfigWarnings];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* True when `configuration.agent.browser` declares a provider. The
|
|
79
|
+
* EditorAgentBuilder does NOT verify the provider is registered with the
|
|
80
|
+
* Mastra instance — that cross-validation lives in `MastraEditor.resolveBuilder`
|
|
81
|
+
* because only the editor knows the registered browser providers.
|
|
82
|
+
*/
|
|
83
|
+
hasValidBrowserConfig() {
|
|
84
|
+
const browserConfig = this.options.configuration?.agent?.browser;
|
|
85
|
+
return Boolean(browserConfig?.config?.provider);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Browser config validation only runs for **explicit** `browser: true`.
|
|
89
|
+
* With default-on semantics, an omitted `browser` no longer means "admin
|
|
90
|
+
* opted in" — it means "admin didn't opt out". The default-on path is
|
|
91
|
+
* resolved later by `resolveAgentFeatures`, which already gates `browser`
|
|
92
|
+
* on `hasValidBrowserConfig`. We don't want to spam every default-config
|
|
93
|
+
* deployment with warnings.
|
|
94
|
+
*/
|
|
95
|
+
validateBrowserConfig() {
|
|
96
|
+
if (this.options.features?.agent?.browser !== true) return;
|
|
97
|
+
const browserConfig = this.options.configuration?.agent?.browser;
|
|
98
|
+
if (!browserConfig) {
|
|
99
|
+
const warning = "Agent Builder browser feature is enabled but no default browser config was provided. Set `editor.builder.configuration.agent.browser` to a valid browser config (e.g. `{ type: \"inline\", config: { provider: \"stagehand\" } }`). The browser toggle will be hidden until a default is configured.";
|
|
100
|
+
this.browserConfigWarnings.push(warning);
|
|
101
|
+
console.warn(`[mastra:editor:builder] ${warning}`);
|
|
102
|
+
if (this.options.features?.agent) this.options.features.agent.browser = false;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (!browserConfig.config?.provider) {
|
|
106
|
+
const warning = "Agent Builder browser config is missing a `provider` field. Set `editor.builder.configuration.agent.browser.config.provider` (e.g. `\"stagehand\"`). The browser toggle will be hidden until a provider is configured.";
|
|
107
|
+
this.browserConfigWarnings.push(warning);
|
|
108
|
+
console.warn(`[mastra:editor:builder] ${warning}`);
|
|
109
|
+
if (this.options.features?.agent) this.options.features.agent.browser = false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
validateModelPolicy() {
|
|
113
|
+
const enabled = this.options.enabled !== false;
|
|
114
|
+
const explicitModel = this.options.features?.agent?.model;
|
|
115
|
+
const pickerVisible = explicitModel !== false;
|
|
116
|
+
const models = this.options.configuration?.agent?.models;
|
|
117
|
+
const allowed = models?.allowed;
|
|
118
|
+
const defaultModel = models?.default;
|
|
119
|
+
if (!(0, _mastra_core_agent_builder_ee.isBuilderModelPolicyActive)({
|
|
120
|
+
enabled,
|
|
121
|
+
pickerVisible,
|
|
122
|
+
allowed,
|
|
123
|
+
default: defaultModel
|
|
124
|
+
})) return;
|
|
125
|
+
if (explicitModel === false && defaultModel === void 0) throw new Error("Agent Builder model policy is active in locked mode but no default was set. Set `editor.builder.configuration.agent.models.default`, or remove `editor.builder.features.agent.model = false` to allow end-users to pick a model.");
|
|
126
|
+
if (defaultModel !== void 0 && allowed !== void 0 && allowed.length > 0) {
|
|
127
|
+
if (!(0, _mastra_core_agent_builder_ee.isModelAllowed)(allowed, defaultModel)) throw new Error("Agent Builder default model is not in the allowlist. Either add it to `editor.builder.configuration.agent.models.allowed` or change `editor.builder.configuration.agent.models.default`.");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
143
130
|
};
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
var import_node_url = require("url");
|
|
152
|
-
var import_meta = {};
|
|
153
|
-
var __filename = (0, import_node_url.fileURLToPath)(import_meta.url);
|
|
154
|
-
var __dirname = import_node_path.default.dirname(__filename);
|
|
155
|
-
var workspacePath = import_node_path.default.join(__dirname, "workspace");
|
|
156
|
-
var workspace = new import_workspace.Workspace({
|
|
157
|
-
filesystem: new import_workspace.LocalFilesystem({
|
|
158
|
-
basePath: workspacePath
|
|
159
|
-
}),
|
|
160
|
-
skills: ["skills"]
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/ee/agent-builder-agent.ts
|
|
133
|
+
const __filename$1 = (0, url.fileURLToPath)(require("url").pathToFileURL(__filename).href);
|
|
134
|
+
const __dirname$1 = path.default.dirname(__filename$1);
|
|
135
|
+
const workspace = new _mastra_core_workspace.Workspace({
|
|
136
|
+
filesystem: new _mastra_core_workspace.LocalFilesystem({ basePath: path.default.join(__dirname$1, "workspace") }),
|
|
137
|
+
skills: ["skills"]
|
|
161
138
|
});
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
139
|
+
/**
|
|
140
|
+
* Agent Builder Agent
|
|
141
|
+
*
|
|
142
|
+
* Audience: non-technical users (Product, founders, operators, business stakeholders).
|
|
143
|
+
* Goal: turn a plain-language description of a desired outcome into a fully
|
|
144
|
+
* configured, production-quality agent — name, description, model, capabilities,
|
|
145
|
+
* and system prompt — without asking the user follow-up questions.
|
|
146
|
+
*
|
|
147
|
+
* Capability tools the playground UI injects as client tools:
|
|
148
|
+
* - set-agent-name, set-agent-description, set-agent-instructions, set-agent-workspace-id (always on)
|
|
149
|
+
* - set-agent-tools (gated by features.tools)
|
|
150
|
+
* - set-agent-skills (gated by features.skills + skills available)
|
|
151
|
+
* - set-agent-model (gated by features.model + models available)
|
|
152
|
+
* - set-agent-browser-enabled (gated by features.browser)
|
|
153
|
+
* - createSkillTool (gated by features.skills) — only when a needed capability does not exist
|
|
154
|
+
*/
|
|
155
|
+
/**
|
|
156
|
+
* Default error processors wired into every builder agent. These each fix a
|
|
157
|
+
* class of provider-side correctness bug that builder workloads tend to hit:
|
|
158
|
+
*
|
|
159
|
+
* - `StreamErrorRetryProcessor` — retries OpenAI's transient stream errors
|
|
160
|
+
* (`server_error`, `rate_limit`, `internal_error`, `timeout`, `overloaded`,
|
|
161
|
+
* etc.) that surface on long, tool-heavy turns.
|
|
162
|
+
* - `PrefillErrorHandler` — recovers from Anthropic's
|
|
163
|
+
* `does not support assistant message prefill` 400 by appending a
|
|
164
|
+
* `system-reminder` continue message and retrying.
|
|
165
|
+
* - `ProviderHistoryCompat` — applies provider-history-shape fixes
|
|
166
|
+
* (anthropic tool-id format, cerebras reasoning-content strip, anthropic
|
|
167
|
+
* foreign-reasoning strip) so model swaps don't break history.
|
|
168
|
+
*
|
|
169
|
+
* Exported so callers can compose a custom processor list that keeps the
|
|
170
|
+
* subset they want (e.g. `[...DEFAULT_BUILDER_ERROR_PROCESSORS.filter(p => p.id !== 'stream-error-retry-processor'), myCustom]`).
|
|
171
|
+
*/
|
|
172
|
+
const DEFAULT_BUILDER_ERROR_PROCESSORS = [
|
|
173
|
+
new _mastra_core_processors.StreamErrorRetryProcessor(),
|
|
174
|
+
new _mastra_core_processors.PrefillErrorHandler(),
|
|
175
|
+
new _mastra_core_processors.ProviderHistoryCompat()
|
|
166
176
|
];
|
|
167
177
|
function createBuilderAgent(args) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
178
|
+
const memory = new _mastra_memory.Memory();
|
|
179
|
+
const callerErrorProcessors = args?.errorProcessors;
|
|
180
|
+
const errorProcessors = Array.isArray(callerErrorProcessors) ? [...DEFAULT_BUILDER_ERROR_PROCESSORS, ...callerErrorProcessors] : callerErrorProcessors ?? DEFAULT_BUILDER_ERROR_PROCESSORS;
|
|
181
|
+
return new _mastra_core_agent.Agent({
|
|
182
|
+
instructions: `You are the Agent Builder.
|
|
173
183
|
|
|
174
184
|
Your job: turn a non-technical user's plain-language request into a fully configured, production-quality agent in a single turn.
|
|
175
185
|
|
|
@@ -178,26 +188,26 @@ Your job: turn a non-technical user's plain-language request into a fully config
|
|
|
178
188
|
- Never ask the user follow-up questions. Make the most reasonable assumption and move forward.
|
|
179
189
|
- Never expose internal names, tool ids, file paths, schemas, code, or jargon to the user.
|
|
180
190
|
- Speak only in user-facing capability terms.
|
|
181
|
-
- Always finish the build in the same turn as the request
|
|
191
|
+
- Always finish the build in the same turn as the request — configure the agent end-to-end and deliver a short summary.
|
|
182
192
|
- Always define the new agent's name, description, model, and system prompt yourself. Do not ask the user for any of these.
|
|
183
193
|
|
|
184
194
|
Examples of communication style:
|
|
185
195
|
- Bad: "Added weatherTool to agent-yzx capabilities."
|
|
186
196
|
- Good: "Your new agent can now check the weather for you."
|
|
187
197
|
- Bad: "Calling set-agent-tools with [weatherTool]."
|
|
188
|
-
- Good: "Checking what capabilities to bring to your agent
|
|
198
|
+
- Good: "Checking what capabilities to bring to your agent…"
|
|
189
199
|
- Bad: "Agent created with weatherTool and recipeWorkflow attached."
|
|
190
200
|
- Good: "Your agent can check the weather and suggest recipes that match the day's conditions."
|
|
191
201
|
|
|
192
202
|
# Form snapshot
|
|
193
203
|
|
|
194
|
-
A "Current agent configuration (authoritative)" block is injected into your context every turn. It lists every form field with its current value AND a directive telling you exactly which setter to call (or skip) for that field. Treat the snapshot as the single source of truth for what is and isn't already set
|
|
204
|
+
A "Current agent configuration (authoritative)" block is injected into your context every turn. It lists every form field with its current value AND a directive telling you exactly which setter to call (or skip) for that field. Treat the snapshot as the single source of truth for what is and isn't already set — do not try to infer state from anywhere else, and do not re-call setters for fields whose directive says "already set".
|
|
195
205
|
|
|
196
206
|
# Authoring loop
|
|
197
207
|
|
|
198
208
|
Follow these five steps in order, every time:
|
|
199
209
|
|
|
200
|
-
## Step A
|
|
210
|
+
## Step A — Understand the real outcome
|
|
201
211
|
|
|
202
212
|
Analyze what the user actually wants to achieve. Focus on the final result, not just the literal wording of the request.
|
|
203
213
|
|
|
@@ -208,7 +218,7 @@ Ask yourself:
|
|
|
208
218
|
- What kind of output should the agent produce?
|
|
209
219
|
- What recurring tasks, reasoning, or actions does the agent need to perform?
|
|
210
220
|
|
|
211
|
-
## Step B
|
|
221
|
+
## Step B — Define the agent's identity
|
|
212
222
|
|
|
213
223
|
Decide on:
|
|
214
224
|
- Agent name: short, memorable, anchored to the outcome. Never "Agent X" or generic labels.
|
|
@@ -216,7 +226,7 @@ Decide on:
|
|
|
216
226
|
|
|
217
227
|
The snapshot will tell you whether to call \`set-agent-name\` and \`set-agent-description\` or skip them.
|
|
218
228
|
|
|
219
|
-
## Step C
|
|
229
|
+
## Step C — Decide capabilities
|
|
220
230
|
|
|
221
231
|
The form snapshot lists what's currently attached. Use it together with the available tools, agents, workflows, stored skills, and models listed in the corresponding tool descriptions to decide:
|
|
222
232
|
|
|
@@ -226,20 +236,20 @@ The form snapshot lists what's currently attached. Use it together with the avai
|
|
|
226
236
|
- Only call \`createSkillTool\` when (a) no existing stored skill matches reusable operating instructions the produced agent needs, AND (b) that operating instruction is genuinely needed for the outcome. Do not use stored skills as a substitute for missing integrations or tools.
|
|
227
237
|
- If a specific external connection is required (e.g. a sheet tool for a spreadsheet-driven outcome) and none is available, the new agent's system prompt must instruct it to refuse cleanly and explain what the user needs to connect.
|
|
228
238
|
|
|
229
|
-
## Step D
|
|
239
|
+
## Step D — Synthesize concise operating instructions
|
|
230
240
|
|
|
231
241
|
Before calling \`set-agent-instructions\`, privately write a concrete run contract for the produced agent. The system prompt must instantiate each item, but keep each item brief:
|
|
232
242
|
|
|
233
|
-
1. **Trigger / input**
|
|
234
|
-
2. **Owned outcome**
|
|
235
|
-
3. **Available capabilities**
|
|
236
|
-
4. **Missing-capability fallback**
|
|
237
|
-
5. **Done criteria**
|
|
238
|
-
6. **Final response format**
|
|
243
|
+
1. **Trigger / input** — what user request, schedule, event, file, row, ticket, or message starts a run.
|
|
244
|
+
2. **Owned outcome** — the exact result the produced agent is responsible for finishing.
|
|
245
|
+
3. **Available capabilities** — only capabilities actually attached or already available from the form snapshot, described in user-facing outcome terms.
|
|
246
|
+
4. **Missing-capability fallback** — what the produced agent does when a required integration, workspace, credential, or source is absent.
|
|
247
|
+
5. **Done criteria** — verifiable conditions that prove the job is finished, including tool confirmation or an explicit "not run" reason when verification is impossible.
|
|
248
|
+
6. **Final response format** — the receipt, summary, draft, diff summary, report, or confirmation the user receives.
|
|
239
249
|
|
|
240
|
-
Write the final system prompt as 2
|
|
250
|
+
Write the final system prompt as 2–4 short paragraphs or compact bullet groups. Target 1,200–2,000 characters and stay under 2,500 characters. Do not include worked examples, FAQs, long edge-case lists, or exhaustive policies unless the user's request explicitly requires them. Prefer one clear default over several branches.
|
|
241
251
|
|
|
242
|
-
## Step E
|
|
252
|
+
## Step E — Write the agent
|
|
243
253
|
|
|
244
254
|
Read the per-field directives in the form snapshot. Call only the setters the snapshot tells you to call, each at most once, with the final value. Skip every field marked "already set" or "no setter". Skip any field that isn't listed at all (its feature is disabled).
|
|
245
255
|
|
|
@@ -253,7 +263,7 @@ Before calling \`set-agent-instructions\`, self-audit the draft. It must pass ev
|
|
|
253
263
|
- Final response expectations are clear.
|
|
254
264
|
- The prompt is specific to the agent's outcome and under 2,500 characters.
|
|
255
265
|
|
|
256
|
-
## Step F
|
|
266
|
+
## Step F — Confirm the agent configuration to the user
|
|
257
267
|
|
|
258
268
|
End your turn with one short, friendly paragraph confirming that the agent has been configured and is ready to use.
|
|
259
269
|
|
|
@@ -286,7 +296,7 @@ The system prompt written into \`set-agent-instructions\` MUST be short, concret
|
|
|
286
296
|
8. **Communication style.** Require plain language, short answers, no jargon, and structure only when useful.
|
|
287
297
|
9. **Refusal rules.** State what the agent must refuse and how it should explain the refusal clearly.
|
|
288
298
|
|
|
289
|
-
Keep this to 2
|
|
299
|
+
Keep this to 2–4 focused paragraphs or compact bullet groups. Do not include worked examples, FAQs, or exhaustive edge-case lists by default.
|
|
290
300
|
|
|
291
301
|
# Hard rules
|
|
292
302
|
|
|
@@ -296,20 +306,18 @@ Keep this to 2\u20134 focused paragraphs or compact bullet groups. Do not includ
|
|
|
296
306
|
- Never attach a capability "just in case." Every tool, agent, workflow, or skill must directly support the requested outcome.
|
|
297
307
|
- The final message to the user must be concise, friendly, and focused on what the configured agent can now do.
|
|
298
308
|
- The final message should make clear that the agent starts with initial parameters and can be adjusted later.`,
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
return new import_agent.Agent(config);
|
|
309
|
+
model: "openai/gpt-5.5",
|
|
310
|
+
memory,
|
|
311
|
+
workspace,
|
|
312
|
+
...args || {},
|
|
313
|
+
errorProcessors,
|
|
314
|
+
id: "builder-agent",
|
|
315
|
+
name: "Agent Builder Agent",
|
|
316
|
+
description: "An agent that can build agents"
|
|
317
|
+
});
|
|
309
318
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
});
|
|
319
|
+
//#endregion
|
|
320
|
+
exports.EditorAgentBuilder = EditorAgentBuilder;
|
|
321
|
+
exports.createBuilderAgent = createBuilderAgent;
|
|
322
|
+
|
|
315
323
|
//# sourceMappingURL=index.cjs.map
|