@retrivora-ai/rag-engine 1.8.0 → 1.8.1

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 (46) hide show
  1. package/dist/DocumentChunker-Dh9TvmGG.d.mts +45 -0
  2. package/dist/DocumentChunker-Dh9TvmGG.d.ts +45 -0
  3. package/dist/{index-DPsQodME.d.mts → ILLMProvider-BfRgI1Xh.d.mts} +58 -1
  4. package/dist/{index-DPsQodME.d.ts → ILLMProvider-BfRgI1Xh.d.ts} +58 -1
  5. package/dist/MultiTablePostgresProvider-YY7LPNJK.mjs +8 -0
  6. package/dist/{chunk-PV3MFHWU.mjs → chunk-BFYLQYQU.mjs} +808 -439
  7. package/dist/chunk-R3RGUMHE.mjs +218 -0
  8. package/dist/handlers/index.d.mts +2 -2
  9. package/dist/handlers/index.d.ts +2 -2
  10. package/dist/handlers/index.js +995 -603
  11. package/dist/handlers/index.mjs +1 -1
  12. package/dist/{index-Bb2yEopi.d.mts → index-1Z4GuYBi.d.ts} +7 -1
  13. package/dist/{index-CkbTzj9J.d.ts → index-BV0z5mb6.d.mts} +7 -1
  14. package/dist/index.d.mts +3 -3
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.js +491 -316
  17. package/dist/index.mjs +411 -217
  18. package/dist/server.d.mts +35 -5
  19. package/dist/server.d.ts +35 -5
  20. package/dist/server.js +1146 -777
  21. package/dist/server.mjs +163 -176
  22. package/package.json +4 -2
  23. package/src/app/page.tsx +1 -2
  24. package/src/components/MessageBubble.tsx +211 -69
  25. package/src/components/ProductCard.tsx +2 -2
  26. package/src/components/VisualizationRenderer.tsx +347 -247
  27. package/src/config/RagConfig.ts +5 -0
  28. package/src/config/serverConfig.ts +3 -1
  29. package/src/core/Pipeline.ts +65 -206
  30. package/src/core/ProviderRegistry.ts +2 -2
  31. package/src/core/VectorPlugin.ts +9 -0
  32. package/src/handlers/index.ts +23 -7
  33. package/src/hooks/useRagChat.ts +2 -2
  34. package/src/llm/LLMFactory.ts +54 -2
  35. package/src/llm/providers/AnthropicProvider.ts +12 -8
  36. package/src/llm/providers/GeminiProvider.ts +188 -143
  37. package/src/llm/providers/OllamaProvider.ts +7 -3
  38. package/src/llm/providers/OpenAIProvider.ts +12 -8
  39. package/src/types/chat.ts +6 -0
  40. package/src/types/index.ts +80 -0
  41. package/src/utils/SchemaMapper.ts +129 -0
  42. package/src/utils/UITransformer.ts +491 -181
  43. package/dist/DocumentChunker-C1GEEosY.d.ts +0 -93
  44. package/dist/DocumentChunker-CFEiRopR.d.mts +0 -93
  45. package/dist/PostgreSQLProvider-BMOETDZA.mjs +0 -8
  46. package/dist/chunk-FLOSGE6A.mjs +0 -202
package/dist/server.mjs CHANGED
@@ -39,14 +39,14 @@ import {
39
39
  sseFrame,
40
40
  sseMetaFrame,
41
41
  sseTextFrame
42
- } from "./chunk-PV3MFHWU.mjs";
42
+ } from "./chunk-BFYLQYQU.mjs";
43
43
  import "./chunk-YLTMFW4M.mjs";
44
44
  import {
45
45
  PineconeProvider
46
46
  } from "./chunk-VUQJVIJT.mjs";
47
47
  import {
48
- PostgreSQLProvider
49
- } from "./chunk-FLOSGE6A.mjs";
48
+ MultiTablePostgresProvider
49
+ } from "./chunk-R3RGUMHE.mjs";
50
50
  import {
51
51
  MongoDBProvider
52
52
  } from "./chunk-5AJ4XHLW.mjs";
@@ -60,8 +60,6 @@ import {
60
60
  BaseVectorProvider
61
61
  } from "./chunk-IMP6FUCY.mjs";
62
62
  import {
63
- __objRest,
64
- __spreadProps,
65
63
  __spreadValues
66
64
  } from "./chunk-X4TOT24V.mjs";
67
65
 
@@ -237,196 +235,187 @@ function createFromPreset(presetName) {
237
235
  return new ConfigBuilder().vectorDb(preset.vectorDb, { apiKey: process.env[`${preset.vectorDb.toUpperCase()}_API_KEY`] }).llm(preset.llm, void 0, process.env[`${preset.llm.toUpperCase()}_API_KEY`]).embedding(preset.embedding, void 0, process.env[`${preset.embedding.toUpperCase()}_API_KEY`]);
238
236
  }
239
237
 
240
- // src/providers/vectordb/MultiTablePostgresProvider.ts
238
+ // src/providers/vectordb/PostgreSQLProvider.ts
241
239
  import { Pool } from "pg";
242
- var MultiTablePostgresProvider = class extends BaseVectorProvider {
240
+ var PostgreSQLProvider = class extends BaseVectorProvider {
243
241
  constructor(config) {
244
- var _a, _b, _c, _d, _e;
242
+ var _a;
245
243
  super(config);
246
- const opts = config.options || {};
247
- if (!opts.connectionString) {
248
- throw new Error("[MultiTablePostgresProvider] options.connectionString is required");
249
- }
244
+ this.tableName = this.indexName.replace(/[^a-z0-9_]/gi, "_");
245
+ const opts = config.options;
246
+ if (!opts.connectionString) throw new Error("[PostgreSQLProvider] options.connectionString is required");
250
247
  this.connectionString = opts.connectionString;
251
- this.dimensions = (_a = opts.dimensions) != null ? _a : 768;
252
- const rawTables = (_c = (_b = opts.tables) != null ? _b : process.env.VECTOR_DB_TABLES) != null ? _c : "";
253
- this.tables = typeof rawTables === "string" ? rawTables.split(",").map((t) => t.trim()).filter(Boolean) : rawTables;
254
- if (this.tables.length === 0) {
255
- console.warn(
256
- "[MultiTablePostgresProvider] No tables configured. Set VECTOR_DB_TABLES as a comma-separated list of table names or pass options.tables."
257
- );
258
- }
259
- const rawSearchFields = (_e = (_d = opts.searchFields) != null ? _d : process.env.VECTOR_DB_SEARCH_FIELDS) != null ? _e : ["name", "product_name", "productname", "title"];
260
- this.searchFields = typeof rawSearchFields === "string" ? rawSearchFields.split(",").map((f) => f.trim()).filter(Boolean) : rawSearchFields;
248
+ this.dimensions = (_a = opts.dimensions) != null ? _a : 1536;
249
+ }
250
+ static getValidator() {
251
+ return {
252
+ validate(config) {
253
+ const errors = [];
254
+ const opts = config.options || {};
255
+ if (!opts.connectionString) {
256
+ errors.push({
257
+ field: "vectorDb.options.connectionString",
258
+ message: "PostgreSQL connection string is required",
259
+ suggestion: "Set PGVECTOR_CONNECTION_STRING environment variable",
260
+ severity: "error"
261
+ });
262
+ }
263
+ if (opts.tables && typeof opts.tables !== "string" && !Array.isArray(opts.tables)) {
264
+ errors.push({
265
+ field: "vectorDb.options.tables",
266
+ message: "PostgreSQL tables must be a string or a string array",
267
+ severity: "error"
268
+ });
269
+ }
270
+ return errors;
271
+ }
272
+ };
273
+ }
274
+ static getHealthChecker() {
275
+ return {
276
+ async check(config) {
277
+ const opts = config.options || {};
278
+ const timestamp = Date.now();
279
+ try {
280
+ const { Client } = await import("pg");
281
+ const client = new Client({ connectionString: opts.connectionString });
282
+ await client.connect();
283
+ const result = await client.query(`
284
+ SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname = 'vector');
285
+ `);
286
+ const hasVector = result.rows[0].exists;
287
+ await client.end();
288
+ return {
289
+ healthy: true,
290
+ provider: "postgresql",
291
+ capabilities: { pgvectorInstalled: hasVector },
292
+ timestamp
293
+ };
294
+ } catch (error) {
295
+ return {
296
+ healthy: false,
297
+ provider: "postgresql",
298
+ error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
299
+ timestamp
300
+ };
301
+ }
302
+ }
303
+ };
261
304
  }
262
305
  async initialize() {
263
306
  this.pool = new Pool({ connectionString: this.connectionString });
264
307
  const client = await this.pool.connect();
265
308
  try {
266
- const res = await client.query(`
267
- SELECT table_name
268
- FROM information_schema.columns
269
- WHERE column_name = 'embedding'
270
- AND table_schema = 'public'
309
+ await client.query("CREATE EXTENSION IF NOT EXISTS vector");
310
+ await client.query(`
311
+ CREATE TABLE IF NOT EXISTS ${this.tableName} (
312
+ id TEXT PRIMARY KEY,
313
+ namespace TEXT NOT NULL DEFAULT '',
314
+ content TEXT NOT NULL,
315
+ metadata JSONB,
316
+ embedding VECTOR(${this.dimensions})
317
+ )
318
+ `);
319
+ await client.query(`
320
+ CREATE INDEX IF NOT EXISTS ${this.tableName}_embedding_idx
321
+ ON ${this.tableName}
322
+ USING hnsw (embedding vector_cosine_ops)
271
323
  `);
272
- const discoveredTables = res.rows.map((r) => r.table_name);
273
- if (this.tables.length === 0) {
274
- this.tables = discoveredTables;
275
- } else {
276
- const staticTables = [...this.tables];
277
- this.tables = staticTables.filter((t) => discoveredTables.includes(t));
278
- if (this.tables.length < staticTables.length) {
279
- const missing = staticTables.filter((t) => !discoveredTables.includes(t));
280
- console.warn(`[MultiTablePostgresProvider] Some configured tables were skipped (missing 'embedding' column): ${missing.join(", ")}`);
281
- }
282
- }
283
- if (this.tables.length === 0) {
284
- console.warn('[MultiTablePostgresProvider] No tables with "embedding" columns found in the database.');
285
- } else {
286
- console.log(
287
- `[MultiTablePostgresProvider] Connected. Searching across ${this.tables.length} table(s): ${this.tables.join(", ")}`
288
- );
289
- }
290
324
  } finally {
291
325
  client.release();
292
326
  }
293
327
  }
294
- /**
295
- * Upsert is not supported for MultiTablePostgresProvider as it's designed for
296
- * searching across pre-existing tables with varying schemas.
297
- */
298
- async upsert(_doc, _namespace) {
299
- throw new Error(
300
- "[MultiTablePostgresProvider] upsert() is not supported in multi-table mode. Please use the standard PostgreSQLProvider for single-table managed indices."
301
- );
302
- }
303
- /**
304
- * Batch upsert is not supported for MultiTablePostgresProvider.
305
- */
306
- async batchUpsert(_docs, _namespace) {
307
- throw new Error(
308
- "[MultiTablePostgresProvider] batchUpsert() is not supported in multi-table mode."
328
+ async upsert(doc, namespace = "") {
329
+ var _a;
330
+ const vectorLiteral = `[${doc.vector.join(",")}]`;
331
+ await this.pool.query(
332
+ `INSERT INTO ${this.tableName} (id, namespace, content, metadata, embedding)
333
+ VALUES ($1, $2, $3, $4, $5::vector)
334
+ ON CONFLICT (id) DO UPDATE
335
+ SET namespace = EXCLUDED.namespace,
336
+ content = EXCLUDED.content,
337
+ metadata = EXCLUDED.metadata,
338
+ embedding = EXCLUDED.embedding`,
339
+ [doc.id, namespace, doc.content, JSON.stringify((_a = doc.metadata) != null ? _a : {}), vectorLiteral]
309
340
  );
310
341
  }
311
- /**
312
- * Query all configured tables and merge results, sorted by cosine similarity score.
313
- */
314
- async query(vector, topK, _namespace, _filter) {
315
- var _a, _b, _c;
316
- if (!this.pool) {
317
- throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
318
- }
319
- const vectorLiteral = `[${vector.join(",")}]`;
320
- const allResults = [];
321
- console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
322
- const queryText = _filter == null ? void 0 : _filter.queryText;
323
- const entityHints = Array.isArray(_filter == null ? void 0 : _filter.__entityHints) ? _filter.__entityHints.filter(
324
- (hint) => typeof hint === "object" && hint !== null && typeof hint.value === "string"
325
- ).map((hint) => hint.value.trim().toLowerCase()).filter(Boolean) : [];
326
- console.log(`[MultiTablePostgresProvider] queryText: "${queryText}"`);
327
- console.log(`[MultiTablePostgresProvider] entityHints: [${entityHints.join(", ")}]`);
328
- const getDynamicKeywordQuery = () => {
329
- if (entityHints.length > 0) {
330
- return entityHints.map((h) => h.includes(" ") ? `"${h}"` : h).join(" & ");
331
- }
332
- if (queryText) {
333
- return queryText.toLowerCase().replace(/\b(show|me|the|product[s]?|item[s]?|card[s]?|of|category|find|list|browse|what|are|display|all|under|for|in|with|about)\b/g, "").trim().replace(/\s+/g, " & ");
334
- }
335
- return "";
336
- };
337
- const dynamicKeywordQuery = getDynamicKeywordQuery();
338
- const queryPromises = this.tables.map(async (table) => {
339
- try {
340
- let sqlQuery = "";
341
- let params = [];
342
- if (queryText) {
343
- const hasEntityHints = entityHints.length > 0;
344
- const exactNameScoreExpr = hasEntityHints ? `+ (
345
- SELECT COALESCE(MAX(
346
- CASE WHEN LOWER(val) IN (${entityHints.map((h) => `'${h.replace(/'/g, "''")}'`).join(", ")})
347
- THEN 1.0 ELSE 0.0 END
348
- ), 0)
349
- FROM jsonb_each_text(to_jsonb(t)) AS kv(key, val)
350
- WHERE key IN (${this.searchFields.map((f) => `'${f}'`).join(", ")})
351
- ) * 3.0` : "";
352
- sqlQuery = `
353
- SELECT *,
354
- (1 - (embedding <=> $1::vector)) AS vector_score,
355
- COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) AS keyword_score,
356
- ((1 - (embedding <=> $1::vector)) + (COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) * 2.0) ${exactNameScoreExpr}) AS hybrid_score
357
- FROM "${table}" t
358
- ORDER BY hybrid_score DESC
359
- LIMIT 50
360
- `;
361
- params = [vectorLiteral, dynamicKeywordQuery];
362
- } else {
363
- sqlQuery = `
364
- SELECT *,
365
- (1 - (embedding <=> $1::vector)) AS hybrid_score
366
- FROM "${table}" t
367
- ORDER BY hybrid_score DESC
368
- LIMIT 50
369
- `;
370
- params = [vectorLiteral];
371
- }
372
- const result = await this.pool.query(sqlQuery, params);
373
- if (result.rowCount && result.rowCount > 0) {
374
- console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].hybrid_score.toFixed(4)}`);
375
- } else {
376
- console.log(` \u26AA Table "${table}": No relevant matches found.`);
377
- }
378
- const tableResults = [];
379
- for (const row of result.rows) {
380
- const _a2 = row, { hybrid_score, id } = _a2, rest = __objRest(_a2, ["hybrid_score", "id"]);
381
- delete rest.embedding;
382
- delete rest.vector_score;
383
- delete rest.keyword_score;
384
- delete rest.exact_name_score;
385
- const content = `[TYPE: ${table.replace(/s$/, "").toUpperCase()}]
386
- ` + Object.entries(rest).filter(([k, v]) => v !== null && typeof v !== "object" && k !== "id").map(([k, v]) => `${k}: ${v}`).join("\n");
387
- tableResults.push({
388
- id: `${table}-${id}`,
389
- score: parseFloat(String(hybrid_score)),
390
- content,
391
- metadata: __spreadProps(__spreadValues({}, rest), { source_table: table })
392
- });
393
- }
394
- return tableResults;
395
- } catch (err) {
396
- console.error(
397
- `[MultiTablePostgresProvider] Error querying table "${table}":`,
398
- err.message
399
- );
400
- return [];
342
+ async batchUpsert(docs, namespace = "") {
343
+ if (docs.length === 0) return;
344
+ const client = await this.pool.connect();
345
+ try {
346
+ await client.query("BEGIN");
347
+ const BATCH_SIZE = 50;
348
+ for (let i = 0; i < docs.length; i += BATCH_SIZE) {
349
+ const batch = docs.slice(i, i + BATCH_SIZE);
350
+ const values = [];
351
+ const valuePlaceholders = batch.map((doc, idx) => {
352
+ var _a;
353
+ const offset = idx * 5;
354
+ values.push(doc.id, namespace, doc.content, JSON.stringify((_a = doc.metadata) != null ? _a : {}), `[${doc.vector.join(",")}]`);
355
+ return `($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${offset + 5}::vector)`;
356
+ }).join(", ");
357
+ const query = `
358
+ INSERT INTO ${this.tableName} (id, namespace, content, metadata, embedding)
359
+ VALUES ${valuePlaceholders}
360
+ ON CONFLICT (id) DO UPDATE
361
+ SET namespace = EXCLUDED.namespace,
362
+ content = EXCLUDED.content,
363
+ metadata = EXCLUDED.metadata,
364
+ embedding = EXCLUDED.embedding
365
+ `;
366
+ await client.query(query, values);
401
367
  }
402
- });
403
- const resultsArray = await Promise.all(queryPromises);
404
- for (const tableResults of resultsArray) {
405
- allResults.push(...tableResults);
406
- }
407
- const resultsByTable = {};
408
- for (const res of allResults) {
409
- const table = (_a = res.metadata) == null ? void 0 : _a.source_table;
410
- if (!resultsByTable[table]) resultsByTable[table] = [];
411
- resultsByTable[table].push(res);
368
+ await client.query("COMMIT");
369
+ } catch (error) {
370
+ await client.query("ROLLBACK");
371
+ throw error;
372
+ } finally {
373
+ client.release();
412
374
  }
413
- const balancedResults = [];
414
- const tables = Object.keys(resultsByTable);
415
- for (const table of tables) {
416
- balancedResults.push(...resultsByTable[table].slice(0, 3));
375
+ }
376
+ async query(vector, topK, namespace, filter) {
377
+ const vectorLiteral = `[${vector.join(",")}]`;
378
+ let whereClause = namespace ? `WHERE namespace = $3` : "";
379
+ const params = [vectorLiteral, topK];
380
+ if (namespace) params.push(namespace);
381
+ const publicFilter = this.sanitizeFilter(filter);
382
+ if (Object.keys(publicFilter).length > 0) {
383
+ const filterConditions = Object.entries(publicFilter).map(([key, val]) => {
384
+ const paramIdx = params.length + 1;
385
+ params.push(JSON.stringify(val));
386
+ return `metadata->>'${key}' = $${paramIdx}`;
387
+ }).join(" AND ");
388
+ whereClause = whereClause ? `${whereClause} AND ${filterConditions}` : `WHERE ${filterConditions}`;
417
389
  }
418
- const finalSorted = balancedResults.sort((a, b) => b.score - a.score);
419
- if (finalSorted.length > 0) {
420
- console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
421
- console.log(`[MultiTablePostgresProvider] Final top match from "${(_c = (_b = finalSorted[0].metadata) == null ? void 0 : _b.source_table) != null ? _c : "unknown"}" with score ${finalSorted[0].score.toFixed(4)}`);
390
+ const client = await this.pool.connect();
391
+ try {
392
+ const efSearch = this.config.options.efSearch || Math.max(topK * 10, 40);
393
+ await client.query(`SET LOCAL hnsw.ef_search = ${efSearch}`);
394
+ const result = await client.query(
395
+ `SELECT id, content, metadata, 1 - (embedding <=> $1::vector) AS score
396
+ FROM ${this.tableName}
397
+ ${whereClause}
398
+ ORDER BY embedding <=> $1::vector
399
+ LIMIT $2`,
400
+ params
401
+ );
402
+ return result.rows.map((row) => ({
403
+ id: String(row["id"]),
404
+ score: parseFloat(String(row["score"])),
405
+ content: String(row["content"]),
406
+ metadata: row["metadata"]
407
+ }));
408
+ } finally {
409
+ client.release();
422
410
  }
423
- return finalSorted.slice(0, Math.max(topK, 15));
424
411
  }
425
- async delete(_id, _namespace) {
426
- console.warn("[MultiTablePostgresProvider] delete() is a no-op for multi-table mode.");
412
+ async delete(id, namespace) {
413
+ const where = namespace ? "WHERE id = $1 AND namespace = $2" : "WHERE id = $1";
414
+ const params = namespace ? [id, namespace] : [id];
415
+ await this.pool.query(`DELETE FROM ${this.tableName} ${where}`, params);
427
416
  }
428
- async deleteNamespace(_namespace) {
429
- console.warn("[MultiTablePostgresProvider] deleteNamespace() is a no-op for multi-table mode.");
417
+ async deleteNamespace(namespace) {
418
+ await this.pool.query(`DELETE FROM ${this.tableName} WHERE namespace = $1`, [namespace]);
430
419
  }
431
420
  async ping() {
432
421
  try {
@@ -437,9 +426,7 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
437
426
  }
438
427
  }
439
428
  async disconnect() {
440
- if (this.pool) {
441
- await this.pool.end();
442
- }
429
+ await this.pool.end();
443
430
  }
444
431
  };
445
432
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "1.8.0",
3
+ "version": "1.8.1",
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",
@@ -85,7 +85,7 @@
85
85
  },
86
86
  "dependencies": {
87
87
  "@anthropic-ai/sdk": "^0.90.0",
88
- "@google/genai": "^1.50.1",
88
+ "@google/generative-ai": "^0.24.1",
89
89
  "@pinecone-database/pinecone": "^7.2.0",
90
90
  "axios": "^1.15.0",
91
91
  "lucide-react": "^1.8.0",
@@ -94,6 +94,8 @@
94
94
  "openai": "^6.34.0",
95
95
  "react": ">=18.0.0",
96
96
  "react-dom": ">=18.0.0",
97
+ "react-is": "^18.3.1",
98
+ "@google/genai": "^0.8.0",
97
99
  "react-markdown": "^10.1.0",
98
100
  "recharts": "^3.8.1",
99
101
  "remark-gfm": "^4.0.1"
package/src/app/page.tsx CHANGED
@@ -15,7 +15,6 @@ import { ChatWindow } from '@/components/ChatWindow';
15
15
  import { ChatWidget } from '@/components/ChatWidget';
16
16
  import { useConfig } from '@/components/ConfigProvider';
17
17
  import { ThemeToggle } from '@/components/ThemeToggle';
18
- import pkg from '../../package.json';
19
18
  import { Snippet, ArchitectureCardProps } from './types';
20
19
  import {
21
20
  LANDING_PAGE_CONTENT,
@@ -178,7 +177,7 @@ export default function HomePage() {
178
177
  </span>
179
178
  <div className="flex items-center gap-1.5">
180
179
  <span className="font-bold text-slate-900 dark:text-white text-[10px] tracking-[0.15em] uppercase opacity-70">Accelerator</span>
181
- <span className="text-[9px] px-1.5 py-0.5 rounded-full bg-slate-100 dark:bg-white/5 text-slate-500 dark:text-white/40 font-mono border border-slate-200/50 dark:border-white/10">v{pkg.version}</span>
180
+ <span className="text-[9px] px-1.5 py-0.5 rounded-full bg-slate-100 dark:bg-white/5 text-slate-500 dark:text-white/40 font-mono border border-slate-200/50 dark:border-white/10">v1.8.0</span>
182
181
  </div>
183
182
  </div>
184
183
  </div>