@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.
@@ -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
- "use strict";
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
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
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
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/ee/index.ts
31
- var ee_exports = {};
32
- __export(ee_exports, {
33
- EditorAgentBuilder: () => EditorAgentBuilder,
34
- createBuilderAgent: () => createBuilderAgent
35
- });
36
- module.exports = __toCommonJS(ee_exports);
37
-
38
- // src/ee/agent-builder.ts
39
- var import_ee = require("@mastra/core/agent-builder/ee");
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
- constructor(options) {
42
- this.modelPolicyWarnings = [];
43
- /** Non-fatal warnings for browser config issues (surfaced alongside model policy warnings). */
44
- this.browserConfigWarnings = [];
45
- const source = options ?? {};
46
- this.options = {
47
- ...source,
48
- features: source.features ? {
49
- ...source.features,
50
- agent: source.features.agent ? { ...source.features.agent } : void 0
51
- } : void 0
52
- };
53
- this.validateModelPolicy();
54
- this.validateBrowserConfig();
55
- this.resolvedFeatures = {
56
- agent: (0, import_ee.resolveAgentFeatures)(this.options.features?.agent, {
57
- hasBrowserConfig: this.hasValidBrowserConfig()
58
- })
59
- };
60
- }
61
- get enabled() {
62
- return this.options.enabled !== false;
63
- }
64
- getFeatures() {
65
- return this.resolvedFeatures;
66
- }
67
- getConfiguration() {
68
- return this.options.configuration;
69
- }
70
- getRegistries() {
71
- return this.options.registries;
72
- }
73
- getModelPolicyWarnings() {
74
- return [...this.modelPolicyWarnings, ...this.browserConfigWarnings];
75
- }
76
- /**
77
- * True when `configuration.agent.browser` declares a provider. The
78
- * EditorAgentBuilder does NOT verify the provider is registered with the
79
- * Mastra instance — that cross-validation lives in `MastraEditor.resolveBuilder`
80
- * because only the editor knows the registered browser providers.
81
- */
82
- hasValidBrowserConfig() {
83
- const browserConfig = this.options.configuration?.agent?.browser;
84
- return Boolean(browserConfig?.config?.provider);
85
- }
86
- /**
87
- * Browser config validation only runs for **explicit** `browser: true`.
88
- * With default-on semantics, an omitted `browser` no longer means "admin
89
- * opted in" — it means "admin didn't opt out". The default-on path is
90
- * resolved later by `resolveAgentFeatures`, which already gates `browser`
91
- * on `hasValidBrowserConfig`. We don't want to spam every default-config
92
- * deployment with warnings.
93
- */
94
- validateBrowserConfig() {
95
- const explicitBrowser = this.options.features?.agent?.browser;
96
- if (explicitBrowser !== 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) {
103
- this.options.features.agent.browser = false;
104
- }
105
- return;
106
- }
107
- if (!browserConfig.config?.provider) {
108
- 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.';
109
- this.browserConfigWarnings.push(warning);
110
- console.warn(`[mastra:editor:builder] ${warning}`);
111
- if (this.options.features?.agent) {
112
- this.options.features.agent.browser = false;
113
- }
114
- }
115
- }
116
- validateModelPolicy() {
117
- const enabled = this.options.enabled !== false;
118
- const explicitModel = this.options.features?.agent?.model;
119
- const pickerVisible = explicitModel !== false;
120
- const models = this.options.configuration?.agent?.models;
121
- const allowed = models?.allowed;
122
- const defaultModel = models?.default;
123
- const active = (0, import_ee.isBuilderModelPolicyActive)({
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
- // src/ee/agent-builder-agent.ts
146
- var import_agent = require("@mastra/core/agent");
147
- var import_memory = require("@mastra/memory");
148
- var import_processors = require("@mastra/core/processors");
149
- var import_workspace = require("@mastra/core/workspace");
150
- var import_node_path = __toESM(require("path"), 1);
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
- var DEFAULT_BUILDER_ERROR_PROCESSORS = [
163
- new import_processors.StreamErrorRetryProcessor(),
164
- new import_processors.PrefillErrorHandler(),
165
- new import_processors.ProviderHistoryCompat()
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
- const memory = new import_memory.Memory();
169
- const callerErrorProcessors = args?.errorProcessors;
170
- const errorProcessors = Array.isArray(callerErrorProcessors) ? [...DEFAULT_BUILDER_ERROR_PROCESSORS, ...callerErrorProcessors] : callerErrorProcessors ?? DEFAULT_BUILDER_ERROR_PROCESSORS;
171
- const config = {
172
- instructions: `You are the Agent Builder.
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 \u2014 configure the agent end-to-end and deliver a short summary.
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\u2026"
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 \u2014 do not try to infer state from anywhere else, and do not re-call setters for fields whose directive says "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 \u2014 Understand the real outcome
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 \u2014 Define the agent's identity
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 \u2014 Decide capabilities
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 \u2014 Synthesize concise operating instructions
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** \u2014 what user request, schedule, event, file, row, ticket, or message starts a run.
234
- 2. **Owned outcome** \u2014 the exact result the produced agent is responsible for finishing.
235
- 3. **Available capabilities** \u2014 only capabilities actually attached or already available from the form snapshot, described in user-facing outcome terms.
236
- 4. **Missing-capability fallback** \u2014 what the produced agent does when a required integration, workspace, credential, or source is absent.
237
- 5. **Done criteria** \u2014 verifiable conditions that prove the job is finished, including tool confirmation or an explicit "not run" reason when verification is impossible.
238
- 6. **Final response format** \u2014 the receipt, summary, draft, diff summary, report, or confirmation the user receives.
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\u20134 short paragraphs or compact bullet groups. Target 1,200\u20132,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.
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 \u2014 Write the agent
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 \u2014 Confirm the agent configuration to the user
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\u20134 focused paragraphs or compact bullet groups. Do not include worked examples, FAQs, or exhaustive edge-case lists by default.
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
- model: "openai/gpt-5.5",
300
- memory,
301
- workspace,
302
- ...args || {},
303
- errorProcessors,
304
- id: "builder-agent",
305
- name: "Agent Builder Agent",
306
- description: "An agent that can build agents"
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
- // Annotate the CommonJS export names for ESM import in node:
311
- 0 && (module.exports = {
312
- EditorAgentBuilder,
313
- createBuilderAgent
314
- });
319
+ //#endregion
320
+ exports.EditorAgentBuilder = EditorAgentBuilder;
321
+ exports.createBuilderAgent = createBuilderAgent;
322
+
315
323
  //# sourceMappingURL=index.cjs.map