@open-mercato/ai-assistant 0.6.1-develop.3246.1.dbef9d7392 → 0.6.1-develop.3256.1.fe3dec2464
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 +82 -18
- package/dist/modules/ai_assistant/__integration__/TC-AI-RUNTIME-OVERRIDES-006-model-picker.spec.js +370 -0
- package/dist/modules/ai_assistant/__integration__/TC-AI-RUNTIME-OVERRIDES-006-model-picker.spec.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/models/route.js +194 -0
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/models/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/agents/route.js +4 -0
- package/dist/modules/ai_assistant/api/ai/agents/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/chat/route.js +169 -5
- package/dist/modules/ai_assistant/api/ai/chat/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/route/route.js +38 -19
- package/dist/modules/ai_assistant/api/route/route.js.map +3 -3
- package/dist/modules/ai_assistant/api/settings/allowlist/route.js +195 -0
- package/dist/modules/ai_assistant/api/settings/allowlist/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/settings/route.js +537 -22
- package/dist/modules/ai_assistant/api/settings/route.js.map +3 -3
- package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.js +701 -147
- 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 +338 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/allowlist/AiTenantAllowlistPageClient.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/allowlist/page.js +10 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/allowlist/page.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/allowlist/page.meta.js +25 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/allowlist/page.meta.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/legacy/page.js +1 -1
- package/dist/modules/ai_assistant/backend/config/ai-assistant/legacy/page.js.map +2 -2
- package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.js +75 -26
- package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.js.map +2 -2
- package/dist/modules/ai_assistant/backend/config/ai-assistant/settings/page.js +10 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/settings/page.js.map +7 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/settings/page.meta.js +25 -0
- package/dist/modules/ai_assistant/backend/config/ai-assistant/settings/page.meta.js.map +7 -0
- package/dist/modules/ai_assistant/components/AiAssistantSettingsPageClient.js +503 -168
- package/dist/modules/ai_assistant/components/AiAssistantSettingsPageClient.js.map +2 -2
- package/dist/modules/ai_assistant/data/entities/AiAgentRuntimeOverride.js +5 -0
- package/dist/modules/ai_assistant/data/entities/AiAgentRuntimeOverride.js.map +7 -0
- package/dist/modules/ai_assistant/data/entities/AiTenantModelAllowlist.js +5 -0
- package/dist/modules/ai_assistant/data/entities/AiTenantModelAllowlist.js.map +7 -0
- package/dist/modules/ai_assistant/data/entities.js +123 -1
- package/dist/modules/ai_assistant/data/entities.js.map +2 -2
- package/dist/modules/ai_assistant/data/repositories/AiAgentRuntimeOverrideRepository.js +157 -0
- package/dist/modules/ai_assistant/data/repositories/AiAgentRuntimeOverrideRepository.js.map +7 -0
- package/dist/modules/ai_assistant/data/repositories/AiTenantModelAllowlistRepository.js +77 -0
- package/dist/modules/ai_assistant/data/repositories/AiTenantModelAllowlistRepository.js.map +7 -0
- package/dist/modules/ai_assistant/frontend/components/AiAssistantSettingsPageClient.js +1 -1
- package/dist/modules/ai_assistant/frontend/components/AiAssistantSettingsPageClient.js.map +2 -2
- package/dist/modules/ai_assistant/i18n/de.json +90 -1
- package/dist/modules/ai_assistant/i18n/en.json +90 -1
- package/dist/modules/ai_assistant/i18n/es.json +90 -1
- package/dist/modules/ai_assistant/i18n/pl.json +90 -1
- package/dist/modules/ai_assistant/lib/agent-registry.js +17 -1
- package/dist/modules/ai_assistant/lib/agent-registry.js.map +2 -2
- package/dist/modules/ai_assistant/lib/agent-runtime.js +133 -36
- package/dist/modules/ai_assistant/lib/agent-runtime.js.map +2 -2
- package/dist/modules/ai_assistant/lib/ai-agent-definition.js.map +2 -2
- package/dist/modules/ai_assistant/lib/baseurl-allowlist.js +29 -0
- package/dist/modules/ai_assistant/lib/baseurl-allowlist.js.map +7 -0
- package/dist/modules/ai_assistant/lib/llm-adapters/anthropic.js +4 -1
- package/dist/modules/ai_assistant/lib/llm-adapters/anthropic.js.map +2 -2
- package/dist/modules/ai_assistant/lib/llm-adapters/google.js +4 -1
- package/dist/modules/ai_assistant/lib/llm-adapters/google.js.map +2 -2
- package/dist/modules/ai_assistant/lib/model-allowlist.js +211 -0
- package/dist/modules/ai_assistant/lib/model-allowlist.js.map +7 -0
- package/dist/modules/ai_assistant/lib/model-factory.js +203 -31
- package/dist/modules/ai_assistant/lib/model-factory.js.map +2 -2
- package/dist/modules/ai_assistant/lib/openai-compatible-presets.js +32 -1
- package/dist/modules/ai_assistant/lib/openai-compatible-presets.js.map +2 -2
- package/dist/modules/ai_assistant/migrations/Migration20260508140000.js +18 -0
- package/dist/modules/ai_assistant/migrations/Migration20260508140000.js.map +7 -0
- package/dist/modules/ai_assistant/migrations/Migration20260512090000.js +16 -0
- package/dist/modules/ai_assistant/migrations/Migration20260512090000.js.map +7 -0
- package/dist/modules/ai_assistant/migrations/Migration20260512130000.js +15 -0
- package/dist/modules/ai_assistant/migrations/Migration20260512130000.js.map +7 -0
- package/generated/entities/ai_agent_runtime_override/index.ts +13 -0
- package/generated/entities/ai_tenant_model_allowlist/index.ts +9 -0
- package/generated/entities.ids.generated.ts +2 -0
- package/generated/entity-fields-registry.ts +26 -0
- package/jest.config.cjs +2 -0
- package/package.json +4 -4
- package/src/modules/ai_assistant/__integration__/TC-AI-RUNTIME-OVERRIDES-006-model-picker.spec.ts +477 -0
- package/src/modules/ai_assistant/__tests__/settings-page-logic.test.ts +116 -0
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/models/__tests__/route.test.ts +240 -0
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/models/route.ts +251 -0
- package/src/modules/ai_assistant/api/ai/agents/route.ts +4 -0
- package/src/modules/ai_assistant/api/ai/chat/__tests__/route.test.ts +273 -0
- package/src/modules/ai_assistant/api/ai/chat/route.ts +211 -2
- package/src/modules/ai_assistant/api/route/route.ts +49 -25
- package/src/modules/ai_assistant/api/settings/__tests__/route.test.ts +408 -0
- package/src/modules/ai_assistant/api/settings/allowlist/route.ts +221 -0
- package/src/modules/ai_assistant/api/settings/route.ts +721 -27
- package/src/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.tsx +858 -177
- package/src/modules/ai_assistant/backend/config/ai-assistant/allowlist/AiTenantAllowlistPageClient.tsx +458 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/allowlist/page.meta.ts +23 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/allowlist/page.tsx +12 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/legacy/page.tsx +1 -1
- package/src/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.tsx +89 -12
- package/src/modules/ai_assistant/backend/config/ai-assistant/settings/page.meta.ts +23 -0
- package/src/modules/ai_assistant/backend/config/ai-assistant/settings/page.tsx +18 -0
- package/src/modules/ai_assistant/components/AiAssistantSettingsPageClient.tsx +617 -209
- package/src/modules/ai_assistant/data/entities/AiAgentRuntimeOverride.ts +7 -0
- package/src/modules/ai_assistant/data/entities/AiTenantModelAllowlist.ts +2 -0
- package/src/modules/ai_assistant/data/entities.ts +164 -0
- package/src/modules/ai_assistant/data/repositories/AiAgentRuntimeOverrideRepository.ts +227 -0
- package/src/modules/ai_assistant/data/repositories/AiTenantModelAllowlistRepository.ts +132 -0
- package/src/modules/ai_assistant/data/repositories/__tests__/AiAgentRuntimeOverrideRepository.test.ts +337 -0
- package/src/modules/ai_assistant/data/repositories/__tests__/AiTenantModelAllowlistRepository.test.ts +181 -0
- package/src/modules/ai_assistant/frontend/components/AiAssistantSettingsPageClient.tsx +1 -1
- package/src/modules/ai_assistant/i18n/de.json +90 -1
- package/src/modules/ai_assistant/i18n/en.json +90 -1
- package/src/modules/ai_assistant/i18n/es.json +90 -1
- package/src/modules/ai_assistant/i18n/pl.json +90 -1
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime-phase4a.test.ts +396 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime.test.ts +60 -6
- package/src/modules/ai_assistant/lib/__tests__/ai-api-operation-runner.test.ts +4 -2
- package/src/modules/ai_assistant/lib/__tests__/baseurl-allowlist.test.ts +75 -0
- package/src/modules/ai_assistant/lib/__tests__/llm-adapters-anthropic.test.ts +18 -0
- package/src/modules/ai_assistant/lib/__tests__/llm-adapters-google.test.ts +18 -0
- package/src/modules/ai_assistant/lib/__tests__/llm-adapters-openai.test.ts +150 -4
- package/src/modules/ai_assistant/lib/__tests__/model-allowlist.test.ts +290 -0
- package/src/modules/ai_assistant/lib/__tests__/model-factory.test.ts +634 -0
- package/src/modules/ai_assistant/lib/agent-registry.ts +20 -1
- package/src/modules/ai_assistant/lib/agent-runtime.ts +220 -44
- package/src/modules/ai_assistant/lib/ai-agent-definition.ts +48 -0
- package/src/modules/ai_assistant/lib/baseurl-allowlist.ts +64 -0
- package/src/modules/ai_assistant/lib/llm-adapters/anthropic.ts +11 -1
- package/src/modules/ai_assistant/lib/llm-adapters/google.ts +4 -1
- package/src/modules/ai_assistant/lib/model-allowlist.ts +407 -0
- package/src/modules/ai_assistant/lib/model-factory.ts +486 -58
- package/src/modules/ai_assistant/lib/openai-compatible-presets.ts +44 -0
- package/src/modules/ai_assistant/migrations/.snapshot-open-mercato.json +704 -235
- package/src/modules/ai_assistant/migrations/Migration20260508140000.ts +18 -0
- package/src/modules/ai_assistant/migrations/Migration20260512090000.ts +16 -0
- package/src/modules/ai_assistant/migrations/Migration20260512130000.ts +13 -0
|
@@ -1,36 +1,332 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import
|
|
4
|
-
import { useQuery } from "@tanstack/react-query";
|
|
5
|
-
import { Bot, Loader2, CheckCircle2, XCircle, ChevronDown, ChevronRight, Server, Wrench, Eye, EyeOff, Database, Link2, Settings, Key } from "lucide-react";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
5
|
+
import { Bot, Loader2, CheckCircle2, XCircle, ChevronDown, ChevronRight, Server, Wrench, Eye, EyeOff, Database, Link2, Settings, Key, X } from "lucide-react";
|
|
6
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
7
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
8
|
+
import { AI_ASSISTANT_LAUNCHER_OPEN_EVENT } from "@open-mercato/ui/ai/AiAssistantLauncher";
|
|
9
|
+
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
6
10
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
7
11
|
import { Switch } from "@open-mercato/ui/primitives/switch";
|
|
12
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@open-mercato/ui/primitives/select";
|
|
13
|
+
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
|
|
8
14
|
import { useAiAssistantVisibility } from "../../../frontend/hooks/useAiAssistantVisibility.js";
|
|
9
15
|
import McpConfigDialog from "./McpConfigDialog.js";
|
|
10
16
|
import SessionKeyDialog from "./SessionKeyDialog.js";
|
|
17
|
+
const LEGACY_AI_ASSISTANT_OPEN_EVENT = "om:open-ai-chat";
|
|
11
18
|
async function fetchHealth() {
|
|
12
|
-
const
|
|
13
|
-
if (!
|
|
14
|
-
return
|
|
19
|
+
const result = await apiCall("/api/ai_assistant/health");
|
|
20
|
+
if (!result.ok || !result.result) throw new Error("Failed to fetch health");
|
|
21
|
+
return result.result;
|
|
15
22
|
}
|
|
16
23
|
async function fetchSettings() {
|
|
17
|
-
const
|
|
18
|
-
if (!
|
|
19
|
-
return
|
|
24
|
+
const result = await apiCall("/api/ai_assistant/settings");
|
|
25
|
+
if (!result.ok || !result.result) throw new Error("Failed to fetch settings");
|
|
26
|
+
return result.result;
|
|
20
27
|
}
|
|
21
28
|
async function fetchTools() {
|
|
22
|
-
const
|
|
23
|
-
if (!
|
|
24
|
-
return
|
|
29
|
+
const result = await apiCall("/api/ai_assistant/tools");
|
|
30
|
+
if (!result.ok || !result.result) throw new Error("Failed to fetch tools");
|
|
31
|
+
return result.result;
|
|
25
32
|
}
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
function GlobalOverrideForm({
|
|
34
|
+
availableProviders,
|
|
35
|
+
tenantOverride,
|
|
36
|
+
onSaved
|
|
37
|
+
}) {
|
|
38
|
+
const t = useT();
|
|
39
|
+
const [selectedProviderId, setSelectedProviderId] = React.useState(
|
|
40
|
+
tenantOverride?.providerId ?? ""
|
|
41
|
+
);
|
|
42
|
+
const [selectedModelId, setSelectedModelId] = React.useState(
|
|
43
|
+
tenantOverride?.modelId ?? ""
|
|
44
|
+
);
|
|
45
|
+
const selectedProvider = availableProviders.find((p) => p.id === selectedProviderId);
|
|
46
|
+
const { runMutation: runSaveMutation } = useGuardedMutation({ contextId: "ai-settings-save-override" });
|
|
47
|
+
const { runMutation: runClearMutation } = useGuardedMutation({ contextId: "ai-settings-clear-override" });
|
|
48
|
+
const [isSaving, setIsSaving] = React.useState(false);
|
|
49
|
+
const [isClearing, setIsClearing] = React.useState(false);
|
|
50
|
+
const handleSave = React.useCallback(async () => {
|
|
51
|
+
setIsSaving(true);
|
|
52
|
+
try {
|
|
53
|
+
await runSaveMutation({
|
|
54
|
+
operation: async () => {
|
|
55
|
+
const result = await apiCall("/api/ai_assistant/settings", {
|
|
56
|
+
method: "PUT",
|
|
57
|
+
headers: { "Content-Type": "application/json" },
|
|
58
|
+
body: JSON.stringify({
|
|
59
|
+
providerId: selectedProviderId || null,
|
|
60
|
+
modelId: selectedModelId || null
|
|
61
|
+
})
|
|
62
|
+
});
|
|
63
|
+
if (!result.ok) {
|
|
64
|
+
const err = result.result?.error;
|
|
65
|
+
throw new Error(err ?? t("ai_assistant.settings.saveError", "Failed to save override."));
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
context: {}
|
|
69
|
+
});
|
|
70
|
+
flash(t("ai_assistant.settings.saveSuccess", "Default model override saved."), "success");
|
|
71
|
+
onSaved();
|
|
72
|
+
} finally {
|
|
73
|
+
setIsSaving(false);
|
|
74
|
+
}
|
|
75
|
+
}, [onSaved, runSaveMutation, selectedModelId, selectedProviderId, t]);
|
|
76
|
+
const handleClear = React.useCallback(async () => {
|
|
77
|
+
setIsClearing(true);
|
|
78
|
+
try {
|
|
79
|
+
await runClearMutation({
|
|
80
|
+
operation: async () => {
|
|
81
|
+
const result = await apiCall("/api/ai_assistant/settings", {
|
|
82
|
+
method: "DELETE",
|
|
83
|
+
headers: { "Content-Type": "application/json" },
|
|
84
|
+
body: JSON.stringify({})
|
|
85
|
+
});
|
|
86
|
+
if (!result.ok) {
|
|
87
|
+
const err = result.result?.error;
|
|
88
|
+
throw new Error(err ?? t("ai_assistant.settings.clearError", "Failed to clear override."));
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
context: {}
|
|
92
|
+
});
|
|
93
|
+
flash(t("ai_assistant.settings.clearSuccess", "Default model override cleared."), "success");
|
|
94
|
+
setSelectedProviderId("");
|
|
95
|
+
setSelectedModelId("");
|
|
96
|
+
onSaved();
|
|
97
|
+
} finally {
|
|
98
|
+
setIsClearing(false);
|
|
99
|
+
}
|
|
100
|
+
}, [runClearMutation, onSaved, t]);
|
|
101
|
+
const isBusy = isSaving || isClearing;
|
|
102
|
+
const configuredProviders = availableProviders.filter((p) => p.configured);
|
|
103
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-6", "data-ai-settings-override-form": "", children: [
|
|
104
|
+
/* @__PURE__ */ jsx("h2", { className: "mb-1 text-sm font-semibold", children: t("ai_assistant.settings.defaultOverrideTitle", "Default model override") }),
|
|
105
|
+
/* @__PURE__ */ jsx("p", { className: "mb-4 text-xs text-muted-foreground", children: t(
|
|
106
|
+
"ai_assistant.settings.defaultOverrideDescription",
|
|
107
|
+
"Set a tenant-wide default provider and model. Agents with a per-agent override or specific defaultModel will take precedence."
|
|
108
|
+
) }),
|
|
109
|
+
tenantOverride && (tenantOverride.providerId || tenantOverride.modelId) ? /* @__PURE__ */ jsxs("div", { className: "mb-4 flex items-center gap-2 rounded-md border border-border bg-muted/30 px-3 py-2 text-xs", children: [
|
|
110
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("ai_assistant.settings.currentOverride", "Current override:") }),
|
|
111
|
+
/* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
112
|
+
tenantOverride.providerId ?? "\u2014",
|
|
113
|
+
" / ",
|
|
114
|
+
tenantOverride.modelId ?? "\u2014"
|
|
115
|
+
] }),
|
|
116
|
+
/* @__PURE__ */ jsxs(
|
|
117
|
+
Button,
|
|
118
|
+
{
|
|
119
|
+
type: "button",
|
|
120
|
+
variant: "ghost",
|
|
121
|
+
size: "sm",
|
|
122
|
+
className: "ml-auto h-6 gap-1 text-xs",
|
|
123
|
+
disabled: isBusy,
|
|
124
|
+
onClick: handleClear,
|
|
125
|
+
"data-ai-settings-clear-override": "",
|
|
126
|
+
children: [
|
|
127
|
+
/* @__PURE__ */ jsx(X, { className: "size-3", "aria-hidden": true }),
|
|
128
|
+
t("ai_assistant.settings.clearOverride", "Clear override")
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
] }) : null,
|
|
133
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end gap-3", children: [
|
|
134
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
135
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: t("ai_assistant.settings.providerLabel", "Provider") }),
|
|
136
|
+
/* @__PURE__ */ jsxs(
|
|
137
|
+
Select,
|
|
138
|
+
{
|
|
139
|
+
value: selectedProviderId,
|
|
140
|
+
onValueChange: (val) => {
|
|
141
|
+
setSelectedProviderId(val);
|
|
142
|
+
setSelectedModelId("");
|
|
143
|
+
},
|
|
144
|
+
disabled: isBusy,
|
|
145
|
+
children: [
|
|
146
|
+
/* @__PURE__ */ jsx(
|
|
147
|
+
SelectTrigger,
|
|
148
|
+
{
|
|
149
|
+
className: "w-[180px]",
|
|
150
|
+
"data-ai-settings-provider-select": "",
|
|
151
|
+
children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("ai_assistant.settings.selectProvider", "Select provider") })
|
|
152
|
+
}
|
|
153
|
+
),
|
|
154
|
+
/* @__PURE__ */ jsx(SelectContent, { children: configuredProviders.map((provider) => /* @__PURE__ */ jsx(SelectItem, { value: provider.id, children: provider.name }, provider.id)) })
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
] }),
|
|
159
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
160
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: t("ai_assistant.settings.modelLabel", "Model") }),
|
|
161
|
+
/* @__PURE__ */ jsxs(
|
|
162
|
+
Select,
|
|
163
|
+
{
|
|
164
|
+
value: selectedModelId,
|
|
165
|
+
onValueChange: setSelectedModelId,
|
|
166
|
+
disabled: isBusy || !selectedProviderId,
|
|
167
|
+
children: [
|
|
168
|
+
/* @__PURE__ */ jsx(
|
|
169
|
+
SelectTrigger,
|
|
170
|
+
{
|
|
171
|
+
className: "w-[220px]",
|
|
172
|
+
"data-ai-settings-model-select": "",
|
|
173
|
+
children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("ai_assistant.settings.selectModel", "Select model") })
|
|
174
|
+
}
|
|
175
|
+
),
|
|
176
|
+
/* @__PURE__ */ jsx(SelectContent, { children: (selectedProvider?.defaultModels ?? []).map((model) => /* @__PURE__ */ jsx(SelectItem, { value: model.id, children: model.name }, model.id)) })
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
)
|
|
180
|
+
] }),
|
|
181
|
+
/* @__PURE__ */ jsxs(
|
|
182
|
+
Button,
|
|
183
|
+
{
|
|
184
|
+
type: "button",
|
|
185
|
+
size: "sm",
|
|
186
|
+
disabled: isBusy || !selectedProviderId || !selectedModelId,
|
|
187
|
+
onClick: handleSave,
|
|
188
|
+
"data-ai-settings-save-override": "",
|
|
189
|
+
children: [
|
|
190
|
+
isSaving ? /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 animate-spin", "aria-hidden": true }) : null,
|
|
191
|
+
t("ai_assistant.settings.saveOverride", "Save override")
|
|
192
|
+
]
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
] })
|
|
196
|
+
] });
|
|
197
|
+
}
|
|
198
|
+
function PerAgentOverrideList({
|
|
199
|
+
agents,
|
|
200
|
+
onCleared
|
|
201
|
+
}) {
|
|
202
|
+
const t = useT();
|
|
203
|
+
const { runMutation: runClearAgentMutation } = useGuardedMutation({ contextId: "ai-settings-clear-agent-override" });
|
|
204
|
+
const [clearingAgentId, setClearingAgentId] = React.useState(null);
|
|
205
|
+
const handleClearAgentOverride = React.useCallback(
|
|
206
|
+
async (agentId) => {
|
|
207
|
+
setClearingAgentId(agentId);
|
|
208
|
+
try {
|
|
209
|
+
await runClearAgentMutation({
|
|
210
|
+
operation: async () => {
|
|
211
|
+
const result = await apiCall("/api/ai_assistant/settings", {
|
|
212
|
+
method: "DELETE",
|
|
213
|
+
headers: { "Content-Type": "application/json" },
|
|
214
|
+
body: JSON.stringify({ agentId })
|
|
215
|
+
});
|
|
216
|
+
if (!result.ok) {
|
|
217
|
+
const err = result.result?.error;
|
|
218
|
+
throw new Error(err ?? t("ai_assistant.settings.clearAgentError", "Failed to clear agent override."));
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
context: {}
|
|
222
|
+
});
|
|
223
|
+
flash(t("ai_assistant.settings.clearAgentSuccess", "Agent override cleared."), "success");
|
|
224
|
+
onCleared();
|
|
225
|
+
} finally {
|
|
226
|
+
setClearingAgentId(null);
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
[runClearAgentMutation, onCleared, t]
|
|
230
|
+
);
|
|
231
|
+
if (agents.length === 0) return null;
|
|
232
|
+
const overriddenAgents = agents.filter((agent) => agent.source !== "env_default" && agent.source !== "provider_default");
|
|
233
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-6", "data-ai-settings-agent-overrides": "", children: [
|
|
234
|
+
/* @__PURE__ */ jsx("h2", { className: "mb-1 text-sm font-semibold", children: t("ai_assistant.settings.agentOverridesTitle", "Per-agent model resolution") }),
|
|
235
|
+
/* @__PURE__ */ jsx("p", { className: "mb-4 text-xs text-muted-foreground", children: t(
|
|
236
|
+
"ai_assistant.settings.agentOverridesDescription",
|
|
237
|
+
"Resolved model for each registered agent. Agents with a custom override show a Clear button."
|
|
238
|
+
) }),
|
|
239
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-xs", children: [
|
|
240
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border text-left text-muted-foreground", children: [
|
|
241
|
+
/* @__PURE__ */ jsx("th", { className: "pb-2 pr-4 font-medium", children: t("ai_assistant.settings.agentIdColumn", "Agent") }),
|
|
242
|
+
/* @__PURE__ */ jsx("th", { className: "pb-2 pr-4 font-medium", children: t("ai_assistant.settings.providerColumn", "Provider") }),
|
|
243
|
+
/* @__PURE__ */ jsx("th", { className: "pb-2 pr-4 font-medium", children: t("ai_assistant.settings.modelColumn", "Model") }),
|
|
244
|
+
/* @__PURE__ */ jsx("th", { className: "pb-2 pr-4 font-medium", children: t("ai_assistant.settings.sourceColumn", "Source") }),
|
|
245
|
+
/* @__PURE__ */ jsx("th", { className: "pb-2 font-medium" })
|
|
246
|
+
] }) }),
|
|
247
|
+
/* @__PURE__ */ jsx("tbody", { children: agents.map((agent) => {
|
|
248
|
+
const hasOverride = overriddenAgents.some((a) => a.agentId === agent.agentId);
|
|
249
|
+
return /* @__PURE__ */ jsxs(
|
|
250
|
+
"tr",
|
|
251
|
+
{
|
|
252
|
+
className: "border-b border-border/50 last:border-0",
|
|
253
|
+
"data-ai-settings-agent-row": agent.agentId,
|
|
254
|
+
children: [
|
|
255
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 pr-4 font-mono", children: agent.agentId }),
|
|
256
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 pr-4", children: agent.providerId }),
|
|
257
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 pr-4", children: agent.modelId }),
|
|
258
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 pr-4 text-muted-foreground", children: agent.source }),
|
|
259
|
+
/* @__PURE__ */ jsx("td", { className: "py-2", children: hasOverride ? /* @__PURE__ */ jsxs(
|
|
260
|
+
Button,
|
|
261
|
+
{
|
|
262
|
+
type: "button",
|
|
263
|
+
variant: "ghost",
|
|
264
|
+
size: "sm",
|
|
265
|
+
className: "h-6 gap-1 text-xs",
|
|
266
|
+
disabled: clearingAgentId !== null,
|
|
267
|
+
onClick: () => void handleClearAgentOverride(agent.agentId),
|
|
268
|
+
"data-ai-settings-clear-agent-override": agent.agentId,
|
|
269
|
+
children: [
|
|
270
|
+
/* @__PURE__ */ jsx(X, { className: "size-3", "aria-hidden": true }),
|
|
271
|
+
t("ai_assistant.settings.clearOverride", "Clear override")
|
|
272
|
+
]
|
|
273
|
+
}
|
|
274
|
+
) : null })
|
|
275
|
+
]
|
|
276
|
+
},
|
|
277
|
+
agent.agentId
|
|
278
|
+
);
|
|
279
|
+
}) })
|
|
280
|
+
] }) })
|
|
281
|
+
] });
|
|
282
|
+
}
|
|
283
|
+
function AiAssistantLauncherCard({
|
|
284
|
+
launchMode,
|
|
285
|
+
showVisibilityControl
|
|
286
|
+
}) {
|
|
287
|
+
const t = useT();
|
|
30
288
|
const { isEnabled, toggleEnabled, isLoaded } = useAiAssistantVisibility();
|
|
31
289
|
const openAiAssistant = () => {
|
|
32
|
-
|
|
290
|
+
const eventName = launchMode === "legacy" ? LEGACY_AI_ASSISTANT_OPEN_EVENT : AI_ASSISTANT_LAUNCHER_OPEN_EVENT;
|
|
291
|
+
window.dispatchEvent(new CustomEvent(eventName));
|
|
33
292
|
};
|
|
293
|
+
return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
|
|
294
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
295
|
+
/* @__PURE__ */ jsxs("h2", { className: "flex items-center gap-2 text-lg font-semibold", children: [
|
|
296
|
+
/* @__PURE__ */ jsx(Bot, { className: "size-5" }),
|
|
297
|
+
t("ai_assistant.settings.visibilityTitle", "AI Assistant")
|
|
298
|
+
] }),
|
|
299
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: showVisibilityControl ? isEnabled ? t("ai_assistant.settings.visibilityEnabled", "Visible in header with Cmd+J shortcut enabled.") : t("ai_assistant.settings.visibilityDisabled", "Hidden from header. Enable to show the button and Cmd+J shortcut.") : t("ai_assistant.settings.launchDescription", "Open the AI assistant from this page.") })
|
|
300
|
+
] }),
|
|
301
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
302
|
+
showVisibilityControl ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-md border bg-muted/30 px-4 py-2", children: [
|
|
303
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("ai_assistant.settings.visibilityToggleLabel", "Visibility") }),
|
|
304
|
+
isEnabled ? /* @__PURE__ */ jsx(Eye, { className: "size-4 text-muted-foreground" }) : /* @__PURE__ */ jsx(EyeOff, { className: "size-4 text-muted-foreground" }),
|
|
305
|
+
/* @__PURE__ */ jsx(
|
|
306
|
+
Switch,
|
|
307
|
+
{
|
|
308
|
+
checked: isEnabled,
|
|
309
|
+
onCheckedChange: toggleEnabled,
|
|
310
|
+
disabled: !isLoaded
|
|
311
|
+
}
|
|
312
|
+
)
|
|
313
|
+
] }) : null,
|
|
314
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", onClick: openAiAssistant, size: "default", className: "gap-2", children: [
|
|
315
|
+
/* @__PURE__ */ jsx(Bot, { className: "size-4" }),
|
|
316
|
+
launchMode === "legacy" ? t("ai_assistant.settings.openButton", "Open AI Assistant") : t("ai_assistant.settings.openSelectorButton", "Open AI assistants")
|
|
317
|
+
] })
|
|
318
|
+
] })
|
|
319
|
+
] }) });
|
|
320
|
+
}
|
|
321
|
+
function AiAssistantSettingsContent({
|
|
322
|
+
launchMode,
|
|
323
|
+
showVisibilityControl
|
|
324
|
+
}) {
|
|
325
|
+
const t = useT();
|
|
326
|
+
const queryClient = useQueryClient();
|
|
327
|
+
const [toolsExpanded, setToolsExpanded] = React.useState(false);
|
|
328
|
+
const [mcpConfigOpen, setMcpConfigOpen] = React.useState(false);
|
|
329
|
+
const [sessionKeyOpen, setSessionKeyOpen] = React.useState(false);
|
|
34
330
|
const healthQuery = useQuery({
|
|
35
331
|
queryKey: ["ai-assistant", "health"],
|
|
36
332
|
queryFn: fetchHealth,
|
|
@@ -47,16 +343,19 @@ function AiAssistantSettingsContent() {
|
|
|
47
343
|
queryFn: fetchTools,
|
|
48
344
|
staleTime: 6e4
|
|
49
345
|
});
|
|
346
|
+
const handleOverrideSaved = React.useCallback(() => {
|
|
347
|
+
void queryClient.invalidateQueries({ queryKey: ["ai-assistant", "settings"] });
|
|
348
|
+
}, [queryClient]);
|
|
50
349
|
const isLoading = healthQuery.isLoading || settingsQuery.isLoading || toolsQuery.isLoading;
|
|
51
350
|
if (isLoading) {
|
|
52
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-muted-foreground
|
|
53
|
-
/* @__PURE__ */ jsx(Loader2, { className: "
|
|
54
|
-
"Loading settings..."
|
|
351
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 py-8 text-muted-foreground", children: [
|
|
352
|
+
/* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin" }),
|
|
353
|
+
t("ai_assistant.settings.loading", "Loading settings...")
|
|
55
354
|
] });
|
|
56
355
|
}
|
|
57
356
|
const health = healthQuery.data;
|
|
58
357
|
const settings = settingsQuery.data;
|
|
59
|
-
const tools = toolsQuery.data?.tools
|
|
358
|
+
const tools = toolsQuery.data?.tools ?? [];
|
|
60
359
|
const toolsByModule = tools.reduce((acc, tool) => {
|
|
61
360
|
const module = tool.module || "other";
|
|
62
361
|
if (!acc[module]) acc[module] = [];
|
|
@@ -64,155 +363,175 @@ function AiAssistantSettingsContent() {
|
|
|
64
363
|
return acc;
|
|
65
364
|
}, {});
|
|
66
365
|
const provider = settings?.provider;
|
|
67
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
366
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", "data-ai-assistant-settings": "", children: [
|
|
68
367
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
69
|
-
/* @__PURE__ */ jsxs("h1", { className: "
|
|
70
|
-
/* @__PURE__ */ jsx(Bot, { className: "
|
|
71
|
-
"AI Assistant Settings"
|
|
368
|
+
/* @__PURE__ */ jsxs("h1", { className: "flex items-center gap-2 text-2xl font-bold", children: [
|
|
369
|
+
/* @__PURE__ */ jsx(Bot, { className: "size-6" }),
|
|
370
|
+
t("ai_assistant.settings.pageTitle", "AI Assistant Settings")
|
|
72
371
|
] }),
|
|
73
|
-
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Configure and monitor the AI assistant" })
|
|
372
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: t("ai_assistant.settings.pageDescription", "Configure and monitor the AI assistant") })
|
|
74
373
|
] }),
|
|
75
|
-
/* @__PURE__ */ jsx(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
/* @__PURE__ */ jsx(Bot, { className: "h-4 w-4" }),
|
|
98
|
-
"Open AI Assistant"
|
|
99
|
-
] })
|
|
100
|
-
] })
|
|
101
|
-
] }) }),
|
|
374
|
+
/* @__PURE__ */ jsx(
|
|
375
|
+
AiAssistantLauncherCard,
|
|
376
|
+
{
|
|
377
|
+
launchMode,
|
|
378
|
+
showVisibilityControl
|
|
379
|
+
}
|
|
380
|
+
),
|
|
381
|
+
settings ? /* @__PURE__ */ jsx(
|
|
382
|
+
GlobalOverrideForm,
|
|
383
|
+
{
|
|
384
|
+
availableProviders: settings.availableProviders,
|
|
385
|
+
tenantOverride: settings.tenantOverride,
|
|
386
|
+
onSaved: handleOverrideSaved
|
|
387
|
+
}
|
|
388
|
+
) : null,
|
|
389
|
+
settings?.agents && settings.agents.length > 0 ? /* @__PURE__ */ jsx(
|
|
390
|
+
PerAgentOverrideList,
|
|
391
|
+
{
|
|
392
|
+
agents: settings.agents,
|
|
393
|
+
onCleared: handleOverrideSaved
|
|
394
|
+
}
|
|
395
|
+
) : null,
|
|
102
396
|
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-6", children: [
|
|
103
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between
|
|
104
|
-
/* @__PURE__ */ jsxs("h2", { className: "
|
|
105
|
-
/* @__PURE__ */ jsx(Link2, { className: "
|
|
106
|
-
"Connections"
|
|
397
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4 flex items-center justify-between", children: [
|
|
398
|
+
/* @__PURE__ */ jsxs("h2", { className: "flex items-center gap-2 text-sm font-semibold", children: [
|
|
399
|
+
/* @__PURE__ */ jsx(Link2, { className: "size-4" }),
|
|
400
|
+
t("ai_assistant.settings.connectionsTitle", "Connections")
|
|
107
401
|
] }),
|
|
108
|
-
healthQuery.isFetching && !healthQuery.isLoading
|
|
402
|
+
healthQuery.isFetching && !healthQuery.isLoading ? /* @__PURE__ */ jsx(Loader2, { className: "size-3 animate-spin text-muted-foreground" }) : null
|
|
109
403
|
] }),
|
|
110
404
|
/* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-3", children: [
|
|
111
|
-
/* @__PURE__ */ jsx(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
405
|
+
/* @__PURE__ */ jsx(
|
|
406
|
+
"div",
|
|
407
|
+
{
|
|
408
|
+
className: `rounded-lg border-2 p-4 ${health?.status === "ok" && health.opencode?.healthy ? "border-status-success-border bg-status-success-bg" : "border-destructive/50 bg-destructive/5"}`,
|
|
409
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
|
|
410
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
411
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
412
|
+
/* @__PURE__ */ jsx(Server, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
413
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "OpenCode" })
|
|
414
|
+
] }),
|
|
415
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: health?.status === "ok" && health.opencode?.healthy ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text", children: [
|
|
416
|
+
/* @__PURE__ */ jsx(CheckCircle2, { className: "size-3" }),
|
|
417
|
+
t("ai_assistant.settings.connected", "Connected")
|
|
418
|
+
] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-destructive", children: [
|
|
419
|
+
/* @__PURE__ */ jsx(XCircle, { className: "size-3" }),
|
|
420
|
+
health?.message ?? t("ai_assistant.settings.disconnected", "Disconnected")
|
|
421
|
+
] }) }),
|
|
422
|
+
health?.opencode?.version ? /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: [
|
|
423
|
+
"v",
|
|
424
|
+
health.opencode.version
|
|
425
|
+
] }) : null,
|
|
426
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: health?.url ?? t("ai_assistant.settings.notConfigured", "Not configured") })
|
|
427
|
+
] }),
|
|
428
|
+
health?.status === "ok" && health.opencode?.healthy ? /* @__PURE__ */ jsx("div", { className: "flex size-5 shrink-0 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon", children: /* @__PURE__ */ jsx("svg", { className: "size-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) }) : null
|
|
429
|
+
] })
|
|
430
|
+
}
|
|
431
|
+
),
|
|
132
432
|
(() => {
|
|
133
433
|
const mcpConnected = health?.mcp && Object.values(health.mcp).some((s) => s.status === "connected");
|
|
134
434
|
const mcpConnecting = health?.mcp && Object.values(health.mcp).some((s) => s.status === "connecting");
|
|
135
435
|
const mcpError = health?.mcp && Object.values(health.mcp).find((s) => s.error)?.error;
|
|
136
|
-
return /* @__PURE__ */ jsx(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
436
|
+
return /* @__PURE__ */ jsx(
|
|
437
|
+
"div",
|
|
438
|
+
{
|
|
439
|
+
className: `rounded-lg border-2 p-4 ${mcpConnected ? "border-status-success-border bg-status-success-bg" : mcpConnecting ? "border-status-warning-border bg-status-warning-bg" : "border-destructive/50 bg-destructive/5"}`,
|
|
440
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
|
|
441
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
442
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
443
|
+
/* @__PURE__ */ jsx(Wrench, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
444
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "MCP Server" })
|
|
445
|
+
] }),
|
|
446
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: mcpConnected ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text", children: [
|
|
447
|
+
/* @__PURE__ */ jsx(CheckCircle2, { className: "size-3" }),
|
|
448
|
+
t("ai_assistant.settings.connected", "Connected")
|
|
449
|
+
] }) : mcpConnecting ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-warning-text", children: [
|
|
450
|
+
/* @__PURE__ */ jsx(Loader2, { className: "size-3 animate-spin" }),
|
|
451
|
+
t("ai_assistant.settings.connecting", "Connecting...")
|
|
452
|
+
] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-destructive", children: [
|
|
453
|
+
/* @__PURE__ */ jsx(XCircle, { className: "size-3" }),
|
|
454
|
+
mcpError ?? t("ai_assistant.settings.disconnected", "Disconnected")
|
|
455
|
+
] }) }),
|
|
456
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: health?.mcpUrl ?? t("ai_assistant.settings.notConfigured", "Not configured") })
|
|
457
|
+
] }),
|
|
458
|
+
mcpConnected ? /* @__PURE__ */ jsx("div", { className: "flex size-5 shrink-0 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon", children: /* @__PURE__ */ jsx("svg", { className: "size-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) }) : null
|
|
459
|
+
] })
|
|
460
|
+
}
|
|
461
|
+
);
|
|
156
462
|
})(),
|
|
157
|
-
/* @__PURE__ */ jsx(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
463
|
+
/* @__PURE__ */ jsx(
|
|
464
|
+
"div",
|
|
465
|
+
{
|
|
466
|
+
className: `rounded-lg border-2 p-4 ${health?.search?.available ? "border-status-success-border bg-status-success-bg" : "border-destructive/50 bg-destructive/5"}`,
|
|
467
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
|
|
468
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
469
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
470
|
+
/* @__PURE__ */ jsx(Database, { className: "size-4 shrink-0 text-muted-foreground" }),
|
|
471
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Meilisearch" })
|
|
472
|
+
] }),
|
|
473
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: health?.search?.available ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text", children: [
|
|
474
|
+
/* @__PURE__ */ jsx(CheckCircle2, { className: "size-3" }),
|
|
475
|
+
t("ai_assistant.settings.connected", "Connected")
|
|
476
|
+
] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-destructive", children: [
|
|
477
|
+
/* @__PURE__ */ jsx(XCircle, { className: "size-3" }),
|
|
478
|
+
t("ai_assistant.settings.notAvailable", "Not available")
|
|
479
|
+
] }) }),
|
|
480
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 truncate text-xs text-muted-foreground", children: health?.search?.url ?? t("ai_assistant.settings.notConfigured", "Not configured") })
|
|
481
|
+
] }),
|
|
482
|
+
health?.search?.available ? /* @__PURE__ */ jsx("div", { className: "flex size-5 shrink-0 items-center justify-center rounded-full bg-status-success-bg text-status-success-icon", children: /* @__PURE__ */ jsx("svg", { className: "size-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) }) : null
|
|
483
|
+
] })
|
|
484
|
+
}
|
|
485
|
+
)
|
|
174
486
|
] }),
|
|
175
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-4
|
|
487
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-4 rounded-md border bg-muted/30 p-3", children: [
|
|
176
488
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
|
|
177
|
-
/* @__PURE__ */ jsx(Key, { className: "
|
|
178
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "MCP Authentication:" }),
|
|
179
|
-
settings?.mcpKeyConfigured ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text
|
|
180
|
-
/* @__PURE__ */ jsx(CheckCircle2, { className: "
|
|
181
|
-
"MCP_SERVER_API_KEY configured"
|
|
182
|
-
] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-warning-text
|
|
183
|
-
/* @__PURE__ */ jsx(XCircle, { className: "
|
|
184
|
-
"MCP_SERVER_API_KEY not set"
|
|
489
|
+
/* @__PURE__ */ jsx(Key, { className: "size-4 text-muted-foreground" }),
|
|
490
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: t("ai_assistant.settings.mcpAuthLabel", "MCP Authentication:") }),
|
|
491
|
+
settings?.mcpKeyConfigured ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs text-status-success-text", children: [
|
|
492
|
+
/* @__PURE__ */ jsx(CheckCircle2, { className: "size-3" }),
|
|
493
|
+
t("ai_assistant.settings.mcpKeyConfigured", "MCP_SERVER_API_KEY configured")
|
|
494
|
+
] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs text-status-warning-text", children: [
|
|
495
|
+
/* @__PURE__ */ jsx(XCircle, { className: "size-3" }),
|
|
496
|
+
t("ai_assistant.settings.mcpKeyMissing", "MCP_SERVER_API_KEY not set")
|
|
185
497
|
] })
|
|
186
498
|
] }),
|
|
187
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground
|
|
499
|
+
/* @__PURE__ */ jsx("p", { className: "ml-6 mt-1 text-xs text-muted-foreground", children: t(
|
|
500
|
+
"ai_assistant.settings.mcpAuthNote",
|
|
501
|
+
"Required for AI to access platform tools via MCP server."
|
|
502
|
+
) })
|
|
188
503
|
] }),
|
|
189
|
-
/* @__PURE__ */ jsx("div", { className: "mt-4
|
|
190
|
-
/* @__PURE__ */ jsx(Server, { className: "
|
|
191
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "LLM Provider:" }),
|
|
192
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium", children: provider?.name
|
|
193
|
-
provider?.configured ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-status-success-text
|
|
194
|
-
/* @__PURE__ */ jsx(CheckCircle2, { className: "
|
|
195
|
-
provider?.envKey,
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
provider?.envKey || "ANTHROPIC_API_KEY",
|
|
200
|
-
" not set"
|
|
504
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 rounded-md border bg-muted/30 p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
|
|
505
|
+
/* @__PURE__ */ jsx(Server, { className: "size-4 text-muted-foreground" }),
|
|
506
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: t("ai_assistant.settings.llmProviderLabel", "LLM Provider:") }),
|
|
507
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: provider?.name ?? "Anthropic" }),
|
|
508
|
+
provider?.configured ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs text-status-success-text", children: [
|
|
509
|
+
/* @__PURE__ */ jsx(CheckCircle2, { className: "size-3" }),
|
|
510
|
+
provider?.envKey ? t("ai_assistant.settings.envKeyConfigured", "{{key}} configured", { key: provider.envKey }) : t("ai_assistant.settings.configured", "Configured")
|
|
511
|
+
] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs text-status-warning-text", children: [
|
|
512
|
+
/* @__PURE__ */ jsx(XCircle, { className: "size-3" }),
|
|
513
|
+
t("ai_assistant.settings.envKeyMissing", "{{key}} not set", { key: provider?.envKey ?? "ANTHROPIC_API_KEY" })
|
|
201
514
|
] })
|
|
202
515
|
] }) }),
|
|
203
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground
|
|
516
|
+
/* @__PURE__ */ jsx("p", { className: "mt-4 text-xs text-muted-foreground", children: t(
|
|
517
|
+
"ai_assistant.settings.meilisearchNote",
|
|
518
|
+
"Meilisearch is required for API endpoint discovery. Endpoints are indexed automatically when the MCP server starts."
|
|
519
|
+
) })
|
|
204
520
|
] }),
|
|
205
521
|
/* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-6", children: [
|
|
206
|
-
/* @__PURE__ */ jsxs("h2", { className: "
|
|
207
|
-
/* @__PURE__ */ jsx(Settings, { className: "
|
|
208
|
-
"Developer Tools"
|
|
522
|
+
/* @__PURE__ */ jsxs("h2", { className: "mb-4 flex items-center gap-2 text-sm font-semibold", children: [
|
|
523
|
+
/* @__PURE__ */ jsx(Settings, { className: "size-4" }),
|
|
524
|
+
t("ai_assistant.settings.developerToolsTitle", "Developer Tools")
|
|
209
525
|
] }),
|
|
210
526
|
/* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
|
|
211
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
212
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
213
|
-
/* @__PURE__ */ jsxs("div", { className: "
|
|
214
|
-
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "MCP Configuration" }),
|
|
215
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground
|
|
527
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-muted/30 p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
528
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-md bg-primary/10 p-2", children: /* @__PURE__ */ jsx(Settings, { className: "size-5 text-primary" }) }),
|
|
529
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
530
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: t("ai_assistant.settings.mcpConfigTitle", "MCP Configuration") }),
|
|
531
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t(
|
|
532
|
+
"ai_assistant.settings.mcpConfigDescription",
|
|
533
|
+
"Generate config for Claude Code or other MCP clients."
|
|
534
|
+
) }),
|
|
216
535
|
/* @__PURE__ */ jsx(
|
|
217
536
|
Button,
|
|
218
537
|
{
|
|
@@ -220,16 +539,19 @@ function AiAssistantSettingsContent() {
|
|
|
220
539
|
variant: "outline",
|
|
221
540
|
className: "mt-3",
|
|
222
541
|
onClick: () => setMcpConfigOpen(true),
|
|
223
|
-
children: "Generate MCP Config"
|
|
542
|
+
children: t("ai_assistant.settings.generateMcpConfig", "Generate MCP Config")
|
|
224
543
|
}
|
|
225
544
|
)
|
|
226
545
|
] })
|
|
227
546
|
] }) }),
|
|
228
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
229
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
230
|
-
/* @__PURE__ */ jsxs("div", { className: "
|
|
231
|
-
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "Session API Key" }),
|
|
232
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground
|
|
547
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-muted/30 p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
548
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-md bg-primary/10 p-2", children: /* @__PURE__ */ jsx(Key, { className: "size-5 text-primary" }) }),
|
|
549
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
550
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: t("ai_assistant.settings.sessionKeyTitle", "Session API Key") }),
|
|
551
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t(
|
|
552
|
+
"ai_assistant.settings.sessionKeyDescription",
|
|
553
|
+
"Generate a temporary token for programmatic LLM access. Expires after 2 hours."
|
|
554
|
+
) }),
|
|
233
555
|
/* @__PURE__ */ jsx(
|
|
234
556
|
Button,
|
|
235
557
|
{
|
|
@@ -237,7 +559,7 @@ function AiAssistantSettingsContent() {
|
|
|
237
559
|
variant: "outline",
|
|
238
560
|
className: "mt-3",
|
|
239
561
|
onClick: () => setSessionKeyOpen(true),
|
|
240
|
-
children: "Generate Session Key"
|
|
562
|
+
children: t("ai_assistant.settings.generateSessionKey", "Generate Session Key")
|
|
241
563
|
}
|
|
242
564
|
)
|
|
243
565
|
] })
|
|
@@ -249,7 +571,7 @@ function AiAssistantSettingsContent() {
|
|
|
249
571
|
{
|
|
250
572
|
open: mcpConfigOpen,
|
|
251
573
|
onOpenChange: setMcpConfigOpen,
|
|
252
|
-
mcpUrl: health?.mcpUrl
|
|
574
|
+
mcpUrl: health?.mcpUrl ?? "http://localhost:3001"
|
|
253
575
|
}
|
|
254
576
|
),
|
|
255
577
|
/* @__PURE__ */ jsx(
|
|
@@ -263,31 +585,44 @@ function AiAssistantSettingsContent() {
|
|
|
263
585
|
/* @__PURE__ */ jsxs(
|
|
264
586
|
"button",
|
|
265
587
|
{
|
|
266
|
-
|
|
267
|
-
|
|
588
|
+
type: "button",
|
|
589
|
+
onClick: () => setToolsExpanded((prev) => !prev),
|
|
590
|
+
className: "flex w-full items-center justify-between text-left",
|
|
268
591
|
children: [
|
|
269
|
-
/* @__PURE__ */ jsxs("h2", { className: "
|
|
270
|
-
/* @__PURE__ */ jsx(Wrench, { className: "
|
|
271
|
-
"MCP Tools
|
|
592
|
+
/* @__PURE__ */ jsxs("h2", { className: "flex items-center gap-2 text-sm font-semibold", children: [
|
|
593
|
+
/* @__PURE__ */ jsx(Wrench, { className: "size-4" }),
|
|
594
|
+
t("ai_assistant.settings.mcpToolsTitle", "MCP Tools"),
|
|
595
|
+
" (",
|
|
272
596
|
tools.length,
|
|
273
|
-
"
|
|
597
|
+
" ",
|
|
598
|
+
t("ai_assistant.settings.mcpToolsCount", "tools"),
|
|
599
|
+
")"
|
|
274
600
|
] }),
|
|
275
|
-
toolsExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "
|
|
601
|
+
toolsExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-4 text-muted-foreground" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-4 text-muted-foreground" })
|
|
276
602
|
]
|
|
277
603
|
}
|
|
278
604
|
),
|
|
279
|
-
toolsExpanded
|
|
280
|
-
/* @__PURE__ */ jsx("h3", { className: "text-xs font-medium text-muted-foreground
|
|
281
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-1", children: moduleTools.map((tool) => /* @__PURE__ */ jsxs("div", { className: "
|
|
605
|
+
toolsExpanded ? /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-4", children: Object.entries(toolsByModule).map(([module, moduleTools]) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
606
|
+
/* @__PURE__ */ jsx("h3", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground", children: module }),
|
|
607
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-1", children: moduleTools.map((tool) => /* @__PURE__ */ jsxs("div", { className: "border-l-2 border-muted py-1 pl-2", children: [
|
|
282
608
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: tool.name }),
|
|
283
609
|
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: tool.description })
|
|
284
610
|
] }, tool.name)) })
|
|
285
|
-
] }, module)) })
|
|
611
|
+
] }, module)) }) : null
|
|
286
612
|
] })
|
|
287
613
|
] });
|
|
288
614
|
}
|
|
289
|
-
function AiAssistantSettingsPageClient(
|
|
290
|
-
|
|
615
|
+
function AiAssistantSettingsPageClient({
|
|
616
|
+
launchMode = "selector",
|
|
617
|
+
showVisibilityControl = false
|
|
618
|
+
}) {
|
|
619
|
+
return /* @__PURE__ */ jsx(
|
|
620
|
+
AiAssistantSettingsContent,
|
|
621
|
+
{
|
|
622
|
+
launchMode,
|
|
623
|
+
showVisibilityControl
|
|
624
|
+
}
|
|
625
|
+
);
|
|
291
626
|
}
|
|
292
627
|
var AiAssistantSettingsPageClient_default = AiAssistantSettingsPageClient;
|
|
293
628
|
export {
|