@open-mercato/ai-assistant 0.6.1-develop.3291.1.6fad645fd0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +30 -4
- package/dist/frontend/components/AiChatButton.js +3 -2
- package/dist/frontend/components/AiChatButton.js.map +2 -2
- package/dist/modules/ai_assistant/__integration__/TC-AI-AGENT-LOOP-001-006.spec.js +364 -0
- package/dist/modules/ai_assistant/__integration__/TC-AI-AGENT-LOOP-001-006.spec.js.map +7 -0
- package/dist/modules/ai_assistant/__integration__/TC-AI-RUNTIME-OVERRIDES-006-model-picker.spec.js +7 -7
- package/dist/modules/ai_assistant/__integration__/TC-AI-RUNTIME-OVERRIDES-006-model-picker.spec.js.map +2 -2
- package/dist/modules/ai_assistant/__integration__/TC-AI-TOKEN-USAGE-001-005.spec.js +182 -0
- package/dist/modules/ai_assistant/__integration__/TC-AI-TOKEN-USAGE-001-005.spec.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/loop-override/route.js +316 -0
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/loop-override/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/models/route.js +8 -7
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/models/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/chat/route.js +43 -20
- package/dist/modules/ai_assistant/api/ai/chat/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/settings/route.js +4 -3
- package/dist/modules/ai_assistant/api/settings/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/usage/daily/route.js +111 -0
- package/dist/modules/ai_assistant/api/usage/daily/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/usage/sessions/[sessionId]/route.js +108 -0
- package/dist/modules/ai_assistant/api/usage/sessions/[sessionId]/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/usage/sessions/route.js +153 -0
- package/dist/modules/ai_assistant/api/usage/sessions/route.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.js +335 -38
- package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.js.map +2 -2
- package/dist/modules/ai_assistant/backend/config/ai-assistant/allowlist/AiTenantAllowlistPageClient.js +2 -7
- package/dist/modules/ai_assistant/backend/config/ai-assistant/allowlist/AiTenantAllowlistPageClient.js.map +2 -2
- package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.js +44 -35
- package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.js.map +2 -2
- package/dist/modules/ai_assistant/backend/config/ai-assistant/usage/AiUsageStatsPageClient.js +282 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/usage/AiUsageStatsPageClient.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/usage/page.js +10 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/usage/page.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/usage/page.meta.js +25 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/usage/page.meta.js.map +7 -0
- package/dist/modules/ai_assistant/cli.js +12 -0
- package/dist/modules/ai_assistant/cli.js.map +2 -2
- package/dist/modules/ai_assistant/components/AiAssistantSettingsPageClient.js.map +1 -1
- package/dist/modules/ai_assistant/data/entities.js +177 -1
- package/dist/modules/ai_assistant/data/entities.js.map +2 -2
- package/dist/modules/ai_assistant/data/repositories/AiAgentRuntimeOverrideRepository.js +104 -2
- package/dist/modules/ai_assistant/data/repositories/AiAgentRuntimeOverrideRepository.js.map +2 -2
- package/dist/modules/ai_assistant/data/repositories/AiTokenUsageRepository.js +168 -0
- package/dist/modules/ai_assistant/data/repositories/AiTokenUsageRepository.js.map +7 -0
- package/dist/modules/ai_assistant/events.js +8 -0
- package/dist/modules/ai_assistant/events.js.map +2 -2
- package/dist/modules/ai_assistant/i18n/de.json +74 -1
- package/dist/modules/ai_assistant/i18n/en.json +74 -1
- package/dist/modules/ai_assistant/i18n/es.json +75 -2
- package/dist/modules/ai_assistant/i18n/pl.json +74 -1
- package/dist/modules/ai_assistant/lib/agent-policy.js.map +2 -2
- package/dist/modules/ai_assistant/lib/agent-runtime.js +588 -23
- package/dist/modules/ai_assistant/lib/agent-runtime.js.map +3 -3
- package/dist/modules/ai_assistant/lib/agent-tools.js +6 -1
- package/dist/modules/ai_assistant/lib/agent-tools.js.map +2 -2
- package/dist/modules/ai_assistant/lib/ai-agent-definition.js.map +2 -2
- package/dist/modules/ai_assistant/lib/model-factory.js +63 -22
- package/dist/modules/ai_assistant/lib/model-factory.js.map +2 -2
- package/dist/modules/ai_assistant/lib/token-usage-recorder.js +78 -0
- package/dist/modules/ai_assistant/lib/token-usage-recorder.js.map +7 -0
- package/dist/modules/ai_assistant/lib/usage-serialization.js +33 -0
- package/dist/modules/ai_assistant/lib/usage-serialization.js.map +7 -0
- package/dist/modules/ai_assistant/migrations/Migration20260508160000_ai_agent_loop_overrides.js +25 -0
- package/dist/modules/ai_assistant/migrations/Migration20260508160000_ai_agent_loop_overrides.js.map +7 -0
- package/dist/modules/ai_assistant/migrations/Migration20260508170000_ai_token_usage.js +88 -0
- package/dist/modules/ai_assistant/migrations/Migration20260508170000_ai_token_usage.js.map +7 -0
- package/dist/modules/ai_assistant/setup.js +34 -0
- package/dist/modules/ai_assistant/setup.js.map +2 -2
- package/dist/modules/ai_assistant/workers/ai-token-usage-prune.js +114 -0
- package/dist/modules/ai_assistant/workers/ai-token-usage-prune.js.map +7 -0
- package/generated/entities/ai_agent_runtime_override/index.ts +7 -0
- package/generated/entities/ai_token_usage_daily/index.ts +16 -0
- package/generated/entities/ai_token_usage_event/index.ts +19 -0
- package/generated/entities.ids.generated.ts +2 -0
- package/generated/entity-fields-registry.ts +47 -1
- package/package.json +15 -7
- package/src/frontend/components/AiChatButton.tsx +3 -2
- package/src/modules/ai_assistant/__integration__/TC-AI-AGENT-LOOP-001-006.spec.ts +521 -0
- package/src/modules/ai_assistant/__integration__/TC-AI-RUNTIME-OVERRIDES-006-model-picker.spec.ts +8 -8
- package/src/modules/ai_assistant/__integration__/TC-AI-TOKEN-USAGE-001-005.spec.ts +231 -0
- package/src/modules/ai_assistant/__tests__/events.test.ts +4 -3
- package/src/modules/ai_assistant/__tests__/settings-page-logic.test.ts +5 -5
- package/src/modules/ai_assistant/__tests__/token-usage-recorder.test.ts +109 -0
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/loop-override/route.ts +388 -0
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/models/__tests__/route.test.ts +5 -0
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/models/route.ts +8 -7
- package/src/modules/ai_assistant/api/ai/chat/__tests__/route.test.ts +102 -5
- package/src/modules/ai_assistant/api/ai/chat/route.ts +55 -18
- package/src/modules/ai_assistant/api/settings/route.ts +5 -3
- package/src/modules/ai_assistant/api/usage/daily/__tests__/route.test.ts +159 -0
- package/src/modules/ai_assistant/api/usage/daily/route.ts +126 -0
- package/src/modules/ai_assistant/api/usage/sessions/[sessionId]/__tests__/route.test.ts +143 -0
- package/src/modules/ai_assistant/api/usage/sessions/[sessionId]/route.ts +130 -0
- package/src/modules/ai_assistant/api/usage/sessions/__tests__/route.test.ts +123 -0
- package/src/modules/ai_assistant/api/usage/sessions/route.ts +184 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.tsx +372 -16
- package/src/modules/ai_assistant/backend/config/ai-assistant/allowlist/AiTenantAllowlistPageClient.tsx +1 -4
- package/src/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.tsx +26 -9
- package/src/modules/ai_assistant/backend/config/ai-assistant/usage/AiUsageStatsPageClient.tsx +469 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/usage/page.meta.ts +23 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/usage/page.tsx +12 -0
- package/src/modules/ai_assistant/cli.ts +18 -0
- package/src/modules/ai_assistant/components/AiAssistantSettingsPageClient.tsx +1 -1
- package/src/modules/ai_assistant/data/entities.ts +237 -0
- package/src/modules/ai_assistant/data/repositories/AiAgentRuntimeOverrideRepository.ts +135 -3
- package/src/modules/ai_assistant/data/repositories/AiTokenUsageRepository.ts +213 -0
- package/src/modules/ai_assistant/data/repositories/__tests__/AiAgentRuntimeOverrideRepository.test.ts +223 -0
- package/src/modules/ai_assistant/data/repositories/__tests__/AiTokenUsageRepository.test.ts +58 -0
- package/src/modules/ai_assistant/events.ts +8 -0
- package/src/modules/ai_assistant/i18n/de.json +74 -1
- package/src/modules/ai_assistant/i18n/en.json +74 -1
- package/src/modules/ai_assistant/i18n/es.json +75 -2
- package/src/modules/ai_assistant/i18n/pl.json +74 -1
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime-loop-phase0.test.ts +439 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime-loop-phase1.test.ts +243 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime-loop-phase2.test.ts +388 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime-loop-phase3.test.ts +359 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime-phase4a.test.ts +2 -2
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime.test.ts +2 -1
- package/src/modules/ai_assistant/lib/__tests__/max-steps-budget.integration.test.ts +12 -13
- package/src/modules/ai_assistant/lib/__tests__/model-factory.test.ts +77 -14
- package/src/modules/ai_assistant/lib/agent-policy.ts +9 -0
- package/src/modules/ai_assistant/lib/agent-runtime.ts +1148 -43
- package/src/modules/ai_assistant/lib/agent-tools.ts +5 -1
- package/src/modules/ai_assistant/lib/ai-agent-definition.ts +289 -2
- package/src/modules/ai_assistant/lib/model-factory.ts +128 -43
- package/src/modules/ai_assistant/lib/token-usage-recorder.ts +122 -0
- package/src/modules/ai_assistant/lib/usage-serialization.ts +29 -0
- package/src/modules/ai_assistant/migrations/.snapshot-open-mercato.json +791 -0
- package/src/modules/ai_assistant/migrations/Migration20260508160000_ai_agent_loop_overrides.ts +25 -0
- package/src/modules/ai_assistant/migrations/Migration20260508170000_ai_token_usage.ts +89 -0
- package/src/modules/ai_assistant/setup.ts +49 -0
- package/src/modules/ai_assistant/workers/__tests__/ai-token-usage-prune.test.ts +144 -0
- package/src/modules/ai_assistant/workers/ai-token-usage-prune.ts +188 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/ai_assistant/components/AiAssistantSettingsPageClient.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { Bot, Loader2, CheckCircle2, XCircle, ChevronDown, ChevronRight, Server, Wrench, Eye, EyeOff, Database, Link2, Settings, Key, X } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { AI_ASSISTANT_LAUNCHER_OPEN_EVENT } from '@open-mercato/ui/ai/AiAssistantLauncher'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useAiAssistantVisibility } from '../../../frontend/hooks/useAiAssistantVisibility'\nimport McpConfigDialog from './McpConfigDialog'\nimport SessionKeyDialog from './SessionKeyDialog'\n\ntype OpenCodeHealthResponse = {\n status: 'ok' | 'error'\n opencode?: {\n healthy: boolean\n version: string\n }\n mcp?: Record<string, { status: string; error?: string }>\n search?: {\n available: boolean\n driver: string | null\n url: string | null\n }\n url: string\n mcpUrl: string\n message?: string\n}\n\ntype ProviderConfig = {\n id: string\n name: string\n model: string\n defaultModel: string\n envKey: string | null\n configured: boolean\n defaultModels: Array<{ id: string; name: string }>\n}\n\ntype TenantOverride = {\n providerId: string | null\n modelId: string | null\n baseURL: string | null\n agentId: string | null\n updatedAt: string\n}\n\ntype SettingsResponse = {\n provider: ProviderConfig\n availableProviders: ProviderConfig[]\n mcpKeyConfigured: boolean\n resolvedDefault: {\n providerId: string\n modelId: string\n baseURL: string | null\n source: string\n } | null\n tenantOverride: TenantOverride | null\n agents: AgentResolution[]\n}\n\ntype AgentResolution = {\n agentId: string\n moduleId: string\n allowRuntimeModelOverride: boolean\n providerId: string\n modelId: string\n baseURL: string | null\n source: string\n}\n\ntype ToolInfo = {\n name: string\n description: string\n module: string\n inputSchema: Record<string, unknown>\n}\n\ntype AiAssistantSettingsPageClientProps = {\n launchMode?: 'selector' | 'legacy'\n showVisibilityControl?: boolean\n}\n\nconst LEGACY_AI_ASSISTANT_OPEN_EVENT = 'om:open-ai-chat'\n\nasync function fetchHealth(): Promise<OpenCodeHealthResponse> {\n const result = await apiCall<OpenCodeHealthResponse>('/api/ai_assistant/health')\n if (!result.ok || !result.result) throw new Error('Failed to fetch health')\n return result.result\n}\n\nasync function fetchSettings(): Promise<SettingsResponse> {\n const result = await apiCall<SettingsResponse>('/api/ai_assistant/settings')\n if (!result.ok || !result.result) throw new Error('Failed to fetch settings')\n return result.result\n}\n\nasync function fetchTools(): Promise<{ tools: ToolInfo[] }> {\n const result = await apiCall<{ tools: ToolInfo[] }>('/api/ai_assistant/tools')\n if (!result.ok || !result.result) throw new Error('Failed to fetch tools')\n return result.result\n}\n\nfunction GlobalOverrideForm({\n availableProviders,\n tenantOverride,\n onSaved,\n}: {\n availableProviders: ProviderConfig[]\n tenantOverride: TenantOverride | null\n onSaved: () => void\n}) {\n const t = useT()\n const [selectedProviderId, setSelectedProviderId] = React.useState<string>(\n tenantOverride?.providerId ?? '',\n )\n const [selectedModelId, setSelectedModelId] = React.useState<string>(\n tenantOverride?.modelId ?? '',\n )\n\n const selectedProvider = availableProviders.find((p) => p.id === selectedProviderId)\n\n const { runMutation: runSaveMutation } = useGuardedMutation({ contextId: 'ai-settings-save-override' })\n const { runMutation: runClearMutation } = useGuardedMutation({ contextId: 'ai-settings-clear-override' })\n const [isSaving, setIsSaving] = React.useState(false)\n const [isClearing, setIsClearing] = React.useState(false)\n\n const handleSave = React.useCallback(async () => {\n setIsSaving(true)\n try {\n await runSaveMutation({\n operation: async () => {\n const result = await apiCall('/api/ai_assistant/settings', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n providerId: selectedProviderId || null,\n modelId: selectedModelId || null,\n }),\n })\n if (!result.ok) {\n const err = (result.result as { error?: string } | null)?.error\n throw new Error(err ?? t('ai_assistant.settings.saveError', 'Failed to save override.'))\n }\n },\n context: {},\n })\n flash(t('ai_assistant.settings.saveSuccess', 'Default model override saved.'), 'success')\n onSaved()\n } finally {\n setIsSaving(false)\n }\n }, [onSaved, runSaveMutation, selectedModelId, selectedProviderId, t])\n\n const handleClear = React.useCallback(async () => {\n setIsClearing(true)\n try {\n await runClearMutation({\n operation: async () => {\n const result = await apiCall('/api/ai_assistant/settings', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({}),\n })\n if (!result.ok) {\n const err = (result.result as { error?: string } | null)?.error\n throw new Error(err ?? t('ai_assistant.settings.clearError', 'Failed to clear override.'))\n }\n },\n context: {},\n })\n flash(t('ai_assistant.settings.clearSuccess', 'Default model override cleared.'), 'success')\n setSelectedProviderId('')\n setSelectedModelId('')\n onSaved()\n } finally {\n setIsClearing(false)\n }\n }, [runClearMutation, onSaved, t])\n\n const isBusy = isSaving || isClearing\n\n const configuredProviders = availableProviders.filter((p) => p.configured)\n\n return (\n <div className=\"rounded-lg border bg-card p-6\" data-ai-settings-override-form=\"\">\n <h2 className=\"mb-1 text-sm font-semibold\">\n {t('ai_assistant.settings.defaultOverrideTitle', 'Default model override')}\n </h2>\n <p className=\"mb-4 text-xs text-muted-foreground\">\n {t(\n 'ai_assistant.settings.defaultOverrideDescription',\n 'Set a tenant-wide default provider and model. Agents with a per-agent override or specific defaultModel will take precedence.',\n )}\n </p>\n {tenantOverride && (tenantOverride.providerId || tenantOverride.modelId) ? (\n <div className=\"mb-4 flex items-center gap-2 rounded-md border border-border bg-muted/30 px-3 py-2 text-xs\">\n <span className=\"text-muted-foreground\">\n {t('ai_assistant.settings.currentOverride', 'Current override:')}\n </span>\n <span className=\"font-medium\">\n {tenantOverride.providerId ?? '\u2014'} / {tenantOverride.modelId ?? '\u2014'}\n </span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto h-6 gap-1 text-xs\"\n disabled={isBusy}\n onClick={handleClear}\n data-ai-settings-clear-override=\"\"\n >\n <X className=\"size-3\" aria-hidden />\n {t('ai_assistant.settings.clearOverride', 'Clear override')}\n </Button>\n </div>\n ) : null}\n <div className=\"flex flex-wrap items-end gap-3\">\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n {t('ai_assistant.settings.providerLabel', 'Provider')}\n </span>\n <Select\n value={selectedProviderId}\n onValueChange={(val) => {\n setSelectedProviderId(val)\n setSelectedModelId('')\n }}\n disabled={isBusy}\n >\n <SelectTrigger\n className=\"w-[180px]\"\n data-ai-settings-provider-select=\"\"\n >\n <SelectValue placeholder={t('ai_assistant.settings.selectProvider', 'Select provider')} />\n </SelectTrigger>\n <SelectContent>\n {configuredProviders.map((provider) => (\n <SelectItem key={provider.id} value={provider.id}>\n {provider.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n {t('ai_assistant.settings.modelLabel', 'Model')}\n </span>\n <Select\n value={selectedModelId}\n onValueChange={setSelectedModelId}\n disabled={isBusy || !selectedProviderId}\n >\n <SelectTrigger\n className=\"w-[220px]\"\n data-ai-settings-model-select=\"\"\n >\n <SelectValue placeholder={t('ai_assistant.settings.selectModel', 'Select model')} />\n </SelectTrigger>\n <SelectContent>\n {(selectedProvider?.defaultModels ?? []).map((model) => (\n <SelectItem key={model.id} value={model.id}>\n {model.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={isBusy || !selectedProviderId || !selectedModelId}\n onClick={handleSave}\n data-ai-settings-save-override=\"\"\n >\n {isSaving ? (\n <Loader2 className=\"size-3.5 animate-spin\" aria-hidden />\n ) : null}\n {t('ai_assistant.settings.saveOverride', 'Save override')}\n </Button>\n </div>\n </div>\n )\n}\n\nfunction PerAgentOverrideList({\n agents,\n onCleared,\n}: {\n agents: AgentResolution[]\n onCleared: () => void\n}) {\n const t = useT()\n const { runMutation: runClearAgentMutation } = useGuardedMutation({ contextId: 'ai-settings-clear-agent-override' })\n const [clearingAgentId, setClearingAgentId] = React.useState<string | null>(null)\n\n const handleClearAgentOverride = React.useCallback(\n async (agentId: string) => {\n setClearingAgentId(agentId)\n try {\n await runClearAgentMutation({\n operation: async () => {\n const result = await apiCall('/api/ai_assistant/settings', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ agentId }),\n })\n if (!result.ok) {\n const err = (result.result as { error?: string } | null)?.error\n throw new Error(err ?? t('ai_assistant.settings.clearAgentError', 'Failed to clear agent override.'))\n }\n },\n context: {},\n })\n flash(t('ai_assistant.settings.clearAgentSuccess', 'Agent override cleared.'), 'success')\n onCleared()\n } finally {\n setClearingAgentId(null)\n }\n },\n [runClearAgentMutation, onCleared, t],\n )\n\n if (agents.length === 0) return null\n\n const overriddenAgents = agents.filter((agent) => agent.source !== 'env_default' && agent.source !== 'provider_default')\n\n return (\n <div className=\"rounded-lg border bg-card p-6\" data-ai-settings-agent-overrides=\"\">\n <h2 className=\"mb-1 text-sm font-semibold\">\n {t('ai_assistant.settings.agentOverridesTitle', 'Per-agent model resolution')}\n </h2>\n <p className=\"mb-4 text-xs text-muted-foreground\">\n {t(\n 'ai_assistant.settings.agentOverridesDescription',\n 'Resolved model for each registered agent. Agents with a custom override show a Clear button.',\n )}\n </p>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-xs\">\n <thead>\n <tr className=\"border-b border-border text-left text-muted-foreground\">\n <th className=\"pb-2 pr-4 font-medium\">\n {t('ai_assistant.settings.agentIdColumn', 'Agent')}\n </th>\n <th className=\"pb-2 pr-4 font-medium\">\n {t('ai_assistant.settings.providerColumn', 'Provider')}\n </th>\n <th className=\"pb-2 pr-4 font-medium\">\n {t('ai_assistant.settings.modelColumn', 'Model')}\n </th>\n <th className=\"pb-2 pr-4 font-medium\">\n {t('ai_assistant.settings.sourceColumn', 'Source')}\n </th>\n <th className=\"pb-2 font-medium\" />\n </tr>\n </thead>\n <tbody>\n {agents.map((agent) => {\n const hasOverride = overriddenAgents.some((a) => a.agentId === agent.agentId)\n return (\n <tr\n key={agent.agentId}\n className=\"border-b border-border/50 last:border-0\"\n data-ai-settings-agent-row={agent.agentId}\n >\n <td className=\"py-2 pr-4 font-mono\">{agent.agentId}</td>\n <td className=\"py-2 pr-4\">{agent.providerId}</td>\n <td className=\"py-2 pr-4\">{agent.modelId}</td>\n <td className=\"py-2 pr-4 text-muted-foreground\">{agent.source}</td>\n <td className=\"py-2\">\n {hasOverride ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-6 gap-1 text-xs\"\n disabled={clearingAgentId !== null}\n onClick={() => void handleClearAgentOverride(agent.agentId)}\n data-ai-settings-clear-agent-override={agent.agentId}\n >\n <X className=\"size-3\" aria-hidden />\n {t('ai_assistant.settings.clearOverride', 'Clear override')}\n </Button>\n ) : null}\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n </div>\n )\n}\n\nfunction AiAssistantLauncherCard({\n launchMode,\n showVisibilityControl,\n}: {\n launchMode: 'selector' | 'legacy'\n showVisibilityControl: boolean\n}) {\n const t = useT()\n const { isEnabled, toggleEnabled, isLoaded } = useAiAssistantVisibility()\n\n const openAiAssistant = () => {\n const eventName = launchMode === 'legacy'\n ? LEGACY_AI_ASSISTANT_OPEN_EVENT\n : AI_ASSISTANT_LAUNCHER_OPEN_EVENT\n window.dispatchEvent(new CustomEvent(eventName))\n }\n\n return (\n <div className=\"rounded-lg border bg-card p-6\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"flex items-center gap-2 text-lg font-semibold\">\n <Bot className=\"size-5\" />\n {t('ai_assistant.settings.visibilityTitle', 'AI Assistant')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {showVisibilityControl\n ? isEnabled\n ? t('ai_assistant.settings.visibilityEnabled', 'Visible in header with Cmd+J shortcut enabled.')\n : t('ai_assistant.settings.visibilityDisabled', 'Hidden from header. Enable to show the button and Cmd+J shortcut.')\n : t('ai_assistant.settings.launchDescription', 'Open the AI assistant from this page.')}\n </p>\n </div>\n <div className=\"flex items-center gap-4\">\n {showVisibilityControl ? (\n <div className=\"flex items-center gap-3 rounded-md border bg-muted/30 px-4 py-2\">\n <span className=\"text-sm font-medium\">\n {t('ai_assistant.settings.visibilityToggleLabel', 'Visibility')}\n </span>\n {isEnabled ? (\n <Eye className=\"size-4 text-muted-foreground\" />\n ) : (\n <EyeOff className=\"size-4 text-muted-foreground\" />\n )}\n <Switch\n checked={isEnabled}\n onCheckedChange={toggleEnabled}\n disabled={!isLoaded}\n />\n </div>\n ) : null}\n <Button type=\"button\" onClick={openAiAssistant} size=\"default\" className=\"gap-2\">\n <Bot className=\"size-4\" />\n {launchMode === 'legacy'\n ? t('ai_assistant.settings.openButton', 'Open AI Assistant')\n : t('ai_assistant.settings.openSelectorButton', 'Open AI assistants')}\n </Button>\n </div>\n </div>\n </div>\n )\n}\n\nfunction AiAssistantSettingsContent({\n launchMode,\n showVisibilityControl,\n}: {\n launchMode: 'selector' | 'legacy'\n showVisibilityControl: boolean\n}) {\n const t = useT()\n const queryClient = useQueryClient()\n const [toolsExpanded, setToolsExpanded] = React.useState(false)\n const [mcpConfigOpen, setMcpConfigOpen] = React.useState(false)\n const [sessionKeyOpen, setSessionKeyOpen] = React.useState(false)\n\n const healthQuery = useQuery({\n queryKey: ['ai-assistant', 'health'],\n queryFn: fetchHealth,\n refetchInterval: 10000,\n staleTime: 5000,\n })\n\n const settingsQuery = useQuery({\n queryKey: ['ai-assistant', 'settings'],\n queryFn: fetchSettings,\n staleTime: 60000,\n })\n\n const toolsQuery = useQuery({\n queryKey: ['ai-assistant', 'tools'],\n queryFn: fetchTools,\n staleTime: 60000,\n })\n\n const handleOverrideSaved = React.useCallback(() => {\n void queryClient.invalidateQueries({ queryKey: ['ai-assistant', 'settings'] })\n }, [queryClient])\n\n const isLoading = healthQuery.isLoading || settingsQuery.isLoading || toolsQuery.isLoading\n\n if (isLoading) {\n return (\n <div className=\"flex items-center gap-2 py-8 text-muted-foreground\">\n <Loader2 className=\"size-4 animate-spin\" />\n {t('ai_assistant.settings.loading', 'Loading settings...')}\n </div>\n )\n }\n\n const health = healthQuery.data\n const settings = settingsQuery.data\n const tools = toolsQuery.data?.tools ?? []\n\n const toolsByModule = tools.reduce<Record<string, ToolInfo[]>>((acc, tool) => {\n const module = tool.module || 'other'\n if (!acc[module]) acc[module] = []\n acc[module].push(tool)\n return acc\n }, {})\n\n const provider = settings?.provider\n\n return (\n <div className=\"flex flex-col gap-6\" data-ai-assistant-settings=\"\">\n <div className=\"space-y-1\">\n <h1 className=\"flex items-center gap-2 text-2xl font-bold\">\n <Bot className=\"size-6\" />\n {t('ai_assistant.settings.pageTitle', 'AI Assistant Settings')}\n </h1>\n <p className=\"text-muted-foreground\">\n {t('ai_assistant.settings.pageDescription', 'Configure and monitor the AI assistant')}\n </p>\n </div>\n\n <AiAssistantLauncherCard\n launchMode={launchMode}\n showVisibilityControl={showVisibilityControl}\n />\n\n {settings ? (\n <GlobalOverrideForm\n availableProviders={settings.availableProviders}\n tenantOverride={settings.tenantOverride}\n onSaved={handleOverrideSaved}\n />\n ) : null}\n\n {settings?.agents && settings.agents.length > 0 ? (\n <PerAgentOverrideList\n agents={settings.agents}\n onCleared={handleOverrideSaved}\n />\n ) : null}\n\n <div className=\"rounded-lg border bg-card p-6\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"flex items-center gap-2 text-sm font-semibold\">\n <Link2 className=\"size-4\" />\n {t('ai_assistant.settings.connectionsTitle', 'Connections')}\n </h2>\n {healthQuery.isFetching && !healthQuery.isLoading ? (\n <Loader2 className=\"size-3 animate-spin text-muted-foreground\" />\n ) : null}\n </div>\n <div className=\"grid gap-4 sm:grid-cols-3\">\n <div\n className={`rounded-lg border-2 p-4 ${\n health?.status === 'ok' && health.opencode?.healthy\n ? 'border-status-success-border bg-status-success-bg'\n : 'border-destructive/50 bg-destructive/5'\n }`}\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <Server className=\"size-4 shrink-0 text-muted-foreground\" />\n <p className=\"text-sm font-medium\">OpenCode</p>\n </div>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {health?.status === 'ok' && health.opencode?.healthy ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"size-3\" />\n {t('ai_assistant.settings.connected', 'Connected')}\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"size-3\" />\n {health?.message ?? t('ai_assistant.settings.disconnected', 'Disconnected')}\n </span>\n )}\n </p>\n {health?.opencode?.version ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">v{health.opencode.version}</p>\n ) : null}\n <p className=\"mt-1 truncate text-xs text-muted-foreground\">\n {health?.url ?? t('ai_assistant.settings.notConfigured', 'Not configured')}\n </p>\n </div>\n {health?.status === 'ok' && health.opencode?.healthy ? (\n <div className=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon\">\n <svg className=\"size-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n ) : null}\n </div>\n </div>\n\n {(() => {\n const mcpConnected =\n health?.mcp && Object.values(health.mcp).some((s) => s.status === 'connected')\n const mcpConnecting =\n health?.mcp && Object.values(health.mcp).some((s) => s.status === 'connecting')\n const mcpError =\n health?.mcp && Object.values(health.mcp).find((s) => s.error)?.error\n return (\n <div\n className={`rounded-lg border-2 p-4 ${\n mcpConnected\n ? 'border-status-success-border bg-status-success-bg'\n : mcpConnecting\n ? 'border-status-warning-border bg-status-warning-bg'\n : 'border-destructive/50 bg-destructive/5'\n }`}\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <Wrench className=\"size-4 shrink-0 text-muted-foreground\" />\n <p className=\"text-sm font-medium\">MCP Server</p>\n </div>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {mcpConnected ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"size-3\" />\n {t('ai_assistant.settings.connected', 'Connected')}\n </span>\n ) : mcpConnecting ? (\n <span className=\"flex items-center gap-1 text-status-warning-text\">\n <Loader2 className=\"size-3 animate-spin\" />\n {t('ai_assistant.settings.connecting', 'Connecting...')}\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"size-3\" />\n {mcpError ?? t('ai_assistant.settings.disconnected', 'Disconnected')}\n </span>\n )}\n </p>\n <p className=\"mt-1 truncate text-xs text-muted-foreground\">\n {health?.mcpUrl ?? t('ai_assistant.settings.notConfigured', 'Not configured')}\n </p>\n </div>\n {mcpConnected ? (\n <div className=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon\">\n <svg className=\"size-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n ) : null}\n </div>\n </div>\n )\n })()}\n\n <div\n className={`rounded-lg border-2 p-4 ${\n health?.search?.available\n ? 'border-status-success-border bg-status-success-bg'\n : 'border-destructive/50 bg-destructive/5'\n }`}\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <Database className=\"size-4 shrink-0 text-muted-foreground\" />\n <p className=\"text-sm font-medium\">Meilisearch</p>\n </div>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {health?.search?.available ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"size-3\" />\n {t('ai_assistant.settings.connected', 'Connected')}\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"size-3\" />\n {t('ai_assistant.settings.notAvailable', 'Not available')}\n </span>\n )}\n </p>\n <p className=\"mt-1 truncate text-xs text-muted-foreground\">\n {health?.search?.url ?? t('ai_assistant.settings.notConfigured', 'Not configured')}\n </p>\n </div>\n {health?.search?.available ? (\n <div className=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon\">\n <svg className=\"size-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n ) : null}\n </div>\n </div>\n </div>\n\n <div className=\"mt-4 rounded-md border bg-muted/30 p-3\">\n <div className=\"flex items-center gap-2 text-sm\">\n <Key className=\"size-4 text-muted-foreground\" />\n <span className=\"font-medium\">\n {t('ai_assistant.settings.mcpAuthLabel', 'MCP Authentication:')}\n </span>\n {settings?.mcpKeyConfigured ? (\n <span className=\"flex items-center gap-1 text-xs text-status-success-text\">\n <CheckCircle2 className=\"size-3\" />\n {t('ai_assistant.settings.mcpKeyConfigured', 'MCP_SERVER_API_KEY configured')}\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-xs text-status-warning-text\">\n <XCircle className=\"size-3\" />\n {t('ai_assistant.settings.mcpKeyMissing', 'MCP_SERVER_API_KEY not set')}\n </span>\n )}\n </div>\n <p className=\"ml-6 mt-1 text-xs text-muted-foreground\">\n {t(\n 'ai_assistant.settings.mcpAuthNote',\n 'Required for AI to access platform tools via MCP server.',\n )}\n </p>\n </div>\n\n <div className=\"mt-4 rounded-md border bg-muted/30 p-3\">\n <div className=\"flex items-center gap-2 text-sm\">\n <Server className=\"size-4 text-muted-foreground\" />\n <span className=\"font-medium\">\n {t('ai_assistant.settings.llmProviderLabel', 'LLM Provider:')}\n </span>\n <span className=\"font-medium\">{provider?.name ?? 'Anthropic'}</span>\n {provider?.configured ? (\n <span className=\"flex items-center gap-1 text-xs text-status-success-text\">\n <CheckCircle2 className=\"size-3\" />\n {provider?.envKey\n ? t('ai_assistant.settings.envKeyConfigured', '{{key}} configured', { key: provider.envKey })\n : t('ai_assistant.settings.configured', 'Configured')}\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-xs text-status-warning-text\">\n <XCircle className=\"size-3\" />\n {t('ai_assistant.settings.envKeyMissing', '{{key}} not set', { key: provider?.envKey ?? 'ANTHROPIC_API_KEY' })}\n </span>\n )}\n </div>\n </div>\n\n <p className=\"mt-4 text-xs text-muted-foreground\">\n {t(\n 'ai_assistant.settings.meilisearchNote',\n 'Meilisearch is required for API endpoint discovery. Endpoints are indexed automatically when the MCP server starts.',\n )}\n </p>\n </div>\n\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"mb-4 flex items-center gap-2 text-sm font-semibold\">\n <Settings className=\"size-4\" />\n {t('ai_assistant.settings.developerToolsTitle', 'Developer Tools')}\n </h2>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"rounded-lg border bg-muted/30 p-4\">\n <div className=\"flex items-start gap-3\">\n <div className=\"rounded-md bg-primary/10 p-2\">\n <Settings className=\"size-5 text-primary\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-sm font-medium\">\n {t('ai_assistant.settings.mcpConfigTitle', 'MCP Configuration')}\n </h3>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t(\n 'ai_assistant.settings.mcpConfigDescription',\n 'Generate config for Claude Code or other MCP clients.',\n )}\n </p>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"mt-3\"\n onClick={() => setMcpConfigOpen(true)}\n >\n {t('ai_assistant.settings.generateMcpConfig', 'Generate MCP Config')}\n </Button>\n </div>\n </div>\n </div>\n\n <div className=\"rounded-lg border bg-muted/30 p-4\">\n <div className=\"flex items-start gap-3\">\n <div className=\"rounded-md bg-primary/10 p-2\">\n <Key className=\"size-5 text-primary\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-sm font-medium\">\n {t('ai_assistant.settings.sessionKeyTitle', 'Session API Key')}\n </h3>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t(\n 'ai_assistant.settings.sessionKeyDescription',\n 'Generate a temporary token for programmatic LLM access. Expires after 2 hours.',\n )}\n </p>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"mt-3\"\n onClick={() => setSessionKeyOpen(true)}\n >\n {t('ai_assistant.settings.generateSessionKey', 'Generate Session Key')}\n </Button>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <McpConfigDialog\n open={mcpConfigOpen}\n onOpenChange={setMcpConfigOpen}\n mcpUrl={health?.mcpUrl ?? 'http://localhost:3001'}\n />\n <SessionKeyDialog\n open={sessionKeyOpen}\n onOpenChange={setSessionKeyOpen}\n />\n\n <div className=\"rounded-lg border bg-card p-6\">\n <button\n type=\"button\"\n onClick={() => setToolsExpanded((prev) => !prev)}\n className=\"flex w-full items-center justify-between text-left\"\n >\n <h2 className=\"flex items-center gap-2 text-sm font-semibold\">\n <Wrench className=\"size-4\" />\n {t('ai_assistant.settings.mcpToolsTitle', 'MCP Tools')} ({tools.length}{' '}\n {t('ai_assistant.settings.mcpToolsCount', 'tools')})\n </h2>\n {toolsExpanded ? (\n <ChevronDown className=\"size-4 text-muted-foreground\" />\n ) : (\n <ChevronRight className=\"size-4 text-muted-foreground\" />\n )}\n </button>\n\n {toolsExpanded ? (\n <div className=\"mt-4 space-y-4\">\n {Object.entries(toolsByModule).map(([module, moduleTools]) => (\n <div key={module} className=\"space-y-2\">\n <h3 className=\"text-xs font-medium uppercase tracking-wider text-muted-foreground\">\n {module}\n </h3>\n <div className=\"space-y-1\">\n {moduleTools.map((tool) => (\n <div key={tool.name} className=\"border-l-2 border-muted py-1 pl-2\">\n <p className=\"text-sm font-medium\">{tool.name}</p>\n <p className=\"text-xs text-muted-foreground\">{tool.description}</p>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n\nexport function AiAssistantSettingsPageClient({\n launchMode = 'selector',\n showVisibilityControl = false,\n}: AiAssistantSettingsPageClientProps) {\n return (\n <AiAssistantSettingsContent\n launchMode={launchMode}\n showVisibilityControl={showVisibilityControl}\n />\n )\n}\n\nexport default AiAssistantSettingsPageClient\n"],
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { Bot, Loader2, CheckCircle2, XCircle, ChevronDown, ChevronRight, Server, Wrench, Eye, EyeOff, Database, Link2, Settings, Key, X } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { AI_ASSISTANT_LAUNCHER_OPEN_EVENT } from '@open-mercato/ui/ai/AiAssistantLauncher'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useAiAssistantVisibility } from '../../../frontend/hooks/useAiAssistantVisibility'\nimport McpConfigDialog from './McpConfigDialog'\nimport SessionKeyDialog from './SessionKeyDialog'\n\ntype OpenCodeHealthResponse = {\n status: 'ok' | 'error'\n opencode?: {\n healthy: boolean\n version: string\n }\n mcp?: Record<string, { status: string; error?: string }>\n search?: {\n available: boolean\n driver: string | null\n url: string | null\n }\n url: string\n mcpUrl: string\n message?: string\n}\n\ntype ProviderConfig = {\n id: string\n name: string\n model: string\n defaultModel: string\n envKey: string | null\n configured: boolean\n defaultModels: Array<{ id: string; name: string }>\n}\n\ntype TenantOverride = {\n providerId: string | null\n modelId: string | null\n baseURL: string | null\n agentId: string | null\n updatedAt: string\n}\n\ntype SettingsResponse = {\n provider: ProviderConfig\n availableProviders: ProviderConfig[]\n mcpKeyConfigured: boolean\n resolvedDefault: {\n providerId: string\n modelId: string\n baseURL: string | null\n source: string\n } | null\n tenantOverride: TenantOverride | null\n agents: AgentResolution[]\n}\n\ntype AgentResolution = {\n agentId: string\n moduleId: string\n allowRuntimeOverride: boolean\n providerId: string\n modelId: string\n baseURL: string | null\n source: string\n}\n\ntype ToolInfo = {\n name: string\n description: string\n module: string\n inputSchema: Record<string, unknown>\n}\n\ntype AiAssistantSettingsPageClientProps = {\n launchMode?: 'selector' | 'legacy'\n showVisibilityControl?: boolean\n}\n\nconst LEGACY_AI_ASSISTANT_OPEN_EVENT = 'om:open-ai-chat'\n\nasync function fetchHealth(): Promise<OpenCodeHealthResponse> {\n const result = await apiCall<OpenCodeHealthResponse>('/api/ai_assistant/health')\n if (!result.ok || !result.result) throw new Error('Failed to fetch health')\n return result.result\n}\n\nasync function fetchSettings(): Promise<SettingsResponse> {\n const result = await apiCall<SettingsResponse>('/api/ai_assistant/settings')\n if (!result.ok || !result.result) throw new Error('Failed to fetch settings')\n return result.result\n}\n\nasync function fetchTools(): Promise<{ tools: ToolInfo[] }> {\n const result = await apiCall<{ tools: ToolInfo[] }>('/api/ai_assistant/tools')\n if (!result.ok || !result.result) throw new Error('Failed to fetch tools')\n return result.result\n}\n\nfunction GlobalOverrideForm({\n availableProviders,\n tenantOverride,\n onSaved,\n}: {\n availableProviders: ProviderConfig[]\n tenantOverride: TenantOverride | null\n onSaved: () => void\n}) {\n const t = useT()\n const [selectedProviderId, setSelectedProviderId] = React.useState<string>(\n tenantOverride?.providerId ?? '',\n )\n const [selectedModelId, setSelectedModelId] = React.useState<string>(\n tenantOverride?.modelId ?? '',\n )\n\n const selectedProvider = availableProviders.find((p) => p.id === selectedProviderId)\n\n const { runMutation: runSaveMutation } = useGuardedMutation({ contextId: 'ai-settings-save-override' })\n const { runMutation: runClearMutation } = useGuardedMutation({ contextId: 'ai-settings-clear-override' })\n const [isSaving, setIsSaving] = React.useState(false)\n const [isClearing, setIsClearing] = React.useState(false)\n\n const handleSave = React.useCallback(async () => {\n setIsSaving(true)\n try {\n await runSaveMutation({\n operation: async () => {\n const result = await apiCall('/api/ai_assistant/settings', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n providerId: selectedProviderId || null,\n modelId: selectedModelId || null,\n }),\n })\n if (!result.ok) {\n const err = (result.result as { error?: string } | null)?.error\n throw new Error(err ?? t('ai_assistant.settings.saveError', 'Failed to save override.'))\n }\n },\n context: {},\n })\n flash(t('ai_assistant.settings.saveSuccess', 'Default model override saved.'), 'success')\n onSaved()\n } finally {\n setIsSaving(false)\n }\n }, [onSaved, runSaveMutation, selectedModelId, selectedProviderId, t])\n\n const handleClear = React.useCallback(async () => {\n setIsClearing(true)\n try {\n await runClearMutation({\n operation: async () => {\n const result = await apiCall('/api/ai_assistant/settings', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({}),\n })\n if (!result.ok) {\n const err = (result.result as { error?: string } | null)?.error\n throw new Error(err ?? t('ai_assistant.settings.clearError', 'Failed to clear override.'))\n }\n },\n context: {},\n })\n flash(t('ai_assistant.settings.clearSuccess', 'Default model override cleared.'), 'success')\n setSelectedProviderId('')\n setSelectedModelId('')\n onSaved()\n } finally {\n setIsClearing(false)\n }\n }, [runClearMutation, onSaved, t])\n\n const isBusy = isSaving || isClearing\n\n const configuredProviders = availableProviders.filter((p) => p.configured)\n\n return (\n <div className=\"rounded-lg border bg-card p-6\" data-ai-settings-override-form=\"\">\n <h2 className=\"mb-1 text-sm font-semibold\">\n {t('ai_assistant.settings.defaultOverrideTitle', 'Default model override')}\n </h2>\n <p className=\"mb-4 text-xs text-muted-foreground\">\n {t(\n 'ai_assistant.settings.defaultOverrideDescription',\n 'Set a tenant-wide default provider and model. Agents with a per-agent override or specific defaultModel will take precedence.',\n )}\n </p>\n {tenantOverride && (tenantOverride.providerId || tenantOverride.modelId) ? (\n <div className=\"mb-4 flex items-center gap-2 rounded-md border border-border bg-muted/30 px-3 py-2 text-xs\">\n <span className=\"text-muted-foreground\">\n {t('ai_assistant.settings.currentOverride', 'Current override:')}\n </span>\n <span className=\"font-medium\">\n {tenantOverride.providerId ?? '\u2014'} / {tenantOverride.modelId ?? '\u2014'}\n </span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto h-6 gap-1 text-xs\"\n disabled={isBusy}\n onClick={handleClear}\n data-ai-settings-clear-override=\"\"\n >\n <X className=\"size-3\" aria-hidden />\n {t('ai_assistant.settings.clearOverride', 'Clear override')}\n </Button>\n </div>\n ) : null}\n <div className=\"flex flex-wrap items-end gap-3\">\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n {t('ai_assistant.settings.providerLabel', 'Provider')}\n </span>\n <Select\n value={selectedProviderId}\n onValueChange={(val) => {\n setSelectedProviderId(val)\n setSelectedModelId('')\n }}\n disabled={isBusy}\n >\n <SelectTrigger\n className=\"w-[180px]\"\n data-ai-settings-provider-select=\"\"\n >\n <SelectValue placeholder={t('ai_assistant.settings.selectProvider', 'Select provider')} />\n </SelectTrigger>\n <SelectContent>\n {configuredProviders.map((provider) => (\n <SelectItem key={provider.id} value={provider.id}>\n {provider.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n {t('ai_assistant.settings.modelLabel', 'Model')}\n </span>\n <Select\n value={selectedModelId}\n onValueChange={setSelectedModelId}\n disabled={isBusy || !selectedProviderId}\n >\n <SelectTrigger\n className=\"w-[220px]\"\n data-ai-settings-model-select=\"\"\n >\n <SelectValue placeholder={t('ai_assistant.settings.selectModel', 'Select model')} />\n </SelectTrigger>\n <SelectContent>\n {(selectedProvider?.defaultModels ?? []).map((model) => (\n <SelectItem key={model.id} value={model.id}>\n {model.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={isBusy || !selectedProviderId || !selectedModelId}\n onClick={handleSave}\n data-ai-settings-save-override=\"\"\n >\n {isSaving ? (\n <Loader2 className=\"size-3.5 animate-spin\" aria-hidden />\n ) : null}\n {t('ai_assistant.settings.saveOverride', 'Save override')}\n </Button>\n </div>\n </div>\n )\n}\n\nfunction PerAgentOverrideList({\n agents,\n onCleared,\n}: {\n agents: AgentResolution[]\n onCleared: () => void\n}) {\n const t = useT()\n const { runMutation: runClearAgentMutation } = useGuardedMutation({ contextId: 'ai-settings-clear-agent-override' })\n const [clearingAgentId, setClearingAgentId] = React.useState<string | null>(null)\n\n const handleClearAgentOverride = React.useCallback(\n async (agentId: string) => {\n setClearingAgentId(agentId)\n try {\n await runClearAgentMutation({\n operation: async () => {\n const result = await apiCall('/api/ai_assistant/settings', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ agentId }),\n })\n if (!result.ok) {\n const err = (result.result as { error?: string } | null)?.error\n throw new Error(err ?? t('ai_assistant.settings.clearAgentError', 'Failed to clear agent override.'))\n }\n },\n context: {},\n })\n flash(t('ai_assistant.settings.clearAgentSuccess', 'Agent override cleared.'), 'success')\n onCleared()\n } finally {\n setClearingAgentId(null)\n }\n },\n [runClearAgentMutation, onCleared, t],\n )\n\n if (agents.length === 0) return null\n\n const overriddenAgents = agents.filter((agent) => agent.source !== 'env_default' && agent.source !== 'provider_default')\n\n return (\n <div className=\"rounded-lg border bg-card p-6\" data-ai-settings-agent-overrides=\"\">\n <h2 className=\"mb-1 text-sm font-semibold\">\n {t('ai_assistant.settings.agentOverridesTitle', 'Per-agent model resolution')}\n </h2>\n <p className=\"mb-4 text-xs text-muted-foreground\">\n {t(\n 'ai_assistant.settings.agentOverridesDescription',\n 'Resolved model for each registered agent. Agents with a custom override show a Clear button.',\n )}\n </p>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-xs\">\n <thead>\n <tr className=\"border-b border-border text-left text-muted-foreground\">\n <th className=\"pb-2 pr-4 font-medium\">\n {t('ai_assistant.settings.agentIdColumn', 'Agent')}\n </th>\n <th className=\"pb-2 pr-4 font-medium\">\n {t('ai_assistant.settings.providerColumn', 'Provider')}\n </th>\n <th className=\"pb-2 pr-4 font-medium\">\n {t('ai_assistant.settings.modelColumn', 'Model')}\n </th>\n <th className=\"pb-2 pr-4 font-medium\">\n {t('ai_assistant.settings.sourceColumn', 'Source')}\n </th>\n <th className=\"pb-2 font-medium\" />\n </tr>\n </thead>\n <tbody>\n {agents.map((agent) => {\n const hasOverride = overriddenAgents.some((a) => a.agentId === agent.agentId)\n return (\n <tr\n key={agent.agentId}\n className=\"border-b border-border/50 last:border-0\"\n data-ai-settings-agent-row={agent.agentId}\n >\n <td className=\"py-2 pr-4 font-mono\">{agent.agentId}</td>\n <td className=\"py-2 pr-4\">{agent.providerId}</td>\n <td className=\"py-2 pr-4\">{agent.modelId}</td>\n <td className=\"py-2 pr-4 text-muted-foreground\">{agent.source}</td>\n <td className=\"py-2\">\n {hasOverride ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-6 gap-1 text-xs\"\n disabled={clearingAgentId !== null}\n onClick={() => void handleClearAgentOverride(agent.agentId)}\n data-ai-settings-clear-agent-override={agent.agentId}\n >\n <X className=\"size-3\" aria-hidden />\n {t('ai_assistant.settings.clearOverride', 'Clear override')}\n </Button>\n ) : null}\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n </div>\n )\n}\n\nfunction AiAssistantLauncherCard({\n launchMode,\n showVisibilityControl,\n}: {\n launchMode: 'selector' | 'legacy'\n showVisibilityControl: boolean\n}) {\n const t = useT()\n const { isEnabled, toggleEnabled, isLoaded } = useAiAssistantVisibility()\n\n const openAiAssistant = () => {\n const eventName = launchMode === 'legacy'\n ? LEGACY_AI_ASSISTANT_OPEN_EVENT\n : AI_ASSISTANT_LAUNCHER_OPEN_EVENT\n window.dispatchEvent(new CustomEvent(eventName))\n }\n\n return (\n <div className=\"rounded-lg border bg-card p-6\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"space-y-1\">\n <h2 className=\"flex items-center gap-2 text-lg font-semibold\">\n <Bot className=\"size-5\" />\n {t('ai_assistant.settings.visibilityTitle', 'AI Assistant')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {showVisibilityControl\n ? isEnabled\n ? t('ai_assistant.settings.visibilityEnabled', 'Visible in header with Cmd+J shortcut enabled.')\n : t('ai_assistant.settings.visibilityDisabled', 'Hidden from header. Enable to show the button and Cmd+J shortcut.')\n : t('ai_assistant.settings.launchDescription', 'Open the AI assistant from this page.')}\n </p>\n </div>\n <div className=\"flex items-center gap-4\">\n {showVisibilityControl ? (\n <div className=\"flex items-center gap-3 rounded-md border bg-muted/30 px-4 py-2\">\n <span className=\"text-sm font-medium\">\n {t('ai_assistant.settings.visibilityToggleLabel', 'Visibility')}\n </span>\n {isEnabled ? (\n <Eye className=\"size-4 text-muted-foreground\" />\n ) : (\n <EyeOff className=\"size-4 text-muted-foreground\" />\n )}\n <Switch\n checked={isEnabled}\n onCheckedChange={toggleEnabled}\n disabled={!isLoaded}\n />\n </div>\n ) : null}\n <Button type=\"button\" onClick={openAiAssistant} size=\"default\" className=\"gap-2\">\n <Bot className=\"size-4\" />\n {launchMode === 'legacy'\n ? t('ai_assistant.settings.openButton', 'Open AI Assistant')\n : t('ai_assistant.settings.openSelectorButton', 'Open AI assistants')}\n </Button>\n </div>\n </div>\n </div>\n )\n}\n\nfunction AiAssistantSettingsContent({\n launchMode,\n showVisibilityControl,\n}: {\n launchMode: 'selector' | 'legacy'\n showVisibilityControl: boolean\n}) {\n const t = useT()\n const queryClient = useQueryClient()\n const [toolsExpanded, setToolsExpanded] = React.useState(false)\n const [mcpConfigOpen, setMcpConfigOpen] = React.useState(false)\n const [sessionKeyOpen, setSessionKeyOpen] = React.useState(false)\n\n const healthQuery = useQuery({\n queryKey: ['ai-assistant', 'health'],\n queryFn: fetchHealth,\n refetchInterval: 10000,\n staleTime: 5000,\n })\n\n const settingsQuery = useQuery({\n queryKey: ['ai-assistant', 'settings'],\n queryFn: fetchSettings,\n staleTime: 60000,\n })\n\n const toolsQuery = useQuery({\n queryKey: ['ai-assistant', 'tools'],\n queryFn: fetchTools,\n staleTime: 60000,\n })\n\n const handleOverrideSaved = React.useCallback(() => {\n void queryClient.invalidateQueries({ queryKey: ['ai-assistant', 'settings'] })\n }, [queryClient])\n\n const isLoading = healthQuery.isLoading || settingsQuery.isLoading || toolsQuery.isLoading\n\n if (isLoading) {\n return (\n <div className=\"flex items-center gap-2 py-8 text-muted-foreground\">\n <Loader2 className=\"size-4 animate-spin\" />\n {t('ai_assistant.settings.loading', 'Loading settings...')}\n </div>\n )\n }\n\n const health = healthQuery.data\n const settings = settingsQuery.data\n const tools = toolsQuery.data?.tools ?? []\n\n const toolsByModule = tools.reduce<Record<string, ToolInfo[]>>((acc, tool) => {\n const module = tool.module || 'other'\n if (!acc[module]) acc[module] = []\n acc[module].push(tool)\n return acc\n }, {})\n\n const provider = settings?.provider\n\n return (\n <div className=\"flex flex-col gap-6\" data-ai-assistant-settings=\"\">\n <div className=\"space-y-1\">\n <h1 className=\"flex items-center gap-2 text-2xl font-bold\">\n <Bot className=\"size-6\" />\n {t('ai_assistant.settings.pageTitle', 'AI Assistant Settings')}\n </h1>\n <p className=\"text-muted-foreground\">\n {t('ai_assistant.settings.pageDescription', 'Configure and monitor the AI assistant')}\n </p>\n </div>\n\n <AiAssistantLauncherCard\n launchMode={launchMode}\n showVisibilityControl={showVisibilityControl}\n />\n\n {settings ? (\n <GlobalOverrideForm\n availableProviders={settings.availableProviders}\n tenantOverride={settings.tenantOverride}\n onSaved={handleOverrideSaved}\n />\n ) : null}\n\n {settings?.agents && settings.agents.length > 0 ? (\n <PerAgentOverrideList\n agents={settings.agents}\n onCleared={handleOverrideSaved}\n />\n ) : null}\n\n <div className=\"rounded-lg border bg-card p-6\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"flex items-center gap-2 text-sm font-semibold\">\n <Link2 className=\"size-4\" />\n {t('ai_assistant.settings.connectionsTitle', 'Connections')}\n </h2>\n {healthQuery.isFetching && !healthQuery.isLoading ? (\n <Loader2 className=\"size-3 animate-spin text-muted-foreground\" />\n ) : null}\n </div>\n <div className=\"grid gap-4 sm:grid-cols-3\">\n <div\n className={`rounded-lg border-2 p-4 ${\n health?.status === 'ok' && health.opencode?.healthy\n ? 'border-status-success-border bg-status-success-bg'\n : 'border-destructive/50 bg-destructive/5'\n }`}\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <Server className=\"size-4 shrink-0 text-muted-foreground\" />\n <p className=\"text-sm font-medium\">OpenCode</p>\n </div>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {health?.status === 'ok' && health.opencode?.healthy ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"size-3\" />\n {t('ai_assistant.settings.connected', 'Connected')}\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"size-3\" />\n {health?.message ?? t('ai_assistant.settings.disconnected', 'Disconnected')}\n </span>\n )}\n </p>\n {health?.opencode?.version ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">v{health.opencode.version}</p>\n ) : null}\n <p className=\"mt-1 truncate text-xs text-muted-foreground\">\n {health?.url ?? t('ai_assistant.settings.notConfigured', 'Not configured')}\n </p>\n </div>\n {health?.status === 'ok' && health.opencode?.healthy ? (\n <div className=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon\">\n <svg className=\"size-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n ) : null}\n </div>\n </div>\n\n {(() => {\n const mcpConnected =\n health?.mcp && Object.values(health.mcp).some((s) => s.status === 'connected')\n const mcpConnecting =\n health?.mcp && Object.values(health.mcp).some((s) => s.status === 'connecting')\n const mcpError =\n health?.mcp && Object.values(health.mcp).find((s) => s.error)?.error\n return (\n <div\n className={`rounded-lg border-2 p-4 ${\n mcpConnected\n ? 'border-status-success-border bg-status-success-bg'\n : mcpConnecting\n ? 'border-status-warning-border bg-status-warning-bg'\n : 'border-destructive/50 bg-destructive/5'\n }`}\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <Wrench className=\"size-4 shrink-0 text-muted-foreground\" />\n <p className=\"text-sm font-medium\">MCP Server</p>\n </div>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {mcpConnected ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"size-3\" />\n {t('ai_assistant.settings.connected', 'Connected')}\n </span>\n ) : mcpConnecting ? (\n <span className=\"flex items-center gap-1 text-status-warning-text\">\n <Loader2 className=\"size-3 animate-spin\" />\n {t('ai_assistant.settings.connecting', 'Connecting...')}\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"size-3\" />\n {mcpError ?? t('ai_assistant.settings.disconnected', 'Disconnected')}\n </span>\n )}\n </p>\n <p className=\"mt-1 truncate text-xs text-muted-foreground\">\n {health?.mcpUrl ?? t('ai_assistant.settings.notConfigured', 'Not configured')}\n </p>\n </div>\n {mcpConnected ? (\n <div className=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon\">\n <svg className=\"size-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n ) : null}\n </div>\n </div>\n )\n })()}\n\n <div\n className={`rounded-lg border-2 p-4 ${\n health?.search?.available\n ? 'border-status-success-border bg-status-success-bg'\n : 'border-destructive/50 bg-destructive/5'\n }`}\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <Database className=\"size-4 shrink-0 text-muted-foreground\" />\n <p className=\"text-sm font-medium\">Meilisearch</p>\n </div>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {health?.search?.available ? (\n <span className=\"flex items-center gap-1 text-status-success-text\">\n <CheckCircle2 className=\"size-3\" />\n {t('ai_assistant.settings.connected', 'Connected')}\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-destructive\">\n <XCircle className=\"size-3\" />\n {t('ai_assistant.settings.notAvailable', 'Not available')}\n </span>\n )}\n </p>\n <p className=\"mt-1 truncate text-xs text-muted-foreground\">\n {health?.search?.url ?? t('ai_assistant.settings.notConfigured', 'Not configured')}\n </p>\n </div>\n {health?.search?.available ? (\n <div className=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon\">\n <svg className=\"size-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n ) : null}\n </div>\n </div>\n </div>\n\n <div className=\"mt-4 rounded-md border bg-muted/30 p-3\">\n <div className=\"flex items-center gap-2 text-sm\">\n <Key className=\"size-4 text-muted-foreground\" />\n <span className=\"font-medium\">\n {t('ai_assistant.settings.mcpAuthLabel', 'MCP Authentication:')}\n </span>\n {settings?.mcpKeyConfigured ? (\n <span className=\"flex items-center gap-1 text-xs text-status-success-text\">\n <CheckCircle2 className=\"size-3\" />\n {t('ai_assistant.settings.mcpKeyConfigured', 'MCP_SERVER_API_KEY configured')}\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-xs text-status-warning-text\">\n <XCircle className=\"size-3\" />\n {t('ai_assistant.settings.mcpKeyMissing', 'MCP_SERVER_API_KEY not set')}\n </span>\n )}\n </div>\n <p className=\"ml-6 mt-1 text-xs text-muted-foreground\">\n {t(\n 'ai_assistant.settings.mcpAuthNote',\n 'Required for AI to access platform tools via MCP server.',\n )}\n </p>\n </div>\n\n <div className=\"mt-4 rounded-md border bg-muted/30 p-3\">\n <div className=\"flex items-center gap-2 text-sm\">\n <Server className=\"size-4 text-muted-foreground\" />\n <span className=\"font-medium\">\n {t('ai_assistant.settings.llmProviderLabel', 'LLM Provider:')}\n </span>\n <span className=\"font-medium\">{provider?.name ?? 'Anthropic'}</span>\n {provider?.configured ? (\n <span className=\"flex items-center gap-1 text-xs text-status-success-text\">\n <CheckCircle2 className=\"size-3\" />\n {provider?.envKey\n ? t('ai_assistant.settings.envKeyConfigured', '{{key}} configured', { key: provider.envKey })\n : t('ai_assistant.settings.configured', 'Configured')}\n </span>\n ) : (\n <span className=\"flex items-center gap-1 text-xs text-status-warning-text\">\n <XCircle className=\"size-3\" />\n {t('ai_assistant.settings.envKeyMissing', '{{key}} not set', { key: provider?.envKey ?? 'ANTHROPIC_API_KEY' })}\n </span>\n )}\n </div>\n </div>\n\n <p className=\"mt-4 text-xs text-muted-foreground\">\n {t(\n 'ai_assistant.settings.meilisearchNote',\n 'Meilisearch is required for API endpoint discovery. Endpoints are indexed automatically when the MCP server starts.',\n )}\n </p>\n </div>\n\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"mb-4 flex items-center gap-2 text-sm font-semibold\">\n <Settings className=\"size-4\" />\n {t('ai_assistant.settings.developerToolsTitle', 'Developer Tools')}\n </h2>\n <div className=\"grid gap-4 sm:grid-cols-2\">\n <div className=\"rounded-lg border bg-muted/30 p-4\">\n <div className=\"flex items-start gap-3\">\n <div className=\"rounded-md bg-primary/10 p-2\">\n <Settings className=\"size-5 text-primary\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-sm font-medium\">\n {t('ai_assistant.settings.mcpConfigTitle', 'MCP Configuration')}\n </h3>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t(\n 'ai_assistant.settings.mcpConfigDescription',\n 'Generate config for Claude Code or other MCP clients.',\n )}\n </p>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"mt-3\"\n onClick={() => setMcpConfigOpen(true)}\n >\n {t('ai_assistant.settings.generateMcpConfig', 'Generate MCP Config')}\n </Button>\n </div>\n </div>\n </div>\n\n <div className=\"rounded-lg border bg-muted/30 p-4\">\n <div className=\"flex items-start gap-3\">\n <div className=\"rounded-md bg-primary/10 p-2\">\n <Key className=\"size-5 text-primary\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-sm font-medium\">\n {t('ai_assistant.settings.sessionKeyTitle', 'Session API Key')}\n </h3>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t(\n 'ai_assistant.settings.sessionKeyDescription',\n 'Generate a temporary token for programmatic LLM access. Expires after 2 hours.',\n )}\n </p>\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"mt-3\"\n onClick={() => setSessionKeyOpen(true)}\n >\n {t('ai_assistant.settings.generateSessionKey', 'Generate Session Key')}\n </Button>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <McpConfigDialog\n open={mcpConfigOpen}\n onOpenChange={setMcpConfigOpen}\n mcpUrl={health?.mcpUrl ?? 'http://localhost:3001'}\n />\n <SessionKeyDialog\n open={sessionKeyOpen}\n onOpenChange={setSessionKeyOpen}\n />\n\n <div className=\"rounded-lg border bg-card p-6\">\n <button\n type=\"button\"\n onClick={() => setToolsExpanded((prev) => !prev)}\n className=\"flex w-full items-center justify-between text-left\"\n >\n <h2 className=\"flex items-center gap-2 text-sm font-semibold\">\n <Wrench className=\"size-4\" />\n {t('ai_assistant.settings.mcpToolsTitle', 'MCP Tools')} ({tools.length}{' '}\n {t('ai_assistant.settings.mcpToolsCount', 'tools')})\n </h2>\n {toolsExpanded ? (\n <ChevronDown className=\"size-4 text-muted-foreground\" />\n ) : (\n <ChevronRight className=\"size-4 text-muted-foreground\" />\n )}\n </button>\n\n {toolsExpanded ? (\n <div className=\"mt-4 space-y-4\">\n {Object.entries(toolsByModule).map(([module, moduleTools]) => (\n <div key={module} className=\"space-y-2\">\n <h3 className=\"text-xs font-medium uppercase tracking-wider text-muted-foreground\">\n {module}\n </h3>\n <div className=\"space-y-1\">\n {moduleTools.map((tool) => (\n <div key={tool.name} className=\"border-l-2 border-muted py-1 pl-2\">\n <p className=\"text-sm font-medium\">{tool.name}</p>\n <p className=\"text-xs text-muted-foreground\">{tool.description}</p>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n\nexport function AiAssistantSettingsPageClient({\n launchMode = 'selector',\n showVisibilityControl = false,\n}: AiAssistantSettingsPageClientProps) {\n return (\n <AiAssistantSettingsContent\n launchMode={launchMode}\n showVisibilityControl={showVisibilityControl}\n />\n )\n}\n\nexport default AiAssistantSettingsPageClient\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -218,6 +218,27 @@ __decorateClass([
|
|
|
218
218
|
__decorateClass([
|
|
219
219
|
Property({ name: "deleted_at", type: Date, nullable: true })
|
|
220
220
|
], AiAgentRuntimeOverride.prototype, "deletedAt", 2);
|
|
221
|
+
__decorateClass([
|
|
222
|
+
Property({ name: "loop_disabled", type: "boolean", nullable: true })
|
|
223
|
+
], AiAgentRuntimeOverride.prototype, "loopDisabled", 2);
|
|
224
|
+
__decorateClass([
|
|
225
|
+
Property({ name: "loop_max_steps", type: "int", nullable: true })
|
|
226
|
+
], AiAgentRuntimeOverride.prototype, "loopMaxSteps", 2);
|
|
227
|
+
__decorateClass([
|
|
228
|
+
Property({ name: "loop_max_tool_calls", type: "int", nullable: true })
|
|
229
|
+
], AiAgentRuntimeOverride.prototype, "loopMaxToolCalls", 2);
|
|
230
|
+
__decorateClass([
|
|
231
|
+
Property({ name: "loop_max_wall_clock_ms", type: "int", nullable: true })
|
|
232
|
+
], AiAgentRuntimeOverride.prototype, "loopMaxWallClockMs", 2);
|
|
233
|
+
__decorateClass([
|
|
234
|
+
Property({ name: "loop_max_tokens", type: "int", nullable: true })
|
|
235
|
+
], AiAgentRuntimeOverride.prototype, "loopMaxTokens", 2);
|
|
236
|
+
__decorateClass([
|
|
237
|
+
Property({ name: "loop_stop_when_json", type: "jsonb", nullable: true })
|
|
238
|
+
], AiAgentRuntimeOverride.prototype, "loopStopWhenJson", 2);
|
|
239
|
+
__decorateClass([
|
|
240
|
+
Property({ name: "loop_active_tools_json", type: "jsonb", nullable: true })
|
|
241
|
+
], AiAgentRuntimeOverride.prototype, "loopActiveToolsJson", 2);
|
|
221
242
|
AiAgentRuntimeOverride = __decorateClass([
|
|
222
243
|
Entity({ tableName: "ai_agent_runtime_overrides" }),
|
|
223
244
|
Index({
|
|
@@ -242,6 +263,159 @@ AiAgentRuntimeOverride = __decorateClass([
|
|
|
242
263
|
})
|
|
243
264
|
], AiAgentRuntimeOverride);
|
|
244
265
|
OptionalProps;
|
|
266
|
+
let AiTokenUsageEvent = class {
|
|
267
|
+
constructor() {
|
|
268
|
+
this.createdAt = /* @__PURE__ */ new Date();
|
|
269
|
+
this.updatedAt = /* @__PURE__ */ new Date();
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
__decorateClass([
|
|
273
|
+
PrimaryKey({ type: "uuid", defaultRaw: "gen_random_uuid()" })
|
|
274
|
+
], AiTokenUsageEvent.prototype, "id", 2);
|
|
275
|
+
__decorateClass([
|
|
276
|
+
Property({ name: "tenant_id", type: "uuid" })
|
|
277
|
+
], AiTokenUsageEvent.prototype, "tenantId", 2);
|
|
278
|
+
__decorateClass([
|
|
279
|
+
Property({ name: "organization_id", type: "uuid", nullable: true })
|
|
280
|
+
], AiTokenUsageEvent.prototype, "organizationId", 2);
|
|
281
|
+
__decorateClass([
|
|
282
|
+
Property({ name: "user_id", type: "uuid" })
|
|
283
|
+
], AiTokenUsageEvent.prototype, "userId", 2);
|
|
284
|
+
__decorateClass([
|
|
285
|
+
Property({ name: "agent_id", type: "text" })
|
|
286
|
+
], AiTokenUsageEvent.prototype, "agentId", 2);
|
|
287
|
+
__decorateClass([
|
|
288
|
+
Property({ name: "module_id", type: "text" })
|
|
289
|
+
], AiTokenUsageEvent.prototype, "moduleId", 2);
|
|
290
|
+
__decorateClass([
|
|
291
|
+
Property({ name: "session_id", type: "uuid" })
|
|
292
|
+
], AiTokenUsageEvent.prototype, "sessionId", 2);
|
|
293
|
+
__decorateClass([
|
|
294
|
+
Property({ name: "turn_id", type: "uuid" })
|
|
295
|
+
], AiTokenUsageEvent.prototype, "turnId", 2);
|
|
296
|
+
__decorateClass([
|
|
297
|
+
Property({ name: "step_index", type: "int" })
|
|
298
|
+
], AiTokenUsageEvent.prototype, "stepIndex", 2);
|
|
299
|
+
__decorateClass([
|
|
300
|
+
Property({ name: "provider_id", type: "text" })
|
|
301
|
+
], AiTokenUsageEvent.prototype, "providerId", 2);
|
|
302
|
+
__decorateClass([
|
|
303
|
+
Property({ name: "model_id", type: "text" })
|
|
304
|
+
], AiTokenUsageEvent.prototype, "modelId", 2);
|
|
305
|
+
__decorateClass([
|
|
306
|
+
Property({ name: "input_tokens", type: "int" })
|
|
307
|
+
], AiTokenUsageEvent.prototype, "inputTokens", 2);
|
|
308
|
+
__decorateClass([
|
|
309
|
+
Property({ name: "output_tokens", type: "int" })
|
|
310
|
+
], AiTokenUsageEvent.prototype, "outputTokens", 2);
|
|
311
|
+
__decorateClass([
|
|
312
|
+
Property({ name: "cached_input_tokens", type: "int", nullable: true })
|
|
313
|
+
], AiTokenUsageEvent.prototype, "cachedInputTokens", 2);
|
|
314
|
+
__decorateClass([
|
|
315
|
+
Property({ name: "reasoning_tokens", type: "int", nullable: true })
|
|
316
|
+
], AiTokenUsageEvent.prototype, "reasoningTokens", 2);
|
|
317
|
+
__decorateClass([
|
|
318
|
+
Property({ name: "finish_reason", type: "text", nullable: true })
|
|
319
|
+
], AiTokenUsageEvent.prototype, "finishReason", 2);
|
|
320
|
+
__decorateClass([
|
|
321
|
+
Property({ name: "loop_abort_reason", type: "text", nullable: true })
|
|
322
|
+
], AiTokenUsageEvent.prototype, "loopAbortReason", 2);
|
|
323
|
+
__decorateClass([
|
|
324
|
+
Property({ name: "created_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
|
|
325
|
+
], AiTokenUsageEvent.prototype, "createdAt", 2);
|
|
326
|
+
__decorateClass([
|
|
327
|
+
Property({ name: "updated_at", type: Date, onUpdate: () => /* @__PURE__ */ new Date() })
|
|
328
|
+
], AiTokenUsageEvent.prototype, "updatedAt", 2);
|
|
329
|
+
AiTokenUsageEvent = __decorateClass([
|
|
330
|
+
Entity({ tableName: "ai_token_usage_events" }),
|
|
331
|
+
Index({
|
|
332
|
+
name: "ai_token_usage_events_tenant_created_idx",
|
|
333
|
+
properties: ["tenantId", "createdAt"]
|
|
334
|
+
}),
|
|
335
|
+
Index({
|
|
336
|
+
name: "ai_token_usage_events_tenant_agent_created_idx",
|
|
337
|
+
properties: ["tenantId", "agentId", "createdAt"]
|
|
338
|
+
}),
|
|
339
|
+
Index({
|
|
340
|
+
name: "ai_token_usage_events_tenant_model_created_idx",
|
|
341
|
+
properties: ["tenantId", "modelId", "createdAt"]
|
|
342
|
+
}),
|
|
343
|
+
Index({
|
|
344
|
+
name: "ai_token_usage_events_tenant_session_turn_step_idx",
|
|
345
|
+
properties: ["tenantId", "sessionId", "turnId", "stepIndex"]
|
|
346
|
+
})
|
|
347
|
+
], AiTokenUsageEvent);
|
|
348
|
+
OptionalProps;
|
|
349
|
+
let AiTokenUsageDaily = class {
|
|
350
|
+
constructor() {
|
|
351
|
+
this.createdAt = /* @__PURE__ */ new Date();
|
|
352
|
+
this.updatedAt = /* @__PURE__ */ new Date();
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
__decorateClass([
|
|
356
|
+
PrimaryKey({ type: "uuid", defaultRaw: "gen_random_uuid()" })
|
|
357
|
+
], AiTokenUsageDaily.prototype, "id", 2);
|
|
358
|
+
__decorateClass([
|
|
359
|
+
Property({ name: "tenant_id", type: "uuid" })
|
|
360
|
+
], AiTokenUsageDaily.prototype, "tenantId", 2);
|
|
361
|
+
__decorateClass([
|
|
362
|
+
Property({ name: "organization_id", type: "uuid", nullable: true })
|
|
363
|
+
], AiTokenUsageDaily.prototype, "organizationId", 2);
|
|
364
|
+
__decorateClass([
|
|
365
|
+
Property({ name: "day", type: "string", columnType: "date" })
|
|
366
|
+
], AiTokenUsageDaily.prototype, "day", 2);
|
|
367
|
+
__decorateClass([
|
|
368
|
+
Property({ name: "agent_id", type: "text" })
|
|
369
|
+
], AiTokenUsageDaily.prototype, "agentId", 2);
|
|
370
|
+
__decorateClass([
|
|
371
|
+
Property({ name: "model_id", type: "text" })
|
|
372
|
+
], AiTokenUsageDaily.prototype, "modelId", 2);
|
|
373
|
+
__decorateClass([
|
|
374
|
+
Property({ name: "provider_id", type: "text" })
|
|
375
|
+
], AiTokenUsageDaily.prototype, "providerId", 2);
|
|
376
|
+
__decorateClass([
|
|
377
|
+
Property({ name: "input_tokens", type: "string", columnType: "bigint" })
|
|
378
|
+
], AiTokenUsageDaily.prototype, "inputTokens", 2);
|
|
379
|
+
__decorateClass([
|
|
380
|
+
Property({ name: "output_tokens", type: "string", columnType: "bigint" })
|
|
381
|
+
], AiTokenUsageDaily.prototype, "outputTokens", 2);
|
|
382
|
+
__decorateClass([
|
|
383
|
+
Property({ name: "cached_input_tokens", type: "string", columnType: "bigint" })
|
|
384
|
+
], AiTokenUsageDaily.prototype, "cachedInputTokens", 2);
|
|
385
|
+
__decorateClass([
|
|
386
|
+
Property({ name: "reasoning_tokens", type: "string", columnType: "bigint" })
|
|
387
|
+
], AiTokenUsageDaily.prototype, "reasoningTokens", 2);
|
|
388
|
+
__decorateClass([
|
|
389
|
+
Property({ name: "step_count", type: "string", columnType: "bigint" })
|
|
390
|
+
], AiTokenUsageDaily.prototype, "stepCount", 2);
|
|
391
|
+
__decorateClass([
|
|
392
|
+
Property({ name: "turn_count", type: "string", columnType: "bigint" })
|
|
393
|
+
], AiTokenUsageDaily.prototype, "turnCount", 2);
|
|
394
|
+
__decorateClass([
|
|
395
|
+
Property({ name: "session_count", type: "string", columnType: "bigint" })
|
|
396
|
+
], AiTokenUsageDaily.prototype, "sessionCount", 2);
|
|
397
|
+
__decorateClass([
|
|
398
|
+
Property({ name: "created_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
|
|
399
|
+
], AiTokenUsageDaily.prototype, "createdAt", 2);
|
|
400
|
+
__decorateClass([
|
|
401
|
+
Property({ name: "updated_at", type: Date, onUpdate: () => /* @__PURE__ */ new Date() })
|
|
402
|
+
], AiTokenUsageDaily.prototype, "updatedAt", 2);
|
|
403
|
+
AiTokenUsageDaily = __decorateClass([
|
|
404
|
+
Entity({ tableName: "ai_token_usage_daily" }),
|
|
405
|
+
Index({
|
|
406
|
+
name: "ai_token_usage_daily_tenant_day_agent_model_org_uq",
|
|
407
|
+
expression: 'create unique index "ai_token_usage_daily_tenant_day_agent_model_org_uq" on "ai_token_usage_daily" ("tenant_id", "day", "agent_id", "model_id", "organization_id") where "organization_id" is not null'
|
|
408
|
+
}),
|
|
409
|
+
Index({
|
|
410
|
+
name: "ai_token_usage_daily_tenant_day_agent_model_null_org_uq",
|
|
411
|
+
expression: 'create unique index "ai_token_usage_daily_tenant_day_agent_model_null_org_uq" on "ai_token_usage_daily" ("tenant_id", "day", "agent_id", "model_id") where "organization_id" is null'
|
|
412
|
+
}),
|
|
413
|
+
Index({
|
|
414
|
+
name: "ai_token_usage_daily_tenant_day_idx",
|
|
415
|
+
properties: ["tenantId", "day"]
|
|
416
|
+
})
|
|
417
|
+
], AiTokenUsageDaily);
|
|
418
|
+
OptionalProps;
|
|
245
419
|
let AiTenantModelAllowlist = class {
|
|
246
420
|
constructor() {
|
|
247
421
|
this.allowedModelsByProvider = {};
|
|
@@ -345,6 +519,8 @@ export {
|
|
|
345
519
|
AiAgentPromptOverride,
|
|
346
520
|
AiAgentRuntimeOverride,
|
|
347
521
|
AiPendingAction,
|
|
348
|
-
AiTenantModelAllowlist
|
|
522
|
+
AiTenantModelAllowlist,
|
|
523
|
+
AiTokenUsageDaily,
|
|
524
|
+
AiTokenUsageEvent
|
|
349
525
|
};
|
|
350
526
|
//# sourceMappingURL=entities.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/ai_assistant/data/entities.ts"],
|
|
4
|
-
"sourcesContent": ["import { OptionalProps } from '@mikro-orm/core'\nimport {\n Entity,\n Index,\n PrimaryKey,\n Property,\n} from '@mikro-orm/decorators/legacy'\nimport type {\n AiPendingActionExecutionResult,\n AiPendingActionFailedRecord,\n AiPendingActionFieldDiff,\n AiPendingActionQueueMode,\n AiPendingActionRecordDiff,\n AiPendingActionStatus,\n} from '../lib/pending-action-types'\n\n/**\n * Versioned additive prompt-override for a registered AI agent (Step 5.3).\n *\n * Each write creates a new row with `version = latest + 1`. Rows are never\n * updated in place \u2014 history is preserved so operators can roll back by\n * reading an earlier `version`. Column set is tenant/org-scoped per the\n * standard Open Mercato RBAC contract.\n *\n * `sections` holds additive text keyed by prompt section id. The runtime\n * composes the final `systemPrompt` via `composeSystemPromptWithOverride`\n * (see `lib/prompt-override-merge.ts`), which NEVER replaces a built-in\n * section \u2014 overrides are append-only by contract.\n */\n@Entity({ tableName: 'ai_agent_prompt_overrides' })\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_org_agent_version_uq',\n expression:\n 'create unique index \"ai_agent_prompt_overrides_tenant_org_agent_version_uq\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\", \"version\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_agent_version_null_org_uq',\n expression:\n 'create unique index \"ai_agent_prompt_overrides_tenant_agent_version_null_org_uq\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"agent_id\", \"version\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_agent_idx',\n properties: ['tenantId', 'agentId'],\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_org_agent_version_idx',\n expression:\n 'create index \"ai_agent_prompt_overrides_tenant_org_agent_version_idx\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\", \"version\" desc)',\n})\nexport class AiAgentPromptOverride {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId' | 'createdByUserId' | 'notes'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'version', type: 'int' })\n version!: number\n\n @Property({ name: 'sections', type: 'jsonb' })\n sections!: Record<string, string>\n\n @Property({ name: 'notes', type: 'text', nullable: true })\n notes?: string | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Persistent mutation-approval gate row backing the Phase 3 WS-C contract\n * (spec \u00A78 `AiPendingAction` + \u00A79 confirm/cancel flow, Step 5.5).\n *\n * One row is created by `prepareMutation` (Step 5.6) whenever the runtime\n * intercepts an `isMutation: true` tool call from a non-read-only agent.\n * The row stores the normalized tool input, a precomputed `fieldDiff` (or\n * per-record batch diff in `records[]`), the target record version, an\n * `idempotencyKey` that dedupes double-submits within the TTL, and a\n * `status` that walks the state machine defined in\n * {@link AI_PENDING_ACTION_ALLOWED_TRANSITIONS}.\n *\n * The cleanup worker (Step 5.12) sweeps `status='pending' AND expiresAt < now`\n * rows and transitions them to `expired`. The confirm route (Step 5.8)\n * walks `pending \u2192 confirmed \u2192 executing \u2192 (failed | terminal success)`.\n * Reads always flow through `findOneWithDecryption` /\n * `findWithDecryption`, even though no column is GDPR-flagged today, so\n * future encrypted columns (e.g. `normalizedInput`) are handled.\n */\n@Entity({ tableName: 'ai_pending_actions' })\n@Index({\n name: 'ai_pending_actions_tenant_org_idempotency_uq',\n expression:\n 'create unique index \"ai_pending_actions_tenant_org_idempotency_uq\" on \"ai_pending_actions\" (\"tenant_id\", \"organization_id\", \"idempotency_key\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_pending_actions_tenant_idem_null_org_uq',\n expression:\n 'create unique index \"ai_pending_actions_tenant_idem_null_org_uq\" on \"ai_pending_actions\" (\"tenant_id\", \"idempotency_key\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_pending_actions_tenant_org_status_expires_idx',\n properties: ['tenantId', 'organizationId', 'status', 'expiresAt'],\n})\n@Index({\n name: 'ai_pending_actions_tenant_org_agent_status_idx',\n properties: ['tenantId', 'organizationId', 'agentId', 'status'],\n})\nexport class AiPendingAction {\n [OptionalProps]?:\n | 'createdAt'\n | 'organizationId'\n | 'conversationId'\n | 'targetEntityType'\n | 'targetRecordId'\n | 'fieldDiff'\n | 'records'\n | 'failedRecords'\n | 'sideEffectsSummary'\n | 'recordVersion'\n | 'attachmentIds'\n | 'executionResult'\n | 'resolvedAt'\n | 'resolvedByUserId'\n | 'queueMode'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'tool_name', type: 'text' })\n toolName!: string\n\n @Property({ name: 'conversation_id', type: 'text', nullable: true })\n conversationId?: string | null\n\n @Property({ name: 'target_entity_type', type: 'text', nullable: true })\n targetEntityType?: string | null\n\n @Property({ name: 'target_record_id', type: 'text', nullable: true })\n targetRecordId?: string | null\n\n @Property({ name: 'normalized_input', type: 'jsonb' })\n normalizedInput!: Record<string, unknown>\n\n @Property({ name: 'field_diff', type: 'jsonb', default: [] })\n fieldDiff: AiPendingActionFieldDiff[] = []\n\n @Property({ name: 'records', type: 'jsonb', nullable: true })\n records?: AiPendingActionRecordDiff[] | null\n\n @Property({ name: 'failed_records', type: 'jsonb', nullable: true })\n failedRecords?: AiPendingActionFailedRecord[] | null\n\n @Property({ name: 'side_effects_summary', type: 'text', nullable: true })\n sideEffectsSummary?: string | null\n\n @Property({ name: 'record_version', type: 'text', nullable: true })\n recordVersion?: string | null\n\n @Property({ name: 'attachment_ids', type: 'jsonb', default: [] })\n attachmentIds: string[] = []\n\n @Property({ name: 'idempotency_key', type: 'text' })\n idempotencyKey!: string\n\n @Property({ name: 'created_by_user_id', type: 'uuid' })\n createdByUserId!: string\n\n @Property({ name: 'status', type: 'text' })\n status!: AiPendingActionStatus\n\n @Property({ name: 'queue_mode', type: 'text', default: 'inline' })\n queueMode: AiPendingActionQueueMode = 'inline'\n\n @Property({ name: 'execution_result', type: 'jsonb', nullable: true })\n executionResult?: AiPendingActionExecutionResult | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'expires_at', type: Date })\n expiresAt!: Date\n\n @Property({ name: 'resolved_at', type: Date, nullable: true })\n resolvedAt?: Date | null\n\n @Property({ name: 'resolved_by_user_id', type: 'uuid', nullable: true })\n resolvedByUserId?: string | null\n}\n\n/**\n * Per-tenant runtime override row that controls which provider, model, and\n * base URL the AI runtime uses for a given agent (or all agents when\n * `agent_id` is null).\n *\n * Resolution at query time: a non-null `agent_id` row takes precedence over\n * a null `agent_id` (tenant-wide) row for the same `(tenant_id,\n * organization_id)` scope. All value columns are nullable \u2014 an admin can\n * override just the provider, just the model, or any subset. A null value\n * means \"inherit from the next source in the factory resolution chain.\"\n *\n * Soft-delete via `deleted_at` so the unique partial index and audit trail\n * remain intact across upsert operations.\n *\n * Phase 4a of spec `2026-04-27-ai-agents-provider-model-baseurl-overrides`.\n */\n@Entity({ tableName: 'ai_agent_runtime_overrides' })\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_org_agent_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_org_agent_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\") where \"deleted_at\" is null and \"organization_id\" is not null and \"agent_id\" is not null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_agent_null_org_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"agent_id\") where \"deleted_at\" is null and \"organization_id\" is null and \"agent_id\" is not null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_null_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_null_agent_null_org_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\") where \"deleted_at\" is null and \"organization_id\" is null and \"agent_id\" is null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_org_null_agent_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_org_null_agent_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"organization_id\") where \"deleted_at\" is null and \"organization_id\" is not null and \"agent_id\" is null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_idx',\n properties: ['tenantId'],\n})\nexport class AiAgentRuntimeOverride {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'agentId'\n | 'providerId'\n | 'modelId'\n | 'baseUrl'\n | 'allowedOverrideProviders'\n | 'allowedOverrideModelsByProvider'\n | 'updatedByUserId'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'string', columnType: 'varchar(128)', nullable: true })\n agentId?: string | null\n\n @Property({ name: 'provider_id', type: 'string', columnType: 'varchar(64)', nullable: true })\n providerId?: string | null\n\n @Property({ name: 'model_id', type: 'string', columnType: 'varchar(256)', nullable: true })\n modelId?: string | null\n\n @Property({ name: 'base_url', type: 'string', columnType: 'varchar(2048)', nullable: true })\n baseUrl?: string | null\n\n @Property({ name: 'allowed_override_providers', type: 'jsonb', nullable: true })\n allowedOverrideProviders?: string[] | null\n\n @Property({ name: 'allowed_override_models_by_provider', type: 'jsonb', default: '{}' })\n allowedOverrideModelsByProvider: Record<string, string[]> = {}\n\n @Property({ name: 'updated_by_user_id', type: 'uuid', nullable: true })\n updatedByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n/**\n * Tenant-scoped override of an agent's declared `mutationPolicy` (Step 5.4).\n *\n * Unlike {@link AiAgentPromptOverride}, this surface is NOT versioned \u2014 it is\n * a single-value policy switch per `(tenantId, organizationId, agentId)`. The\n * runtime enforces the override as a DOWNGRADE only: the effective policy\n * equals the MOST RESTRICTIVE of `{ code-declared, override }`. Escalation is\n * a code-level change and is rejected at the route layer.\n *\n * Hierarchy (most restrictive \u2192 least): `read-only` < `destructive-confirm-required`\n * < `confirm-required`. The route never allows an override to widen the\n * code-declared policy.\n */\n/**\n * Tenant-scoped allowlist clipping which providers and models the runtime is\n * permitted to use within the env-driven allowlist (Phase 1780-6 of spec\n * `2026-04-27-ai-agents-provider-model-baseurl-overrides`).\n *\n * Effective constraint chain (outer \u2192 inner): `OM_AI_AVAILABLE_*` env vars \u2192\n * this tenant allowlist \u2192 per-tenant runtime overrides \u2192 per-request overrides.\n * The tenant allowlist may NEVER widen the env allowlist; the runtime\n * intersects the two and surfaces the intersection through the settings GET\n * response so the UI never offers a value the runtime would refuse.\n *\n * `allowedProviders === null` means \"inherit env\" (no tenant-level restriction\n * beyond what the env imposes). `allowedModelsByProvider` keys are provider\n * ids; a missing key means \"inherit env\" for that provider; an empty array\n * means \"no models permitted for this provider\" (effectively disabling it).\n */\n@Entity({ tableName: 'ai_tenant_model_allowlists' })\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_org_uq',\n expression:\n 'create unique index \"ai_tenant_model_allowlists_tenant_org_uq\" on \"ai_tenant_model_allowlists\" (\"tenant_id\", \"organization_id\") where \"deleted_at\" is null and \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_null_org_uq',\n expression:\n 'create unique index \"ai_tenant_model_allowlists_tenant_null_org_uq\" on \"ai_tenant_model_allowlists\" (\"tenant_id\") where \"deleted_at\" is null and \"organization_id\" is null',\n})\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_idx',\n properties: ['tenantId'],\n})\nexport class AiTenantModelAllowlist {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'allowedProviders'\n | 'allowedModelsByProvider'\n | 'updatedByUserId'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'allowed_providers', type: 'jsonb', nullable: true })\n allowedProviders?: string[] | null\n\n @Property({ name: 'allowed_models_by_provider', type: 'jsonb', default: '{}' })\n allowedModelsByProvider: Record<string, string[]> = {}\n\n @Property({ name: 'updated_by_user_id', type: 'uuid', nullable: true })\n updatedByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'ai_agent_mutation_policy_overrides' })\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_org_agent_uq',\n expression:\n 'create unique index \"ai_agent_mutation_policy_overrides_tenant_org_agent_uq\" on \"ai_agent_mutation_policy_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_mutation_policy_overrides_tenant_agent_null_org_uq\" on \"ai_agent_mutation_policy_overrides\" (\"tenant_id\", \"agent_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_agent_idx',\n properties: ['tenantId', 'agentId'],\n})\nexport class AiAgentMutationPolicyOverride {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId' | 'createdByUserId' | 'notes'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'mutation_policy', type: 'text' })\n mutationPolicy!: string\n\n @Property({ name: 'notes', type: 'text', nullable: true })\n notes?: string | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { OptionalProps } from '@mikro-orm/core'\nimport {\n Entity,\n Index,\n PrimaryKey,\n Property,\n} from '@mikro-orm/decorators/legacy'\nimport type {\n AiPendingActionExecutionResult,\n AiPendingActionFailedRecord,\n AiPendingActionFieldDiff,\n AiPendingActionQueueMode,\n AiPendingActionRecordDiff,\n AiPendingActionStatus,\n} from '../lib/pending-action-types'\n\n/**\n * Versioned additive prompt-override for a registered AI agent (Step 5.3).\n *\n * Each write creates a new row with `version = latest + 1`. Rows are never\n * updated in place \u2014 history is preserved so operators can roll back by\n * reading an earlier `version`. Column set is tenant/org-scoped per the\n * standard Open Mercato RBAC contract.\n *\n * `sections` holds additive text keyed by prompt section id. The runtime\n * composes the final `systemPrompt` via `composeSystemPromptWithOverride`\n * (see `lib/prompt-override-merge.ts`), which NEVER replaces a built-in\n * section \u2014 overrides are append-only by contract.\n */\n@Entity({ tableName: 'ai_agent_prompt_overrides' })\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_org_agent_version_uq',\n expression:\n 'create unique index \"ai_agent_prompt_overrides_tenant_org_agent_version_uq\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\", \"version\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_agent_version_null_org_uq',\n expression:\n 'create unique index \"ai_agent_prompt_overrides_tenant_agent_version_null_org_uq\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"agent_id\", \"version\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_agent_idx',\n properties: ['tenantId', 'agentId'],\n})\n@Index({\n name: 'ai_agent_prompt_overrides_tenant_org_agent_version_idx',\n expression:\n 'create index \"ai_agent_prompt_overrides_tenant_org_agent_version_idx\" on \"ai_agent_prompt_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\", \"version\" desc)',\n})\nexport class AiAgentPromptOverride {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId' | 'createdByUserId' | 'notes'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'version', type: 'int' })\n version!: number\n\n @Property({ name: 'sections', type: 'jsonb' })\n sections!: Record<string, string>\n\n @Property({ name: 'notes', type: 'text', nullable: true })\n notes?: string | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Persistent mutation-approval gate row backing the Phase 3 WS-C contract\n * (spec \u00A78 `AiPendingAction` + \u00A79 confirm/cancel flow, Step 5.5).\n *\n * One row is created by `prepareMutation` (Step 5.6) whenever the runtime\n * intercepts an `isMutation: true` tool call from a non-read-only agent.\n * The row stores the normalized tool input, a precomputed `fieldDiff` (or\n * per-record batch diff in `records[]`), the target record version, an\n * `idempotencyKey` that dedupes double-submits within the TTL, and a\n * `status` that walks the state machine defined in\n * {@link AI_PENDING_ACTION_ALLOWED_TRANSITIONS}.\n *\n * The cleanup worker (Step 5.12) sweeps `status='pending' AND expiresAt < now`\n * rows and transitions them to `expired`. The confirm route (Step 5.8)\n * walks `pending \u2192 confirmed \u2192 executing \u2192 (failed | terminal success)`.\n * Reads always flow through `findOneWithDecryption` /\n * `findWithDecryption`, even though no column is GDPR-flagged today, so\n * future encrypted columns (e.g. `normalizedInput`) are handled.\n */\n@Entity({ tableName: 'ai_pending_actions' })\n@Index({\n name: 'ai_pending_actions_tenant_org_idempotency_uq',\n expression:\n 'create unique index \"ai_pending_actions_tenant_org_idempotency_uq\" on \"ai_pending_actions\" (\"tenant_id\", \"organization_id\", \"idempotency_key\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_pending_actions_tenant_idem_null_org_uq',\n expression:\n 'create unique index \"ai_pending_actions_tenant_idem_null_org_uq\" on \"ai_pending_actions\" (\"tenant_id\", \"idempotency_key\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_pending_actions_tenant_org_status_expires_idx',\n properties: ['tenantId', 'organizationId', 'status', 'expiresAt'],\n})\n@Index({\n name: 'ai_pending_actions_tenant_org_agent_status_idx',\n properties: ['tenantId', 'organizationId', 'agentId', 'status'],\n})\nexport class AiPendingAction {\n [OptionalProps]?:\n | 'createdAt'\n | 'organizationId'\n | 'conversationId'\n | 'targetEntityType'\n | 'targetRecordId'\n | 'fieldDiff'\n | 'records'\n | 'failedRecords'\n | 'sideEffectsSummary'\n | 'recordVersion'\n | 'attachmentIds'\n | 'executionResult'\n | 'resolvedAt'\n | 'resolvedByUserId'\n | 'queueMode'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'tool_name', type: 'text' })\n toolName!: string\n\n @Property({ name: 'conversation_id', type: 'text', nullable: true })\n conversationId?: string | null\n\n @Property({ name: 'target_entity_type', type: 'text', nullable: true })\n targetEntityType?: string | null\n\n @Property({ name: 'target_record_id', type: 'text', nullable: true })\n targetRecordId?: string | null\n\n @Property({ name: 'normalized_input', type: 'jsonb' })\n normalizedInput!: Record<string, unknown>\n\n @Property({ name: 'field_diff', type: 'jsonb', default: [] })\n fieldDiff: AiPendingActionFieldDiff[] = []\n\n @Property({ name: 'records', type: 'jsonb', nullable: true })\n records?: AiPendingActionRecordDiff[] | null\n\n @Property({ name: 'failed_records', type: 'jsonb', nullable: true })\n failedRecords?: AiPendingActionFailedRecord[] | null\n\n @Property({ name: 'side_effects_summary', type: 'text', nullable: true })\n sideEffectsSummary?: string | null\n\n @Property({ name: 'record_version', type: 'text', nullable: true })\n recordVersion?: string | null\n\n @Property({ name: 'attachment_ids', type: 'jsonb', default: [] })\n attachmentIds: string[] = []\n\n @Property({ name: 'idempotency_key', type: 'text' })\n idempotencyKey!: string\n\n @Property({ name: 'created_by_user_id', type: 'uuid' })\n createdByUserId!: string\n\n @Property({ name: 'status', type: 'text' })\n status!: AiPendingActionStatus\n\n @Property({ name: 'queue_mode', type: 'text', default: 'inline' })\n queueMode: AiPendingActionQueueMode = 'inline'\n\n @Property({ name: 'execution_result', type: 'jsonb', nullable: true })\n executionResult?: AiPendingActionExecutionResult | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'expires_at', type: Date })\n expiresAt!: Date\n\n @Property({ name: 'resolved_at', type: Date, nullable: true })\n resolvedAt?: Date | null\n\n @Property({ name: 'resolved_by_user_id', type: 'uuid', nullable: true })\n resolvedByUserId?: string | null\n}\n\n/**\n * Per-tenant runtime override row that controls which provider, model, and\n * base URL the AI runtime uses for a given agent (or all agents when\n * `agent_id` is null).\n *\n * Resolution at query time: a non-null `agent_id` row takes precedence over\n * a null `agent_id` (tenant-wide) row for the same `(tenant_id,\n * organization_id)` scope. All value columns are nullable \u2014 an admin can\n * override just the provider, just the model, or any subset. A null value\n * means \"inherit from the next source in the factory resolution chain.\"\n *\n * Soft-delete via `deleted_at` so the unique partial index and audit trail\n * remain intact across upsert operations.\n *\n * Phase 4a of spec `2026-04-27-ai-agents-provider-model-baseurl-overrides`.\n */\n@Entity({ tableName: 'ai_agent_runtime_overrides' })\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_org_agent_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_org_agent_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\") where \"deleted_at\" is null and \"organization_id\" is not null and \"agent_id\" is not null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_agent_null_org_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"agent_id\") where \"deleted_at\" is null and \"organization_id\" is null and \"agent_id\" is not null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_null_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_null_agent_null_org_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\") where \"deleted_at\" is null and \"organization_id\" is null and \"agent_id\" is null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_org_null_agent_uq',\n expression:\n 'create unique index \"ai_agent_runtime_overrides_tenant_org_null_agent_uq\" on \"ai_agent_runtime_overrides\" (\"tenant_id\", \"organization_id\") where \"deleted_at\" is null and \"organization_id\" is not null and \"agent_id\" is null',\n})\n@Index({\n name: 'ai_agent_runtime_overrides_tenant_idx',\n properties: ['tenantId'],\n})\nexport class AiAgentRuntimeOverride {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'agentId'\n | 'providerId'\n | 'modelId'\n | 'baseUrl'\n | 'allowedOverrideProviders'\n | 'allowedOverrideModelsByProvider'\n | 'updatedByUserId'\n | 'deletedAt'\n | 'loopDisabled'\n | 'loopMaxSteps'\n | 'loopMaxToolCalls'\n | 'loopMaxWallClockMs'\n | 'loopMaxTokens'\n | 'loopStopWhenJson'\n | 'loopActiveToolsJson'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'string', columnType: 'varchar(128)', nullable: true })\n agentId?: string | null\n\n @Property({ name: 'provider_id', type: 'string', columnType: 'varchar(64)', nullable: true })\n providerId?: string | null\n\n @Property({ name: 'model_id', type: 'string', columnType: 'varchar(256)', nullable: true })\n modelId?: string | null\n\n @Property({ name: 'base_url', type: 'string', columnType: 'varchar(2048)', nullable: true })\n baseUrl?: string | null\n\n @Property({ name: 'allowed_override_providers', type: 'jsonb', nullable: true })\n allowedOverrideProviders?: string[] | null\n\n @Property({ name: 'allowed_override_models_by_provider', type: 'jsonb', default: '{}' })\n allowedOverrideModelsByProvider: Record<string, string[]> = {}\n\n @Property({ name: 'updated_by_user_id', type: 'uuid', nullable: true })\n updatedByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n\n /**\n * Kill switch \u2014 when `true`, runtime forces `stopWhen: stepCountIs(1)` and\n * ignores all other loop config. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_disabled', type: 'boolean', nullable: true })\n loopDisabled?: boolean | null\n\n /**\n * Override `loop.maxSteps`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_steps', type: 'int', nullable: true })\n loopMaxSteps?: number | null\n\n /**\n * Override `loop.budget.maxToolCalls`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_tool_calls', type: 'int', nullable: true })\n loopMaxToolCalls?: number | null\n\n /**\n * Override `loop.budget.maxWallClockMs`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_wall_clock_ms', type: 'int', nullable: true })\n loopMaxWallClockMs?: number | null\n\n /**\n * Override `loop.budget.maxTokens`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_max_tokens', type: 'int', nullable: true })\n loopMaxTokens?: number | null\n\n /**\n * Override `loop.stopWhen`. JSON-safe variants only (`stepCount`,\n * `hasToolCall`); validator rejects `kind: 'custom'`. Phase 3 of spec\n * `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_stop_when_json', type: 'jsonb', nullable: true })\n loopStopWhenJson?: unknown | null\n\n /**\n * Override `loop.activeTools` (must be subset of `agent.allowedTools`).\n * Phase 3 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n @Property({ name: 'loop_active_tools_json', type: 'jsonb', nullable: true })\n loopActiveToolsJson?: unknown | null\n}\n\n/**\n * Append-only event log for token usage per step (chat) or per turn (object).\n *\n * One row is created by `recordTokenUsage` (Phase 6.3) for every completed\n * AI SDK step. Indexed for the three read patterns: daily rollup, per-agent\n * report, and session drill-down.\n *\n * Retention: rows older than `AI_TOKEN_USAGE_EVENTS_RETENTION_DAYS` (default\n * 90) are swept by the `ai-token-usage-prune` worker (Phase 6.4).\n *\n * Phase 6.0 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n@Entity({ tableName: 'ai_token_usage_events' })\n@Index({\n name: 'ai_token_usage_events_tenant_created_idx',\n properties: ['tenantId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_agent_created_idx',\n properties: ['tenantId', 'agentId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_model_created_idx',\n properties: ['tenantId', 'modelId', 'createdAt'],\n})\n@Index({\n name: 'ai_token_usage_events_tenant_session_turn_step_idx',\n properties: ['tenantId', 'sessionId', 'turnId', 'stepIndex'],\n})\nexport class AiTokenUsageEvent {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'cachedInputTokens'\n | 'reasoningTokens'\n | 'finishReason'\n | 'loopAbortReason'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'user_id', type: 'uuid' })\n userId!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'module_id', type: 'text' })\n moduleId!: string\n\n @Property({ name: 'session_id', type: 'uuid' })\n sessionId!: string\n\n @Property({ name: 'turn_id', type: 'uuid' })\n turnId!: string\n\n @Property({ name: 'step_index', type: 'int' })\n stepIndex!: number\n\n @Property({ name: 'provider_id', type: 'text' })\n providerId!: string\n\n @Property({ name: 'model_id', type: 'text' })\n modelId!: string\n\n @Property({ name: 'input_tokens', type: 'int' })\n inputTokens!: number\n\n @Property({ name: 'output_tokens', type: 'int' })\n outputTokens!: number\n\n @Property({ name: 'cached_input_tokens', type: 'int', nullable: true })\n cachedInputTokens?: number | null\n\n @Property({ name: 'reasoning_tokens', type: 'int', nullable: true })\n reasoningTokens?: number | null\n\n @Property({ name: 'finish_reason', type: 'text', nullable: true })\n finishReason?: string | null\n\n @Property({ name: 'loop_abort_reason', type: 'text', nullable: true })\n loopAbortReason?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Materialized daily rollup of token usage per `(tenant, day, agent, model)`.\n *\n * Updated incrementally by UPSERT on every `recordTokenUsage` call so the\n * rollup is always current even when the prune worker is behind. A daily\n * reconciliation worker (Phase 6.4) recomputes `session_count` from the events\n * table to correct any drift caused by event delivery delays or outages.\n *\n * `session_count` is maintained via a per-row LATERAL exists check at write\n * time (first event in a `(tenant, day, agent, model, session)` window\n * increments the counter). This counter may drift if events arrive out of\n * order; the daily worker corrects it.\n *\n * Phase 6.1 of spec `2026-04-28-ai-agents-agentic-loop-controls`.\n */\n@Entity({ tableName: 'ai_token_usage_daily' })\n@Index({\n name: 'ai_token_usage_daily_tenant_day_agent_model_org_uq',\n expression:\n 'create unique index \"ai_token_usage_daily_tenant_day_agent_model_org_uq\" on \"ai_token_usage_daily\" (\"tenant_id\", \"day\", \"agent_id\", \"model_id\", \"organization_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_token_usage_daily_tenant_day_agent_model_null_org_uq',\n expression:\n 'create unique index \"ai_token_usage_daily_tenant_day_agent_model_null_org_uq\" on \"ai_token_usage_daily\" (\"tenant_id\", \"day\", \"agent_id\", \"model_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_token_usage_daily_tenant_day_idx',\n properties: ['tenantId', 'day'],\n})\nexport class AiTokenUsageDaily {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'day', type: 'string', columnType: 'date' })\n day!: string\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'model_id', type: 'text' })\n modelId!: string\n\n @Property({ name: 'provider_id', type: 'text' })\n providerId!: string\n\n @Property({ name: 'input_tokens', type: 'string', columnType: 'bigint' })\n inputTokens!: string\n\n @Property({ name: 'output_tokens', type: 'string', columnType: 'bigint' })\n outputTokens!: string\n\n @Property({ name: 'cached_input_tokens', type: 'string', columnType: 'bigint' })\n cachedInputTokens!: string\n\n @Property({ name: 'reasoning_tokens', type: 'string', columnType: 'bigint' })\n reasoningTokens!: string\n\n @Property({ name: 'step_count', type: 'string', columnType: 'bigint' })\n stepCount!: string\n\n @Property({ name: 'turn_count', type: 'string', columnType: 'bigint' })\n turnCount!: string\n\n @Property({ name: 'session_count', type: 'string', columnType: 'bigint' })\n sessionCount!: string\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n\n/**\n * Tenant-scoped override of an agent's declared `mutationPolicy` (Step 5.4).\n *\n * Unlike {@link AiAgentPromptOverride}, this surface is NOT versioned \u2014 it is\n * a single-value policy switch per `(tenantId, organizationId, agentId)`. The\n * runtime enforces the override as a DOWNGRADE only: the effective policy\n * equals the MOST RESTRICTIVE of `{ code-declared, override }`. Escalation is\n * a code-level change and is rejected at the route layer.\n *\n * Hierarchy (most restrictive \u2192 least): `read-only` < `destructive-confirm-required`\n * < `confirm-required`. The route never allows an override to widen the\n * code-declared policy.\n */\n/**\n * Tenant-scoped allowlist clipping which providers and models the runtime is\n * permitted to use within the env-driven allowlist (Phase 1780-6 of spec\n * `2026-04-27-ai-agents-provider-model-baseurl-overrides`).\n *\n * Effective constraint chain (outer \u2192 inner): `OM_AI_AVAILABLE_*` env vars \u2192\n * this tenant allowlist \u2192 per-tenant runtime overrides \u2192 per-request overrides.\n * The tenant allowlist may NEVER widen the env allowlist; the runtime\n * intersects the two and surfaces the intersection through the settings GET\n * response so the UI never offers a value the runtime would refuse.\n *\n * `allowedProviders === null` means \"inherit env\" (no tenant-level restriction\n * beyond what the env imposes). `allowedModelsByProvider` keys are provider\n * ids; a missing key means \"inherit env\" for that provider; an empty array\n * means \"no models permitted for this provider\" (effectively disabling it).\n */\n@Entity({ tableName: 'ai_tenant_model_allowlists' })\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_org_uq',\n expression:\n 'create unique index \"ai_tenant_model_allowlists_tenant_org_uq\" on \"ai_tenant_model_allowlists\" (\"tenant_id\", \"organization_id\") where \"deleted_at\" is null and \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_null_org_uq',\n expression:\n 'create unique index \"ai_tenant_model_allowlists_tenant_null_org_uq\" on \"ai_tenant_model_allowlists\" (\"tenant_id\") where \"deleted_at\" is null and \"organization_id\" is null',\n})\n@Index({\n name: 'ai_tenant_model_allowlists_tenant_idx',\n properties: ['tenantId'],\n})\nexport class AiTenantModelAllowlist {\n [OptionalProps]?:\n | 'createdAt'\n | 'updatedAt'\n | 'organizationId'\n | 'allowedProviders'\n | 'allowedModelsByProvider'\n | 'updatedByUserId'\n | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'allowed_providers', type: 'jsonb', nullable: true })\n allowedProviders?: string[] | null\n\n @Property({ name: 'allowed_models_by_provider', type: 'jsonb', default: '{}' })\n allowedModelsByProvider: Record<string, string[]> = {}\n\n @Property({ name: 'updated_by_user_id', type: 'uuid', nullable: true })\n updatedByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'ai_agent_mutation_policy_overrides' })\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_org_agent_uq',\n expression:\n 'create unique index \"ai_agent_mutation_policy_overrides_tenant_org_agent_uq\" on \"ai_agent_mutation_policy_overrides\" (\"tenant_id\", \"organization_id\", \"agent_id\") where \"organization_id\" is not null',\n})\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_agent_null_org_uq',\n expression:\n 'create unique index \"ai_agent_mutation_policy_overrides_tenant_agent_null_org_uq\" on \"ai_agent_mutation_policy_overrides\" (\"tenant_id\", \"agent_id\") where \"organization_id\" is null',\n})\n@Index({\n name: 'ai_agent_mutation_policy_overrides_tenant_agent_idx',\n properties: ['tenantId', 'agentId'],\n})\nexport class AiAgentMutationPolicyOverride {\n [OptionalProps]?: 'createdAt' | 'updatedAt' | 'organizationId' | 'createdByUserId' | 'notes'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'agent_id', type: 'text' })\n agentId!: string\n\n @Property({ name: 'mutation_policy', type: 'text' })\n mutationPolicy!: string\n\n @Property({ name: 'notes', type: 'text', nullable: true })\n notes?: string | null\n\n @Property({ name: 'created_by_user_id', type: 'uuid', nullable: true })\n createdByUserId?: string | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|