@burtson-labs/bandit-engine 2.0.40 → 2.0.41
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/README.md +14 -11
- package/dist/{aiProviderStore-JMA5RWX7.mjs → aiProviderStore-UQI33C5E.mjs} +2 -2
- package/dist/{chat-JMWPOSQ4.mjs → chat-T5ANWWYQ.mjs} +5 -5
- package/dist/chat-provider.js +151 -103
- package/dist/chat-provider.js.map +1 -1
- package/dist/chat-provider.mjs +4 -4
- package/dist/{chunk-D3AGKOM6.mjs → chunk-22EY3ZDC.mjs} +3 -3
- package/dist/{chunk-6ELNWXKC.mjs → chunk-3E57HLDV.mjs} +4 -4
- package/dist/{chunk-QJYPWWA5.mjs → chunk-54ZQ3FSN.mjs} +104 -61
- package/dist/chunk-54ZQ3FSN.mjs.map +1 -0
- package/dist/{chunk-7KEBNVCO.mjs → chunk-A6OBEF72.mjs} +15 -10
- package/dist/{chunk-7KEBNVCO.mjs.map → chunk-A6OBEF72.mjs.map} +1 -1
- package/dist/{chunk-2ZCR2TDY.mjs → chunk-CX3INLYJ.mjs} +3 -3
- package/dist/{chunk-VIYBZO5W.mjs → chunk-LYWVYBKU.mjs} +3 -3
- package/dist/{chunk-26QQ4CLA.mjs → chunk-QFNEHSY4.mjs} +4 -4
- package/dist/{chunk-75W5VWPV.mjs → chunk-WPWWWUD7.mjs} +51 -46
- package/dist/chunk-WPWWWUD7.mjs.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.js +159 -106
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -8
- package/dist/management/management.js +159 -106
- package/dist/management/management.js.map +1 -1
- package/dist/management/management.mjs +6 -6
- package/dist/modals/chat-modal/chat-modal.js +103 -60
- package/dist/modals/chat-modal/chat-modal.js.map +1 -1
- package/dist/modals/chat-modal/chat-modal.mjs +4 -4
- package/docs/01_quickstart.md +10 -4
- package/docs/02_gateway_api.md +19 -3
- package/docs/03_provider_integration.md +5 -4
- package/docs/api_reference/media/02_gateway_api.md +19 -3
- package/docs/api_reference/media/README.md +3 -1
- package/package.json +1 -1
- package/dist/chunk-75W5VWPV.mjs.map +0 -1
- package/dist/chunk-QJYPWWA5.mjs.map +0 -1
- /package/dist/{aiProviderStore-JMA5RWX7.mjs.map → aiProviderStore-UQI33C5E.mjs.map} +0 -0
- /package/dist/{chat-JMWPOSQ4.mjs.map → chat-T5ANWWYQ.mjs.map} +0 -0
- /package/dist/{chunk-D3AGKOM6.mjs.map → chunk-22EY3ZDC.mjs.map} +0 -0
- /package/dist/{chunk-6ELNWXKC.mjs.map → chunk-3E57HLDV.mjs.map} +0 -0
- /package/dist/{chunk-2ZCR2TDY.mjs.map → chunk-CX3INLYJ.mjs.map} +0 -0
- /package/dist/{chunk-VIYBZO5W.mjs.map → chunk-LYWVYBKU.mjs.map} +0 -0
- /package/dist/{chunk-26QQ4CLA.mjs.map → chunk-QFNEHSY4.mjs.map} +0 -0
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ An AI chat toolkit built for speed, design, and control. Power branded AI assist
|
|
|
20
20
|
- 🔌 Plug-and-play React chat, modal, and management surfaces
|
|
21
21
|
- 🧠 Memory, vector knowledge, and provider switching behind a secure gateway
|
|
22
22
|
- 🎨 Full MUI theming, dark mode, and branding controls out of the box
|
|
23
|
-
- 🌐 Multimodal support (voice, images, documents) with Ollama, OpenAI, Azure OpenAI, Anthropic, and xAI today — tell us which providers you need next so we can prioritize them
|
|
23
|
+
- 🌐 Multimodal support (voice, images, documents) with Bandit AI, Ollama, OpenAI, Azure OpenAI, Anthropic, and xAI today — tell us which providers you need next so we can prioritize them
|
|
24
24
|
- 🛠️ CLI scaffolding, sample gateway, and docs to launch in minutes
|
|
25
25
|
|
|
26
26
|
## Quick Links
|
|
@@ -44,7 +44,7 @@ npx @burtson-labs/bandit-engine create my-bandit-app
|
|
|
44
44
|
What you get out of the box:
|
|
45
45
|
|
|
46
46
|
- Vite + React project wired with `Chat`, `ChatModal`, and `ChatProvider`
|
|
47
|
-
- Express gateway that proxies OpenAI, Azure OpenAI, Anthropic, xAI, or Ollama behind `/api`
|
|
47
|
+
- Express gateway that proxies Bandit AI, OpenAI, Azure OpenAI, Anthropic, xAI, or Ollama behind `/api`
|
|
48
48
|
- Next.js App Router gateway scaffold (in `server/next-app/`) ready to copy into a Next project
|
|
49
49
|
- Branding + persona config in `public/config.json`, ready for your logo or prompts
|
|
50
50
|
|
|
@@ -58,7 +58,7 @@ Customize the output with options such as:
|
|
|
58
58
|
|
|
59
59
|
> 📦 The generated project installs directly from `https://registry.npmjs.org/` — no GitHub npm token is required once the package is public.
|
|
60
60
|
|
|
61
|
-
> ⚠️ The scaffolded gateway focuses on OpenAI/xAI/Ollama chat and model discovery. All advanced routes (file storage uploads, vector embedding, voice, MCP, etc.) are generated as `501` placeholders so you can wire them to your own infrastructure. Implement the contracts below before turning on those features in production.
|
|
61
|
+
> ⚠️ The scaffolded gateway focuses on Bandit AI/OpenAI/xAI/Ollama chat and model discovery. All advanced routes (file storage uploads, vector embedding, voice, MCP, etc.) are generated as `501` placeholders so you can wire them to your own infrastructure. Implement the contracts below before turning on those features in production.
|
|
62
62
|
|
|
63
63
|
Check out the [CLI quick start guide](./docs/05_cli_quickstart.md) for the full walkthrough, option matrix, and project anatomy.
|
|
64
64
|
|
|
@@ -125,7 +125,7 @@ const chatPackageSettings = {
|
|
|
125
125
|
aiProvider: {
|
|
126
126
|
type: "gateway" as const,
|
|
127
127
|
gatewayUrl: import.meta.env.VITE_GATEWAY_API_URL!,
|
|
128
|
-
provider: "
|
|
128
|
+
provider: "bandit" // Backend: bandit, openai, azure-openai, anthropic, xai, ollama
|
|
129
129
|
},
|
|
130
130
|
|
|
131
131
|
// Direct Ollama configuration (development only)
|
|
@@ -168,7 +168,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
|
168
168
|
aiProvider: {
|
|
169
169
|
type: "gateway",
|
|
170
170
|
gatewayUrl: "https://your-api-gateway.com", // Your backend API
|
|
171
|
-
provider: "
|
|
171
|
+
provider: "bandit" // Specify which AI provider to use (bandit, openai, azure-openai, anthropic, xai, ollama)
|
|
172
172
|
}
|
|
173
173
|
```
|
|
174
174
|
|
|
@@ -189,10 +189,10 @@ aiProvider: {
|
|
|
189
189
|
- `GET /api/memory` — hydrate personal memory when the feature is enabled
|
|
190
190
|
- **Chat & text generation**
|
|
191
191
|
- `POST /api/chat/completions` — default provider routing
|
|
192
|
-
- `POST /api/{provider}/chat/completions` — provider-specific routing (e.g. `openai`, `azure-openai`, `anthropic`)
|
|
192
|
+
- `POST /api/{provider}/chat/completions` — provider-specific routing (e.g. `bandit`, `openai`, `azure-openai`, `anthropic`, `xai`)
|
|
193
193
|
- `POST /api/ollama/chat` — native Ollama chat format
|
|
194
194
|
- `POST /api/generate` — non-chat generation (conversation starters, summaries, etc.)
|
|
195
|
-
- `POST /api/{provider}/generate` — same contract, but scoped per provider (required for conversation starters to respect OpenAI
|
|
195
|
+
- `POST /api/{provider}/generate` — same contract, but scoped per provider (required for conversation starters to respect Bandit/OpenAI/Azure routing)
|
|
196
196
|
- **Knowledge & vector search** (required for memories, knowledge management, and MCP document tools)
|
|
197
197
|
- `POST /api/embedding/embed-memory`
|
|
198
198
|
- `POST /api/embedding/batch-embed-memories`
|
|
@@ -211,6 +211,7 @@ aiProvider: {
|
|
|
211
211
|
- `GET /subscription/{userId}` and `PUT /subscription/{userId}` — synchronize subscription tiers used by the feature-flag system
|
|
212
212
|
|
|
213
213
|
> **⚠️ Important:** The Bandit Engine automatically routes to provider-specific endpoints:
|
|
214
|
+
> - **Bandit AI** → `/api/bandit/chat/completions` (OpenAI format, token or API key)
|
|
214
215
|
> - **Ollama** → `/api/ollama/chat` (native Ollama format)
|
|
215
216
|
> - **OpenAI/Azure/xAI/Anthropic** → `/api/{provider}/chat/completions` (OpenAI format)
|
|
216
217
|
> - **TTS/STT** → Technology-agnostic endpoints that work with any backend implementation
|
|
@@ -674,10 +675,12 @@ Bandit Engine features a unified, gateway-based AI provider architecture that su
|
|
|
674
675
|
### Supported Providers
|
|
675
676
|
|
|
676
677
|
- **🌟 Gateway Provider** (Recommended): Routes all requests through your secure backend
|
|
678
|
+
- **Bandit AI**: Bandit Core models served through the secure gateway
|
|
677
679
|
- **Ollama**: Self-hosted models and Ollama-compatible endpoints
|
|
678
680
|
- **OpenAI**: GPT models via OpenAI API
|
|
679
681
|
- **Azure OpenAI**: Azure-hosted OpenAI models
|
|
680
682
|
- **Anthropic**: Claude models via Anthropic API
|
|
683
|
+
- **xAI**: Grok models via xAI API
|
|
681
684
|
|
|
682
685
|
> We do not support every AI provider yet. Let us know which services you rely on—community interest directly shapes the integration roadmap.
|
|
683
686
|
|
|
@@ -691,7 +694,7 @@ const chatPackageSettings = {
|
|
|
691
694
|
aiProvider: {
|
|
692
695
|
type: "gateway" as const,
|
|
693
696
|
gatewayUrl: "https://your-gateway-api.example.com",
|
|
694
|
-
provider: "
|
|
697
|
+
provider: "bandit" // Backend provider: bandit, openai, azure-openai, anthropic, xai, ollama
|
|
695
698
|
},
|
|
696
699
|
// ... other settings
|
|
697
700
|
};
|
|
@@ -709,7 +712,7 @@ Your gateway API can be built with any technology (Node.js, Python, .NET, Java,
|
|
|
709
712
|
- `GET /api/health` — Health check endpoint that lists available providers.
|
|
710
713
|
- `GET /api/models` and `GET /api/models/{provider}` — Model discovery for the management UI.
|
|
711
714
|
- `POST /api/chat/completions` and `POST /api/generate` — Default OpenAI-style routes when no provider override is present.
|
|
712
|
-
- `POST /api/{provider}/chat/completions` and `POST /api/{provider}/generate` — Provider-specific routing for `openai`, `azure-openai`, and `
|
|
715
|
+
- `POST /api/{provider}/chat/completions` and `POST /api/{provider}/generate` — Provider-specific routing for `bandit`, `openai`, `azure-openai`, `anthropic`, and `xai`.
|
|
713
716
|
- `POST /api/ollama/chat` and `POST /api/ollama/generate` — Native Ollama routes (no `/chat/completions` suffix).
|
|
714
717
|
|
|
715
718
|
### Legacy Direct Providers
|
|
@@ -1135,7 +1138,7 @@ const chatPackageSettings = {
|
|
|
1135
1138
|
aiProvider: {
|
|
1136
1139
|
type: "gateway",
|
|
1137
1140
|
gatewayUrl: "https://your-api-gateway.com",
|
|
1138
|
-
provider: "
|
|
1141
|
+
provider: "bandit" // or "openai", "anthropic", "azure-openai", "xai", "ollama"
|
|
1139
1142
|
},
|
|
1140
1143
|
gatewayApiUrl: "https://your-api-gateway.com", // Same URL for TTS/STT services
|
|
1141
1144
|
// No API keys in frontend code
|
|
@@ -1157,7 +1160,7 @@ const oldSettings = {
|
|
|
1157
1160
|
|
|
1158
1161
|
// ✅ Recommended (unified gateway approach)
|
|
1159
1162
|
const newSettings = {
|
|
1160
|
-
aiProvider: { type: "gateway", gatewayUrl: "https://your-gateway.com", provider: "
|
|
1163
|
+
aiProvider: { type: "gateway", gatewayUrl: "https://your-gateway.com", provider: "bandit" },
|
|
1161
1164
|
gatewayApiUrl: "https://your-gateway.com", // Handles TTS, STT, and MCP
|
|
1162
1165
|
};
|
|
1163
1166
|
```
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useAIProviderStore
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-54ZQ3FSN.mjs";
|
|
4
4
|
import "./chunk-KCI46M23.mjs";
|
|
5
5
|
import "./chunk-BJTO5JO5.mjs";
|
|
6
6
|
export {
|
|
7
7
|
useAIProviderStore
|
|
8
8
|
};
|
|
9
|
-
//# sourceMappingURL=aiProviderStore-
|
|
9
|
+
//# sourceMappingURL=aiProviderStore-UQI33C5E.mjs.map
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
chat_default
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QFNEHSY4.mjs";
|
|
4
4
|
import "./chunk-ONQMRE2G.mjs";
|
|
5
5
|
import "./chunk-RTQDQ6TC.mjs";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-LYWVYBKU.mjs";
|
|
7
|
+
import "./chunk-CX3INLYJ.mjs";
|
|
8
8
|
import "./chunk-XUBYA5I7.mjs";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-54ZQ3FSN.mjs";
|
|
10
10
|
import "./chunk-KCI46M23.mjs";
|
|
11
11
|
import "./chunk-BJTO5JO5.mjs";
|
|
12
12
|
export {
|
|
13
13
|
chat_default as default
|
|
14
14
|
};
|
|
15
|
-
//# sourceMappingURL=chat-
|
|
15
|
+
//# sourceMappingURL=chat-T5ANWWYQ.mjs.map
|
package/dist/chat-provider.js
CHANGED
|
@@ -2222,61 +2222,15 @@ var init_gateway_service = __esm({
|
|
|
2222
2222
|
*/
|
|
2223
2223
|
chat(request) {
|
|
2224
2224
|
const endpoint = request.provider === "ollama" ? `/api/${request.provider}/chat` : request.provider ? `/api/${request.provider}/chat/completions` : "/api/chat/completions";
|
|
2225
|
-
const
|
|
2225
|
+
const fallbackEndpoint = request.provider === "bandit" ? "/completions" : null;
|
|
2226
2226
|
const normalizedModel = request.provider === "bandit" ? (() => {
|
|
2227
2227
|
const trimmed = (request.model ?? "").replace(/^bandit:/, "").trim();
|
|
2228
2228
|
return trimmed !== "" ? trimmed : "bandit-core-1";
|
|
2229
2229
|
})() : request.model;
|
|
2230
|
-
debugLogger.debug(`Gateway chat request to ${url} with provider: ${request.provider || "default"}`, {
|
|
2231
|
-
model: normalizedModel,
|
|
2232
|
-
messageCount: request.messages.length,
|
|
2233
|
-
hasImages: !!(request.images && request.images.length > 0),
|
|
2234
|
-
imageCount: request.images?.length || 0
|
|
2235
|
-
});
|
|
2236
2230
|
const requestBody = { ...request, model: normalizedModel, stream: request.stream !== false };
|
|
2237
2231
|
return new import_rxjs6.Observable((observer) => {
|
|
2238
2232
|
const controller = new AbortController();
|
|
2239
|
-
const
|
|
2240
|
-
method: "POST",
|
|
2241
|
-
headers: this._getHeaders(),
|
|
2242
|
-
body: JSON.stringify(requestBody),
|
|
2243
|
-
signal: controller.signal
|
|
2244
|
-
});
|
|
2245
|
-
task.then(async (response) => {
|
|
2246
|
-
debugLogger.debug(`Gateway chat response status: ${response.status} for provider: ${request.provider || "default"}`);
|
|
2247
|
-
if (!response.ok) {
|
|
2248
|
-
let errorText = "";
|
|
2249
|
-
let errorData = null;
|
|
2250
|
-
try {
|
|
2251
|
-
errorText = await response.text();
|
|
2252
|
-
debugLogger.error("GatewayService chat error response body", {
|
|
2253
|
-
status: response.status,
|
|
2254
|
-
statusText: response.statusText,
|
|
2255
|
-
url: response.url,
|
|
2256
|
-
body: errorText
|
|
2257
|
-
});
|
|
2258
|
-
} catch (readError) {
|
|
2259
|
-
debugLogger.error("GatewayService chat failed to read error response body", { error: readError });
|
|
2260
|
-
errorText = `Request failed with status ${response.status}`;
|
|
2261
|
-
}
|
|
2262
|
-
try {
|
|
2263
|
-
errorData = JSON.parse(errorText);
|
|
2264
|
-
debugLogger.error("GatewayService chat parsed error payload", errorData);
|
|
2265
|
-
} catch (parseError) {
|
|
2266
|
-
debugLogger.error("GatewayService chat error payload was not valid JSON");
|
|
2267
|
-
errorData = { message: errorText };
|
|
2268
|
-
}
|
|
2269
|
-
const error = this._createHttpError(
|
|
2270
|
-
`POST ${url} failed: ${response.status} ${response.statusText ?? ""}`,
|
|
2271
|
-
{
|
|
2272
|
-
status: response.status,
|
|
2273
|
-
statusText: response.statusText ?? "",
|
|
2274
|
-
data: errorData,
|
|
2275
|
-
url
|
|
2276
|
-
}
|
|
2277
|
-
);
|
|
2278
|
-
throw error;
|
|
2279
|
-
}
|
|
2233
|
+
const handleStreamingResponse = async (response) => {
|
|
2280
2234
|
const reader = response.body?.getReader();
|
|
2281
2235
|
const decoder = new TextDecoder();
|
|
2282
2236
|
let buffer = "";
|
|
@@ -2351,14 +2305,75 @@ var init_gateway_service = __esm({
|
|
|
2351
2305
|
}).catch((err) => observer.error(err));
|
|
2352
2306
|
};
|
|
2353
2307
|
read();
|
|
2354
|
-
}
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2308
|
+
};
|
|
2309
|
+
const sendRequest = (targetEndpoint, allowFallback) => {
|
|
2310
|
+
const url = `${this._baseUrl}${targetEndpoint}`;
|
|
2311
|
+
debugLogger.debug(`Gateway chat request to ${url} with provider: ${request.provider || "default"}`, {
|
|
2312
|
+
model: normalizedModel,
|
|
2313
|
+
messageCount: request.messages.length,
|
|
2314
|
+
hasImages: !!(request.images && request.images.length > 0),
|
|
2315
|
+
imageCount: request.images?.length || 0
|
|
2359
2316
|
});
|
|
2360
|
-
|
|
2361
|
-
|
|
2317
|
+
fetch(url, {
|
|
2318
|
+
method: "POST",
|
|
2319
|
+
headers: this._getHeaders(),
|
|
2320
|
+
body: JSON.stringify(requestBody),
|
|
2321
|
+
signal: controller.signal
|
|
2322
|
+
}).then(async (response) => {
|
|
2323
|
+
debugLogger.debug(`Gateway chat response status: ${response.status} for provider: ${request.provider || "default"}`);
|
|
2324
|
+
if (response.status === 404 && allowFallback && fallbackEndpoint) {
|
|
2325
|
+
debugLogger.warn("GatewayService chat endpoint returned 404, attempting fallback route", {
|
|
2326
|
+
provider: request.provider,
|
|
2327
|
+
attemptedEndpoint: targetEndpoint,
|
|
2328
|
+
fallbackEndpoint
|
|
2329
|
+
});
|
|
2330
|
+
sendRequest(fallbackEndpoint, false);
|
|
2331
|
+
return;
|
|
2332
|
+
}
|
|
2333
|
+
if (!response.ok) {
|
|
2334
|
+
let errorText = "";
|
|
2335
|
+
let errorData = null;
|
|
2336
|
+
try {
|
|
2337
|
+
errorText = await response.text();
|
|
2338
|
+
debugLogger.error("GatewayService chat error response body", {
|
|
2339
|
+
status: response.status,
|
|
2340
|
+
statusText: response.statusText,
|
|
2341
|
+
url: response.url,
|
|
2342
|
+
body: errorText
|
|
2343
|
+
});
|
|
2344
|
+
} catch (readError) {
|
|
2345
|
+
debugLogger.error("GatewayService chat failed to read error response body", { error: readError });
|
|
2346
|
+
errorText = `Request failed with status ${response.status}`;
|
|
2347
|
+
}
|
|
2348
|
+
try {
|
|
2349
|
+
errorData = JSON.parse(errorText);
|
|
2350
|
+
debugLogger.error("GatewayService chat parsed error payload", errorData);
|
|
2351
|
+
} catch (parseError) {
|
|
2352
|
+
debugLogger.error("GatewayService chat error payload was not valid JSON");
|
|
2353
|
+
errorData = { message: errorText };
|
|
2354
|
+
}
|
|
2355
|
+
const error = this._createHttpError(
|
|
2356
|
+
`POST ${url} failed: ${response.status} ${response.statusText ?? ""}`,
|
|
2357
|
+
{
|
|
2358
|
+
status: response.status,
|
|
2359
|
+
statusText: response.statusText ?? "",
|
|
2360
|
+
data: errorData,
|
|
2361
|
+
url
|
|
2362
|
+
}
|
|
2363
|
+
);
|
|
2364
|
+
throw error;
|
|
2365
|
+
}
|
|
2366
|
+
await handleStreamingResponse(response);
|
|
2367
|
+
}).catch((err) => {
|
|
2368
|
+
debugLogger.error("GatewayService chat fetch error", {
|
|
2369
|
+
error: err,
|
|
2370
|
+
url,
|
|
2371
|
+
provider: request.provider
|
|
2372
|
+
});
|
|
2373
|
+
observer.error(err);
|
|
2374
|
+
});
|
|
2375
|
+
};
|
|
2376
|
+
sendRequest(endpoint, true);
|
|
2362
2377
|
return () => {
|
|
2363
2378
|
try {
|
|
2364
2379
|
controller.abort();
|
|
@@ -2491,18 +2506,46 @@ var init_gateway_service = __esm({
|
|
|
2491
2506
|
);
|
|
2492
2507
|
}
|
|
2493
2508
|
_getHeaders() {
|
|
2494
|
-
const
|
|
2509
|
+
const rawToken2 = this._tokenFactory();
|
|
2495
2510
|
const headers = {
|
|
2496
2511
|
"Content-Type": "application/json"
|
|
2497
2512
|
};
|
|
2498
|
-
if (
|
|
2499
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
2500
|
-
debugLogger.debug("Authorization header set with token");
|
|
2501
|
-
} else {
|
|
2513
|
+
if (!rawToken2) {
|
|
2502
2514
|
debugLogger.warn("GatewayService: No token found, skipping Authorization header");
|
|
2515
|
+
return headers;
|
|
2516
|
+
}
|
|
2517
|
+
const token = rawToken2.trim();
|
|
2518
|
+
if (token === "") {
|
|
2519
|
+
debugLogger.warn("GatewayService: Token factory returned empty string");
|
|
2520
|
+
return headers;
|
|
2521
|
+
}
|
|
2522
|
+
if (/^(Bearer|ApiKey)\s+/i.test(token)) {
|
|
2523
|
+
headers["Authorization"] = token;
|
|
2524
|
+
debugLogger.debug("GatewayService: Authorization header set with explicit scheme");
|
|
2525
|
+
return headers;
|
|
2503
2526
|
}
|
|
2527
|
+
if (this._isLikelyBanditApiKey(token)) {
|
|
2528
|
+
headers["Authorization"] = `ApiKey ${token}`;
|
|
2529
|
+
headers["X-Burtson-Api-Key"] = token;
|
|
2530
|
+
debugLogger.debug("GatewayService: Authorization header set using API key");
|
|
2531
|
+
return headers;
|
|
2532
|
+
}
|
|
2533
|
+
if (this._isLikelyJwt(token)) {
|
|
2534
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
2535
|
+
debugLogger.debug("GatewayService: Authorization header set using bearer token");
|
|
2536
|
+
return headers;
|
|
2537
|
+
}
|
|
2538
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
2539
|
+
debugLogger.debug("GatewayService: Authorization header defaulted to bearer scheme");
|
|
2504
2540
|
return headers;
|
|
2505
2541
|
}
|
|
2542
|
+
_isLikelyJwt(token) {
|
|
2543
|
+
const segments = token.split(".");
|
|
2544
|
+
return segments.length === 3 && segments.every((segment) => segment.length > 0);
|
|
2545
|
+
}
|
|
2546
|
+
_isLikelyBanditApiKey(value) {
|
|
2547
|
+
return /^bai_[a-z0-9]{10,}$/i.test(value);
|
|
2548
|
+
}
|
|
2506
2549
|
/**
|
|
2507
2550
|
* Submit feedback to the gateway API
|
|
2508
2551
|
*/
|
|
@@ -9764,26 +9807,7 @@ var AIProviderInitService = class _AIProviderInitService {
|
|
|
9764
9807
|
if (providerConfig.type === "anthropic" /* ANTHROPIC */) {
|
|
9765
9808
|
providerConfig = this.convertAnthropicConfig(providerConfig, settings?.gatewayApiUrl);
|
|
9766
9809
|
}
|
|
9767
|
-
|
|
9768
|
-
providerConfig.tokenFactory = () => {
|
|
9769
|
-
let token = authenticationService.getToken();
|
|
9770
|
-
if (!token) {
|
|
9771
|
-
token = localStorage.getItem("authToken");
|
|
9772
|
-
}
|
|
9773
|
-
if (!token) {
|
|
9774
|
-
try {
|
|
9775
|
-
const { useAuthenticationStore: useAuthenticationStore2 } = require("../../store/authenticationStore");
|
|
9776
|
-
const authStore = useAuthenticationStore2.getState();
|
|
9777
|
-
token = authStore.token;
|
|
9778
|
-
} catch (e) {
|
|
9779
|
-
}
|
|
9780
|
-
}
|
|
9781
|
-
debugLogger.info("AI Provider Init: IndexedDB config token factory", {
|
|
9782
|
-
hasToken: !!token
|
|
9783
|
-
});
|
|
9784
|
-
return token;
|
|
9785
|
-
};
|
|
9786
|
-
}
|
|
9810
|
+
providerConfig = this.ensureTokenFactory(providerConfig);
|
|
9787
9811
|
try {
|
|
9788
9812
|
const { createProvider } = useAIProviderStore.getState();
|
|
9789
9813
|
createProvider(providerConfig);
|
|
@@ -9811,27 +9835,7 @@ var AIProviderInitService = class _AIProviderInitService {
|
|
|
9811
9835
|
if (providerConfig.type === "anthropic" /* ANTHROPIC */) {
|
|
9812
9836
|
providerConfig = this.convertAnthropicConfig(providerConfig, settings.gatewayApiUrl);
|
|
9813
9837
|
}
|
|
9814
|
-
|
|
9815
|
-
providerConfig.tokenFactory = () => {
|
|
9816
|
-
let token = authenticationService.getToken();
|
|
9817
|
-
if (!token) {
|
|
9818
|
-
token = localStorage.getItem("authToken");
|
|
9819
|
-
}
|
|
9820
|
-
if (!token) {
|
|
9821
|
-
try {
|
|
9822
|
-
const { useAuthenticationStore: useAuthenticationStore2 } = require("../../store/authenticationStore");
|
|
9823
|
-
const authStore = useAuthenticationStore2.getState();
|
|
9824
|
-
token = authStore.token;
|
|
9825
|
-
} catch (e) {
|
|
9826
|
-
}
|
|
9827
|
-
}
|
|
9828
|
-
debugLogger.info("AIProviderInit: Explicit config tokenFactory", {
|
|
9829
|
-
hasToken: !!token,
|
|
9830
|
-
localStorage: !!localStorage.getItem("authToken")
|
|
9831
|
-
});
|
|
9832
|
-
return token;
|
|
9833
|
-
};
|
|
9834
|
-
}
|
|
9838
|
+
providerConfig = this.ensureTokenFactory(providerConfig);
|
|
9835
9839
|
debugLogger.info("Using explicit AI provider config", providerConfig);
|
|
9836
9840
|
} else {
|
|
9837
9841
|
providerConfig = {
|
|
@@ -9943,9 +9947,10 @@ var AIProviderInitService = class _AIProviderInitService {
|
|
|
9943
9947
|
*/
|
|
9944
9948
|
switchProvider(config) {
|
|
9945
9949
|
try {
|
|
9950
|
+
const normalizedConfig = this.ensureTokenFactory({ ...config });
|
|
9946
9951
|
const { switchProvider } = useAIProviderStore.getState();
|
|
9947
|
-
switchProvider(
|
|
9948
|
-
debugLogger.info(`Switched to AI provider: ${
|
|
9952
|
+
switchProvider(normalizedConfig);
|
|
9953
|
+
debugLogger.info(`Switched to AI provider: ${normalizedConfig.type}`);
|
|
9949
9954
|
} catch (error) {
|
|
9950
9955
|
debugLogger.error("Failed to switch AI provider:", { error });
|
|
9951
9956
|
throw error;
|
|
@@ -9979,6 +9984,49 @@ var AIProviderInitService = class _AIProviderInitService {
|
|
|
9979
9984
|
debugLogger.info("AI Provider Init: Converted direct Anthropic provider to gateway configuration");
|
|
9980
9985
|
return normalized;
|
|
9981
9986
|
}
|
|
9987
|
+
/**
|
|
9988
|
+
* Ensure providers that require auth have a token factory configured.
|
|
9989
|
+
* Handles both UI auth tokens and API key scenarios.
|
|
9990
|
+
*/
|
|
9991
|
+
ensureTokenFactory(config) {
|
|
9992
|
+
if (config.type === "ollama" /* OLLAMA */ || config.type === "gateway" /* GATEWAY */) {
|
|
9993
|
+
const existingFactory = config.tokenFactory;
|
|
9994
|
+
if (existingFactory) {
|
|
9995
|
+
return config;
|
|
9996
|
+
}
|
|
9997
|
+
if (typeof config.apiKey === "string" && config.apiKey.trim() !== "") {
|
|
9998
|
+
const key = config.apiKey.trim();
|
|
9999
|
+
config.tokenFactory = () => key;
|
|
10000
|
+
debugLogger.info("AIProviderInit: Using API key for token factory", {
|
|
10001
|
+
type: config.type,
|
|
10002
|
+
hasKey: true
|
|
10003
|
+
});
|
|
10004
|
+
return config;
|
|
10005
|
+
}
|
|
10006
|
+
config.tokenFactory = () => {
|
|
10007
|
+
let token = authenticationService.getToken();
|
|
10008
|
+
if (!token && typeof localStorage !== "undefined") {
|
|
10009
|
+
try {
|
|
10010
|
+
token = localStorage.getItem("authToken");
|
|
10011
|
+
} catch {
|
|
10012
|
+
}
|
|
10013
|
+
}
|
|
10014
|
+
if (!token) {
|
|
10015
|
+
try {
|
|
10016
|
+
const { useAuthenticationStore: useAuthenticationStore2 } = require("../../store/authenticationStore");
|
|
10017
|
+
const authStore = useAuthenticationStore2.getState();
|
|
10018
|
+
token = authStore.token;
|
|
10019
|
+
} catch {
|
|
10020
|
+
}
|
|
10021
|
+
}
|
|
10022
|
+
debugLogger.info("AIProviderInit: Token factory resolved auth token", {
|
|
10023
|
+
hasToken: !!token
|
|
10024
|
+
});
|
|
10025
|
+
return token;
|
|
10026
|
+
};
|
|
10027
|
+
}
|
|
10028
|
+
return config;
|
|
10029
|
+
}
|
|
9982
10030
|
};
|
|
9983
10031
|
var aiProviderInitService = AIProviderInitService.getInstance();
|
|
9984
10032
|
|