vectra-js 0.9.3 → 0.9.5
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/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/dependabot.yml +11 -0
- package/.github/workflows/npm-publish.yml +42 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/LICENSE +674 -674
- package/README.md +30 -0
- package/bin/vectra.js +9 -3
- package/package.json +23 -21
- package/src/backends/chroma_store.js +13 -2
- package/src/config.js +9 -0
- package/src/core.js +203 -1
- package/src/dashboard/dashboard-script.js +260 -0
- package/src/dashboard/index.html +362 -0
- package/src/dashboard/logo.png +0 -0
- package/src/dashboard/trace-script.js +184 -0
- package/src/dashboard/trace.html +239 -0
- package/src/observability.js +226 -0
- package/src/processor.js +1 -1
- package/src/ui/index.html +278 -236
- package/src/ui/logo.png +0 -0
- package/src/ui/script.js +59 -10
- package/src/ui/style.css +2 -2
- package/src/webconfig_server.js +162 -2
package/README.md
CHANGED
|
@@ -161,6 +161,13 @@ const config = {
|
|
|
161
161
|
- `enrichment`: boolean; generate `summary`, `keywords`, `hypothetical_questions`
|
|
162
162
|
- Callbacks
|
|
163
163
|
- `callbacks`: array of handlers; use `LoggingCallbackHandler` or `StructuredLoggingCallbackHandler`
|
|
164
|
+
- Observability
|
|
165
|
+
- `enabled`: boolean; enable SQLite-based observability (default: false)
|
|
166
|
+
- `sqlitePath`: string; path to SQLite database file (default: 'vectra-observability.db')
|
|
167
|
+
- `projectId`: string; project identifier for multi-project support (default: 'default')
|
|
168
|
+
- `trackMetrics`: boolean; track latency and other metrics
|
|
169
|
+
- `trackTraces`: boolean; track detailed workflow traces
|
|
170
|
+
- `sessionTracking`: boolean; track chat sessions
|
|
164
171
|
- Index Helpers (Postgres + Prisma)
|
|
165
172
|
- `ensureIndexes()`: creates ivfflat and GIN FTS indexes and optional `tsvector` trigger
|
|
166
173
|
|
|
@@ -601,6 +608,29 @@ const { StructuredLoggingCallbackHandler } = require('vectra-js/src/callbacks');
|
|
|
601
608
|
const config = { callbacks: [ new StructuredLoggingCallbackHandler() ] };
|
|
602
609
|
```
|
|
603
610
|
|
|
611
|
+
### Observability
|
|
612
|
+
|
|
613
|
+
Built-in SQLite-based observability to track metrics, traces, and sessions.
|
|
614
|
+
|
|
615
|
+
```javascript
|
|
616
|
+
const config = {
|
|
617
|
+
// ...
|
|
618
|
+
observability: {
|
|
619
|
+
enabled: true,
|
|
620
|
+
sqlitePath: 'vectra-observability.db',
|
|
621
|
+
projectId: 'my-project',
|
|
622
|
+
trackMetrics: true,
|
|
623
|
+
trackTraces: true,
|
|
624
|
+
sessionTracking: true
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
This tracks:
|
|
630
|
+
- **Metrics**: Latency (ingest, query).
|
|
631
|
+
- **Traces**: Detailed spans for retrieval, generation, and ingestion workflows.
|
|
632
|
+
- **Sessions**: Chat session history and last query tracking.
|
|
633
|
+
|
|
604
634
|
### Vector Stores
|
|
605
635
|
- Prisma (Postgres + pgvector), Chroma, Qdrant, Milvus.
|
|
606
636
|
- Configure `database.type`, `tableName`, `columnMap`, `clientInstance`.
|
package/bin/vectra.js
CHANGED
|
@@ -28,12 +28,18 @@ async function run() {
|
|
|
28
28
|
|
|
29
29
|
if (cmd === 'webconfig') {
|
|
30
30
|
const cfgPath = configPath || path.join(process.cwd(), 'vectra-config.json');
|
|
31
|
-
startWebConfig(cfgPath);
|
|
31
|
+
startWebConfig(cfgPath, 'webconfig');
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
if (
|
|
36
|
-
|
|
35
|
+
if (cmd === 'dashboard') {
|
|
36
|
+
const cfgPath = configPath || path.join(process.cwd(), 'vectra-config.json');
|
|
37
|
+
startWebConfig(cfgPath, 'dashboard');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!cmd || (!target && cmd !== 'webconfig' && cmd !== 'dashboard')) {
|
|
42
|
+
console.error('Usage: vectra <ingest|query|webconfig|dashboard> <path|text> [--config=path] [--stream]');
|
|
37
43
|
process.exit(1);
|
|
38
44
|
}
|
|
39
45
|
|
package/package.json
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vectra-js",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.5",
|
|
4
4
|
"description": "A production-ready, provider-agnostic Node.js SDK for End-to-End RAG pipelines.",
|
|
5
5
|
"main": "index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
-
"prisma:generate": "prisma generate",
|
|
9
|
-
"lint": "eslint . --ext .js,.cjs,.mjs",
|
|
10
|
-
"lint:fix": "eslint . --ext .js,.cjs,.mjs --fix",
|
|
11
|
-
"prepublishOnly": "pnpm run lint",
|
|
12
|
-
"publish": "npm publish --access public"
|
|
13
|
-
},
|
|
14
6
|
"bin": {
|
|
15
7
|
"vectra": "bin/vectra.js"
|
|
16
8
|
},
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public"
|
|
11
|
+
},
|
|
17
12
|
"keywords": [
|
|
18
13
|
"rag",
|
|
19
14
|
"llm",
|
|
@@ -33,22 +28,29 @@
|
|
|
33
28
|
"author": "Abhishek N",
|
|
34
29
|
"license": "GPL-3.0",
|
|
35
30
|
"dependencies": {
|
|
36
|
-
"@anthropic-ai/sdk": "^0.20.
|
|
37
|
-
"@google/genai": "^1.
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
31
|
+
"@anthropic-ai/sdk": "^0.20.9",
|
|
32
|
+
"@google/genai": "^1.34.0",
|
|
33
|
+
"dotenv": "^16.6.1",
|
|
34
|
+
"mammoth": "^1.11.0",
|
|
35
|
+
"openai": "^6.15.0",
|
|
36
|
+
"pdf-parse": "^2.4.5",
|
|
37
|
+
"sqlite3": "^5.1.7",
|
|
38
|
+
"uuid": "^9.0.1",
|
|
42
39
|
"xlsx": "^0.18.5",
|
|
43
|
-
"
|
|
44
|
-
"dotenv": "^16.0.0"
|
|
40
|
+
"zod": "^3.25.76"
|
|
45
41
|
},
|
|
46
42
|
"peerDependencies": {
|
|
47
43
|
"@prisma/client": "^5.0.0"
|
|
48
44
|
},
|
|
49
45
|
"devDependencies": {
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
46
|
+
"eslint": "^9.39.2",
|
|
47
|
+
"globals": "^16.5.0",
|
|
48
|
+
"prisma": "^7.2.0"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
52
|
+
"prisma:generate": "prisma generate",
|
|
53
|
+
"lint": "eslint . --ext .js,.cjs,.mjs",
|
|
54
|
+
"lint:fix": "eslint . --ext .js,.cjs,.mjs --fix"
|
|
53
55
|
}
|
|
54
|
-
}
|
|
56
|
+
}
|
|
@@ -15,11 +15,22 @@ class ChromaVectorStore extends VectorStore {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
_cleanMetadata(meta) {
|
|
19
|
+
if (!meta) return {};
|
|
20
|
+
const out = {};
|
|
21
|
+
for (const [k, v] of Object.entries(meta)) {
|
|
22
|
+
if (v !== undefined && v !== null) {
|
|
23
|
+
out[k] = v;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
async addDocuments(docs) {
|
|
19
30
|
await this._init();
|
|
20
31
|
const ids = docs.map((d) => d.id || uuidv4());
|
|
21
32
|
const embeddings = docs.map(d => d.embedding);
|
|
22
|
-
const metadatas = docs.map(d => d.metadata);
|
|
33
|
+
const metadatas = docs.map(d => this._cleanMetadata(d.metadata));
|
|
23
34
|
const documents = docs.map(d => d.content);
|
|
24
35
|
|
|
25
36
|
await this.collection.add({
|
|
@@ -34,7 +45,7 @@ class ChromaVectorStore extends VectorStore {
|
|
|
34
45
|
await this._init();
|
|
35
46
|
const ids = docs.map((d) => d.id || uuidv4());
|
|
36
47
|
const embeddings = docs.map(d => d.embedding);
|
|
37
|
-
const metadatas = docs.map(d => d.metadata);
|
|
48
|
+
const metadatas = docs.map(d => this._cleanMetadata(d.metadata));
|
|
38
49
|
const documents = docs.map(d => d.content);
|
|
39
50
|
if (typeof this.collection.upsert === 'function') {
|
|
40
51
|
await this.collection.upsert({ ids, embeddings, metadatas, documents });
|
package/src/config.js
CHANGED
|
@@ -114,6 +114,15 @@ const RAGConfigSchema = z.object({
|
|
|
114
114
|
prompts: z.object({ query: z.string().optional(), reranking: z.string().optional() }).optional(),
|
|
115
115
|
tracing: z.object({ enable: z.boolean().default(false) }).optional(),
|
|
116
116
|
callbacks: z.array(z.custom((val) => true)).optional(),
|
|
117
|
+
observability: z.object({
|
|
118
|
+
enabled: z.boolean().default(false),
|
|
119
|
+
sqlitePath: z.string().default('vectra-observability.db'),
|
|
120
|
+
projectId: z.string().default('default'),
|
|
121
|
+
trackMetrics: z.boolean().default(true),
|
|
122
|
+
trackTraces: z.boolean().default(true),
|
|
123
|
+
trackLogs: z.boolean().default(true),
|
|
124
|
+
sessionTracking: z.boolean().default(true)
|
|
125
|
+
}).default({})
|
|
117
126
|
});
|
|
118
127
|
|
|
119
128
|
module.exports = {
|
package/src/core.js
CHANGED
|
@@ -16,12 +16,20 @@ const { LLMReranker } = require('./reranker');
|
|
|
16
16
|
const { InMemoryHistory, RedisHistory, PostgresHistory } = require('./memory');
|
|
17
17
|
const { OllamaBackend } = require('./backends/ollama');
|
|
18
18
|
const { v5: uuidv5 } = require('uuid');
|
|
19
|
+
const { v4: uuidv4 } = require('uuid');
|
|
20
|
+
const SQLiteLogger = require('./observability');
|
|
19
21
|
|
|
20
22
|
class VectraClient {
|
|
21
23
|
constructor(config) {
|
|
22
24
|
const parsed = RAGConfigSchema.parse(config);
|
|
23
25
|
this.config = parsed;
|
|
24
26
|
this.callbacks = config.callbacks || [];
|
|
27
|
+
|
|
28
|
+
// Initialize observability
|
|
29
|
+
this.logger = (this.config.observability && this.config.observability.enabled)
|
|
30
|
+
? new SQLiteLogger(this.config.observability)
|
|
31
|
+
: null;
|
|
32
|
+
|
|
25
33
|
// Initialize processor
|
|
26
34
|
const agenticLlm = (this.config.chunking && this.config.chunking.agenticLlm)
|
|
27
35
|
? this.createLLM(this.config.chunking.agenticLlm)
|
|
@@ -128,6 +136,12 @@ class VectraClient {
|
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
async ingestDocuments(filePath) {
|
|
139
|
+
const traceId = uuidv4();
|
|
140
|
+
const rootSpanId = uuidv4();
|
|
141
|
+
const tStart = Date.now();
|
|
142
|
+
const provider = this.config.embedding.provider;
|
|
143
|
+
const modelName = this.config.embedding.modelName;
|
|
144
|
+
|
|
131
145
|
try {
|
|
132
146
|
const stats = await fs.promises.stat(filePath);
|
|
133
147
|
|
|
@@ -292,8 +306,35 @@ class VectraClient {
|
|
|
292
306
|
}
|
|
293
307
|
const durationMs = Date.now() - t0;
|
|
294
308
|
this.trigger('onIngestEnd', filePath, chunks.length, durationMs);
|
|
309
|
+
|
|
310
|
+
this.logger.logTrace({
|
|
311
|
+
traceId,
|
|
312
|
+
spanId: rootSpanId,
|
|
313
|
+
name: 'ingestDocuments',
|
|
314
|
+
startTime: tStart,
|
|
315
|
+
endTime: Date.now(),
|
|
316
|
+
input: { filePath },
|
|
317
|
+
output: { chunks: chunks.length, durationMs },
|
|
318
|
+
attributes: { fileSize: size },
|
|
319
|
+
provider,
|
|
320
|
+
modelName
|
|
321
|
+
});
|
|
322
|
+
this.logger.logMetric({ name: 'ingest_latency', value: durationMs, tags: { type: 'single_file' } });
|
|
323
|
+
|
|
295
324
|
} catch (e) {
|
|
296
325
|
this.trigger('onError', e);
|
|
326
|
+
this.logger.logTrace({
|
|
327
|
+
traceId,
|
|
328
|
+
spanId: rootSpanId,
|
|
329
|
+
name: 'ingestDocuments',
|
|
330
|
+
startTime: tStart,
|
|
331
|
+
endTime: Date.now(),
|
|
332
|
+
input: { filePath },
|
|
333
|
+
error: { message: e.message },
|
|
334
|
+
status: 'error',
|
|
335
|
+
provider,
|
|
336
|
+
modelName
|
|
337
|
+
});
|
|
297
338
|
throw e;
|
|
298
339
|
}
|
|
299
340
|
}
|
|
@@ -459,6 +500,19 @@ class VectraClient {
|
|
|
459
500
|
}
|
|
460
501
|
|
|
461
502
|
async queryRAG(query, filter = null, stream = false, sessionId = null) {
|
|
503
|
+
const traceId = uuidv4();
|
|
504
|
+
const rootSpanId = uuidv4();
|
|
505
|
+
const tStart = Date.now();
|
|
506
|
+
|
|
507
|
+
if (sessionId) {
|
|
508
|
+
this.logger.updateSession(sessionId, null, { lastQuery: query });
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const provider = this.config.llm.provider;
|
|
512
|
+
const modelName = this.config.llm.modelName;
|
|
513
|
+
const embeddingProvider = this.config.embedding.provider;
|
|
514
|
+
const embeddingModelName = this.config.embedding.modelName;
|
|
515
|
+
|
|
462
516
|
try {
|
|
463
517
|
const tRetrieval = Date.now();
|
|
464
518
|
this.trigger('onRetrievalStart', query);
|
|
@@ -505,6 +559,20 @@ class VectraClient {
|
|
|
505
559
|
|
|
506
560
|
const retrievalMs = Date.now() - tRetrieval;
|
|
507
561
|
this.trigger('onRetrievalEnd', docs.length, retrievalMs);
|
|
562
|
+
|
|
563
|
+
this.logger.logTrace({
|
|
564
|
+
traceId,
|
|
565
|
+
spanId: uuidv4(),
|
|
566
|
+
parentSpanId: rootSpanId,
|
|
567
|
+
name: 'retrieval',
|
|
568
|
+
startTime: tRetrieval,
|
|
569
|
+
endTime: Date.now(),
|
|
570
|
+
input: { query, filter, strategy },
|
|
571
|
+
output: { documentsFound: docs.length },
|
|
572
|
+
provider: embeddingProvider,
|
|
573
|
+
modelName: embeddingModelName
|
|
574
|
+
});
|
|
575
|
+
|
|
508
576
|
const terms = query.toLowerCase().split(/\W+/).filter(t=>t.length>2);
|
|
509
577
|
docs = docs.map(d => {
|
|
510
578
|
const kws = Array.isArray(d.metadata?.keywords) ? d.metadata.keywords.map(k=>String(k).toLowerCase()) : [];
|
|
@@ -547,7 +615,91 @@ class VectraClient {
|
|
|
547
615
|
if (stream) {
|
|
548
616
|
// Streaming return
|
|
549
617
|
if (!this.llm.generateStream) throw new Error("Streaming not implemented for this provider");
|
|
550
|
-
|
|
618
|
+
|
|
619
|
+
this.logger.logTrace({
|
|
620
|
+
traceId,
|
|
621
|
+
spanId: uuidv4(),
|
|
622
|
+
parentSpanId: rootSpanId,
|
|
623
|
+
name: 'generation_stream_start',
|
|
624
|
+
startTime: tGen,
|
|
625
|
+
endTime: Date.now(),
|
|
626
|
+
input: { prompt },
|
|
627
|
+
output: { stream: true },
|
|
628
|
+
provider,
|
|
629
|
+
modelName
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
const originalStream = await this.llm.generateStream(prompt, systemInst);
|
|
633
|
+
const self = this;
|
|
634
|
+
|
|
635
|
+
async function* wrappedStream() {
|
|
636
|
+
let fullAnswer = '';
|
|
637
|
+
try {
|
|
638
|
+
for await (const chunk of originalStream) {
|
|
639
|
+
const delta = (chunk && chunk.delta) ? chunk.delta : (typeof chunk === 'string' ? chunk : '');
|
|
640
|
+
fullAnswer += delta;
|
|
641
|
+
yield chunk;
|
|
642
|
+
}
|
|
643
|
+
} catch (e) {
|
|
644
|
+
self.trigger('onError', e);
|
|
645
|
+
self.logger.logTrace({
|
|
646
|
+
traceId,
|
|
647
|
+
spanId: rootSpanId,
|
|
648
|
+
name: 'queryRAG',
|
|
649
|
+
startTime: tStart,
|
|
650
|
+
endTime: Date.now(),
|
|
651
|
+
input: { query, sessionId },
|
|
652
|
+
error: { message: e.message, stack: e.stack },
|
|
653
|
+
status: 'error',
|
|
654
|
+
provider,
|
|
655
|
+
modelName
|
|
656
|
+
});
|
|
657
|
+
throw e;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// Stream finished successfully
|
|
661
|
+
const genMs = Date.now() - tGen;
|
|
662
|
+
self.trigger('onGenerationEnd', fullAnswer, genMs);
|
|
663
|
+
|
|
664
|
+
const promptChars = prompt.length;
|
|
665
|
+
const answerChars = fullAnswer.length;
|
|
666
|
+
|
|
667
|
+
self.logger.logTrace({
|
|
668
|
+
traceId,
|
|
669
|
+
spanId: uuidv4(),
|
|
670
|
+
parentSpanId: rootSpanId,
|
|
671
|
+
name: 'generation',
|
|
672
|
+
startTime: tGen,
|
|
673
|
+
endTime: Date.now(),
|
|
674
|
+
input: { prompt },
|
|
675
|
+
output: { answer: fullAnswer.substring(0, 1000) },
|
|
676
|
+
attributes: { prompt_chars: promptChars, completion_chars: answerChars },
|
|
677
|
+
provider,
|
|
678
|
+
modelName
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
self.logger.logMetric({ name: 'prompt_chars', value: promptChars });
|
|
682
|
+
self.logger.logMetric({ name: 'completion_chars', value: answerChars });
|
|
683
|
+
|
|
684
|
+
self.logger.logTrace({
|
|
685
|
+
traceId,
|
|
686
|
+
spanId: rootSpanId,
|
|
687
|
+
name: 'queryRAG',
|
|
688
|
+
startTime: tStart,
|
|
689
|
+
endTime: Date.now(),
|
|
690
|
+
input: { query, sessionId },
|
|
691
|
+
output: { success: true },
|
|
692
|
+
attributes: { retrievalMs, genMs, docCount: docs.length },
|
|
693
|
+
provider,
|
|
694
|
+
modelName
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
self.logger.logMetric({ name: 'query_latency', value: Date.now() - tStart, tags: { type: 'total' } });
|
|
698
|
+
self.logger.logMetric({ name: 'retrieval_latency', value: retrievalMs, tags: { type: 'retrieval' } });
|
|
699
|
+
self.logger.logMetric({ name: 'generation_latency', value: genMs, tags: { type: 'generation' } });
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
return wrappedStream();
|
|
551
703
|
} else {
|
|
552
704
|
const answer = await this.llm.generate(prompt, systemInst);
|
|
553
705
|
if (this.history && sessionId) {
|
|
@@ -561,6 +713,44 @@ class VectraClient {
|
|
|
561
713
|
}
|
|
562
714
|
const genMs = Date.now() - tGen;
|
|
563
715
|
this.trigger('onGenerationEnd', answer, genMs);
|
|
716
|
+
|
|
717
|
+
const promptChars = prompt.length;
|
|
718
|
+
const answerChars = answer ? String(answer).length : 0;
|
|
719
|
+
|
|
720
|
+
this.logger.logTrace({
|
|
721
|
+
traceId,
|
|
722
|
+
spanId: uuidv4(),
|
|
723
|
+
parentSpanId: rootSpanId,
|
|
724
|
+
name: 'generation',
|
|
725
|
+
startTime: tGen,
|
|
726
|
+
endTime: Date.now(),
|
|
727
|
+
input: { prompt },
|
|
728
|
+
output: { answer: String(answer).substring(0, 1000) }, // Truncate for log
|
|
729
|
+
attributes: { prompt_chars: promptChars, completion_chars: answerChars },
|
|
730
|
+
provider,
|
|
731
|
+
modelName
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
this.logger.logMetric({ name: 'prompt_chars', value: promptChars });
|
|
735
|
+
this.logger.logMetric({ name: 'completion_chars', value: answerChars });
|
|
736
|
+
|
|
737
|
+
this.logger.logTrace({
|
|
738
|
+
traceId,
|
|
739
|
+
spanId: rootSpanId,
|
|
740
|
+
name: 'queryRAG',
|
|
741
|
+
startTime: tStart,
|
|
742
|
+
endTime: Date.now(),
|
|
743
|
+
input: { query, sessionId },
|
|
744
|
+
output: { success: true },
|
|
745
|
+
attributes: { retrievalMs, genMs, docCount: docs.length },
|
|
746
|
+
provider,
|
|
747
|
+
modelName
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
this.logger.logMetric({ name: 'query_latency', value: Date.now() - tStart, tags: { type: 'total' } });
|
|
751
|
+
this.logger.logMetric({ name: 'retrieval_latency', value: retrievalMs, tags: { type: 'retrieval' } });
|
|
752
|
+
this.logger.logMetric({ name: 'generation_latency', value: genMs, tags: { type: 'generation' } });
|
|
753
|
+
|
|
564
754
|
if (this.config.generation && this.config.generation.outputFormat === 'json') {
|
|
565
755
|
try { const parsed = JSON.parse(String(answer)); return { answer: parsed, sources: docs.map(d => d.metadata) }; } catch { return { answer, sources: docs.map(d => d.metadata) }; }
|
|
566
756
|
}
|
|
@@ -568,6 +758,18 @@ class VectraClient {
|
|
|
568
758
|
}
|
|
569
759
|
} catch (e) {
|
|
570
760
|
this.trigger('onError', e);
|
|
761
|
+
this.logger.logTrace({
|
|
762
|
+
traceId,
|
|
763
|
+
spanId: rootSpanId,
|
|
764
|
+
name: 'queryRAG',
|
|
765
|
+
startTime: tStart,
|
|
766
|
+
endTime: Date.now(),
|
|
767
|
+
input: { query, sessionId },
|
|
768
|
+
error: { message: e.message, stack: e.stack },
|
|
769
|
+
status: 'error',
|
|
770
|
+
provider,
|
|
771
|
+
modelName
|
|
772
|
+
});
|
|
571
773
|
throw e;
|
|
572
774
|
}
|
|
573
775
|
}
|