@retrivora-ai/rag-engine 1.9.6 → 1.9.7

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 (44) hide show
  1. package/README.md +32 -7
  2. package/dist/{ILLMProvider-DNhyOYoK.d.mts → ILLMProvider-Bhk6zJOK.d.mts} +2 -6
  3. package/dist/{ILLMProvider-DNhyOYoK.d.ts → ILLMProvider-Bhk6zJOK.d.ts} +2 -6
  4. package/dist/handlers/index.d.mts +2 -2
  5. package/dist/handlers/index.d.ts +2 -2
  6. package/dist/handlers/index.js +213 -67
  7. package/dist/handlers/index.mjs +212 -67
  8. package/dist/{index-CjQdL0cX.d.ts → index-B9J_XEh0.d.ts} +6 -2
  9. package/dist/{index-C9v7-tWd.d.mts → index-BJ4cd-t5.d.mts} +6 -2
  10. package/dist/{index-Hgbwl9X4.d.ts → index-Bu7T6xgr.d.ts} +20 -3
  11. package/dist/{index-CHL1jdYm.d.mts → index-C3SVtPYg.d.mts} +20 -3
  12. package/dist/index.css +197 -10
  13. package/dist/index.d.mts +13 -5
  14. package/dist/index.d.ts +13 -5
  15. package/dist/index.js +39 -6
  16. package/dist/index.mjs +38 -7
  17. package/dist/server.d.mts +5 -5
  18. package/dist/server.d.ts +5 -5
  19. package/dist/server.js +310 -113
  20. package/dist/server.mjs +307 -112
  21. package/package.json +2 -4
  22. package/src/app/constants.tsx +183 -218
  23. package/src/app/layout.tsx +4 -28
  24. package/src/app/types.ts +17 -17
  25. package/src/components/ChatWidget.tsx +3 -1
  26. package/src/components/ChatWindow.tsx +5 -1
  27. package/src/components/DocViewer.tsx +71 -5
  28. package/src/components/Documentation.tsx +74 -11
  29. package/src/components/constants.tsx +275 -0
  30. package/src/config/RagConfig.ts +10 -10
  31. package/src/config/constants.ts +1 -0
  32. package/src/core/ConfigResolver.ts +24 -25
  33. package/src/core/Pipeline.ts +2 -1
  34. package/src/core/ProviderRegistry.ts +5 -5
  35. package/src/core/Retrivora.ts +46 -6
  36. package/src/core/VectorPlugin.ts +62 -8
  37. package/src/exceptions/index.ts +52 -0
  38. package/src/handlers/index.ts +71 -0
  39. package/src/hooks/useRagChat.ts +4 -1
  40. package/src/index.ts +2 -0
  41. package/src/llm/LLMFactory.ts +6 -5
  42. package/src/server.ts +16 -13
  43. package/src/types/chat.ts +2 -0
  44. package/src/types/props.ts +38 -1
@@ -3,6 +3,7 @@ import { ChatMessage, ChatResponse, IngestDocument } from '../types';
3
3
  import { ConfigResolver } from './ConfigResolver';
4
4
  import { ConfigValidator } from './ConfigValidator';
5
5
  import { Pipeline } from './Pipeline';
6
+ import { wrapError, RetrivoraErrorCode } from '../exceptions';
6
7
 
7
8
  /**
8
9
  * Public SDK facade matching the prompt-level Retrivora API.
@@ -20,27 +21,65 @@ export class Retrivora {
20
21
  }
21
22
 
22
23
  async initialize(): Promise<void> {
23
- await ConfigValidator.validateAndThrow(this.config);
24
- await this.pipeline.initialize();
24
+ try {
25
+ await ConfigValidator.validateAndThrow(this.config);
26
+ } catch (err) {
27
+ throw wrapError(err, 'CONFIGURATION_ERROR');
28
+ }
29
+ try {
30
+ await this.pipeline.initialize();
31
+ } catch (err) {
32
+ throw wrapError(err, 'AUTHENTICATION_ERROR');
33
+ }
25
34
  }
26
35
 
27
36
  async ingest(
28
37
  documents: IngestDocument[],
29
38
  namespace?: string,
30
39
  ): Promise<Array<{ docId: string | number; chunksIngested: number }>> {
31
- return this.pipeline.ingest(documents, namespace);
40
+ try {
41
+ return await this.pipeline.ingest(documents, namespace);
42
+ } catch (err) {
43
+ const msg = String(err);
44
+ let defaultCode: RetrivoraErrorCode = 'RETRIEVAL_FAILED';
45
+ if (msg.includes('Embed') || msg.includes('embed')) {
46
+ defaultCode = 'EMBEDDING_FAILED';
47
+ }
48
+ throw wrapError(err, defaultCode);
49
+ }
32
50
  }
33
51
 
34
52
  async ask(question: string, history: ChatMessage[] = [], namespace?: string): Promise<ChatResponse> {
35
- return this.pipeline.ask(question, history, namespace);
53
+ try {
54
+ return await this.pipeline.ask(question, history, namespace);
55
+ } catch (err) {
56
+ const msg = String(err);
57
+ let defaultCode: RetrivoraErrorCode = 'RETRIEVAL_FAILED';
58
+ if (msg.includes('Embed') || msg.includes('embed')) {
59
+ defaultCode = 'EMBEDDING_FAILED';
60
+ }
61
+ throw wrapError(err, defaultCode);
62
+ }
36
63
  }
37
64
 
38
- askStream(
65
+ async *askStream(
39
66
  question: string,
40
67
  history: ChatMessage[] = [],
41
68
  namespace?: string,
42
69
  ): AsyncIterable<string | ChatResponse> {
43
- return this.pipeline.askStream(question, history, namespace);
70
+ try {
71
+ const stream = this.pipeline.askStream(question, history, namespace);
72
+ for await (const chunk of stream) {
73
+ yield chunk;
74
+ }
75
+ } catch (err) {
76
+ const msg = String(err);
77
+ let defaultCode: RetrivoraErrorCode = 'RETRIEVAL_FAILED';
78
+ if (msg.includes('Embed') || msg.includes('embed')) {
79
+ defaultCode = 'EMBEDDING_FAILED';
80
+ }
81
+ throw wrapError(err, defaultCode);
82
+ }
44
83
  }
45
84
 
46
85
  getPipeline(): Pipeline {
@@ -49,3 +88,4 @@ export class Retrivora {
49
88
  }
50
89
 
51
90
  export type { RetrievalConfig, UniversalRagConfig };
91
+
@@ -5,6 +5,7 @@ import { Pipeline } from './Pipeline';
5
5
  import { ProviderHealthCheck, HealthCheckResult } from './ProviderHealthCheck';
6
6
  import { IngestDocument, ChatResponse } from '../types';
7
7
  import { ChatMessage } from '../types';
8
+ import { wrapError, RetrivoraErrorCode } from '../exceptions';
8
9
 
9
10
  /**
10
11
  * VectorPlugin — main orchestrator class.
@@ -27,6 +28,8 @@ export class VectorPlugin {
27
28
 
28
29
  // Start validation early
29
30
  this.validationPromise = ConfigValidator.validateAndThrow(this.config);
31
+ // Prevent unhandled promise rejection warning
32
+ this.validationPromise.catch(() => {});
30
33
 
31
34
  this.pipeline = new Pipeline(this.config);
32
35
  }
@@ -70,31 +73,82 @@ export class VectorPlugin {
70
73
  * Run a chat query.
71
74
  */
72
75
  async chat(message: string, history: ChatMessage[] = [], namespace?: string): Promise<ChatResponse> {
73
- await this.validationPromise;
74
- return this.pipeline.ask(message, history, namespace);
76
+ try {
77
+ await this.validationPromise;
78
+ } catch (err) {
79
+ throw wrapError(err, 'CONFIGURATION_ERROR');
80
+ }
81
+ try {
82
+ return await this.pipeline.ask(message, history, namespace);
83
+ } catch (err) {
84
+ const msg = String(err);
85
+ let defaultCode: RetrivoraErrorCode = 'RETRIEVAL_FAILED';
86
+ if (msg.includes('Embed') || msg.includes('embed')) {
87
+ defaultCode = 'EMBEDDING_FAILED';
88
+ }
89
+ throw wrapError(err, defaultCode);
90
+ }
75
91
  }
76
92
 
77
93
  /**
78
94
  * Run a streaming chat query.
79
95
  */
80
96
  async *chatStream(message: string, history: ChatMessage[] = [], namespace?: string) {
81
- await this.validationPromise;
82
- yield* this.pipeline.askStream(message, history, namespace);
97
+ try {
98
+ await this.validationPromise;
99
+ } catch (err) {
100
+ throw wrapError(err, 'CONFIGURATION_ERROR');
101
+ }
102
+ try {
103
+ const stream = this.pipeline.askStream(message, history, namespace);
104
+ for await (const chunk of stream) {
105
+ yield chunk;
106
+ }
107
+ } catch (err) {
108
+ const msg = String(err);
109
+ let defaultCode: RetrivoraErrorCode = 'RETRIEVAL_FAILED';
110
+ if (msg.includes('Embed') || msg.includes('embed')) {
111
+ defaultCode = 'EMBEDDING_FAILED';
112
+ }
113
+ throw wrapError(err, defaultCode);
114
+ }
83
115
  }
84
116
 
85
117
  /**
86
118
  * Ingest documents into the vector database.
87
119
  */
88
120
  async ingest(documents: IngestDocument[], namespace?: string): Promise<Array<{ docId: string | number; chunksIngested: number }>> {
89
- await this.validationPromise;
90
- return this.pipeline.ingest(documents, namespace);
121
+ try {
122
+ await this.validationPromise;
123
+ } catch (err) {
124
+ throw wrapError(err, 'CONFIGURATION_ERROR');
125
+ }
126
+ try {
127
+ return await this.pipeline.ingest(documents, namespace);
128
+ } catch (err) {
129
+ const msg = String(err);
130
+ let defaultCode: RetrivoraErrorCode = 'RETRIEVAL_FAILED';
131
+ if (msg.includes('Embed') || msg.includes('embed')) {
132
+ defaultCode = 'EMBEDDING_FAILED';
133
+ }
134
+ throw wrapError(err, defaultCode);
135
+ }
91
136
  }
92
137
 
93
138
  /**
94
139
  * Get auto-suggestions based on a query prefix.
95
140
  */
96
141
  async getSuggestions(query: string, namespace?: string): Promise<string[]> {
97
- await this.validationPromise;
98
- return this.pipeline.getSuggestions(query, namespace);
142
+ try {
143
+ await this.validationPromise;
144
+ } catch (err) {
145
+ throw wrapError(err, 'CONFIGURATION_ERROR');
146
+ }
147
+ try {
148
+ return await this.pipeline.getSuggestions(query, namespace);
149
+ } catch (err) {
150
+ throw wrapError(err, 'RETRIEVAL_FAILED');
151
+ }
99
152
  }
100
153
  }
154
+
@@ -57,3 +57,55 @@ export class AuthenticationException extends RetrivoraError {
57
57
  super(message, 'AUTHENTICATION_ERROR', details);
58
58
  }
59
59
  }
60
+
61
+ /**
62
+ * Wraps any unknown error into an appropriate RetrivoraError subclass.
63
+ */
64
+ export function wrapError(
65
+ err: unknown,
66
+ defaultCode: RetrivoraErrorCode,
67
+ defaultMessage?: string,
68
+ ): RetrivoraError {
69
+ if (err instanceof RetrivoraError) {
70
+ return err;
71
+ }
72
+
73
+ const error = err as any;
74
+ const message = error?.message || defaultMessage || String(err);
75
+ const status = error?.status || error?.statusCode || error?.response?.status;
76
+ const code = error?.code;
77
+
78
+ // 1. Rate Limit Recognition
79
+ if (status === 429 || /rate[- ]?limit/i.test(message) || code === 'RATE_LIMIT_EXCEEDED') {
80
+ return new RateLimitException(message, err);
81
+ }
82
+
83
+ // 2. Authentication Recognition
84
+ if (
85
+ status === 401 ||
86
+ status === 403 ||
87
+ /unauthorized|auth|api[- ]?key/i.test(message) ||
88
+ code === 'INVALID_API_KEY'
89
+ ) {
90
+ return new AuthenticationException(message, err);
91
+ }
92
+
93
+ // Fallback Mapping based on defaultCode
94
+ switch (defaultCode) {
95
+ case 'PROVIDER_NOT_FOUND':
96
+ return new ProviderNotFoundException('provider', message, err);
97
+ case 'EMBEDDING_FAILED':
98
+ return new EmbeddingFailedException(message, err);
99
+ case 'RETRIEVAL_FAILED':
100
+ return new RetrievalException(message, err);
101
+ case 'RATE_LIMITED':
102
+ return new RateLimitException(message, err);
103
+ case 'CONFIGURATION_ERROR':
104
+ return new ConfigurationException(message, err);
105
+ case 'AUTHENTICATION_ERROR':
106
+ return new AuthenticationException(message, err);
107
+ default:
108
+ return new RetrivoraError(message, defaultCode, err);
109
+ }
110
+ }
111
+
@@ -413,5 +413,76 @@ export function createSuggestionsHandler(configOrPlugin?: Partial<RagConfig> | V
413
413
  };
414
414
  }
415
415
 
416
+ /**
417
+ * createRagHandler — factory that returns GET and POST handlers for a catch-all route
418
+ * (e.g. `src/app/api/retrivora/[[...retrivora]]/route.ts`).
419
+ */
420
+ export function createRagHandler(configOrPlugin?: Partial<RagConfig> | VectorPlugin) {
421
+ const plugin =
422
+ configOrPlugin instanceof VectorPlugin
423
+ ? configOrPlugin
424
+ : new VectorPlugin(configOrPlugin);
425
+
426
+ const chatHandler = createChatHandler(plugin);
427
+ const streamHandler = createStreamHandler(plugin);
428
+ const uploadHandler = createUploadHandler(plugin);
429
+ const healthHandler = createHealthHandler(plugin);
430
+ const suggestionsHandler = createSuggestionsHandler(plugin);
431
+
432
+ async function routePostRequest(req: NextRequest, segment: string) {
433
+ switch (segment) {
434
+ case 'chat':
435
+ return streamHandler(req);
436
+ case 'chat-sync':
437
+ return chatHandler(req);
438
+ case 'upload':
439
+ return uploadHandler(req);
440
+ case 'suggestions':
441
+ return suggestionsHandler(req);
442
+ case 'health':
443
+ return healthHandler();
444
+ default:
445
+ return NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
446
+ }
447
+ }
448
+
449
+ async function routeGetRequest(req: NextRequest, segment: string) {
450
+ if (segment === 'health') {
451
+ return healthHandler();
452
+ }
453
+ return NextResponse.json({ error: `Method Not Allowed: GET is only supported for "health" segment.` }, { status: 405 });
454
+ }
455
+
456
+ async function getSegment(context: any): Promise<string> {
457
+ const resolvedParams = typeof context?.params?.then === 'function'
458
+ ? await context.params
459
+ : context?.params;
460
+
461
+ const segments: string[] = resolvedParams?.retrivora || [];
462
+ return segments[0] || 'chat';
463
+ }
464
+
465
+ return {
466
+ GET: async (req: NextRequest, context: any) => {
467
+ try {
468
+ const segment = await getSegment(context);
469
+ return await routeGetRequest(req, segment);
470
+ } catch (err) {
471
+ const msg = err instanceof Error ? err.message : 'GET Routing failed';
472
+ return NextResponse.json({ error: msg }, { status: 500 });
473
+ }
474
+ },
475
+ POST: async (req: NextRequest, context: any) => {
476
+ try {
477
+ const segment = await getSegment(context);
478
+ return await routePostRequest(req, segment);
479
+ } catch (err) {
480
+ const msg = err instanceof Error ? err.message : 'POST Routing failed';
481
+ return NextResponse.json({ error: msg }, { status: 500 });
482
+ }
483
+ }
484
+ };
485
+ }
486
+
416
487
  // Re-export SSE helpers so host apps can use them in custom handlers
417
488
  export { sseFrame, sseTextFrame, sseMetaFrame, sseErrorFrame, sseUIFrame, sseObservabilityFrame };
@@ -115,7 +115,10 @@ export function useRagChat(
115
115
 
116
116
  const response = await fetch(apiUrl, {
117
117
  method: 'POST',
118
- headers: { 'Content-Type': 'application/json' },
118
+ headers: {
119
+ 'Content-Type': 'application/json',
120
+ ...(options.headers || {})
121
+ },
119
122
  signal: controller.signal,
120
123
  body: JSON.stringify({
121
124
  message: trimmed,
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  /**
2
4
  * Package entry point — public API exported to consumers of this npm package.
3
5
  * This entry point is CLIENT-SAFE and can be imported in React Client Components.
@@ -83,11 +83,12 @@ export class LLMFactory {
83
83
  return new UniversalLLMAdapter(llmConfig);
84
84
  }
85
85
  throw new ProviderNotFoundException(
86
- 'LLM',
87
- String(llmConfig.provider),
88
- `[LLMFactory] Unknown provider "${llmConfig.provider}". ` +
89
- `Built-in providers: ${LLMFactory.listProviders().join(', ')}. ` +
90
- `Register a custom provider with LLMFactory.register().`
86
+ 'llm',
87
+ llmConfig.provider ?? 'undefined',
88
+ {
89
+ message: `Unknown provider "${llmConfig.provider}". Register a custom provider with LLMFactory.register().`,
90
+ available: LLMFactory.listProviders()
91
+ }
91
92
  );
92
93
  }
93
94
  }
package/src/server.ts CHANGED
@@ -28,8 +28,8 @@ export type { ValidationError } from './core/ConfigValidator';
28
28
  export type { BatchOptions, BatchResult } from './core/BatchProcessor';
29
29
 
30
30
  // ── Core Orchestration ─────────────────────────────────────────
31
- export { VectorPlugin } from './core/VectorPlugin';
32
31
  export { Retrivora } from './core/Retrivora';
32
+ export { VectorPlugin } from './core/VectorPlugin';
33
33
  export { Pipeline } from './core/Pipeline';
34
34
  export { ConfigResolver } from './core/ConfigResolver';
35
35
  export { ProviderRegistry } from './core/ProviderRegistry';
@@ -37,18 +37,6 @@ export { ConfigValidator } from './core/ConfigValidator';
37
37
  export { ProviderHealthCheck } from './core/ProviderHealthCheck';
38
38
  export { BatchProcessor } from './core/BatchProcessor';
39
39
 
40
- // ── Exceptions ────────────────────────────────────────────────
41
- export {
42
- RetrivoraError,
43
- ProviderNotFoundException,
44
- EmbeddingFailedException,
45
- RetrievalException,
46
- RateLimitException,
47
- ConfigurationException,
48
- AuthenticationException,
49
- } from './exceptions';
50
- export type { RetrivoraErrorCode } from './exceptions';
51
-
52
40
  // ── Configuration Helpers ──────────────────────────────────────
53
41
  export { getRagConfig } from './config/serverConfig';
54
42
  export { ConfigBuilder, PRESETS, createFromPreset } from './config/ConfigBuilder';
@@ -86,8 +74,23 @@ export {
86
74
  createIngestHandler,
87
75
  createHealthHandler,
88
76
  createUploadHandler,
77
+ createRagHandler,
89
78
  sseFrame,
90
79
  sseTextFrame,
91
80
  sseMetaFrame,
92
81
  sseErrorFrame,
93
82
  } from './handlers';
83
+
84
+ // ── Exceptions ────────────────────────────────────────────────
85
+ export type { RetrivoraErrorCode } from './exceptions';
86
+ export {
87
+ RetrivoraError,
88
+ ProviderNotFoundException,
89
+ EmbeddingFailedException,
90
+ RetrievalException,
91
+ RateLimitException,
92
+ ConfigurationException,
93
+ AuthenticationException,
94
+ wrapError,
95
+ } from './exceptions';
96
+
package/src/types/chat.ts CHANGED
@@ -49,6 +49,8 @@ export interface UseRagChatOptions {
49
49
  onReply?: (message: RagMessage) => void;
50
50
  /** Called on error */
51
51
  onError?: (error: string) => void;
52
+ /** Optional custom headers to send with the chat request */
53
+ headers?: Record<string, string>;
52
54
  }
53
55
 
54
56
  export interface UseRagChatReturn {
@@ -1,8 +1,37 @@
1
- import { ReactNode, CSSProperties, MouseEvent } from 'react';
1
+ import { ReactNode, CSSProperties, MouseEvent, ElementType } from 'react';
2
2
  import { Product, VectorMatch } from './index';
3
3
  import { RagMessage } from './chat';
4
4
  import { UIConfig } from '../config/RagConfig';
5
5
 
6
+ export interface ArchitectureCardProps {
7
+ icon: ReactNode;
8
+ title: string;
9
+ description: string;
10
+ badge: string;
11
+ badgeColor: string;
12
+ }
13
+
14
+ export interface Snippet {
15
+ id: string;
16
+ title: string;
17
+ description: string;
18
+ code: string;
19
+ language: string;
20
+ }
21
+
22
+ export interface PipelineStep {
23
+ step: string;
24
+ Icon: ElementType;
25
+ title: string;
26
+ desc: string;
27
+ colors: { from: string; to: string };
28
+ }
29
+
30
+ export interface ProviderPill {
31
+ Icon: ElementType;
32
+ label: string;
33
+ }
34
+
6
35
  export type ChatViewportSize = 'compact' | 'medium' | 'large';
7
36
 
8
37
  export interface ChatWindowProps {
@@ -26,6 +55,10 @@ export interface ChatWindowProps {
26
55
  isMaximized?: boolean;
27
56
  /** Called when the user clicks 'Add to Cart' on a product */
28
57
  onAddToCart?: (product: Product) => void;
58
+ /** Optional custom API URL to send chat messages to */
59
+ apiUrl?: string;
60
+ /** Optional custom headers to send with the chat request */
61
+ headers?: Record<string, string>;
29
62
  }
30
63
 
31
64
  export interface ChatWidgetProps {
@@ -33,6 +66,10 @@ export interface ChatWidgetProps {
33
66
  position?: 'bottom-right' | 'bottom-left';
34
67
  /** Called when the user clicks 'Add to Cart' on a product */
35
68
  onAddToCart?: (product: Product) => void;
69
+ /** Optional custom API URL to send chat messages to */
70
+ apiUrl?: string;
71
+ /** Optional custom headers to send with the chat request */
72
+ headers?: Record<string, string>;
36
73
  }
37
74
 
38
75
  export interface MessageBubbleProps {