@mastra/factory 0.9.0-alpha.2 → 0.9.0-alpha.3

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/factory.d.ts.map +1 -1
  3. package/dist/factory.js +4 -4
  4. package/dist/factory.js.map +1 -1
  5. package/dist/integrations/platform/api-client.d.ts.map +1 -1
  6. package/dist/integrations/platform/api-client.js +2 -2
  7. package/dist/integrations/platform/api-client.js.map +1 -1
  8. package/dist/integrations/slack/slack.d.ts +2 -1
  9. package/dist/integrations/slack/slack.d.ts.map +1 -1
  10. package/dist/integrations/slack/slack.js +7 -3
  11. package/dist/integrations/slack/slack.js.map +1 -1
  12. package/dist/routes/config.d.ts +12 -1
  13. package/dist/routes/config.d.ts.map +1 -1
  14. package/dist/routes/config.js +74 -20
  15. package/dist/routes/config.js.map +1 -1
  16. package/dist/routes/oauth.d.ts +3 -3
  17. package/dist/routes/oauth.d.ts.map +1 -1
  18. package/dist/routes/oauth.js +36 -19
  19. package/dist/routes/oauth.js.map +1 -1
  20. package/dist/routes/surface.d.ts.map +1 -1
  21. package/dist/routes/surface.js +1 -0
  22. package/dist/routes/surface.js.map +1 -1
  23. package/dist/routes/tenant-credentials.d.ts +1 -1
  24. package/dist/routes/tenant-credentials.d.ts.map +1 -1
  25. package/dist/routes/tenant-credentials.js +12 -7
  26. package/dist/routes/tenant-credentials.js.map +1 -1
  27. package/dist/rules/start-coordinator.d.ts.map +1 -1
  28. package/dist/rules/start-coordinator.js +9 -3
  29. package/dist/rules/start-coordinator.js.map +1 -1
  30. package/dist/session/factory-session.d.ts +11 -2
  31. package/dist/session/factory-session.d.ts.map +1 -1
  32. package/dist/session/factory-session.js +8 -4
  33. package/dist/session/factory-session.js.map +1 -1
  34. package/dist/session/memory-settings-hydration.d.ts +1 -1
  35. package/dist/session/memory-settings-hydration.d.ts.map +1 -1
  36. package/dist/session/memory-settings-hydration.js +2 -2
  37. package/dist/session/memory-settings-hydration.js.map +1 -1
  38. package/dist/storage/domains/credentials/base.d.ts +9 -5
  39. package/dist/storage/domains/credentials/base.d.ts.map +1 -1
  40. package/dist/storage/domains/credentials/base.js +34 -27
  41. package/dist/storage/domains/credentials/base.js.map +1 -1
  42. package/dist/storage/domains/memory-settings/base.d.ts +8 -0
  43. package/dist/storage/domains/memory-settings/base.d.ts.map +1 -1
  44. package/dist/storage/domains/memory-settings/base.js +11 -1
  45. package/dist/storage/domains/memory-settings/base.js.map +1 -1
  46. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","names":[],"sources":["../../src/routes/config.ts"],"sourcesContent":["import type { AuthStorage } from '@mastra/code-sdk/auth/storage';\nimport { DEFAULT_OM_MODEL_ID } from '@mastra/code-sdk/constants';\nimport { getAvailableModePacks, resolveProviderOMDefault } from '@mastra/code-sdk/onboarding/packs';\nimport type { ModePack, ProviderAccess, ProviderAccessLevel } from '@mastra/code-sdk/onboarding/packs';\nimport {\n getCustomProviderId,\n isThinkingLevelSetting,\n loadSettings,\n saveSettings,\n THINKING_LEVEL_VALUES,\n} from '@mastra/code-sdk/onboarding/settings';\nimport type { CustomProviderSetting, ThinkingLevelSetting } from '@mastra/code-sdk/onboarding/settings';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\n\nimport type { Context } from 'hono';\nimport {\n applyStoredMemorySettings,\n DEFAULT_OBSERVATION_THRESHOLD,\n DEFAULT_REFLECTION_THRESHOLD,\n} from '../session/memory-settings-hydration.js';\nimport { applyActiveModelPack } from '../session/model-pack-hydration.js';\nimport type {\n CredentialRecord,\n LoginSessionKind,\n ModelCredentialsStorage,\n} from '../storage/domains/credentials/base.js';\nimport type { CustomProviderRecord, CustomProvidersStorage } from '../storage/domains/custom-providers/base.js';\nimport type {\n MemorySettingsFillIfUnset,\n MemorySettingsPatch,\n MemorySettingsRecord,\n MemorySettingsStorage,\n} from '../storage/domains/memory-settings/base.js';\nimport type { ModelPackRecord, ModelPacksStorage } from '../storage/domains/model-packs/base.js';\nimport type { SourceControlStorageHandle } from '../storage/domains/source-control/base.js';\nimport {\n getAuthProviderId,\n listTenantCredentialsForRequest,\n resolveCredentialContext,\n tenantOrgId,\n WEB_OAUTH_FLOW_KINDS,\n} from './provider-credentials.js';\nimport { Route } from './route.js';\nimport type { RouteAuth, RouteDependencies } from './route.js';\n\n/** Widen a route-local Hono context to the plain `Context` the auth helpers take. */\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\n/**\n * Server-side configuration routes for the web app.\n *\n * The browser has no access to the credential store or the model catalog, so\n * the web settings panel asks the server — which owns both — to list providers\n * and manage API keys. This mirrors the TUI's `/api-keys` command, exposing the\n * same `AuthStorage`-backed key management over HTTP.\n *\n * Keys are never returned to the client; only their presence and source.\n */\n\n/**\n * Where a provider's active credential comes from, as seen by the caller.\n * Local mode reports `oauth`/`stored` (server-global `auth.json`); tenant mode\n * reports the scoped variants (`oauth-user`/`stored-user`/`stored-org`).\n */\nexport type ProviderCredentialSource =\n | 'oauth'\n | 'stored'\n | 'env'\n | 'none'\n | 'oauth-user'\n | 'stored-user'\n | 'stored-org';\n\n/** A model provider with the current source of its credentials. */\nexport interface ProviderInfo {\n provider: string;\n /** Env var the provider's key is read from, if any. */\n envVar?: string;\n /** Where the active credential comes from. */\n source: ProviderCredentialSource;\n /**\n * Tenant mode: whether an org-wide API key exists for this provider, even\n * when the caller's personal credential shadows it. Lets the UI tell\n * \"shared with the org\" apart from \"only works for me\".\n */\n orgKey?: boolean;\n /** Web OAuth sign-in capability, when the provider supports it. */\n oauth?: { supported: true; modes: LoginSessionKind[] };\n}\n\n/** Minimal session surface a pack activation touches. */\ninterface PackSession {\n mode: { get: () => string };\n model: { switch: (args: { modelId: string }) => Promise<void> };\n subagents: { model: { set: (args: { modelId: string; agentType: string }) => Promise<void> } };\n thread: {\n getId: () => string | null;\n getSetting: (args: { key: string }) => Promise<unknown>;\n setSetting: (args: { key: string; value: unknown }) => Promise<void>;\n };\n}\n\n/** One observational-memory role's read/switch surface. */\ninterface OMRole {\n modelId: () => string | undefined;\n threshold: () => number | undefined;\n switchModel: (args: { modelId: string }) => Promise<void>;\n}\n\n/**\n * Session-state fields the OM config routes write. The index signatures mirror\n * `MastraCodeState` so the concrete `Session.state.set(Partial<MastraCodeState>)`\n * stays assignable to this minimal surface (contravariant parameter check).\n */\ninterface OMStateWrites {\n [key: string]: unknown;\n [key: `subagentModelId_${string}`]: string | undefined;\n observationThreshold?: number;\n reflectionThreshold?: number;\n observeAttachments?: 'auto' | boolean;\n}\n\n/** Minimal session surface the OM config routes touch. */\nexport interface OMSession extends PackSession {\n state: {\n get: () => Record<string, unknown> | undefined;\n set: (updates: OMStateWrites) => Promise<void> | void;\n };\n om: { observer: OMRole; reflector: OMRole };\n}\n\n/** Minimal controller surface this module needs (model catalog + modes + sessions). */\ninterface ModelCatalog {\n listAvailableModels: () => Promise<\n Array<{ id?: string; modelName?: string; provider: string; hasApiKey: boolean; apiKeyEnvVar?: string }>\n >;\n listModes?: () => Array<{ id: string; defaultModelId?: string }>;\n getSessionByResource?: (resourceId: string, scope?: string) => Promise<OMSession | undefined>;\n}\n\n/**\n * Build a deduplicated, sorted list of providers from the model catalog,\n * annotated with where each provider's credential currently comes from.\n * Mirrors the TUI's `/api-keys` provider list.\n *\n * When `tenantCredentials` is given (deployed mode), sources reflect the\n * *caller's* tenant rows with user > org precedence and the server-global\n * `authStorage` is ignored; otherwise the local `auth.json` view is reported.\n */\nexport async function listProviders({\n controller,\n authStorage,\n tenantCredentials,\n}: {\n controller: ModelCatalog;\n authStorage?: AuthStorage;\n tenantCredentials?: CredentialRecord[];\n}): Promise<ProviderInfo[]> {\n const models = await controller.listAvailableModels();\n const seen = new Map<string, ProviderInfo>();\n\n for (const model of models) {\n if (seen.has(model.provider)) continue;\n\n const authProviderId = getAuthProviderId(model.provider);\n let source: ProviderInfo['source'] = 'none';\n let orgKey: boolean | undefined;\n if (tenantCredentials) {\n const userRec = tenantCredentials.find(r => r.scope === 'user' && r.provider === authProviderId);\n const orgRec = tenantCredentials.find(r => r.scope === 'org' && r.provider === authProviderId);\n orgKey = orgRec?.credential.type === 'api_key';\n if (userRec?.credential.type === 'oauth') {\n source = 'oauth-user';\n } else if (userRec?.credential.type === 'api_key') {\n source = 'stored-user';\n } else if (orgRec?.credential.type === 'api_key') {\n source = 'stored-org';\n }\n } else if (authStorage?.isLoggedIn(authProviderId)) {\n source = 'oauth';\n } else if (authStorage?.hasStoredApiKey(model.provider)) {\n source = 'stored';\n } else if (model.apiKeyEnvVar && process.env[model.apiKeyEnvVar]) {\n source = 'env';\n } else if (model.hasApiKey) {\n source = 'env';\n }\n\n const flowKind = WEB_OAUTH_FLOW_KINDS[model.provider];\n seen.set(model.provider, {\n provider: model.provider,\n envVar: model.apiKeyEnvVar,\n source,\n ...(orgKey !== undefined ? { orgKey } : {}),\n ...(flowKind ? { oauth: { supported: true as const, modes: [flowKind] } } : {}),\n });\n }\n\n return Array.from(seen.values()).sort((a, b) => a.provider.localeCompare(b.provider));\n}\n\n/** A user-defined OpenAI-compatible provider, with key presence (never the key). */\nexport interface CustomProviderInfo {\n id: string;\n name: string;\n url: string;\n hasApiKey: boolean;\n models: string[];\n}\n\n/** Redact a stored custom-provider row for the client (key presence only). */\nfunction toCustomProviderInfo(record: CustomProviderRecord): CustomProviderInfo {\n return {\n id: record.providerId,\n name: record.name,\n url: record.url,\n hasApiKey: Boolean(record.apiKey),\n models: record.models,\n };\n}\n\n/** The resolved custom-providers storage scope for a request. */\ninterface CustomProvidersContext {\n storage: CustomProvidersStorage;\n orgId: string;\n userId: string;\n}\n\n/**\n * Resolve the custom-providers context for a request, or a ready-to-return\n * error response. Same posture as memory settings: tenant rows in deployed\n * mode, a sentinel `local` org in no-auth mode — never settings.json.\n */\nasync function resolveCustomProvidersContext({\n c,\n auth,\n customProviders,\n}: {\n c: Context;\n auth: RouteAuth;\n customProviders?: CustomProvidersStorage;\n}): Promise<CustomProvidersContext | { response: Response }> {\n await auth.ensureUser(c);\n const tenant = auth.tenant(c);\n if (!tenant && auth.enabled()) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (customProviders) {\n try {\n await customProviders.ensureReady();\n return tenant\n ? { storage: customProviders, orgId: tenantOrgId(tenant), userId: tenant.userId }\n : { storage: customProviders, orgId: 'local', userId: 'local' };\n } catch {\n // fall through to the unavailable response\n }\n }\n return {\n response: c.json(\n {\n error: 'custom_providers_unavailable',\n message: 'Custom provider storage is unavailable — the app database is not configured or failed to start.',\n },\n 503,\n ),\n };\n}\n\n/** Validate + coerce a request body into a CustomProviderSetting. */\nfunction parseCustomProviderBody(body: unknown): CustomProviderSetting | { error: string } {\n if (!body || typeof body !== 'object') return { error: 'Invalid JSON body' };\n const b = body as Record<string, unknown>;\n const name = typeof b.name === 'string' ? b.name.trim() : '';\n if (!name) return { error: 'Missing required field: name' };\n const url = typeof b.url === 'string' ? b.url.trim() : '';\n if (!url) return { error: 'Missing required field: url' };\n try {\n const parsed = new URL(url);\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return { error: 'url must be an http(s) URL' };\n }\n } catch {\n return { error: 'url must be a valid URL' };\n }\n const apiKey = typeof b.apiKey === 'string' && b.apiKey.trim() ? b.apiKey.trim() : undefined;\n const models = Array.isArray(b.models)\n ? b.models.filter((m): m is string => typeof m === 'string' && m.trim().length > 0).map(m => m.trim())\n : [];\n return { name, url, apiKey, models };\n}\n\n// ── Model packs ──────────────────────────────────────────────────────────\n\n/** A model pack as surfaced to the web client, with an `active` flag. */\nexport interface ModelPackInfo extends ModePack {\n custom: boolean;\n active: boolean;\n}\n\n/**\n * Compute which providers the user can reach, mirroring the TUI's\n * `/models-pack` access derivation: OAuth/api-key from the credential store for\n * the named providers, plus any other provider that has a usable key.\n */\nexport async function buildProviderAccess({\n controller,\n authStorage,\n tenantCredentials,\n}: {\n controller: ModelCatalog;\n authStorage?: AuthStorage;\n tenantCredentials?: CredentialRecord[];\n}): Promise<ProviderAccess> {\n const models = await controller.listAvailableModels();\n const hasModelKey = (provider: string) => models.some(m => m.provider === provider && m.hasApiKey);\n const accessLevel = (provider: string): ProviderAccessLevel => {\n const authProviderId = getAuthProviderId(provider);\n if (tenantCredentials) {\n const userRec = tenantCredentials.find(r => r.scope === 'user' && r.provider === authProviderId);\n const orgRec = tenantCredentials.find(r => r.scope === 'org' && r.provider === authProviderId);\n const credential = userRec?.credential ?? orgRec?.credential;\n if (credential?.type === 'oauth') return 'oauth';\n if (credential?.type === 'api_key' && credential.key.trim().length > 0) return 'apikey';\n return false;\n }\n\n const oauthCredential = authStorage?.get(authProviderId);\n if (oauthCredential?.type === 'oauth') return 'oauth';\n if (authStorage?.hasStoredApiKey(provider)) return 'apikey';\n const directCredential = authStorage?.get(provider);\n if (directCredential?.type === 'api_key' && directCredential.key.trim().length > 0) return 'apikey';\n return hasModelKey(provider) ? 'apikey' : false;\n };\n const access: ProviderAccess = {\n anthropic: accessLevel('anthropic'),\n openai: accessLevel('openai'),\n cerebras: accessLevel('cerebras'),\n google: accessLevel('google'),\n deepseek: accessLevel('deepseek'),\n 'github-copilot': accessLevel('github-copilot'),\n };\n const seen = new Set(Object.keys(access));\n for (const m of models) {\n if (!seen.has(m.provider)) {\n access[m.provider] = accessLevel(m.provider);\n seen.add(m.provider);\n }\n }\n return access;\n}\n\nfunction canUseModelProvider(access: ProviderAccess, provider: string): boolean {\n return Boolean(access[provider]);\n}\n\n/**\n * Where a request's custom model packs live. Same posture as memory settings\n * and custom providers: the `model-packs` factory storage domain, scoped per\n * org in deployed mode and to a sentinel `local` org in no-auth mode — never\n * settings.json.\n */\nexport interface PackContext {\n storage: ModelPacksStorage;\n orgId: string;\n userId: string;\n}\n\n/** Resolve the pack context for a request, or a ready-to-return error response. */\nasync function resolvePackContext({\n c,\n auth,\n modelPacks,\n}: {\n c: Context;\n auth: RouteAuth;\n modelPacks?: ModelPacksStorage;\n}): Promise<PackContext | { response: Response }> {\n await auth.ensureUser(c);\n const tenant = auth.tenant(c);\n if (!tenant && auth.enabled()) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (modelPacks) {\n try {\n await modelPacks.ensureReady();\n return tenant\n ? { storage: modelPacks, orgId: tenantOrgId(tenant), userId: tenant.userId }\n : { storage: modelPacks, orgId: 'local', userId: 'local' };\n } catch {\n // fall through to the unavailable response\n }\n }\n return {\n response: c.json(\n {\n error: 'model_packs_unavailable',\n message: 'Model pack storage is unavailable — the app database is not configured or failed to start.',\n },\n 503,\n ),\n };\n}\n\nasync function authorizePackSession({\n c,\n auth,\n sessions,\n packContext,\n resourceId,\n scope,\n}: {\n c: Context;\n auth: RouteAuth;\n sessions?: Pick<SourceControlStorageHandle['sessions'], 'getBySessionId'>;\n packContext: PackContext;\n resourceId: string;\n scope: string | undefined;\n}): Promise<Response | null> {\n if (!auth.enabled()) return null;\n if (!sessions) return c.json({ error: 'session_authorization_unavailable' }, 503);\n\n const sourceSession = await sessions.getBySessionId(resourceId);\n if (\n !sourceSession ||\n sourceSession.orgId !== packContext.orgId ||\n sourceSession.userId !== packContext.userId ||\n (scope !== undefined && sourceSession.sandboxWorkdir !== scope)\n ) {\n return c.json({ error: `No session for resourceId \"${resourceId}\"` }, 404);\n }\n return null;\n}\n\n/** DB row → the `ModePack` shape the packs list and activation flow consume. */\nfunction recordToModePack(record: ModelPackRecord): ModePack {\n return { id: `custom:${record.id}`, name: record.name, description: 'Saved custom pack', models: record.models };\n}\n\n/**\n * List available model packs (built-in, gated by provider access, plus saved\n * custom packs from the request's pack context). Drops the synthetic\n * \"New Custom\" placeholder because the web client has its own create flow.\n * `active` marks the user's default pack for new interactive chats.\n */\nexport async function listModelPacks({\n controller,\n authStorage,\n tenantCredentials,\n packContext,\n activePackId,\n}: {\n controller: ModelCatalog;\n authStorage?: AuthStorage;\n tenantCredentials?: CredentialRecord[];\n packContext: PackContext;\n activePackId?: string | null;\n}): Promise<ModelPackInfo[]> {\n const access = await buildProviderAccess({ controller, authStorage, tenantCredentials });\n const packs = [\n ...getAvailableModePacks(access),\n ...(await packContext.storage.list({ orgId: packContext.orgId })).map(recordToModePack),\n ];\n return packs\n .filter(p => p.id !== 'custom') // synthetic \"choose each model\" placeholder\n .map(p => ({\n ...p,\n custom: p.id.startsWith('custom:'),\n active: activePackId != null && p.id === activePackId,\n }));\n}\n\nasync function resolveSessionModelPackId(session: PackSession | undefined): Promise<string | null> {\n if (!session?.thread.getId()) return null;\n const value = await session.thread.getSetting({ key: 'activeModelPackId' });\n return typeof value === 'string' ? value : null;\n}\n\n// ── Observational memory ────────────────────────────────────────────────────\n// Mirrors the TUI `/om` command. Settings are persisted per organization and\n// user in the Factory app database. Requests with an active session also apply\n// changes immediately to that session's state and thread settings.\n\n/** Read the current OM config from a session. */\nexport interface OMConfigInfo {\n observerModelId: string;\n reflectorModelId: string;\n observationThreshold: number;\n reflectionThreshold: number;\n observeAttachments: 'auto' | boolean;\n}\n\nexport interface ProviderOMDefaultsResponse {\n ok: true;\n config: OMConfigInfo;\n}\n\n/** `GET /web/config/thinking` — deployment-scoped reasoning-effort defaults. */\nexport interface ThinkingConfigInfo {\n /** All selectable levels, in escalation order. */\n levels: readonly ThinkingLevelSetting[];\n /** `preferences.thinkingLevel` — fallback when a mode has no default. */\n globalDefault: ThinkingLevelSetting;\n /** `models.modeThinkingDefaults` — per-mode overrides of the global default. */\n modeDefaults: Record<string, ThinkingLevelSetting>;\n /** Mode ids known to the controller (for rendering per-mode rows). */\n modes: string[];\n}\n\n/** `PUT /web/config/thinking` success payload. */\nexport interface UpdateThinkingConfigResponse {\n ok: true;\n globalDefault: ThinkingLevelSetting;\n modeDefaults: Record<string, ThinkingLevelSetting>;\n}\n\nexport function readOMConfig(session: OMSession): OMConfigInfo {\n const state = session.state.get() ?? {};\n const observeAttachments = state.observeAttachments;\n return {\n observerModelId: session.om.observer.modelId() ?? '',\n reflectorModelId: session.om.reflector.modelId() ?? '',\n observationThreshold: session.om.observer.threshold() ?? DEFAULT_OBSERVATION_THRESHOLD,\n reflectionThreshold: session.om.reflector.threshold() ?? DEFAULT_REFLECTION_THRESHOLD,\n observeAttachments: observeAttachments === true || observeAttachments === false ? observeAttachments : 'auto',\n };\n}\n\nfunction readStoredOMConfig(record: MemorySettingsRecord | null): OMConfigInfo {\n return {\n observerModelId: record?.observerModelId ?? DEFAULT_OM_MODEL_ID,\n reflectorModelId: record?.reflectorModelId ?? DEFAULT_OM_MODEL_ID,\n observationThreshold: record?.observationThreshold ?? DEFAULT_OBSERVATION_THRESHOLD,\n reflectionThreshold: record?.reflectionThreshold ?? DEFAULT_REFLECTION_THRESHOLD,\n observeAttachments: record?.observeAttachments ?? 'auto',\n };\n}\n\n/**\n * Where a request's OM settings live: the `memory-settings` factory storage\n * domain, one row per (org, user). Without a tenant (auth disabled), settings\n * land on a sentinel `(local, local)` row in the same table — the web surface\n * never reads or writes `settings.json` for memory settings.\n */\ninterface MemorySettingsContext {\n storage: MemorySettingsStorage;\n orgId: string;\n userId: string;\n}\n\n/** Resolve the memory-settings context for a request, or a ready-to-return error response. */\nasync function resolveMemorySettingsContext({\n c,\n auth,\n memorySettings,\n}: {\n c: Context;\n auth: RouteAuth;\n memorySettings?: MemorySettingsStorage;\n}): Promise<MemorySettingsContext | { response: Response }> {\n await auth.ensureUser(c);\n const tenant = auth.tenant(c);\n if (!tenant && auth.enabled()) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (memorySettings) {\n try {\n await memorySettings.ensureReady();\n return tenant\n ? { storage: memorySettings, orgId: tenantOrgId(tenant), userId: tenant.userId }\n : { storage: memorySettings, orgId: 'local', userId: 'local' };\n } catch {\n // fall through to the unavailable response\n }\n }\n return {\n response: c.json(\n {\n error: 'memory_settings_unavailable',\n message: 'Memory settings storage is unavailable — the app database is not configured or failed to start.',\n },\n 503,\n ),\n };\n}\n\n/** Persist an OM knob change to the caller's memory-settings row. */\nasync function persistMemorySettings(\n context: MemorySettingsContext,\n patch: MemorySettingsPatch,\n fillIfUnset?: MemorySettingsFillIfUnset,\n): Promise<void> {\n await context.storage.patch({ orgId: context.orgId, userId: context.userId, patch, fillIfUnset });\n}\n\n/** Dependencies injected into {@link ConfigRoutes}. */\nexport interface ConfigRoutesDeps extends RouteDependencies {\n controller: ModelCatalog;\n features?: { knowledge: boolean };\n authStorage?: AuthStorage;\n /** Tenant credential domain handle; absent in local (no-DB) mode. */\n modelCredentials?: ModelCredentialsStorage;\n /** Tenant model-packs domain handle; absent in local (no-DB) mode. */\n modelPacks?: ModelPacksStorage;\n /** Source-control sessions used to authorize session-scoped model-pack access. */\n sourceControlSessions?: Pick<SourceControlStorageHandle['sessions'], 'getBySessionId'>;\n /** Tenant memory-settings domain handle; absent in local (no-DB) mode. */\n memorySettings?: MemorySettingsStorage;\n /** Custom-providers domain handle; absent when the app database is missing. */\n customProviders?: CustomProvidersStorage;\n /** Notifies the host after tenant credentials change so caches can be dropped. */\n onCredentialsChanged?: (tenant: { orgId: string; userId?: string }) => void;\n /** Notifies the host after custom providers change so model-router caches can be dropped. */\n onCustomProvidersChanged?: (tenant: { orgId: string }) => void;\n /**\n * Path of the server's settings.json backing the deployment-scoped thinking\n * defaults. Defaults to the standard app-data location; injectable for tests.\n */\n settingsPath?: string;\n}\n\n/**\n * The web config routes as Mastra `apiRoutes`:\n * - `GET /web/config/features` — list server-enabled product features\n * - `GET /web/config/providers` — list providers + key source\n * - `PUT /web/config/providers/:provider/key` — set/update a provider's API key\n * - `DELETE /web/config/providers/:provider/key` — remove a stored API key\n * - `GET /web/config/models` — list available models (credentialed providers)\n * - `GET /web/config/custom-providers` — list custom OpenAI-compatible providers\n * - `POST /web/config/custom-providers` — create/update a custom provider\n * - `DELETE /web/config/custom-providers/:id` — remove a custom provider\n * - `GET /web/config/thinking` — read thinking (reasoning-effort) defaults\n * - `PUT /web/config/thinking` — set global/per-mode thinking defaults\n * - `GET /web/config/om` — read OM models/thresholds/observe-attachments\n * - `PUT /web/config/om/:role/model` — switch observer/reflector model\n * - `PUT /web/config/om/thresholds` — set observation/reflection thresholds\n * - `PUT /web/config/om/observe-attachments` — set observe-attachments (auto/on/off)\n */\nexport class ConfigRoutes extends Route<ConfigRoutesDeps> {\n routes(): ApiRoute[] {\n const options = this.deps;\n const { controller, authStorage, auth } = options;\n const onCredentialsChanged = options.onCredentialsChanged ?? (() => {});\n const onCustomProvidersChanged = options.onCustomProvidersChanged ?? (() => {});\n\n return [\n registerApiRoute('/web/config/features', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => c.json({ knowledge: options.features?.knowledge ?? false }),\n }),\n\n registerApiRoute('/web/config/providers', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n try {\n // Tenant mode lists the caller's rows and never exposes the\n // server-global auth.json; local mode is unchanged.\n const tenantCredentials = await listTenantCredentialsForRequest({\n c: loose(c),\n auth,\n credentials: options.modelCredentials,\n });\n // Tenant mode also reports whether the caller may write org-wide\n // keys, so the settings UI can gate the \"Everyone in org\" option.\n const tenant = auth.tenant(loose(c));\n const orgKeyAdmin = tenant ? await auth.isOrganizationAdmin(loose(c), tenantOrgId(tenant)) : undefined;\n return c.json({\n providers: await listProviders({\n controller,\n authStorage: tenantCredentials ? undefined : authStorage,\n tenantCredentials,\n }),\n ...(orgKeyAdmin !== undefined ? { orgKeyAdmin } : {}),\n });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/providers/:provider/key', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: options.modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n let body: { key?: unknown; envVar?: unknown; scope?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const key = typeof body.key === 'string' ? body.key.trim() : '';\n if (!key) return c.json({ error: 'Missing required field: key' }, 400);\n const envVar = typeof body.envVar === 'string' ? body.envVar : undefined;\n const scope = body.scope === 'org' ? 'org' : 'user';\n try {\n if (ctx.mode === 'tenant') {\n if (scope === 'org' && !(await auth.isOrganizationAdmin(loose(c), ctx.orgId))) {\n return c.json({ error: 'organization_admin_required' }, 403);\n }\n const tenant = scope === 'org' ? { orgId: ctx.orgId } : { orgId: ctx.orgId, userId: ctx.userId };\n // envVar is intentionally ignored: tenant credentials are resolved\n // per-request, never written into process.env.\n await ctx.storage.setCredential(tenant, getAuthProviderId(provider), { type: 'api_key', key });\n onCredentialsChanged(tenant);\n const records = await ctx.storage.listCredentials(ctx.orgId, ctx.userId);\n const providers = await listProviders({ controller, tenantCredentials: records });\n return c.json({ ok: true, provider: providers.find(p => p.provider === provider) });\n }\n if (!authStorage) return c.json({ error: 'Credential storage is not available' }, 503);\n // Local mode is single-user: scope is meaningless and ignored.\n authStorage.setStoredApiKey(provider, key, envVar);\n const providers = await listProviders({ controller, authStorage });\n return c.json({ ok: true, provider: providers.find(p => p.provider === provider) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/providers/:provider/key', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: options.modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n const scope = c.req.query('scope') === 'org' ? 'org' : 'user';\n try {\n if (ctx.mode === 'tenant') {\n if (scope === 'org' && !(await auth.isOrganizationAdmin(loose(c), ctx.orgId))) {\n return c.json({ error: 'organization_admin_required' }, 403);\n }\n const tenant = scope === 'org' ? { orgId: ctx.orgId } : { orgId: ctx.orgId, userId: ctx.userId };\n await ctx.storage.removeCredential(tenant, getAuthProviderId(provider));\n onCredentialsChanged(tenant);\n const records = await ctx.storage.listCredentials(ctx.orgId, ctx.userId);\n const providers = await listProviders({ controller, tenantCredentials: records });\n return c.json({ ok: true, provider: providers.find(p => p.provider === provider) });\n }\n if (!authStorage) return c.json({ error: 'Credential storage is not available' }, 503);\n authStorage.remove(`apikey:${provider}`);\n const providers = await listProviders({ controller, authStorage });\n return c.json({ ok: true, provider: providers.find(p => p.provider === provider) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n // ── Custom providers (OpenAI-compatible endpoints) ──────────────────────\n // Mirrors the TUI's /custom-providers command, but backed by the\n // `custom-providers` domain (org rows in tenant mode, a sentinel `local`\n // org in no-auth mode) — the server never reads settings.json for these.\n\n registerApiRoute('/web/config/custom-providers', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCustomProvidersContext({\n c: loose(c),\n auth,\n customProviders: options.customProviders,\n });\n if ('response' in ctx) return ctx.response;\n try {\n const records = await ctx.storage.list({ orgId: ctx.orgId });\n return c.json({ providers: records.map(toCustomProviderInfo) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/custom-providers', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCustomProvidersContext({\n c: loose(c),\n auth,\n customProviders: options.customProviders,\n });\n if ('response' in ctx) return ctx.response;\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const parsed = parseCustomProviderBody(body);\n if ('error' in parsed) return c.json({ error: parsed.error }, 400);\n // `previousId` lets a rename remove the old entry as well as any name clash.\n const previousId =\n body && typeof body === 'object' && typeof (body as Record<string, unknown>).previousId === 'string'\n ? ((body as Record<string, unknown>).previousId as string)\n : undefined;\n try {\n const record = await ctx.storage.upsert({\n orgId: ctx.orgId,\n userId: ctx.userId,\n input: {\n providerId: getCustomProviderId(parsed.name),\n name: parsed.name,\n url: parsed.url,\n apiKey: parsed.apiKey,\n models: parsed.models,\n },\n previousProviderId: previousId,\n });\n onCustomProvidersChanged({ orgId: ctx.orgId });\n return c.json({ ok: true, provider: toCustomProviderInfo(record) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/custom-providers/:id', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCustomProvidersContext({\n c: loose(c),\n auth,\n customProviders: options.customProviders,\n });\n if ('response' in ctx) return ctx.response;\n const id = c.req.param('id');\n try {\n await ctx.storage.delete({ orgId: ctx.orgId, providerId: id });\n onCustomProvidersChanged({ orgId: ctx.orgId });\n return c.json({ ok: true });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n // ── Available models ────────────────────────────────────────────────────\n // Session-independent model catalog for settings pickers (Factory default\n // model, pack editors). Only models whose provider has a credential are\n // returned — the same filter the session-scoped hook applies client-side.\n\n registerApiRoute('/web/config/models', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n try {\n const tenantCredentials = await listTenantCredentialsForRequest({\n c: loose(c),\n auth,\n credentials: options.modelCredentials,\n });\n const [models, access] = await Promise.all([\n controller.listAvailableModels(),\n buildProviderAccess({\n controller,\n authStorage: tenantCredentials ? undefined : authStorage,\n tenantCredentials,\n }),\n ]);\n const catalog = models\n .filter(m => canUseModelProvider(access, m.provider) && typeof m.id === 'string')\n .map(m => ({ id: m.id!, provider: m.provider, modelName: m.modelName, hasApiKey: true }));\n // Append the caller's custom provider models (DB-backed, org rows in\n // tenant mode / sentinel `local` org in no-auth mode). The boot-time\n // gateway catalog only carries the local list, so tenant callers get\n // theirs here. Dedupe against ids already present.\n if (options.customProviders) {\n try {\n const ctx = await resolveCustomProvidersContext({\n c: loose(c),\n auth,\n customProviders: options.customProviders,\n });\n if (!('response' in ctx)) {\n const known = new Set(catalog.map(m => m.id));\n for (const record of await ctx.storage.list({ orgId: ctx.orgId })) {\n for (const model of record.models) {\n const id = `${record.providerId}/${model}`;\n if (known.has(id)) continue;\n known.add(id);\n catalog.push({ id, provider: record.providerId, modelName: model, hasApiKey: true });\n }\n }\n }\n } catch {\n // Fail soft: the catalog still serves the built-in models.\n }\n }\n return c.json({\n models: catalog.sort((a, b) =>\n a.provider === b.provider ? a.id.localeCompare(b.id) : a.provider.localeCompare(b.provider),\n ),\n });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n // ── Model packs ─────────────────────────────────────────────────────────\n // Custom pack definitions are organization-scoped. Each user can choose a\n // default for new interactive chats, while a thread-specific activation\n // takes precedence. Factory work sessions use the project default model.\n\n registerApiRoute('/web/config/model-packs', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const packContext = await resolvePackContext({ c: loose(c), auth, modelPacks: options.modelPacks });\n if ('response' in packContext) return packContext.response;\n const resourceId = c.req.query('resourceId');\n const scope = c.req.query('scope') || undefined;\n try {\n const activePack = await packContext.storage.getActive({\n orgId: packContext.orgId,\n userId: packContext.userId,\n });\n const activePackId = activePack?.packId ?? null;\n if (resourceId) {\n const unauthorized = await authorizePackSession({\n c: loose(c),\n auth,\n sessions: options.sourceControlSessions,\n packContext,\n resourceId,\n scope,\n });\n if (unauthorized) return unauthorized;\n }\n const session = resourceId ? await controller.getSessionByResource?.(resourceId, scope) : undefined;\n const sessionPackId = await resolveSessionModelPackId(session);\n const tenantCredentials = await listTenantCredentialsForRequest({\n c: loose(c),\n auth,\n credentials: options.modelCredentials,\n });\n return c.json({\n packs: await listModelPacks({\n controller,\n authStorage: tenantCredentials ? undefined : authStorage,\n tenantCredentials,\n packContext,\n activePackId,\n }),\n activePackId,\n sessionPackId,\n });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/model-packs', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const packContext = await resolvePackContext({ c: loose(c), auth, modelPacks: options.modelPacks });\n if ('response' in packContext) return packContext.response;\n let body: { name?: unknown; models?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const name = typeof body.name === 'string' ? body.name.trim() : '';\n if (!name) return c.json({ error: 'Missing required field: name' }, 400);\n const m = (body.models ?? {}) as Record<string, unknown>;\n const build = typeof m.build === 'string' ? m.build.trim() : '';\n const plan = typeof m.plan === 'string' ? m.plan.trim() : '';\n const fast = typeof m.fast === 'string' ? m.fast.trim() : '';\n if (!build || !plan || !fast) {\n return c.json({ error: 'models.build, models.plan and models.fast are required' }, 400);\n }\n try {\n const record = await packContext.storage.upsert({\n orgId: packContext.orgId,\n userId: packContext.userId,\n input: { name, models: { build, plan, fast } },\n });\n return c.json({ ok: true, pack: recordToModePack(record) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/model-packs/active', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const packContext = await resolvePackContext({ c: loose(c), auth, modelPacks: options.modelPacks });\n if ('response' in packContext) return packContext.response;\n try {\n await packContext.storage.clearActive({ orgId: packContext.orgId, userId: packContext.userId });\n return c.json({ ok: true, activePackId: null });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/model-packs/:id', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const packContext = await resolvePackContext({ c: loose(c), auth, modelPacks: options.modelPacks });\n if ('response' in packContext) return packContext.response;\n const id = decodeURIComponent(c.req.param('id'));\n try {\n const recordId = id.startsWith('custom:') ? id.slice('custom:'.length) : id;\n const deleted = await packContext.storage.delete({ orgId: packContext.orgId, id: recordId });\n return deleted ? c.json({ ok: true }) : c.json({ error: `Unknown pack \"${id}\"` }, 404);\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/model-packs/:id/activate', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const packContext = await resolvePackContext({ c: loose(c), auth, modelPacks: options.modelPacks });\n if ('response' in packContext) return packContext.response;\n const id = decodeURIComponent(c.req.param('id'));\n let body: { resourceId?: unknown; scope?: unknown; target?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const target = body.target ?? 'default';\n if (target !== 'default' && target !== 'session') {\n return c.json({ error: 'target must be \"default\" or \"session\"' }, 400);\n }\n const resourceId = typeof body.resourceId === 'string' && body.resourceId ? body.resourceId : undefined;\n const scope = typeof body.scope === 'string' && body.scope ? body.scope : undefined;\n if (target === 'session' && !resourceId) {\n return c.json({ error: 'Missing required field for session activation: resourceId' }, 400);\n }\n try {\n if (target === 'session' && resourceId) {\n const unauthorized = await authorizePackSession({\n c: loose(c),\n auth,\n sessions: options.sourceControlSessions,\n packContext,\n resourceId,\n scope,\n });\n if (unauthorized) return unauthorized;\n }\n const session =\n target === 'session' && resourceId\n ? await controller.getSessionByResource?.(resourceId, scope)\n : undefined;\n if (target === 'session' && !session) {\n return c.json({ error: `No session for resourceId \"${resourceId}\"` }, 404);\n }\n const tenantCredentials = await listTenantCredentialsForRequest({\n c: loose(c),\n auth,\n credentials: options.modelCredentials,\n });\n const packs = await listModelPacks({\n controller,\n authStorage: tenantCredentials ? undefined : authStorage,\n tenantCredentials,\n packContext,\n });\n const pack = packs.find(p => p.id === id);\n if (!pack) return c.json({ error: `Unknown pack \"${id}\"` }, 404);\n if (target === 'default') {\n await packContext.storage.setActive({\n orgId: packContext.orgId,\n userId: packContext.userId,\n packId: pack.id,\n models: pack.models,\n });\n return c.json({ ok: true, target, activePackId: pack.id });\n }\n if (session) {\n await applyActiveModelPack(session, { packId: pack.id, models: pack.models });\n }\n return c.json({ ok: true, target, sessionPackId: pack.id });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n // ── Thinking (reasoning-effort) defaults ─────────────────────────────────\n // Deployment-scoped defaults stored in the server's settings.json: the\n // global `preferences.thinkingLevel` plus per-mode\n // `models.modeThinkingDefaults`. These are what request-time resolution\n // falls back to when a session carries no explicit override — including\n // automated (rule-driven) Factory runs nobody opens interactively. In\n // tenant mode, writes are disabled because the settings file is shared\n // deployment-wide rather than scoped to an organization.\n\n registerApiRoute('/web/config/thinking', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n try {\n const settings = loadSettings(options.settingsPath);\n const modes = controller.listModes?.().map(mode => mode.id) ?? [];\n return c.json({\n levels: THINKING_LEVEL_VALUES,\n globalDefault: settings.preferences.thinkingLevel,\n modeDefaults: settings.models.modeThinkingDefaults,\n modes,\n });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/thinking', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n if (auth.enabled()) {\n return c.json({ error: 'Deployment thinking defaults can only be changed in local mode' }, 403);\n }\n let body: { globalDefault?: unknown; modeDefaults?: unknown };\n try {\n const parsed: unknown = await c.req.json();\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return c.json({ error: 'Request body must be a JSON object' }, 400);\n }\n body = parsed as { globalDefault?: unknown; modeDefaults?: unknown };\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (body.globalDefault === undefined && body.modeDefaults === undefined) {\n return c.json({ error: 'Provide globalDefault and/or modeDefaults' }, 400);\n }\n if (body.globalDefault !== undefined && !isThinkingLevelSetting(body.globalDefault)) {\n return c.json(\n { error: `Invalid globalDefault — expected one of: ${THINKING_LEVEL_VALUES.join(', ')}` },\n 400,\n );\n }\n // Per-mode patch semantics: a valid level sets the mode's default,\n // `null` clears it (back to the global default).\n const modePatch: Record<string, ThinkingLevelSetting | null> = {};\n if (body.modeDefaults !== undefined) {\n if (!body.modeDefaults || typeof body.modeDefaults !== 'object' || Array.isArray(body.modeDefaults)) {\n return c.json({ error: 'modeDefaults must be an object of mode → level (or null to clear)' }, 400);\n }\n const knownModes = new Set(controller.listModes?.().map(mode => mode.id) ?? []);\n for (const [mode, level] of Object.entries(body.modeDefaults as Record<string, unknown>)) {\n if (!knownModes.has(mode)) {\n return c.json({ error: `Unknown mode \"${mode}\"` }, 400);\n }\n if (level === null) {\n modePatch[mode] = null;\n } else if (isThinkingLevelSetting(level)) {\n modePatch[mode] = level;\n } else {\n return c.json(\n { error: `Invalid level for mode \"${mode}\" — expected one of: ${THINKING_LEVEL_VALUES.join(', ')}` },\n 400,\n );\n }\n }\n }\n try {\n const settings = loadSettings(options.settingsPath);\n if (body.globalDefault !== undefined && isThinkingLevelSetting(body.globalDefault)) {\n settings.preferences.thinkingLevel = body.globalDefault;\n }\n for (const [mode, level] of Object.entries(modePatch)) {\n if (level === null) delete settings.models.modeThinkingDefaults[mode];\n else settings.models.modeThinkingDefaults[mode] = level;\n }\n saveSettings(settings, options.settingsPath);\n return c.json({\n ok: true,\n globalDefault: settings.preferences.thinkingLevel,\n modeDefaults: settings.models.modeThinkingDefaults,\n });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/om/provider-defaults', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n let body: { providerId?: unknown; factoryModelId?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const providerId = typeof body.providerId === 'string' ? body.providerId.trim() : '';\n const factoryModelId = typeof body.factoryModelId === 'string' ? body.factoryModelId.trim() : '';\n if (!providerId) return c.json({ error: 'Missing required field: providerId' }, 400);\n\n const context = await resolveMemorySettingsContext({\n c: loose(c),\n auth,\n memorySettings: options.memorySettings,\n });\n if ('response' in context) return context.response;\n\n try {\n const tenantCredentials = await listTenantCredentialsForRequest({\n c: loose(c),\n auth,\n credentials: options.modelCredentials,\n });\n const access = await buildProviderAccess({\n controller,\n authStorage: tenantCredentials ? undefined : authStorage,\n tenantCredentials,\n });\n if (!access[providerId]) return c.json({ error: `Provider \"${providerId}\" is not configured` }, 400);\n\n const modelId = resolveProviderOMDefault(providerId, factoryModelId).modelId;\n const record = await context.storage.patch({\n orgId: context.orgId,\n userId: context.userId,\n patch: {},\n fillIfUnset: { observerModelId: modelId, reflectorModelId: modelId },\n });\n return c.json({ ok: true, config: readStoredOMConfig(record) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n // ── Observational memory ──────────────────────────────────────────────────\n // Mirrors the TUI's /om command. All five knobs are durably stored in the\n // per-(org, user) `memory-settings` app table — never settings.json. When a\n // session is supplied, changes are also applied to its state and thread.\n\n registerApiRoute('/web/config/om', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resourceId = c.req.query('resourceId');\n const scope = c.req.query('scope') || undefined;\n const context = await resolveMemorySettingsContext({\n c: loose(c),\n auth,\n memorySettings: options.memorySettings,\n });\n if ('response' in context) return context.response;\n try {\n const record = await context.storage.get({ orgId: context.orgId, userId: context.userId });\n if (!resourceId) return c.json({ config: readStoredOMConfig(record) });\n\n // Session sync is best-effort: the stored row is authoritative and\n // new sessions hydrate from it, so a resourceId without a live\n // session (e.g. settings page after a restart) still reads the\n // stored config instead of failing.\n const session = await controller.getSessionByResource?.(resourceId, scope);\n if (!session) return c.json({ config: readStoredOMConfig(record) });\n await applyStoredMemorySettings(session, record);\n return c.json({ config: readOMConfig(session) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/om/:role/model', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n const role = c.req.param('role');\n if (role !== 'observer' && role !== 'reflector') {\n return c.json({ error: `Unknown OM role \"${role}\"` }, 400);\n }\n let body: { resourceId?: unknown; modelId?: unknown; scope?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const resourceId = typeof body.resourceId === 'string' ? body.resourceId : '';\n const scope = typeof body.scope === 'string' && body.scope ? body.scope : undefined;\n const modelId = typeof body.modelId === 'string' ? body.modelId.trim() : '';\n if (!modelId) return c.json({ error: 'Missing required field: modelId' }, 400);\n const context = await resolveMemorySettingsContext({\n c: loose(c),\n auth,\n memorySettings: options.memorySettings,\n });\n if ('response' in context) return context.response;\n try {\n // Best-effort session sync: persist regardless, apply to the live\n // session only when one exists for the resourceId.\n const session = resourceId ? await controller.getSessionByResource?.(resourceId, scope) : undefined;\n const otherRole = session ? (role === 'observer' ? session.om.reflector : session.om.observer) : undefined;\n const otherRoleCurrentModelId = otherRole?.modelId() ?? null;\n await session?.om[role].switchModel({ modelId });\n // Pin the other role's current model too, so a later restart\n // doesn't drift it once this role is explicitly overridden. The\n // \"only if still unset\" check runs inside the storage layer's\n // atomic update, so a concurrent explicit switch of the other\n // role is never clobbered by this fill.\n const otherKey = role === 'observer' ? 'reflectorModelId' : 'observerModelId';\n await persistMemorySettings(\n context,\n { [role === 'observer' ? 'observerModelId' : 'reflectorModelId']: modelId },\n otherRoleCurrentModelId ? { [otherKey]: otherRoleCurrentModelId } : undefined,\n );\n const config = session\n ? readOMConfig(session)\n : readStoredOMConfig(await context.storage.get({ orgId: context.orgId, userId: context.userId }));\n return c.json({ ok: true, config });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/om/thresholds', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n let body: {\n resourceId?: unknown;\n observationThreshold?: unknown;\n reflectionThreshold?: unknown;\n scope?: unknown;\n };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const resourceId = typeof body.resourceId === 'string' ? body.resourceId : '';\n const scope = typeof body.scope === 'string' && body.scope ? body.scope : undefined;\n const observation =\n typeof body.observationThreshold === 'number' && body.observationThreshold > 0\n ? Math.round(body.observationThreshold)\n : undefined;\n const reflection =\n typeof body.reflectionThreshold === 'number' && body.reflectionThreshold > 0\n ? Math.round(body.reflectionThreshold)\n : undefined;\n if (observation === undefined && reflection === undefined) {\n return c.json({ error: 'Provide observationThreshold and/or reflectionThreshold (positive numbers)' }, 400);\n }\n const context = await resolveMemorySettingsContext({\n c: loose(c),\n auth,\n memorySettings: options.memorySettings,\n });\n if ('response' in context) return context.response;\n try {\n // Best-effort session sync: persist regardless, apply to the live\n // session only when one exists for the resourceId.\n const session = resourceId ? await controller.getSessionByResource?.(resourceId, scope) : undefined;\n if (observation !== undefined && session) {\n await session.state.set({ observationThreshold: observation });\n await session.thread.setSetting({ key: 'observationThreshold', value: observation });\n }\n if (reflection !== undefined && session) {\n await session.state.set({ reflectionThreshold: reflection });\n await session.thread.setSetting({ key: 'reflectionThreshold', value: reflection });\n }\n await persistMemorySettings(context, {\n ...(observation !== undefined ? { observationThreshold: observation } : {}),\n ...(reflection !== undefined ? { reflectionThreshold: reflection } : {}),\n });\n const config = session\n ? readOMConfig(session)\n : readStoredOMConfig(await context.storage.get({ orgId: context.orgId, userId: context.userId }));\n return c.json({ ok: true, config });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/om/observe-attachments', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n let body: { resourceId?: unknown; value?: unknown; scope?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const resourceId = typeof body.resourceId === 'string' ? body.resourceId : '';\n const scope = typeof body.scope === 'string' && body.scope ? body.scope : undefined;\n const raw = body.value;\n const value: 'auto' | boolean = raw === 'auto' || raw === true || raw === false ? raw : 'auto';\n if (raw !== 'auto' && raw !== true && raw !== false) {\n return c.json({ error: \"value must be 'auto', true, or false\" }, 400);\n }\n const context = await resolveMemorySettingsContext({\n c: loose(c),\n auth,\n memorySettings: options.memorySettings,\n });\n if ('response' in context) return context.response;\n try {\n // Best-effort session sync: persist regardless, apply to the live\n // session only when one exists for the resourceId.\n const session = resourceId ? await controller.getSessionByResource?.(resourceId, scope) : undefined;\n if (session) {\n await session.state.set({ observeAttachments: value });\n await session.thread.setSetting({ key: 'observeAttachments', value });\n }\n await persistMemorySettings(context, { observeAttachments: value });\n const config = session\n ? readOMConfig(session)\n : readStoredOMConfig(await context.storage.get({ orgId: context.orgId, userId: context.userId }));\n return c.json({ ok: true, config });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n ];\n }\n}\n"],"mappings":";;;;;;;;;;AA+CA,SAAS,MAAM,GAAqB;CAClC,OAAO;AACT;;;;;;;;;;AAuGA,eAAsB,cAAc,EAClC,YACA,aACA,qBAK0B;CAC1B,MAAM,SAAS,MAAM,WAAW,oBAAoB;CACpD,MAAM,uBAAO,IAAI,IAA0B;CAE3C,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,KAAK,IAAI,MAAM,QAAQ,GAAG;EAE9B,MAAM,iBAAiB,kBAAkB,MAAM,QAAQ;EACvD,IAAI,SAAiC;EACrC,IAAI;EACJ,IAAI,mBAAmB;GACrB,MAAM,UAAU,kBAAkB,MAAK,MAAK,EAAE,UAAU,UAAU,EAAE,aAAa,cAAc;GAC/F,MAAM,SAAS,kBAAkB,MAAK,MAAK,EAAE,UAAU,SAAS,EAAE,aAAa,cAAc;GAC7F,SAAS,QAAQ,WAAW,SAAS;GACrC,IAAI,SAAS,WAAW,SAAS,SAC/B,SAAS;QACJ,IAAI,SAAS,WAAW,SAAS,WACtC,SAAS;QACJ,IAAI,QAAQ,WAAW,SAAS,WACrC,SAAS;EAEb,OAAO,IAAI,aAAa,WAAW,cAAc,GAC/C,SAAS;OACJ,IAAI,aAAa,gBAAgB,MAAM,QAAQ,GACpD,SAAS;OACJ,IAAI,MAAM,gBAAgB,QAAQ,IAAI,MAAM,eACjD,SAAS;OACJ,IAAI,MAAM,WACf,SAAS;EAGX,MAAM,WAAW,qBAAqB,MAAM;EAC5C,KAAK,IAAI,MAAM,UAAU;GACvB,UAAU,MAAM;GAChB,QAAQ,MAAM;GACd;GACA,GAAI,WAAW,KAAA,IAAY,EAAE,OAAO,IAAI,CAAC;GACzC,GAAI,WAAW,EAAE,OAAO;IAAE,WAAW;IAAe,OAAO,CAAC,QAAQ;GAAE,EAAE,IAAI,CAAC;EAC/E,CAAC;CACH;CAEA,OAAO,MAAM,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,SAAS,cAAc,EAAE,QAAQ,CAAC;AACtF;;AAYA,SAAS,qBAAqB,QAAkD;CAC9E,OAAO;EACL,IAAI,OAAO;EACX,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,WAAW,QAAQ,OAAO,MAAM;EAChC,QAAQ,OAAO;CACjB;AACF;;;;;;AAcA,eAAe,8BAA8B,EAC3C,GACA,MACA,mBAK2D;CAC3D,MAAM,KAAK,WAAW,CAAC;CACvB,MAAM,SAAS,KAAK,OAAO,CAAC;CAC5B,IAAI,CAAC,UAAU,KAAK,QAAQ,GAAG,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,eAAe,GAAG,GAAG,EAAE;CACzF,IAAI,iBACF,IAAI;EACF,MAAM,gBAAgB,YAAY;EAClC,OAAO,SACH;GAAE,SAAS;GAAiB,OAAO,YAAY,MAAM;GAAG,QAAQ,OAAO;EAAO,IAC9E;GAAE,SAAS;GAAiB,OAAO;GAAS,QAAQ;EAAQ;CAClE,QAAQ,CAER;CAEF,OAAO,EACL,UAAU,EAAE,KACV;EACE,OAAO;EACP,SAAS;CACX,GACA,GACF,EACF;AACF;;AAGA,SAAS,wBAAwB,MAA0D;CACzF,IAAI,CAAC,QAAQ,OAAO,SAAS,UAAU,OAAO,EAAE,OAAO,oBAAoB;CAC3E,MAAM,IAAI;CACV,MAAM,OAAO,OAAO,EAAE,SAAS,WAAW,EAAE,KAAK,KAAK,IAAI;CAC1D,IAAI,CAAC,MAAM,OAAO,EAAE,OAAO,+BAA+B;CAC1D,MAAM,MAAM,OAAO,EAAE,QAAQ,WAAW,EAAE,IAAI,KAAK,IAAI;CACvD,IAAI,CAAC,KAAK,OAAO,EAAE,OAAO,8BAA8B;CACxD,IAAI;EACF,MAAM,SAAS,IAAI,IAAI,GAAG;EAC1B,IAAI,OAAO,aAAa,WAAW,OAAO,aAAa,UACrD,OAAO,EAAE,OAAO,6BAA6B;CAEjD,QAAQ;EACN,OAAO,EAAE,OAAO,0BAA0B;CAC5C;CAKA,OAAO;EAAE;EAAM;EAAK,QAJL,OAAO,EAAE,WAAW,YAAY,EAAE,OAAO,KAAK,IAAI,EAAE,OAAO,KAAK,IAAI,KAAA;EAIvD,QAHb,MAAM,QAAQ,EAAE,MAAM,IACjC,EAAE,OAAO,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,IACnG,CAAC;CAC8B;AACrC;;;;;;AAeA,eAAsB,oBAAoB,EACxC,YACA,aACA,qBAK0B;CAC1B,MAAM,SAAS,MAAM,WAAW,oBAAoB;CACpD,MAAM,eAAe,aAAqB,OAAO,MAAK,MAAK,EAAE,aAAa,YAAY,EAAE,SAAS;CACjG,MAAM,eAAe,aAA0C;EAC7D,MAAM,iBAAiB,kBAAkB,QAAQ;EACjD,IAAI,mBAAmB;GACrB,MAAM,UAAU,kBAAkB,MAAK,MAAK,EAAE,UAAU,UAAU,EAAE,aAAa,cAAc;GAC/F,MAAM,SAAS,kBAAkB,MAAK,MAAK,EAAE,UAAU,SAAS,EAAE,aAAa,cAAc;GAC7F,MAAM,aAAa,SAAS,cAAc,QAAQ;GAClD,IAAI,YAAY,SAAS,SAAS,OAAO;GACzC,IAAI,YAAY,SAAS,aAAa,WAAW,IAAI,KAAK,CAAC,CAAC,SAAS,GAAG,OAAO;GAC/E,OAAO;EACT;EAGA,KADwB,aAAa,IAAI,cAAc,EAAA,EAClC,SAAS,SAAS,OAAO;EAC9C,IAAI,aAAa,gBAAgB,QAAQ,GAAG,OAAO;EACnD,MAAM,mBAAmB,aAAa,IAAI,QAAQ;EAClD,IAAI,kBAAkB,SAAS,aAAa,iBAAiB,IAAI,KAAK,CAAC,CAAC,SAAS,GAAG,OAAO;EAC3F,OAAO,YAAY,QAAQ,IAAI,WAAW;CAC5C;CACA,MAAM,SAAyB;EAC7B,WAAW,YAAY,WAAW;EAClC,QAAQ,YAAY,QAAQ;EAC5B,UAAU,YAAY,UAAU;EAChC,QAAQ,YAAY,QAAQ;EAC5B,UAAU,YAAY,UAAU;EAChC,kBAAkB,YAAY,gBAAgB;CAChD;CACA,MAAM,OAAO,IAAI,IAAI,OAAO,KAAK,MAAM,CAAC;CACxC,KAAK,MAAM,KAAK,QACd,IAAI,CAAC,KAAK,IAAI,EAAE,QAAQ,GAAG;EACzB,OAAO,EAAE,YAAY,YAAY,EAAE,QAAQ;EAC3C,KAAK,IAAI,EAAE,QAAQ;CACrB;CAEF,OAAO;AACT;AAEA,SAAS,oBAAoB,QAAwB,UAA2B;CAC9E,OAAO,QAAQ,OAAO,SAAS;AACjC;;AAeA,eAAe,mBAAmB,EAChC,GACA,MACA,cAKgD;CAChD,MAAM,KAAK,WAAW,CAAC;CACvB,MAAM,SAAS,KAAK,OAAO,CAAC;CAC5B,IAAI,CAAC,UAAU,KAAK,QAAQ,GAAG,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,eAAe,GAAG,GAAG,EAAE;CACzF,IAAI,YACF,IAAI;EACF,MAAM,WAAW,YAAY;EAC7B,OAAO,SACH;GAAE,SAAS;GAAY,OAAO,YAAY,MAAM;GAAG,QAAQ,OAAO;EAAO,IACzE;GAAE,SAAS;GAAY,OAAO;GAAS,QAAQ;EAAQ;CAC7D,QAAQ,CAER;CAEF,OAAO,EACL,UAAU,EAAE,KACV;EACE,OAAO;EACP,SAAS;CACX,GACA,GACF,EACF;AACF;AAEA,eAAe,qBAAqB,EAClC,GACA,MACA,UACA,aACA,YACA,SAQ2B;CAC3B,IAAI,CAAC,KAAK,QAAQ,GAAG,OAAO;CAC5B,IAAI,CAAC,UAAU,OAAO,EAAE,KAAK,EAAE,OAAO,oCAAoC,GAAG,GAAG;CAEhF,MAAM,gBAAgB,MAAM,SAAS,eAAe,UAAU;CAC9D,IACE,CAAC,iBACD,cAAc,UAAU,YAAY,SACpC,cAAc,WAAW,YAAY,UACpC,UAAU,KAAA,KAAa,cAAc,mBAAmB,OAEzD,OAAO,EAAE,KAAK,EAAE,OAAO,8BAA8B,WAAW,GAAG,GAAG,GAAG;CAE3E,OAAO;AACT;;AAGA,SAAS,iBAAiB,QAAmC;CAC3D,OAAO;EAAE,IAAI,UAAU,OAAO;EAAM,MAAM,OAAO;EAAM,aAAa;EAAqB,QAAQ,OAAO;CAAO;AACjH;;;;;;;AAQA,eAAsB,eAAe,EACnC,YACA,aACA,mBACA,aACA,gBAO2B;CAM3B,OAAO,CAHL,GAAG,sBAAsB,MAFN,oBAAoB;EAAE;EAAY;EAAa;CAAkB,CAAC,CAEtD,GAC/B,IAAI,MAAM,YAAY,QAAQ,KAAK,EAAE,OAAO,YAAY,MAAM,CAAC,EAAA,CAAG,IAAI,gBAAgB,CAE7E,CAAC,CACT,QAAO,MAAK,EAAE,OAAO,QAAQ,CAAC,CAC9B,KAAI,OAAM;EACT,GAAG;EACH,QAAQ,EAAE,GAAG,WAAW,SAAS;EACjC,QAAQ,gBAAgB,QAAQ,EAAE,OAAO;CAC3C,EAAE;AACN;AAEA,eAAe,0BAA0B,SAA0D;CACjG,IAAI,CAAC,SAAS,OAAO,MAAM,GAAG,OAAO;CACrC,MAAM,QAAQ,MAAM,QAAQ,OAAO,WAAW,EAAE,KAAK,oBAAoB,CAAC;CAC1E,OAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;AAwCA,SAAgB,aAAa,SAAkC;CAE7D,MAAM,sBADQ,QAAQ,MAAM,IAAI,KAAK,CAAC,EAAA,CACL;CACjC,OAAO;EACL,iBAAiB,QAAQ,GAAG,SAAS,QAAQ,KAAK;EAClD,kBAAkB,QAAQ,GAAG,UAAU,QAAQ,KAAK;EACpD,sBAAsB,QAAQ,GAAG,SAAS,UAAU,KAAA;EACpD,qBAAqB,QAAQ,GAAG,UAAU,UAAU,KAAA;EACpD,oBAAoB,uBAAuB,QAAQ,uBAAuB,QAAQ,qBAAqB;CACzG;AACF;AAEA,SAAS,mBAAmB,QAAmD;CAC7E,OAAO;EACL,iBAAiB,QAAQ,mBAAmB;EAC5C,kBAAkB,QAAQ,oBAAoB;EAC9C,sBAAsB,QAAQ,wBAAA;EAC9B,qBAAqB,QAAQ,uBAAA;EAC7B,oBAAoB,QAAQ,sBAAsB;CACpD;AACF;;AAeA,eAAe,6BAA6B,EAC1C,GACA,MACA,kBAK0D;CAC1D,MAAM,KAAK,WAAW,CAAC;CACvB,MAAM,SAAS,KAAK,OAAO,CAAC;CAC5B,IAAI,CAAC,UAAU,KAAK,QAAQ,GAAG,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,eAAe,GAAG,GAAG,EAAE;CACzF,IAAI,gBACF,IAAI;EACF,MAAM,eAAe,YAAY;EACjC,OAAO,SACH;GAAE,SAAS;GAAgB,OAAO,YAAY,MAAM;GAAG,QAAQ,OAAO;EAAO,IAC7E;GAAE,SAAS;GAAgB,OAAO;GAAS,QAAQ;EAAQ;CACjE,QAAQ,CAER;CAEF,OAAO,EACL,UAAU,EAAE,KACV;EACE,OAAO;EACP,SAAS;CACX,GACA,GACF,EACF;AACF;;AAGA,eAAe,sBACb,SACA,OACA,aACe;CACf,MAAM,QAAQ,QAAQ,MAAM;EAAE,OAAO,QAAQ;EAAO,QAAQ,QAAQ;EAAQ;EAAO;CAAY,CAAC;AAClG;;;;;;;;;;;;;;;;;;AA6CA,IAAa,eAAb,cAAkC,MAAwB;CACxD,SAAqB;EACnB,MAAM,UAAU,KAAK;EACrB,MAAM,EAAE,YAAY,aAAa,SAAS;EAC1C,MAAM,uBAAuB,QAAQ,+BAA+B,CAAC;EACrE,MAAM,2BAA2B,QAAQ,mCAAmC,CAAC;EAE7E,OAAO;GACL,iBAAiB,wBAAwB;IACvC,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK,EAAE,KAAK,EAAE,WAAW,QAAQ,UAAU,aAAa,MAAM,CAAC;GAChF,CAAC;GAED,iBAAiB,yBAAyB;IACxC,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,IAAI;MAGF,MAAM,oBAAoB,MAAM,gCAAgC;OAC9D,GAAG,MAAM,CAAC;OACV;OACA,aAAa,QAAQ;MACvB,CAAC;MAGD,MAAM,SAAS,KAAK,OAAO,MAAM,CAAC,CAAC;MACnC,MAAM,cAAc,SAAS,MAAM,KAAK,oBAAoB,MAAM,CAAC,GAAG,YAAY,MAAM,CAAC,IAAI,KAAA;MAC7F,OAAO,EAAE,KAAK;OACZ,WAAW,MAAM,cAAc;QAC7B;QACA,aAAa,oBAAoB,KAAA,IAAY;QAC7C;OACF,CAAC;OACD,GAAI,gBAAgB,KAAA,IAAY,EAAE,YAAY,IAAI,CAAC;MACrD,CAAC;KACH,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,uCAAuC;IACtD,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,MAAM,MAAM,yBAAyB;MAAE,GAAG,MAAM,CAAC;MAAG;MAAM,aAAa,QAAQ;KAAiB,CAAC;KACvG,IAAI,cAAc,KAAK,OAAO,IAAI;KAElC,MAAM,WAAW,EAAE,IAAI,MAAM,UAAU;KACvC,IAAI;KACJ,IAAI;MACF,OAAO,MAAM,EAAE,IAAI,KAAK;KAC1B,QAAQ;MACN,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KACnD;KACA,MAAM,MAAM,OAAO,KAAK,QAAQ,WAAW,KAAK,IAAI,KAAK,IAAI;KAC7D,IAAI,CAAC,KAAK,OAAO,EAAE,KAAK,EAAE,OAAO,8BAA8B,GAAG,GAAG;KACrE,MAAM,SAAS,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS,KAAA;KAC/D,MAAM,QAAQ,KAAK,UAAU,QAAQ,QAAQ;KAC7C,IAAI;MACF,IAAI,IAAI,SAAS,UAAU;OACzB,IAAI,UAAU,SAAS,CAAE,MAAM,KAAK,oBAAoB,MAAM,CAAC,GAAG,IAAI,KAAK,GACzE,OAAO,EAAE,KAAK,EAAE,OAAO,8BAA8B,GAAG,GAAG;OAE7D,MAAM,SAAS,UAAU,QAAQ,EAAE,OAAO,IAAI,MAAM,IAAI;QAAE,OAAO,IAAI;QAAO,QAAQ,IAAI;OAAO;OAG/F,MAAM,IAAI,QAAQ,cAAc,QAAQ,kBAAkB,QAAQ,GAAG;QAAE,MAAM;QAAW;OAAI,CAAC;OAC7F,qBAAqB,MAAM;OAC3B,MAAM,UAAU,MAAM,IAAI,QAAQ,gBAAgB,IAAI,OAAO,IAAI,MAAM;OACvE,MAAM,YAAY,MAAM,cAAc;QAAE;QAAY,mBAAmB;OAAQ,CAAC;OAChF,OAAO,EAAE,KAAK;QAAE,IAAI;QAAM,UAAU,UAAU,MAAK,MAAK,EAAE,aAAa,QAAQ;OAAE,CAAC;MACpF;MACA,IAAI,CAAC,aAAa,OAAO,EAAE,KAAK,EAAE,OAAO,sCAAsC,GAAG,GAAG;MAErF,YAAY,gBAAgB,UAAU,KAAK,MAAM;MACjD,MAAM,YAAY,MAAM,cAAc;OAAE;OAAY;MAAY,CAAC;MACjE,OAAO,EAAE,KAAK;OAAE,IAAI;OAAM,UAAU,UAAU,MAAK,MAAK,EAAE,aAAa,QAAQ;MAAE,CAAC;KACpF,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,uCAAuC;IACtD,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,MAAM,MAAM,yBAAyB;MAAE,GAAG,MAAM,CAAC;MAAG;MAAM,aAAa,QAAQ;KAAiB,CAAC;KACvG,IAAI,cAAc,KAAK,OAAO,IAAI;KAElC,MAAM,WAAW,EAAE,IAAI,MAAM,UAAU;KACvC,MAAM,QAAQ,EAAE,IAAI,MAAM,OAAO,MAAM,QAAQ,QAAQ;KACvD,IAAI;MACF,IAAI,IAAI,SAAS,UAAU;OACzB,IAAI,UAAU,SAAS,CAAE,MAAM,KAAK,oBAAoB,MAAM,CAAC,GAAG,IAAI,KAAK,GACzE,OAAO,EAAE,KAAK,EAAE,OAAO,8BAA8B,GAAG,GAAG;OAE7D,MAAM,SAAS,UAAU,QAAQ,EAAE,OAAO,IAAI,MAAM,IAAI;QAAE,OAAO,IAAI;QAAO,QAAQ,IAAI;OAAO;OAC/F,MAAM,IAAI,QAAQ,iBAAiB,QAAQ,kBAAkB,QAAQ,CAAC;OACtE,qBAAqB,MAAM;OAC3B,MAAM,UAAU,MAAM,IAAI,QAAQ,gBAAgB,IAAI,OAAO,IAAI,MAAM;OACvE,MAAM,YAAY,MAAM,cAAc;QAAE;QAAY,mBAAmB;OAAQ,CAAC;OAChF,OAAO,EAAE,KAAK;QAAE,IAAI;QAAM,UAAU,UAAU,MAAK,MAAK,EAAE,aAAa,QAAQ;OAAE,CAAC;MACpF;MACA,IAAI,CAAC,aAAa,OAAO,EAAE,KAAK,EAAE,OAAO,sCAAsC,GAAG,GAAG;MACrF,YAAY,OAAO,UAAU,UAAU;MACvC,MAAM,YAAY,MAAM,cAAc;OAAE;OAAY;MAAY,CAAC;MACjE,OAAO,EAAE,KAAK;OAAE,IAAI;OAAM,UAAU,UAAU,MAAK,MAAK,EAAE,aAAa,QAAQ;MAAE,CAAC;KACpF,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAOD,iBAAiB,gCAAgC;IAC/C,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,MAAM,MAAM,8BAA8B;MAC9C,GAAG,MAAM,CAAC;MACV;MACA,iBAAiB,QAAQ;KAC3B,CAAC;KACD,IAAI,cAAc,KAAK,OAAO,IAAI;KAClC,IAAI;MACF,MAAM,UAAU,MAAM,IAAI,QAAQ,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC;MAC3D,OAAO,EAAE,KAAK,EAAE,WAAW,QAAQ,IAAI,oBAAoB,EAAE,CAAC;KAChE,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,gCAAgC;IAC/C,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,MAAM,MAAM,8BAA8B;MAC9C,GAAG,MAAM,CAAC;MACV;MACA,iBAAiB,QAAQ;KAC3B,CAAC;KACD,IAAI,cAAc,KAAK,OAAO,IAAI;KAClC,IAAI;KACJ,IAAI;MACF,OAAO,MAAM,EAAE,IAAI,KAAK;KAC1B,QAAQ;MACN,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KACnD;KACA,MAAM,SAAS,wBAAwB,IAAI;KAC3C,IAAI,WAAW,QAAQ,OAAO,EAAE,KAAK,EAAE,OAAO,OAAO,MAAM,GAAG,GAAG;KAEjE,MAAM,aACJ,QAAQ,OAAO,SAAS,YAAY,OAAQ,KAAiC,eAAe,WACtF,KAAiC,aACnC,KAAA;KACN,IAAI;MACF,MAAM,SAAS,MAAM,IAAI,QAAQ,OAAO;OACtC,OAAO,IAAI;OACX,QAAQ,IAAI;OACZ,OAAO;QACL,YAAY,oBAAoB,OAAO,IAAI;QAC3C,MAAM,OAAO;QACb,KAAK,OAAO;QACZ,QAAQ,OAAO;QACf,QAAQ,OAAO;OACjB;OACA,oBAAoB;MACtB,CAAC;MACD,yBAAyB,EAAE,OAAO,IAAI,MAAM,CAAC;MAC7C,OAAO,EAAE,KAAK;OAAE,IAAI;OAAM,UAAU,qBAAqB,MAAM;MAAE,CAAC;KACpE,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,oCAAoC;IACnD,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,MAAM,MAAM,8BAA8B;MAC9C,GAAG,MAAM,CAAC;MACV;MACA,iBAAiB,QAAQ;KAC3B,CAAC;KACD,IAAI,cAAc,KAAK,OAAO,IAAI;KAClC,MAAM,KAAK,EAAE,IAAI,MAAM,IAAI;KAC3B,IAAI;MACF,MAAM,IAAI,QAAQ,OAAO;OAAE,OAAO,IAAI;OAAO,YAAY;MAAG,CAAC;MAC7D,yBAAyB,EAAE,OAAO,IAAI,MAAM,CAAC;MAC7C,OAAO,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC;KAC5B,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAOD,iBAAiB,sBAAsB;IACrC,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,IAAI;MACF,MAAM,oBAAoB,MAAM,gCAAgC;OAC9D,GAAG,MAAM,CAAC;OACV;OACA,aAAa,QAAQ;MACvB,CAAC;MACD,MAAM,CAAC,QAAQ,UAAU,MAAM,QAAQ,IAAI,CACzC,WAAW,oBAAoB,GAC/B,oBAAoB;OAClB;OACA,aAAa,oBAAoB,KAAA,IAAY;OAC7C;MACF,CAAC,CACH,CAAC;MACD,MAAM,UAAU,OACb,QAAO,MAAK,oBAAoB,QAAQ,EAAE,QAAQ,KAAK,OAAO,EAAE,OAAO,QAAQ,CAAC,CAChF,KAAI,OAAM;OAAE,IAAI,EAAE;OAAK,UAAU,EAAE;OAAU,WAAW,EAAE;OAAW,WAAW;MAAK,EAAE;MAK1F,IAAI,QAAQ,iBACV,IAAI;OACF,MAAM,MAAM,MAAM,8BAA8B;QAC9C,GAAG,MAAM,CAAC;QACV;QACA,iBAAiB,QAAQ;OAC3B,CAAC;OACD,IAAI,EAAE,cAAc,MAAM;QACxB,MAAM,QAAQ,IAAI,IAAI,QAAQ,KAAI,MAAK,EAAE,EAAE,CAAC;QAC5C,KAAK,MAAM,UAAU,MAAM,IAAI,QAAQ,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,GAC9D,KAAK,MAAM,SAAS,OAAO,QAAQ;SACjC,MAAM,KAAK,GAAG,OAAO,WAAW,GAAG;SACnC,IAAI,MAAM,IAAI,EAAE,GAAG;SACnB,MAAM,IAAI,EAAE;SACZ,QAAQ,KAAK;UAAE;UAAI,UAAU,OAAO;UAAY,WAAW;UAAO,WAAW;SAAK,CAAC;QACrF;OAEJ;MACF,QAAQ,CAER;MAEF,OAAO,EAAE,KAAK,EACZ,QAAQ,QAAQ,MAAM,GAAG,MACvB,EAAE,aAAa,EAAE,WAAW,EAAE,GAAG,cAAc,EAAE,EAAE,IAAI,EAAE,SAAS,cAAc,EAAE,QAAQ,CAC5F,EACF,CAAC;KACH,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAOD,iBAAiB,2BAA2B;IAC1C,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,cAAc,MAAM,mBAAmB;MAAE,GAAG,MAAM,CAAC;MAAG;MAAM,YAAY,QAAQ;KAAW,CAAC;KAClG,IAAI,cAAc,aAAa,OAAO,YAAY;KAClD,MAAM,aAAa,EAAE,IAAI,MAAM,YAAY;KAC3C,MAAM,QAAQ,EAAE,IAAI,MAAM,OAAO,KAAK,KAAA;KACtC,IAAI;MAKF,MAAM,gBAAe,MAJI,YAAY,QAAQ,UAAU;OACrD,OAAO,YAAY;OACnB,QAAQ,YAAY;MACtB,CAAC,EAAA,EACgC,UAAU;MAC3C,IAAI,YAAY;OACd,MAAM,eAAe,MAAM,qBAAqB;QAC9C,GAAG,MAAM,CAAC;QACV;QACA,UAAU,QAAQ;QAClB;QACA;QACA;OACF,CAAC;OACD,IAAI,cAAc,OAAO;MAC3B;MAEA,MAAM,gBAAgB,MAAM,0BADZ,aAAa,MAAM,WAAW,uBAAuB,YAAY,KAAK,IAAI,KAAA,CAC7B;MAC7D,MAAM,oBAAoB,MAAM,gCAAgC;OAC9D,GAAG,MAAM,CAAC;OACV;OACA,aAAa,QAAQ;MACvB,CAAC;MACD,OAAO,EAAE,KAAK;OACZ,OAAO,MAAM,eAAe;QAC1B;QACA,aAAa,oBAAoB,KAAA,IAAY;QAC7C;QACA;QACA;OACF,CAAC;OACD;OACA;MACF,CAAC;KACH,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,2BAA2B;IAC1C,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,cAAc,MAAM,mBAAmB;MAAE,GAAG,MAAM,CAAC;MAAG;MAAM,YAAY,QAAQ;KAAW,CAAC;KAClG,IAAI,cAAc,aAAa,OAAO,YAAY;KAClD,IAAI;KACJ,IAAI;MACF,OAAO,MAAM,EAAE,IAAI,KAAK;KAC1B,QAAQ;MACN,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KACnD;KACA,MAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,KAAK,KAAK,IAAI;KAChE,IAAI,CAAC,MAAM,OAAO,EAAE,KAAK,EAAE,OAAO,+BAA+B,GAAG,GAAG;KACvE,MAAM,IAAK,KAAK,UAAU,CAAC;KAC3B,MAAM,QAAQ,OAAO,EAAE,UAAU,WAAW,EAAE,MAAM,KAAK,IAAI;KAC7D,MAAM,OAAO,OAAO,EAAE,SAAS,WAAW,EAAE,KAAK,KAAK,IAAI;KAC1D,MAAM,OAAO,OAAO,EAAE,SAAS,WAAW,EAAE,KAAK,KAAK,IAAI;KAC1D,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MACtB,OAAO,EAAE,KAAK,EAAE,OAAO,yDAAyD,GAAG,GAAG;KAExF,IAAI;MACF,MAAM,SAAS,MAAM,YAAY,QAAQ,OAAO;OAC9C,OAAO,YAAY;OACnB,QAAQ,YAAY;OACpB,OAAO;QAAE;QAAM,QAAQ;SAAE;SAAO;SAAM;QAAK;OAAE;MAC/C,CAAC;MACD,OAAO,EAAE,KAAK;OAAE,IAAI;OAAM,MAAM,iBAAiB,MAAM;MAAE,CAAC;KAC5D,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,kCAAkC;IACjD,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,cAAc,MAAM,mBAAmB;MAAE,GAAG,MAAM,CAAC;MAAG;MAAM,YAAY,QAAQ;KAAW,CAAC;KAClG,IAAI,cAAc,aAAa,OAAO,YAAY;KAClD,IAAI;MACF,MAAM,YAAY,QAAQ,YAAY;OAAE,OAAO,YAAY;OAAO,QAAQ,YAAY;MAAO,CAAC;MAC9F,OAAO,EAAE,KAAK;OAAE,IAAI;OAAM,cAAc;MAAK,CAAC;KAChD,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,+BAA+B;IAC9C,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,cAAc,MAAM,mBAAmB;MAAE,GAAG,MAAM,CAAC;MAAG;MAAM,YAAY,QAAQ;KAAW,CAAC;KAClG,IAAI,cAAc,aAAa,OAAO,YAAY;KAClD,MAAM,KAAK,mBAAmB,EAAE,IAAI,MAAM,IAAI,CAAC;KAC/C,IAAI;MACF,MAAM,WAAW,GAAG,WAAW,SAAS,IAAI,GAAG,MAAM,CAAgB,IAAI;MAEzE,OAAO,MADe,YAAY,QAAQ,OAAO;OAAE,OAAO,YAAY;OAAO,IAAI;MAAS,CAAC,IAC1E,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,iBAAiB,GAAG,GAAG,GAAG,GAAG;KACvF,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,wCAAwC;IACvD,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,cAAc,MAAM,mBAAmB;MAAE,GAAG,MAAM,CAAC;MAAG;MAAM,YAAY,QAAQ;KAAW,CAAC;KAClG,IAAI,cAAc,aAAa,OAAO,YAAY;KAClD,MAAM,KAAK,mBAAmB,EAAE,IAAI,MAAM,IAAI,CAAC;KAC/C,IAAI;KACJ,IAAI;MACF,OAAO,MAAM,EAAE,IAAI,KAAK;KAC1B,QAAQ;MACN,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KACnD;KACA,MAAM,SAAS,KAAK,UAAU;KAC9B,IAAI,WAAW,aAAa,WAAW,WACrC,OAAO,EAAE,KAAK,EAAE,OAAO,4CAAwC,GAAG,GAAG;KAEvE,MAAM,aAAa,OAAO,KAAK,eAAe,YAAY,KAAK,aAAa,KAAK,aAAa,KAAA;KAC9F,MAAM,QAAQ,OAAO,KAAK,UAAU,YAAY,KAAK,QAAQ,KAAK,QAAQ,KAAA;KAC1E,IAAI,WAAW,aAAa,CAAC,YAC3B,OAAO,EAAE,KAAK,EAAE,OAAO,4DAA4D,GAAG,GAAG;KAE3F,IAAI;MACF,IAAI,WAAW,aAAa,YAAY;OACtC,MAAM,eAAe,MAAM,qBAAqB;QAC9C,GAAG,MAAM,CAAC;QACV;QACA,UAAU,QAAQ;QAClB;QACA;QACA;OACF,CAAC;OACD,IAAI,cAAc,OAAO;MAC3B;MACA,MAAM,UACJ,WAAW,aAAa,aACpB,MAAM,WAAW,uBAAuB,YAAY,KAAK,IACzD,KAAA;MACN,IAAI,WAAW,aAAa,CAAC,SAC3B,OAAO,EAAE,KAAK,EAAE,OAAO,8BAA8B,WAAW,GAAG,GAAG,GAAG;MAE3E,MAAM,oBAAoB,MAAM,gCAAgC;OAC9D,GAAG,MAAM,CAAC;OACV;OACA,aAAa,QAAQ;MACvB,CAAC;MAOD,MAAM,QAAO,MANO,eAAe;OACjC;OACA,aAAa,oBAAoB,KAAA,IAAY;OAC7C;OACA;MACF,CAAC,EAAA,CACkB,MAAK,MAAK,EAAE,OAAO,EAAE;MACxC,IAAI,CAAC,MAAM,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,GAAG,GAAG,GAAG,GAAG;MAC/D,IAAI,WAAW,WAAW;OACxB,MAAM,YAAY,QAAQ,UAAU;QAClC,OAAO,YAAY;QACnB,QAAQ,YAAY;QACpB,QAAQ,KAAK;QACb,QAAQ,KAAK;OACf,CAAC;OACD,OAAO,EAAE,KAAK;QAAE,IAAI;QAAM;QAAQ,cAAc,KAAK;OAAG,CAAC;MAC3D;MACA,IAAI,SACF,MAAM,qBAAqB,SAAS;OAAE,QAAQ,KAAK;OAAI,QAAQ,KAAK;MAAO,CAAC;MAE9E,OAAO,EAAE,KAAK;OAAE,IAAI;OAAM;OAAQ,eAAe,KAAK;MAAG,CAAC;KAC5D,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAWD,iBAAiB,wBAAwB;IACvC,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,IAAI;MACF,MAAM,WAAW,aAAa,QAAQ,YAAY;MAClD,MAAM,QAAQ,WAAW,YAAY,CAAC,CAAC,KAAI,SAAQ,KAAK,EAAE,KAAK,CAAC;MAChE,OAAO,EAAE,KAAK;OACZ,QAAQ;OACR,eAAe,SAAS,YAAY;OACpC,cAAc,SAAS,OAAO;OAC9B;MACF,CAAC;KACH,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,wBAAwB;IACvC,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,IAAI,KAAK,QAAQ,GACf,OAAO,EAAE,KAAK,EAAE,OAAO,iEAAiE,GAAG,GAAG;KAEhG,IAAI;KACJ,IAAI;MACF,MAAM,SAAkB,MAAM,EAAE,IAAI,KAAK;MACzC,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAC/D,OAAO,EAAE,KAAK,EAAE,OAAO,qCAAqC,GAAG,GAAG;MAEpE,OAAO;KACT,QAAQ;MACN,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KACnD;KACA,IAAI,KAAK,kBAAkB,KAAA,KAAa,KAAK,iBAAiB,KAAA,GAC5D,OAAO,EAAE,KAAK,EAAE,OAAO,4CAA4C,GAAG,GAAG;KAE3E,IAAI,KAAK,kBAAkB,KAAA,KAAa,CAAC,uBAAuB,KAAK,aAAa,GAChF,OAAO,EAAE,KACP,EAAE,OAAO,4CAA4C,sBAAsB,KAAK,IAAI,IAAI,GACxF,GACF;KAIF,MAAM,YAAyD,CAAC;KAChE,IAAI,KAAK,iBAAiB,KAAA,GAAW;MACnC,IAAI,CAAC,KAAK,gBAAgB,OAAO,KAAK,iBAAiB,YAAY,MAAM,QAAQ,KAAK,YAAY,GAChG,OAAO,EAAE,KAAK,EAAE,OAAO,oEAAoE,GAAG,GAAG;MAEnG,MAAM,aAAa,IAAI,IAAI,WAAW,YAAY,CAAC,CAAC,KAAI,SAAQ,KAAK,EAAE,KAAK,CAAC,CAAC;MAC9E,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,KAAK,YAAuC,GAAG;OACxF,IAAI,CAAC,WAAW,IAAI,IAAI,GACtB,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,KAAK,GAAG,GAAG,GAAG;OAExD,IAAI,UAAU,MACZ,UAAU,QAAQ;YACb,IAAI,uBAAuB,KAAK,GACrC,UAAU,QAAQ;YAElB,OAAO,EAAE,KACP,EAAE,OAAO,2BAA2B,KAAK,uBAAuB,sBAAsB,KAAK,IAAI,IAAI,GACnG,GACF;MAEJ;KACF;KACA,IAAI;MACF,MAAM,WAAW,aAAa,QAAQ,YAAY;MAClD,IAAI,KAAK,kBAAkB,KAAA,KAAa,uBAAuB,KAAK,aAAa,GAC/E,SAAS,YAAY,gBAAgB,KAAK;MAE5C,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,SAAS,GAClD,IAAI,UAAU,MAAM,OAAO,SAAS,OAAO,qBAAqB;WAC3D,SAAS,OAAO,qBAAqB,QAAQ;MAEpD,aAAa,UAAU,QAAQ,YAAY;MAC3C,OAAO,EAAE,KAAK;OACZ,IAAI;OACJ,eAAe,SAAS,YAAY;OACpC,cAAc,SAAS,OAAO;MAChC,CAAC;KACH,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,oCAAoC;IACnD,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,IAAI;KACJ,IAAI;MACF,OAAO,MAAM,EAAE,IAAI,KAAK;KAC1B,QAAQ;MACN,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KACnD;KACA,MAAM,aAAa,OAAO,KAAK,eAAe,WAAW,KAAK,WAAW,KAAK,IAAI;KAClF,MAAM,iBAAiB,OAAO,KAAK,mBAAmB,WAAW,KAAK,eAAe,KAAK,IAAI;KAC9F,IAAI,CAAC,YAAY,OAAO,EAAE,KAAK,EAAE,OAAO,qCAAqC,GAAG,GAAG;KAEnF,MAAM,UAAU,MAAM,6BAA6B;MACjD,GAAG,MAAM,CAAC;MACV;MACA,gBAAgB,QAAQ;KAC1B,CAAC;KACD,IAAI,cAAc,SAAS,OAAO,QAAQ;KAE1C,IAAI;MACF,MAAM,oBAAoB,MAAM,gCAAgC;OAC9D,GAAG,MAAM,CAAC;OACV;OACA,aAAa,QAAQ;MACvB,CAAC;MAMD,IAAI,EAAC,MALgB,oBAAoB;OACvC;OACA,aAAa,oBAAoB,KAAA,IAAY;OAC7C;MACF,CAAC,EAAA,CACW,aAAa,OAAO,EAAE,KAAK,EAAE,OAAO,aAAa,WAAW,qBAAqB,GAAG,GAAG;MAEnG,MAAM,UAAU,yBAAyB,YAAY,cAAc,CAAC,CAAC;MACrE,MAAM,SAAS,MAAM,QAAQ,QAAQ,MAAM;OACzC,OAAO,QAAQ;OACf,QAAQ,QAAQ;OAChB,OAAO,CAAC;OACR,aAAa;QAAE,iBAAiB;QAAS,kBAAkB;OAAQ;MACrE,CAAC;MACD,OAAO,EAAE,KAAK;OAAE,IAAI;OAAM,QAAQ,mBAAmB,MAAM;MAAE,CAAC;KAChE,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAOD,iBAAiB,kBAAkB;IACjC,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,aAAa,EAAE,IAAI,MAAM,YAAY;KAC3C,MAAM,QAAQ,EAAE,IAAI,MAAM,OAAO,KAAK,KAAA;KACtC,MAAM,UAAU,MAAM,6BAA6B;MACjD,GAAG,MAAM,CAAC;MACV;MACA,gBAAgB,QAAQ;KAC1B,CAAC;KACD,IAAI,cAAc,SAAS,OAAO,QAAQ;KAC1C,IAAI;MACF,MAAM,SAAS,MAAM,QAAQ,QAAQ,IAAI;OAAE,OAAO,QAAQ;OAAO,QAAQ,QAAQ;MAAO,CAAC;MACzF,IAAI,CAAC,YAAY,OAAO,EAAE,KAAK,EAAE,QAAQ,mBAAmB,MAAM,EAAE,CAAC;MAMrE,MAAM,UAAU,MAAM,WAAW,uBAAuB,YAAY,KAAK;MACzE,IAAI,CAAC,SAAS,OAAO,EAAE,KAAK,EAAE,QAAQ,mBAAmB,MAAM,EAAE,CAAC;MAClE,MAAM,0BAA0B,SAAS,MAAM;MAC/C,OAAO,EAAE,KAAK,EAAE,QAAQ,aAAa,OAAO,EAAE,CAAC;KACjD,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,8BAA8B;IAC7C,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,MAAM,OAAO,EAAE,IAAI,MAAM,MAAM;KAC/B,IAAI,SAAS,cAAc,SAAS,aAClC,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,KAAK,GAAG,GAAG,GAAG;KAE3D,IAAI;KACJ,IAAI;MACF,OAAO,MAAM,EAAE,IAAI,KAAK;KAC1B,QAAQ;MACN,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KACnD;KACA,MAAM,aAAa,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;KAC3E,MAAM,QAAQ,OAAO,KAAK,UAAU,YAAY,KAAK,QAAQ,KAAK,QAAQ,KAAA;KAC1E,MAAM,UAAU,OAAO,KAAK,YAAY,WAAW,KAAK,QAAQ,KAAK,IAAI;KACzE,IAAI,CAAC,SAAS,OAAO,EAAE,KAAK,EAAE,OAAO,kCAAkC,GAAG,GAAG;KAC7E,MAAM,UAAU,MAAM,6BAA6B;MACjD,GAAG,MAAM,CAAC;MACV;MACA,gBAAgB,QAAQ;KAC1B,CAAC;KACD,IAAI,cAAc,SAAS,OAAO,QAAQ;KAC1C,IAAI;MAGF,MAAM,UAAU,aAAa,MAAM,WAAW,uBAAuB,YAAY,KAAK,IAAI,KAAA;MAE1F,MAAM,2BADY,UAAW,SAAS,aAAa,QAAQ,GAAG,YAAY,QAAQ,GAAG,WAAY,KAAA,EAAA,EACtD,QAAQ,KAAK;MACxD,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,EAAE,QAAQ,CAAC;MAM/C,MAAM,WAAW,SAAS,aAAa,qBAAqB;MAC5D,MAAM,sBACJ,SACA,GAAG,SAAS,aAAa,oBAAoB,qBAAqB,QAAQ,GAC1E,0BAA0B,GAAG,WAAW,wBAAwB,IAAI,KAAA,CACtE;MACA,MAAM,SAAS,UACX,aAAa,OAAO,IACpB,mBAAmB,MAAM,QAAQ,QAAQ,IAAI;OAAE,OAAO,QAAQ;OAAO,QAAQ,QAAQ;MAAO,CAAC,CAAC;MAClG,OAAO,EAAE,KAAK;OAAE,IAAI;OAAM;MAAO,CAAC;KACpC,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,6BAA6B;IAC5C,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,IAAI;KAMJ,IAAI;MACF,OAAO,MAAM,EAAE,IAAI,KAAK;KAC1B,QAAQ;MACN,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KACnD;KACA,MAAM,aAAa,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;KAC3E,MAAM,QAAQ,OAAO,KAAK,UAAU,YAAY,KAAK,QAAQ,KAAK,QAAQ,KAAA;KAC1E,MAAM,cACJ,OAAO,KAAK,yBAAyB,YAAY,KAAK,uBAAuB,IACzE,KAAK,MAAM,KAAK,oBAAoB,IACpC,KAAA;KACN,MAAM,aACJ,OAAO,KAAK,wBAAwB,YAAY,KAAK,sBAAsB,IACvE,KAAK,MAAM,KAAK,mBAAmB,IACnC,KAAA;KACN,IAAI,gBAAgB,KAAA,KAAa,eAAe,KAAA,GAC9C,OAAO,EAAE,KAAK,EAAE,OAAO,6EAA6E,GAAG,GAAG;KAE5G,MAAM,UAAU,MAAM,6BAA6B;MACjD,GAAG,MAAM,CAAC;MACV;MACA,gBAAgB,QAAQ;KAC1B,CAAC;KACD,IAAI,cAAc,SAAS,OAAO,QAAQ;KAC1C,IAAI;MAGF,MAAM,UAAU,aAAa,MAAM,WAAW,uBAAuB,YAAY,KAAK,IAAI,KAAA;MAC1F,IAAI,gBAAgB,KAAA,KAAa,SAAS;OACxC,MAAM,QAAQ,MAAM,IAAI,EAAE,sBAAsB,YAAY,CAAC;OAC7D,MAAM,QAAQ,OAAO,WAAW;QAAE,KAAK;QAAwB,OAAO;OAAY,CAAC;MACrF;MACA,IAAI,eAAe,KAAA,KAAa,SAAS;OACvC,MAAM,QAAQ,MAAM,IAAI,EAAE,qBAAqB,WAAW,CAAC;OAC3D,MAAM,QAAQ,OAAO,WAAW;QAAE,KAAK;QAAuB,OAAO;OAAW,CAAC;MACnF;MACA,MAAM,sBAAsB,SAAS;OACnC,GAAI,gBAAgB,KAAA,IAAY,EAAE,sBAAsB,YAAY,IAAI,CAAC;OACzE,GAAI,eAAe,KAAA,IAAY,EAAE,qBAAqB,WAAW,IAAI,CAAC;MACxE,CAAC;MACD,MAAM,SAAS,UACX,aAAa,OAAO,IACpB,mBAAmB,MAAM,QAAQ,QAAQ,IAAI;OAAE,OAAO,QAAQ;OAAO,QAAQ,QAAQ;MAAO,CAAC,CAAC;MAClG,OAAO,EAAE,KAAK;OAAE,IAAI;OAAM;MAAO,CAAC;KACpC,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;GAED,iBAAiB,sCAAsC;IACrD,QAAQ;IACR,cAAc;IACd,SAAS,OAAM,MAAK;KAClB,IAAI;KACJ,IAAI;MACF,OAAO,MAAM,EAAE,IAAI,KAAK;KAC1B,QAAQ;MACN,OAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;KACnD;KACA,MAAM,aAAa,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;KAC3E,MAAM,QAAQ,OAAO,KAAK,UAAU,YAAY,KAAK,QAAQ,KAAK,QAAQ,KAAA;KAC1E,MAAM,MAAM,KAAK;KACjB,MAAM,QAA0B,QAAQ,UAAU,QAAQ,QAAQ,QAAQ,QAAQ,MAAM;KACxF,IAAI,QAAQ,UAAU,QAAQ,QAAQ,QAAQ,OAC5C,OAAO,EAAE,KAAK,EAAE,OAAO,uCAAuC,GAAG,GAAG;KAEtE,MAAM,UAAU,MAAM,6BAA6B;MACjD,GAAG,MAAM,CAAC;MACV;MACA,gBAAgB,QAAQ;KAC1B,CAAC;KACD,IAAI,cAAc,SAAS,OAAO,QAAQ;KAC1C,IAAI;MAGF,MAAM,UAAU,aAAa,MAAM,WAAW,uBAAuB,YAAY,KAAK,IAAI,KAAA;MAC1F,IAAI,SAAS;OACX,MAAM,QAAQ,MAAM,IAAI,EAAE,oBAAoB,MAAM,CAAC;OACrD,MAAM,QAAQ,OAAO,WAAW;QAAE,KAAK;QAAsB;OAAM,CAAC;MACtE;MACA,MAAM,sBAAsB,SAAS,EAAE,oBAAoB,MAAM,CAAC;MAClE,MAAM,SAAS,UACX,aAAa,OAAO,IACpB,mBAAmB,MAAM,QAAQ,QAAQ,IAAI;OAAE,OAAO,QAAQ;OAAO,QAAQ,QAAQ;MAAO,CAAC,CAAC;MAClG,OAAO,EAAE,KAAK;OAAE,IAAI;OAAM;MAAO,CAAC;KACpC,SAAS,OAAO;MACd,OAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,GAAG,GAAG;KACtF;IACF;GACF,CAAC;EACH;CACF;AACF"}
1
+ {"version":3,"file":"config.js","names":[],"sources":["../../src/routes/config.ts"],"sourcesContent":["import type { AuthStorage } from '@mastra/code-sdk/auth/storage';\nimport { DEFAULT_OM_MODEL_ID } from '@mastra/code-sdk/constants';\nimport { getAvailableModePacks, resolveProviderOMDefault } from '@mastra/code-sdk/onboarding/packs';\nimport type { ModePack, ProviderAccess, ProviderAccessLevel } from '@mastra/code-sdk/onboarding/packs';\nimport {\n getCustomProviderId,\n isThinkingLevelSetting,\n loadSettings,\n saveSettings,\n THINKING_LEVEL_VALUES,\n} from '@mastra/code-sdk/onboarding/settings';\nimport type { CustomProviderSetting, ThinkingLevelSetting } from '@mastra/code-sdk/onboarding/settings';\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\n\nimport type { Context } from 'hono';\nimport {\n applyStoredMemorySettings,\n DEFAULT_OBSERVATION_THRESHOLD,\n DEFAULT_REFLECTION_THRESHOLD,\n} from '../session/memory-settings-hydration.js';\nimport { applyActiveModelPack } from '../session/model-pack-hydration.js';\nimport type {\n CredentialRecord,\n LoginSessionKind,\n ModelCredentialsStorage,\n} from '../storage/domains/credentials/base.js';\nimport type { CustomProviderRecord, CustomProvidersStorage } from '../storage/domains/custom-providers/base.js';\nimport { factoryMemorySettingsUserId } from '../storage/domains/memory-settings/base.js';\nimport type {\n MemorySettingsFillIfUnset,\n MemorySettingsPatch,\n MemorySettingsRecord,\n MemorySettingsStorage,\n} from '../storage/domains/memory-settings/base.js';\nimport type { ModelPackRecord, ModelPacksStorage } from '../storage/domains/model-packs/base.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { SourceControlStorageHandle } from '../storage/domains/source-control/base.js';\nimport {\n getAuthProviderId,\n listTenantCredentialsForRequest,\n resolveCredentialContext,\n tenantOrgId,\n WEB_OAUTH_FLOW_KINDS,\n} from './provider-credentials.js';\nimport { Route } from './route.js';\nimport type { RouteAuth, RouteDependencies } from './route.js';\n\n/** Widen a route-local Hono context to the plain `Context` the auth helpers take. */\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\n/**\n * Server-side configuration routes for the web app.\n *\n * The browser has no access to the credential store or the model catalog, so\n * the web settings panel asks the server — which owns both — to list providers\n * and manage API keys. This mirrors the TUI's `/api-keys` command, exposing the\n * same `AuthStorage`-backed key management over HTTP.\n *\n * Keys are never returned to the client; only their presence and source.\n */\n\n/**\n * Where a provider's active credential comes from, as seen by the caller.\n * Local mode reports `oauth`/`stored` (server-global `auth.json`); tenant mode\n * reports the scoped variants (`oauth-user`/`stored-user`/`stored-org`).\n */\nexport type ProviderCredentialSource =\n | 'oauth'\n | 'stored'\n | 'env'\n | 'none'\n | 'oauth-user'\n | 'oauth-org'\n | 'stored-user'\n | 'stored-org';\n\n/** A model provider with the current source of its credentials. */\nexport interface ProviderInfo {\n provider: string;\n /** Env var the provider's key is read from, if any. */\n envVar?: string;\n /** Where the active credential comes from. */\n source: ProviderCredentialSource;\n /**\n * Tenant mode: whether an org-wide API key exists for this provider, even\n * when the caller's personal credential shadows it. Lets the UI tell\n * \"shared with the org\" apart from \"only works for me\".\n */\n orgKey?: boolean;\n /**\n * Tenant mode: the caller's personal credential for this provider, if any.\n * Reported independently of `source` so the UI can manage each scope even\n * when one shadows the other.\n */\n userCredential?: 'oauth' | 'api_key';\n /** Tenant mode: the shared org credential for this provider, if any. */\n orgCredential?: 'oauth' | 'api_key';\n /** Web OAuth sign-in capability, when the provider supports it. */\n oauth?: { supported: true; modes: LoginSessionKind[] };\n}\n\n/** Minimal session surface a pack activation touches. */\ninterface PackSession {\n mode: { get: () => string };\n model: { switch: (args: { modelId: string }) => Promise<void> };\n subagents: { model: { set: (args: { modelId: string; agentType: string }) => Promise<void> } };\n thread: {\n getId: () => string | null;\n getSetting: (args: { key: string }) => Promise<unknown>;\n setSetting: (args: { key: string; value: unknown }) => Promise<void>;\n };\n}\n\n/** One observational-memory role's read/switch surface. */\ninterface OMRole {\n modelId: () => string | undefined;\n threshold: () => number | undefined;\n switchModel: (args: { modelId: string }) => Promise<void>;\n}\n\n/**\n * Session-state fields the OM config routes write. The index signatures mirror\n * `MastraCodeState` so the concrete `Session.state.set(Partial<MastraCodeState>)`\n * stays assignable to this minimal surface (contravariant parameter check).\n */\ninterface OMStateWrites {\n [key: string]: unknown;\n [key: `subagentModelId_${string}`]: string | undefined;\n observationThreshold?: number;\n reflectionThreshold?: number;\n observeAttachments?: 'auto' | boolean;\n}\n\n/** Minimal session surface the OM config routes touch. */\nexport interface OMSession extends PackSession {\n state: {\n get: () => Record<string, unknown> | undefined;\n set: (updates: OMStateWrites) => Promise<void> | void;\n };\n om: { observer: OMRole; reflector: OMRole };\n}\n\n/** Minimal controller surface this module needs (model catalog + modes + sessions). */\ninterface ModelCatalog {\n listAvailableModels: () => Promise<\n Array<{ id?: string; modelName?: string; provider: string; hasApiKey: boolean; apiKeyEnvVar?: string }>\n >;\n listModes?: () => Array<{ id: string; defaultModelId?: string }>;\n getSessionByResource?: (resourceId: string, scope?: string) => Promise<OMSession | undefined>;\n}\n\n/**\n * Build a deduplicated, sorted list of providers from the model catalog,\n * annotated with where each provider's credential currently comes from.\n * Mirrors the TUI's `/api-keys` provider list.\n *\n * When `tenantCredentials` is given (deployed mode), sources reflect the\n * *caller's* tenant rows with user > org precedence and the server-global\n * `authStorage` is ignored; otherwise the local `auth.json` view is reported.\n */\nexport async function listProviders({\n controller,\n authStorage,\n tenantCredentials,\n}: {\n controller: ModelCatalog;\n authStorage?: AuthStorage;\n tenantCredentials?: CredentialRecord[];\n}): Promise<ProviderInfo[]> {\n const models = await controller.listAvailableModels();\n const seen = new Map<string, ProviderInfo>();\n\n for (const model of models) {\n if (seen.has(model.provider)) continue;\n\n const authProviderId = getAuthProviderId(model.provider);\n let source: ProviderInfo['source'] = 'none';\n let orgKey: boolean | undefined;\n let userCredential: ProviderInfo['userCredential'];\n let orgCredential: ProviderInfo['orgCredential'];\n if (tenantCredentials) {\n const userRec = tenantCredentials.find(r => r.scope === 'user' && r.provider === authProviderId);\n const orgRec = tenantCredentials.find(r => r.scope === 'org' && r.provider === authProviderId);\n // Any shared org credential (API key or org-wide OAuth) counts.\n orgKey = orgRec !== undefined;\n userCredential = userRec?.credential.type;\n orgCredential = orgRec?.credential.type;\n if (userRec?.credential.type === 'oauth') {\n source = 'oauth-user';\n } else if (userRec?.credential.type === 'api_key') {\n source = 'stored-user';\n } else if (orgRec?.credential.type === 'oauth') {\n source = 'oauth-org';\n } else if (orgRec?.credential.type === 'api_key') {\n source = 'stored-org';\n }\n } else if (authStorage?.isLoggedIn(authProviderId)) {\n source = 'oauth';\n } else if (authStorage?.hasStoredApiKey(model.provider)) {\n source = 'stored';\n } else if (model.apiKeyEnvVar && process.env[model.apiKeyEnvVar]) {\n source = 'env';\n } else if (model.hasApiKey) {\n source = 'env';\n }\n\n const flowKind = WEB_OAUTH_FLOW_KINDS[model.provider];\n seen.set(model.provider, {\n provider: model.provider,\n envVar: model.apiKeyEnvVar,\n source,\n ...(orgKey !== undefined ? { orgKey } : {}),\n ...(userCredential ? { userCredential } : {}),\n ...(orgCredential ? { orgCredential } : {}),\n ...(flowKind ? { oauth: { supported: true as const, modes: [flowKind] } } : {}),\n });\n }\n\n return Array.from(seen.values()).sort((a, b) => a.provider.localeCompare(b.provider));\n}\n\n/** A user-defined OpenAI-compatible provider, with key presence (never the key). */\nexport interface CustomProviderInfo {\n id: string;\n name: string;\n url: string;\n hasApiKey: boolean;\n models: string[];\n}\n\n/** Redact a stored custom-provider row for the client (key presence only). */\nfunction toCustomProviderInfo(record: CustomProviderRecord): CustomProviderInfo {\n return {\n id: record.providerId,\n name: record.name,\n url: record.url,\n hasApiKey: Boolean(record.apiKey),\n models: record.models,\n };\n}\n\n/** The resolved custom-providers storage scope for a request. */\ninterface CustomProvidersContext {\n storage: CustomProvidersStorage;\n orgId: string;\n userId: string;\n}\n\n/**\n * Resolve the custom-providers context for a request, or a ready-to-return\n * error response. Same posture as memory settings: tenant rows in deployed\n * mode, a sentinel `local` org in no-auth mode — never settings.json.\n */\nasync function resolveCustomProvidersContext({\n c,\n auth,\n customProviders,\n}: {\n c: Context;\n auth: RouteAuth;\n customProviders?: CustomProvidersStorage;\n}): Promise<CustomProvidersContext | { response: Response }> {\n await auth.ensureUser(c);\n const tenant = auth.tenant(c);\n if (!tenant && auth.enabled()) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (customProviders) {\n try {\n await customProviders.ensureReady();\n return tenant\n ? { storage: customProviders, orgId: tenantOrgId(tenant), userId: tenant.userId }\n : { storage: customProviders, orgId: 'local', userId: 'local' };\n } catch {\n // fall through to the unavailable response\n }\n }\n return {\n response: c.json(\n {\n error: 'custom_providers_unavailable',\n message: 'Custom provider storage is unavailable — the app database is not configured or failed to start.',\n },\n 503,\n ),\n };\n}\n\n/** Validate + coerce a request body into a CustomProviderSetting. */\nfunction parseCustomProviderBody(body: unknown): CustomProviderSetting | { error: string } {\n if (!body || typeof body !== 'object') return { error: 'Invalid JSON body' };\n const b = body as Record<string, unknown>;\n const name = typeof b.name === 'string' ? b.name.trim() : '';\n if (!name) return { error: 'Missing required field: name' };\n const url = typeof b.url === 'string' ? b.url.trim() : '';\n if (!url) return { error: 'Missing required field: url' };\n try {\n const parsed = new URL(url);\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return { error: 'url must be an http(s) URL' };\n }\n } catch {\n return { error: 'url must be a valid URL' };\n }\n const apiKey = typeof b.apiKey === 'string' && b.apiKey.trim() ? b.apiKey.trim() : undefined;\n const models = Array.isArray(b.models)\n ? b.models.filter((m): m is string => typeof m === 'string' && m.trim().length > 0).map(m => m.trim())\n : [];\n return { name, url, apiKey, models };\n}\n\n// ── Model packs ──────────────────────────────────────────────────────────\n\n/** A model pack as surfaced to the web client, with an `active` flag. */\nexport interface ModelPackInfo extends ModePack {\n custom: boolean;\n active: boolean;\n}\n\n/**\n * Compute which providers the user can reach, mirroring the TUI's\n * `/models-pack` access derivation: OAuth/api-key from the credential store for\n * the named providers, plus any other provider that has a usable key.\n */\nexport async function buildProviderAccess({\n controller,\n authStorage,\n tenantCredentials,\n}: {\n controller: ModelCatalog;\n authStorage?: AuthStorage;\n tenantCredentials?: CredentialRecord[];\n}): Promise<ProviderAccess> {\n const models = await controller.listAvailableModels();\n const hasModelKey = (provider: string) => models.some(m => m.provider === provider && m.hasApiKey);\n const accessLevel = (provider: string): ProviderAccessLevel => {\n const authProviderId = getAuthProviderId(provider);\n if (tenantCredentials) {\n const userRec = tenantCredentials.find(r => r.scope === 'user' && r.provider === authProviderId);\n const orgRec = tenantCredentials.find(r => r.scope === 'org' && r.provider === authProviderId);\n const credential = userRec?.credential ?? orgRec?.credential;\n if (credential?.type === 'oauth') return 'oauth';\n if (credential?.type === 'api_key' && credential.key.trim().length > 0) return 'apikey';\n return false;\n }\n\n const oauthCredential = authStorage?.get(authProviderId);\n if (oauthCredential?.type === 'oauth') return 'oauth';\n if (authStorage?.hasStoredApiKey(provider)) return 'apikey';\n const directCredential = authStorage?.get(provider);\n if (directCredential?.type === 'api_key' && directCredential.key.trim().length > 0) return 'apikey';\n return hasModelKey(provider) ? 'apikey' : false;\n };\n const access: ProviderAccess = {\n anthropic: accessLevel('anthropic'),\n openai: accessLevel('openai'),\n cerebras: accessLevel('cerebras'),\n google: accessLevel('google'),\n deepseek: accessLevel('deepseek'),\n 'github-copilot': accessLevel('github-copilot'),\n };\n const seen = new Set(Object.keys(access));\n for (const m of models) {\n if (!seen.has(m.provider)) {\n access[m.provider] = accessLevel(m.provider);\n seen.add(m.provider);\n }\n }\n return access;\n}\n\nfunction canUseModelProvider(access: ProviderAccess, provider: string): boolean {\n return Boolean(access[provider]);\n}\n\n/**\n * Where a request's custom model packs live. Same posture as memory settings\n * and custom providers: the `model-packs` factory storage domain, scoped per\n * org in deployed mode and to a sentinel `local` org in no-auth mode — never\n * settings.json.\n */\nexport interface PackContext {\n storage: ModelPacksStorage;\n orgId: string;\n userId: string;\n}\n\n/** Resolve the pack context for a request, or a ready-to-return error response. */\nasync function resolvePackContext({\n c,\n auth,\n modelPacks,\n}: {\n c: Context;\n auth: RouteAuth;\n modelPacks?: ModelPacksStorage;\n}): Promise<PackContext | { response: Response }> {\n await auth.ensureUser(c);\n const tenant = auth.tenant(c);\n if (!tenant && auth.enabled()) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (modelPacks) {\n try {\n await modelPacks.ensureReady();\n return tenant\n ? { storage: modelPacks, orgId: tenantOrgId(tenant), userId: tenant.userId }\n : { storage: modelPacks, orgId: 'local', userId: 'local' };\n } catch {\n // fall through to the unavailable response\n }\n }\n return {\n response: c.json(\n {\n error: 'model_packs_unavailable',\n message: 'Model pack storage is unavailable — the app database is not configured or failed to start.',\n },\n 503,\n ),\n };\n}\n\nasync function authorizePackSession({\n c,\n auth,\n sessions,\n packContext,\n resourceId,\n scope,\n}: {\n c: Context;\n auth: RouteAuth;\n sessions?: Pick<SourceControlStorageHandle['sessions'], 'getBySessionId'>;\n packContext: PackContext;\n resourceId: string;\n scope: string | undefined;\n}): Promise<Response | null> {\n if (!auth.enabled()) return null;\n if (!sessions) return c.json({ error: 'session_authorization_unavailable' }, 503);\n\n const sourceSession = await sessions.getBySessionId(resourceId);\n if (\n !sourceSession ||\n sourceSession.orgId !== packContext.orgId ||\n sourceSession.userId !== packContext.userId ||\n (scope !== undefined && sourceSession.sandboxWorkdir !== scope)\n ) {\n return c.json({ error: `No session for resourceId \"${resourceId}\"` }, 404);\n }\n return null;\n}\n\n/** DB row → the `ModePack` shape the packs list and activation flow consume. */\nfunction recordToModePack(record: ModelPackRecord): ModePack {\n return { id: `custom:${record.id}`, name: record.name, description: 'Saved custom pack', models: record.models };\n}\n\n/**\n * List available model packs (built-in, gated by provider access, plus saved\n * custom packs from the request's pack context). Drops the synthetic\n * \"New Custom\" placeholder because the web client has its own create flow.\n * `active` marks the user's default pack for new interactive chats.\n */\nexport async function listModelPacks({\n controller,\n authStorage,\n tenantCredentials,\n packContext,\n activePackId,\n}: {\n controller: ModelCatalog;\n authStorage?: AuthStorage;\n tenantCredentials?: CredentialRecord[];\n packContext: PackContext;\n activePackId?: string | null;\n}): Promise<ModelPackInfo[]> {\n const access = await buildProviderAccess({ controller, authStorage, tenantCredentials });\n const packs = [\n ...getAvailableModePacks(access),\n ...(await packContext.storage.list({ orgId: packContext.orgId })).map(recordToModePack),\n ];\n return packs\n .filter(p => p.id !== 'custom') // synthetic \"choose each model\" placeholder\n .map(p => ({\n ...p,\n custom: p.id.startsWith('custom:'),\n active: activePackId != null && p.id === activePackId,\n }));\n}\n\nasync function resolveSessionModelPackId(session: PackSession | undefined): Promise<string | null> {\n if (!session?.thread.getId()) return null;\n const value = await session.thread.getSetting({ key: 'activeModelPackId' });\n return typeof value === 'string' ? value : null;\n}\n\n// ── Observational memory ────────────────────────────────────────────────────\n// Mirrors the TUI `/om` command. Settings are persisted per organization and\n// user in the Factory app database. Requests with an active session also apply\n// changes immediately to that session's state and thread settings.\n\n/** Read the current OM config from a session. */\nexport interface OMConfigInfo {\n observerModelId: string;\n reflectorModelId: string;\n observationThreshold: number;\n reflectionThreshold: number;\n observeAttachments: 'auto' | boolean;\n}\n\nexport interface ProviderOMDefaultsResponse {\n ok: true;\n config: OMConfigInfo;\n}\n\n/** `GET /web/config/thinking` — deployment-scoped reasoning-effort defaults. */\nexport interface ThinkingConfigInfo {\n /** All selectable levels, in escalation order. */\n levels: readonly ThinkingLevelSetting[];\n /** `preferences.thinkingLevel` — fallback when a mode has no default. */\n globalDefault: ThinkingLevelSetting;\n /** `models.modeThinkingDefaults` — per-mode overrides of the global default. */\n modeDefaults: Record<string, ThinkingLevelSetting>;\n /** Mode ids known to the controller (for rendering per-mode rows). */\n modes: string[];\n}\n\n/** `PUT /web/config/thinking` success payload. */\nexport interface UpdateThinkingConfigResponse {\n ok: true;\n globalDefault: ThinkingLevelSetting;\n modeDefaults: Record<string, ThinkingLevelSetting>;\n}\n\nexport function readOMConfig(session: OMSession): OMConfigInfo {\n const state = session.state.get() ?? {};\n const observeAttachments = state.observeAttachments;\n return {\n observerModelId: session.om.observer.modelId() ?? '',\n reflectorModelId: session.om.reflector.modelId() ?? '',\n observationThreshold: session.om.observer.threshold() ?? DEFAULT_OBSERVATION_THRESHOLD,\n reflectionThreshold: session.om.reflector.threshold() ?? DEFAULT_REFLECTION_THRESHOLD,\n observeAttachments: observeAttachments === true || observeAttachments === false ? observeAttachments : 'auto',\n };\n}\n\nfunction readStoredOMConfig(record: MemorySettingsRecord | null, fallbackOmModelId?: string): OMConfigInfo {\n const fallback = fallbackOmModelId ?? DEFAULT_OM_MODEL_ID;\n return {\n observerModelId: record?.observerModelId ?? fallback,\n reflectorModelId: record?.reflectorModelId ?? fallback,\n observationThreshold: record?.observationThreshold ?? DEFAULT_OBSERVATION_THRESHOLD,\n reflectionThreshold: record?.reflectionThreshold ?? DEFAULT_REFLECTION_THRESHOLD,\n observeAttachments: record?.observeAttachments ?? 'auto',\n };\n}\n\n/**\n * Where a request's OM settings live: the `memory-settings` factory storage\n * domain, one row per (org, user). Without a tenant (auth disabled), settings\n * land on a sentinel `(local, local)` row in the same table — the web surface\n * never reads or writes `settings.json` for memory settings.\n */\ninterface MemorySettingsContext {\n storage: MemorySettingsStorage;\n orgId: string;\n userId: string;\n}\n\n/**\n * Resolve the memory-settings context for a request, or a ready-to-return\n * error response. When `factoryProjectId` is provided the row addressed is the\n * factory project's shared settings (a sentinel user id in the caller's org)\n * instead of the caller's personal row — this is what factory board runs and\n * channel sessions hydrate from.\n */\nasync function resolveMemorySettingsContext({\n c,\n auth,\n memorySettings,\n factoryProjectId,\n factoryProjects,\n}: {\n c: Context;\n auth: RouteAuth;\n memorySettings?: MemorySettingsStorage;\n factoryProjectId?: string;\n factoryProjects?: FactoryProjectsStorage;\n}): Promise<MemorySettingsContext | { response: Response }> {\n await auth.ensureUser(c);\n const tenant = auth.tenant(c);\n if (!tenant && auth.enabled()) return { response: c.json({ error: 'unauthorized' }, 401) };\n // Factory-scoped rows are shared org state: the target project must exist in\n // the caller's org before its settings row can be read or written.\n if (factoryProjectId && tenant) {\n if (!factoryProjects) return { response: c.json({ error: 'factory_unavailable' }, 503) };\n try {\n await factoryProjects.ensureReady();\n const project = await factoryProjects.get({ orgId: tenantOrgId(tenant), id: factoryProjectId });\n if (!project) return { response: c.json({ error: 'factory_project_not_found' }, 404) };\n } catch {\n return { response: c.json({ error: 'factory_unavailable' }, 503) };\n }\n }\n if (memorySettings) {\n try {\n await memorySettings.ensureReady();\n const factoryUserId = factoryProjectId ? factoryMemorySettingsUserId(factoryProjectId) : undefined;\n return tenant\n ? { storage: memorySettings, orgId: tenantOrgId(tenant), userId: factoryUserId ?? tenant.userId }\n : { storage: memorySettings, orgId: 'local', userId: factoryUserId ?? 'local' };\n } catch {\n // fall through to the unavailable response\n }\n }\n return {\n response: c.json(\n {\n error: 'memory_settings_unavailable',\n message: 'Memory settings storage is unavailable — the app database is not configured or failed to start.',\n },\n 503,\n ),\n };\n}\n\n/** Persist an OM knob change to the caller's memory-settings row. */\nasync function persistMemorySettings(\n context: MemorySettingsContext,\n patch: MemorySettingsPatch,\n fillIfUnset?: MemorySettingsFillIfUnset,\n): Promise<void> {\n await context.storage.patch({ orgId: context.orgId, userId: context.userId, patch, fillIfUnset });\n}\n\n/** Dependencies injected into {@link ConfigRoutes}. */\nexport interface ConfigRoutesDeps extends RouteDependencies {\n controller: ModelCatalog;\n features?: { knowledge: boolean };\n authStorage?: AuthStorage;\n /** Tenant credential domain handle; absent in local (no-DB) mode. */\n modelCredentials?: ModelCredentialsStorage;\n /** Tenant model-packs domain handle; absent in local (no-DB) mode. */\n modelPacks?: ModelPacksStorage;\n /** Source-control sessions used to authorize session-scoped model-pack access. */\n sourceControlSessions?: Pick<SourceControlStorageHandle['sessions'], 'getBySessionId'>;\n /** Tenant memory-settings domain handle; absent in local (no-DB) mode. */\n memorySettings?: MemorySettingsStorage;\n /** Factory projects domain, used to derive OM fallbacks from a factory's default model. */\n factoryProjects?: FactoryProjectsStorage;\n /** Custom-providers domain handle; absent when the app database is missing. */\n customProviders?: CustomProvidersStorage;\n /** Notifies the host after tenant credentials change so caches can be dropped. */\n onCredentialsChanged?: (tenant: { orgId: string; userId?: string }) => void;\n /** Notifies the host after custom providers change so model-router caches can be dropped. */\n onCustomProvidersChanged?: (tenant: { orgId: string }) => void;\n /**\n * Path of the server's settings.json backing the deployment-scoped thinking\n * defaults. Defaults to the standard app-data location; injectable for tests.\n */\n settingsPath?: string;\n}\n\n/**\n * The web config routes as Mastra `apiRoutes`:\n * - `GET /web/config/features` — list server-enabled product features\n * - `GET /web/config/providers` — list providers + key source\n * - `PUT /web/config/providers/:provider/key` — set/update a provider's API key\n * - `DELETE /web/config/providers/:provider/key` — remove a stored API key\n * - `GET /web/config/models` — list available models (credentialed providers)\n * - `GET /web/config/custom-providers` — list custom OpenAI-compatible providers\n * - `POST /web/config/custom-providers` — create/update a custom provider\n * - `DELETE /web/config/custom-providers/:id` — remove a custom provider\n * - `GET /web/config/thinking` — read thinking (reasoning-effort) defaults\n * - `PUT /web/config/thinking` — set global/per-mode thinking defaults\n * - `GET /web/config/om` — read OM models/thresholds/observe-attachments\n * - `PUT /web/config/om/:role/model` — switch observer/reflector model\n * - `PUT /web/config/om/thresholds` — set observation/reflection thresholds\n * - `PUT /web/config/om/observe-attachments` — set observe-attachments (auto/on/off)\n */\nexport class ConfigRoutes extends Route<ConfigRoutesDeps> {\n routes(): ApiRoute[] {\n const options = this.deps;\n const { controller, authStorage, auth } = options;\n const onCredentialsChanged = options.onCredentialsChanged ?? (() => {});\n const onCustomProvidersChanged = options.onCustomProvidersChanged ?? (() => {});\n\n // Factory-scoped OM reads without a stored row fall back to the low-cost\n // OM model of the factory default model's provider — not the global\n // built-in default, whose provider may have no credential here.\n const factoryOmFallback = async (factoryProjectId: string | undefined): Promise<string | undefined> => {\n if (!factoryProjectId || !options.factoryProjects) return undefined;\n try {\n const project = await options.factoryProjects.getById({ id: factoryProjectId });\n const defaultModelId = project?.defaultModelId ?? undefined;\n const provider = defaultModelId?.split('/')[0];\n return provider ? resolveProviderOMDefault(provider, defaultModelId).modelId : undefined;\n } catch {\n return undefined;\n }\n };\n\n return [\n registerApiRoute('/web/config/features', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => c.json({ knowledge: options.features?.knowledge ?? false }),\n }),\n\n registerApiRoute('/web/config/providers', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n try {\n // Tenant mode lists the caller's rows and never exposes the\n // server-global auth.json; local mode is unchanged.\n const tenantCredentials = await listTenantCredentialsForRequest({\n c: loose(c),\n auth,\n credentials: options.modelCredentials,\n });\n // Tenant mode also reports whether the caller may write org-wide\n // keys, so the settings UI can gate the \"Everyone in org\" option.\n const tenant = auth.tenant(loose(c));\n const orgKeyAdmin = tenant ? await auth.isOrganizationAdmin(loose(c), tenantOrgId(tenant)) : undefined;\n return c.json({\n providers: await listProviders({\n controller,\n authStorage: tenantCredentials ? undefined : authStorage,\n tenantCredentials,\n }),\n ...(orgKeyAdmin !== undefined ? { orgKeyAdmin } : {}),\n });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/providers/:provider/key', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: options.modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n let body: { key?: unknown; envVar?: unknown; scope?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const key = typeof body.key === 'string' ? body.key.trim() : '';\n if (!key) return c.json({ error: 'Missing required field: key' }, 400);\n const envVar = typeof body.envVar === 'string' ? body.envVar : undefined;\n const scope = body.scope === 'org' ? 'org' : 'user';\n try {\n if (ctx.mode === 'tenant') {\n if (scope === 'org' && !(await auth.isOrganizationAdmin(loose(c), ctx.orgId))) {\n return c.json({ error: 'organization_admin_required' }, 403);\n }\n const tenant = scope === 'org' ? { orgId: ctx.orgId } : { orgId: ctx.orgId, userId: ctx.userId };\n // envVar is intentionally ignored: tenant credentials are resolved\n // per-request, never written into process.env.\n await ctx.storage.setCredential(tenant, getAuthProviderId(provider), { type: 'api_key', key });\n onCredentialsChanged(tenant);\n const records = await ctx.storage.listCredentials(ctx.orgId, ctx.userId);\n const providers = await listProviders({ controller, tenantCredentials: records });\n return c.json({ ok: true, provider: providers.find(p => p.provider === provider) });\n }\n if (!authStorage) return c.json({ error: 'Credential storage is not available' }, 503);\n // Local mode is single-user: scope is meaningless and ignored.\n authStorage.setStoredApiKey(provider, key, envVar);\n const providers = await listProviders({ controller, authStorage });\n return c.json({ ok: true, provider: providers.find(p => p.provider === provider) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/providers/:provider/key', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCredentialContext({ c: loose(c), auth, credentials: options.modelCredentials });\n if ('response' in ctx) return ctx.response;\n\n const provider = c.req.param('provider');\n const scope = c.req.query('scope') === 'org' ? 'org' : 'user';\n try {\n if (ctx.mode === 'tenant') {\n if (scope === 'org' && !(await auth.isOrganizationAdmin(loose(c), ctx.orgId))) {\n return c.json({ error: 'organization_admin_required' }, 403);\n }\n const tenant = scope === 'org' ? { orgId: ctx.orgId } : { orgId: ctx.orgId, userId: ctx.userId };\n await ctx.storage.removeCredential(tenant, getAuthProviderId(provider));\n onCredentialsChanged(tenant);\n const records = await ctx.storage.listCredentials(ctx.orgId, ctx.userId);\n const providers = await listProviders({ controller, tenantCredentials: records });\n return c.json({ ok: true, provider: providers.find(p => p.provider === provider) });\n }\n if (!authStorage) return c.json({ error: 'Credential storage is not available' }, 503);\n authStorage.remove(`apikey:${provider}`);\n const providers = await listProviders({ controller, authStorage });\n return c.json({ ok: true, provider: providers.find(p => p.provider === provider) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n // ── Custom providers (OpenAI-compatible endpoints) ──────────────────────\n // Mirrors the TUI's /custom-providers command, but backed by the\n // `custom-providers` domain (org rows in tenant mode, a sentinel `local`\n // org in no-auth mode) — the server never reads settings.json for these.\n\n registerApiRoute('/web/config/custom-providers', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCustomProvidersContext({\n c: loose(c),\n auth,\n customProviders: options.customProviders,\n });\n if ('response' in ctx) return ctx.response;\n try {\n const records = await ctx.storage.list({ orgId: ctx.orgId });\n return c.json({ providers: records.map(toCustomProviderInfo) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/custom-providers', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCustomProvidersContext({\n c: loose(c),\n auth,\n customProviders: options.customProviders,\n });\n if ('response' in ctx) return ctx.response;\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const parsed = parseCustomProviderBody(body);\n if ('error' in parsed) return c.json({ error: parsed.error }, 400);\n // `previousId` lets a rename remove the old entry as well as any name clash.\n const previousId =\n body && typeof body === 'object' && typeof (body as Record<string, unknown>).previousId === 'string'\n ? ((body as Record<string, unknown>).previousId as string)\n : undefined;\n try {\n const record = await ctx.storage.upsert({\n orgId: ctx.orgId,\n userId: ctx.userId,\n input: {\n providerId: getCustomProviderId(parsed.name),\n name: parsed.name,\n url: parsed.url,\n apiKey: parsed.apiKey,\n models: parsed.models,\n },\n previousProviderId: previousId,\n });\n onCustomProvidersChanged({ orgId: ctx.orgId });\n return c.json({ ok: true, provider: toCustomProviderInfo(record) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/custom-providers/:id', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const ctx = await resolveCustomProvidersContext({\n c: loose(c),\n auth,\n customProviders: options.customProviders,\n });\n if ('response' in ctx) return ctx.response;\n const id = c.req.param('id');\n try {\n await ctx.storage.delete({ orgId: ctx.orgId, providerId: id });\n onCustomProvidersChanged({ orgId: ctx.orgId });\n return c.json({ ok: true });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n // ── Available models ────────────────────────────────────────────────────\n // Session-independent model catalog for settings pickers (Factory default\n // model, pack editors). Only models whose provider has a credential are\n // returned — the same filter the session-scoped hook applies client-side.\n\n registerApiRoute('/web/config/models', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n try {\n const tenantCredentials = await listTenantCredentialsForRequest({\n c: loose(c),\n auth,\n credentials: options.modelCredentials,\n });\n const [models, access] = await Promise.all([\n controller.listAvailableModels(),\n buildProviderAccess({\n controller,\n authStorage: tenantCredentials ? undefined : authStorage,\n tenantCredentials,\n }),\n ]);\n const catalog = models\n .filter(m => canUseModelProvider(access, m.provider) && typeof m.id === 'string')\n .map(m => ({ id: m.id!, provider: m.provider, modelName: m.modelName, hasApiKey: true }));\n // Append the caller's custom provider models (DB-backed, org rows in\n // tenant mode / sentinel `local` org in no-auth mode). The boot-time\n // gateway catalog only carries the local list, so tenant callers get\n // theirs here. Dedupe against ids already present.\n if (options.customProviders) {\n try {\n const ctx = await resolveCustomProvidersContext({\n c: loose(c),\n auth,\n customProviders: options.customProviders,\n });\n if (!('response' in ctx)) {\n const known = new Set(catalog.map(m => m.id));\n for (const record of await ctx.storage.list({ orgId: ctx.orgId })) {\n for (const model of record.models) {\n const id = `${record.providerId}/${model}`;\n if (known.has(id)) continue;\n known.add(id);\n catalog.push({ id, provider: record.providerId, modelName: model, hasApiKey: true });\n }\n }\n }\n } catch {\n // Fail soft: the catalog still serves the built-in models.\n }\n }\n return c.json({\n models: catalog.sort((a, b) =>\n a.provider === b.provider ? a.id.localeCompare(b.id) : a.provider.localeCompare(b.provider),\n ),\n });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n // ── Model packs ─────────────────────────────────────────────────────────\n // Custom pack definitions are organization-scoped. Each user can choose a\n // default for new interactive chats, while a thread-specific activation\n // takes precedence. Factory work sessions use the project default model.\n\n registerApiRoute('/web/config/model-packs', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const packContext = await resolvePackContext({ c: loose(c), auth, modelPacks: options.modelPacks });\n if ('response' in packContext) return packContext.response;\n const resourceId = c.req.query('resourceId');\n const scope = c.req.query('scope') || undefined;\n try {\n const activePack = await packContext.storage.getActive({\n orgId: packContext.orgId,\n userId: packContext.userId,\n });\n const activePackId = activePack?.packId ?? null;\n if (resourceId) {\n const unauthorized = await authorizePackSession({\n c: loose(c),\n auth,\n sessions: options.sourceControlSessions,\n packContext,\n resourceId,\n scope,\n });\n if (unauthorized) return unauthorized;\n }\n const session = resourceId ? await controller.getSessionByResource?.(resourceId, scope) : undefined;\n const sessionPackId = await resolveSessionModelPackId(session);\n const tenantCredentials = await listTenantCredentialsForRequest({\n c: loose(c),\n auth,\n credentials: options.modelCredentials,\n });\n return c.json({\n packs: await listModelPacks({\n controller,\n authStorage: tenantCredentials ? undefined : authStorage,\n tenantCredentials,\n packContext,\n activePackId,\n }),\n activePackId,\n sessionPackId,\n });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/model-packs', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const packContext = await resolvePackContext({ c: loose(c), auth, modelPacks: options.modelPacks });\n if ('response' in packContext) return packContext.response;\n let body: { name?: unknown; models?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const name = typeof body.name === 'string' ? body.name.trim() : '';\n if (!name) return c.json({ error: 'Missing required field: name' }, 400);\n const m = (body.models ?? {}) as Record<string, unknown>;\n const build = typeof m.build === 'string' ? m.build.trim() : '';\n const plan = typeof m.plan === 'string' ? m.plan.trim() : '';\n const fast = typeof m.fast === 'string' ? m.fast.trim() : '';\n if (!build || !plan || !fast) {\n return c.json({ error: 'models.build, models.plan and models.fast are required' }, 400);\n }\n try {\n const record = await packContext.storage.upsert({\n orgId: packContext.orgId,\n userId: packContext.userId,\n input: { name, models: { build, plan, fast } },\n });\n return c.json({ ok: true, pack: recordToModePack(record) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/model-packs/active', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const packContext = await resolvePackContext({ c: loose(c), auth, modelPacks: options.modelPacks });\n if ('response' in packContext) return packContext.response;\n try {\n await packContext.storage.clearActive({ orgId: packContext.orgId, userId: packContext.userId });\n return c.json({ ok: true, activePackId: null });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/model-packs/:id', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const packContext = await resolvePackContext({ c: loose(c), auth, modelPacks: options.modelPacks });\n if ('response' in packContext) return packContext.response;\n const id = decodeURIComponent(c.req.param('id'));\n try {\n const recordId = id.startsWith('custom:') ? id.slice('custom:'.length) : id;\n const deleted = await packContext.storage.delete({ orgId: packContext.orgId, id: recordId });\n return deleted ? c.json({ ok: true }) : c.json({ error: `Unknown pack \"${id}\"` }, 404);\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/model-packs/:id/activate', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const packContext = await resolvePackContext({ c: loose(c), auth, modelPacks: options.modelPacks });\n if ('response' in packContext) return packContext.response;\n const id = decodeURIComponent(c.req.param('id'));\n let body: { resourceId?: unknown; scope?: unknown; target?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const target = body.target ?? 'default';\n if (target !== 'default' && target !== 'session') {\n return c.json({ error: 'target must be \"default\" or \"session\"' }, 400);\n }\n const resourceId = typeof body.resourceId === 'string' && body.resourceId ? body.resourceId : undefined;\n const scope = typeof body.scope === 'string' && body.scope ? body.scope : undefined;\n if (target === 'session' && !resourceId) {\n return c.json({ error: 'Missing required field for session activation: resourceId' }, 400);\n }\n try {\n if (target === 'session' && resourceId) {\n const unauthorized = await authorizePackSession({\n c: loose(c),\n auth,\n sessions: options.sourceControlSessions,\n packContext,\n resourceId,\n scope,\n });\n if (unauthorized) return unauthorized;\n }\n const session =\n target === 'session' && resourceId\n ? await controller.getSessionByResource?.(resourceId, scope)\n : undefined;\n if (target === 'session' && !session) {\n return c.json({ error: `No session for resourceId \"${resourceId}\"` }, 404);\n }\n const tenantCredentials = await listTenantCredentialsForRequest({\n c: loose(c),\n auth,\n credentials: options.modelCredentials,\n });\n const packs = await listModelPacks({\n controller,\n authStorage: tenantCredentials ? undefined : authStorage,\n tenantCredentials,\n packContext,\n });\n const pack = packs.find(p => p.id === id);\n if (!pack) return c.json({ error: `Unknown pack \"${id}\"` }, 404);\n if (target === 'default') {\n await packContext.storage.setActive({\n orgId: packContext.orgId,\n userId: packContext.userId,\n packId: pack.id,\n models: pack.models,\n });\n return c.json({ ok: true, target, activePackId: pack.id });\n }\n if (session) {\n await applyActiveModelPack(session, { packId: pack.id, models: pack.models });\n }\n return c.json({ ok: true, target, sessionPackId: pack.id });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n // ── Thinking (reasoning-effort) defaults ─────────────────────────────────\n // Deployment-scoped defaults stored in the server's settings.json: the\n // global `preferences.thinkingLevel` plus per-mode\n // `models.modeThinkingDefaults`. These are what request-time resolution\n // falls back to when a session carries no explicit override — including\n // automated (rule-driven) Factory runs nobody opens interactively. In\n // tenant mode, writes are disabled because the settings file is shared\n // deployment-wide rather than scoped to an organization.\n\n registerApiRoute('/web/config/thinking', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n try {\n const settings = loadSettings(options.settingsPath);\n const modes = controller.listModes?.().map(mode => mode.id) ?? [];\n return c.json({\n levels: THINKING_LEVEL_VALUES,\n globalDefault: settings.preferences.thinkingLevel,\n modeDefaults: settings.models.modeThinkingDefaults,\n modes,\n });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/thinking', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n if (auth.enabled()) {\n return c.json({ error: 'Deployment thinking defaults can only be changed in local mode' }, 403);\n }\n let body: { globalDefault?: unknown; modeDefaults?: unknown };\n try {\n const parsed: unknown = await c.req.json();\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return c.json({ error: 'Request body must be a JSON object' }, 400);\n }\n body = parsed as { globalDefault?: unknown; modeDefaults?: unknown };\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n if (body.globalDefault === undefined && body.modeDefaults === undefined) {\n return c.json({ error: 'Provide globalDefault and/or modeDefaults' }, 400);\n }\n if (body.globalDefault !== undefined && !isThinkingLevelSetting(body.globalDefault)) {\n return c.json(\n { error: `Invalid globalDefault — expected one of: ${THINKING_LEVEL_VALUES.join(', ')}` },\n 400,\n );\n }\n // Per-mode patch semantics: a valid level sets the mode's default,\n // `null` clears it (back to the global default).\n const modePatch: Record<string, ThinkingLevelSetting | null> = {};\n if (body.modeDefaults !== undefined) {\n if (!body.modeDefaults || typeof body.modeDefaults !== 'object' || Array.isArray(body.modeDefaults)) {\n return c.json({ error: 'modeDefaults must be an object of mode → level (or null to clear)' }, 400);\n }\n const knownModes = new Set(controller.listModes?.().map(mode => mode.id) ?? []);\n for (const [mode, level] of Object.entries(body.modeDefaults as Record<string, unknown>)) {\n if (!knownModes.has(mode)) {\n return c.json({ error: `Unknown mode \"${mode}\"` }, 400);\n }\n if (level === null) {\n modePatch[mode] = null;\n } else if (isThinkingLevelSetting(level)) {\n modePatch[mode] = level;\n } else {\n return c.json(\n { error: `Invalid level for mode \"${mode}\" — expected one of: ${THINKING_LEVEL_VALUES.join(', ')}` },\n 400,\n );\n }\n }\n }\n try {\n const settings = loadSettings(options.settingsPath);\n if (body.globalDefault !== undefined && isThinkingLevelSetting(body.globalDefault)) {\n settings.preferences.thinkingLevel = body.globalDefault;\n }\n for (const [mode, level] of Object.entries(modePatch)) {\n if (level === null) delete settings.models.modeThinkingDefaults[mode];\n else settings.models.modeThinkingDefaults[mode] = level;\n }\n saveSettings(settings, options.settingsPath);\n return c.json({\n ok: true,\n globalDefault: settings.preferences.thinkingLevel,\n modeDefaults: settings.models.modeThinkingDefaults,\n });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/om/provider-defaults', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n let body: { providerId?: unknown; factoryModelId?: unknown; factoryId?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const providerId = typeof body.providerId === 'string' ? body.providerId.trim() : '';\n const factoryModelId = typeof body.factoryModelId === 'string' ? body.factoryModelId.trim() : '';\n const factoryProjectId = typeof body.factoryId === 'string' && body.factoryId ? body.factoryId : undefined;\n if (!providerId) return c.json({ error: 'Missing required field: providerId' }, 400);\n\n const context = await resolveMemorySettingsContext({\n c: loose(c),\n auth,\n memorySettings: options.memorySettings,\n factoryProjectId,\n factoryProjects: options.factoryProjects,\n });\n if ('response' in context) return context.response;\n\n try {\n const tenantCredentials = await listTenantCredentialsForRequest({\n c: loose(c),\n auth,\n credentials: options.modelCredentials,\n });\n const access = await buildProviderAccess({\n controller,\n authStorage: tenantCredentials ? undefined : authStorage,\n tenantCredentials,\n });\n if (!access[providerId]) return c.json({ error: `Provider \"${providerId}\" is not configured` }, 400);\n\n const modelId = resolveProviderOMDefault(providerId, factoryModelId).modelId;\n const record = await context.storage.patch({\n orgId: context.orgId,\n userId: context.userId,\n patch: {},\n fillIfUnset: { observerModelId: modelId, reflectorModelId: modelId },\n });\n return c.json({ ok: true, config: readStoredOMConfig(record) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n // ── Observational memory ──────────────────────────────────────────────────\n // Mirrors the TUI's /om command. All five knobs are durably stored in the\n // per-(org, user) `memory-settings` app table — never settings.json. When a\n // session is supplied, changes are also applied to its state and thread.\n\n registerApiRoute('/web/config/om', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resourceId = c.req.query('resourceId');\n const scope = c.req.query('scope') || undefined;\n const factoryProjectId = c.req.query('factoryId') || undefined;\n const context = await resolveMemorySettingsContext({\n c: loose(c),\n auth,\n memorySettings: options.memorySettings,\n factoryProjectId,\n factoryProjects: options.factoryProjects,\n });\n if ('response' in context) return context.response;\n try {\n const record = await context.storage.get({ orgId: context.orgId, userId: context.userId });\n const fallback = await factoryOmFallback(factoryProjectId);\n if (!resourceId) return c.json({ config: readStoredOMConfig(record, fallback) });\n\n // Session sync is best-effort: the stored row is authoritative and\n // new sessions hydrate from it, so a resourceId without a live\n // session (e.g. settings page after a restart) still reads the\n // stored config instead of failing.\n const session = await controller.getSessionByResource?.(resourceId, scope);\n if (!session) return c.json({ config: readStoredOMConfig(record, fallback) });\n await applyStoredMemorySettings(session, record, fallback);\n return c.json({ config: readOMConfig(session) });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/om/:role/model', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n const role = c.req.param('role');\n if (role !== 'observer' && role !== 'reflector') {\n return c.json({ error: `Unknown OM role \"${role}\"` }, 400);\n }\n let body: { resourceId?: unknown; modelId?: unknown; scope?: unknown; factoryId?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const resourceId = typeof body.resourceId === 'string' ? body.resourceId : '';\n const scope = typeof body.scope === 'string' && body.scope ? body.scope : undefined;\n const factoryProjectId = typeof body.factoryId === 'string' && body.factoryId ? body.factoryId : undefined;\n const modelId = typeof body.modelId === 'string' ? body.modelId.trim() : '';\n if (!modelId) return c.json({ error: 'Missing required field: modelId' }, 400);\n const context = await resolveMemorySettingsContext({\n c: loose(c),\n auth,\n memorySettings: options.memorySettings,\n factoryProjectId,\n factoryProjects: options.factoryProjects,\n });\n if ('response' in context) return context.response;\n try {\n // Best-effort session sync: persist regardless, apply to the live\n // session only when one exists for the resourceId.\n const session = resourceId ? await controller.getSessionByResource?.(resourceId, scope) : undefined;\n const otherRole = session ? (role === 'observer' ? session.om.reflector : session.om.observer) : undefined;\n const otherRoleCurrentModelId = otherRole?.modelId() ?? null;\n await session?.om[role].switchModel({ modelId });\n // Pin the other role's current model too, so a later restart\n // doesn't drift it once this role is explicitly overridden. The\n // \"only if still unset\" check runs inside the storage layer's\n // atomic update, so a concurrent explicit switch of the other\n // role is never clobbered by this fill.\n const otherKey = role === 'observer' ? 'reflectorModelId' : 'observerModelId';\n await persistMemorySettings(\n context,\n { [role === 'observer' ? 'observerModelId' : 'reflectorModelId']: modelId },\n otherRoleCurrentModelId ? { [otherKey]: otherRoleCurrentModelId } : undefined,\n );\n const config = session\n ? readOMConfig(session)\n : readStoredOMConfig(\n await context.storage.get({ orgId: context.orgId, userId: context.userId }),\n await factoryOmFallback(factoryProjectId),\n );\n return c.json({ ok: true, config });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/om/thresholds', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n let body: {\n resourceId?: unknown;\n observationThreshold?: unknown;\n reflectionThreshold?: unknown;\n scope?: unknown;\n factoryId?: unknown;\n };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const resourceId = typeof body.resourceId === 'string' ? body.resourceId : '';\n const scope = typeof body.scope === 'string' && body.scope ? body.scope : undefined;\n const factoryProjectId = typeof body.factoryId === 'string' && body.factoryId ? body.factoryId : undefined;\n const observation =\n typeof body.observationThreshold === 'number' && body.observationThreshold > 0\n ? Math.round(body.observationThreshold)\n : undefined;\n const reflection =\n typeof body.reflectionThreshold === 'number' && body.reflectionThreshold > 0\n ? Math.round(body.reflectionThreshold)\n : undefined;\n if (observation === undefined && reflection === undefined) {\n return c.json({ error: 'Provide observationThreshold and/or reflectionThreshold (positive numbers)' }, 400);\n }\n const context = await resolveMemorySettingsContext({\n c: loose(c),\n auth,\n memorySettings: options.memorySettings,\n factoryProjectId,\n factoryProjects: options.factoryProjects,\n });\n if ('response' in context) return context.response;\n try {\n // Best-effort session sync: persist regardless, apply to the live\n // session only when one exists for the resourceId.\n const session = resourceId ? await controller.getSessionByResource?.(resourceId, scope) : undefined;\n if (observation !== undefined && session) {\n await session.state.set({ observationThreshold: observation });\n await session.thread.setSetting({ key: 'observationThreshold', value: observation });\n }\n if (reflection !== undefined && session) {\n await session.state.set({ reflectionThreshold: reflection });\n await session.thread.setSetting({ key: 'reflectionThreshold', value: reflection });\n }\n await persistMemorySettings(context, {\n ...(observation !== undefined ? { observationThreshold: observation } : {}),\n ...(reflection !== undefined ? { reflectionThreshold: reflection } : {}),\n });\n const config = session\n ? readOMConfig(session)\n : readStoredOMConfig(\n await context.storage.get({ orgId: context.orgId, userId: context.userId }),\n await factoryOmFallback(factoryProjectId),\n );\n return c.json({ ok: true, config });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n\n registerApiRoute('/web/config/om/observe-attachments', {\n method: 'PUT',\n requiresAuth: false,\n handler: async c => {\n let body: { resourceId?: unknown; value?: unknown; scope?: unknown; factoryId?: unknown };\n try {\n body = await c.req.json();\n } catch {\n return c.json({ error: 'Invalid JSON body' }, 400);\n }\n const resourceId = typeof body.resourceId === 'string' ? body.resourceId : '';\n const scope = typeof body.scope === 'string' && body.scope ? body.scope : undefined;\n const factoryProjectId = typeof body.factoryId === 'string' && body.factoryId ? body.factoryId : undefined;\n const raw = body.value;\n const value: 'auto' | boolean = raw === 'auto' || raw === true || raw === false ? raw : 'auto';\n if (raw !== 'auto' && raw !== true && raw !== false) {\n return c.json({ error: \"value must be 'auto', true, or false\" }, 400);\n }\n const context = await resolveMemorySettingsContext({\n c: loose(c),\n auth,\n memorySettings: options.memorySettings,\n factoryProjectId,\n factoryProjects: options.factoryProjects,\n });\n if ('response' in context) return context.response;\n try {\n // Best-effort session sync: persist regardless, apply to the live\n // session only when one exists for the resourceId.\n const session = resourceId ? await controller.getSessionByResource?.(resourceId, scope) : undefined;\n if (session) {\n await session.state.set({ observeAttachments: value });\n await session.thread.setSetting({ key: 'observeAttachments', value });\n }\n await persistMemorySettings(context, { observeAttachments: value });\n const config = session\n ? readOMConfig(session)\n : readStoredOMConfig(\n await context.storage.get({ orgId: context.orgId, userId: context.userId }),\n await factoryOmFallback(factoryProjectId),\n );\n return c.json({ ok: true, config });\n } catch (error) {\n return c.json({ error: error instanceof Error ? error.message : String(error) }, 500);\n }\n },\n }),\n ];\n }\n}\n"],"mappings":"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"}
@@ -6,9 +6,9 @@
6
6
  * HTTP routes. Flow state lives in login sessions — the `model-credentials`
7
7
  * domain's `oauth_login_sessions` table in tenant mode (any replica can
8
8
  * complete/poll), an in-memory store in local mode — so a flow can span
9
- * requests. Completed credentials are always **user-scoped** (plan tokens are
10
- * personal subscriptions) in tenant mode, or written to the file-backed
11
- * `AuthStorage` in local mode.
9
+ * requests. Completed credentials are **user-scoped by default**; org admins
10
+ * can start a flow with `{ scope: 'org' }` to share the credential with the
11
+ * whole org. Local mode writes to the file-backed `AuthStorage`.
12
12
  *
13
13
  * Tokens never leave the server; responses only carry flow metadata (URLs,
14
14
  * user codes, poll delays).
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/routes/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgBH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAIpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AAIjF,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAuMpD,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IACxD,kEAAkE;IAClE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,uBAAuB,CAAC;IAC3C,kFAAkF;IAClF,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAC7E;AAED;;;;;;;GAOG;AACH,qBAAa,WAAY,SAAQ,KAAK,CAAC,eAAe,CAAC;IACrD,MAAM,IAAI,QAAQ,EAAE;CAuNrB"}
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/routes/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgBH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAIpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AAIjF,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA0MpD,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IACxD,kEAAkE;IAClE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,uBAAuB,CAAC;IAC3C,kFAAkF;IAClF,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CAC7E;AAED;;;;;;;GAOG;AACH,qBAAa,WAAY,SAAQ,KAAK,CAAC,eAAe,CAAC;IACrD,MAAM,IAAI,QAAQ,EAAE;CA+PrB"}
@@ -17,9 +17,9 @@ import { pollXAIDeviceLogin, startXAIDeviceLogin } from "@mastra/code-sdk/auth/p
17
17
  * HTTP routes. Flow state lives in login sessions — the `model-credentials`
18
18
  * domain's `oauth_login_sessions` table in tenant mode (any replica can
19
19
  * complete/poll), an in-memory store in local mode — so a flow can span
20
- * requests. Completed credentials are always **user-scoped** (plan tokens are
21
- * personal subscriptions) in tenant mode, or written to the file-backed
22
- * `AuthStorage` in local mode.
20
+ * requests. Completed credentials are **user-scoped by default**; org admins
21
+ * can start a flow with `{ scope: 'org' }` to share the credential with the
22
+ * whole org. Local mode writes to the file-backed `AuthStorage`.
23
23
  *
24
24
  * Tokens never leave the server; responses only carry flow metadata (URLs,
25
25
  * user codes, poll delays).
@@ -180,21 +180,19 @@ async function loadOwnedSession({ ctx, provider, sessionId }) {
180
180
  if (session.provider !== provider) return void 0;
181
181
  return session;
182
182
  }
183
- /** Persist completed OAuth credentials — always user-scoped in tenant mode. */
184
- async function persistOAuthCredential({ ctx, provider, credentials, authStorage, onCredentialsChanged }) {
183
+ /** Persist completed OAuth credentials — user-scoped unless the flow was started org-wide. */
184
+ async function persistOAuthCredential({ ctx, provider, scope, credentials, authStorage, onCredentialsChanged }) {
185
185
  const authProviderId = getAuthProviderId(provider);
186
186
  if (ctx.mode === "tenant") {
187
- await ctx.storage.setCredential({
187
+ const tenant = {
188
188
  orgId: ctx.orgId,
189
- userId: ctx.userId
190
- }, authProviderId, {
189
+ ...scope === "org" ? {} : { userId: ctx.userId }
190
+ };
191
+ await ctx.storage.setCredential(tenant, authProviderId, {
191
192
  type: "oauth",
192
193
  ...credentials
193
194
  });
194
- onCredentialsChanged({
195
- orgId: ctx.orgId,
196
- userId: ctx.userId
197
- });
195
+ onCredentialsChanged(tenant);
198
196
  return;
199
197
  }
200
198
  if (!authStorage) throw new Error("Credential storage is not available");
@@ -245,6 +243,11 @@ var OAuthRoutes = class extends Route {
245
243
  error: "invalid_mode",
246
244
  message: `Unsupported mode for ${provider}: ${body.mode}`
247
245
  }, 400);
246
+ const scope = body.scope === "org" ? "org" : "user";
247
+ if (scope === "org" && ctx.mode === "tenant" && !await auth.isOrganizationAdmin(loose(c), ctx.orgId)) return c.json({
248
+ error: "forbidden",
249
+ message: "Only org admins can sign in for the whole org"
250
+ }, 403);
248
251
  let started;
249
252
  try {
250
253
  started = await flow.start();
@@ -259,6 +262,7 @@ var OAuthRoutes = class extends Route {
259
262
  userId: tenant.userId,
260
263
  provider,
261
264
  kind: flow.kind,
265
+ ...scope === "org" && ctx.mode === "tenant" ? { credentialScope: scope } : {},
262
266
  pending: started.pending,
263
267
  expiresAt: new Date(started.expiresAt),
264
268
  nextPollAt: started.nextPollMs != null ? new Date(Date.now() + started.nextPollMs) : null
@@ -298,6 +302,10 @@ var OAuthRoutes = class extends Route {
298
302
  });
299
303
  if (!session) return c.json({ error: "session_not_found" }, 404);
300
304
  if (session.kind !== "paste-code") return c.json({ error: "wrong_session_kind" }, 400);
305
+ if (session.credentialScope === "org" && ctx.mode === "tenant" && !await auth.isOrganizationAdmin(loose(c), ctx.orgId)) return c.json({
306
+ error: "forbidden",
307
+ message: "Only org admins can sign in for the whole org"
308
+ }, 403);
301
309
  const claimed = await (await sessionStore(ctx)).claimLoginSession(sessionId, {
302
310
  orgId: session.orgId,
303
311
  userId: session.userId,
@@ -315,6 +323,7 @@ var OAuthRoutes = class extends Route {
315
323
  await persistOAuthCredential({
316
324
  ctx,
317
325
  provider,
326
+ scope: session.credentialScope,
318
327
  credentials,
319
328
  authStorage,
320
329
  onCredentialsChanged
@@ -349,6 +358,10 @@ var OAuthRoutes = class extends Route {
349
358
  });
350
359
  if (!session) return c.json({ error: "session_not_found" }, 404);
351
360
  if (session.kind !== "device-code") return c.json({ error: "wrong_session_kind" }, 400);
361
+ if (session.credentialScope === "org" && ctx.mode === "tenant" && !await auth.isOrganizationAdmin(loose(c), ctx.orgId)) return c.json({
362
+ error: "forbidden",
363
+ message: "Only org admins can sign in for the whole org"
364
+ }, 403);
352
365
  const now = Date.now();
353
366
  const nextPollAt = session.nextPollAt?.getTime();
354
367
  if (nextPollAt != null && now < nextPollAt) return c.json({
@@ -376,6 +389,7 @@ var OAuthRoutes = class extends Route {
376
389
  await persistOAuthCredential({
377
390
  ctx,
378
391
  provider,
392
+ scope: session.credentialScope,
379
393
  credentials: result.credentials,
380
394
  authStorage,
381
395
  onCredentialsChanged
@@ -434,16 +448,19 @@ var OAuthRoutes = class extends Route {
434
448
  });
435
449
  if ("response" in ctx) return ctx.response;
436
450
  const authProviderId = getAuthProviderId(c.req.param("provider"));
451
+ const scope = c.req.query("scope") === "org" ? "org" : "user";
437
452
  try {
438
453
  if (ctx.mode === "tenant") {
439
- await ctx.storage.removeCredential({
440
- orgId: ctx.orgId,
441
- userId: ctx.userId
442
- }, authProviderId);
443
- onCredentialsChanged({
454
+ if (scope === "org" && !await auth.isOrganizationAdmin(loose(c), ctx.orgId)) return c.json({
455
+ error: "forbidden",
456
+ message: "Only org admins can remove an org-wide sign-in"
457
+ }, 403);
458
+ const tenant = {
444
459
  orgId: ctx.orgId,
445
- userId: ctx.userId
446
- });
460
+ ...scope === "org" ? {} : { userId: ctx.userId }
461
+ };
462
+ await ctx.storage.removeCredential(tenant, authProviderId);
463
+ onCredentialsChanged(tenant);
447
464
  } else {
448
465
  if (!authStorage) return c.json({ error: "Credential storage is not available" }, 503);
449
466
  authStorage.remove(authProviderId);