import type { AuthStorage } from '@mastra/code-sdk/auth/storage'; import type { ModePack, ProviderAccess } from '@mastra/code-sdk/onboarding/packs'; import type { ThinkingLevelSetting } from '@mastra/code-sdk/onboarding/settings'; import type { ApiRoute } from '@mastra/core/server'; import type { CredentialRecord, LoginSessionKind, ModelCredentialsStorage } from '../storage/domains/credentials/base.js'; import type { CustomProvidersStorage } from '../storage/domains/custom-providers/base.js'; import type { MemorySettingsStorage } from '../storage/domains/memory-settings/base.js'; import type { ModelPacksStorage } from '../storage/domains/model-packs/base.js'; import type { FactoryProjectsStorage } from '../storage/domains/projects/base.js'; import type { SourceControlStorageHandle } from '../storage/domains/source-control/base.js'; import { Route } from './route.js'; import type { RouteDependencies } from './route.js'; /** * Server-side configuration routes for the web app. * * The browser has no access to the credential store or the model catalog, so * the web settings panel asks the server — which owns both — to list providers * and manage API keys. This mirrors the TUI's `/api-keys` command, exposing the * same `AuthStorage`-backed key management over HTTP. * * Keys are never returned to the client; only their presence and source. */ /** * Where a provider's active credential comes from, as seen by the caller. * Local mode reports `oauth`/`stored` (server-global `auth.json`); tenant mode * reports the scoped variants (`oauth-user`/`stored-user`/`stored-org`). */ export type ProviderCredentialSource = 'oauth' | 'stored' | 'env' | 'none' | 'oauth-user' | 'oauth-org' | 'stored-user' | 'stored-org'; /** A model provider with the current source of its credentials. */ export interface ProviderInfo { provider: string; /** Env var the provider's key is read from, if any. */ envVar?: string; /** Where the active credential comes from. */ source: ProviderCredentialSource; /** * Tenant mode: whether an org-wide API key exists for this provider, even * when the caller's personal credential shadows it. Lets the UI tell * "shared with the org" apart from "only works for me". */ orgKey?: boolean; /** * Tenant mode: the caller's personal credential for this provider, if any. * Reported independently of `source` so the UI can manage each scope even * when one shadows the other. */ userCredential?: 'oauth' | 'api_key'; /** Tenant mode: the shared org credential for this provider, if any. */ orgCredential?: 'oauth' | 'api_key'; /** Web OAuth sign-in capability, when the provider supports it. */ oauth?: { supported: true; modes: LoginSessionKind[]; }; } /** Minimal session surface a pack activation touches. */ interface PackSession { mode: { get: () => string; }; model: { switch: (args: { modelId: string; }) => Promise; }; subagents: { model: { set: (args: { modelId: string; agentType: string; }) => Promise; }; }; thread: { getId: () => string | null; getSetting: (args: { key: string; }) => Promise; setSetting: (args: { key: string; value: unknown; }) => Promise; }; } /** One observational-memory role's read/switch surface. */ interface OMRole { modelId: () => string | undefined; threshold: () => number | undefined; switchModel: (args: { modelId: string; }) => Promise; } /** * Session-state fields the OM config routes write. The index signatures mirror * `MastraCodeState` so the concrete `Session.state.set(Partial)` * stays assignable to this minimal surface (contravariant parameter check). */ interface OMStateWrites { [key: string]: unknown; [key: `subagentModelId_${string}`]: string | undefined; observationThreshold?: number; reflectionThreshold?: number; observeAttachments?: 'auto' | boolean; } /** Minimal session surface the OM config routes touch. */ export interface OMSession extends PackSession { state: { get: () => Record | undefined; set: (updates: OMStateWrites) => Promise | void; }; om: { observer: OMRole; reflector: OMRole; }; } /** Minimal controller surface this module needs (model catalog + modes + sessions). */ interface ModelCatalog { listAvailableModels: () => Promise>; listModes?: () => Array<{ id: string; defaultModelId?: string; }>; getSessionByResource?: (resourceId: string, scope?: string) => Promise; } /** * Build a deduplicated, sorted list of providers from the model catalog, * annotated with where each provider's credential currently comes from. * Mirrors the TUI's `/api-keys` provider list. * * When `tenantCredentials` is given (deployed mode), sources reflect the * *caller's* tenant rows with user > org precedence and the server-global * `authStorage` is ignored; otherwise the local `auth.json` view is reported. */ export declare function listProviders({ controller, authStorage, tenantCredentials, }: { controller: ModelCatalog; authStorage?: AuthStorage; tenantCredentials?: CredentialRecord[]; }): Promise; /** A user-defined OpenAI-compatible provider, with key presence (never the key). */ export interface CustomProviderInfo { id: string; name: string; url: string; hasApiKey: boolean; models: string[]; } /** A model pack as surfaced to the web client, with an `active` flag. */ export interface ModelPackInfo extends ModePack { custom: boolean; active: boolean; } /** * Compute which providers the user can reach, mirroring the TUI's * `/models-pack` access derivation: OAuth/api-key from the credential store for * the named providers, plus any other provider that has a usable key. */ export declare function buildProviderAccess({ controller, authStorage, tenantCredentials, }: { controller: ModelCatalog; authStorage?: AuthStorage; tenantCredentials?: CredentialRecord[]; }): Promise; /** * Where a request's custom model packs live. Same posture as memory settings * and custom providers: the `model-packs` factory storage domain, scoped per * org in deployed mode and to a sentinel `local` org in no-auth mode — never * settings.json. */ export interface PackContext { storage: ModelPacksStorage; orgId: string; userId: string; } /** * List available model packs (built-in, gated by provider access, plus saved * custom packs from the request's pack context). Drops the synthetic * "New Custom" placeholder because the web client has its own create flow. * `active` marks the user's default pack for new interactive chats. */ export declare function listModelPacks({ controller, authStorage, tenantCredentials, packContext, activePackId, }: { controller: ModelCatalog; authStorage?: AuthStorage; tenantCredentials?: CredentialRecord[]; packContext: PackContext; activePackId?: string | null; }): Promise; /** Read the current OM config from a session. */ export interface OMConfigInfo { observerModelId: string; reflectorModelId: string; observationThreshold: number; reflectionThreshold: number; observeAttachments: 'auto' | boolean; } export interface ProviderOMDefaultsResponse { ok: true; config: OMConfigInfo; } /** `GET /web/config/thinking` — deployment-scoped reasoning-effort defaults. */ export interface ThinkingConfigInfo { /** All selectable levels, in escalation order. */ levels: readonly ThinkingLevelSetting[]; /** `preferences.thinkingLevel` — fallback when a mode has no default. */ globalDefault: ThinkingLevelSetting; /** `models.modeThinkingDefaults` — per-mode overrides of the global default. */ modeDefaults: Record; /** Mode ids known to the controller (for rendering per-mode rows). */ modes: string[]; /** False when the deployment refuses writes, so the UI can render read-only rows. */ editable: boolean; } /** `PUT /web/config/thinking` success payload. */ export interface UpdateThinkingConfigResponse { ok: true; globalDefault: ThinkingLevelSetting; modeDefaults: Record; } export declare function readOMConfig(session: OMSession): OMConfigInfo; /** Dependencies injected into {@link ConfigRoutes}. */ export interface ConfigRoutesDeps extends RouteDependencies { controller: ModelCatalog; features?: { knowledge: boolean; }; authStorage?: AuthStorage; /** Tenant credential domain handle; absent in local (no-DB) mode. */ modelCredentials?: ModelCredentialsStorage; /** Tenant model-packs domain handle; absent in local (no-DB) mode. */ modelPacks?: ModelPacksStorage; /** Source-control sessions used to authorize session-scoped model-pack access. */ sourceControlSessions?: Pick; /** Tenant memory-settings domain handle; absent in local (no-DB) mode. */ memorySettings?: MemorySettingsStorage; /** Factory projects domain, used to derive OM fallbacks from a factory's default model. */ factoryProjects?: FactoryProjectsStorage; /** Custom-providers domain handle; absent when the app database is missing. */ customProviders?: CustomProvidersStorage; /** Notifies the host after tenant credentials change so caches can be dropped. */ onCredentialsChanged?: (tenant: { orgId: string; userId?: string; }) => void; /** Notifies the host after custom providers change so model-router caches can be dropped. */ onCustomProvidersChanged?: (tenant: { orgId: string; }) => void; /** * Path of the server's settings.json backing the deployment-scoped thinking * defaults. Defaults to the standard app-data location; injectable for tests. */ settingsPath?: string; } /** * The web config routes as Mastra `apiRoutes`: * - `GET /web/config/features` — list server-enabled product features * - `GET /web/config/providers` — list providers + key source * - `PUT /web/config/providers/:provider/key` — set/update a provider's API key * - `DELETE /web/config/providers/:provider/key` — remove a stored API key * - `GET /web/config/models` — list available models (credentialed providers) * - `GET /web/config/custom-providers` — list custom OpenAI-compatible providers * - `POST /web/config/custom-providers` — create/update a custom provider * - `DELETE /web/config/custom-providers/:id` — remove a custom provider * - `GET /web/config/thinking` — read thinking (reasoning-effort) defaults * - `PUT /web/config/thinking` — set global/per-mode thinking defaults * - `GET /web/config/om` — read OM models/thresholds/observe-attachments * - `PUT /web/config/om/:role/model` — switch observer/reflector model * - `PUT /web/config/om/thresholds` — set observation/reflection thresholds * - `PUT /web/config/om/observe-attachments` — set observe-attachments (auto/on/off) */ export declare class ConfigRoutes extends Route { routes(): ApiRoute[]; } export {}; //# sourceMappingURL=config.d.ts.map