@burtson-labs/bandit-engine 2.1.7 → 2.1.8
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/CHANGELOG.md +14 -0
- package/dist/AdvancedTab-HZTDXFST.mjs +229 -0
- package/dist/AdvancedTab-HZTDXFST.mjs.map +1 -0
- package/dist/CrewSection-YM26YD2N.mjs +12 -0
- package/dist/InstructionsTab-MKOGBQ5L.mjs +195 -0
- package/dist/InstructionsTab-MKOGBQ5L.mjs.map +1 -0
- package/dist/PersonalizationTab-2XHFTYYW.mjs +179 -0
- package/dist/PersonalizationTab-2XHFTYYW.mjs.map +1 -0
- package/dist/{ProjectsPane-E5D72PUG.mjs → ProjectsPane-KE5DGFN4.mjs} +9 -6
- package/dist/ProjectsPane-KE5DGFN4.mjs.map +1 -0
- package/dist/{SchedulesTab-AKJ6WFZV.mjs → SchedulesTab-AM5QP36K.mjs} +7 -5
- package/dist/SchedulesTab-AM5QP36K.mjs.map +1 -0
- package/dist/{aiProviderStore-ANPQVHGD.mjs → aiProviderStore-GH4JZTMW.mjs} +3 -2
- package/dist/chat-D66YM4MB.mjs +26 -0
- package/dist/{chunk-4NUQYUZH.mjs → chunk-2FI2IICG.mjs} +7 -569
- package/dist/chunk-2FI2IICG.mjs.map +1 -0
- package/dist/chunk-2THUYNVU.mjs +1203 -0
- package/dist/chunk-2THUYNVU.mjs.map +1 -0
- package/dist/{chunk-KWOUXBSF.mjs → chunk-5LXCZJLJ.mjs} +5 -213
- package/dist/chunk-5LXCZJLJ.mjs.map +1 -0
- package/dist/chunk-5WCKKD3S.mjs +1742 -0
- package/dist/chunk-5WCKKD3S.mjs.map +1 -0
- package/dist/{chunk-GX4FVZNA.mjs → chunk-DHXSFFLX.mjs} +4 -26
- package/dist/chunk-DHXSFFLX.mjs.map +1 -0
- package/dist/chunk-EKPPIS3X.mjs +336 -0
- package/dist/chunk-EKPPIS3X.mjs.map +1 -0
- package/dist/chunk-FBLITVVY.mjs +5845 -0
- package/dist/chunk-FBLITVVY.mjs.map +1 -0
- package/dist/chunk-H2XUGGKV.mjs +168 -0
- package/dist/chunk-H2XUGGKV.mjs.map +1 -0
- package/dist/chunk-K4AO466X.mjs +570 -0
- package/dist/chunk-K4AO466X.mjs.map +1 -0
- package/dist/chunk-KPT7NNNK.mjs +214 -0
- package/dist/chunk-KPT7NNNK.mjs.map +1 -0
- package/dist/{chunk-SQJ4OKWM.mjs → chunk-LAH6UL3Q.mjs} +10 -1726
- package/dist/chunk-LAH6UL3Q.mjs.map +1 -0
- package/dist/chunk-LC64VSDS.mjs +541 -0
- package/dist/chunk-LC64VSDS.mjs.map +1 -0
- package/dist/{chunk-DH5A2HT2.mjs → chunk-LY3O7UWA.mjs} +45 -1
- package/dist/chunk-LY3O7UWA.mjs.map +1 -0
- package/dist/{chunk-4NHPLHXU.mjs → chunk-WZGDQ4EA.mjs} +5176 -11535
- package/dist/chunk-WZGDQ4EA.mjs.map +1 -0
- package/dist/chunk-Y272M3D5.mjs +28 -0
- package/dist/chunk-Y272M3D5.mjs.map +1 -0
- package/dist/index.d.mts +121 -8
- package/dist/index.d.ts +121 -8
- package/dist/index.js +8732 -7511
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1243 -2243
- package/dist/index.mjs.map +1 -1
- package/dist/{modelStore-YNANSWCN.mjs → modelStore-KO45QAO2.mjs} +3 -2
- package/dist/modelStore-KO45QAO2.mjs.map +1 -0
- package/dist/{public-Tq2Pmw9m.d.ts → public-_W_Zew3C.d.mts} +14 -0
- package/dist/{public-Tq2Pmw9m.d.mts → public-_W_Zew3C.d.ts} +14 -0
- package/dist/public-types.d.mts +1 -1
- package/dist/public-types.d.ts +1 -1
- package/package.json +1 -1
- package/dist/ProjectsPane-E5D72PUG.mjs.map +0 -1
- package/dist/SchedulesTab-AKJ6WFZV.mjs.map +0 -1
- package/dist/chat-MI4IL3WK.mjs +0 -19
- package/dist/chunk-4NHPLHXU.mjs.map +0 -1
- package/dist/chunk-4NUQYUZH.mjs.map +0 -1
- package/dist/chunk-DH5A2HT2.mjs.map +0 -1
- package/dist/chunk-GX4FVZNA.mjs.map +0 -1
- package/dist/chunk-KWOUXBSF.mjs.map +0 -1
- package/dist/chunk-SQJ4OKWM.mjs.map +0 -1
- /package/dist/{aiProviderStore-ANPQVHGD.mjs.map → CrewSection-YM26YD2N.mjs.map} +0 -0
- /package/dist/{chat-MI4IL3WK.mjs.map → aiProviderStore-GH4JZTMW.mjs.map} +0 -0
- /package/dist/{modelStore-YNANSWCN.mjs.map → chat-D66YM4MB.mjs.map} +0 -0
|
@@ -0,0 +1,1203 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useVoiceStore
|
|
3
|
+
} from "./chunk-LC64VSDS.mjs";
|
|
4
|
+
import {
|
|
5
|
+
Refresh,
|
|
6
|
+
Settings
|
|
7
|
+
} from "./chunk-K4AO466X.mjs";
|
|
8
|
+
import {
|
|
9
|
+
ManagementCard,
|
|
10
|
+
ManagementEmptyState
|
|
11
|
+
} from "./chunk-LY3O7UWA.mjs";
|
|
12
|
+
import {
|
|
13
|
+
AIProviderFactory,
|
|
14
|
+
GatewayService,
|
|
15
|
+
useAIProviderStore
|
|
16
|
+
} from "./chunk-DHXSFFLX.mjs";
|
|
17
|
+
import {
|
|
18
|
+
indexedDBService_default
|
|
19
|
+
} from "./chunk-KPT7NNNK.mjs";
|
|
20
|
+
import {
|
|
21
|
+
usePackageSettingsStore
|
|
22
|
+
} from "./chunk-K7SQWDNF.mjs";
|
|
23
|
+
import {
|
|
24
|
+
authenticationService
|
|
25
|
+
} from "./chunk-S3DWWUBD.mjs";
|
|
26
|
+
import {
|
|
27
|
+
debugLogger
|
|
28
|
+
} from "./chunk-NI7BKLC7.mjs";
|
|
29
|
+
|
|
30
|
+
// src/hooks/useGatewayQueries.ts
|
|
31
|
+
import { useMemo } from "react";
|
|
32
|
+
import { lastValueFrom } from "rxjs";
|
|
33
|
+
import { useQuery } from "@tanstack/react-query";
|
|
34
|
+
var useGatewayClient = () => {
|
|
35
|
+
const settings = usePackageSettingsStore((state) => state.settings);
|
|
36
|
+
const gatewayUrl = settings?.gatewayApiUrl;
|
|
37
|
+
const feedbackEmail = settings?.feedbackEmail;
|
|
38
|
+
const service = useMemo(() => {
|
|
39
|
+
if (!gatewayUrl) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return new GatewayService(
|
|
43
|
+
gatewayUrl,
|
|
44
|
+
() => authenticationService.getToken(),
|
|
45
|
+
feedbackEmail
|
|
46
|
+
);
|
|
47
|
+
}, [gatewayUrl, feedbackEmail]);
|
|
48
|
+
return { service, gatewayUrl };
|
|
49
|
+
};
|
|
50
|
+
var useGatewayHealth = (options) => {
|
|
51
|
+
const { service, gatewayUrl } = useGatewayClient();
|
|
52
|
+
const enabled = Boolean(service && gatewayUrl) && (options?.enabled ?? true);
|
|
53
|
+
return useQuery({
|
|
54
|
+
...options,
|
|
55
|
+
queryKey: ["gateway", "health", gatewayUrl],
|
|
56
|
+
queryFn: async () => {
|
|
57
|
+
if (!service) {
|
|
58
|
+
throw new Error("Gateway service is not configured");
|
|
59
|
+
}
|
|
60
|
+
return lastValueFrom(service.getHealth());
|
|
61
|
+
},
|
|
62
|
+
enabled
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
var useGatewayModels = (options) => {
|
|
66
|
+
const { service, gatewayUrl } = useGatewayClient();
|
|
67
|
+
const enabled = Boolean(service && gatewayUrl) && (options?.enabled ?? true);
|
|
68
|
+
return useQuery({
|
|
69
|
+
...options,
|
|
70
|
+
queryKey: ["gateway", "models", gatewayUrl],
|
|
71
|
+
queryFn: async () => {
|
|
72
|
+
if (!service) {
|
|
73
|
+
throw new Error("Gateway service is not configured");
|
|
74
|
+
}
|
|
75
|
+
return lastValueFrom(service.listModels());
|
|
76
|
+
},
|
|
77
|
+
enabled
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
var useGatewayMemory = (options) => {
|
|
81
|
+
const { service, gatewayUrl } = useGatewayClient();
|
|
82
|
+
const enabled = Boolean(service && gatewayUrl) && (options?.enabled ?? true);
|
|
83
|
+
return useQuery({
|
|
84
|
+
...options,
|
|
85
|
+
queryKey: ["gateway", "memory", gatewayUrl],
|
|
86
|
+
queryFn: async () => {
|
|
87
|
+
if (!service) {
|
|
88
|
+
throw new Error("Gateway service is not configured");
|
|
89
|
+
}
|
|
90
|
+
return lastValueFrom(service.getMemory());
|
|
91
|
+
},
|
|
92
|
+
enabled
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// src/management/components/ServiceStatusCard.tsx
|
|
97
|
+
import { useCallback } from "react";
|
|
98
|
+
import { Box, Chip, IconButton, Tooltip, Typography } from "@mui/material";
|
|
99
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
100
|
+
var spinSx = {
|
|
101
|
+
animation: "spin 1s linear infinite",
|
|
102
|
+
"@keyframes spin": {
|
|
103
|
+
"0%": { transform: "rotate(0deg)" },
|
|
104
|
+
"100%": { transform: "rotate(360deg)" }
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var ServiceStatusCard = ({
|
|
108
|
+
packageSettings
|
|
109
|
+
}) => {
|
|
110
|
+
const isTTSSTTAvailable = useVoiceStore((state) => state.isServiceAvailable);
|
|
111
|
+
const gatewayConfigured = Boolean(packageSettings?.gatewayApiUrl);
|
|
112
|
+
const {
|
|
113
|
+
data: gatewayHealth,
|
|
114
|
+
error: gatewayHealthError,
|
|
115
|
+
isLoading: gatewayHealthLoading,
|
|
116
|
+
isFetching: gatewayHealthFetching,
|
|
117
|
+
refetch: refetchGatewayHealth
|
|
118
|
+
} = useGatewayHealth({
|
|
119
|
+
enabled: gatewayConfigured,
|
|
120
|
+
refetchOnWindowFocus: false,
|
|
121
|
+
staleTime: 6e4
|
|
122
|
+
});
|
|
123
|
+
const isGatewayLoading = gatewayHealthLoading || gatewayHealthFetching;
|
|
124
|
+
const gatewayChipLabel = gatewayConfigured ? isGatewayLoading ? "Checking\u2026" : gatewayHealthError ? "Offline" : gatewayHealth ? gatewayHealth.status?.toLowerCase() === "healthy" ? "Online" : "Offline" : "Unknown" : "Not configured";
|
|
125
|
+
const gatewayChipColor = (() => {
|
|
126
|
+
if (!gatewayConfigured) return "default";
|
|
127
|
+
if (gatewayHealthError) return "error";
|
|
128
|
+
if (isGatewayLoading) return "default";
|
|
129
|
+
if (!gatewayHealth) return "warning";
|
|
130
|
+
return gatewayHealth.status?.toLowerCase() === "healthy" ? "success" : "error";
|
|
131
|
+
})();
|
|
132
|
+
const handleGatewayStatusRefresh = useCallback(() => {
|
|
133
|
+
if (!gatewayConfigured) return;
|
|
134
|
+
refetchGatewayHealth();
|
|
135
|
+
}, [gatewayConfigured, refetchGatewayHealth]);
|
|
136
|
+
const voiceChip = /* @__PURE__ */ jsx(
|
|
137
|
+
Chip,
|
|
138
|
+
{
|
|
139
|
+
label: isTTSSTTAvailable ? "Available" : packageSettings?.gatewayApiUrl ? "Unavailable" : "Not configured",
|
|
140
|
+
color: isTTSSTTAvailable ? "success" : packageSettings?.gatewayApiUrl ? "warning" : "default",
|
|
141
|
+
size: "small"
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
const row = (label, chip) => /* @__PURE__ */ jsxs(
|
|
145
|
+
Box,
|
|
146
|
+
{
|
|
147
|
+
sx: {
|
|
148
|
+
display: "flex",
|
|
149
|
+
alignItems: "center",
|
|
150
|
+
justifyContent: "space-between",
|
|
151
|
+
flexWrap: "wrap",
|
|
152
|
+
gap: 1
|
|
153
|
+
},
|
|
154
|
+
children: [
|
|
155
|
+
/* @__PURE__ */ jsx(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: label }),
|
|
156
|
+
chip
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
return /* @__PURE__ */ jsx(
|
|
161
|
+
ManagementCard,
|
|
162
|
+
{
|
|
163
|
+
title: "Service status",
|
|
164
|
+
description: "The services this deployment is configured with. Your administrator enables or configures them.",
|
|
165
|
+
children: /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", flexDirection: "column", gap: 1.5 }, children: [
|
|
166
|
+
row(
|
|
167
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { fontWeight: 600 }, children: "Text-to-speech (TTS)" }),
|
|
168
|
+
voiceChip
|
|
169
|
+
),
|
|
170
|
+
row(
|
|
171
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { fontWeight: 600 }, children: "Speech-to-text (STT)" }),
|
|
172
|
+
voiceChip
|
|
173
|
+
),
|
|
174
|
+
row(
|
|
175
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
176
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", sx: { fontWeight: 600 }, children: "Gateway/MCP" }),
|
|
177
|
+
gatewayConfigured && /* @__PURE__ */ jsx(Tooltip, { title: "Refresh gateway status", placement: "top", children: /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(
|
|
178
|
+
IconButton,
|
|
179
|
+
{
|
|
180
|
+
size: "small",
|
|
181
|
+
onClick: handleGatewayStatusRefresh,
|
|
182
|
+
disabled: isGatewayLoading,
|
|
183
|
+
"aria-label": "Refresh gateway status",
|
|
184
|
+
sx: { width: { xs: 44, sm: 28 }, height: { xs: 44, sm: 28 } },
|
|
185
|
+
children: /* @__PURE__ */ jsx(
|
|
186
|
+
Refresh,
|
|
187
|
+
{
|
|
188
|
+
fontSize: "small",
|
|
189
|
+
sx: isGatewayLoading ? spinSx : void 0
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
) }) })
|
|
194
|
+
] }),
|
|
195
|
+
/* @__PURE__ */ jsx(Chip, { label: gatewayChipLabel, color: gatewayChipColor, size: "small" })
|
|
196
|
+
),
|
|
197
|
+
gatewayConfigured && gatewayHealthError && /* @__PURE__ */ jsxs(Box, { sx: { display: "flex", flexDirection: "column", gap: 0.75 }, children: [
|
|
198
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "error", children: "Couldn't reach the gateway. Use refresh to check again." }),
|
|
199
|
+
gatewayHealthError.message && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "text.secondary", children: gatewayHealthError.message })
|
|
200
|
+
] })
|
|
201
|
+
] })
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// src/management/components/ProviderTab.tsx
|
|
207
|
+
import { useState, useEffect, useCallback as useCallback2, useRef } from "react";
|
|
208
|
+
import {
|
|
209
|
+
Box as Box2,
|
|
210
|
+
Typography as Typography2,
|
|
211
|
+
Paper,
|
|
212
|
+
Button,
|
|
213
|
+
TextField,
|
|
214
|
+
MenuItem,
|
|
215
|
+
Chip as Chip2,
|
|
216
|
+
Snackbar,
|
|
217
|
+
Alert,
|
|
218
|
+
CircularProgress,
|
|
219
|
+
Stack
|
|
220
|
+
} from "@mui/material";
|
|
221
|
+
|
|
222
|
+
// src/services/ai-provider-init.service.ts
|
|
223
|
+
var sessionTokenFactory = (label) => () => {
|
|
224
|
+
const token = authenticationService.getToken();
|
|
225
|
+
debugLogger.info(`AIProviderInit: ${label}`, { hasToken: !!token });
|
|
226
|
+
return token;
|
|
227
|
+
};
|
|
228
|
+
var AIProviderInitService = class _AIProviderInitService {
|
|
229
|
+
static instance;
|
|
230
|
+
constructor() {
|
|
231
|
+
}
|
|
232
|
+
static getInstance() {
|
|
233
|
+
if (!_AIProviderInitService.instance) {
|
|
234
|
+
_AIProviderInitService.instance = new _AIProviderInitService();
|
|
235
|
+
}
|
|
236
|
+
return _AIProviderInitService.instance;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Initialize AI provider from package settings
|
|
240
|
+
* Provides backward compatibility with existing Ollama settings
|
|
241
|
+
*/
|
|
242
|
+
async initializeFromSettings() {
|
|
243
|
+
const settings = usePackageSettingsStore.getState().settings;
|
|
244
|
+
if (!settings) {
|
|
245
|
+
debugLogger.warn("No package settings found, cannot initialize AI provider");
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
let providerConfig;
|
|
249
|
+
debugLogger.info("AI Provider Init: Starting initialization", {
|
|
250
|
+
hasSettings: !!settings,
|
|
251
|
+
hasAiProvider: !!settings.aiProvider,
|
|
252
|
+
ollamaUrl: settings.ollamaUrl
|
|
253
|
+
});
|
|
254
|
+
const isPlaygroundEnvironment = settings.playgroundMode === true || settings.aiProvider?.type === "playground" /* PLAYGROUND */ || (settings.gatewayApiUrl?.toLowerCase()?.startsWith("playground://") ?? false) || typeof window !== "undefined" && window.location.pathname.includes("/playground");
|
|
255
|
+
if (isPlaygroundEnvironment) {
|
|
256
|
+
debugLogger.info(
|
|
257
|
+
"AI Provider Init: Playground environment detected, bypassing saved provider config"
|
|
258
|
+
);
|
|
259
|
+
} else {
|
|
260
|
+
try {
|
|
261
|
+
const savedConfig = await indexedDBService_default.get(
|
|
262
|
+
"banditConfig",
|
|
263
|
+
1,
|
|
264
|
+
"config",
|
|
265
|
+
"aiProvider",
|
|
266
|
+
[{ name: "config", keyPath: "id" }]
|
|
267
|
+
);
|
|
268
|
+
if (savedConfig) {
|
|
269
|
+
debugLogger.info("AI Provider Init: Found saved config in IndexedDB", {
|
|
270
|
+
type: savedConfig.type
|
|
271
|
+
});
|
|
272
|
+
const { id: _id, ...configWithoutId } = savedConfig;
|
|
273
|
+
providerConfig = { ...configWithoutId };
|
|
274
|
+
if (providerConfig.type === "anthropic" /* ANTHROPIC */) {
|
|
275
|
+
providerConfig = this.convertAnthropicConfig(
|
|
276
|
+
providerConfig,
|
|
277
|
+
settings?.gatewayApiUrl
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
providerConfig = this.ensureTokenFactory(providerConfig);
|
|
281
|
+
try {
|
|
282
|
+
const { createProvider } = useAIProviderStore.getState();
|
|
283
|
+
createProvider(providerConfig);
|
|
284
|
+
const provider = useAIProviderStore.getState().provider;
|
|
285
|
+
if (provider) {
|
|
286
|
+
try {
|
|
287
|
+
await provider.validateServiceAvailability({ timeoutMs: 5e3 });
|
|
288
|
+
debugLogger.info(
|
|
289
|
+
`AI Provider initialized and validated from IndexedDB: ${providerConfig.type}`
|
|
290
|
+
);
|
|
291
|
+
} catch (validationError) {
|
|
292
|
+
debugLogger.warn(`AI Provider created but validation failed`, {
|
|
293
|
+
error: validationError
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return;
|
|
298
|
+
} catch (error) {
|
|
299
|
+
debugLogger.error(
|
|
300
|
+
"Failed to initialize saved provider config, falling back to package settings",
|
|
301
|
+
{ error }
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
debugLogger.info(
|
|
306
|
+
"AI Provider Init: No saved config found, using package settings"
|
|
307
|
+
);
|
|
308
|
+
} catch (error) {
|
|
309
|
+
debugLogger.warn(
|
|
310
|
+
"AI Provider Init: Failed to load from IndexedDB, using package settings",
|
|
311
|
+
{ error }
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (settings.aiProvider) {
|
|
316
|
+
providerConfig = { ...settings.aiProvider };
|
|
317
|
+
if (providerConfig.type === "anthropic" /* ANTHROPIC */) {
|
|
318
|
+
providerConfig = this.convertAnthropicConfig(
|
|
319
|
+
providerConfig,
|
|
320
|
+
settings.gatewayApiUrl
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
providerConfig = this.ensureTokenFactory(providerConfig);
|
|
324
|
+
debugLogger.info("Using explicit AI provider config", providerConfig);
|
|
325
|
+
} else {
|
|
326
|
+
providerConfig = {
|
|
327
|
+
type: "ollama" /* OLLAMA */,
|
|
328
|
+
baseUrl: settings.ollamaUrl,
|
|
329
|
+
tokenFactory: sessionTokenFactory("Token factory called")
|
|
330
|
+
};
|
|
331
|
+
debugLogger.info("Using legacy Ollama config", providerConfig);
|
|
332
|
+
}
|
|
333
|
+
try {
|
|
334
|
+
const { createProvider } = useAIProviderStore.getState();
|
|
335
|
+
createProvider(providerConfig);
|
|
336
|
+
const provider = useAIProviderStore.getState().provider;
|
|
337
|
+
if (provider) {
|
|
338
|
+
try {
|
|
339
|
+
await provider.validateServiceAvailability({ timeoutMs: 5e3 });
|
|
340
|
+
debugLogger.info(
|
|
341
|
+
`AI Provider initialized and validated: ${providerConfig.type}`
|
|
342
|
+
);
|
|
343
|
+
} catch (validationError) {
|
|
344
|
+
debugLogger.warn(`AI Provider created but validation failed:`, {
|
|
345
|
+
error: validationError
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
} catch (error) {
|
|
350
|
+
debugLogger.error("Failed to initialize AI provider:", { error });
|
|
351
|
+
if (providerConfig.type !== "ollama" /* OLLAMA */) {
|
|
352
|
+
try {
|
|
353
|
+
const fallbackConfig = {
|
|
354
|
+
type: "ollama" /* OLLAMA */,
|
|
355
|
+
baseUrl: settings.ollamaUrl || "http://localhost:11434",
|
|
356
|
+
tokenFactory: sessionTokenFactory("Fallback tokenFactory")
|
|
357
|
+
};
|
|
358
|
+
const { createProvider } = useAIProviderStore.getState();
|
|
359
|
+
createProvider(fallbackConfig);
|
|
360
|
+
debugLogger.info("Fallback to Ollama provider successful");
|
|
361
|
+
} catch (fallbackError) {
|
|
362
|
+
debugLogger.error("Failed to initialize fallback Ollama provider:", {
|
|
363
|
+
error: fallbackError
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
} else {
|
|
367
|
+
try {
|
|
368
|
+
const localFallbackConfig = {
|
|
369
|
+
type: "ollama" /* OLLAMA */,
|
|
370
|
+
baseUrl: "http://localhost:11434",
|
|
371
|
+
tokenFactory: sessionTokenFactory("Local fallback tokenFactory")
|
|
372
|
+
};
|
|
373
|
+
const { createProvider } = useAIProviderStore.getState();
|
|
374
|
+
createProvider(localFallbackConfig);
|
|
375
|
+
debugLogger.info("Fallback to localhost Ollama provider successful");
|
|
376
|
+
} catch (localFallbackError) {
|
|
377
|
+
debugLogger.error("All provider initialization attempts failed:", {
|
|
378
|
+
error: localFallbackError
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Switch to a different AI provider
|
|
386
|
+
*/
|
|
387
|
+
switchProvider(config) {
|
|
388
|
+
try {
|
|
389
|
+
const normalizedConfig = this.ensureTokenFactory({ ...config });
|
|
390
|
+
const { switchProvider } = useAIProviderStore.getState();
|
|
391
|
+
switchProvider(normalizedConfig);
|
|
392
|
+
debugLogger.info(`Switched to AI provider: ${normalizedConfig.type}`);
|
|
393
|
+
} catch (error) {
|
|
394
|
+
debugLogger.error("Failed to switch AI provider:", { error });
|
|
395
|
+
throw error;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Get the current provider type
|
|
400
|
+
*/
|
|
401
|
+
getCurrentProviderType() {
|
|
402
|
+
const provider = useAIProviderStore.getState().provider;
|
|
403
|
+
return provider ? provider.getProviderType() : null;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Check if a provider is initialized
|
|
407
|
+
*/
|
|
408
|
+
isProviderInitialized() {
|
|
409
|
+
return useAIProviderStore.getState().provider !== null;
|
|
410
|
+
}
|
|
411
|
+
convertAnthropicConfig(config, gatewayUrl) {
|
|
412
|
+
if (config.type !== "anthropic" /* ANTHROPIC */) {
|
|
413
|
+
return config;
|
|
414
|
+
}
|
|
415
|
+
const defaultModel = typeof config.defaultModel === "string" && config.defaultModel.trim() ? config.defaultModel.trim() : "claude-3-5-sonnet-latest";
|
|
416
|
+
const normalized = {
|
|
417
|
+
type: "gateway" /* GATEWAY */,
|
|
418
|
+
gatewayUrl: gatewayUrl || config.gatewayUrl || "",
|
|
419
|
+
provider: "anthropic",
|
|
420
|
+
defaultModel,
|
|
421
|
+
tokenFactory: config.tokenFactory
|
|
422
|
+
};
|
|
423
|
+
debugLogger.info(
|
|
424
|
+
"AI Provider Init: Converted direct Anthropic provider to gateway configuration"
|
|
425
|
+
);
|
|
426
|
+
return normalized;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Ensure providers that require auth have a token factory configured.
|
|
430
|
+
* Handles both UI auth tokens and API key scenarios.
|
|
431
|
+
*/
|
|
432
|
+
ensureTokenFactory(config) {
|
|
433
|
+
if (config.type === "ollama" /* OLLAMA */ || config.type === "gateway" /* GATEWAY */) {
|
|
434
|
+
const existingFactory = config.tokenFactory;
|
|
435
|
+
if (existingFactory) {
|
|
436
|
+
return config;
|
|
437
|
+
}
|
|
438
|
+
if (typeof config.apiKey === "string" && config.apiKey.trim() !== "") {
|
|
439
|
+
const key = config.apiKey.trim();
|
|
440
|
+
config.tokenFactory = () => key;
|
|
441
|
+
debugLogger.info("AIProviderInit: Using API key for token factory", {
|
|
442
|
+
type: config.type,
|
|
443
|
+
hasKey: true
|
|
444
|
+
});
|
|
445
|
+
return config;
|
|
446
|
+
}
|
|
447
|
+
config.tokenFactory = sessionTokenFactory("Token factory resolved auth token");
|
|
448
|
+
}
|
|
449
|
+
return config;
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
var aiProviderInitService = AIProviderInitService.getInstance();
|
|
453
|
+
|
|
454
|
+
// src/management/components/ProviderTab.tsx
|
|
455
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
456
|
+
var ProviderTab = () => {
|
|
457
|
+
const { provider: currentProvider, config: currentProviderConfig } = useAIProviderStore();
|
|
458
|
+
const { settings: packageSettings } = usePackageSettingsStore();
|
|
459
|
+
const getSuggestedModel = useCallback2(
|
|
460
|
+
(type) => {
|
|
461
|
+
const configuredDefault = packageSettings?.defaultModel?.trim();
|
|
462
|
+
if (configuredDefault) {
|
|
463
|
+
return configuredDefault;
|
|
464
|
+
}
|
|
465
|
+
switch (type) {
|
|
466
|
+
case "openai" /* OPENAI */:
|
|
467
|
+
return "gpt-4o-mini";
|
|
468
|
+
case "xai" /* XAI */:
|
|
469
|
+
return "grok-beta";
|
|
470
|
+
case "bandit" /* BANDIT */:
|
|
471
|
+
return "bandit-core-1";
|
|
472
|
+
default:
|
|
473
|
+
return "";
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
[packageSettings?.defaultModel]
|
|
477
|
+
);
|
|
478
|
+
const applyDefaultModel = useCallback2(
|
|
479
|
+
(config) => {
|
|
480
|
+
const normalized = { ...config };
|
|
481
|
+
const trimmed = typeof normalized.defaultModel === "string" ? normalized.defaultModel.trim() : void 0;
|
|
482
|
+
const requiresModel = normalized.type === "openai" /* OPENAI */ || normalized.type === "xai" /* XAI */ || normalized.type === "bandit" /* BANDIT */;
|
|
483
|
+
if (trimmed) {
|
|
484
|
+
normalized.defaultModel = trimmed;
|
|
485
|
+
return normalized;
|
|
486
|
+
}
|
|
487
|
+
if (!requiresModel) {
|
|
488
|
+
delete normalized.defaultModel;
|
|
489
|
+
return normalized;
|
|
490
|
+
}
|
|
491
|
+
const suggestion = getSuggestedModel(normalized.type);
|
|
492
|
+
if (suggestion) {
|
|
493
|
+
normalized.defaultModel = suggestion;
|
|
494
|
+
} else {
|
|
495
|
+
delete normalized.defaultModel;
|
|
496
|
+
}
|
|
497
|
+
return normalized;
|
|
498
|
+
},
|
|
499
|
+
[getSuggestedModel]
|
|
500
|
+
);
|
|
501
|
+
const sanitizeConfigForSave = useCallback2(
|
|
502
|
+
(config) => {
|
|
503
|
+
const sanitized = { ...config };
|
|
504
|
+
if (typeof sanitized.defaultModel === "string") {
|
|
505
|
+
const trimmed = sanitized.defaultModel.trim();
|
|
506
|
+
sanitized.defaultModel = trimmed || void 0;
|
|
507
|
+
}
|
|
508
|
+
if (typeof sanitized.apiKey === "string") {
|
|
509
|
+
const trimmedKey = sanitized.apiKey.trim();
|
|
510
|
+
sanitized.apiKey = trimmedKey || void 0;
|
|
511
|
+
}
|
|
512
|
+
return sanitized;
|
|
513
|
+
},
|
|
514
|
+
[]
|
|
515
|
+
);
|
|
516
|
+
const [providerConfig, setProviderConfig] = useState({
|
|
517
|
+
type: "gateway",
|
|
518
|
+
gatewayUrl: packageSettings?.gatewayApiUrl || "",
|
|
519
|
+
provider: "bandit"
|
|
520
|
+
});
|
|
521
|
+
const [saveResult, setSaveResult] = useState({ state: "idle" });
|
|
522
|
+
const [testResult, setTestResult] = useState({ state: "idle" });
|
|
523
|
+
const providerTypeRef = useRef(null);
|
|
524
|
+
const formRef = useRef(null);
|
|
525
|
+
const revealProviderForm = () => {
|
|
526
|
+
formRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
527
|
+
providerTypeRef.current?.focus();
|
|
528
|
+
};
|
|
529
|
+
const [snackbarMessage, setSnackbarMessage] = useState("");
|
|
530
|
+
const [showSnackbar, setShowSnackbar] = useState(false);
|
|
531
|
+
const [snackbarSeverity, setSnackbarSeverity] = useState(
|
|
532
|
+
"success"
|
|
533
|
+
);
|
|
534
|
+
const saveProviderConfigToDB = async (config) => {
|
|
535
|
+
try {
|
|
536
|
+
const { tokenFactory: _tokenFactory, ...persistableConfig } = config;
|
|
537
|
+
const serializableConfig = {
|
|
538
|
+
...persistableConfig,
|
|
539
|
+
id: "aiProvider"
|
|
540
|
+
};
|
|
541
|
+
await indexedDBService_default.put(
|
|
542
|
+
"banditConfig",
|
|
543
|
+
1,
|
|
544
|
+
"config",
|
|
545
|
+
serializableConfig,
|
|
546
|
+
[{ name: "config", keyPath: "id" }]
|
|
547
|
+
);
|
|
548
|
+
debugLogger.info("Provider configuration saved to IndexedDB", {
|
|
549
|
+
type: config.type
|
|
550
|
+
});
|
|
551
|
+
} catch (error) {
|
|
552
|
+
debugLogger.error("Failed to save provider config to IndexedDB:", { error });
|
|
553
|
+
throw error;
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
const loadProviderConfigFromDB = async () => {
|
|
557
|
+
try {
|
|
558
|
+
const config = await indexedDBService_default.get(
|
|
559
|
+
"banditConfig",
|
|
560
|
+
1,
|
|
561
|
+
"config",
|
|
562
|
+
"aiProvider",
|
|
563
|
+
[{ name: "config", keyPath: "id" }]
|
|
564
|
+
);
|
|
565
|
+
if (config) {
|
|
566
|
+
debugLogger.info("Provider configuration loaded from IndexedDB", {
|
|
567
|
+
type: config.type
|
|
568
|
+
});
|
|
569
|
+
const { id: _id, ...configWithoutId } = config;
|
|
570
|
+
return configWithoutId;
|
|
571
|
+
}
|
|
572
|
+
} catch (error) {
|
|
573
|
+
debugLogger.error("Failed to load provider config from IndexedDB:", { error });
|
|
574
|
+
}
|
|
575
|
+
return null;
|
|
576
|
+
};
|
|
577
|
+
const convertAnthropicConfig = useCallback2(
|
|
578
|
+
(config) => {
|
|
579
|
+
if (!config) return null;
|
|
580
|
+
if (config.type !== "anthropic" /* ANTHROPIC */) {
|
|
581
|
+
return config;
|
|
582
|
+
}
|
|
583
|
+
const gatewayUrl = config.gatewayUrl || packageSettings?.gatewayApiUrl || "";
|
|
584
|
+
const defaultModel = typeof config.defaultModel === "string" && config.defaultModel.trim() ? config.defaultModel.trim() : "claude-3-5-sonnet-latest";
|
|
585
|
+
const converted = {
|
|
586
|
+
type: "gateway" /* GATEWAY */,
|
|
587
|
+
gatewayUrl,
|
|
588
|
+
provider: "anthropic",
|
|
589
|
+
defaultModel,
|
|
590
|
+
tokenFactory: config.tokenFactory
|
|
591
|
+
};
|
|
592
|
+
return converted;
|
|
593
|
+
},
|
|
594
|
+
[packageSettings?.gatewayApiUrl]
|
|
595
|
+
);
|
|
596
|
+
useEffect(() => {
|
|
597
|
+
const initializeProviderConfig = async () => {
|
|
598
|
+
const savedConfig = await loadProviderConfigFromDB();
|
|
599
|
+
if (savedConfig) {
|
|
600
|
+
const normalized = convertAnthropicConfig(savedConfig) || savedConfig;
|
|
601
|
+
setProviderConfig(applyDefaultModel(normalized));
|
|
602
|
+
} else if (currentProviderConfig) {
|
|
603
|
+
const normalized = convertAnthropicConfig(currentProviderConfig) || currentProviderConfig;
|
|
604
|
+
setProviderConfig(applyDefaultModel(normalized));
|
|
605
|
+
} else if (packageSettings?.aiProvider) {
|
|
606
|
+
const normalized = convertAnthropicConfig(packageSettings.aiProvider) || packageSettings.aiProvider;
|
|
607
|
+
setProviderConfig(applyDefaultModel(normalized));
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
initializeProviderConfig();
|
|
611
|
+
}, [applyDefaultModel, convertAnthropicConfig, currentProviderConfig, packageSettings]);
|
|
612
|
+
const showMessage = (message, severity) => {
|
|
613
|
+
setSnackbarMessage(message);
|
|
614
|
+
setSnackbarSeverity(severity);
|
|
615
|
+
setShowSnackbar(true);
|
|
616
|
+
};
|
|
617
|
+
const handleProviderTypeChange = (type) => {
|
|
618
|
+
setSaveResult({ state: "idle" });
|
|
619
|
+
setTestResult({ state: "idle" });
|
|
620
|
+
const baseConfig = { type };
|
|
621
|
+
switch (type) {
|
|
622
|
+
case "ollama" /* OLLAMA */:
|
|
623
|
+
setProviderConfig(
|
|
624
|
+
applyDefaultModel({
|
|
625
|
+
...baseConfig,
|
|
626
|
+
baseUrl: "http://localhost:11434"
|
|
627
|
+
})
|
|
628
|
+
);
|
|
629
|
+
break;
|
|
630
|
+
case "openai" /* OPENAI */:
|
|
631
|
+
setProviderConfig(
|
|
632
|
+
applyDefaultModel({
|
|
633
|
+
...baseConfig,
|
|
634
|
+
baseUrl: "https://api.openai.com/v1",
|
|
635
|
+
apiKey: ""
|
|
636
|
+
})
|
|
637
|
+
);
|
|
638
|
+
break;
|
|
639
|
+
case "azure-openai" /* AZURE_OPENAI */:
|
|
640
|
+
setProviderConfig(
|
|
641
|
+
applyDefaultModel({
|
|
642
|
+
...baseConfig,
|
|
643
|
+
baseUrl: "",
|
|
644
|
+
apiKey: "",
|
|
645
|
+
apiVersion: "2024-02-01",
|
|
646
|
+
deploymentName: ""
|
|
647
|
+
})
|
|
648
|
+
);
|
|
649
|
+
break;
|
|
650
|
+
case "anthropic" /* ANTHROPIC */:
|
|
651
|
+
showMessage(
|
|
652
|
+
"Anthropic is only available via the Gateway provider. Please configure Gateway and choose Anthropic as the backend.",
|
|
653
|
+
"error"
|
|
654
|
+
);
|
|
655
|
+
setProviderConfig(
|
|
656
|
+
applyDefaultModel({
|
|
657
|
+
type: "gateway" /* GATEWAY */,
|
|
658
|
+
gatewayUrl: packageSettings?.gatewayApiUrl || "",
|
|
659
|
+
provider: "anthropic",
|
|
660
|
+
defaultModel: "claude-3-5-sonnet-latest"
|
|
661
|
+
})
|
|
662
|
+
);
|
|
663
|
+
break;
|
|
664
|
+
case "xai" /* XAI */:
|
|
665
|
+
setProviderConfig(
|
|
666
|
+
applyDefaultModel({
|
|
667
|
+
...baseConfig,
|
|
668
|
+
baseUrl: "https://api.x.ai/v1",
|
|
669
|
+
apiKey: ""
|
|
670
|
+
})
|
|
671
|
+
);
|
|
672
|
+
break;
|
|
673
|
+
case "bandit" /* BANDIT */:
|
|
674
|
+
setProviderConfig(
|
|
675
|
+
applyDefaultModel({
|
|
676
|
+
...baseConfig,
|
|
677
|
+
baseUrl: "https://api.burtson.ai",
|
|
678
|
+
apiKey: "",
|
|
679
|
+
defaultModel: "bandit-core-1"
|
|
680
|
+
})
|
|
681
|
+
);
|
|
682
|
+
break;
|
|
683
|
+
case "gateway" /* GATEWAY */:
|
|
684
|
+
setProviderConfig(
|
|
685
|
+
applyDefaultModel({
|
|
686
|
+
...baseConfig,
|
|
687
|
+
gatewayUrl: packageSettings?.gatewayApiUrl || "",
|
|
688
|
+
provider: "bandit"
|
|
689
|
+
})
|
|
690
|
+
);
|
|
691
|
+
break;
|
|
692
|
+
case "playground" /* PLAYGROUND */:
|
|
693
|
+
setProviderConfig(
|
|
694
|
+
applyDefaultModel({
|
|
695
|
+
...baseConfig
|
|
696
|
+
})
|
|
697
|
+
);
|
|
698
|
+
break;
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
const handleSaveProviderConfig = async () => {
|
|
702
|
+
setSaveResult({ state: "pending" });
|
|
703
|
+
try {
|
|
704
|
+
const normalizedConfigIntermediate = sanitizeConfigForSave(providerConfig);
|
|
705
|
+
const normalizedConfig = convertAnthropicConfig(normalizedConfigIntermediate) || normalizedConfigIntermediate;
|
|
706
|
+
const requiresModel = normalizedConfig.type === "openai" /* OPENAI */ || normalizedConfig.type === "xai" /* XAI */ || normalizedConfig.type === "bandit" /* BANDIT */;
|
|
707
|
+
if (requiresModel && !normalizedConfig.defaultModel) {
|
|
708
|
+
setSaveResult({
|
|
709
|
+
state: "error",
|
|
710
|
+
message: "Not saved. Enter a default model ID for this provider."
|
|
711
|
+
});
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
const isValid = AIProviderFactory.validateConfig(normalizedConfig);
|
|
715
|
+
if (!isValid) {
|
|
716
|
+
setSaveResult({
|
|
717
|
+
state: "error",
|
|
718
|
+
message: "Not saved. Some required fields are missing or invalid."
|
|
719
|
+
});
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
await saveProviderConfigToDB(normalizedConfig);
|
|
723
|
+
await aiProviderInitService.switchProvider(normalizedConfig);
|
|
724
|
+
if (packageSettings) {
|
|
725
|
+
const updatedSettings = {
|
|
726
|
+
...packageSettings,
|
|
727
|
+
aiProvider: normalizedConfig
|
|
728
|
+
};
|
|
729
|
+
if (normalizedConfig.defaultModel) {
|
|
730
|
+
updatedSettings.defaultModel = normalizedConfig.defaultModel;
|
|
731
|
+
}
|
|
732
|
+
usePackageSettingsStore.setState({ settings: updatedSettings });
|
|
733
|
+
}
|
|
734
|
+
setProviderConfig(applyDefaultModel(normalizedConfig));
|
|
735
|
+
setSaveResult({ state: "success", message: "Saved. Chat now uses this provider." });
|
|
736
|
+
debugLogger.info("Provider configuration saved and switched", {
|
|
737
|
+
type: normalizedConfig.type
|
|
738
|
+
});
|
|
739
|
+
} catch (error) {
|
|
740
|
+
debugLogger.error("Failed to save provider configuration:", { error });
|
|
741
|
+
setSaveResult({
|
|
742
|
+
state: "error",
|
|
743
|
+
message: `Couldn't save or switch provider: ${error instanceof Error ? error.message : "unknown error"}`
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
const handleTestProviderConnection = async () => {
|
|
748
|
+
setTestResult({ state: "pending" });
|
|
749
|
+
try {
|
|
750
|
+
const testConfig = sanitizeConfigForSave(providerConfig);
|
|
751
|
+
const normalizedTestConfig = convertAnthropicConfig(testConfig) || testConfig;
|
|
752
|
+
const testProvider = AIProviderFactory.createProvider(normalizedTestConfig);
|
|
753
|
+
const result = await testProvider.validateServiceAvailability({ timeoutMs: 1e4 });
|
|
754
|
+
if (result.isAvailable) {
|
|
755
|
+
setTestResult({
|
|
756
|
+
state: "success",
|
|
757
|
+
message: "Connected. The provider responded."
|
|
758
|
+
});
|
|
759
|
+
} else {
|
|
760
|
+
setTestResult({
|
|
761
|
+
state: "error",
|
|
762
|
+
message: "Couldn't reach the provider. Check the URL and key."
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
} catch (error) {
|
|
766
|
+
debugLogger.error("Provider connection test failed:", { error });
|
|
767
|
+
setTestResult({
|
|
768
|
+
state: "error",
|
|
769
|
+
message: `Connection test failed${error instanceof Error && error.message ? `: ${error.message}` : "."}`
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
const resultColor = (state) => state === "success" ? "success.main" : state === "error" ? "error.main" : "text.secondary";
|
|
774
|
+
return /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
775
|
+
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
776
|
+
currentProvider ? /* @__PURE__ */ jsxs2(
|
|
777
|
+
Paper,
|
|
778
|
+
{
|
|
779
|
+
variant: "outlined",
|
|
780
|
+
sx: { p: { xs: 1.5, sm: 1.75 }, mb: { xs: 1.5, md: 1.75 } },
|
|
781
|
+
children: [
|
|
782
|
+
/* @__PURE__ */ jsx2(
|
|
783
|
+
Typography2,
|
|
784
|
+
{
|
|
785
|
+
variant: "overline",
|
|
786
|
+
sx: {
|
|
787
|
+
fontWeight: 700,
|
|
788
|
+
color: "text.secondary",
|
|
789
|
+
letterSpacing: 0.6,
|
|
790
|
+
display: "block",
|
|
791
|
+
mb: 1
|
|
792
|
+
},
|
|
793
|
+
children: "Current provider"
|
|
794
|
+
}
|
|
795
|
+
),
|
|
796
|
+
/* @__PURE__ */ jsxs2(
|
|
797
|
+
Box2,
|
|
798
|
+
{
|
|
799
|
+
sx: {
|
|
800
|
+
display: "flex",
|
|
801
|
+
alignItems: "center",
|
|
802
|
+
gap: 1.5,
|
|
803
|
+
flexWrap: "wrap",
|
|
804
|
+
minWidth: 0
|
|
805
|
+
},
|
|
806
|
+
children: [
|
|
807
|
+
/* @__PURE__ */ jsx2(
|
|
808
|
+
Chip2,
|
|
809
|
+
{
|
|
810
|
+
label: currentProvider.getProviderType().toUpperCase(),
|
|
811
|
+
color: "primary",
|
|
812
|
+
variant: "outlined",
|
|
813
|
+
size: "small"
|
|
814
|
+
}
|
|
815
|
+
),
|
|
816
|
+
/* @__PURE__ */ jsx2(
|
|
817
|
+
Typography2,
|
|
818
|
+
{
|
|
819
|
+
variant: "body2",
|
|
820
|
+
color: "text.secondary",
|
|
821
|
+
sx: { wordBreak: "break-all", minWidth: 0 },
|
|
822
|
+
children: currentProviderConfig?.baseUrl || currentProviderConfig?.gatewayUrl || "No URL configured"
|
|
823
|
+
}
|
|
824
|
+
)
|
|
825
|
+
]
|
|
826
|
+
}
|
|
827
|
+
)
|
|
828
|
+
]
|
|
829
|
+
}
|
|
830
|
+
) : /* @__PURE__ */ jsx2(Box2, { sx: { mb: { xs: 1.5, md: 1.75 } }, children: /* @__PURE__ */ jsx2(
|
|
831
|
+
ManagementEmptyState,
|
|
832
|
+
{
|
|
833
|
+
compact: true,
|
|
834
|
+
icon: /* @__PURE__ */ jsx2(Settings, {}),
|
|
835
|
+
title: "No provider configured",
|
|
836
|
+
description: "A provider is the model service Bandit sends chat requests to, such as the Bandit gateway, Ollama or OpenAI. Chat won't answer until one is saved.",
|
|
837
|
+
action: /* @__PURE__ */ jsx2(Button, { variant: "contained", onClick: revealProviderForm, children: "Configure a provider" })
|
|
838
|
+
}
|
|
839
|
+
) }),
|
|
840
|
+
/* @__PURE__ */ jsxs2(
|
|
841
|
+
Paper,
|
|
842
|
+
{
|
|
843
|
+
ref: formRef,
|
|
844
|
+
variant: "outlined",
|
|
845
|
+
sx: {
|
|
846
|
+
p: { xs: 1.5, sm: 1.75 },
|
|
847
|
+
mb: { xs: 1.5, md: 1.75 },
|
|
848
|
+
scrollMarginTop: 16
|
|
849
|
+
},
|
|
850
|
+
children: [
|
|
851
|
+
/* @__PURE__ */ jsx2(
|
|
852
|
+
Typography2,
|
|
853
|
+
{
|
|
854
|
+
variant: "overline",
|
|
855
|
+
sx: {
|
|
856
|
+
fontWeight: 700,
|
|
857
|
+
color: "text.secondary",
|
|
858
|
+
letterSpacing: 0.6,
|
|
859
|
+
display: "block"
|
|
860
|
+
},
|
|
861
|
+
children: "Provider configuration"
|
|
862
|
+
}
|
|
863
|
+
),
|
|
864
|
+
/* @__PURE__ */ jsx2(Typography2, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: "Changes here apply only when you select Save and switch provider." }),
|
|
865
|
+
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
866
|
+
/* @__PURE__ */ jsxs2(
|
|
867
|
+
TextField,
|
|
868
|
+
{
|
|
869
|
+
label: "Provider type",
|
|
870
|
+
select: true,
|
|
871
|
+
inputRef: providerTypeRef,
|
|
872
|
+
value: providerConfig.type,
|
|
873
|
+
onChange: (e) => handleProviderTypeChange(e.target.value),
|
|
874
|
+
fullWidth: true,
|
|
875
|
+
sx: { mb: 3 },
|
|
876
|
+
children: [
|
|
877
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "gateway", children: "Gateway (Recommended)" }),
|
|
878
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "ollama", children: "Ollama" }),
|
|
879
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "openai", children: "OpenAI" }),
|
|
880
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "azure-openai", children: "Azure OpenAI" }),
|
|
881
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "bandit", children: "Bandit AI" }),
|
|
882
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "xai", children: "xAI" }),
|
|
883
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "playground", children: "Playground (Mock Demo)" })
|
|
884
|
+
]
|
|
885
|
+
}
|
|
886
|
+
),
|
|
887
|
+
providerConfig.type === "gateway" && /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
888
|
+
/* @__PURE__ */ jsx2(
|
|
889
|
+
TextField,
|
|
890
|
+
{
|
|
891
|
+
label: "Gateway URL",
|
|
892
|
+
value: providerConfig.gatewayUrl || "",
|
|
893
|
+
onChange: (e) => setProviderConfig({ ...providerConfig, gatewayUrl: e.target.value }),
|
|
894
|
+
fullWidth: true,
|
|
895
|
+
sx: { mb: 2 },
|
|
896
|
+
placeholder: "https://your-gateway-api.com"
|
|
897
|
+
}
|
|
898
|
+
),
|
|
899
|
+
/* @__PURE__ */ jsxs2(
|
|
900
|
+
TextField,
|
|
901
|
+
{
|
|
902
|
+
label: "Backend provider",
|
|
903
|
+
select: true,
|
|
904
|
+
value: providerConfig.provider || "openai",
|
|
905
|
+
onChange: (e) => setProviderConfig({
|
|
906
|
+
...providerConfig,
|
|
907
|
+
provider: e.target.value
|
|
908
|
+
}),
|
|
909
|
+
fullWidth: true,
|
|
910
|
+
sx: { mb: 2 },
|
|
911
|
+
children: [
|
|
912
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "openai", children: "OpenAI" }),
|
|
913
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "azure-openai", children: "Azure OpenAI" }),
|
|
914
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "anthropic", children: "Anthropic" }),
|
|
915
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "ollama", children: "Ollama" }),
|
|
916
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "bandit", children: "Bandit AI" }),
|
|
917
|
+
/* @__PURE__ */ jsx2(MenuItem, { value: "xai", children: "xAI" })
|
|
918
|
+
]
|
|
919
|
+
}
|
|
920
|
+
)
|
|
921
|
+
] }),
|
|
922
|
+
providerConfig.type === "ollama" && /* @__PURE__ */ jsx2(
|
|
923
|
+
TextField,
|
|
924
|
+
{
|
|
925
|
+
label: "Ollama URL",
|
|
926
|
+
value: providerConfig.baseUrl || "",
|
|
927
|
+
onChange: (e) => setProviderConfig({ ...providerConfig, baseUrl: e.target.value }),
|
|
928
|
+
fullWidth: true,
|
|
929
|
+
placeholder: "http://localhost:11434"
|
|
930
|
+
}
|
|
931
|
+
),
|
|
932
|
+
providerConfig.type === "bandit" && /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
933
|
+
/* @__PURE__ */ jsx2(
|
|
934
|
+
TextField,
|
|
935
|
+
{
|
|
936
|
+
label: "API base URL",
|
|
937
|
+
value: providerConfig.baseUrl || "",
|
|
938
|
+
onChange: (e) => setProviderConfig((prev) => ({
|
|
939
|
+
...prev,
|
|
940
|
+
baseUrl: e.target.value
|
|
941
|
+
})),
|
|
942
|
+
fullWidth: true,
|
|
943
|
+
sx: { mb: 2 },
|
|
944
|
+
placeholder: "https://api.burtson.ai",
|
|
945
|
+
helperText: "Defaults to https://api.burtson.ai"
|
|
946
|
+
}
|
|
947
|
+
),
|
|
948
|
+
/* @__PURE__ */ jsx2(
|
|
949
|
+
TextField,
|
|
950
|
+
{
|
|
951
|
+
label: "API key",
|
|
952
|
+
type: "password",
|
|
953
|
+
value: providerConfig.apiKey || "",
|
|
954
|
+
onChange: (e) => setProviderConfig((prev) => ({
|
|
955
|
+
...prev,
|
|
956
|
+
apiKey: e.target.value
|
|
957
|
+
})),
|
|
958
|
+
fullWidth: true,
|
|
959
|
+
sx: { mb: 2 },
|
|
960
|
+
placeholder: "bai_..."
|
|
961
|
+
}
|
|
962
|
+
),
|
|
963
|
+
/* @__PURE__ */ jsx2(
|
|
964
|
+
TextField,
|
|
965
|
+
{
|
|
966
|
+
label: "Default model ID",
|
|
967
|
+
value: providerConfig.defaultModel || "",
|
|
968
|
+
onChange: (e) => setProviderConfig((prev) => ({
|
|
969
|
+
...prev,
|
|
970
|
+
defaultModel: e.target.value
|
|
971
|
+
})),
|
|
972
|
+
fullWidth: true,
|
|
973
|
+
placeholder: "bandit-core-1",
|
|
974
|
+
helperText: "Example: bandit-core-1 (Bandit Core canonical alias)."
|
|
975
|
+
}
|
|
976
|
+
)
|
|
977
|
+
] }),
|
|
978
|
+
providerConfig.type === "openai" && /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
979
|
+
/* @__PURE__ */ jsx2(
|
|
980
|
+
TextField,
|
|
981
|
+
{
|
|
982
|
+
label: "API base URL",
|
|
983
|
+
value: providerConfig.baseUrl || "",
|
|
984
|
+
onChange: (e) => setProviderConfig((prev) => ({
|
|
985
|
+
...prev,
|
|
986
|
+
baseUrl: e.target.value
|
|
987
|
+
})),
|
|
988
|
+
fullWidth: true,
|
|
989
|
+
sx: { mb: 2 },
|
|
990
|
+
placeholder: "https://api.openai.com/v1"
|
|
991
|
+
}
|
|
992
|
+
),
|
|
993
|
+
/* @__PURE__ */ jsx2(
|
|
994
|
+
TextField,
|
|
995
|
+
{
|
|
996
|
+
label: "API key",
|
|
997
|
+
type: "password",
|
|
998
|
+
value: providerConfig.apiKey || "",
|
|
999
|
+
onChange: (e) => setProviderConfig((prev) => ({
|
|
1000
|
+
...prev,
|
|
1001
|
+
apiKey: e.target.value
|
|
1002
|
+
})),
|
|
1003
|
+
fullWidth: true,
|
|
1004
|
+
sx: { mb: 2 },
|
|
1005
|
+
placeholder: "sk-..."
|
|
1006
|
+
}
|
|
1007
|
+
),
|
|
1008
|
+
/* @__PURE__ */ jsx2(
|
|
1009
|
+
TextField,
|
|
1010
|
+
{
|
|
1011
|
+
label: "Default model ID",
|
|
1012
|
+
value: providerConfig.defaultModel || "",
|
|
1013
|
+
onChange: (e) => setProviderConfig((prev) => ({
|
|
1014
|
+
...prev,
|
|
1015
|
+
defaultModel: e.target.value
|
|
1016
|
+
})),
|
|
1017
|
+
fullWidth: true,
|
|
1018
|
+
placeholder: "gpt-4o-mini",
|
|
1019
|
+
helperText: "Example: gpt-4o-mini, gpt-4.1, gpt-3.5-turbo"
|
|
1020
|
+
}
|
|
1021
|
+
)
|
|
1022
|
+
] }),
|
|
1023
|
+
providerConfig.type === "azure-openai" && /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1024
|
+
/* @__PURE__ */ jsx2(
|
|
1025
|
+
TextField,
|
|
1026
|
+
{
|
|
1027
|
+
label: "Azure endpoint",
|
|
1028
|
+
value: providerConfig.baseUrl || "",
|
|
1029
|
+
onChange: (e) => setProviderConfig({ ...providerConfig, baseUrl: e.target.value }),
|
|
1030
|
+
fullWidth: true,
|
|
1031
|
+
sx: { mb: 2 },
|
|
1032
|
+
placeholder: "https://your-resource.openai.azure.com"
|
|
1033
|
+
}
|
|
1034
|
+
),
|
|
1035
|
+
/* @__PURE__ */ jsx2(
|
|
1036
|
+
TextField,
|
|
1037
|
+
{
|
|
1038
|
+
label: "API key",
|
|
1039
|
+
type: "password",
|
|
1040
|
+
value: providerConfig.apiKey || "",
|
|
1041
|
+
onChange: (e) => setProviderConfig({ ...providerConfig, apiKey: e.target.value }),
|
|
1042
|
+
fullWidth: true,
|
|
1043
|
+
sx: { mb: 2 }
|
|
1044
|
+
}
|
|
1045
|
+
),
|
|
1046
|
+
/* @__PURE__ */ jsx2(
|
|
1047
|
+
TextField,
|
|
1048
|
+
{
|
|
1049
|
+
label: "API version",
|
|
1050
|
+
value: providerConfig.apiVersion || "",
|
|
1051
|
+
onChange: (e) => setProviderConfig({ ...providerConfig, apiVersion: e.target.value }),
|
|
1052
|
+
fullWidth: true,
|
|
1053
|
+
sx: { mb: 2 },
|
|
1054
|
+
placeholder: "2024-02-01"
|
|
1055
|
+
}
|
|
1056
|
+
),
|
|
1057
|
+
/* @__PURE__ */ jsx2(
|
|
1058
|
+
TextField,
|
|
1059
|
+
{
|
|
1060
|
+
label: "Deployment name",
|
|
1061
|
+
value: providerConfig.deploymentName || "",
|
|
1062
|
+
onChange: (e) => setProviderConfig({
|
|
1063
|
+
...providerConfig,
|
|
1064
|
+
deploymentName: e.target.value
|
|
1065
|
+
}),
|
|
1066
|
+
fullWidth: true,
|
|
1067
|
+
placeholder: "gpt-4"
|
|
1068
|
+
}
|
|
1069
|
+
)
|
|
1070
|
+
] }),
|
|
1071
|
+
providerConfig.type === "xai" && /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1072
|
+
/* @__PURE__ */ jsx2(
|
|
1073
|
+
TextField,
|
|
1074
|
+
{
|
|
1075
|
+
label: "API base URL",
|
|
1076
|
+
value: providerConfig.baseUrl || "",
|
|
1077
|
+
onChange: (e) => setProviderConfig((prev) => ({
|
|
1078
|
+
...prev,
|
|
1079
|
+
baseUrl: e.target.value
|
|
1080
|
+
})),
|
|
1081
|
+
fullWidth: true,
|
|
1082
|
+
sx: { mb: 2 },
|
|
1083
|
+
placeholder: "https://api.x.ai/v1"
|
|
1084
|
+
}
|
|
1085
|
+
),
|
|
1086
|
+
/* @__PURE__ */ jsx2(
|
|
1087
|
+
TextField,
|
|
1088
|
+
{
|
|
1089
|
+
label: "API key",
|
|
1090
|
+
type: "password",
|
|
1091
|
+
value: providerConfig.apiKey || "",
|
|
1092
|
+
onChange: (e) => setProviderConfig((prev) => ({
|
|
1093
|
+
...prev,
|
|
1094
|
+
apiKey: e.target.value
|
|
1095
|
+
})),
|
|
1096
|
+
fullWidth: true,
|
|
1097
|
+
sx: { mb: 2 },
|
|
1098
|
+
placeholder: "xai-..."
|
|
1099
|
+
}
|
|
1100
|
+
),
|
|
1101
|
+
/* @__PURE__ */ jsx2(
|
|
1102
|
+
TextField,
|
|
1103
|
+
{
|
|
1104
|
+
label: "Default model ID",
|
|
1105
|
+
value: providerConfig.defaultModel || "",
|
|
1106
|
+
onChange: (e) => setProviderConfig((prev) => ({
|
|
1107
|
+
...prev,
|
|
1108
|
+
defaultModel: e.target.value
|
|
1109
|
+
})),
|
|
1110
|
+
fullWidth: true,
|
|
1111
|
+
placeholder: "grok-beta",
|
|
1112
|
+
helperText: "Example: grok-beta, grok-2, grok-vision-beta"
|
|
1113
|
+
}
|
|
1114
|
+
)
|
|
1115
|
+
] }),
|
|
1116
|
+
providerConfig.type === "anthropic" && /* @__PURE__ */ jsx2(Alert, { severity: "warning", sx: { mt: 2 }, children: "Anthropic is only supported through the Bandit Gateway provider. Please switch to Gateway and select Anthropic as the backend service." }),
|
|
1117
|
+
/* @__PURE__ */ jsxs2(Box2, { sx: { display: "flex", flexWrap: "wrap", gap: 1.5, mt: 3 }, children: [
|
|
1118
|
+
/* @__PURE__ */ jsx2(
|
|
1119
|
+
Button,
|
|
1120
|
+
{
|
|
1121
|
+
variant: "outlined",
|
|
1122
|
+
onClick: handleTestProviderConnection,
|
|
1123
|
+
disabled: !providerConfig.type || testResult.state === "pending",
|
|
1124
|
+
startIcon: testResult.state === "pending" ? /* @__PURE__ */ jsx2(CircularProgress, { size: 14, color: "inherit" }) : void 0,
|
|
1125
|
+
children: testResult.state === "pending" ? "Testing\u2026" : "Test connection"
|
|
1126
|
+
}
|
|
1127
|
+
),
|
|
1128
|
+
/* @__PURE__ */ jsx2(
|
|
1129
|
+
Button,
|
|
1130
|
+
{
|
|
1131
|
+
variant: "contained",
|
|
1132
|
+
onClick: handleSaveProviderConfig,
|
|
1133
|
+
disabled: !providerConfig.type || saveResult.state === "pending",
|
|
1134
|
+
startIcon: saveResult.state === "pending" ? /* @__PURE__ */ jsx2(CircularProgress, { size: 14, color: "inherit" }) : void 0,
|
|
1135
|
+
children: saveResult.state === "pending" ? "Saving\u2026" : "Save & switch provider"
|
|
1136
|
+
}
|
|
1137
|
+
)
|
|
1138
|
+
] }),
|
|
1139
|
+
(testResult.state === "success" || testResult.state === "error" || saveResult.state === "success" || saveResult.state === "error") && /* @__PURE__ */ jsxs2(Stack, { spacing: 0.5, sx: { mt: 1.5 }, role: "status", "aria-live": "polite", children: [
|
|
1140
|
+
(testResult.state === "success" || testResult.state === "error") && /* @__PURE__ */ jsx2(
|
|
1141
|
+
Typography2,
|
|
1142
|
+
{
|
|
1143
|
+
variant: "body2",
|
|
1144
|
+
sx: { color: resultColor(testResult.state) },
|
|
1145
|
+
"data-testid": "provider-test-result",
|
|
1146
|
+
children: testResult.message
|
|
1147
|
+
}
|
|
1148
|
+
),
|
|
1149
|
+
(saveResult.state === "success" || saveResult.state === "error") && /* @__PURE__ */ jsx2(
|
|
1150
|
+
Typography2,
|
|
1151
|
+
{
|
|
1152
|
+
variant: "body2",
|
|
1153
|
+
sx: { color: resultColor(saveResult.state) },
|
|
1154
|
+
"data-testid": "provider-save-result",
|
|
1155
|
+
children: saveResult.message
|
|
1156
|
+
}
|
|
1157
|
+
)
|
|
1158
|
+
] })
|
|
1159
|
+
] })
|
|
1160
|
+
]
|
|
1161
|
+
}
|
|
1162
|
+
),
|
|
1163
|
+
/* @__PURE__ */ jsx2(
|
|
1164
|
+
Typography2,
|
|
1165
|
+
{
|
|
1166
|
+
variant: "caption",
|
|
1167
|
+
color: "text.secondary",
|
|
1168
|
+
sx: { display: "block", mt: 0.5, lineHeight: 1.5 },
|
|
1169
|
+
children: "Gateway is recommended for production. It routes requests through your backend, keeps API keys server-side, and adds rate limiting and monitoring."
|
|
1170
|
+
}
|
|
1171
|
+
)
|
|
1172
|
+
] }),
|
|
1173
|
+
/* @__PURE__ */ jsx2(
|
|
1174
|
+
Snackbar,
|
|
1175
|
+
{
|
|
1176
|
+
open: showSnackbar,
|
|
1177
|
+
autoHideDuration: 6e3,
|
|
1178
|
+
onClose: () => setShowSnackbar(false),
|
|
1179
|
+
anchorOrigin: { vertical: "bottom", horizontal: "left" },
|
|
1180
|
+
children: /* @__PURE__ */ jsx2(
|
|
1181
|
+
Alert,
|
|
1182
|
+
{
|
|
1183
|
+
onClose: () => setShowSnackbar(false),
|
|
1184
|
+
severity: snackbarSeverity,
|
|
1185
|
+
variant: "filled",
|
|
1186
|
+
sx: { width: "100%" },
|
|
1187
|
+
children: snackbarMessage
|
|
1188
|
+
}
|
|
1189
|
+
)
|
|
1190
|
+
}
|
|
1191
|
+
)
|
|
1192
|
+
] });
|
|
1193
|
+
};
|
|
1194
|
+
|
|
1195
|
+
export {
|
|
1196
|
+
aiProviderInitService,
|
|
1197
|
+
useGatewayHealth,
|
|
1198
|
+
useGatewayModels,
|
|
1199
|
+
useGatewayMemory,
|
|
1200
|
+
ServiceStatusCard,
|
|
1201
|
+
ProviderTab
|
|
1202
|
+
};
|
|
1203
|
+
//# sourceMappingURL=chunk-2THUYNVU.mjs.map
|