@mastra/core
Version:
Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack.
1 lines • 40.1 kB
Source Map (JSON)
{"version":3,"sources":["../../../src/agent-builder/ee/types.ts","../../../src/agent-builder/ee/errors.ts","../../../src/agent-builder/ee/normalize-candidate.ts","../../../src/agent-builder/ee/allowlist.ts","../../../src/agent-builder/ee/policy.ts","../../../src/agent-builder/ee/picker.ts"],"names":["getRegisteredProviders","parseModelString","isProviderRegistered"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { Provider, ModelForProvider } from '../../llm/model';\nimport type { SerializedMemoryConfig } from '../../memory/types';\nimport type { StorageBrowserRef, StorageWorkspaceRef } from '../../storage/types';\n\n/**\n * Allowlist entry for a known provider (one of the generated `Provider` strings).\n * `modelId` narrows to the union of model ids declared for that provider.\n * Omitting `modelId` is the **provider wildcard** — every model under the provider is allowed.\n */\nexport type KnownProviderEntry = {\n [P in Provider]: { provider: P; modelId?: ModelForProvider<P> };\n}[Provider];\n\n/**\n * Allowlist entry for a custom / gateway provider that isn't in the generated registry.\n *\n * The `kind: 'custom'` discriminant is **required** — without it, an arbitrary string\n * provider would silently bypass the typo protection that `KnownProviderEntry` gives.\n * `modelId` is `string` (with the `& {}` escape hatch keeping autocomplete usable).\n */\nexport type CustomProviderEntry = {\n kind: 'custom';\n provider: string;\n // string & {} preserves IDE autocomplete on call sites that still pass known model\n // strings, while making the type accept arbitrary gateway model ids.\n modelId?: string & {};\n};\n\n/**\n * Allowlist entry. Either a typed known-provider entry, or a tagged custom-provider entry.\n */\nexport type ProviderModelEntry = KnownProviderEntry | CustomProviderEntry;\n\n/**\n * Default model entry. Same shape as {@link ProviderModelEntry} but `modelId` is required —\n * a default needs to point at a specific model, not a whole provider.\n */\nexport type DefaultModelEntry =\n | { [P in Provider]: { provider: P; modelId: ModelForProvider<P> } }[Provider]\n | { kind: 'custom'; provider: string; modelId: string & {} };\n\n/**\n * Admin-controlled model policy for the Agent Builder.\n * Owned here; re-exported from `@mastra/core/agent-builder/ee` and the SDK.\n *\n * Invariants (enforced in Phase 4):\n * - `active: false` → all other fields ignored.\n * - `active: true` + `pickerVisible: false` (locked) → `default` MUST be set.\n * - When `allowed` is non-empty, `default` (if set) MUST satisfy `isModelAllowed(allowed, default)`.\n */\nexport interface BuilderModelPolicy {\n active: boolean;\n pickerVisible?: boolean;\n allowed?: ProviderModelEntry[];\n default?: DefaultModelEntry;\n}\n\n/**\n * Default values for agents created via the builder.\n * Used as fallbacks when the user doesn't specify a value.\n */\nexport interface BuilderAgentDefaults extends Record<string, unknown> {\n /** Default memory configuration for new agents */\n memory?: SerializedMemoryConfig;\n /** Default workspace reference for new agents */\n workspace?: StorageWorkspaceRef;\n /** Default browser configuration for new agents */\n browser?: StorageBrowserRef;\n /**\n * Admin-controlled model allowlist + default applied to new agents.\n * `allowed` empty/undefined ⇒ no restriction. `default` (if set) is preselected on create.\n * See parent RFC for full semantics (wildcards, custom gateways, deny-by-default).\n */\n models?: {\n allowed?: ProviderModelEntry[];\n default?: DefaultModelEntry;\n };\n /**\n * Admin-controlled allowlist of tool IDs visible in the builder tools picker.\n *\n * Semantics:\n * - omitted (`undefined`) ⇒ unrestricted; show all registered tools.\n * - `allowed: []` ⇒ empty picker (explicit lockdown).\n * - `allowed: [...ids]` ⇒ show only the listed tool IDs.\n *\n * IDs are `tool.id` (preferred — what you see in the UI, URLs and traces)\n * but the registration key (the property name under `Mastra({ tools: {…} })`)\n * is also accepted as an alias. Matched against the registered tools at\n * request time. Unknown IDs are dropped and surfaced as warnings.\n */\n tools?: {\n allowed?: string[];\n };\n /**\n * Admin-controlled allowlist of agent IDs visible in the builder sub-agents picker.\n *\n * Semantics:\n * - omitted (`undefined`) ⇒ unrestricted; show all registered agents.\n * - `allowed: []` ⇒ empty picker (explicit lockdown).\n * - `allowed: [...ids]` ⇒ show only the listed agent IDs.\n *\n * IDs are `Agent.id` (preferred — what you see in the UI, URLs and traces)\n * but the registration key (the property name under `Mastra({ agents: {…} })`)\n * is also accepted as an alias. Matched against the registered agents at\n * request time. Unknown IDs are dropped and surfaced as warnings.\n */\n agents?: {\n allowed?: string[];\n };\n /**\n * Admin-controlled allowlist of workflow IDs visible in the builder workflows picker.\n *\n * Semantics:\n * - omitted (`undefined`) ⇒ unrestricted; show all registered workflows.\n * - `allowed: []` ⇒ empty picker (explicit lockdown).\n * - `allowed: [...ids]` ⇒ show only the listed workflow IDs.\n *\n * IDs are `workflow.id` (preferred — what you see in the UI, URLs and traces)\n * but the registration key (the property name under `Mastra({ workflows: {…} })`)\n * is also accepted as an alias. Matched against the registered workflows at\n * request time. Unknown IDs are dropped and surfaced as warnings.\n */\n workflows?: {\n allowed?: string[];\n };\n}\n\n/**\n * Feature toggles for the agent editor surface.\n * Each key controls visibility of that section in the builder UI.\n *\n * **Semantic: omitted = true (allowlist model — features default ON)**\n * - omitted or `true` — feature is visible to users\n * - `false` — feature is hidden\n *\n * Admins opt OUT of features by setting them to `false`. The raw\n * `AgentFeatures` shape carries `undefined`/`true`/`false`; the resolved\n * shape produced by {@link resolveAgentFeatures} is fully populated and is\n * what consumers (server handlers, UI hooks) actually read via\n * `IAgentBuilder.getFeatures()`.\n *\n * Consumer code should use strict equality on the resolved shape:\n * ```ts\n * const showTools = builder.getFeatures()?.agent?.tools === true;\n * ```\n *\n * Special case — `browser`: defaults to `true` ONLY when a valid\n * `configuration.agent.browser` (with `config.provider`) is provided.\n * Without a provider, the toggle has no backend, so the resolved value is\n * `false` regardless of the omitted-default. An explicit `browser: true`\n * with missing/invalid config is downgraded to `false` and surfaced as a\n * warning by `EditorAgentBuilder` (admin error feedback).\n */\nexport interface AgentFeatures {\n tools?: boolean;\n agents?: boolean;\n workflows?: boolean;\n scorers?: boolean;\n skills?: boolean;\n memory?: boolean;\n variables?: boolean;\n /** Favorite agents and skills with per-user state and aggregate counts. */\n favorites?: boolean;\n avatarUpload?: boolean;\n /**\n * Allow end-users to enable browser access for their agents.\n * Defaults to `true` only when a valid browser provider is configured;\n * otherwise resolves to `false`. See doc above for the full rule.\n */\n browser?: boolean;\n /**\n * Whether the model picker is visible to end-users in the Agent Builder.\n * Omitted ⇒ picker visible (default-on). `false` ⇒ picker hidden (locked\n * mode); admin's `models.default` is applied.\n * When visible, choices are filtered by `models.allowed` if set.\n */\n model?: boolean;\n}\n\n/**\n * Default-on values for {@link AgentFeatures}. `browser` is defaulted\n * dynamically by {@link resolveAgentFeatures} based on configuration; it is\n * intentionally absent here so the shape mirrors what `resolveAgentFeatures`\n * unconditionally fills in.\n */\nexport const BUILDER_FEATURE_DEFAULTS: Required<Omit<AgentFeatures, 'browser'>> = {\n tools: true,\n agents: true,\n workflows: true,\n scorers: true,\n skills: true,\n memory: true,\n variables: true,\n favorites: true,\n avatarUpload: true,\n model: true,\n};\n\n/**\n * Context required to resolve {@link AgentFeatures} defaults. Lives separately\n * from the raw config so this helper stays pure and synchronous.\n */\nexport interface ResolveAgentFeaturesContext {\n /**\n * Whether `configuration.agent.browser` declares a valid provider.\n * Drives the default-on/off decision for `features.agent.browser`.\n */\n hasBrowserConfig: boolean;\n}\n\n/**\n * Pure normalization of the raw {@link AgentFeatures} into a fully-populated\n * shape with default-on semantics applied.\n *\n * Rules:\n * - Explicit `false` always wins (admin opt-out).\n * - Explicit `true` wins for non-`browser` keys.\n * - Omitted keys resolve to `true` (except `browser`, see below).\n * - `browser`:\n * - explicit `false` ⇒ `false`.\n * - explicit `true` + `hasBrowserConfig: false` ⇒ `false` (caller is\n * responsible for emitting a warning; this helper does not throw).\n * - explicit `true` + `hasBrowserConfig: true` ⇒ `true`.\n * - omitted ⇒ `hasBrowserConfig` (default-on only when prerequisite met).\n */\nexport function resolveAgentFeatures(\n raw: AgentFeatures | undefined,\n ctx: ResolveAgentFeaturesContext,\n): Required<AgentFeatures> {\n const pick = <K extends keyof typeof BUILDER_FEATURE_DEFAULTS>(key: K): boolean => {\n const explicit = raw?.[key];\n return explicit === undefined ? BUILDER_FEATURE_DEFAULTS[key] : explicit;\n };\n\n const resolveBrowser = (): boolean => {\n const explicit = raw?.browser;\n if (explicit === false) return false;\n if (explicit === true) return ctx.hasBrowserConfig;\n return ctx.hasBrowserConfig;\n };\n\n return {\n tools: pick('tools'),\n agents: pick('agents'),\n workflows: pick('workflows'),\n scorers: pick('scorers'),\n skills: pick('skills'),\n memory: pick('memory'),\n variables: pick('variables'),\n favorites: pick('favorites'),\n avatarUpload: pick('avatarUpload'),\n model: pick('model'),\n browser: resolveBrowser(),\n };\n}\n\n/**\n * Configuration for the Agent Builder EE feature.\n * Passed to `MastraEditorConfig.builder`.\n *\n * All fields are optional. JSON-safe (no functions, no class instances).\n */\nexport interface AgentBuilderOptions {\n /**\n * Whether the builder is enabled. Default: true.\n * Set to false to disable the builder without removing the config.\n */\n enabled?: boolean;\n\n /**\n * Deployment-level feature toggles.\n * Key presence means \"this surface exists for this deployment.\"\n */\n features?: {\n agent?: AgentFeatures;\n };\n\n /**\n * Admin-pinned values applied to every artifact the builder produces.\n * Not overridable by end-users.\n *\n * Known fields are typed explicitly; additional fields allowed for extensibility.\n */\n configuration?: {\n agent?: BuilderAgentDefaults;\n };\n\n /**\n * Skill registries the Agent Builder is allowed to browse and install from.\n *\n * Each registry is opt-in. When no registries are enabled, the Builder hides\n * registry browse UI entirely. When at least one is enabled, the Builder\n * shows a \"Browse registries\" entry alongside \"Create skill\".\n */\n registries?: {\n /**\n * The public skills.sh registry (https://skills.sh).\n * Off by default — admins must explicitly opt in.\n */\n skillsSh?: {\n /** When true, the Builder may browse and install from skills.sh. */\n enabled: boolean;\n };\n };\n}\n\n/**\n * Public interface for the Agent Builder.\n * Implemented by EditorAgentBuilder in @mastra/editor/ee.\n */\nexport interface IAgentBuilder {\n readonly enabled: boolean;\n getFeatures(): AgentBuilderOptions['features'];\n getConfiguration(): AgentBuilderOptions['configuration'];\n /**\n * The opt-in skill registries this Builder is allowed to browse and install\n * from. Returns `undefined` when the admin has not configured any registries.\n */\n getRegistries?(): AgentBuilderOptions['registries'];\n /**\n * Optional warnings produced during construction-time validation\n * (e.g. allowlist entries with unknown providers that lack `kind: 'custom'`).\n * Surfaced via `GET /editor/builder/settings.modelPolicyWarnings` for admin UI display.\n */\n getModelPolicyWarnings?(): string[];\n}\n","import type { ModelCandidate } from './normalize-candidate';\nimport type { ProviderModelEntry } from './types';\n\nexport const MODEL_NOT_ALLOWED_CODE = 'MODEL_NOT_ALLOWED' as const;\n\n/**\n * Thrown by `enforceModelAllowlist` call sites when a write attempts to persist\n * a model that the active builder allowlist does not permit.\n *\n * Lives in `@mastra/core` so editor and server layers can both throw it\n * without crossing package boundaries. The server adapter\n * (`packages/server/src/server/handlers/error.ts`) maps this to HTTP 422 with\n * a structured JSON body of the same shape.\n */\nexport class ModelNotAllowedError extends Error {\n readonly code = MODEL_NOT_ALLOWED_CODE;\n readonly allowed: ProviderModelEntry[] | undefined;\n readonly attempted: ModelCandidate;\n readonly offendingLabel: string;\n\n constructor(args: {\n allowed: ProviderModelEntry[] | undefined;\n attempted: ModelCandidate;\n offendingLabel: string;\n message?: string;\n }) {\n const message =\n args.message ??\n `Model \"${args.attempted.provider}/${args.attempted.modelId}\" (${args.offendingLabel}) is not in the configured allowlist.`;\n super(message);\n this.name = 'ModelNotAllowedError';\n this.allowed = args.allowed;\n this.attempted = args.attempted;\n this.offendingLabel = args.offendingLabel;\n }\n}\n\nexport function isModelNotAllowedError(error: unknown): error is ModelNotAllowedError {\n return error instanceof Error && (error as { code?: unknown }).code === MODEL_NOT_ALLOWED_CODE;\n}\n","import { getRegisteredProviders, parseModelString } from '../../llm/model/provider-registry.js';\nimport type { MastraModelConfig } from '../../llm/model/shared.types.js';\nimport type { StorageConditionalField, StorageConditionalVariant, StorageModelConfig } from '../../storage/types.js';\n\nexport type ModelCandidateOrigin =\n | 'static'\n | 'conditional-variant'\n | 'conditional-default'\n | 'runtime'\n | 'list'\n | 'sdk-instance'\n | 'openai-compatible';\n\n/**\n * A single normalized provider/model candidate extracted from one of the many\n * shapes a model can be expressed in across the codebase.\n *\n * `origin` records which dispatch branch produced the candidate, mainly for\n * error messages on conditional variants.\n *\n * `label` is a short human-friendly description (variant index / SDK provider id\n * / etc.) used by `enforceModelAllowlist` when reporting the offending entry.\n */\nexport interface ModelCandidate {\n provider: string;\n modelId: string;\n origin: ModelCandidateOrigin;\n label?: string;\n}\n\n/**\n * Anything we accept as input to {@link toModelCandidates}. Kept open so call\n * sites can pass arbitrary stored or runtime model values without manual coercion.\n */\nexport type ModelCandidateInput =\n | string\n | MastraModelConfig\n | StorageModelConfig\n | StorageConditionalField<StorageModelConfig>\n | StorageConditionalVariant<string>[]\n | { provider?: unknown; modelId?: unknown; name?: unknown; id?: unknown; providerId?: unknown }\n | ((...args: unknown[]) => unknown)\n | null\n | undefined;\n\n/**\n * Gateway-aware split of a runtime model string. `parseModelString` only splits\n * on the first slash, which fails for gateway provider IDs that themselves\n * contain a slash (e.g. `acme/custom/foo-1`). We try the longest registered\n * provider prefix first and fall back to the first-slash split when no match\n * is found in the registry.\n */\nfunction splitRuntimeModelString(input: string): { provider: string; modelId: string } | undefined {\n const providers = getRegisteredProviders().sort((a, b) => b.length - a.length);\n for (const providerId of providers) {\n const prefix = `${providerId}/`;\n if (input.startsWith(prefix)) {\n const modelId = input.slice(prefix.length);\n if (modelId.length > 0) return { provider: providerId, modelId };\n }\n }\n const parsed = parseModelString(input);\n if (parsed.provider && parsed.modelId) {\n return { provider: parsed.provider, modelId: parsed.modelId };\n }\n return undefined;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction fromObject(value: Record<string, unknown>, origin: ModelCandidateOrigin, label?: string): ModelCandidate[] {\n // SDK instance: AI SDK language models expose `provider` + `modelId`.\n const providerField = value.provider;\n const modelIdField = value.modelId;\n const nameField = value.name;\n const idField = value.id;\n const providerIdField = value.providerId;\n\n // OpenAICompatibleConfig `{ id: 'provider/model' }` — must be checked before\n // `{ provider, modelId }` so AI SDK instances (which also have `provider`)\n // don't get pre-empted by a stale `id` lookup.\n if (typeof idField === 'string' && idField.includes('/') && providerField === undefined) {\n const split = splitRuntimeModelString(idField);\n if (split) {\n return [{ ...split, origin: 'openai-compatible', label: label ?? idField }];\n }\n }\n\n // OpenAICompatibleConfig `{ providerId, modelId }`\n if (typeof providerIdField === 'string' && typeof modelIdField === 'string') {\n return [\n {\n provider: providerIdField,\n modelId: modelIdField,\n origin: 'openai-compatible',\n label: label ?? `${providerIdField}/${modelIdField}`,\n },\n ];\n }\n\n // AI SDK language model instance: `{ provider, modelId, ... doGenerate }`\n if (typeof providerField === 'string' && typeof modelIdField === 'string') {\n const isSdkInstance = typeof (value as { doGenerate?: unknown }).doGenerate === 'function';\n return [\n {\n provider: providerField,\n modelId: modelIdField,\n origin: isSdkInstance ? 'sdk-instance' : origin,\n label: label ?? `${providerField}/${modelIdField}`,\n },\n ];\n }\n\n // Stored static `{ provider, name }`\n if (typeof providerField === 'string' && typeof nameField === 'string') {\n return [\n {\n provider: providerField,\n modelId: nameField,\n origin,\n label: label ?? `${providerField}/${nameField}`,\n },\n ];\n }\n\n return [];\n}\n\n/**\n * Convert any supported model expression into a flat list of `{ provider, modelId }`\n * candidates. Empty array means \"could not statically determine\" — callers\n * should treat that as unenforced at this level (runtime defense in Phase 7\n * picks it up).\n *\n * Dispatch order:\n * 1. `null` / `undefined` / `function` → `[]` (dynamic, defer to runtime)\n * 2. `string` → gateway-aware split\n * 3. Conditional variants array → walk each variant\n * 4. Object → openai-compatible / SDK instance / stored static, see {@link fromObject}\n */\nexport function toModelCandidates(input: ModelCandidateInput): ModelCandidate[] {\n if (input === null || input === undefined) return [];\n\n if (typeof input === 'function') return [];\n\n if (typeof input === 'string') {\n const split = splitRuntimeModelString(input);\n if (!split) return [];\n return [{ ...split, origin: 'runtime', label: input }];\n }\n\n if (Array.isArray(input)) {\n const candidates: ModelCandidate[] = [];\n input.forEach((variant, index) => {\n if (!isPlainObject(variant)) return;\n const value = (variant as { value?: unknown }).value ?? variant;\n const hasRules = isPlainObject(variant) && 'rules' in variant && (variant as { rules?: unknown }).rules != null;\n const origin: ModelCandidateOrigin = hasRules ? 'conditional-variant' : 'conditional-default';\n const label = hasRules ? `variant[${index}]` : `variant[${index}] (default)`;\n if (typeof value === 'string') {\n const split = splitRuntimeModelString(value);\n if (split) {\n candidates.push({ ...split, origin, label });\n }\n return;\n }\n if (isPlainObject(value)) {\n candidates.push(...fromObject(value, origin, label));\n }\n });\n return candidates;\n }\n\n if (isPlainObject(input)) {\n return fromObject(input, 'static');\n }\n\n return [];\n}\n","import { isProviderRegistered } from '../../llm/model/provider-registry.js';\nimport { ModelNotAllowedError } from './errors.js';\nimport { toModelCandidates } from './normalize-candidate.js';\nimport type { ModelCandidate, ModelCandidateInput } from './normalize-candidate.js';\nimport type { ProviderModelEntry } from './types.js';\n\n/**\n * Candidate model to check against the allowlist.\n * Caller is responsible for normalizing the source shape via {@link toModelCandidates}\n * (in `./normalize-candidate.ts`) before reaching this matcher.\n */\nexport interface ModelMatchCandidate {\n provider: string;\n modelId: string;\n}\n\n/**\n * Single-entry match: provider equality (case-sensitive). When the entry omits\n * `modelId` it matches every model under that provider (provider wildcard).\n *\n * Custom (`kind: 'custom'`) entries match by exact provider string. Known-provider\n * entries match by exact provider string too — the typed surface is purely a\n * compile-time guard.\n */\nexport function matchesProvider(entry: ProviderModelEntry, candidate: ModelMatchCandidate): boolean {\n if (entry.provider !== candidate.provider) return false;\n if (!entry.modelId) return true; // wildcard\n return entry.modelId === candidate.modelId;\n}\n\n/**\n * Returns `true` if the candidate is allowed under the given allowlist.\n *\n * Rules:\n * - `undefined` allowlist ⇒ unrestricted (always `true`).\n * - `[]` empty allowlist ⇒ unrestricted (always `true`).\n * - Non-empty allowlist where **every** entry's provider is unknown to the\n * runtime registry AND not tagged `kind: 'custom'` ⇒ deny everything. This\n * prevents typos (e.g. `openaii`) from acting as an unintended deny-all that\n * silently allows anything else; it is the documented \"deny vs ignore\" rule.\n */\nexport function isModelAllowed(allowed: ProviderModelEntry[] | undefined, candidate: ModelMatchCandidate): boolean {\n if (allowed === undefined) return true;\n if (allowed.length === 0) return true;\n\n const activeEntries = allowed.filter(entry => {\n if ('kind' in entry && entry.kind === 'custom') return true;\n return isProviderRegistered(entry.provider);\n });\n\n if (activeEntries.length === 0) return false;\n\n return activeEntries.some(entry => matchesProvider(entry, candidate));\n}\n\n/**\n * Result of an allowlist enforcement check.\n *\n * `attempted` is the candidate (or list of candidates) that triggered the\n * decision; `offendingLabel` (when set) names the specific failing entry so\n * callers can surface it in error messages — particularly useful for\n * conditional model variants.\n */\nexport type EnforceModelAllowlistResult =\n | { ok: true }\n | {\n ok: false;\n attempted: ModelCandidate;\n offendingLabel: string;\n };\n\n/**\n * Apply an allowlist to any supported model expression. Normalizes via\n * `toModelCandidates`, then runs `isModelAllowed` per candidate. Returns the\n * **first** failing candidate so error messages can pinpoint which variant of\n * a conditional / fallback list violated the policy.\n *\n * If `toModelCandidates` returns no candidates (dynamic function, unparsable\n * shape) this passes — runtime defense (Phase 7) handles those cases.\n */\nexport function enforceModelAllowlist(\n allowed: ProviderModelEntry[] | undefined,\n input: ModelCandidateInput,\n): EnforceModelAllowlistResult {\n const candidates = toModelCandidates(input);\n for (const candidate of candidates) {\n if (!isModelAllowed(allowed, candidate)) {\n return {\n ok: false,\n attempted: candidate,\n offendingLabel: candidate.label ?? candidate.origin,\n };\n }\n }\n return { ok: true };\n}\n\n/**\n * Convenience wrapper around `enforceModelAllowlist` that throws\n * `ModelNotAllowedError` on rejection. Use at write call sites so the server\n * adapter can translate into HTTP 422 + structured body.\n */\nexport function assertModelAllowed(allowed: ProviderModelEntry[] | undefined, input: ModelCandidateInput): void {\n const result = enforceModelAllowlist(allowed, input);\n if (result.ok) return;\n throw new ModelNotAllowedError({\n allowed,\n attempted: result.attempted,\n offendingLabel: result.offendingLabel,\n });\n}\n","import type { IAgentBuilder, BuilderModelPolicy, DefaultModelEntry, ProviderModelEntry } from './types';\n\n/**\n * Inputs for the shared {@link isBuilderModelPolicyActive} predicate.\n *\n * Lives separately from {@link BuilderModelPolicy} because we need to ask the\n * \"is the model slice active?\" question at config-validation time, *before*\n * a `BuilderModelPolicy` has been built.\n */\nexport interface BuilderModelPolicyInputs {\n /** `AgentBuilderOptions.enabled` (defaulted: missing = `true`). */\n enabled: boolean;\n /** `features.agent.model` — `true` means picker visible. */\n pickerVisible: boolean;\n /** `configuration.agent.models.allowed`. */\n allowed?: ProviderModelEntry[];\n /** `configuration.agent.models.default`. */\n default?: DefaultModelEntry;\n}\n\n/**\n * Single source of truth for whether the admin has actually configured a model\n * policy. Reused by:\n * - {@link builderToModelPolicy} (UI / runtime derivation)\n * - `EditorAgentBuilder` config validation (Phase 4)\n * - Server-side enforcement gate (Phase 6)\n *\n * \"Active\" means the admin opted into the model slice in some way:\n * - the picker is visible (open-mode), OR\n * - an allowlist was set, OR\n * - a default model was set.\n *\n * If the builder is `enabled: false`, the slice is never active.\n */\nexport function isBuilderModelPolicyActive(inputs: BuilderModelPolicyInputs): boolean {\n if (!inputs.enabled) return false;\n if (inputs.pickerVisible) return true;\n if (inputs.allowed !== undefined) return true;\n if (inputs.default !== undefined) return true;\n return false;\n}\n\n/**\n * Pure derivation of the {@link BuilderModelPolicy} from an `IAgentBuilder`.\n * No `Mastra` / `IEditor` dependency — server and editor wrappers feed it\n * a builder instance through their own resolution paths.\n *\n * Returns `{ active: false }` when:\n * - the builder is missing,\n * - the builder is disabled, or\n * - none of the model-slice signals are present.\n *\n * In every active case, `allowed` and `default` are passed through verbatim\n * so locked-mode UI still has the data it needs to render the chosen model.\n */\nexport function builderToModelPolicy(builder: IAgentBuilder | undefined): BuilderModelPolicy {\n if (!builder || !builder.enabled) {\n return { active: false };\n }\n\n const features = builder.getFeatures();\n const configuration = builder.getConfiguration();\n const pickerVisible = features?.agent?.model === true;\n const models = configuration?.agent?.models;\n const allowed = models?.allowed;\n const defaultModel = models?.default;\n\n const active = isBuilderModelPolicyActive({\n enabled: builder.enabled,\n pickerVisible,\n allowed,\n default: defaultModel,\n });\n\n if (!active) {\n return { active: false };\n }\n\n return {\n active: true,\n pickerVisible,\n ...(allowed !== undefined ? { allowed } : {}),\n ...(defaultModel !== undefined ? { default: defaultModel } : {}),\n };\n}\n","import type { BuilderAgentDefaults } from './types';\n\n/**\n * Resolved picker visibility for the Agent Builder configure panel.\n *\n * One field per kind (tools / agents / workflows).\n * - `null` ⇒ unrestricted (show all registered entries).\n * - `string[]` ⇒ explicit allowlist (may be empty to show none).\n */\nexport interface ResolvedPickerVisibility {\n visibleTools: string[] | null;\n visibleAgents: string[] | null;\n visibleWorkflows: string[] | null;\n /** Non-fatal warnings (e.g. unknown IDs in any allowlist). */\n warnings: string[];\n}\n\nexport interface ResolvePickerVisibilityInputs {\n /** The `agent` slice of `AgentBuilderOptions['configuration']`. */\n config: BuilderAgentDefaults | undefined;\n /** All tool IDs currently registered with the Mastra instance. */\n registeredToolIds: readonly string[];\n /** All agent IDs currently registered with the Mastra instance. */\n registeredAgentIds: readonly string[];\n /** All workflow IDs currently registered with the Mastra instance. */\n registeredWorkflowIds: readonly string[];\n}\n\ninterface ResolveOneResult {\n visible: string[] | null;\n warnings: string[];\n}\n\nfunction resolveOne(\n allowlist: string[] | undefined,\n registered: readonly string[],\n kindLabel: string,\n configPath: string,\n): ResolveOneResult {\n if (allowlist === undefined) {\n return { visible: null, warnings: [] };\n }\n\n const known = new Set(registered);\n const seen = new Set<string>();\n const visible: string[] = [];\n const warnings: string[] = [];\n\n for (const id of allowlist) {\n if (seen.has(id)) continue;\n seen.add(id);\n if (known.has(id)) {\n visible.push(id);\n } else {\n warnings.push(\n `${configPath} references unknown ${kindLabel} \"${id}\" — no ${kindLabel} with this ID is registered. It will be hidden from the builder picker.`,\n );\n }\n }\n\n return { visible, warnings };\n}\n\n/**\n * Pure derivation of {@link ResolvedPickerVisibility} from admin config and\n * the registered tool/agent/workflow sets.\n *\n * Per kind:\n * - allowlist undefined ⇒ `null` (unrestricted), no warnings.\n * - allowlist provided ⇒ filter to known IDs; emit one warning per unknown ID.\n *\n * Stable order: each visible list preserves admin-provided order with unknowns\n * dropped. Duplicates are de-duplicated.\n */\nexport function resolvePickerVisibility({\n config,\n registeredToolIds,\n registeredAgentIds,\n registeredWorkflowIds,\n}: ResolvePickerVisibilityInputs): ResolvedPickerVisibility {\n const tools = resolveOne(config?.tools?.allowed, registeredToolIds, 'tool', 'configuration.agent.tools.allowed');\n const agents = resolveOne(config?.agents?.allowed, registeredAgentIds, 'agent', 'configuration.agent.agents.allowed');\n const workflows = resolveOne(\n config?.workflows?.allowed,\n registeredWorkflowIds,\n 'workflow',\n 'configuration.agent.workflows.allowed',\n );\n\n return {\n visibleTools: tools.visible,\n visibleAgents: agents.visible,\n visibleWorkflows: workflows.visible,\n warnings: [...tools.warnings, ...agents.warnings, ...workflows.warnings],\n };\n}\n"]}