@burtson-labs/bandit-engine 2.0.40 → 2.0.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +14 -11
  2. package/dist/{aiProviderStore-JMA5RWX7.mjs → aiProviderStore-UQI33C5E.mjs} +2 -2
  3. package/dist/{chat-JMWPOSQ4.mjs → chat-XDC4SNJF.mjs} +5 -5
  4. package/dist/chat-provider.js +156 -106
  5. package/dist/chat-provider.js.map +1 -1
  6. package/dist/chat-provider.mjs +4 -4
  7. package/dist/{chunk-7KEBNVCO.mjs → chunk-4RCAVVDN.mjs} +15 -10
  8. package/dist/{chunk-7KEBNVCO.mjs.map → chunk-4RCAVVDN.mjs.map} +1 -1
  9. package/dist/{chunk-QJYPWWA5.mjs → chunk-54ZQ3FSN.mjs} +104 -61
  10. package/dist/chunk-54ZQ3FSN.mjs.map +1 -0
  11. package/dist/{chunk-26QQ4CLA.mjs → chunk-EOEI74X4.mjs} +4 -4
  12. package/dist/{chunk-6ELNWXKC.mjs → chunk-ERV7GLY3.mjs} +4 -4
  13. package/dist/{chunk-75W5VWPV.mjs → chunk-H4PBQ5LJ.mjs} +51 -46
  14. package/dist/chunk-H4PBQ5LJ.mjs.map +1 -0
  15. package/dist/{chunk-D3AGKOM6.mjs → chunk-KBKWVG7X.mjs} +3 -3
  16. package/dist/{chunk-VIYBZO5W.mjs → chunk-SBNENBUQ.mjs} +3 -3
  17. package/dist/{chunk-2ZCR2TDY.mjs → chunk-UXE67LR7.mjs} +8 -6
  18. package/dist/{chunk-2ZCR2TDY.mjs.map → chunk-UXE67LR7.mjs.map} +1 -1
  19. package/dist/cli.js +1 -1
  20. package/dist/cli.js.map +1 -1
  21. package/dist/index.js +164 -109
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +8 -8
  24. package/dist/management/management.js +164 -109
  25. package/dist/management/management.js.map +1 -1
  26. package/dist/management/management.mjs +6 -6
  27. package/dist/modals/chat-modal/chat-modal.js +108 -63
  28. package/dist/modals/chat-modal/chat-modal.js.map +1 -1
  29. package/dist/modals/chat-modal/chat-modal.mjs +4 -4
  30. package/docs/01_quickstart.md +10 -4
  31. package/docs/02_gateway_api.md +19 -3
  32. package/docs/03_provider_integration.md +5 -4
  33. package/docs/api_reference/media/02_gateway_api.md +19 -3
  34. package/docs/api_reference/media/README.md +3 -1
  35. package/package.json +1 -1
  36. package/dist/chunk-75W5VWPV.mjs.map +0 -1
  37. package/dist/chunk-QJYPWWA5.mjs.map +0 -1
  38. /package/dist/{aiProviderStore-JMA5RWX7.mjs.map → aiProviderStore-UQI33C5E.mjs.map} +0 -0
  39. /package/dist/{chat-JMWPOSQ4.mjs.map → chat-XDC4SNJF.mjs.map} +0 -0
  40. /package/dist/{chunk-26QQ4CLA.mjs.map → chunk-EOEI74X4.mjs.map} +0 -0
  41. /package/dist/{chunk-6ELNWXKC.mjs.map → chunk-ERV7GLY3.mjs.map} +0 -0
  42. /package/dist/{chunk-D3AGKOM6.mjs.map → chunk-KBKWVG7X.mjs.map} +0 -0
  43. /package/dist/{chunk-VIYBZO5W.mjs.map → chunk-SBNENBUQ.mjs.map} +0 -0
package/dist/index.js CHANGED
@@ -4468,61 +4468,15 @@ var init_gateway_service = __esm({
4468
4468
  */
4469
4469
  chat(request) {
4470
4470
  const endpoint = request.provider === "ollama" ? `/api/${request.provider}/chat` : request.provider ? `/api/${request.provider}/chat/completions` : "/api/chat/completions";
4471
- const url = `${this._baseUrl}${endpoint}`;
4471
+ const fallbackEndpoint = request.provider === "bandit" ? "/completions" : null;
4472
4472
  const normalizedModel = request.provider === "bandit" ? (() => {
4473
4473
  const trimmed = (request.model ?? "").replace(/^bandit:/, "").trim();
4474
4474
  return trimmed !== "" ? trimmed : "bandit-core-1";
4475
4475
  })() : request.model;
4476
- debugLogger.debug(`Gateway chat request to ${url} with provider: ${request.provider || "default"}`, {
4477
- model: normalizedModel,
4478
- messageCount: request.messages.length,
4479
- hasImages: !!(request.images && request.images.length > 0),
4480
- imageCount: request.images?.length || 0
4481
- });
4482
4476
  const requestBody = { ...request, model: normalizedModel, stream: request.stream !== false };
4483
4477
  return new import_rxjs6.Observable((observer) => {
4484
4478
  const controller = new AbortController();
4485
- const task = fetch(url, {
4486
- method: "POST",
4487
- headers: this._getHeaders(),
4488
- body: JSON.stringify(requestBody),
4489
- signal: controller.signal
4490
- });
4491
- task.then(async (response) => {
4492
- debugLogger.debug(`Gateway chat response status: ${response.status} for provider: ${request.provider || "default"}`);
4493
- if (!response.ok) {
4494
- let errorText = "";
4495
- let errorData = null;
4496
- try {
4497
- errorText = await response.text();
4498
- debugLogger.error("GatewayService chat error response body", {
4499
- status: response.status,
4500
- statusText: response.statusText,
4501
- url: response.url,
4502
- body: errorText
4503
- });
4504
- } catch (readError) {
4505
- debugLogger.error("GatewayService chat failed to read error response body", { error: readError });
4506
- errorText = `Request failed with status ${response.status}`;
4507
- }
4508
- try {
4509
- errorData = JSON.parse(errorText);
4510
- debugLogger.error("GatewayService chat parsed error payload", errorData);
4511
- } catch (parseError) {
4512
- debugLogger.error("GatewayService chat error payload was not valid JSON");
4513
- errorData = { message: errorText };
4514
- }
4515
- const error = this._createHttpError(
4516
- `POST ${url} failed: ${response.status} ${response.statusText ?? ""}`,
4517
- {
4518
- status: response.status,
4519
- statusText: response.statusText ?? "",
4520
- data: errorData,
4521
- url
4522
- }
4523
- );
4524
- throw error;
4525
- }
4479
+ const handleStreamingResponse = async (response) => {
4526
4480
  const reader = response.body?.getReader();
4527
4481
  const decoder = new TextDecoder();
4528
4482
  let buffer = "";
@@ -4597,14 +4551,75 @@ var init_gateway_service = __esm({
4597
4551
  }).catch((err) => observer.error(err));
4598
4552
  };
4599
4553
  read();
4600
- }).catch((err) => {
4601
- debugLogger.error("GatewayService chat fetch error", {
4602
- error: err,
4603
- url,
4604
- provider: request.provider
4554
+ };
4555
+ const sendRequest = (targetEndpoint, allowFallback) => {
4556
+ const url = `${this._baseUrl}${targetEndpoint}`;
4557
+ debugLogger.debug(`Gateway chat request to ${url} with provider: ${request.provider || "default"}`, {
4558
+ model: normalizedModel,
4559
+ messageCount: request.messages.length,
4560
+ hasImages: !!(request.images && request.images.length > 0),
4561
+ imageCount: request.images?.length || 0
4605
4562
  });
4606
- observer.error(err);
4607
- });
4563
+ fetch(url, {
4564
+ method: "POST",
4565
+ headers: this._getHeaders(),
4566
+ body: JSON.stringify(requestBody),
4567
+ signal: controller.signal
4568
+ }).then(async (response) => {
4569
+ debugLogger.debug(`Gateway chat response status: ${response.status} for provider: ${request.provider || "default"}`);
4570
+ if (response.status === 404 && allowFallback && fallbackEndpoint) {
4571
+ debugLogger.warn("GatewayService chat endpoint returned 404, attempting fallback route", {
4572
+ provider: request.provider,
4573
+ attemptedEndpoint: targetEndpoint,
4574
+ fallbackEndpoint
4575
+ });
4576
+ sendRequest(fallbackEndpoint, false);
4577
+ return;
4578
+ }
4579
+ if (!response.ok) {
4580
+ let errorText = "";
4581
+ let errorData = null;
4582
+ try {
4583
+ errorText = await response.text();
4584
+ debugLogger.error("GatewayService chat error response body", {
4585
+ status: response.status,
4586
+ statusText: response.statusText,
4587
+ url: response.url,
4588
+ body: errorText
4589
+ });
4590
+ } catch (readError) {
4591
+ debugLogger.error("GatewayService chat failed to read error response body", { error: readError });
4592
+ errorText = `Request failed with status ${response.status}`;
4593
+ }
4594
+ try {
4595
+ errorData = JSON.parse(errorText);
4596
+ debugLogger.error("GatewayService chat parsed error payload", errorData);
4597
+ } catch (parseError) {
4598
+ debugLogger.error("GatewayService chat error payload was not valid JSON");
4599
+ errorData = { message: errorText };
4600
+ }
4601
+ const error = this._createHttpError(
4602
+ `POST ${url} failed: ${response.status} ${response.statusText ?? ""}`,
4603
+ {
4604
+ status: response.status,
4605
+ statusText: response.statusText ?? "",
4606
+ data: errorData,
4607
+ url
4608
+ }
4609
+ );
4610
+ throw error;
4611
+ }
4612
+ await handleStreamingResponse(response);
4613
+ }).catch((err) => {
4614
+ debugLogger.error("GatewayService chat fetch error", {
4615
+ error: err,
4616
+ url,
4617
+ provider: request.provider
4618
+ });
4619
+ observer.error(err);
4620
+ });
4621
+ };
4622
+ sendRequest(endpoint, true);
4608
4623
  return () => {
4609
4624
  try {
4610
4625
  controller.abort();
@@ -4737,18 +4752,46 @@ var init_gateway_service = __esm({
4737
4752
  );
4738
4753
  }
4739
4754
  _getHeaders() {
4740
- const token = this._tokenFactory();
4755
+ const rawToken2 = this._tokenFactory();
4741
4756
  const headers = {
4742
4757
  "Content-Type": "application/json"
4743
4758
  };
4744
- if (token && token.trim() !== "") {
4745
- headers["Authorization"] = `Bearer ${token}`;
4746
- debugLogger.debug("Authorization header set with token");
4747
- } else {
4759
+ if (!rawToken2) {
4748
4760
  debugLogger.warn("GatewayService: No token found, skipping Authorization header");
4761
+ return headers;
4762
+ }
4763
+ const token = rawToken2.trim();
4764
+ if (token === "") {
4765
+ debugLogger.warn("GatewayService: Token factory returned empty string");
4766
+ return headers;
4767
+ }
4768
+ if (/^(Bearer|ApiKey)\s+/i.test(token)) {
4769
+ headers["Authorization"] = token;
4770
+ debugLogger.debug("GatewayService: Authorization header set with explicit scheme");
4771
+ return headers;
4772
+ }
4773
+ if (this._isLikelyBanditApiKey(token)) {
4774
+ headers["Authorization"] = `ApiKey ${token}`;
4775
+ headers["X-Burtson-Api-Key"] = token;
4776
+ debugLogger.debug("GatewayService: Authorization header set using API key");
4777
+ return headers;
4749
4778
  }
4779
+ if (this._isLikelyJwt(token)) {
4780
+ headers["Authorization"] = `Bearer ${token}`;
4781
+ debugLogger.debug("GatewayService: Authorization header set using bearer token");
4782
+ return headers;
4783
+ }
4784
+ headers["Authorization"] = `Bearer ${token}`;
4785
+ debugLogger.debug("GatewayService: Authorization header defaulted to bearer scheme");
4750
4786
  return headers;
4751
4787
  }
4788
+ _isLikelyJwt(token) {
4789
+ const segments = token.split(".");
4790
+ return segments.length === 3 && segments.every((segment) => segment.length > 0);
4791
+ }
4792
+ _isLikelyBanditApiKey(value) {
4793
+ return /^bai_[a-z0-9]{10,}$/i.test(value);
4794
+ }
4752
4795
  /**
4753
4796
  * Submit feedback to the gateway API
4754
4797
  */
@@ -9435,9 +9478,11 @@ var init_useVectorStore = __esm({
9435
9478
  setHasCompatibleProvider(false);
9436
9479
  return false;
9437
9480
  }
9438
- const isOllama = config.type === "ollama";
9439
- const isGatewayWithOllama = config.type === "gateway" && config.provider === "ollama";
9440
- const isCompatible = isOllama || isGatewayWithOllama;
9481
+ const vectorCapableProviders = /* @__PURE__ */ new Set(["ollama", "bandit"]);
9482
+ const isNativeOllama = config.type === "ollama";
9483
+ const hasVectorCapableProvider = typeof config.provider === "string" && vectorCapableProviders.has(config.provider);
9484
+ const isGatewayWithVectorSupport = config.type === "gateway" && hasVectorCapableProvider;
9485
+ const isCompatible = isNativeOllama || isGatewayWithVectorSupport;
9441
9486
  setHasCompatibleProvider(isCompatible);
9442
9487
  return isCompatible;
9443
9488
  } catch (error) {
@@ -29268,26 +29313,7 @@ var AIProviderInitService = class _AIProviderInitService {
29268
29313
  if (providerConfig.type === "anthropic" /* ANTHROPIC */) {
29269
29314
  providerConfig = this.convertAnthropicConfig(providerConfig, settings?.gatewayApiUrl);
29270
29315
  }
29271
- if ((providerConfig.type === "ollama" /* OLLAMA */ || providerConfig.type === "gateway" /* GATEWAY */) && !providerConfig.tokenFactory) {
29272
- providerConfig.tokenFactory = () => {
29273
- let token = authenticationService.getToken();
29274
- if (!token) {
29275
- token = localStorage.getItem("authToken");
29276
- }
29277
- if (!token) {
29278
- try {
29279
- const { useAuthenticationStore: useAuthenticationStore2 } = require("../../store/authenticationStore");
29280
- const authStore = useAuthenticationStore2.getState();
29281
- token = authStore.token;
29282
- } catch (e) {
29283
- }
29284
- }
29285
- debugLogger.info("AI Provider Init: IndexedDB config token factory", {
29286
- hasToken: !!token
29287
- });
29288
- return token;
29289
- };
29290
- }
29316
+ providerConfig = this.ensureTokenFactory(providerConfig);
29291
29317
  try {
29292
29318
  const { createProvider } = useAIProviderStore.getState();
29293
29319
  createProvider(providerConfig);
@@ -29315,27 +29341,7 @@ var AIProviderInitService = class _AIProviderInitService {
29315
29341
  if (providerConfig.type === "anthropic" /* ANTHROPIC */) {
29316
29342
  providerConfig = this.convertAnthropicConfig(providerConfig, settings.gatewayApiUrl);
29317
29343
  }
29318
- if (providerConfig.type === "ollama" /* OLLAMA */ && !providerConfig.tokenFactory) {
29319
- providerConfig.tokenFactory = () => {
29320
- let token = authenticationService.getToken();
29321
- if (!token) {
29322
- token = localStorage.getItem("authToken");
29323
- }
29324
- if (!token) {
29325
- try {
29326
- const { useAuthenticationStore: useAuthenticationStore2 } = require("../../store/authenticationStore");
29327
- const authStore = useAuthenticationStore2.getState();
29328
- token = authStore.token;
29329
- } catch (e) {
29330
- }
29331
- }
29332
- debugLogger.info("AIProviderInit: Explicit config tokenFactory", {
29333
- hasToken: !!token,
29334
- localStorage: !!localStorage.getItem("authToken")
29335
- });
29336
- return token;
29337
- };
29338
- }
29344
+ providerConfig = this.ensureTokenFactory(providerConfig);
29339
29345
  debugLogger.info("Using explicit AI provider config", providerConfig);
29340
29346
  } else {
29341
29347
  providerConfig = {
@@ -29447,9 +29453,10 @@ var AIProviderInitService = class _AIProviderInitService {
29447
29453
  */
29448
29454
  switchProvider(config) {
29449
29455
  try {
29456
+ const normalizedConfig = this.ensureTokenFactory({ ...config });
29450
29457
  const { switchProvider } = useAIProviderStore.getState();
29451
- switchProvider(config);
29452
- debugLogger.info(`Switched to AI provider: ${config.type}`);
29458
+ switchProvider(normalizedConfig);
29459
+ debugLogger.info(`Switched to AI provider: ${normalizedConfig.type}`);
29453
29460
  } catch (error) {
29454
29461
  debugLogger.error("Failed to switch AI provider:", { error });
29455
29462
  throw error;
@@ -29483,6 +29490,49 @@ var AIProviderInitService = class _AIProviderInitService {
29483
29490
  debugLogger.info("AI Provider Init: Converted direct Anthropic provider to gateway configuration");
29484
29491
  return normalized;
29485
29492
  }
29493
+ /**
29494
+ * Ensure providers that require auth have a token factory configured.
29495
+ * Handles both UI auth tokens and API key scenarios.
29496
+ */
29497
+ ensureTokenFactory(config) {
29498
+ if (config.type === "ollama" /* OLLAMA */ || config.type === "gateway" /* GATEWAY */) {
29499
+ const existingFactory = config.tokenFactory;
29500
+ if (existingFactory) {
29501
+ return config;
29502
+ }
29503
+ if (typeof config.apiKey === "string" && config.apiKey.trim() !== "") {
29504
+ const key = config.apiKey.trim();
29505
+ config.tokenFactory = () => key;
29506
+ debugLogger.info("AIProviderInit: Using API key for token factory", {
29507
+ type: config.type,
29508
+ hasKey: true
29509
+ });
29510
+ return config;
29511
+ }
29512
+ config.tokenFactory = () => {
29513
+ let token = authenticationService.getToken();
29514
+ if (!token && typeof localStorage !== "undefined") {
29515
+ try {
29516
+ token = localStorage.getItem("authToken");
29517
+ } catch {
29518
+ }
29519
+ }
29520
+ if (!token) {
29521
+ try {
29522
+ const { useAuthenticationStore: useAuthenticationStore2 } = require("../../store/authenticationStore");
29523
+ const authStore = useAuthenticationStore2.getState();
29524
+ token = authStore.token;
29525
+ } catch {
29526
+ }
29527
+ }
29528
+ debugLogger.info("AIProviderInit: Token factory resolved auth token", {
29529
+ hasToken: !!token
29530
+ });
29531
+ return token;
29532
+ };
29533
+ }
29534
+ return config;
29535
+ }
29486
29536
  };
29487
29537
  var aiProviderInitService = AIProviderInitService.getInstance();
29488
29538
 
@@ -39186,11 +39236,16 @@ var ProviderTab = () => {
39186
39236
  const trimmed = sanitized.defaultModel.trim();
39187
39237
  sanitized.defaultModel = trimmed || void 0;
39188
39238
  }
39239
+ if (typeof sanitized.apiKey === "string") {
39240
+ const trimmedKey = sanitized.apiKey.trim();
39241
+ sanitized.apiKey = trimmedKey || void 0;
39242
+ }
39189
39243
  return sanitized;
39190
39244
  }, []);
39191
39245
  const [providerConfig, setProviderConfig] = (0, import_react53.useState)({
39192
- type: "ollama",
39193
- baseUrl: "http://localhost:11434"
39246
+ type: "gateway",
39247
+ gatewayUrl: packageSettings?.gatewayApiUrl || "",
39248
+ provider: "bandit"
39194
39249
  });
39195
39250
  const [isProviderConfigOpen, setIsProviderConfigOpen] = (0, import_react53.useState)(false);
39196
39251
  const [snackbarMessage, setSnackbarMessage] = (0, import_react53.useState)("");
@@ -39326,7 +39381,7 @@ var ProviderTab = () => {
39326
39381
  setProviderConfig(applyDefaultModel({
39327
39382
  ...baseConfig,
39328
39383
  gatewayUrl: packageSettings?.gatewayApiUrl || "",
39329
- provider: "openai"
39384
+ provider: "bandit"
39330
39385
  }));
39331
39386
  break;
39332
39387
  case "playground" /* PLAYGROUND */: