@retrivora-ai/rag-engine 0.3.2 → 0.3.4

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.
@@ -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' | 'gemini' | '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' | 'gemini' | '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' | 'gemini' | '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' | 'gemini' | '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")
@@ -629,21 +657,19 @@ var ConfigValidator = class {
629
657
  }
630
658
  }
631
659
  if (config.borderRadius) {
632
- const validValues = ["none", "sm", "md", "lg", "xl", "full"];
633
- if (!validValues.includes(config.borderRadius)) {
660
+ if (!UI_BORDER_RADIUS_OPTIONS.includes(config.borderRadius)) {
634
661
  errors.push({
635
662
  field: "ui.borderRadius",
636
- message: `borderRadius must be one of: ${validValues.join(", ")}`,
663
+ message: `borderRadius must be one of: ${UI_BORDER_RADIUS_OPTIONS.join(", ")}`,
637
664
  severity: "warning"
638
665
  });
639
666
  }
640
667
  }
641
668
  if (config.visualStyle) {
642
- const validValues = ["glass", "solid"];
643
- if (!validValues.includes(config.visualStyle)) {
669
+ if (!UI_VISUAL_STYLES.includes(config.visualStyle)) {
644
670
  errors.push({
645
671
  field: "ui.visualStyle",
646
- message: `visualStyle must be one of: ${validValues.join(", ")}`,
672
+ message: `visualStyle must be one of: ${UI_VISUAL_STYLES.join(", ")}`,
647
673
  severity: "warning"
648
674
  });
649
675
  }
@@ -983,8 +1009,18 @@ var GeminiProvider = class {
983
1009
  constructor(llmConfig, embeddingConfig) {
984
1010
  if (!llmConfig.apiKey) throw new Error("[GeminiProvider] llmConfig.apiKey is required");
985
1011
  this.client = new GoogleGenAI({ apiKey: llmConfig.apiKey });
986
- this.llmConfig = llmConfig;
987
- this.embeddingConfig = embeddingConfig;
1012
+ this.llmConfig = __spreadProps(__spreadValues({}, llmConfig), {
1013
+ model: this.sanitizeModel(llmConfig.model)
1014
+ });
1015
+ if (embeddingConfig) {
1016
+ this.embeddingConfig = __spreadProps(__spreadValues({}, embeddingConfig), {
1017
+ model: this.sanitizeModel(embeddingConfig.model)
1018
+ });
1019
+ }
1020
+ }
1021
+ sanitizeModel(model) {
1022
+ if (!model) return model;
1023
+ return model.split(":")[0];
988
1024
  }
989
1025
  async chat(messages, context, options) {
990
1026
  var _a, _b, _c, _d, _e, _f;
@@ -1013,8 +1049,10 @@ ${context}`;
1013
1049
  return (_f = response.text) != null ? _f : "";
1014
1050
  }
1015
1051
  async embed(text, options) {
1016
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1017
- 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";
1052
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1053
+ const model = this.sanitizeModel(
1054
+ (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-004"
1055
+ );
1018
1056
  const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
1019
1057
  const client = apiKey !== this.llmConfig.apiKey ? new GoogleGenAI({ apiKey }) : this.client;
1020
1058
  let content = text;
@@ -1031,14 +1069,20 @@ ${context}`;
1031
1069
  }
1032
1070
  const response = await client.models.embedContent({
1033
1071
  model,
1034
- contents: content
1072
+ contents: content,
1073
+ config: ((_h = this.embeddingConfig) == null ? void 0 : _h.dimensions) ? { outputDimensionality: this.embeddingConfig.dimensions } : void 0
1074
+ }).catch((err) => {
1075
+ console.error(`[GeminiProvider] Embedding failed for model "${model}":`, err.message);
1076
+ throw err;
1035
1077
  });
1036
- return (_j = (_i = (_h = response.embeddings) == null ? void 0 : _h[0]) == null ? void 0 : _i.values) != null ? _j : [];
1078
+ return (_k = (_j = (_i = response.embeddings) == null ? void 0 : _i[0]) == null ? void 0 : _j.values) != null ? _k : [];
1037
1079
  }
1038
1080
  async batchEmbed(texts, options) {
1039
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1081
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1040
1082
  const vectors = [];
1041
- 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";
1083
+ const model = this.sanitizeModel(
1084
+ (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-004"
1085
+ );
1042
1086
  const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
1043
1087
  const client = apiKey !== this.llmConfig.apiKey ? new GoogleGenAI({ apiKey }) : this.client;
1044
1088
  let contents = texts;
@@ -1051,12 +1095,16 @@ ${context}`;
1051
1095
  }
1052
1096
  const response = await client.models.embedContent({
1053
1097
  model,
1054
- contents
1098
+ contents,
1099
+ config: ((_h = this.embeddingConfig) == null ? void 0 : _h.dimensions) ? { outputDimensionality: this.embeddingConfig.dimensions } : void 0
1100
+ }).catch((err) => {
1101
+ console.error(`[GeminiProvider] Batch embedding failed for model "${model}":`, err.message);
1102
+ throw err;
1055
1103
  });
1056
- return (_i = (_h = response.embeddings) == null ? void 0 : _h.map((e) => {
1104
+ return (_j = (_i = response.embeddings) == null ? void 0 : _i.map((e) => {
1057
1105
  var _a2;
1058
1106
  return (_a2 = e.values) != null ? _a2 : [];
1059
- })) != null ? _i : [];
1107
+ })) != null ? _j : [];
1060
1108
  }
1061
1109
  async ping() {
1062
1110
  try {
@@ -1661,8 +1709,7 @@ var EmbeddingStrategyResolver = class {
1661
1709
  * Check if an LLM provider natively supports embeddings
1662
1710
  */
1663
1711
  static supportsEmbedding(provider) {
1664
- const providersWithEmbedding = ["openai", "ollama", "gemini", "rest", "universal_rest"];
1665
- return providersWithEmbedding.includes(provider);
1712
+ return PROVIDERS_WITH_EMBEDDINGS.includes(provider);
1666
1713
  }
1667
1714
  /**
1668
1715
  * Get a human-readable description of the strategy
@@ -1,3 +1,3 @@
1
- import '../RagConfig-Crz-l02S.mjs';
2
- export { c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from '../index-Cd4CdmEi.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-Crz-l02S.js';
2
- export { c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from '../index-DQ1pXmlK.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")
@@ -1797,21 +1825,19 @@ var ConfigValidator = class {
1797
1825
  }
1798
1826
  }
1799
1827
  if (config.borderRadius) {
1800
- const validValues = ["none", "sm", "md", "lg", "xl", "full"];
1801
- if (!validValues.includes(config.borderRadius)) {
1828
+ if (!UI_BORDER_RADIUS_OPTIONS.includes(config.borderRadius)) {
1802
1829
  errors.push({
1803
1830
  field: "ui.borderRadius",
1804
- message: `borderRadius must be one of: ${validValues.join(", ")}`,
1831
+ message: `borderRadius must be one of: ${UI_BORDER_RADIUS_OPTIONS.join(", ")}`,
1805
1832
  severity: "warning"
1806
1833
  });
1807
1834
  }
1808
1835
  }
1809
1836
  if (config.visualStyle) {
1810
- const validValues = ["glass", "solid"];
1811
- if (!validValues.includes(config.visualStyle)) {
1837
+ if (!UI_VISUAL_STYLES.includes(config.visualStyle)) {
1812
1838
  errors.push({
1813
1839
  field: "ui.visualStyle",
1814
- message: `visualStyle must be one of: ${validValues.join(", ")}`,
1840
+ message: `visualStyle must be one of: ${UI_VISUAL_STYLES.join(", ")}`,
1815
1841
  severity: "warning"
1816
1842
  });
1817
1843
  }
@@ -2151,8 +2177,18 @@ var GeminiProvider = class {
2151
2177
  constructor(llmConfig, embeddingConfig) {
2152
2178
  if (!llmConfig.apiKey) throw new Error("[GeminiProvider] llmConfig.apiKey is required");
2153
2179
  this.client = new import_genai.GoogleGenAI({ apiKey: llmConfig.apiKey });
2154
- this.llmConfig = llmConfig;
2155
- this.embeddingConfig = embeddingConfig;
2180
+ this.llmConfig = __spreadProps(__spreadValues({}, llmConfig), {
2181
+ model: this.sanitizeModel(llmConfig.model)
2182
+ });
2183
+ if (embeddingConfig) {
2184
+ this.embeddingConfig = __spreadProps(__spreadValues({}, embeddingConfig), {
2185
+ model: this.sanitizeModel(embeddingConfig.model)
2186
+ });
2187
+ }
2188
+ }
2189
+ sanitizeModel(model) {
2190
+ if (!model) return model;
2191
+ return model.split(":")[0];
2156
2192
  }
2157
2193
  async chat(messages, context, options) {
2158
2194
  var _a, _b, _c, _d, _e, _f;
@@ -2181,8 +2217,10 @@ ${context}`;
2181
2217
  return (_f = response.text) != null ? _f : "";
2182
2218
  }
2183
2219
  async embed(text, options) {
2184
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2185
- 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";
2220
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2221
+ const model = this.sanitizeModel(
2222
+ (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-004"
2223
+ );
2186
2224
  const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
2187
2225
  const client = apiKey !== this.llmConfig.apiKey ? new import_genai.GoogleGenAI({ apiKey }) : this.client;
2188
2226
  let content = text;
@@ -2199,14 +2237,20 @@ ${context}`;
2199
2237
  }
2200
2238
  const response = await client.models.embedContent({
2201
2239
  model,
2202
- contents: content
2240
+ contents: content,
2241
+ config: ((_h = this.embeddingConfig) == null ? void 0 : _h.dimensions) ? { outputDimensionality: this.embeddingConfig.dimensions } : void 0
2242
+ }).catch((err) => {
2243
+ console.error(`[GeminiProvider] Embedding failed for model "${model}":`, err.message);
2244
+ throw err;
2203
2245
  });
2204
- return (_j = (_i = (_h = response.embeddings) == null ? void 0 : _h[0]) == null ? void 0 : _i.values) != null ? _j : [];
2246
+ return (_k = (_j = (_i = response.embeddings) == null ? void 0 : _i[0]) == null ? void 0 : _j.values) != null ? _k : [];
2205
2247
  }
2206
2248
  async batchEmbed(texts, options) {
2207
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2249
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2208
2250
  const vectors = [];
2209
- 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";
2251
+ const model = this.sanitizeModel(
2252
+ (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-004"
2253
+ );
2210
2254
  const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
2211
2255
  const client = apiKey !== this.llmConfig.apiKey ? new import_genai.GoogleGenAI({ apiKey }) : this.client;
2212
2256
  let contents = texts;
@@ -2219,12 +2263,16 @@ ${context}`;
2219
2263
  }
2220
2264
  const response = await client.models.embedContent({
2221
2265
  model,
2222
- contents
2266
+ contents,
2267
+ config: ((_h = this.embeddingConfig) == null ? void 0 : _h.dimensions) ? { outputDimensionality: this.embeddingConfig.dimensions } : void 0
2268
+ }).catch((err) => {
2269
+ console.error(`[GeminiProvider] Batch embedding failed for model "${model}":`, err.message);
2270
+ throw err;
2223
2271
  });
2224
- return (_i = (_h = response.embeddings) == null ? void 0 : _h.map((e) => {
2272
+ return (_j = (_i = response.embeddings) == null ? void 0 : _i.map((e) => {
2225
2273
  var _a2;
2226
2274
  return (_a2 = e.values) != null ? _a2 : [];
2227
- })) != null ? _i : [];
2275
+ })) != null ? _j : [];
2228
2276
  }
2229
2277
  async ping() {
2230
2278
  try {
@@ -2785,8 +2833,7 @@ var EmbeddingStrategyResolver = class {
2785
2833
  * Check if an LLM provider natively supports embeddings
2786
2834
  */
2787
2835
  static supportsEmbedding(provider) {
2788
- const providersWithEmbedding = ["openai", "ollama", "gemini", "rest", "universal_rest"];
2789
- return providersWithEmbedding.includes(provider);
2836
+ return PROVIDERS_WITH_EMBEDDINGS.includes(provider);
2790
2837
  }
2791
2838
  /**
2792
2839
  * 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-7BPQDPOC.mjs";
6
+ } from "../chunk-GE4AVGA5.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-Crz-l02S.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-Crz-l02S.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-Crz-l02S.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-Crz-l02S.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-Crz-l02S.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-Crz-l02S.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-Crz-l02S.mjs';
2
- export { R as RAGConfig, U as UIConfig } from './RagConfig-Crz-l02S.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-Cd4CdmEi.mjs';
6
- export { P as ProviderHealthCheck, c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from './index-Cd4CdmEi.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
  /**
package/dist/server.d.ts 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-Crz-l02S.js';
2
- export { R as RAGConfig, U as UIConfig } from './RagConfig-Crz-l02S.js';
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.js';
2
+ export { R as RAGConfig, U as UIConfig } from './RagConfig-Bpp39-um.js';
3
3
  import { C as ChatMessage, I as ILLMProvider, a as ChatOptions, E as EmbedOptions } from './DocumentChunker-BICIjSuG.js';
4
4
  export { b as Chunk, c as ChunkOptions, D as DocumentChunker } from './DocumentChunker-BICIjSuG.js';
5
- import { H as HealthCheckResult } from './index-DQ1pXmlK.js';
6
- export { P as ProviderHealthCheck, c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from './index-DQ1pXmlK.js';
5
+ import { H as HealthCheckResult } from './index-DSaQwkKA.js';
6
+ export { P as ProviderHealthCheck, c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from './index-DSaQwkKA.js';
7
7
  import 'next/server';
8
8
 
9
9
  /**
package/dist/server.js CHANGED
@@ -1223,7 +1223,7 @@ module.exports = __toCommonJS(server_exports);
1223
1223
  // src/core/ConfigResolver.ts
1224
1224
  init_templateUtils();
1225
1225
 
1226
- // src/config/serverConfig.ts
1226
+ // src/config/constants.ts
1227
1227
  var VECTOR_DB_PROVIDERS = [
1228
1228
  "pinecone",
1229
1229
  "pgvector",
@@ -1238,8 +1238,34 @@ var VECTOR_DB_PROVIDERS = [
1238
1238
  "universal_rest",
1239
1239
  "custom"
1240
1240
  ];
1241
- var LLM_PROVIDERS = ["openai", "anthropic", "ollama", "rest", "universal_rest", "custom"];
1242
- var EMBEDDING_PROVIDERS = ["openai", "ollama", "rest", "universal_rest", "custom"];
1241
+ var LLM_PROVIDERS = [
1242
+ "openai",
1243
+ "anthropic",
1244
+ "ollama",
1245
+ "gemini",
1246
+ "rest",
1247
+ "universal_rest",
1248
+ "custom"
1249
+ ];
1250
+ var EMBEDDING_PROVIDERS = [
1251
+ "openai",
1252
+ "ollama",
1253
+ "gemini",
1254
+ "rest",
1255
+ "universal_rest",
1256
+ "custom"
1257
+ ];
1258
+ var PROVIDERS_WITH_EMBEDDINGS = [
1259
+ "openai",
1260
+ "ollama",
1261
+ "gemini",
1262
+ "rest",
1263
+ "universal_rest"
1264
+ ];
1265
+ var UI_VISUAL_STYLES = ["glass", "solid"];
1266
+ var UI_BORDER_RADIUS_OPTIONS = ["none", "sm", "md", "lg", "xl", "full"];
1267
+
1268
+ // src/config/serverConfig.ts
1243
1269
  function readString(env, name) {
1244
1270
  var _a;
1245
1271
  const value = (_a = env[name]) == null ? void 0 : _a.trim();
@@ -1306,6 +1332,7 @@ function getRagConfig(env = process.env) {
1306
1332
  const llmApiKeyByProvider = {
1307
1333
  openai: readString(env, "OPENAI_API_KEY"),
1308
1334
  anthropic: readString(env, "ANTHROPIC_API_KEY"),
1335
+ gemini: readString(env, "GEMINI_API_KEY"),
1309
1336
  ollama: void 0,
1310
1337
  universal_rest: readString(env, "LLM_API_KEY"),
1311
1338
  rest: readString(env, "LLM_API_KEY"),
@@ -1313,6 +1340,7 @@ function getRagConfig(env = process.env) {
1313
1340
  };
1314
1341
  const embeddingApiKeyByProvider = {
1315
1342
  openai: readString(env, "OPENAI_API_KEY"),
1343
+ gemini: readString(env, "GEMINI_API_KEY"),
1316
1344
  ollama: void 0,
1317
1345
  universal_rest: (_q = readString(env, "EMBEDDING_API_KEY")) != null ? _q : readString(env, "OPENAI_API_KEY"),
1318
1346
  custom: (_r = readString(env, "EMBEDDING_API_KEY")) != null ? _r : readString(env, "OPENAI_API_KEY")
@@ -1841,21 +1869,19 @@ var ConfigValidator = class {
1841
1869
  }
1842
1870
  }
1843
1871
  if (config.borderRadius) {
1844
- const validValues = ["none", "sm", "md", "lg", "xl", "full"];
1845
- if (!validValues.includes(config.borderRadius)) {
1872
+ if (!UI_BORDER_RADIUS_OPTIONS.includes(config.borderRadius)) {
1846
1873
  errors.push({
1847
1874
  field: "ui.borderRadius",
1848
- message: `borderRadius must be one of: ${validValues.join(", ")}`,
1875
+ message: `borderRadius must be one of: ${UI_BORDER_RADIUS_OPTIONS.join(", ")}`,
1849
1876
  severity: "warning"
1850
1877
  });
1851
1878
  }
1852
1879
  }
1853
1880
  if (config.visualStyle) {
1854
- const validValues = ["glass", "solid"];
1855
- if (!validValues.includes(config.visualStyle)) {
1881
+ if (!UI_VISUAL_STYLES.includes(config.visualStyle)) {
1856
1882
  errors.push({
1857
1883
  field: "ui.visualStyle",
1858
- message: `visualStyle must be one of: ${validValues.join(", ")}`,
1884
+ message: `visualStyle must be one of: ${UI_VISUAL_STYLES.join(", ")}`,
1859
1885
  severity: "warning"
1860
1886
  });
1861
1887
  }
@@ -2195,8 +2221,18 @@ var GeminiProvider = class {
2195
2221
  constructor(llmConfig, embeddingConfig) {
2196
2222
  if (!llmConfig.apiKey) throw new Error("[GeminiProvider] llmConfig.apiKey is required");
2197
2223
  this.client = new import_genai.GoogleGenAI({ apiKey: llmConfig.apiKey });
2198
- this.llmConfig = llmConfig;
2199
- this.embeddingConfig = embeddingConfig;
2224
+ this.llmConfig = __spreadProps(__spreadValues({}, llmConfig), {
2225
+ model: this.sanitizeModel(llmConfig.model)
2226
+ });
2227
+ if (embeddingConfig) {
2228
+ this.embeddingConfig = __spreadProps(__spreadValues({}, embeddingConfig), {
2229
+ model: this.sanitizeModel(embeddingConfig.model)
2230
+ });
2231
+ }
2232
+ }
2233
+ sanitizeModel(model) {
2234
+ if (!model) return model;
2235
+ return model.split(":")[0];
2200
2236
  }
2201
2237
  async chat(messages, context, options) {
2202
2238
  var _a, _b, _c, _d, _e, _f;
@@ -2225,8 +2261,10 @@ ${context}`;
2225
2261
  return (_f = response.text) != null ? _f : "";
2226
2262
  }
2227
2263
  async embed(text, options) {
2228
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2229
- 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";
2264
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2265
+ const model = this.sanitizeModel(
2266
+ (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-004"
2267
+ );
2230
2268
  const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
2231
2269
  const client = apiKey !== this.llmConfig.apiKey ? new import_genai.GoogleGenAI({ apiKey }) : this.client;
2232
2270
  let content = text;
@@ -2243,14 +2281,20 @@ ${context}`;
2243
2281
  }
2244
2282
  const response = await client.models.embedContent({
2245
2283
  model,
2246
- contents: content
2284
+ contents: content,
2285
+ config: ((_h = this.embeddingConfig) == null ? void 0 : _h.dimensions) ? { outputDimensionality: this.embeddingConfig.dimensions } : void 0
2286
+ }).catch((err) => {
2287
+ console.error(`[GeminiProvider] Embedding failed for model "${model}":`, err.message);
2288
+ throw err;
2247
2289
  });
2248
- return (_j = (_i = (_h = response.embeddings) == null ? void 0 : _h[0]) == null ? void 0 : _i.values) != null ? _j : [];
2290
+ return (_k = (_j = (_i = response.embeddings) == null ? void 0 : _i[0]) == null ? void 0 : _j.values) != null ? _k : [];
2249
2291
  }
2250
2292
  async batchEmbed(texts, options) {
2251
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2293
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2252
2294
  const vectors = [];
2253
- 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";
2295
+ const model = this.sanitizeModel(
2296
+ (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-004"
2297
+ );
2254
2298
  const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
2255
2299
  const client = apiKey !== this.llmConfig.apiKey ? new import_genai.GoogleGenAI({ apiKey }) : this.client;
2256
2300
  let contents = texts;
@@ -2263,12 +2307,16 @@ ${context}`;
2263
2307
  }
2264
2308
  const response = await client.models.embedContent({
2265
2309
  model,
2266
- contents
2310
+ contents,
2311
+ config: ((_h = this.embeddingConfig) == null ? void 0 : _h.dimensions) ? { outputDimensionality: this.embeddingConfig.dimensions } : void 0
2312
+ }).catch((err) => {
2313
+ console.error(`[GeminiProvider] Batch embedding failed for model "${model}":`, err.message);
2314
+ throw err;
2267
2315
  });
2268
- return (_i = (_h = response.embeddings) == null ? void 0 : _h.map((e) => {
2316
+ return (_j = (_i = response.embeddings) == null ? void 0 : _i.map((e) => {
2269
2317
  var _a2;
2270
2318
  return (_a2 = e.values) != null ? _a2 : [];
2271
- })) != null ? _i : [];
2319
+ })) != null ? _j : [];
2272
2320
  }
2273
2321
  async ping() {
2274
2322
  try {
@@ -2874,8 +2922,7 @@ var EmbeddingStrategyResolver = class {
2874
2922
  * Check if an LLM provider natively supports embeddings
2875
2923
  */
2876
2924
  static supportsEmbedding(provider) {
2877
- const providersWithEmbedding = ["openai", "ollama", "gemini", "rest", "universal_rest"];
2878
- return providersWithEmbedding.includes(provider);
2925
+ return PROVIDERS_WITH_EMBEDDINGS.includes(provider);
2879
2926
  }
2880
2927
  /**
2881
2928
  * Get a human-readable description of the strategy
package/dist/server.mjs CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  createIngestHandler,
35
35
  createUploadHandler,
36
36
  getRagConfig
37
- } from "./chunk-7BPQDPOC.mjs";
37
+ } from "./chunk-GE4AVGA5.mjs";
38
38
  import "./chunk-EDLTMSNY.mjs";
39
39
  import {
40
40
  PineconeProvider
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
5
5
  "author": "Abhinav Alkuchi",
6
6
  "license": "MIT",
@@ -12,6 +12,7 @@
12
12
  import { ILLMProvider } from '../llm/ILLMProvider';
13
13
  import { LLMFactory } from '../llm/LLMFactory';
14
14
  import { LLMConfig, EmbeddingConfig, LLMProvider, EmbeddingProvider } from './RagConfig';
15
+ import { PROVIDERS_WITH_EMBEDDINGS } from './constants';
15
16
 
16
17
  export enum EmbeddingStrategy {
17
18
  /**
@@ -125,8 +126,7 @@ export class EmbeddingStrategyResolver {
125
126
  * Check if an LLM provider natively supports embeddings
126
127
  */
127
128
  private static supportsEmbedding(provider: LLMProvider | string): boolean {
128
- const providersWithEmbedding = ['openai', 'ollama', 'gemini', 'rest', 'universal_rest'];
129
- return providersWithEmbedding.includes(provider);
129
+ return (PROVIDERS_WITH_EMBEDDINGS as readonly string[]).includes(provider);
130
130
  }
131
131
 
132
132
  /**
@@ -8,7 +8,13 @@
8
8
  // Vector DB
9
9
  // ---------------------------------------------------------------------------
10
10
 
11
- export type VectorDBProvider = 'pinecone' | 'pgvector' | 'postgresql' | 'mongodb' | 'milvus' | 'qdrant' | 'chromadb' | 'redis' | 'weaviate' | 'rest' | 'universal_rest' | 'custom';
11
+ import {
12
+ VECTOR_DB_PROVIDERS,
13
+ LLM_PROVIDERS,
14
+ EMBEDDING_PROVIDERS,
15
+ } from './constants';
16
+
17
+ export type VectorDBProvider = typeof VECTOR_DB_PROVIDERS[number];
12
18
 
13
19
  export interface VectorDBConfig {
14
20
  /** Which vector database to use */
@@ -40,7 +46,7 @@ export interface VectorDBConfig {
40
46
  // LLM Provider
41
47
  // ---------------------------------------------------------------------------
42
48
 
43
- export type LLMProvider = 'openai' | 'anthropic' | 'ollama' | 'gemini' | 'rest' | 'universal_rest' | 'custom';
49
+ export type LLMProvider = typeof LLM_PROVIDERS[number];
44
50
 
45
51
  export interface LLMConfig {
46
52
  /** Which LLM provider to use */
@@ -72,7 +78,7 @@ export interface LLMConfig {
72
78
  // Embedding
73
79
  // ---------------------------------------------------------------------------
74
80
 
75
- export type EmbeddingProvider = 'openai' | 'ollama' | 'gemini' | 'rest' | 'universal_rest' | 'custom';
81
+ export type EmbeddingProvider = typeof EMBEDDING_PROVIDERS[number];
76
82
 
77
83
  export interface EmbeddingConfig {
78
84
  /** Which embedding provider to use */
@@ -0,0 +1,52 @@
1
+ /**
2
+ * constants.ts — Centralized definitions of acceptable configuration values.
3
+ *
4
+ * This file serves as the single source of truth for all statically supported
5
+ * providers and stylistic options in the Retrivora AI RAG Engine.
6
+ */
7
+
8
+ export const VECTOR_DB_PROVIDERS = [
9
+ 'pinecone',
10
+ 'pgvector',
11
+ 'postgresql',
12
+ 'mongodb',
13
+ 'milvus',
14
+ 'qdrant',
15
+ 'chromadb',
16
+ 'redis',
17
+ 'weaviate',
18
+ 'rest',
19
+ 'universal_rest',
20
+ 'custom',
21
+ ] as const;
22
+
23
+ export const LLM_PROVIDERS = [
24
+ 'openai',
25
+ 'anthropic',
26
+ 'ollama',
27
+ 'gemini',
28
+ 'rest',
29
+ 'universal_rest',
30
+ 'custom',
31
+ ] as const;
32
+
33
+ export const EMBEDDING_PROVIDERS = [
34
+ 'openai',
35
+ 'ollama',
36
+ 'gemini',
37
+ 'rest',
38
+ 'universal_rest',
39
+ 'custom',
40
+ ] as const;
41
+
42
+ export const PROVIDERS_WITH_EMBEDDINGS = [
43
+ 'openai',
44
+ 'ollama',
45
+ 'gemini',
46
+ 'rest',
47
+ 'universal_rest',
48
+ ] as const;
49
+
50
+ export const UI_VISUAL_STYLES = ['glass', 'solid'] as const;
51
+
52
+ export const UI_BORDER_RADIUS_OPTIONS = ['none', 'sm', 'md', 'lg', 'xl', 'full'] as const;
@@ -19,14 +19,11 @@
19
19
  */
20
20
 
21
21
  import { RagConfig } from './RagConfig';
22
-
23
- const VECTOR_DB_PROVIDERS = [
24
- 'pinecone', 'pgvector', 'postgresql', 'mongodb', 'milvus',
25
- 'qdrant', 'chromadb', 'redis', 'weaviate', 'rest', 'universal_rest', 'custom',
26
- ] as const;
27
-
28
- const LLM_PROVIDERS = ['openai', 'anthropic', 'ollama', 'rest', 'universal_rest', 'custom'] as const;
29
- const EMBEDDING_PROVIDERS = ['openai', 'ollama', 'rest', 'universal_rest', 'custom'] as const;
22
+ import {
23
+ VECTOR_DB_PROVIDERS,
24
+ LLM_PROVIDERS,
25
+ EMBEDDING_PROVIDERS,
26
+ } from './constants';
30
27
 
31
28
  function readString(env: Record<string, string | undefined>, name: string): string | undefined {
32
29
  const value = env[name]?.trim();
@@ -112,6 +109,7 @@ export function getRagConfig(env: Record<string, string | undefined> = process.e
112
109
  const llmApiKeyByProvider: Record<string, string | undefined> = {
113
110
  openai: readString(env, 'OPENAI_API_KEY'),
114
111
  anthropic: readString(env, 'ANTHROPIC_API_KEY'),
112
+ gemini: readString(env, 'GEMINI_API_KEY'),
115
113
  ollama: undefined,
116
114
  universal_rest: readString(env, 'LLM_API_KEY'),
117
115
  rest: readString(env, 'LLM_API_KEY'),
@@ -120,6 +118,7 @@ export function getRagConfig(env: Record<string, string | undefined> = process.e
120
118
 
121
119
  const embeddingApiKeyByProvider: Record<string, string | undefined> = {
122
120
  openai: readString(env, 'OPENAI_API_KEY'),
121
+ gemini: readString(env, 'GEMINI_API_KEY'),
123
122
  ollama: undefined,
124
123
  universal_rest: readString(env, 'EMBEDDING_API_KEY') ?? readString(env, 'OPENAI_API_KEY'),
125
124
  custom: readString(env, 'EMBEDDING_API_KEY') ?? readString(env, 'OPENAI_API_KEY'),
@@ -10,6 +10,10 @@
10
10
  */
11
11
 
12
12
  import { RagConfig, VectorDBConfig, LLMConfig, EmbeddingConfig } from '../config/RagConfig';
13
+ import {
14
+ UI_VISUAL_STYLES,
15
+ UI_BORDER_RADIUS_OPTIONS,
16
+ } from '../config/constants';
13
17
 
14
18
  export interface ValidationError {
15
19
  field: string;
@@ -508,22 +512,20 @@ export class ConfigValidator {
508
512
  }
509
513
 
510
514
  if (config.borderRadius) {
511
- const validValues = ['none', 'sm', 'md', 'lg', 'xl', 'full'];
512
- if (!validValues.includes(config.borderRadius as string)) {
515
+ if (!UI_BORDER_RADIUS_OPTIONS.includes(config.borderRadius as any)) {
513
516
  errors.push({
514
517
  field: 'ui.borderRadius',
515
- message: `borderRadius must be one of: ${validValues.join(', ')}`,
518
+ message: `borderRadius must be one of: ${UI_BORDER_RADIUS_OPTIONS.join(', ')}`,
516
519
  severity: 'warning',
517
520
  });
518
521
  }
519
522
  }
520
523
 
521
524
  if (config.visualStyle) {
522
- const validValues = ['glass', 'solid'];
523
- if (!validValues.includes(config.visualStyle as string)) {
525
+ if (!UI_VISUAL_STYLES.includes(config.visualStyle as any)) {
524
526
  errors.push({
525
527
  field: 'ui.visualStyle',
526
- message: `visualStyle must be one of: ${validValues.join(', ')}`,
528
+ message: `visualStyle must be one of: ${UI_VISUAL_STYLES.join(', ')}`,
527
529
  severity: 'warning',
528
530
  });
529
531
  }
@@ -26,10 +26,28 @@ export class GeminiProvider implements ILLMProvider {
26
26
  constructor(llmConfig: LLMConfig, embeddingConfig?: EmbeddingConfig) {
27
27
  if (!llmConfig.apiKey) throw new Error('[GeminiProvider] llmConfig.apiKey is required');
28
28
  this.client = new GoogleGenAI({ apiKey: llmConfig.apiKey });
29
- this.llmConfig = llmConfig;
30
- this.embeddingConfig = embeddingConfig;
29
+
30
+ // Sanitize model names (e.g. remove ':latest' suffix used by Ollama)
31
+ this.llmConfig = {
32
+ ...llmConfig,
33
+ model: this.sanitizeModel(llmConfig.model)
34
+ };
35
+
36
+ if (embeddingConfig) {
37
+ this.embeddingConfig = {
38
+ ...embeddingConfig,
39
+ model: this.sanitizeModel(embeddingConfig.model)
40
+ };
41
+ }
31
42
  }
32
43
 
44
+ private sanitizeModel(model: string): string {
45
+ if (!model) return model;
46
+ // Strip :latest suffix common in Ollama but invalid in Google SDK
47
+ return model.split(':')[0];
48
+ }
49
+
50
+
33
51
  async chat(messages: ChatMessage[], context: string, options?: ChatOptions): Promise<string> {
34
52
  const systemPrompt =
35
53
  this.llmConfig.systemPrompt ??
@@ -62,10 +80,11 @@ export class GeminiProvider implements ILLMProvider {
62
80
  }
63
81
 
64
82
  async embed(text: string, options?: EmbedOptions): Promise<number[]> {
65
- const model =
83
+ const model = this.sanitizeModel(
66
84
  options?.model ??
67
85
  this.embeddingConfig?.model ??
68
- 'text-embedding-004';
86
+ 'text-embedding-004'
87
+ );
69
88
 
70
89
  const apiKey = this.embeddingConfig?.apiKey ?? this.llmConfig.apiKey;
71
90
  const client = apiKey !== this.llmConfig.apiKey
@@ -91,6 +110,10 @@ export class GeminiProvider implements ILLMProvider {
91
110
  const response = await client.models.embedContent({
92
111
  model,
93
112
  contents: content,
113
+ config: this.embeddingConfig?.dimensions ? { outputDimensionality: this.embeddingConfig.dimensions } : undefined
114
+ }).catch(err => {
115
+ console.error(`[GeminiProvider] Embedding failed for model "${model}":`, err.message);
116
+ throw err;
94
117
  });
95
118
 
96
119
  return response.embeddings?.[0]?.values ?? [];
@@ -101,10 +124,11 @@ export class GeminiProvider implements ILLMProvider {
101
124
  // Sequential fallback for Gemini (API doesn't have a direct batch endpoint in the same way, though you can pass multiple contents.
102
125
  // For simplicity and to match the other providers' structure, we'll iterate or pass array.
103
126
  // The new SDK supports an array of contents.
104
- const model =
127
+ const model = this.sanitizeModel(
105
128
  options?.model ??
106
129
  this.embeddingConfig?.model ??
107
- 'text-embedding-004';
130
+ 'text-embedding-004'
131
+ );
108
132
 
109
133
  const apiKey = this.embeddingConfig?.apiKey ?? this.llmConfig.apiKey;
110
134
  const client = apiKey !== this.llmConfig.apiKey
@@ -126,6 +150,10 @@ export class GeminiProvider implements ILLMProvider {
126
150
  const response = await client.models.embedContent({
127
151
  model,
128
152
  contents,
153
+ config: this.embeddingConfig?.dimensions ? { outputDimensionality: this.embeddingConfig.dimensions } : undefined
154
+ }).catch(err => {
155
+ console.error(`[GeminiProvider] Batch embedding failed for model "${model}":`, err.message);
156
+ throw err;
129
157
  });
130
158
 
131
159
  return response.embeddings?.map(e => e.values ?? []) ?? [];