@appium/mcp-documentation 1.0.0
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/CHANGELOG.md +0 -0
- package/LICENSE +201 -0
- package/README.md +126 -0
- package/dist/answer-appium.d.ts +8 -0
- package/dist/answer-appium.d.ts.map +1 -0
- package/dist/answer-appium.js +38 -0
- package/dist/answer-appium.js.map +1 -0
- package/dist/appium-skills.d.ts +5 -0
- package/dist/appium-skills.d.ts.map +1 -0
- package/dist/appium-skills.js +168 -0
- package/dist/appium-skills.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +5 -0
- package/dist/logger.js.map +1 -0
- package/dist/markdown-header-splitter.d.ts +32 -0
- package/dist/markdown-header-splitter.d.ts.map +1 -0
- package/dist/markdown-header-splitter.js +180 -0
- package/dist/markdown-header-splitter.js.map +1 -0
- package/dist/paths.d.ts +2 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +22 -0
- package/dist/paths.js.map +1 -0
- package/dist/plugin.d.ts +19 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +18 -0
- package/dist/plugin.js.map +1 -0
- package/dist/reasoning-rag.d.ts +89 -0
- package/dist/reasoning-rag.d.ts.map +1 -0
- package/dist/reasoning-rag.js +282 -0
- package/dist/reasoning-rag.js.map +1 -0
- package/dist/scripts/eval-documentation-rag.d.ts +50 -0
- package/dist/scripts/eval-documentation-rag.d.ts.map +1 -0
- package/dist/scripts/eval-documentation-rag.js +287 -0
- package/dist/scripts/eval-documentation-rag.js.map +1 -0
- package/dist/scripts/generate-embeddings-cache.d.ts +13 -0
- package/dist/scripts/generate-embeddings-cache.d.ts.map +1 -0
- package/dist/scripts/generate-embeddings-cache.js +24 -0
- package/dist/scripts/generate-embeddings-cache.js.map +1 -0
- package/dist/scripts/rag-eval-dataset.json +516 -0
- package/dist/scripts/simple-index-documentation.d.ts +21 -0
- package/dist/scripts/simple-index-documentation.d.ts.map +1 -0
- package/dist/scripts/simple-index-documentation.js +77 -0
- package/dist/scripts/simple-index-documentation.js.map +1 -0
- package/dist/scripts/simple-query-documentation.d.ts +13 -0
- package/dist/scripts/simple-query-documentation.d.ts.map +1 -0
- package/dist/scripts/simple-query-documentation.js +52 -0
- package/dist/scripts/simple-query-documentation.js.map +1 -0
- package/dist/sentence-transformers-embeddings.d.ts +40 -0
- package/dist/sentence-transformers-embeddings.d.ts.map +1 -0
- package/dist/sentence-transformers-embeddings.js +119 -0
- package/dist/sentence-transformers-embeddings.js.map +1 -0
- package/dist/simple-pdf-indexer.d.ts +47 -0
- package/dist/simple-pdf-indexer.d.ts.map +1 -0
- package/dist/simple-pdf-indexer.js +572 -0
- package/dist/simple-pdf-indexer.js.map +1 -0
- package/dist/tests/__mocks__/@appium/support.d.ts +92 -0
- package/dist/tests/__mocks__/@appium/support.d.ts.map +1 -0
- package/dist/tests/__mocks__/@appium/support.js +66 -0
- package/dist/tests/__mocks__/@appium/support.js.map +1 -0
- package/dist/tests/appium-skills.test.d.ts +2 -0
- package/dist/tests/appium-skills.test.d.ts.map +1 -0
- package/dist/tests/appium-skills.test.js +26 -0
- package/dist/tests/appium-skills.test.js.map +1 -0
- package/dist/tests/plugin.test.d.ts +2 -0
- package/dist/tests/plugin.test.d.ts.map +1 -0
- package/dist/tests/plugin.test.js +18 -0
- package/dist/tests/plugin.test.js.map +1 -0
- package/dist/tests/simple-pdf-indexer.test.d.ts +2 -0
- package/dist/tests/simple-pdf-indexer.test.d.ts.map +1 -0
- package/dist/tests/simple-pdf-indexer.test.js +37 -0
- package/dist/tests/simple-pdf-indexer.test.js.map +1 -0
- package/dist/tool-response.d.ts +4 -0
- package/dist/tool-response.d.ts.map +1 -0
- package/dist/tool-response.js +12 -0
- package/dist/tool-response.js.map +1 -0
- package/dist/tools.d.ts +3 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +3 -0
- package/dist/tools.js.map +1 -0
- package/dist/uploads/documents.json +1 -0
- package/package.json +84 -0
- package/scripts/zip-assets.mjs +75 -0
- package/src/resources/submodules.zip +0 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reasoning-Enhanced RAG System
|
|
3
|
+
*
|
|
4
|
+
* This module enhances the existing RAG system by adding reasoning capabilities
|
|
5
|
+
* using Xenova transformers during the document retrieval process.
|
|
6
|
+
* It can perform summarization, question-answering, and analysis on retrieved chunks.
|
|
7
|
+
*/
|
|
8
|
+
import { queryVectorStore } from './simple-pdf-indexer.js';
|
|
9
|
+
import log from './logger.js';
|
|
10
|
+
/**
|
|
11
|
+
* Reasoning-enhanced RAG processor
|
|
12
|
+
*/
|
|
13
|
+
export class ReasoningRAG {
|
|
14
|
+
transformers = null;
|
|
15
|
+
models = new Map();
|
|
16
|
+
isInitialized = false;
|
|
17
|
+
constructor() {
|
|
18
|
+
void this.initializeTransformers();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Enhanced RAG query with reasoning capabilities
|
|
22
|
+
*/
|
|
23
|
+
async queryWithReasoning(query, options = {}) {
|
|
24
|
+
const { topK = 50, reasoningTasks = ['summarization', 'question-answering'], customConfigs, } = options;
|
|
25
|
+
try {
|
|
26
|
+
log.info(`Starting reasoning-enhanced RAG query: "${query}"`);
|
|
27
|
+
// Step 1: Retrieve relevant chunks using existing RAG
|
|
28
|
+
log.info(`Retrieving top ${topK} relevant chunks...`);
|
|
29
|
+
const retrievedChunks = await queryVectorStore(query, topK);
|
|
30
|
+
if (!retrievedChunks || retrievedChunks.length === 0) {
|
|
31
|
+
return {
|
|
32
|
+
query,
|
|
33
|
+
retrievedChunks: [],
|
|
34
|
+
reasoningResults: [],
|
|
35
|
+
summary: 'No relevant information found in the documentation.',
|
|
36
|
+
answer: 'No relevant information found to answer your query.',
|
|
37
|
+
sources: [],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
log.info(`Retrieved ${retrievedChunks.length} chunks for reasoning`);
|
|
41
|
+
// Step 2: Configure reasoning models
|
|
42
|
+
const configs = customConfigs || [
|
|
43
|
+
// Summarization using T5
|
|
44
|
+
{
|
|
45
|
+
task: 'summarization',
|
|
46
|
+
modelName: 'Xenova/t5-small',
|
|
47
|
+
maxLength: 150,
|
|
48
|
+
minLength: 30,
|
|
49
|
+
},
|
|
50
|
+
// Question answering using DistilBERT
|
|
51
|
+
{
|
|
52
|
+
task: 'question-answering',
|
|
53
|
+
modelName: 'Xenova/distilbert-base-cased-distilled-squad',
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
// Filter configs based on requested tasks
|
|
57
|
+
const filteredConfigs = configs.filter((config) => reasoningTasks.includes(config.task));
|
|
58
|
+
// Step 3: Perform reasoning on retrieved chunks
|
|
59
|
+
log.info(`Performing reasoning with ${filteredConfigs.length} different models...`);
|
|
60
|
+
const reasoningResults = await this.processChunksWithReasoning(retrievedChunks, filteredConfigs, query);
|
|
61
|
+
// Step 4: Generate comprehensive summary
|
|
62
|
+
log.info('Generating comprehensive summary...');
|
|
63
|
+
const summary = await this.generateComprehensiveSummary(reasoningResults, query);
|
|
64
|
+
// Step 5: Extract best answer from reasoning results
|
|
65
|
+
const qaResults = reasoningResults.filter((result) => result.metadata.task === 'question-answering' &&
|
|
66
|
+
!result.metadata.error);
|
|
67
|
+
const bestAnswer = qaResults.length > 0
|
|
68
|
+
? qaResults.sort((a, b) => (b.confidence || 0) - (a.confidence || 0))[0].reasoningOutput
|
|
69
|
+
: summary;
|
|
70
|
+
// Step 6: Extract sources
|
|
71
|
+
const sources = retrievedChunks
|
|
72
|
+
.map((doc) => doc.metadata?.relativePath ||
|
|
73
|
+
doc.metadata?.filename ||
|
|
74
|
+
doc.metadata?.source)
|
|
75
|
+
.filter((source, index, arr) => source && arr.indexOf(source) === index);
|
|
76
|
+
log.info(`Reasoning-enhanced RAG completed. Generated ${reasoningResults.length} reasoning results from ${sources.length} sources`);
|
|
77
|
+
return {
|
|
78
|
+
query,
|
|
79
|
+
retrievedChunks,
|
|
80
|
+
reasoningResults,
|
|
81
|
+
summary,
|
|
82
|
+
answer: bestAnswer,
|
|
83
|
+
sources,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
log.error('Error in reasoning-enhanced RAG:', error);
|
|
88
|
+
throw new Error(`Reasoning-enhanced RAG failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get available reasoning models and their capabilities
|
|
93
|
+
*/
|
|
94
|
+
getAvailableModels() {
|
|
95
|
+
return {
|
|
96
|
+
summarization: [
|
|
97
|
+
'Xenova/t5-small',
|
|
98
|
+
'Xenova/t5-base',
|
|
99
|
+
'Xenova/bart-large-cnn',
|
|
100
|
+
],
|
|
101
|
+
'question-answering': [
|
|
102
|
+
'Xenova/distilbert-base-cased-distilled-squad',
|
|
103
|
+
'Xenova/roberta-base-squad2',
|
|
104
|
+
],
|
|
105
|
+
analysis: ['Xenova/gpt2', 'Xenova/distilgpt2'],
|
|
106
|
+
classification: [
|
|
107
|
+
'Xenova/distilbert-base-uncased-finetuned-sst-2-english',
|
|
108
|
+
'Xenova/bert-base-uncased',
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Clean up resources
|
|
114
|
+
*/
|
|
115
|
+
async cleanup() {
|
|
116
|
+
this.models.clear();
|
|
117
|
+
log.info('Reasoning RAG resources cleaned up');
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Initialize the transformers library dynamically
|
|
121
|
+
*/
|
|
122
|
+
async initializeTransformers() {
|
|
123
|
+
if (this.transformers) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
// Use eval to avoid CommonJS/ESM conflict during compilation
|
|
128
|
+
const importTransformers = new Function('return import("@xenova/transformers")');
|
|
129
|
+
this.transformers = await importTransformers();
|
|
130
|
+
this.isInitialized = true;
|
|
131
|
+
log.info('Xenova transformers initialized for reasoning');
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
log.error('Error importing @xenova/transformers:', error);
|
|
135
|
+
throw new Error(`Failed to import @xenova/transformers: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get or create a model pipeline for a specific task
|
|
140
|
+
*/
|
|
141
|
+
async getModel(config) {
|
|
142
|
+
const modelKey = `${config.task}-${config.modelName}`;
|
|
143
|
+
if (this.models.has(modelKey)) {
|
|
144
|
+
return this.models.get(modelKey);
|
|
145
|
+
}
|
|
146
|
+
await this.initializeTransformers();
|
|
147
|
+
log.info(`Loading model for ${config.task}: ${config.modelName}`);
|
|
148
|
+
try {
|
|
149
|
+
const model = await this.transformers.pipeline(config.task, config.modelName);
|
|
150
|
+
this.models.set(modelKey, model);
|
|
151
|
+
log.info(`Successfully loaded model: ${config.modelName}`);
|
|
152
|
+
return model;
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
log.error(`Error loading model ${config.modelName}:`, error);
|
|
156
|
+
throw new Error(`Failed to load model: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Perform reasoning on a text chunk
|
|
161
|
+
*/
|
|
162
|
+
async performReasoning(text, config, query) {
|
|
163
|
+
const model = await this.getModel(config);
|
|
164
|
+
try {
|
|
165
|
+
let reasoningOutput;
|
|
166
|
+
let confidence;
|
|
167
|
+
switch (config.task) {
|
|
168
|
+
case 'summarization':
|
|
169
|
+
const summaryResult = await model(text, {
|
|
170
|
+
max_length: config.maxLength || 150,
|
|
171
|
+
min_length: config.minLength || 30,
|
|
172
|
+
do_sample: false,
|
|
173
|
+
});
|
|
174
|
+
reasoningOutput = summaryResult[0].summary_text;
|
|
175
|
+
confidence = summaryResult[0].score;
|
|
176
|
+
break;
|
|
177
|
+
case 'question-answering':
|
|
178
|
+
if (!query) {
|
|
179
|
+
throw new Error('Query is required for question-answering task');
|
|
180
|
+
}
|
|
181
|
+
const qaResult = await model({
|
|
182
|
+
question: query,
|
|
183
|
+
context: text,
|
|
184
|
+
});
|
|
185
|
+
reasoningOutput = qaResult.answer;
|
|
186
|
+
confidence = qaResult.score;
|
|
187
|
+
break;
|
|
188
|
+
case 'analysis':
|
|
189
|
+
// For analysis, we can use a text generation model
|
|
190
|
+
const analysisResult = await model(`Analyze the following text and provide key insights:\n\n${text}\n\nAnalysis:`, {
|
|
191
|
+
max_length: config.maxLength || 200,
|
|
192
|
+
temperature: 0.7,
|
|
193
|
+
do_sample: true,
|
|
194
|
+
});
|
|
195
|
+
reasoningOutput =
|
|
196
|
+
analysisResult[0].generated_text.split('Analysis:')[1]?.trim() ||
|
|
197
|
+
'No analysis generated';
|
|
198
|
+
break;
|
|
199
|
+
case 'classification':
|
|
200
|
+
// For classification, we can use a classification model
|
|
201
|
+
const classResult = await model(text);
|
|
202
|
+
reasoningOutput = `Classification: ${classResult[0].label} (confidence: ${classResult[0].score.toFixed(3)})`;
|
|
203
|
+
confidence = classResult[0].score;
|
|
204
|
+
break;
|
|
205
|
+
default:
|
|
206
|
+
throw new Error(`Unsupported reasoning task: ${config.task}`);
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
originalChunk: text,
|
|
210
|
+
reasoningOutput,
|
|
211
|
+
confidence,
|
|
212
|
+
metadata: {
|
|
213
|
+
task: config.task,
|
|
214
|
+
model: config.modelName,
|
|
215
|
+
timestamp: new Date().toISOString(),
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
log.error(`Error performing reasoning with ${config.task}:`, error);
|
|
221
|
+
return {
|
|
222
|
+
originalChunk: text,
|
|
223
|
+
reasoningOutput: `Error during reasoning: ${error instanceof Error ? error.message : String(error)}`,
|
|
224
|
+
metadata: {
|
|
225
|
+
task: config.task,
|
|
226
|
+
model: config.modelName,
|
|
227
|
+
error: true,
|
|
228
|
+
timestamp: new Date().toISOString(),
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Process multiple chunks with reasoning in parallel
|
|
235
|
+
*/
|
|
236
|
+
async processChunksWithReasoning(chunks, configs, query) {
|
|
237
|
+
const results = [];
|
|
238
|
+
// Process chunks in batches to avoid overwhelming the system
|
|
239
|
+
const batchSize = 5;
|
|
240
|
+
for (let i = 0; i < chunks.length; i += batchSize) {
|
|
241
|
+
const batch = chunks.slice(i, i + batchSize);
|
|
242
|
+
const batchPromises = batch.flatMap((chunk) => configs.map((config) => this.performReasoning(chunk.pageContent, config, query)));
|
|
243
|
+
const batchResults = await Promise.all(batchPromises);
|
|
244
|
+
results.push(...batchResults);
|
|
245
|
+
// Log progress for large batches
|
|
246
|
+
if (chunks.length > batchSize) {
|
|
247
|
+
log.info(`Processed reasoning for ${Math.min(i + batchSize, chunks.length)}/${chunks.length} chunks`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return results;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Generate a comprehensive summary from reasoning results
|
|
254
|
+
*/
|
|
255
|
+
async generateComprehensiveSummary(reasoningResults, query) {
|
|
256
|
+
// Extract all reasoning outputs
|
|
257
|
+
const summaries = reasoningResults
|
|
258
|
+
.filter((result) => result.metadata.task === 'summarization')
|
|
259
|
+
.map((result) => result.reasoningOutput);
|
|
260
|
+
const analyses = reasoningResults
|
|
261
|
+
.filter((result) => result.metadata.task === 'analysis')
|
|
262
|
+
.map((result) => result.reasoningOutput);
|
|
263
|
+
const qaResults = reasoningResults
|
|
264
|
+
.filter((result) => result.metadata.task === 'question-answering')
|
|
265
|
+
.map((result) => result.reasoningOutput);
|
|
266
|
+
// Combine all insights
|
|
267
|
+
let comprehensiveSummary = `## Query: ${query}\n\n`;
|
|
268
|
+
if (summaries.length > 0) {
|
|
269
|
+
comprehensiveSummary += `### Key Summaries:\n${summaries.map((s, i) => `${i + 1}. ${s}`).join('\n')}\n\n`;
|
|
270
|
+
}
|
|
271
|
+
if (analyses.length > 0) {
|
|
272
|
+
comprehensiveSummary += `### Analysis Insights:\n${analyses.map((a, i) => `${i + 1}. ${a}`).join('\n')}\n\n`;
|
|
273
|
+
}
|
|
274
|
+
if (qaResults.length > 0) {
|
|
275
|
+
comprehensiveSummary += `### Direct Answers:\n${qaResults.map((qa, i) => `${i + 1}. ${qa}`).join('\n')}\n\n`;
|
|
276
|
+
}
|
|
277
|
+
return comprehensiveSummary;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Export a singleton instance
|
|
281
|
+
export const reasoningRAG = new ReasoningRAG();
|
|
282
|
+
//# sourceMappingURL=reasoning-rag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reasoning-rag.js","sourceRoot":"","sources":["../src/reasoning-rag.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Answer-grounded RAG eval for the Appium documentation tool.
|
|
3
|
+
*
|
|
4
|
+
* Runs the documentation_query retrieval pipeline against a fixed set of
|
|
5
|
+
* realistic queries and asks the only question that matters downstream:
|
|
6
|
+
* "did the answer text actually land in the chunks an LLM would see?"
|
|
7
|
+
*
|
|
8
|
+
* What we measure:
|
|
9
|
+
*
|
|
10
|
+
* 1. answerSpanRecall@K
|
|
11
|
+
* For each query, the dataset declares short verbatim phrases lifted
|
|
12
|
+
* from the docs (`answerSpans`). We concatenate the top-K retrieved
|
|
13
|
+
* chunks and check what fraction of the spans appears in that text.
|
|
14
|
+
* "anyOf" semantics: a query that finds at least one span counts as a
|
|
15
|
+
* hit. Spans are 30-140 chars and chosen so any reasonable chunk
|
|
16
|
+
* containing the answer will include them, regardless of chunk
|
|
17
|
+
* boundaries -- so the metric is splitter-neutral.
|
|
18
|
+
*
|
|
19
|
+
* 2. hit@{1,3,5,10}
|
|
20
|
+
* Did any chunk at rank <= K carry any answerSpan? Direct measure of
|
|
21
|
+
* "does the LLM see the answer" at different context budgets.
|
|
22
|
+
*
|
|
23
|
+
* 3. MRR
|
|
24
|
+
* Mean reciprocal rank of the *first* chunk that carries an answerSpan.
|
|
25
|
+
* MRR-equivalent on content, not on file paths -- a chunk from the
|
|
26
|
+
* right file but wrong section is worth nothing here.
|
|
27
|
+
*
|
|
28
|
+
* 4. contextEfficiency
|
|
29
|
+
* For queries we hit, 1000 * spansCovered / totalChars(topK). Spans-per-
|
|
30
|
+
* kchar density. Low = lots of noise around the answer.
|
|
31
|
+
*
|
|
32
|
+
* 5. fileRecall@{5,10} (diagnostic only)
|
|
33
|
+
* Did the right *file* appear in top-K? Kept so we can spot the
|
|
34
|
+
* "right-file wrong-chunk" failure mode (right file present but no
|
|
35
|
+
* answerSpan landed).
|
|
36
|
+
*
|
|
37
|
+
* Match semantics: lowercase + collapse whitespace, then substring check.
|
|
38
|
+
*
|
|
39
|
+
* Usage (after `npm run build`):
|
|
40
|
+
* node dist/scripts/eval-documentation-rag.js \
|
|
41
|
+
* [--top-k=10] [--label=NAME] [--quiet] [--no-save]
|
|
42
|
+
*
|
|
43
|
+
* --top-k=N number of chunks to retrieve & evaluate (default 10)
|
|
44
|
+
* --label=N label written into the saved run, useful for comparing
|
|
45
|
+
* index variants (e.g. --label=before, --label=after)
|
|
46
|
+
* --quiet suppress the per-query log lines and table
|
|
47
|
+
* --no-save don't persist results JSON to disk
|
|
48
|
+
*/
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=eval-documentation-rag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-documentation-rag.d.ts","sourceRoot":"","sources":["../../src/scripts/eval-documentation-rag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG"}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Answer-grounded RAG eval for the Appium documentation tool.
|
|
3
|
+
*
|
|
4
|
+
* Runs the documentation_query retrieval pipeline against a fixed set of
|
|
5
|
+
* realistic queries and asks the only question that matters downstream:
|
|
6
|
+
* "did the answer text actually land in the chunks an LLM would see?"
|
|
7
|
+
*
|
|
8
|
+
* What we measure:
|
|
9
|
+
*
|
|
10
|
+
* 1. answerSpanRecall@K
|
|
11
|
+
* For each query, the dataset declares short verbatim phrases lifted
|
|
12
|
+
* from the docs (`answerSpans`). We concatenate the top-K retrieved
|
|
13
|
+
* chunks and check what fraction of the spans appears in that text.
|
|
14
|
+
* "anyOf" semantics: a query that finds at least one span counts as a
|
|
15
|
+
* hit. Spans are 30-140 chars and chosen so any reasonable chunk
|
|
16
|
+
* containing the answer will include them, regardless of chunk
|
|
17
|
+
* boundaries -- so the metric is splitter-neutral.
|
|
18
|
+
*
|
|
19
|
+
* 2. hit@{1,3,5,10}
|
|
20
|
+
* Did any chunk at rank <= K carry any answerSpan? Direct measure of
|
|
21
|
+
* "does the LLM see the answer" at different context budgets.
|
|
22
|
+
*
|
|
23
|
+
* 3. MRR
|
|
24
|
+
* Mean reciprocal rank of the *first* chunk that carries an answerSpan.
|
|
25
|
+
* MRR-equivalent on content, not on file paths -- a chunk from the
|
|
26
|
+
* right file but wrong section is worth nothing here.
|
|
27
|
+
*
|
|
28
|
+
* 4. contextEfficiency
|
|
29
|
+
* For queries we hit, 1000 * spansCovered / totalChars(topK). Spans-per-
|
|
30
|
+
* kchar density. Low = lots of noise around the answer.
|
|
31
|
+
*
|
|
32
|
+
* 5. fileRecall@{5,10} (diagnostic only)
|
|
33
|
+
* Did the right *file* appear in top-K? Kept so we can spot the
|
|
34
|
+
* "right-file wrong-chunk" failure mode (right file present but no
|
|
35
|
+
* answerSpan landed).
|
|
36
|
+
*
|
|
37
|
+
* Match semantics: lowercase + collapse whitespace, then substring check.
|
|
38
|
+
*
|
|
39
|
+
* Usage (after `npm run build`):
|
|
40
|
+
* node dist/scripts/eval-documentation-rag.js \
|
|
41
|
+
* [--top-k=10] [--label=NAME] [--quiet] [--no-save]
|
|
42
|
+
*
|
|
43
|
+
* --top-k=N number of chunks to retrieve & evaluate (default 10)
|
|
44
|
+
* --label=N label written into the saved run, useful for comparing
|
|
45
|
+
* index variants (e.g. --label=before, --label=after)
|
|
46
|
+
* --quiet suppress the per-query log lines and table
|
|
47
|
+
* --no-save don't persist results JSON to disk
|
|
48
|
+
*/
|
|
49
|
+
import * as fs from 'node:fs';
|
|
50
|
+
import * as path from 'node:path';
|
|
51
|
+
import { fileURLToPath } from 'node:url';
|
|
52
|
+
import { queryVectorStore } from '../simple-pdf-indexer.js';
|
|
53
|
+
// -- arg parsing ----------------------------------------------------------
|
|
54
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
55
|
+
const __dirname = path.dirname(__filename);
|
|
56
|
+
const args = process.argv.slice(2);
|
|
57
|
+
const flagSet = new Set(args);
|
|
58
|
+
const QUIET = flagSet.has('--quiet');
|
|
59
|
+
const NO_SAVE = flagSet.has('--no-save');
|
|
60
|
+
function flagValue(name, dflt) {
|
|
61
|
+
const a = args.find((x) => x.startsWith(`${name}=`));
|
|
62
|
+
return a ? a.split('=').slice(1).join('=') : dflt;
|
|
63
|
+
}
|
|
64
|
+
const TOP_K = Number(flagValue('--top-k', '10'));
|
|
65
|
+
const LABEL = flagValue('--label', 'default');
|
|
66
|
+
// -- paths ----------------------------------------------------------------
|
|
67
|
+
function resolveDatasetPath() {
|
|
68
|
+
const candidates = [
|
|
69
|
+
path.resolve(__dirname, 'rag-eval-dataset.json'),
|
|
70
|
+
path.resolve(__dirname, '../../src/scripts/rag-eval-dataset.json'),
|
|
71
|
+
];
|
|
72
|
+
for (const p of candidates) {
|
|
73
|
+
if (fs.existsSync(p)) {
|
|
74
|
+
return p;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
throw new Error(`rag-eval-dataset.json not found in: ${candidates.join(', ')}`);
|
|
78
|
+
}
|
|
79
|
+
function resolveResultsDir() {
|
|
80
|
+
const dir = path.resolve(__dirname, '../../src/scripts/eval-results');
|
|
81
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
82
|
+
return dir;
|
|
83
|
+
}
|
|
84
|
+
// -- matching helpers -----------------------------------------------------
|
|
85
|
+
function normalize(s) {
|
|
86
|
+
return s.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
87
|
+
}
|
|
88
|
+
function chunkContainsSpan(chunkText, span) {
|
|
89
|
+
return normalize(chunkText).includes(normalize(span));
|
|
90
|
+
}
|
|
91
|
+
function endsWithExpected(retrievedRelPath, expected) {
|
|
92
|
+
return retrievedRelPath === expected || retrievedRelPath.endsWith(expected);
|
|
93
|
+
}
|
|
94
|
+
// -- per-query evaluation -------------------------------------------------
|
|
95
|
+
function evaluateQuery(q, chunks) {
|
|
96
|
+
const hitRanks = [];
|
|
97
|
+
const spansCovered = new Set();
|
|
98
|
+
for (const chunk of chunks) {
|
|
99
|
+
let chunkHadHit = false;
|
|
100
|
+
for (const span of q.answerSpans) {
|
|
101
|
+
if (chunkContainsSpan(chunk.text, span)) {
|
|
102
|
+
spansCovered.add(span);
|
|
103
|
+
chunkHadHit = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (chunkHadHit) {
|
|
107
|
+
hitRanks.push(chunk.rank);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const firstHitRank = hitRanks.length > 0 ? hitRanks[0] : null;
|
|
111
|
+
const spansMissing = q.answerSpans.filter((s) => !spansCovered.has(s));
|
|
112
|
+
return {
|
|
113
|
+
hitRanks,
|
|
114
|
+
firstHitRank,
|
|
115
|
+
spansCovered: [...spansCovered],
|
|
116
|
+
spansMissing,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// -- aggregation ----------------------------------------------------------
|
|
120
|
+
function aggregate(results) {
|
|
121
|
+
if (results.length === 0) {
|
|
122
|
+
return {
|
|
123
|
+
count: 0,
|
|
124
|
+
answerSpanRecall: 0,
|
|
125
|
+
hitAnyAt1: 0,
|
|
126
|
+
hitAnyAt3: 0,
|
|
127
|
+
hitAnyAt5: 0,
|
|
128
|
+
hitAnyAt10: 0,
|
|
129
|
+
mrr: 0,
|
|
130
|
+
contextEfficiency: 0,
|
|
131
|
+
fileRecallAt5: 0,
|
|
132
|
+
fileRecallAt10: 0,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const n = results.length;
|
|
136
|
+
const mean = (xs) => xs.reduce((a, b) => a + b, 0) / xs.length;
|
|
137
|
+
const hitResults = results.filter((r) => r.hitAnyAt10 === 1);
|
|
138
|
+
return {
|
|
139
|
+
count: n,
|
|
140
|
+
answerSpanRecall: mean(results.map((r) => r.answerSpanRecall)),
|
|
141
|
+
hitAnyAt1: mean(results.map((r) => r.hitAnyAt1)),
|
|
142
|
+
hitAnyAt3: mean(results.map((r) => r.hitAnyAt3)),
|
|
143
|
+
hitAnyAt5: mean(results.map((r) => r.hitAnyAt5)),
|
|
144
|
+
hitAnyAt10: mean(results.map((r) => r.hitAnyAt10)),
|
|
145
|
+
mrr: mean(results.map((r) => r.reciprocalRank)),
|
|
146
|
+
contextEfficiency: hitResults.length
|
|
147
|
+
? mean(hitResults.map((r) => r.contextEfficiency))
|
|
148
|
+
: 0,
|
|
149
|
+
fileRecallAt5: mean(results.map((r) => r.fileRecallAt5)),
|
|
150
|
+
fileRecallAt10: mean(results.map((r) => r.fileRecallAt10)),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function fmt(n, dp = 3) {
|
|
154
|
+
return n.toFixed(dp);
|
|
155
|
+
}
|
|
156
|
+
function printAggregate(label, m) {
|
|
157
|
+
const tag = `${label} (n=${m.count})`.padEnd(20);
|
|
158
|
+
console.log(`${tag} spanRecall=${fmt(m.answerSpanRecall)} hit@1=${fmt(m.hitAnyAt1)} hit@3=${fmt(m.hitAnyAt3)} hit@5=${fmt(m.hitAnyAt5)} hit@10=${fmt(m.hitAnyAt10)} MRR=${fmt(m.mrr)} ctxEff=${fmt(m.contextEfficiency, 2)} fileR@5=${fmt(m.fileRecallAt5)}`);
|
|
159
|
+
}
|
|
160
|
+
function printPerQueryTable(results) {
|
|
161
|
+
const header = 'id | diff | fhr | spans | hit@5 | unique | sources';
|
|
162
|
+
const sep = '-'.repeat(110);
|
|
163
|
+
console.log(sep);
|
|
164
|
+
console.log(header);
|
|
165
|
+
console.log(sep);
|
|
166
|
+
for (const r of results) {
|
|
167
|
+
const fhr = r.firstHitRank === null ? ' - ' : String(r.firstHitRank).padStart(3, ' ');
|
|
168
|
+
const spans = `${r.spansCovered.length}/${r.answerSpans.length}`;
|
|
169
|
+
const matched = r.retrievedSources[0]
|
|
170
|
+
? r.retrievedSources.slice(0, 2).join(', ')
|
|
171
|
+
: '(empty)';
|
|
172
|
+
console.log(`${r.id.padEnd(4)} | ${r.difficulty.padEnd(6)} | ${fhr} | ${spans.padEnd(6)} | ${String(r.hitAnyAt5).padEnd(5)} | ${String(r.uniqueFiles).padEnd(6)} | ${matched}`);
|
|
173
|
+
}
|
|
174
|
+
console.log(sep);
|
|
175
|
+
}
|
|
176
|
+
// -- main -----------------------------------------------------------------
|
|
177
|
+
async function runEval() {
|
|
178
|
+
const datasetPath = resolveDatasetPath();
|
|
179
|
+
const dataset = JSON.parse(fs.readFileSync(datasetPath, 'utf-8'));
|
|
180
|
+
console.log(`\n=== Appium RAG eval (answer-grounded) ===`);
|
|
181
|
+
console.log(`Dataset: ${datasetPath}`);
|
|
182
|
+
console.log(`Queries: ${dataset.queries.length} topK: ${TOP_K} label: ${LABEL}\n`);
|
|
183
|
+
const perQuery = [];
|
|
184
|
+
for (const q of dataset.queries) {
|
|
185
|
+
const docs = await queryVectorStore(q.query, TOP_K);
|
|
186
|
+
const chunks = docs.map((d, i) => ({
|
|
187
|
+
rank: i + 1,
|
|
188
|
+
text: d.pageContent,
|
|
189
|
+
source: d.metadata?.relativePath ??
|
|
190
|
+
d.metadata?.filename,
|
|
191
|
+
charCount: d.pageContent.length,
|
|
192
|
+
}));
|
|
193
|
+
const retrievedSources = chunks
|
|
194
|
+
.map((c) => c.source)
|
|
195
|
+
.filter((s) => !!s);
|
|
196
|
+
const topKChars = chunks.reduce((a, c) => a + c.charCount, 0);
|
|
197
|
+
const uniqueFiles = new Set(retrievedSources).size;
|
|
198
|
+
const { hitRanks, firstHitRank, spansCovered, spansMissing } = evaluateQuery(q, chunks);
|
|
199
|
+
const answerSpanRecall = q.answerSpans.length === 0
|
|
200
|
+
? 0
|
|
201
|
+
: spansCovered.length / q.answerSpans.length;
|
|
202
|
+
const hitAnyAt = (k) => hitRanks.some((r) => r <= k) ? 1 : 0;
|
|
203
|
+
const reciprocalRank = firstHitRank ? 1 / firstHitRank : 0;
|
|
204
|
+
const contextEfficiency = firstHitRank !== null && topKChars > 0
|
|
205
|
+
? (1000 * spansCovered.length) / topKChars
|
|
206
|
+
: 0;
|
|
207
|
+
const fileMatched = (k) => {
|
|
208
|
+
const top = retrievedSources.slice(0, k);
|
|
209
|
+
return top.some((rs) => q.expectedSources.some((es) => endsWithExpected(rs, es)))
|
|
210
|
+
? 1
|
|
211
|
+
: 0;
|
|
212
|
+
};
|
|
213
|
+
perQuery.push({
|
|
214
|
+
id: q.id,
|
|
215
|
+
query: q.query,
|
|
216
|
+
difficulty: q.difficulty,
|
|
217
|
+
category: q.category,
|
|
218
|
+
expectedSources: q.expectedSources,
|
|
219
|
+
answerSpans: q.answerSpans,
|
|
220
|
+
retrievedSources,
|
|
221
|
+
topKChunks: chunks.length,
|
|
222
|
+
topKChars,
|
|
223
|
+
uniqueFiles,
|
|
224
|
+
hitRanks,
|
|
225
|
+
firstHitRank,
|
|
226
|
+
spansCovered,
|
|
227
|
+
spansMissing,
|
|
228
|
+
answerSpanRecall,
|
|
229
|
+
hitAnyAt1: hitAnyAt(1),
|
|
230
|
+
hitAnyAt3: hitAnyAt(3),
|
|
231
|
+
hitAnyAt5: hitAnyAt(5),
|
|
232
|
+
hitAnyAt10: hitAnyAt(10),
|
|
233
|
+
reciprocalRank,
|
|
234
|
+
contextEfficiency,
|
|
235
|
+
fileRecallAt5: fileMatched(5),
|
|
236
|
+
fileRecallAt10: fileMatched(10),
|
|
237
|
+
});
|
|
238
|
+
if (!QUIET) {
|
|
239
|
+
const status = hitAnyAt(5) ? 'OK' : 'MISS';
|
|
240
|
+
console.log(`${status.padEnd(4)} ${q.id} spans=${spansCovered.length}/${q.answerSpans.length} fhr=${firstHitRank ?? '-'}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (!QUIET) {
|
|
244
|
+
printPerQueryTable(perQuery);
|
|
245
|
+
}
|
|
246
|
+
const overall = aggregate(perQuery);
|
|
247
|
+
const byDifficulty = {};
|
|
248
|
+
for (const d of ['easy', 'medium', 'vague']) {
|
|
249
|
+
byDifficulty[d] = aggregate(perQuery.filter((r) => r.difficulty === d));
|
|
250
|
+
}
|
|
251
|
+
console.log('');
|
|
252
|
+
printAggregate('overall', overall);
|
|
253
|
+
for (const d of ['easy', 'medium', 'vague']) {
|
|
254
|
+
printAggregate(d, byDifficulty[d]);
|
|
255
|
+
}
|
|
256
|
+
console.log('');
|
|
257
|
+
if (!NO_SAVE) {
|
|
258
|
+
const run = {
|
|
259
|
+
timestamp: new Date().toISOString(),
|
|
260
|
+
label: LABEL,
|
|
261
|
+
datasetVersion: dataset.version,
|
|
262
|
+
topK: TOP_K,
|
|
263
|
+
overall,
|
|
264
|
+
byDifficulty,
|
|
265
|
+
perQuery,
|
|
266
|
+
};
|
|
267
|
+
const dir = resolveResultsDir();
|
|
268
|
+
const stamp = run.timestamp.replace(/[:.]/g, '-');
|
|
269
|
+
const outPath = path.join(dir, `${LABEL}-${stamp}.json`);
|
|
270
|
+
const labelLatestPath = path.join(dir, `${LABEL}-latest.json`);
|
|
271
|
+
const latestPath = path.join(dir, 'latest.json');
|
|
272
|
+
fs.writeFileSync(outPath, JSON.stringify(run, null, 2));
|
|
273
|
+
fs.writeFileSync(labelLatestPath, JSON.stringify(run, null, 2));
|
|
274
|
+
fs.writeFileSync(latestPath, JSON.stringify(run, null, 2));
|
|
275
|
+
console.log(`Saved: ${path.relative(process.cwd(), outPath)}`);
|
|
276
|
+
console.log(` ${path.relative(process.cwd(), labelLatestPath)}`);
|
|
277
|
+
console.log(` ${path.relative(process.cwd(), latestPath)}\n`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
try {
|
|
281
|
+
await runEval();
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
console.error('Eval failed:', err);
|
|
285
|
+
process.exit(1);
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=eval-documentation-rag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-documentation-rag.js","sourceRoot":"","sources":["../../src/scripts/eval-documentation-rag.ts"],"names":[],"mappings":"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"}
|