@retrivora-ai/rag-engine 0.3.1 → 0.3.3

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/.env.example CHANGED
@@ -20,7 +20,7 @@ VECTOR_DB_REST_API_KEY=your-rest-api-key
20
20
  # VECTOR_DB_UPSERT_PATH=/upsert
21
21
 
22
22
  # ─── LLM ──────────────────────────────────────────────────────
23
- # Choose: openai | anthropic | ollama | universal_rest
23
+ # Choose: openai | anthropic | ollama | gemini | universal_rest
24
24
  LLM_PROVIDER=openai
25
25
  LLM_MODEL=gpt-4o
26
26
  LLM_MAX_TOKENS=1024
@@ -33,6 +33,9 @@ OPENAI_API_KEY=sk-...
33
33
  # Anthropic (if provider=anthropic)
34
34
  ANTHROPIC_API_KEY=sk-ant-...
35
35
 
36
+ # Gemini (if provider=gemini)
37
+ GEMINI_API_KEY=AIza...
38
+
36
39
  # Ollama (if provider=ollama)
37
40
  LLM_BASE_URL=http://localhost:11434
38
41
 
@@ -52,7 +55,7 @@ VECTOR_BASE_URL=http://localhost:6333
52
55
  VECTOR_DB_INDEX=my-index
53
56
 
54
57
  # ─── Embedding ────────────────────────────────────────────────
55
- # Choose: openai | ollama | custom
58
+ # Choose: openai | ollama | gemini | custom
56
59
  EMBEDDING_PROVIDER=openai
57
60
  EMBEDDING_MODEL=text-embedding-3-small
58
61
  EMBEDDING_DIMENSIONS=1536
@@ -20,12 +20,23 @@ interface ChatResponse {
20
20
  sources: VectorMatch[];
21
21
  }
22
22
 
23
+ /**
24
+ * constants.ts — Centralized definitions of acceptable configuration values.
25
+ *
26
+ * This file serves as the single source of truth for all statically supported
27
+ * providers and stylistic options in the Retrivora AI RAG Engine.
28
+ */
29
+ declare const VECTOR_DB_PROVIDERS: readonly ["pinecone", "pgvector", "postgresql", "mongodb", "milvus", "qdrant", "chromadb", "redis", "weaviate", "rest", "universal_rest", "custom"];
30
+ declare const LLM_PROVIDERS: readonly ["openai", "anthropic", "ollama", "gemini", "rest", "universal_rest", "custom"];
31
+ declare const EMBEDDING_PROVIDERS: readonly ["openai", "ollama", "gemini", "rest", "universal_rest", "custom"];
32
+
23
33
  /**
24
34
  * Master configuration interface for Retrivora AI.
25
35
  * Each consuming project provides one RagConfig object to drive
26
36
  * vector DB selection, LLM selection, embedding, and UI branding.
27
37
  */
28
- type VectorDBProvider = 'pinecone' | 'pgvector' | 'postgresql' | 'mongodb' | 'milvus' | 'qdrant' | 'chromadb' | 'redis' | 'weaviate' | 'rest' | 'universal_rest' | 'custom';
38
+
39
+ type VectorDBProvider = typeof VECTOR_DB_PROVIDERS[number];
29
40
  interface VectorDBConfig {
30
41
  /** Which vector database to use */
31
42
  provider: VectorDBProvider;
@@ -51,7 +62,7 @@ interface VectorDBConfig {
51
62
  */
52
63
  options: Record<string, unknown>;
53
64
  }
54
- type LLMProvider = 'openai' | 'anthropic' | 'ollama' | 'rest' | 'universal_rest' | 'custom';
65
+ type LLMProvider = typeof LLM_PROVIDERS[number];
55
66
  interface LLMConfig {
56
67
  /** Which LLM provider to use */
57
68
  provider: LLMProvider;
@@ -77,7 +88,7 @@ interface LLMConfig {
77
88
  */
78
89
  options?: Record<string, unknown>;
79
90
  }
80
- type EmbeddingProvider = 'openai' | 'ollama' | 'rest' | 'universal_rest' | 'custom';
91
+ type EmbeddingProvider = typeof EMBEDDING_PROVIDERS[number];
81
92
  interface EmbeddingConfig {
82
93
  /** Which embedding provider to use */
83
94
  provider: EmbeddingProvider;
@@ -20,12 +20,23 @@ interface ChatResponse {
20
20
  sources: VectorMatch[];
21
21
  }
22
22
 
23
+ /**
24
+ * constants.ts — Centralized definitions of acceptable configuration values.
25
+ *
26
+ * This file serves as the single source of truth for all statically supported
27
+ * providers and stylistic options in the Retrivora AI RAG Engine.
28
+ */
29
+ declare const VECTOR_DB_PROVIDERS: readonly ["pinecone", "pgvector", "postgresql", "mongodb", "milvus", "qdrant", "chromadb", "redis", "weaviate", "rest", "universal_rest", "custom"];
30
+ declare const LLM_PROVIDERS: readonly ["openai", "anthropic", "ollama", "gemini", "rest", "universal_rest", "custom"];
31
+ declare const EMBEDDING_PROVIDERS: readonly ["openai", "ollama", "gemini", "rest", "universal_rest", "custom"];
32
+
23
33
  /**
24
34
  * Master configuration interface for Retrivora AI.
25
35
  * Each consuming project provides one RagConfig object to drive
26
36
  * vector DB selection, LLM selection, embedding, and UI branding.
27
37
  */
28
- type VectorDBProvider = 'pinecone' | 'pgvector' | 'postgresql' | 'mongodb' | 'milvus' | 'qdrant' | 'chromadb' | 'redis' | 'weaviate' | 'rest' | 'universal_rest' | 'custom';
38
+
39
+ type VectorDBProvider = typeof VECTOR_DB_PROVIDERS[number];
29
40
  interface VectorDBConfig {
30
41
  /** Which vector database to use */
31
42
  provider: VectorDBProvider;
@@ -51,7 +62,7 @@ interface VectorDBConfig {
51
62
  */
52
63
  options: Record<string, unknown>;
53
64
  }
54
- type LLMProvider = 'openai' | 'anthropic' | 'ollama' | 'rest' | 'universal_rest' | 'custom';
65
+ type LLMProvider = typeof LLM_PROVIDERS[number];
55
66
  interface LLMConfig {
56
67
  /** Which LLM provider to use */
57
68
  provider: LLMProvider;
@@ -77,7 +88,7 @@ interface LLMConfig {
77
88
  */
78
89
  options?: Record<string, unknown>;
79
90
  }
80
- type EmbeddingProvider = 'openai' | 'ollama' | 'rest' | 'universal_rest' | 'custom';
91
+ type EmbeddingProvider = typeof EMBEDDING_PROVIDERS[number];
81
92
  interface EmbeddingConfig {
82
93
  /** Which embedding provider to use */
83
94
  provider: EmbeddingProvider;
@@ -11,7 +11,7 @@ import {
11
11
  // src/handlers/index.ts
12
12
  import { NextResponse } from "next/server";
13
13
 
14
- // src/config/serverConfig.ts
14
+ // src/config/constants.ts
15
15
  var VECTOR_DB_PROVIDERS = [
16
16
  "pinecone",
17
17
  "pgvector",
@@ -26,8 +26,34 @@ var VECTOR_DB_PROVIDERS = [
26
26
  "universal_rest",
27
27
  "custom"
28
28
  ];
29
- var LLM_PROVIDERS = ["openai", "anthropic", "ollama", "rest", "universal_rest", "custom"];
30
- var EMBEDDING_PROVIDERS = ["openai", "ollama", "rest", "universal_rest", "custom"];
29
+ var LLM_PROVIDERS = [
30
+ "openai",
31
+ "anthropic",
32
+ "ollama",
33
+ "gemini",
34
+ "rest",
35
+ "universal_rest",
36
+ "custom"
37
+ ];
38
+ var EMBEDDING_PROVIDERS = [
39
+ "openai",
40
+ "ollama",
41
+ "gemini",
42
+ "rest",
43
+ "universal_rest",
44
+ "custom"
45
+ ];
46
+ var PROVIDERS_WITH_EMBEDDINGS = [
47
+ "openai",
48
+ "ollama",
49
+ "gemini",
50
+ "rest",
51
+ "universal_rest"
52
+ ];
53
+ var UI_VISUAL_STYLES = ["glass", "solid"];
54
+ var UI_BORDER_RADIUS_OPTIONS = ["none", "sm", "md", "lg", "xl", "full"];
55
+
56
+ // src/config/serverConfig.ts
31
57
  function readString(env, name) {
32
58
  var _a;
33
59
  const value = (_a = env[name]) == null ? void 0 : _a.trim();
@@ -94,6 +120,7 @@ function getRagConfig(env = process.env) {
94
120
  const llmApiKeyByProvider = {
95
121
  openai: readString(env, "OPENAI_API_KEY"),
96
122
  anthropic: readString(env, "ANTHROPIC_API_KEY"),
123
+ gemini: readString(env, "GEMINI_API_KEY"),
97
124
  ollama: void 0,
98
125
  universal_rest: readString(env, "LLM_API_KEY"),
99
126
  rest: readString(env, "LLM_API_KEY"),
@@ -101,6 +128,7 @@ function getRagConfig(env = process.env) {
101
128
  };
102
129
  const embeddingApiKeyByProvider = {
103
130
  openai: readString(env, "OPENAI_API_KEY"),
131
+ gemini: readString(env, "GEMINI_API_KEY"),
104
132
  ollama: void 0,
105
133
  universal_rest: (_q = readString(env, "EMBEDDING_API_KEY")) != null ? _q : readString(env, "OPENAI_API_KEY"),
106
134
  custom: (_r = readString(env, "EMBEDDING_API_KEY")) != null ? _r : readString(env, "OPENAI_API_KEY")
@@ -515,6 +543,16 @@ var ConfigValidator = class {
515
543
  });
516
544
  }
517
545
  break;
546
+ case "gemini":
547
+ if (!config.apiKey) {
548
+ errors.push({
549
+ field: "llm.apiKey",
550
+ message: "Gemini API key is required",
551
+ suggestion: "Set GEMINI_API_KEY environment variable",
552
+ severity: "error"
553
+ });
554
+ }
555
+ break;
518
556
  case "ollama":
519
557
  if (!config.baseUrl) {
520
558
  errors.push({
@@ -581,6 +619,14 @@ var ConfigValidator = class {
581
619
  severity: "error"
582
620
  });
583
621
  }
622
+ if (config.provider === "gemini" && !config.apiKey) {
623
+ errors.push({
624
+ field: "embedding.apiKey",
625
+ message: "Gemini API key is required for embedding",
626
+ suggestion: "Set GEMINI_API_KEY environment variable",
627
+ severity: "error"
628
+ });
629
+ }
584
630
  if (config.provider === "ollama" && !config.baseUrl) {
585
631
  errors.push({
586
632
  field: "embedding.baseUrl",
@@ -611,21 +657,19 @@ var ConfigValidator = class {
611
657
  }
612
658
  }
613
659
  if (config.borderRadius) {
614
- const validValues = ["none", "sm", "md", "lg", "xl", "full"];
615
- if (!validValues.includes(config.borderRadius)) {
660
+ if (!UI_BORDER_RADIUS_OPTIONS.includes(config.borderRadius)) {
616
661
  errors.push({
617
662
  field: "ui.borderRadius",
618
- message: `borderRadius must be one of: ${validValues.join(", ")}`,
663
+ message: `borderRadius must be one of: ${UI_BORDER_RADIUS_OPTIONS.join(", ")}`,
619
664
  severity: "warning"
620
665
  });
621
666
  }
622
667
  }
623
668
  if (config.visualStyle) {
624
- const validValues = ["glass", "solid"];
625
- if (!validValues.includes(config.visualStyle)) {
669
+ if (!UI_VISUAL_STYLES.includes(config.visualStyle)) {
626
670
  errors.push({
627
671
  field: "ui.visualStyle",
628
- message: `visualStyle must be one of: ${validValues.join(", ")}`,
672
+ message: `visualStyle must be one of: ${UI_VISUAL_STYLES.join(", ")}`,
629
673
  severity: "warning"
630
674
  });
631
675
  }
@@ -959,6 +1003,101 @@ ${context}`;
959
1003
  }
960
1004
  };
961
1005
 
1006
+ // src/llm/providers/GeminiProvider.ts
1007
+ import { GoogleGenAI } from "@google/genai";
1008
+ var GeminiProvider = class {
1009
+ constructor(llmConfig, embeddingConfig) {
1010
+ if (!llmConfig.apiKey) throw new Error("[GeminiProvider] llmConfig.apiKey is required");
1011
+ this.client = new GoogleGenAI({ apiKey: llmConfig.apiKey });
1012
+ this.llmConfig = llmConfig;
1013
+ this.embeddingConfig = embeddingConfig;
1014
+ }
1015
+ async chat(messages, context, options) {
1016
+ var _a, _b, _c, _d, _e, _f;
1017
+ const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
1018
+
1019
+ Context:
1020
+ ${context}`;
1021
+ const systemInstruction = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
1022
+
1023
+ Context:
1024
+ ${context}`;
1025
+ const geminiMessages = messages.map((m) => ({
1026
+ role: m.role === "assistant" ? "model" : "user",
1027
+ parts: [{ text: m.content }]
1028
+ }));
1029
+ const response = await this.client.models.generateContent({
1030
+ model: this.llmConfig.model,
1031
+ contents: geminiMessages,
1032
+ config: {
1033
+ systemInstruction,
1034
+ temperature: (_c = (_b = options == null ? void 0 : options.temperature) != null ? _b : this.llmConfig.temperature) != null ? _c : 0.7,
1035
+ maxOutputTokens: (_e = (_d = options == null ? void 0 : options.maxTokens) != null ? _d : this.llmConfig.maxTokens) != null ? _e : 1024,
1036
+ stopSequences: options == null ? void 0 : options.stop
1037
+ }
1038
+ });
1039
+ return (_f = response.text) != null ? _f : "";
1040
+ }
1041
+ async embed(text, options) {
1042
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1043
+ const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-004";
1044
+ const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
1045
+ const client = apiKey !== this.llmConfig.apiKey ? new GoogleGenAI({ apiKey }) : this.client;
1046
+ let content = text;
1047
+ const queryPrefix = (_f = this.embeddingConfig) == null ? void 0 : _f.queryPrefix;
1048
+ const docPrefix = (_g = this.embeddingConfig) == null ? void 0 : _g.documentPrefix;
1049
+ if ((options == null ? void 0 : options.taskType) === "query" && queryPrefix) {
1050
+ if (!content.startsWith(queryPrefix)) {
1051
+ content = `${queryPrefix}${text}`;
1052
+ }
1053
+ } else if ((options == null ? void 0 : options.taskType) === "document" && docPrefix) {
1054
+ if (!content.startsWith(docPrefix)) {
1055
+ content = `${docPrefix}${text}`;
1056
+ }
1057
+ }
1058
+ const response = await client.models.embedContent({
1059
+ model,
1060
+ contents: content
1061
+ });
1062
+ return (_j = (_i = (_h = response.embeddings) == null ? void 0 : _h[0]) == null ? void 0 : _i.values) != null ? _j : [];
1063
+ }
1064
+ async batchEmbed(texts, options) {
1065
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1066
+ const vectors = [];
1067
+ const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-004";
1068
+ const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
1069
+ const client = apiKey !== this.llmConfig.apiKey ? new GoogleGenAI({ apiKey }) : this.client;
1070
+ let contents = texts;
1071
+ const queryPrefix = (_f = this.embeddingConfig) == null ? void 0 : _f.queryPrefix;
1072
+ const docPrefix = (_g = this.embeddingConfig) == null ? void 0 : _g.documentPrefix;
1073
+ if ((options == null ? void 0 : options.taskType) === "query" && queryPrefix) {
1074
+ contents = texts.map((text) => text.startsWith(queryPrefix) ? text : `${queryPrefix}${text}`);
1075
+ } else if ((options == null ? void 0 : options.taskType) === "document" && docPrefix) {
1076
+ contents = texts.map((text) => text.startsWith(docPrefix) ? text : `${docPrefix}${text}`);
1077
+ }
1078
+ const response = await client.models.embedContent({
1079
+ model,
1080
+ contents
1081
+ });
1082
+ return (_i = (_h = response.embeddings) == null ? void 0 : _h.map((e) => {
1083
+ var _a2;
1084
+ return (_a2 = e.values) != null ? _a2 : [];
1085
+ })) != null ? _i : [];
1086
+ }
1087
+ async ping() {
1088
+ try {
1089
+ await this.client.models.embedContent({
1090
+ model: "text-embedding-004",
1091
+ contents: "ping"
1092
+ });
1093
+ return true;
1094
+ } catch (err) {
1095
+ console.error("[GeminiProvider] Ping failed:", err);
1096
+ return false;
1097
+ }
1098
+ }
1099
+ };
1100
+
962
1101
  // src/llm/providers/UniversalLLMAdapter.ts
963
1102
  import axios2 from "axios";
964
1103
 
@@ -1155,6 +1294,8 @@ var LLMFactory = class _LLMFactory {
1155
1294
  return new AnthropicProvider(llmConfig, embeddingConfig);
1156
1295
  case "ollama":
1157
1296
  return new OllamaProvider(llmConfig, embeddingConfig);
1297
+ case "gemini":
1298
+ return new GeminiProvider(llmConfig, embeddingConfig);
1158
1299
  case "rest":
1159
1300
  case "universal_rest":
1160
1301
  case "custom":
@@ -1546,8 +1687,7 @@ var EmbeddingStrategyResolver = class {
1546
1687
  * Check if an LLM provider natively supports embeddings
1547
1688
  */
1548
1689
  static supportsEmbedding(provider) {
1549
- const providersWithEmbedding = ["openai", "ollama", "rest", "universal_rest"];
1550
- return providersWithEmbedding.includes(provider);
1690
+ return PROVIDERS_WITH_EMBEDDINGS.includes(provider);
1551
1691
  }
1552
1692
  /**
1553
1693
  * Get a human-readable description of the strategy
@@ -1,3 +1,3 @@
1
- import '../RagConfig-D3Inaf9N.mjs';
2
- export { c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from '../index-Ymwm-_OR.mjs';
1
+ import '../RagConfig-Bpp39-um.mjs';
2
+ export { c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from '../index-CZE72wnV.mjs';
3
3
  import 'next/server';
@@ -1,3 +1,3 @@
1
- import '../RagConfig-D3Inaf9N.js';
2
- export { c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from '../index-BhNJQ2SS.js';
1
+ import '../RagConfig-Bpp39-um.js';
2
+ export { c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from '../index-DSaQwkKA.js';
3
3
  import 'next/server';
@@ -1179,7 +1179,7 @@ var import_server = require("next/server");
1179
1179
  // src/core/ConfigResolver.ts
1180
1180
  init_templateUtils();
1181
1181
 
1182
- // src/config/serverConfig.ts
1182
+ // src/config/constants.ts
1183
1183
  var VECTOR_DB_PROVIDERS = [
1184
1184
  "pinecone",
1185
1185
  "pgvector",
@@ -1194,8 +1194,34 @@ var VECTOR_DB_PROVIDERS = [
1194
1194
  "universal_rest",
1195
1195
  "custom"
1196
1196
  ];
1197
- var LLM_PROVIDERS = ["openai", "anthropic", "ollama", "rest", "universal_rest", "custom"];
1198
- var EMBEDDING_PROVIDERS = ["openai", "ollama", "rest", "universal_rest", "custom"];
1197
+ var LLM_PROVIDERS = [
1198
+ "openai",
1199
+ "anthropic",
1200
+ "ollama",
1201
+ "gemini",
1202
+ "rest",
1203
+ "universal_rest",
1204
+ "custom"
1205
+ ];
1206
+ var EMBEDDING_PROVIDERS = [
1207
+ "openai",
1208
+ "ollama",
1209
+ "gemini",
1210
+ "rest",
1211
+ "universal_rest",
1212
+ "custom"
1213
+ ];
1214
+ var PROVIDERS_WITH_EMBEDDINGS = [
1215
+ "openai",
1216
+ "ollama",
1217
+ "gemini",
1218
+ "rest",
1219
+ "universal_rest"
1220
+ ];
1221
+ var UI_VISUAL_STYLES = ["glass", "solid"];
1222
+ var UI_BORDER_RADIUS_OPTIONS = ["none", "sm", "md", "lg", "xl", "full"];
1223
+
1224
+ // src/config/serverConfig.ts
1199
1225
  function readString(env, name) {
1200
1226
  var _a;
1201
1227
  const value = (_a = env[name]) == null ? void 0 : _a.trim();
@@ -1262,6 +1288,7 @@ function getRagConfig(env = process.env) {
1262
1288
  const llmApiKeyByProvider = {
1263
1289
  openai: readString(env, "OPENAI_API_KEY"),
1264
1290
  anthropic: readString(env, "ANTHROPIC_API_KEY"),
1291
+ gemini: readString(env, "GEMINI_API_KEY"),
1265
1292
  ollama: void 0,
1266
1293
  universal_rest: readString(env, "LLM_API_KEY"),
1267
1294
  rest: readString(env, "LLM_API_KEY"),
@@ -1269,6 +1296,7 @@ function getRagConfig(env = process.env) {
1269
1296
  };
1270
1297
  const embeddingApiKeyByProvider = {
1271
1298
  openai: readString(env, "OPENAI_API_KEY"),
1299
+ gemini: readString(env, "GEMINI_API_KEY"),
1272
1300
  ollama: void 0,
1273
1301
  universal_rest: (_q = readString(env, "EMBEDDING_API_KEY")) != null ? _q : readString(env, "OPENAI_API_KEY"),
1274
1302
  custom: (_r = readString(env, "EMBEDDING_API_KEY")) != null ? _r : readString(env, "OPENAI_API_KEY")
@@ -1683,6 +1711,16 @@ var ConfigValidator = class {
1683
1711
  });
1684
1712
  }
1685
1713
  break;
1714
+ case "gemini":
1715
+ if (!config.apiKey) {
1716
+ errors.push({
1717
+ field: "llm.apiKey",
1718
+ message: "Gemini API key is required",
1719
+ suggestion: "Set GEMINI_API_KEY environment variable",
1720
+ severity: "error"
1721
+ });
1722
+ }
1723
+ break;
1686
1724
  case "ollama":
1687
1725
  if (!config.baseUrl) {
1688
1726
  errors.push({
@@ -1749,6 +1787,14 @@ var ConfigValidator = class {
1749
1787
  severity: "error"
1750
1788
  });
1751
1789
  }
1790
+ if (config.provider === "gemini" && !config.apiKey) {
1791
+ errors.push({
1792
+ field: "embedding.apiKey",
1793
+ message: "Gemini API key is required for embedding",
1794
+ suggestion: "Set GEMINI_API_KEY environment variable",
1795
+ severity: "error"
1796
+ });
1797
+ }
1752
1798
  if (config.provider === "ollama" && !config.baseUrl) {
1753
1799
  errors.push({
1754
1800
  field: "embedding.baseUrl",
@@ -1779,21 +1825,19 @@ var ConfigValidator = class {
1779
1825
  }
1780
1826
  }
1781
1827
  if (config.borderRadius) {
1782
- const validValues = ["none", "sm", "md", "lg", "xl", "full"];
1783
- if (!validValues.includes(config.borderRadius)) {
1828
+ if (!UI_BORDER_RADIUS_OPTIONS.includes(config.borderRadius)) {
1784
1829
  errors.push({
1785
1830
  field: "ui.borderRadius",
1786
- message: `borderRadius must be one of: ${validValues.join(", ")}`,
1831
+ message: `borderRadius must be one of: ${UI_BORDER_RADIUS_OPTIONS.join(", ")}`,
1787
1832
  severity: "warning"
1788
1833
  });
1789
1834
  }
1790
1835
  }
1791
1836
  if (config.visualStyle) {
1792
- const validValues = ["glass", "solid"];
1793
- if (!validValues.includes(config.visualStyle)) {
1837
+ if (!UI_VISUAL_STYLES.includes(config.visualStyle)) {
1794
1838
  errors.push({
1795
1839
  field: "ui.visualStyle",
1796
- message: `visualStyle must be one of: ${validValues.join(", ")}`,
1840
+ message: `visualStyle must be one of: ${UI_VISUAL_STYLES.join(", ")}`,
1797
1841
  severity: "warning"
1798
1842
  });
1799
1843
  }
@@ -2127,6 +2171,101 @@ ${context}`;
2127
2171
  }
2128
2172
  };
2129
2173
 
2174
+ // src/llm/providers/GeminiProvider.ts
2175
+ var import_genai = require("@google/genai");
2176
+ var GeminiProvider = class {
2177
+ constructor(llmConfig, embeddingConfig) {
2178
+ if (!llmConfig.apiKey) throw new Error("[GeminiProvider] llmConfig.apiKey is required");
2179
+ this.client = new import_genai.GoogleGenAI({ apiKey: llmConfig.apiKey });
2180
+ this.llmConfig = llmConfig;
2181
+ this.embeddingConfig = embeddingConfig;
2182
+ }
2183
+ async chat(messages, context, options) {
2184
+ var _a, _b, _c, _d, _e, _f;
2185
+ const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
2186
+
2187
+ Context:
2188
+ ${context}`;
2189
+ const systemInstruction = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
2190
+
2191
+ Context:
2192
+ ${context}`;
2193
+ const geminiMessages = messages.map((m) => ({
2194
+ role: m.role === "assistant" ? "model" : "user",
2195
+ parts: [{ text: m.content }]
2196
+ }));
2197
+ const response = await this.client.models.generateContent({
2198
+ model: this.llmConfig.model,
2199
+ contents: geminiMessages,
2200
+ config: {
2201
+ systemInstruction,
2202
+ temperature: (_c = (_b = options == null ? void 0 : options.temperature) != null ? _b : this.llmConfig.temperature) != null ? _c : 0.7,
2203
+ maxOutputTokens: (_e = (_d = options == null ? void 0 : options.maxTokens) != null ? _d : this.llmConfig.maxTokens) != null ? _e : 1024,
2204
+ stopSequences: options == null ? void 0 : options.stop
2205
+ }
2206
+ });
2207
+ return (_f = response.text) != null ? _f : "";
2208
+ }
2209
+ async embed(text, options) {
2210
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2211
+ const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-004";
2212
+ const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
2213
+ const client = apiKey !== this.llmConfig.apiKey ? new import_genai.GoogleGenAI({ apiKey }) : this.client;
2214
+ let content = text;
2215
+ const queryPrefix = (_f = this.embeddingConfig) == null ? void 0 : _f.queryPrefix;
2216
+ const docPrefix = (_g = this.embeddingConfig) == null ? void 0 : _g.documentPrefix;
2217
+ if ((options == null ? void 0 : options.taskType) === "query" && queryPrefix) {
2218
+ if (!content.startsWith(queryPrefix)) {
2219
+ content = `${queryPrefix}${text}`;
2220
+ }
2221
+ } else if ((options == null ? void 0 : options.taskType) === "document" && docPrefix) {
2222
+ if (!content.startsWith(docPrefix)) {
2223
+ content = `${docPrefix}${text}`;
2224
+ }
2225
+ }
2226
+ const response = await client.models.embedContent({
2227
+ model,
2228
+ contents: content
2229
+ });
2230
+ return (_j = (_i = (_h = response.embeddings) == null ? void 0 : _h[0]) == null ? void 0 : _i.values) != null ? _j : [];
2231
+ }
2232
+ async batchEmbed(texts, options) {
2233
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2234
+ const vectors = [];
2235
+ const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-004";
2236
+ const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
2237
+ const client = apiKey !== this.llmConfig.apiKey ? new import_genai.GoogleGenAI({ apiKey }) : this.client;
2238
+ let contents = texts;
2239
+ const queryPrefix = (_f = this.embeddingConfig) == null ? void 0 : _f.queryPrefix;
2240
+ const docPrefix = (_g = this.embeddingConfig) == null ? void 0 : _g.documentPrefix;
2241
+ if ((options == null ? void 0 : options.taskType) === "query" && queryPrefix) {
2242
+ contents = texts.map((text) => text.startsWith(queryPrefix) ? text : `${queryPrefix}${text}`);
2243
+ } else if ((options == null ? void 0 : options.taskType) === "document" && docPrefix) {
2244
+ contents = texts.map((text) => text.startsWith(docPrefix) ? text : `${docPrefix}${text}`);
2245
+ }
2246
+ const response = await client.models.embedContent({
2247
+ model,
2248
+ contents
2249
+ });
2250
+ return (_i = (_h = response.embeddings) == null ? void 0 : _h.map((e) => {
2251
+ var _a2;
2252
+ return (_a2 = e.values) != null ? _a2 : [];
2253
+ })) != null ? _i : [];
2254
+ }
2255
+ async ping() {
2256
+ try {
2257
+ await this.client.models.embedContent({
2258
+ model: "text-embedding-004",
2259
+ contents: "ping"
2260
+ });
2261
+ return true;
2262
+ } catch (err) {
2263
+ console.error("[GeminiProvider] Ping failed:", err);
2264
+ return false;
2265
+ }
2266
+ }
2267
+ };
2268
+
2130
2269
  // src/llm/providers/UniversalLLMAdapter.ts
2131
2270
  var import_axios2 = __toESM(require("axios"));
2132
2271
  init_templateUtils();
@@ -2285,6 +2424,8 @@ var LLMFactory = class _LLMFactory {
2285
2424
  return new AnthropicProvider(llmConfig, embeddingConfig);
2286
2425
  case "ollama":
2287
2426
  return new OllamaProvider(llmConfig, embeddingConfig);
2427
+ case "gemini":
2428
+ return new GeminiProvider(llmConfig, embeddingConfig);
2288
2429
  case "rest":
2289
2430
  case "universal_rest":
2290
2431
  case "custom":
@@ -2670,8 +2811,7 @@ var EmbeddingStrategyResolver = class {
2670
2811
  * Check if an LLM provider natively supports embeddings
2671
2812
  */
2672
2813
  static supportsEmbedding(provider) {
2673
- const providersWithEmbedding = ["openai", "ollama", "rest", "universal_rest"];
2674
- return providersWithEmbedding.includes(provider);
2814
+ return PROVIDERS_WITH_EMBEDDINGS.includes(provider);
2675
2815
  }
2676
2816
  /**
2677
2817
  * Get a human-readable description of the strategy
@@ -3,7 +3,7 @@ import {
3
3
  createHealthHandler,
4
4
  createIngestHandler,
5
5
  createUploadHandler
6
- } from "../chunk-GT72OIOD.mjs";
6
+ } from "../chunk-SNPFZBDK.mjs";
7
7
  import "../chunk-EDLTMSNY.mjs";
8
8
  import "../chunk-FWCSY2DS.mjs";
9
9
  export {
@@ -1,4 +1,4 @@
1
- import { c as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, a as RagConfig, C as ChatResponse } from './RagConfig-D3Inaf9N.mjs';
1
+ import { c as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, a as RagConfig, C as ChatResponse } from './RagConfig-Bpp39-um.mjs';
2
2
  import { NextRequest, NextResponse } from 'next/server';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { c as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, a as RagConfig, C as ChatResponse } from './RagConfig-D3Inaf9N.js';
1
+ import { c as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, a as RagConfig, C as ChatResponse } from './RagConfig-Bpp39-um.js';
2
2
  import { NextRequest, NextResponse } from 'next/server';
3
3
 
4
4
  /**
package/dist/index.d.mts CHANGED
@@ -2,8 +2,8 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React$1, { ReactNode } from 'react';
3
3
  import { C as ChatMessage } from './DocumentChunker-BICIjSuG.mjs';
4
4
  export { a as ChatOptions, b as Chunk, c as ChunkOptions, E as EmbedOptions, I as ILLMProvider } from './DocumentChunker-BICIjSuG.mjs';
5
- import { V as VectorMatch, U as UIConfig } from './RagConfig-D3Inaf9N.mjs';
6
- export { C as ChatResponse, E as EmbeddingConfig, I as IngestDocument, L as LLMConfig, R as RAGConfig, a as RagConfig, b as UpsertDocument, c as VectorDBConfig } from './RagConfig-D3Inaf9N.mjs';
5
+ import { V as VectorMatch, U as UIConfig } from './RagConfig-Bpp39-um.mjs';
6
+ export { C as ChatResponse, E as EmbeddingConfig, I as IngestDocument, L as LLMConfig, R as RAGConfig, a as RagConfig, b as UpsertDocument, c as VectorDBConfig } from './RagConfig-Bpp39-um.mjs';
7
7
 
8
8
  interface ChatWidgetProps {
9
9
  /** Position of the floating button. Defaults to bottom-right. */
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React$1, { ReactNode } from 'react';
3
3
  import { C as ChatMessage } from './DocumentChunker-BICIjSuG.js';
4
4
  export { a as ChatOptions, b as Chunk, c as ChunkOptions, E as EmbedOptions, I as ILLMProvider } from './DocumentChunker-BICIjSuG.js';
5
- import { V as VectorMatch, U as UIConfig } from './RagConfig-D3Inaf9N.js';
6
- export { C as ChatResponse, E as EmbeddingConfig, I as IngestDocument, L as LLMConfig, R as RAGConfig, a as RagConfig, b as UpsertDocument, c as VectorDBConfig } from './RagConfig-D3Inaf9N.js';
5
+ import { V as VectorMatch, U as UIConfig } from './RagConfig-Bpp39-um.js';
6
+ export { C as ChatResponse, E as EmbeddingConfig, I as IngestDocument, L as LLMConfig, R as RAGConfig, a as RagConfig, b as UpsertDocument, c as VectorDBConfig } from './RagConfig-Bpp39-um.js';
7
7
 
8
8
  interface ChatWidgetProps {
9
9
  /** Position of the floating button. Defaults to bottom-right. */
package/dist/server.d.mts CHANGED
@@ -1,9 +1,9 @@
1
- import { a as RagConfig, C as ChatResponse, I as IngestDocument, c as VectorDBConfig, b as UpsertDocument, V as VectorMatch, L as LLMConfig, E as EmbeddingConfig, d as VectorDBProvider, e as LLMProvider, f as EmbeddingProvider } from './RagConfig-D3Inaf9N.mjs';
2
- export { R as RAGConfig, U as UIConfig } from './RagConfig-D3Inaf9N.mjs';
1
+ import { a as RagConfig, C as ChatResponse, I as IngestDocument, c as VectorDBConfig, b as UpsertDocument, V as VectorMatch, L as LLMConfig, E as EmbeddingConfig, d as VectorDBProvider, e as LLMProvider, f as EmbeddingProvider } from './RagConfig-Bpp39-um.mjs';
2
+ export { R as RAGConfig, U as UIConfig } from './RagConfig-Bpp39-um.mjs';
3
3
  import { C as ChatMessage, I as ILLMProvider, a as ChatOptions, E as EmbedOptions } from './DocumentChunker-BICIjSuG.mjs';
4
4
  export { b as Chunk, c as ChunkOptions, D as DocumentChunker } from './DocumentChunker-BICIjSuG.mjs';
5
- import { H as HealthCheckResult } from './index-Ymwm-_OR.mjs';
6
- export { P as ProviderHealthCheck, c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from './index-Ymwm-_OR.mjs';
5
+ import { H as HealthCheckResult } from './index-CZE72wnV.mjs';
6
+ export { P as ProviderHealthCheck, c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from './index-CZE72wnV.mjs';
7
7
  import 'next/server';
8
8
 
9
9
  /**