@burtson-labs/bandit-engine 2.0.38 → 2.0.40

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 (45) hide show
  1. package/dist/{aiProviderStore-XN7GCBHJ.mjs → aiProviderStore-JMA5RWX7.mjs} +2 -2
  2. package/dist/{chat-5QJNWB7I.mjs → chat-JMWPOSQ4.mjs} +5 -5
  3. package/dist/chat-provider.js +421 -20
  4. package/dist/chat-provider.js.map +1 -1
  5. package/dist/chat-provider.mjs +4 -4
  6. package/dist/{chunk-WO5KFNNW.mjs → chunk-26QQ4CLA.mjs} +62 -24
  7. package/dist/chunk-26QQ4CLA.mjs.map +1 -0
  8. package/dist/{chunk-CDQYBO3Q.mjs → chunk-2ZCR2TDY.mjs} +27 -5
  9. package/dist/chunk-2ZCR2TDY.mjs.map +1 -0
  10. package/dist/{chunk-ECRNIAG6.mjs → chunk-6ELNWXKC.mjs} +4 -4
  11. package/dist/{chunk-EOKIE5HZ.mjs → chunk-75W5VWPV.mjs} +3 -3
  12. package/dist/{chunk-JRCDANLN.mjs → chunk-7KEBNVCO.mjs} +67 -9
  13. package/dist/{chunk-JRCDANLN.mjs.map → chunk-7KEBNVCO.mjs.map} +1 -1
  14. package/dist/{chunk-3A2527TE.mjs → chunk-D3AGKOM6.mjs} +3 -3
  15. package/dist/{chunk-QU5S5QQP.mjs → chunk-QJYPWWA5.mjs} +379 -18
  16. package/dist/chunk-QJYPWWA5.mjs.map +1 -0
  17. package/dist/{chunk-QYH2T4L5.mjs → chunk-VIYBZO5W.mjs} +3 -3
  18. package/dist/{cli/cli.js → cli.js} +424 -12
  19. package/dist/cli.js.map +1 -0
  20. package/dist/{gateway-B0LJ3-jT.d.ts → gateway-5yt_3QDP.d.mts} +4 -4
  21. package/dist/{gateway-B0LJ3-jT.d.mts → gateway-5yt_3QDP.d.ts} +4 -4
  22. package/dist/index.d.mts +2 -2
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.js +598 -101
  25. package/dist/index.js.map +1 -1
  26. package/dist/index.mjs +8 -8
  27. package/dist/management/management.js +596 -99
  28. package/dist/management/management.js.map +1 -1
  29. package/dist/management/management.mjs +6 -6
  30. package/dist/modals/chat-modal/chat-modal.js +430 -29
  31. package/dist/modals/chat-modal/chat-modal.js.map +1 -1
  32. package/dist/modals/chat-modal/chat-modal.mjs +4 -4
  33. package/dist/public-types.d.mts +1 -1
  34. package/dist/public-types.d.ts +1 -1
  35. package/package.json +2 -3
  36. package/dist/chunk-CDQYBO3Q.mjs.map +0 -1
  37. package/dist/chunk-QU5S5QQP.mjs.map +0 -1
  38. package/dist/chunk-WO5KFNNW.mjs.map +0 -1
  39. package/dist/cli/cli.js.map +0 -1
  40. /package/dist/{aiProviderStore-XN7GCBHJ.mjs.map → aiProviderStore-JMA5RWX7.mjs.map} +0 -0
  41. /package/dist/{chat-5QJNWB7I.mjs.map → chat-JMWPOSQ4.mjs.map} +0 -0
  42. /package/dist/{chunk-ECRNIAG6.mjs.map → chunk-6ELNWXKC.mjs.map} +0 -0
  43. /package/dist/{chunk-EOKIE5HZ.mjs.map → chunk-75W5VWPV.mjs.map} +0 -0
  44. /package/dist/{chunk-3A2527TE.mjs.map → chunk-D3AGKOM6.mjs.map} +0 -0
  45. /package/dist/{chunk-QYH2T4L5.mjs.map → chunk-VIYBZO5W.mjs.map} +0 -0
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  useAIProviderStore
3
- } from "./chunk-QU5S5QQP.mjs";
3
+ } from "./chunk-QJYPWWA5.mjs";
4
4
  import "./chunk-KCI46M23.mjs";
5
5
  import "./chunk-BJTO5JO5.mjs";
6
6
  export {
7
7
  useAIProviderStore
8
8
  };
9
- //# sourceMappingURL=aiProviderStore-XN7GCBHJ.mjs.map
9
+ //# sourceMappingURL=aiProviderStore-JMA5RWX7.mjs.map
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  chat_default
3
- } from "./chunk-WO5KFNNW.mjs";
3
+ } from "./chunk-26QQ4CLA.mjs";
4
4
  import "./chunk-ONQMRE2G.mjs";
5
5
  import "./chunk-RTQDQ6TC.mjs";
6
- import "./chunk-QYH2T4L5.mjs";
7
- import "./chunk-CDQYBO3Q.mjs";
6
+ import "./chunk-VIYBZO5W.mjs";
7
+ import "./chunk-2ZCR2TDY.mjs";
8
8
  import "./chunk-XUBYA5I7.mjs";
9
- import "./chunk-QU5S5QQP.mjs";
9
+ import "./chunk-QJYPWWA5.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-5QJNWB7I.mjs.map
15
+ //# sourceMappingURL=chat-JMWPOSQ4.mjs.map
@@ -12,11 +12,11 @@ var __export = (target, all) => {
12
12
  for (var name in all)
13
13
  __defProp(target, name, { get: all[name], enumerable: true });
14
14
  };
15
- var __copyProps = (to, from7, except, desc) => {
16
- if (from7 && typeof from7 === "object" || typeof from7 === "function") {
17
- for (let key of __getOwnPropNames(from7))
15
+ var __copyProps = (to, from8, except, desc) => {
16
+ if (from8 && typeof from8 === "object" || typeof from8 === "function") {
17
+ for (let key of __getOwnPropNames(from8))
18
18
  if (!__hasOwnProp.call(to, key) && key !== except)
19
- __defProp(to, key, { get: () => from7[key], enumerable: !(desc = __getOwnPropDesc(from7, key)) || desc.enumerable });
19
+ __defProp(to, key, { get: () => from8[key], enumerable: !(desc = __getOwnPropDesc(from8, key)) || desc.enumerable });
20
20
  }
21
21
  return to;
22
22
  };
@@ -2223,13 +2223,17 @@ var init_gateway_service = __esm({
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
2225
  const url = `${this._baseUrl}${endpoint}`;
2226
+ const normalizedModel = request.provider === "bandit" ? (() => {
2227
+ const trimmed = (request.model ?? "").replace(/^bandit:/, "").trim();
2228
+ return trimmed !== "" ? trimmed : "bandit-core-1";
2229
+ })() : request.model;
2226
2230
  debugLogger.debug(`Gateway chat request to ${url} with provider: ${request.provider || "default"}`, {
2227
- model: request.model,
2231
+ model: normalizedModel,
2228
2232
  messageCount: request.messages.length,
2229
2233
  hasImages: !!(request.images && request.images.length > 0),
2230
2234
  imageCount: request.images?.length || 0
2231
2235
  });
2232
- const requestBody = { ...request, stream: request.stream !== false };
2236
+ const requestBody = { ...request, model: normalizedModel, stream: request.stream !== false };
2233
2237
  return new import_rxjs6.Observable((observer) => {
2234
2238
  const controller = new AbortController();
2235
2239
  const task = fetch(url, {
@@ -2369,12 +2373,18 @@ var init_gateway_service = __esm({
2369
2373
  generate(request) {
2370
2374
  const endpoint = request.provider ? `/api/${request.provider}/generate` : "/api/generate";
2371
2375
  const url = `${this._baseUrl}${endpoint}`;
2372
- debugLogger.debug(`Gateway generate request to ${url} with provider: ${request.provider || "default"}`);
2376
+ const normalizedModel = request.provider === "bandit" ? (() => {
2377
+ const trimmed = (request.model ?? "").replace(/^bandit:/, "").trim();
2378
+ return trimmed !== "" ? trimmed : "bandit-core-1";
2379
+ })() : request.model;
2380
+ debugLogger.debug(`Gateway generate request to ${url} with provider: ${request.provider || "default"}`, {
2381
+ model: normalizedModel
2382
+ });
2373
2383
  return new import_rxjs6.Observable((observer) => {
2374
2384
  const task = fetch(url, {
2375
2385
  method: "POST",
2376
2386
  headers: this._getHeaders(),
2377
- body: JSON.stringify({ ...request, stream: request.stream !== false })
2387
+ body: JSON.stringify({ ...request, model: normalizedModel, stream: request.stream !== false })
2378
2388
  });
2379
2389
  task.then(async (response) => {
2380
2390
  if (!response.ok) {
@@ -2972,6 +2982,112 @@ var init_ollama_gateway_service = __esm({
2972
2982
  }
2973
2983
  });
2974
2984
 
2985
+ // src/services/gateway/bandit-gateway.service.ts
2986
+ var import_operators5, normalizeBanditModel, isGatewayMessageContent, normalizeBanditMessages, BanditAIGatewayService;
2987
+ var init_bandit_gateway_service = __esm({
2988
+ "src/services/gateway/bandit-gateway.service.ts"() {
2989
+ "use strict";
2990
+ init_gateway_service();
2991
+ import_operators5 = require("rxjs/operators");
2992
+ init_debugLogger();
2993
+ normalizeBanditModel = (model) => {
2994
+ if (typeof model !== "string" || model.trim() === "") {
2995
+ return "bandit-core-1";
2996
+ }
2997
+ const normalized = model.replace(/^bandit:/, "").trim();
2998
+ return normalized === "" ? "bandit-core-1" : normalized;
2999
+ };
3000
+ isGatewayMessageContent = (value) => {
3001
+ if (!value || typeof value !== "object") return false;
3002
+ const candidate = value;
3003
+ if (candidate.type !== "text" && candidate.type !== "image_url") {
3004
+ return false;
3005
+ }
3006
+ if (candidate.type === "text") {
3007
+ return typeof candidate.text === "string";
3008
+ }
3009
+ if (candidate.type === "image_url") {
3010
+ return !!candidate.image_url && typeof candidate.image_url.url === "string";
3011
+ }
3012
+ return false;
3013
+ };
3014
+ normalizeBanditMessages = (messages) => messages.map((message) => {
3015
+ const content = message.content;
3016
+ if (typeof content === "string") {
3017
+ return { role: message.role, content };
3018
+ }
3019
+ if (Array.isArray(content)) {
3020
+ const filtered = content.filter(isGatewayMessageContent);
3021
+ if (filtered.length === 0) {
3022
+ return { role: message.role, content: JSON.stringify(content) };
3023
+ }
3024
+ return {
3025
+ role: message.role,
3026
+ content: filtered
3027
+ };
3028
+ }
3029
+ return { role: message.role, content: content != null ? String(content) : "" };
3030
+ });
3031
+ BanditAIGatewayService = class {
3032
+ _gatewayService;
3033
+ constructor(gatewayUrl, tokenFactory) {
3034
+ this._gatewayService = new GatewayService(gatewayUrl, tokenFactory);
3035
+ debugLogger.info("BanditAIGatewayService initialized", { gatewayUrl });
3036
+ }
3037
+ async validateServiceAvailability(args) {
3038
+ return this._gatewayService.validateServiceAvailability(args);
3039
+ }
3040
+ chat(request) {
3041
+ const model = normalizeBanditModel(request.model);
3042
+ const messages = normalizeBanditMessages(request.messages);
3043
+ const gatewayRequest = {
3044
+ ...request,
3045
+ messages,
3046
+ model,
3047
+ provider: "bandit",
3048
+ stream: request.stream
3049
+ };
3050
+ debugLogger.debug("Bandit Gateway chat request", {
3051
+ model,
3052
+ messageCount: request.messages.length,
3053
+ stream: request.stream
3054
+ });
3055
+ return this._gatewayService.chat(gatewayRequest);
3056
+ }
3057
+ complete(prompt, options) {
3058
+ const model = normalizeBanditModel(options.model);
3059
+ const gatewayRequest = {
3060
+ model,
3061
+ prompt,
3062
+ temperature: options.temperature,
3063
+ max_tokens: options.max_tokens,
3064
+ stream: options.stream,
3065
+ stop: options.stop,
3066
+ provider: "bandit"
3067
+ };
3068
+ debugLogger.debug("Bandit Gateway generate request", {
3069
+ model,
3070
+ promptLength: prompt.length,
3071
+ stream: options.stream
3072
+ });
3073
+ return this._gatewayService.generate(gatewayRequest);
3074
+ }
3075
+ listModels() {
3076
+ debugLogger.debug("Fetching Bandit models through gateway");
3077
+ return this._gatewayService.listModelsByProvider("bandit");
3078
+ }
3079
+ getHealth() {
3080
+ return this._gatewayService.getHealth().pipe(
3081
+ (0, import_operators5.map)((health) => ({
3082
+ ...health,
3083
+ bandit_status: health.providers.find((p) => p.name === "bandit")?.status || "unavailable"
3084
+ }))
3085
+ );
3086
+ }
3087
+ };
3088
+ }
3089
+ });
3090
+
2975
3091
  // src/services/ai-provider/providers/gateway.provider.ts
2976
3092
  var import_rxjs7, GatewayProvider;
2977
3093
  var init_gateway_provider = __esm({
@@ -2985,6 +3101,7 @@ var init_gateway_provider = __esm({
2985
3101
  init_azure_openai_gateway_service();
2986
3102
  init_anthropic_gateway_service();
2987
3103
  init_ollama_gateway_service();
3104
+ init_bandit_gateway_service();
2988
3105
  GatewayProvider = class {
2989
3106
  config;
2990
3107
  gatewayService;
@@ -3026,6 +3143,9 @@ var init_gateway_provider = __esm({
3026
3143
  case "anthropic":
3027
3144
  this.providerSpecificService = new AnthropicGatewayService(gatewayUrl, tokenFactory);
3028
3145
  break;
3146
+ case "bandit":
3147
+ this.providerSpecificService = new BanditAIGatewayService(gatewayUrl, tokenFactory);
3148
+ break;
3029
3149
  case "ollama":
3030
3150
  this.providerSpecificService = new OllamaGatewayService(gatewayUrl, tokenFactory);
3031
3151
  break;
@@ -3040,6 +3160,16 @@ var init_gateway_provider = __esm({
3040
3160
  role: msg.role,
3041
3161
  content: msg.content
3042
3162
  }));
3163
+ const normalizeImageUrl2 = (value) => {
3164
+ if (!value) {
3165
+ return value;
3166
+ }
3167
+ const trimmed = value.trim();
3168
+ if (/^data:/i.test(trimmed) || /^https?:\/\//i.test(trimmed)) {
3169
+ return trimmed;
3170
+ }
3171
+ return `data:image/jpeg;base64,${trimmed}`;
3172
+ };
3043
3173
  if (request.images && request.images.length > 0) {
3044
3174
  const lastUserMessageIndex = messages.map((m) => m.role).lastIndexOf("user");
3045
3175
  if (this.config.provider === "ollama") {
@@ -3049,7 +3179,7 @@ var init_gateway_provider = __esm({
3049
3179
  images: request.images
3050
3180
  };
3051
3181
  }
3052
- } else if (["openai", "azure-openai", "anthropic"].includes(this.config.provider || "")) {
3182
+ } else if (["openai", "azure-openai", "anthropic", "bandit"].includes(this.config.provider || "")) {
3053
3183
  if (lastUserMessageIndex !== -1) {
3054
3184
  const currentMessage = messages[lastUserMessageIndex];
3055
3185
  const contentArray = [
@@ -3058,11 +3188,11 @@ var init_gateway_provider = __esm({
3058
3188
  text: currentMessage.content
3059
3189
  }
3060
3190
  ];
3061
- request.images.forEach((base64Image) => {
3191
+ request.images.forEach((imageRef) => {
3062
3192
  contentArray.push({
3063
3193
  type: "image_url",
3064
3194
  image_url: {
3065
- url: base64Image.startsWith("data:") ? base64Image : `data:image/jpeg;base64,${base64Image}`,
3195
+ url: normalizeImageUrl2(imageRef),
3066
3196
  detail: "auto"
3067
3197
  }
3068
3198
  });
@@ -3071,6 +3201,11 @@ var init_gateway_provider = __esm({
3071
3201
  ...messages[lastUserMessageIndex],
3072
3202
  content: contentArray
3073
3203
  };
3204
+ debugLogger.debug("Gateway provider injected image attachments", {
3205
+ provider: this.config.provider,
3206
+ imageCount: request.images.length,
3207
+ messageIndex: lastUserMessageIndex
3208
+ });
3074
3209
  }
3075
3210
  }
3076
3211
  }
@@ -3579,6 +3714,244 @@ var init_xai_provider = __esm({
3579
3714
  }
3580
3715
  });
3581
3716
 
3717
+ // src/services/ai-provider/providers/bandit-ai.provider.ts
3718
+ var import_rxjs10, DEFAULT_BANDIT_BASE, normalizeImageUrl, injectImagesIntoMessages, BanditAIProvider;
3719
+ var init_bandit_ai_provider = __esm({
3720
+ "src/services/ai-provider/providers/bandit-ai.provider.ts"() {
3721
+ "use strict";
3722
+ import_rxjs10 = require("rxjs");
3723
+ init_common_types();
3724
+ init_debugLogger();
3725
+ DEFAULT_BANDIT_BASE = "https://api.burtson.ai";
3726
+ normalizeImageUrl = (value) => {
3727
+ if (!value) {
3728
+ return null;
3729
+ }
3730
+ const trimmed = value.trim();
3731
+ if (!trimmed) {
3732
+ return null;
3733
+ }
3734
+ if (/^data:/i.test(trimmed) || /^https?:\/\//i.test(trimmed)) {
3735
+ return trimmed;
3736
+ }
3737
+ return `data:image/jpeg;base64,${trimmed}`;
3738
+ };
3739
+ injectImagesIntoMessages = (messages, images) => {
3740
+ const normalized = messages.map((message) => ({
3741
+ role: message.role,
3742
+ content: message.content
3743
+ }));
3744
+ if (!images || images.length === 0) {
3745
+ return normalized;
3746
+ }
3747
+ const normalizedImages = images.map(normalizeImageUrl).filter((url) => Boolean(url));
3748
+ if (normalizedImages.length === 0) {
3749
+ return normalized;
3750
+ }
3751
+ const lastUserIndex = normalized.map((msg) => msg.role).lastIndexOf("user");
3752
+ if (lastUserIndex === -1) {
3753
+ return normalized;
3754
+ }
3755
+ const target = normalized[lastUserIndex];
3756
+ const baseContent = typeof target.content === "string" && target.content.trim().length > 0 ? [
3757
+ {
3758
+ type: "text",
3759
+ text: target.content
3760
+ }
3761
+ ] : [];
3762
+ const imageContent = normalizedImages.map((url) => ({
3763
+ type: "image_url",
3764
+ image_url: { url, detail: "auto" }
3765
+ }));
3766
+ normalized[lastUserIndex] = {
3767
+ role: target.role,
3768
+ content: [...baseContent, ...imageContent]
3769
+ };
3770
+ return normalized;
3771
+ };
3772
+ BanditAIProvider = class {
3773
+ config;
3774
+ baseUrl;
3775
+ constructor(config) {
3776
+ this.config = config;
3777
+ this.baseUrl = (config.baseUrl || DEFAULT_BANDIT_BASE).replace(/\/$/, "");
3778
+ }
3779
+ chat(request) {
3780
+ const url = `${this.baseUrl}/chat/completions`;
3781
+ const messages = injectImagesIntoMessages(request.messages, request.images);
3782
+ const payload = {
3783
+ model: request.model,
3784
+ messages,
3785
+ stream: Boolean(request.stream),
3786
+ temperature: request.temperature,
3787
+ max_tokens: request.maxTokens
3788
+ };
3789
+ if (request.stream) {
3790
+ return this.streamChatRequest(url, payload);
3791
+ }
3792
+ return this.nonStreamChatRequest(url, payload);
3793
+ }
3794
+ generate(request) {
3795
+ const chatRequest = {
3796
+ model: request.model,
3797
+ messages: [{ role: "user", content: request.prompt }],
3798
+ stream: request.stream,
3799
+ options: request.options
3800
+ };
3801
+ return this.chat(chatRequest).pipe(
3802
+ (0, import_rxjs10.map)((response) => ({
3803
+ response: response.message.content,
3804
+ done: response.done
3805
+ }))
3806
+ );
3807
+ }
3808
+ listModels() {
3809
+ const url = `${this.baseUrl}/models`;
3810
+ return (0, import_rxjs10.from)(fetch(url, { headers: this.getHeaders() })).pipe(
3811
+ (0, import_rxjs10.switchMap)((response) => {
3812
+ if (!response.ok) {
3813
+ debugLogger.error("BanditAI listModels failed", { status: response.status, url });
3814
+ return (0, import_rxjs10.throwError)(() => new Error(`Failed to list Bandit models: ${response.status}`));
3815
+ }
3816
+ return (0, import_rxjs10.from)(response.json());
3817
+ }),
3818
+ (0, import_rxjs10.map)(
3819
+ (data) => data.data.map((model) => ({
3820
+ name: model.id,
3821
+ details: {
3822
+ format: "bandit",
3823
+ family: model.object
3824
+ }
3825
+ }))
3826
+ )
3827
+ );
3828
+ }
3829
+ async validateServiceAvailability(args) {
3830
+ const attempt = async (url) => {
3831
+ try {
3832
+ const controller = new AbortController();
3833
+ const timeoutId = setTimeout(() => controller.abort(), args.timeoutMs);
3834
+ const response = await fetch(`${url}/models`, {
3835
+ headers: this.getHeaders(),
3836
+ signal: controller.signal
3837
+ });
3838
+ clearTimeout(timeoutId);
3839
+ return response.ok;
3840
+ } catch (error) {
3841
+ debugLogger.warn("BanditAI availability check failed", { url, error });
3842
+ return false;
3843
+ }
3844
+ };
3845
+ const primary = await attempt(this.baseUrl);
3846
+ if (primary) {
3847
+ return { url: this.baseUrl, isAvailable: true };
3848
+ }
3849
+ if (args.fallbackUrl) {
3850
+ const fallback = args.fallbackUrl.replace(/\/$/, "");
3851
+ if (await attempt(fallback)) {
3852
+ this.baseUrl = fallback;
3853
+ return { url: fallback, isAvailable: true };
3854
+ }
3855
+ }
3856
+ return { url: this.baseUrl, isAvailable: false };
3857
+ }
3858
+ getProviderType() {
3859
+ return "bandit" /* BANDIT */;
3860
+ }
3861
+ getConfig() {
3862
+ return this.config;
3863
+ }
3864
+ streamChatRequest(url, payload) {
3865
+ return new import_rxjs10.Observable((observer) => {
3866
+ const task = fetch(url, {
3867
+ method: "POST",
3868
+ headers: {
3869
+ ...this.getHeaders(),
3870
+ "Content-Type": "application/json"
3871
+ },
3872
+ body: JSON.stringify(payload)
3873
+ });
3874
+ task.then((response) => {
3875
+ if (!response.ok) {
3876
+ observer.error(new Error(`BanditAI request failed: ${response.status}`));
3877
+ return;
3878
+ }
3879
+ const reader = response.body?.getReader();
3880
+ const decoder = new TextDecoder();
3881
+ let buffer = "";
3882
+ const read = () => {
3883
+ reader?.read().then(({ done, value }) => {
3884
+ if (done) {
3885
+ observer.next({ message: { content: "", role: "assistant" }, done: true });
3886
+ observer.complete();
3887
+ return;
3888
+ }
3889
+ buffer += decoder.decode(value, { stream: true });
3890
+ const lines = buffer.split("\n");
3891
+ buffer = lines.pop() ?? "";
3892
+ for (const rawLine of lines) {
3893
+ const line = rawLine.trim();
3894
+ if (!line.startsWith("data: ")) {
3895
+ continue;
3896
+ }
3897
+ const data = line.slice(6).trim();
3898
+ if (data === "[DONE]") {
3899
+ observer.next({ message: { content: "", role: "assistant" }, done: true });
3900
+ observer.complete();
3901
+ return;
3902
+ }
3903
+ try {
3904
+ const parsed = JSON.parse(data);
3905
+ const content = parsed.choices?.[0]?.delta?.content ?? "";
3906
+ if (content) {
3907
+ observer.next({ message: { content, role: "assistant" }, done: false });
3908
+ }
3909
+ } catch (error) {
3910
+ debugLogger.error("BanditAI stream chunk parse failure", { data, error });
3911
+ }
3912
+ }
3913
+ read();
3914
+ }).catch((err) => observer.error(err));
3915
+ };
3916
+ read();
3917
+ }).catch((err) => observer.error(err));
3918
+ });
3919
+ }
3920
+ nonStreamChatRequest(url, payload) {
3921
+ return (0, import_rxjs10.from)(fetch(url, {
3922
+ method: "POST",
3923
+ headers: {
3924
+ ...this.getHeaders(),
3925
+ "Content-Type": "application/json"
3926
+ },
3927
+ body: JSON.stringify(payload)
3928
+ })).pipe(
3929
+ (0, import_rxjs10.switchMap)((response) => {
3930
+ if (!response.ok) {
3931
+ return (0, import_rxjs10.throwError)(() => new Error(`BanditAI request failed: ${response.status}`));
3932
+ }
3933
+ return (0, import_rxjs10.from)(response.json());
3934
+ }),
3935
+ (0, import_rxjs10.map)((data) => ({
3936
+ message: {
3937
+ content: data.choices?.[0]?.message?.content ?? "",
3938
+ role: "assistant"
3939
+ },
3940
+ done: true
3941
+ }))
3942
+ );
3943
+ }
3944
+ getHeaders() {
3945
+ const headers = {};
3946
+ if (this.config.apiKey) {
3947
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
3948
+ }
3949
+ return headers;
3950
+ }
3951
+ };
3952
+ }
3953
+ });
3954
+
3582
3955
  // src/services/ai-provider/ai-provider.factory.ts
3583
3956
  var AIProviderFactory;
3584
3957
  var init_ai_provider_factory = __esm({
@@ -3592,6 +3965,7 @@ var init_ai_provider_factory = __esm({
3592
3965
  init_gateway_provider();
3593
3966
  init_playground_provider();
3594
3967
  init_xai_provider();
3968
+ init_bandit_ai_provider();
3595
3969
  AIProviderFactory = class {
3596
3970
  static createProvider(config) {
3597
3971
  switch (config.type) {
@@ -3605,6 +3979,8 @@ var init_ai_provider_factory = __esm({
3605
3979
  return new AnthropicProvider(config);
3606
3980
  case "xai" /* XAI */:
3607
3981
  return new XAIProvider(config);
3982
+ case "bandit" /* BANDIT */:
3983
+ return new BanditAIProvider(config);
3608
3984
  case "gateway" /* GATEWAY */:
3609
3985
  return new GatewayProvider(config);
3610
3986
  case "playground" /* PLAYGROUND */:
@@ -3619,6 +3995,7 @@ var init_ai_provider_factory = __esm({
3619
3995
  "openai" /* OPENAI */,
3620
3996
  "azure-openai" /* AZURE_OPENAI */,
3621
3997
  "xai" /* XAI */,
3998
+ "bandit" /* BANDIT */,
3622
3999
  "gateway" /* GATEWAY */,
3623
4000
  "playground" /* PLAYGROUND */
3624
4001
  ];
@@ -3636,6 +4013,8 @@ var init_ai_provider_factory = __esm({
3636
4013
  return !!config.apiKey;
3637
4014
  case "xai" /* XAI */:
3638
4015
  return !!config.apiKey;
4016
+ case "bandit" /* BANDIT */:
4017
+ return !!config.apiKey;
3639
4018
  case "gateway" /* GATEWAY */:
3640
4019
  return !!(config.gatewayUrl && config.provider);
3641
4020
  case "playground" /* PLAYGROUND */:
@@ -4427,13 +4806,17 @@ var useConversationStore = (0, import_zustand6.create)((set, get) => ({
4427
4806
  const updatedConversations = conversations.map((c) => {
4428
4807
  if (c.id === currentId && c.history.length > 0) {
4429
4808
  const updatedHistory = [...c.history];
4809
+ const existingImages = updatedHistory[updatedHistory.length - 1].images;
4810
+ const nextImages = Array.isArray(images) && images.length > 0 ? [...images] : Array.isArray(existingImages) && existingImages.length > 0 ? [...existingImages] : existingImages;
4430
4811
  updatedHistory[updatedHistory.length - 1] = {
4431
4812
  ...updatedHistory[updatedHistory.length - 1],
4432
4813
  answer,
4433
4814
  memoryUpdated,
4434
- images: images ?? updatedHistory[updatedHistory.length - 1].images,
4815
+ images: nextImages,
4435
4816
  sourceFiles: sourceFiles ?? updatedHistory[updatedHistory.length - 1].sourceFiles,
4436
- cancelled: cancelled ?? updatedHistory[updatedHistory.length - 1].cancelled
4817
+ cancelled: cancelled ?? updatedHistory[updatedHistory.length - 1].cancelled,
4818
+ placeholder: false,
4819
+ rawQuestion: void 0
4437
4820
  };
4438
4821
  return normalizeConversation({ ...c, history: updatedHistory, updatedAt: /* @__PURE__ */ new Date() });
4439
4822
  }
@@ -4514,6 +4897,24 @@ var useConversationStore = (0, import_zustand6.create)((set, get) => ({
4514
4897
  });
4515
4898
  continue;
4516
4899
  }
4900
+ if (Array.isArray(existing.history) && Array.isArray(conversation.history)) {
4901
+ const mergedHistory = conversation.history.map((incomingEntry, index) => {
4902
+ const existingEntry = existing.history[index];
4903
+ if (!existingEntry) {
4904
+ return incomingEntry;
4905
+ }
4906
+ const mergedImagesSource = Array.isArray(incomingEntry.images) && incomingEntry.images.length > 0 ? incomingEntry.images : existingEntry.images;
4907
+ const mergedImages = Array.isArray(mergedImagesSource) && mergedImagesSource.length > 0 ? [...mergedImagesSource] : mergedImagesSource;
4908
+ return {
4909
+ ...existingEntry,
4910
+ ...incomingEntry,
4911
+ images: mergedImages,
4912
+ placeholder: incomingEntry.placeholder ?? existingEntry.placeholder,
4913
+ rawQuestion: incomingEntry.rawQuestion ?? existingEntry.rawQuestion
4914
+ };
4915
+ });
4916
+ conversation.history = mergedHistory;
4917
+ }
4517
4918
  }
4518
4919
  next.set(conversation.id, conversation);
4519
4920
  toPersist.push(conversation);
@@ -6086,7 +6487,7 @@ var import_mammoth = __toESM(require("mammoth"));
6086
6487
  var pdfjsLib = __toESM(require("pdfjs-dist/legacy/build/pdf"));
6087
6488
 
6088
6489
  // src/services/prompts/conversationStarters.ts
6089
- var import_rxjs10 = require("rxjs");
6490
+ var import_rxjs11 = require("rxjs");
6090
6491
  init_aiProviderStore();
6091
6492
  init_packageSettingsStore();
6092
6493
 
@@ -6244,19 +6645,19 @@ var NotificationService = class {
6244
6645
  var notificationService = new NotificationService();
6245
6646
 
6246
6647
  // src/services/prompts/moodDetection.ts
6247
- var import_rxjs11 = require("rxjs");
6648
+ var import_rxjs12 = require("rxjs");
6248
6649
  init_aiProviderStore();
6249
6650
  init_packageSettingsStore();
6250
6651
  init_debugLogger();
6251
6652
 
6252
6653
  // src/services/prompts/detectUserInterestAndExcitement.ts
6253
- var import_rxjs12 = require("rxjs");
6654
+ var import_rxjs13 = require("rxjs");
6254
6655
  init_aiProviderStore();
6255
6656
  init_packageSettingsStore();
6256
6657
  init_debugLogger();
6257
6658
 
6258
6659
  // src/services/prompts/documentSummarization.ts
6259
- var import_rxjs13 = require("rxjs");
6660
+ var import_rxjs14 = require("rxjs");
6260
6661
  init_aiProviderStore();
6261
6662
  init_packageSettingsStore();
6262
6663
  init_debugLogger();
@@ -6284,8 +6685,8 @@ ${content.slice(0, 4e3)}
6284
6685
  stream: false,
6285
6686
  options: { temperature: 0.3, num_predict: 100 }
6286
6687
  });
6287
- const summary$ = data$.pipe((0, import_rxjs13.map)((d) => d.response.trim()));
6288
- const summary = await (0, import_rxjs13.lastValueFrom)(summary$);
6688
+ const summary$ = data$.pipe((0, import_rxjs14.map)((d) => d.response.trim()));
6689
+ const summary = await (0, import_rxjs14.lastValueFrom)(summary$);
6289
6690
  debugLogger.ragDebug("summarizeDocument result", { name, summary });
6290
6691
  return summary || `Document summary for ${name}`;
6291
6692
  } catch (error) {
@@ -6295,7 +6696,7 @@ ${content.slice(0, 4e3)}
6295
6696
  };
6296
6697
 
6297
6698
  // src/services/prompts/documentRelevance.ts
6298
- var import_rxjs14 = require("rxjs");
6699
+ var import_rxjs15 = require("rxjs");
6299
6700
  init_aiProviderStore();
6300
6701
  init_packageSettingsStore();
6301
6702
  init_debugLogger();