retrieval-lens 0.1.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/README.md +87 -0
- package/dist/db/index.d.ts +63 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +222 -0
- package/dist/db/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +108 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/diff.d.ts +26 -0
- package/dist/tools/diff.d.ts.map +1 -0
- package/dist/tools/diff.js +71 -0
- package/dist/tools/diff.js.map +1 -0
- package/dist/tools/observe.d.ts +18 -0
- package/dist/tools/observe.d.ts.map +1 -0
- package/dist/tools/observe.js +24 -0
- package/dist/tools/observe.js.map +1 -0
- package/dist/tools/query.d.ts +24 -0
- package/dist/tools/query.d.ts.map +1 -0
- package/dist/tools/query.js +27 -0
- package/dist/tools/query.js.map +1 -0
- package/dist/tools/stats.d.ts +21 -0
- package/dist/tools/stats.d.ts.map +1 -0
- package/dist/tools/stats.js +73 -0
- package/dist/tools/stats.js.map +1 -0
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +32 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# retrieval-lens
|
|
2
|
+
|
|
3
|
+
> A black-box flight recorder for RAG retrieval inside MCP agents.
|
|
4
|
+
|
|
5
|
+
**retrieval-lens** is an MCP server that logs every retrieval step your RAG agent makes — what chunks were retrieved, their scores, sources, and rankings — so you can audit, replay, and diff retrieval runs after the fact.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx retrieval-lens
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## The Problem
|
|
14
|
+
|
|
15
|
+
When a RAG agent gives a wrong answer, you need to know: did retrieval fail, or did generation fail? Right now there's no easy way to answer that. Your observability tool shows you the LLM call. It doesn't show you which chunks the model saw before it answered, what scores they had, or how retrieval changed between yesterday and today.
|
|
16
|
+
|
|
17
|
+
retrieval-lens fixes that. Every retrieval run is logged. Nothing is hidden.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## MCP Tools
|
|
22
|
+
|
|
23
|
+
| Tool | What it does |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `retrieval_observe` | Log a retrieval run — query, chunks, scores, sources, rankings |
|
|
26
|
+
| `retrieval_query` | Replay what the model saw before a specific answer |
|
|
27
|
+
| `retrieval_diff` | Compare two retrieval runs — what changed, what score drifted |
|
|
28
|
+
| `retrieval_stats` | Aggregate score distributions, top sources, runs over time |
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Quickstart
|
|
33
|
+
|
|
34
|
+
Add to your MCP client config (Claude Desktop, Cursor, Windsurf):
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"retrieval-lens": {
|
|
40
|
+
"command": "npx",
|
|
41
|
+
"args": ["retrieval-lens"]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then call `retrieval_observe` after every retrieval step in your RAG pipeline:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
await mcp.call("retrieval_observe", {
|
|
51
|
+
run_id: crypto.randomUUID(),
|
|
52
|
+
query: "what is the refund policy?",
|
|
53
|
+
chunks: [
|
|
54
|
+
{ content: "Refunds are processed within 5 days...", score: 0.91, source: "policy.md", rank: 1 },
|
|
55
|
+
{ content: "Contact support for refund requests...", score: 0.74, source: "faq.md", rank: 2 }
|
|
56
|
+
],
|
|
57
|
+
pipeline_tag: "support-bot"
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Why not LangSmith / Langfuse?
|
|
64
|
+
|
|
65
|
+
Those are full observability platforms. retrieval-lens is surgical:
|
|
66
|
+
|
|
67
|
+
- **Local-first** — SQLite, zero signup, no data leaves your machine
|
|
68
|
+
- **MCP-native** — one config line, works in any MCP client
|
|
69
|
+
- **Retrieval-only** — focused on the layer where most RAG failures actually happen
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Status
|
|
74
|
+
|
|
75
|
+
🚧 Active development. Harness-first build using [harness engineering](https://walkinglabs.github.io/learn-harness-engineering/en/) principles.
|
|
76
|
+
|
|
77
|
+
- [x] F05 — scaffold
|
|
78
|
+
- [ ] F01 — `retrieval_observe`
|
|
79
|
+
- [ ] F02 — `retrieval_query`
|
|
80
|
+
- [ ] F03 — `retrieval_diff`
|
|
81
|
+
- [ ] F04 — `retrieval_stats`
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type Client } from "@libsql/client";
|
|
2
|
+
export interface ObservedChunkRecord {
|
|
3
|
+
content: string;
|
|
4
|
+
content_hash: string;
|
|
5
|
+
score: number;
|
|
6
|
+
source: string;
|
|
7
|
+
rank: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ObservedRunRecord {
|
|
10
|
+
run_id: string;
|
|
11
|
+
query: string;
|
|
12
|
+
pipeline_tag: string | null;
|
|
13
|
+
created_at: string;
|
|
14
|
+
chunks: ObservedChunkRecord[];
|
|
15
|
+
}
|
|
16
|
+
export interface QueryRunFilter {
|
|
17
|
+
run_id?: string | undefined;
|
|
18
|
+
pipeline_tag?: string | undefined;
|
|
19
|
+
since_iso?: string | undefined;
|
|
20
|
+
limit: number;
|
|
21
|
+
}
|
|
22
|
+
export interface RetrievedChunkRecord {
|
|
23
|
+
content: string;
|
|
24
|
+
score: number;
|
|
25
|
+
source: string;
|
|
26
|
+
rank: number;
|
|
27
|
+
}
|
|
28
|
+
export interface RetrievedRunRecord {
|
|
29
|
+
run_id: string;
|
|
30
|
+
query: string;
|
|
31
|
+
pipeline_tag: string | null;
|
|
32
|
+
created_at: string;
|
|
33
|
+
chunks: RetrievedChunkRecord[];
|
|
34
|
+
}
|
|
35
|
+
export interface StatsRunFilter {
|
|
36
|
+
pipeline_tag?: string | undefined;
|
|
37
|
+
since_iso?: string | undefined;
|
|
38
|
+
until_iso?: string | undefined;
|
|
39
|
+
}
|
|
40
|
+
export interface StatsChunkRecord {
|
|
41
|
+
score: number;
|
|
42
|
+
source: string;
|
|
43
|
+
rank: number;
|
|
44
|
+
}
|
|
45
|
+
export interface StatsRunRecord {
|
|
46
|
+
run_id: string;
|
|
47
|
+
created_at: string;
|
|
48
|
+
chunks: StatsChunkRecord[];
|
|
49
|
+
}
|
|
50
|
+
export interface DiffChunkRecord {
|
|
51
|
+
content: string;
|
|
52
|
+
content_hash: string;
|
|
53
|
+
score: number;
|
|
54
|
+
source: string;
|
|
55
|
+
rank: number;
|
|
56
|
+
}
|
|
57
|
+
export declare function getDb(): Promise<Client>;
|
|
58
|
+
export declare function insertObservedRun(run: ObservedRunRecord): Promise<boolean>;
|
|
59
|
+
export declare function findRetrievedRuns(filter: QueryRunFilter): Promise<RetrievedRunRecord[]>;
|
|
60
|
+
export declare function runExists(runId: string): Promise<boolean>;
|
|
61
|
+
export declare function findDiffChunks(runId: string): Promise<DiffChunkRecord[]>;
|
|
62
|
+
export declare function findStatsRuns(filter: StatsRunFilter): Promise<StatsRunRecord[]>;
|
|
63
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAS3D,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,mBAAmB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,oBAAoB,EAAE,CAAC;CAChC;AAGD,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AA0DD,wBAAsB,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAQ7C;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAgChF;AAkBD,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CA4D7F;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ/D;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAc9E;AAGD,wBAAsB,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAwDrF"}
|
package/dist/db/index.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { createClient } from "@libsql/client";
|
|
2
|
+
import { mkdir, readFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { homedir, tmpdir } from "node:os";
|
|
6
|
+
let db;
|
|
7
|
+
let initializing;
|
|
8
|
+
function defaultDbUrl() {
|
|
9
|
+
return `file:${join(homedir(), ".retrieval-lens", "audit.db")}`;
|
|
10
|
+
}
|
|
11
|
+
function configuredDbUrl() {
|
|
12
|
+
const configured = process.env.RETRIEVAL_LENS_DB;
|
|
13
|
+
if (configured === undefined || configured.length === 0) {
|
|
14
|
+
return defaultDbUrl();
|
|
15
|
+
}
|
|
16
|
+
if (configured === ":memory:") {
|
|
17
|
+
return `file:${join(tmpdir(), `retrieval-lens-${process.pid}.db`)}`;
|
|
18
|
+
}
|
|
19
|
+
if (configured.includes(":")) {
|
|
20
|
+
return configured;
|
|
21
|
+
}
|
|
22
|
+
return `file:${configured}`;
|
|
23
|
+
}
|
|
24
|
+
async function readSchema() {
|
|
25
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
26
|
+
const localSchemaPath = join(dirname(currentFile), "schema.sql");
|
|
27
|
+
try {
|
|
28
|
+
return await readFile(localSchemaPath, "utf8");
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
32
|
+
return readFile(join(process.cwd(), "src", "db", "schema.sql"), "utf8");
|
|
33
|
+
}
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function initializeDb() {
|
|
38
|
+
const url = configuredDbUrl();
|
|
39
|
+
if (url.startsWith("file:") && url !== "file::memory:") {
|
|
40
|
+
await mkdir(dirname(url.slice("file:".length)), { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
const client = createClient({ url });
|
|
43
|
+
const schema = await readSchema();
|
|
44
|
+
await client.migrate(schema
|
|
45
|
+
.split(";")
|
|
46
|
+
.map((statement) => statement.trim())
|
|
47
|
+
.filter((statement) => statement.length > 0));
|
|
48
|
+
return client;
|
|
49
|
+
}
|
|
50
|
+
export async function getDb() {
|
|
51
|
+
if (db !== undefined) {
|
|
52
|
+
return db;
|
|
53
|
+
}
|
|
54
|
+
initializing ??= initializeDb();
|
|
55
|
+
db = await initializing;
|
|
56
|
+
return db;
|
|
57
|
+
}
|
|
58
|
+
export async function insertObservedRun(run) {
|
|
59
|
+
const client = await getDb();
|
|
60
|
+
const transaction = await client.transaction("write");
|
|
61
|
+
let committed = false;
|
|
62
|
+
try {
|
|
63
|
+
const insertRun = await transaction.execute({
|
|
64
|
+
sql: "INSERT OR IGNORE INTO runs (run_id, query, pipeline_tag, created_at) VALUES (?, ?, ?, ?)",
|
|
65
|
+
args: [run.run_id, run.query, run.pipeline_tag, run.created_at],
|
|
66
|
+
});
|
|
67
|
+
if (insertRun.rowsAffected === 0) {
|
|
68
|
+
await transaction.commit();
|
|
69
|
+
committed = true;
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
for (const chunk of run.chunks) {
|
|
73
|
+
await transaction.execute({
|
|
74
|
+
sql: "INSERT INTO chunks (run_id, content, content_hash, score, source, rank) VALUES (?, ?, ?, ?, ?, ?)",
|
|
75
|
+
args: [run.run_id, chunk.content, chunk.content_hash, chunk.score, chunk.source, chunk.rank],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
await transaction.commit();
|
|
79
|
+
committed = true;
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
if (!committed) {
|
|
84
|
+
transaction.close();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function textValue(value) {
|
|
89
|
+
return typeof value === "string" ? value : String(value);
|
|
90
|
+
}
|
|
91
|
+
function nullableTextValue(value) {
|
|
92
|
+
if (value === null) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
return textValue(value);
|
|
96
|
+
}
|
|
97
|
+
function numericValue(value) {
|
|
98
|
+
return typeof value === "number" ? value : Number(value);
|
|
99
|
+
}
|
|
100
|
+
export async function findRetrievedRuns(filter) {
|
|
101
|
+
const client = await getDb();
|
|
102
|
+
const conditions = [];
|
|
103
|
+
const args = [];
|
|
104
|
+
const limit = filter.run_id === undefined ? filter.limit : 1;
|
|
105
|
+
if (filter.run_id !== undefined) {
|
|
106
|
+
conditions.push("run_id = ?");
|
|
107
|
+
args.push(filter.run_id);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
if (filter.pipeline_tag !== undefined) {
|
|
111
|
+
conditions.push("pipeline_tag = ?");
|
|
112
|
+
args.push(filter.pipeline_tag);
|
|
113
|
+
}
|
|
114
|
+
if (filter.since_iso !== undefined) {
|
|
115
|
+
conditions.push("created_at >= ?");
|
|
116
|
+
args.push(filter.since_iso);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const whereClause = conditions.length === 0 ? "" : `WHERE ${conditions.join(" AND ")}`;
|
|
120
|
+
const runResult = await client.execute({
|
|
121
|
+
sql: `SELECT run_id, query, pipeline_tag, created_at FROM runs ${whereClause} ORDER BY created_at DESC LIMIT ?`,
|
|
122
|
+
args: [...args, limit],
|
|
123
|
+
});
|
|
124
|
+
const runs = runResult.rows.map((row) => ({
|
|
125
|
+
run_id: textValue(row.run_id),
|
|
126
|
+
query: textValue(row.query),
|
|
127
|
+
pipeline_tag: nullableTextValue(row.pipeline_tag),
|
|
128
|
+
created_at: textValue(row.created_at),
|
|
129
|
+
chunks: [],
|
|
130
|
+
}));
|
|
131
|
+
if (runs.length === 0) {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
const chunksByRun = new Map(runs.map((run) => [run.run_id, run.chunks]));
|
|
135
|
+
const placeholders = runs.map(() => "?").join(", ");
|
|
136
|
+
const chunkResult = await client.execute({
|
|
137
|
+
sql: `SELECT run_id, content, score, source, rank FROM chunks WHERE run_id IN (${placeholders}) ORDER BY run_id, rank ASC`,
|
|
138
|
+
args: runs.map((run) => run.run_id),
|
|
139
|
+
});
|
|
140
|
+
for (const row of chunkResult.rows) {
|
|
141
|
+
const runChunks = chunksByRun.get(textValue(row.run_id));
|
|
142
|
+
if (runChunks !== undefined) {
|
|
143
|
+
runChunks.push({
|
|
144
|
+
content: textValue(row.content),
|
|
145
|
+
score: numericValue(row.score),
|
|
146
|
+
source: textValue(row.source),
|
|
147
|
+
rank: numericValue(row.rank),
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return runs;
|
|
152
|
+
}
|
|
153
|
+
export async function runExists(runId) {
|
|
154
|
+
const client = await getDb();
|
|
155
|
+
const result = await client.execute({
|
|
156
|
+
sql: "SELECT 1 FROM runs WHERE run_id = ? LIMIT 1",
|
|
157
|
+
args: [runId],
|
|
158
|
+
});
|
|
159
|
+
return result.rows.length > 0;
|
|
160
|
+
}
|
|
161
|
+
export async function findDiffChunks(runId) {
|
|
162
|
+
const client = await getDb();
|
|
163
|
+
const result = await client.execute({
|
|
164
|
+
sql: "SELECT content, content_hash, score, source, rank FROM chunks WHERE run_id = ? ORDER BY rank ASC",
|
|
165
|
+
args: [runId],
|
|
166
|
+
});
|
|
167
|
+
return result.rows.map((row) => ({
|
|
168
|
+
content: textValue(row.content),
|
|
169
|
+
content_hash: textValue(row.content_hash),
|
|
170
|
+
score: numericValue(row.score),
|
|
171
|
+
source: textValue(row.source),
|
|
172
|
+
rank: numericValue(row.rank),
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
export async function findStatsRuns(filter) {
|
|
176
|
+
const client = await getDb();
|
|
177
|
+
const conditions = [];
|
|
178
|
+
const args = [];
|
|
179
|
+
if (filter.pipeline_tag !== undefined) {
|
|
180
|
+
conditions.push("pipeline_tag = ?");
|
|
181
|
+
args.push(filter.pipeline_tag);
|
|
182
|
+
}
|
|
183
|
+
if (filter.since_iso !== undefined) {
|
|
184
|
+
conditions.push("created_at >= ?");
|
|
185
|
+
args.push(filter.since_iso);
|
|
186
|
+
}
|
|
187
|
+
if (filter.until_iso !== undefined) {
|
|
188
|
+
conditions.push("created_at <= ?");
|
|
189
|
+
args.push(filter.until_iso);
|
|
190
|
+
}
|
|
191
|
+
const whereClause = conditions.length === 0 ? "" : `WHERE ${conditions.join(" AND ")}`;
|
|
192
|
+
const runResult = await client.execute({
|
|
193
|
+
sql: `SELECT run_id, created_at FROM runs ${whereClause} ORDER BY created_at ASC`,
|
|
194
|
+
args,
|
|
195
|
+
});
|
|
196
|
+
const runs = runResult.rows.map((row) => ({
|
|
197
|
+
run_id: textValue(row.run_id),
|
|
198
|
+
created_at: textValue(row.created_at),
|
|
199
|
+
chunks: [],
|
|
200
|
+
}));
|
|
201
|
+
if (runs.length === 0) {
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
204
|
+
const chunksByRun = new Map(runs.map((run) => [run.run_id, run.chunks]));
|
|
205
|
+
const placeholders = runs.map(() => "?").join(", ");
|
|
206
|
+
const chunkResult = await client.execute({
|
|
207
|
+
sql: `SELECT run_id, score, source, rank FROM chunks WHERE run_id IN (${placeholders}) ORDER BY run_id, rank ASC`,
|
|
208
|
+
args: runs.map((run) => run.run_id),
|
|
209
|
+
});
|
|
210
|
+
for (const row of chunkResult.rows) {
|
|
211
|
+
const runChunks = chunksByRun.get(textValue(row.run_id));
|
|
212
|
+
if (runChunks !== undefined) {
|
|
213
|
+
runChunks.push({
|
|
214
|
+
score: numericValue(row.score),
|
|
215
|
+
source: textValue(row.source),
|
|
216
|
+
rank: numericValue(row.rank),
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return runs;
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA2BpE,wBAAgB,YAAY,IAAI,SAAS,CAmGxC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { getDb } from "./db/index.js";
|
|
5
|
+
import { retrievalObserve } from "./tools/observe.js";
|
|
6
|
+
import { retrievalQuery } from "./tools/query.js";
|
|
7
|
+
import { retrievalDiff } from "./tools/diff.js";
|
|
8
|
+
import { retrievalStats } from "./tools/stats.js";
|
|
9
|
+
import { logger } from "./utils/logger.js";
|
|
10
|
+
const chunkSchema = z.object({
|
|
11
|
+
content: z.string(),
|
|
12
|
+
score: z.number(),
|
|
13
|
+
source: z.string(),
|
|
14
|
+
rank: z.number().int(),
|
|
15
|
+
});
|
|
16
|
+
const retrievedChunkSchema = chunkSchema;
|
|
17
|
+
function asStructuredContent(value) {
|
|
18
|
+
return {
|
|
19
|
+
content: [{ type: "text", text: JSON.stringify(value) }],
|
|
20
|
+
structuredContent: value,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function createServer() {
|
|
24
|
+
const server = new McpServer({ name: "retrieval-lens", version: "0.1.0" });
|
|
25
|
+
server.registerTool("retrieval_observe", {
|
|
26
|
+
title: "Retrieval Observe",
|
|
27
|
+
description: "Stub capture tool for retrieval runs.",
|
|
28
|
+
inputSchema: z.object({
|
|
29
|
+
run_id: z.string(),
|
|
30
|
+
query: z.string(),
|
|
31
|
+
chunks: z.array(chunkSchema),
|
|
32
|
+
pipeline_tag: z.string().optional(),
|
|
33
|
+
}),
|
|
34
|
+
outputSchema: z.object({
|
|
35
|
+
stored: z.boolean(),
|
|
36
|
+
run_id: z.string(),
|
|
37
|
+
chunk_count: z.number(),
|
|
38
|
+
}),
|
|
39
|
+
}, async (input) => asStructuredContent(await retrievalObserve(input)));
|
|
40
|
+
server.registerTool("retrieval_query", {
|
|
41
|
+
title: "Retrieval Query",
|
|
42
|
+
description: "Stub playback tool for retrieval runs.",
|
|
43
|
+
inputSchema: z.object({
|
|
44
|
+
run_id: z.string().optional(),
|
|
45
|
+
pipeline_tag: z.string().optional(),
|
|
46
|
+
limit: z.number().optional(),
|
|
47
|
+
since_iso: z.string().optional(),
|
|
48
|
+
}),
|
|
49
|
+
outputSchema: z.object({
|
|
50
|
+
runs: z.array(z.object({
|
|
51
|
+
run_id: z.string(),
|
|
52
|
+
query: z.string(),
|
|
53
|
+
pipeline_tag: z.string().nullable(),
|
|
54
|
+
timestamp: z.string(),
|
|
55
|
+
chunks: z.array(retrievedChunkSchema),
|
|
56
|
+
})),
|
|
57
|
+
}),
|
|
58
|
+
}, async (input) => asStructuredContent(await retrievalQuery(input)));
|
|
59
|
+
server.registerTool("retrieval_diff", {
|
|
60
|
+
title: "Retrieval Diff",
|
|
61
|
+
description: "Stub comparison tool for retrieval runs.",
|
|
62
|
+
inputSchema: z.object({
|
|
63
|
+
run_id_a: z.string(),
|
|
64
|
+
run_id_b: z.string(),
|
|
65
|
+
match_by: z.enum(["source", "content_hash"]),
|
|
66
|
+
}),
|
|
67
|
+
outputSchema: z.object({
|
|
68
|
+
only_in_a: z.array(retrievedChunkSchema),
|
|
69
|
+
only_in_b: z.array(retrievedChunkSchema),
|
|
70
|
+
shared: z.array(z.object({
|
|
71
|
+
chunk: retrievedChunkSchema,
|
|
72
|
+
score_a: z.number(),
|
|
73
|
+
score_b: z.number(),
|
|
74
|
+
score_delta: z.number(),
|
|
75
|
+
})),
|
|
76
|
+
summary: z.string(),
|
|
77
|
+
}),
|
|
78
|
+
}, async (input) => asStructuredContent(await retrievalDiff(input)));
|
|
79
|
+
server.registerTool("retrieval_stats", {
|
|
80
|
+
title: "Retrieval Stats",
|
|
81
|
+
description: "Stub aggregate stats tool for retrieval runs.",
|
|
82
|
+
inputSchema: z.object({
|
|
83
|
+
pipeline_tag: z.string().optional(),
|
|
84
|
+
since_iso: z.string().optional(),
|
|
85
|
+
until_iso: z.string().optional(),
|
|
86
|
+
}),
|
|
87
|
+
outputSchema: z.object({
|
|
88
|
+
total_runs: z.number(),
|
|
89
|
+
avg_top1_score: z.number(),
|
|
90
|
+
p50_score: z.number(),
|
|
91
|
+
p90_score: z.number(),
|
|
92
|
+
top_sources: z.array(z.object({ source: z.string(), count: z.number() })),
|
|
93
|
+
runs_per_day: z.array(z.object({ date: z.string(), count: z.number() })),
|
|
94
|
+
}),
|
|
95
|
+
}, async (input) => asStructuredContent(await retrievalStats(input)));
|
|
96
|
+
return server;
|
|
97
|
+
}
|
|
98
|
+
async function main() {
|
|
99
|
+
await getDb();
|
|
100
|
+
const server = createServer();
|
|
101
|
+
await server.connect(new StdioServerTransport());
|
|
102
|
+
}
|
|
103
|
+
main().catch((error) => {
|
|
104
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
105
|
+
logger.error(message);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
});
|
|
108
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type MatchBy = "source" | "content_hash";
|
|
2
|
+
export interface DiffInput {
|
|
3
|
+
run_id_a: string;
|
|
4
|
+
run_id_b: string;
|
|
5
|
+
match_by: MatchBy;
|
|
6
|
+
}
|
|
7
|
+
export interface DiffChunk {
|
|
8
|
+
content: string;
|
|
9
|
+
score: number;
|
|
10
|
+
source: string;
|
|
11
|
+
rank: number;
|
|
12
|
+
}
|
|
13
|
+
export interface SharedChunk {
|
|
14
|
+
chunk: DiffChunk;
|
|
15
|
+
score_a: number;
|
|
16
|
+
score_b: number;
|
|
17
|
+
score_delta: number;
|
|
18
|
+
}
|
|
19
|
+
export interface DiffOutput {
|
|
20
|
+
only_in_a: DiffChunk[];
|
|
21
|
+
only_in_b: DiffChunk[];
|
|
22
|
+
shared: SharedChunk[];
|
|
23
|
+
summary: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function retrievalDiff(input: DiffInput): Promise<DiffOutput>;
|
|
26
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/tools/diff.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,cAAc,CAAC;AAEhD,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AA6CD,wBAAsB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CA4CzE"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { findDiffChunks, runExists } from "../db/index.js";
|
|
2
|
+
function publicChunk(chunk) {
|
|
3
|
+
return {
|
|
4
|
+
content: chunk.content,
|
|
5
|
+
score: chunk.score,
|
|
6
|
+
source: chunk.source,
|
|
7
|
+
rank: chunk.rank,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function matchKey(chunk, matchBy) {
|
|
11
|
+
return matchBy === "source" ? chunk.source : chunk.content_hash;
|
|
12
|
+
}
|
|
13
|
+
function indexChunks(chunks, matchBy) {
|
|
14
|
+
const indexed = new Map();
|
|
15
|
+
chunks.forEach((chunk, index) => {
|
|
16
|
+
const key = matchKey(chunk, matchBy);
|
|
17
|
+
const existing = indexed.get(key);
|
|
18
|
+
const value = { chunk, index };
|
|
19
|
+
if (existing === undefined) {
|
|
20
|
+
indexed.set(key, [value]);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
existing.push(value);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return indexed;
|
|
27
|
+
}
|
|
28
|
+
function buildSummary(onlyInA, onlyInB, shared) {
|
|
29
|
+
const averageDelta = shared.length === 0 ? 0 : shared.reduce((total, current) => total + current.score_delta, 0) / shared.length;
|
|
30
|
+
return `${onlyInA.length} chunks only in A, ${onlyInB.length} only in B, ${shared.length} shared (avg delta ${averageDelta.toFixed(2)})`;
|
|
31
|
+
}
|
|
32
|
+
export async function retrievalDiff(input) {
|
|
33
|
+
const [runAExists, runBExists] = await Promise.all([runExists(input.run_id_a), runExists(input.run_id_b)]);
|
|
34
|
+
if (!runAExists) {
|
|
35
|
+
throw new Error(`run_id ${input.run_id_a} not found`);
|
|
36
|
+
}
|
|
37
|
+
if (!runBExists) {
|
|
38
|
+
throw new Error(`run_id ${input.run_id_b} not found`);
|
|
39
|
+
}
|
|
40
|
+
const [chunksA, chunksB] = await Promise.all([findDiffChunks(input.run_id_a), findDiffChunks(input.run_id_b)]);
|
|
41
|
+
const indexedB = indexChunks(chunksB, input.match_by);
|
|
42
|
+
const matchedBIndexes = new Set();
|
|
43
|
+
const onlyInA = [];
|
|
44
|
+
const shared = [];
|
|
45
|
+
for (const chunkA of chunksA) {
|
|
46
|
+
const candidates = indexedB.get(matchKey(chunkA, input.match_by));
|
|
47
|
+
const match = candidates?.find((candidate) => !matchedBIndexes.has(candidate.index));
|
|
48
|
+
if (match === undefined) {
|
|
49
|
+
onlyInA.push(publicChunk(chunkA));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
matchedBIndexes.add(match.index);
|
|
53
|
+
shared.push({
|
|
54
|
+
chunk: publicChunk(chunkA),
|
|
55
|
+
score_a: chunkA.score,
|
|
56
|
+
score_b: match.chunk.score,
|
|
57
|
+
score_delta: match.chunk.score - chunkA.score,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const onlyInB = chunksB
|
|
62
|
+
.filter((_chunk, index) => !matchedBIndexes.has(index))
|
|
63
|
+
.map((chunk) => publicChunk(chunk));
|
|
64
|
+
return {
|
|
65
|
+
only_in_a: onlyInA,
|
|
66
|
+
only_in_b: onlyInB,
|
|
67
|
+
shared,
|
|
68
|
+
summary: buildSummary(onlyInA, onlyInB, shared),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/tools/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAwB,MAAM,gBAAgB,CAAC;AAoCjF,SAAS,WAAW,CAAC,KAAsB;IACzC,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,KAAsB,EAAE,OAAgB;IACxD,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;AAClE,CAAC;AAED,SAAS,WAAW,CAAC,MAAyB,EAAE,OAAgB;IAC9D,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAElD,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAC9B,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QAE/B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,YAAY,CAAC,OAAoB,EAAE,OAAoB,EAAE,MAAqB;IACrF,MAAM,YAAY,GAChB,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;IAE9G,OAAO,GAAG,OAAO,CAAC,MAAM,sBAAsB,OAAO,CAAC,MAAM,eAAe,MAAM,CAAC,MAAM,sBAAsB,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAC3I,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAgB;IAClD,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAE3G,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,UAAU,KAAK,CAAC,QAAQ,YAAY,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,UAAU,KAAK,CAAC,QAAQ,YAAY,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC/G,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACtD,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAC1C,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QAClE,MAAM,KAAK,GAAG,UAAU,EAAE,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QAErF,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACjC,MAAM,CAAC,IAAI,CAAC;gBACV,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC;gBAC1B,OAAO,EAAE,MAAM,CAAC,KAAK;gBACrB,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK;gBAC1B,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK;aAC9C,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,OAAO;SACpB,MAAM,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;SACtD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IAEtC,OAAO;QACL,SAAS,EAAE,OAAO;QAClB,SAAS,EAAE,OAAO;QAClB,MAAM;QACN,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC;KAChD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ObserveInput {
|
|
2
|
+
run_id: string;
|
|
3
|
+
query: string;
|
|
4
|
+
chunks: Array<{
|
|
5
|
+
content: string;
|
|
6
|
+
score: number;
|
|
7
|
+
source: string;
|
|
8
|
+
rank: number;
|
|
9
|
+
}>;
|
|
10
|
+
pipeline_tag?: string | undefined;
|
|
11
|
+
}
|
|
12
|
+
export interface ObserveOutput {
|
|
13
|
+
stored: boolean;
|
|
14
|
+
run_id: string;
|
|
15
|
+
chunk_count: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function retrievalObserve(input: ObserveInput): Promise<ObserveOutput>;
|
|
18
|
+
//# sourceMappingURL=observe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../src/tools/observe.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAMD,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAoBlF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { insertObservedRun } from "../db/index.js";
|
|
3
|
+
function contentHash(content) {
|
|
4
|
+
return createHash("sha256").update(content).digest("hex");
|
|
5
|
+
}
|
|
6
|
+
export async function retrievalObserve(input) {
|
|
7
|
+
const createdAt = new Date().toISOString();
|
|
8
|
+
const chunks = input.chunks.map((chunk) => ({
|
|
9
|
+
...chunk,
|
|
10
|
+
content_hash: contentHash(chunk.content),
|
|
11
|
+
}));
|
|
12
|
+
const stored = await insertObservedRun({
|
|
13
|
+
run_id: input.run_id,
|
|
14
|
+
query: input.query,
|
|
15
|
+
pipeline_tag: input.pipeline_tag ?? null,
|
|
16
|
+
created_at: createdAt,
|
|
17
|
+
chunks,
|
|
18
|
+
});
|
|
19
|
+
if (!stored) {
|
|
20
|
+
return { stored: false, run_id: input.run_id, chunk_count: 0 };
|
|
21
|
+
}
|
|
22
|
+
return { stored: true, run_id: input.run_id, chunk_count: input.chunks.length };
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=observe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observe.js","sourceRoot":"","sources":["../../src/tools/observe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAoBnD,SAAS,WAAW,CAAC,OAAe;IAClC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAmB;IACxD,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1C,GAAG,KAAK;QACR,YAAY,EAAE,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC;KACzC,CAAC,CAAC,CAAC;IAEJ,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;QACrC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,IAAI;QACxC,UAAU,EAAE,SAAS;QACrB,MAAM;KACP,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;IACjE,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;AAClF,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface QueryInput {
|
|
2
|
+
run_id?: string | undefined;
|
|
3
|
+
pipeline_tag?: string | undefined;
|
|
4
|
+
limit?: number | undefined;
|
|
5
|
+
since_iso?: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
export interface RetrievedChunk {
|
|
8
|
+
content: string;
|
|
9
|
+
score: number;
|
|
10
|
+
source: string;
|
|
11
|
+
rank: number;
|
|
12
|
+
}
|
|
13
|
+
export interface RunRecord {
|
|
14
|
+
run_id: string;
|
|
15
|
+
query: string;
|
|
16
|
+
pipeline_tag: string | null;
|
|
17
|
+
timestamp: string;
|
|
18
|
+
chunks: RetrievedChunk[];
|
|
19
|
+
}
|
|
20
|
+
export interface QueryOutput {
|
|
21
|
+
runs: RunRecord[];
|
|
22
|
+
}
|
|
23
|
+
export declare function retrievalQuery(input?: QueryInput): Promise<QueryOutput>;
|
|
24
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB;AAaD,wBAAsB,cAAc,CAAC,KAAK,GAAE,UAAe,GAAG,OAAO,CAAC,WAAW,CAAC,CAiBjF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { findRetrievedRuns } from "../db/index.js";
|
|
2
|
+
const DEFAULT_LIMIT = 10;
|
|
3
|
+
const MAX_LIMIT = 100;
|
|
4
|
+
function normalizeLimit(limit) {
|
|
5
|
+
if (limit === undefined) {
|
|
6
|
+
return DEFAULT_LIMIT;
|
|
7
|
+
}
|
|
8
|
+
return Math.min(Math.max(Math.trunc(limit), 0), MAX_LIMIT);
|
|
9
|
+
}
|
|
10
|
+
export async function retrievalQuery(input = {}) {
|
|
11
|
+
const runs = await findRetrievedRuns({
|
|
12
|
+
run_id: input.run_id,
|
|
13
|
+
pipeline_tag: input.pipeline_tag,
|
|
14
|
+
since_iso: input.since_iso,
|
|
15
|
+
limit: normalizeLimit(input.limit),
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
runs: runs.map((run) => ({
|
|
19
|
+
run_id: run.run_id,
|
|
20
|
+
query: run.query,
|
|
21
|
+
pipeline_tag: run.pipeline_tag,
|
|
22
|
+
timestamp: run.created_at,
|
|
23
|
+
chunks: run.chunks,
|
|
24
|
+
})),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AA4BnD,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB,SAAS,cAAc,CAAC,KAAyB;IAC/C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAoB,EAAE;IACzD,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC;QACnC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,KAAK,EAAE,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC;KACnC,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACvB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,YAAY,EAAE,GAAG,CAAC,YAAY;YAC9B,SAAS,EAAE,GAAG,CAAC,UAAU;YACzB,MAAM,EAAE,GAAG,CAAC,MAAM;SACnB,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface StatsInput {
|
|
2
|
+
pipeline_tag?: string | undefined;
|
|
3
|
+
since_iso?: string | undefined;
|
|
4
|
+
until_iso?: string | undefined;
|
|
5
|
+
}
|
|
6
|
+
export interface StatsOutput {
|
|
7
|
+
total_runs: number;
|
|
8
|
+
avg_top1_score: number;
|
|
9
|
+
p50_score: number;
|
|
10
|
+
p90_score: number;
|
|
11
|
+
top_sources: Array<{
|
|
12
|
+
source: string;
|
|
13
|
+
count: number;
|
|
14
|
+
}>;
|
|
15
|
+
runs_per_day: Array<{
|
|
16
|
+
date: string;
|
|
17
|
+
count: number;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
20
|
+
export declare function retrievalStats(input?: StatsInput): Promise<StatsOutput>;
|
|
21
|
+
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/tools/stats.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,KAAK,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;IACH,YAAY,EAAE,KAAK,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AA6CD,wBAAsB,cAAc,CAAC,KAAK,GAAE,UAAe,GAAG,OAAO,CAAC,WAAW,CAAC,CA2CjF"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { findStatsRuns } from "../db/index.js";
|
|
2
|
+
const EMPTY_STATS = {
|
|
3
|
+
total_runs: 0,
|
|
4
|
+
avg_top1_score: 0,
|
|
5
|
+
p50_score: 0,
|
|
6
|
+
p90_score: 0,
|
|
7
|
+
top_sources: [],
|
|
8
|
+
runs_per_day: [],
|
|
9
|
+
};
|
|
10
|
+
function average(values) {
|
|
11
|
+
if (values.length === 0) {
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
return values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
15
|
+
}
|
|
16
|
+
function median(sortedValues) {
|
|
17
|
+
if (sortedValues.length === 0) {
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
const midpoint = Math.floor(sortedValues.length / 2);
|
|
21
|
+
if (sortedValues.length % 2 === 1) {
|
|
22
|
+
return sortedValues[midpoint] ?? 0;
|
|
23
|
+
}
|
|
24
|
+
const lower = sortedValues[midpoint - 1] ?? 0;
|
|
25
|
+
const upper = sortedValues[midpoint] ?? 0;
|
|
26
|
+
return (lower + upper) / 2;
|
|
27
|
+
}
|
|
28
|
+
function nearestRankPercentile(sortedValues, percentile) {
|
|
29
|
+
if (sortedValues.length === 0) {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
const rawIndex = Math.ceil((percentile / 100) * sortedValues.length) - 1;
|
|
33
|
+
const index = Math.max(0, Math.min(sortedValues.length - 1, rawIndex));
|
|
34
|
+
return sortedValues[index] ?? 0;
|
|
35
|
+
}
|
|
36
|
+
export async function retrievalStats(input = {}) {
|
|
37
|
+
const runs = await findStatsRuns(input);
|
|
38
|
+
if (runs.length === 0) {
|
|
39
|
+
return { ...EMPTY_STATS, top_sources: [], runs_per_day: [] };
|
|
40
|
+
}
|
|
41
|
+
const top1Scores = [];
|
|
42
|
+
const allScores = [];
|
|
43
|
+
const sourceCounts = new Map();
|
|
44
|
+
const runsPerDay = new Map();
|
|
45
|
+
for (const run of runs) {
|
|
46
|
+
const day = run.created_at.slice(0, 10);
|
|
47
|
+
runsPerDay.set(day, (runsPerDay.get(day) ?? 0) + 1);
|
|
48
|
+
for (const chunk of run.chunks) {
|
|
49
|
+
allScores.push(chunk.score);
|
|
50
|
+
sourceCounts.set(chunk.source, (sourceCounts.get(chunk.source) ?? 0) + 1);
|
|
51
|
+
if (chunk.rank === 1) {
|
|
52
|
+
top1Scores.push(chunk.score);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const sortedScores = [...allScores].sort((left, right) => left - right);
|
|
57
|
+
const topSources = [...sourceCounts.entries()]
|
|
58
|
+
.map(([source, count]) => ({ source, count }))
|
|
59
|
+
.sort((left, right) => right.count - left.count || left.source.localeCompare(right.source))
|
|
60
|
+
.slice(0, 10);
|
|
61
|
+
const runsPerDayRows = [...runsPerDay.entries()]
|
|
62
|
+
.map(([date, count]) => ({ date, count }))
|
|
63
|
+
.sort((left, right) => left.date.localeCompare(right.date));
|
|
64
|
+
return {
|
|
65
|
+
total_runs: runs.length,
|
|
66
|
+
avg_top1_score: average(top1Scores),
|
|
67
|
+
p50_score: median(sortedScores),
|
|
68
|
+
p90_score: nearestRankPercentile(sortedScores, 90),
|
|
69
|
+
top_sources: topSources,
|
|
70
|
+
runs_per_day: runsPerDayRows,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/tools/stats.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAwB3D,eAAO,MAAM,MAAM;mBACF,MAAM,GAAG,IAAI;kBAGd,MAAM,GAAG,IAAI;kBAGb,MAAM,GAAG,IAAI;mBAGZ,MAAM,GAAG,IAAI;CAG7B,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const levelRanks = {
|
|
2
|
+
debug: 10,
|
|
3
|
+
info: 20,
|
|
4
|
+
warn: 30,
|
|
5
|
+
error: 40,
|
|
6
|
+
};
|
|
7
|
+
function configuredLevel() {
|
|
8
|
+
const configured = process.env.RETRIEVAL_LENS_LOG;
|
|
9
|
+
return configured === "debug" || configured === "info" || configured === "warn" || configured === "error"
|
|
10
|
+
? configured
|
|
11
|
+
: "warn";
|
|
12
|
+
}
|
|
13
|
+
function write(level, message, writer = process.stderr.write.bind(process.stderr)) {
|
|
14
|
+
if (levelRanks[level] >= levelRanks[configuredLevel()]) {
|
|
15
|
+
writer(`[${level}] ${message}\n`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export const logger = {
|
|
19
|
+
debug(message) {
|
|
20
|
+
write("debug", message);
|
|
21
|
+
},
|
|
22
|
+
info(message) {
|
|
23
|
+
write("info", message);
|
|
24
|
+
},
|
|
25
|
+
warn(message) {
|
|
26
|
+
write("warn", message);
|
|
27
|
+
},
|
|
28
|
+
error(message) {
|
|
29
|
+
write("error", message);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,GAA6B;IAC3C,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,EAAE;IACR,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,EAAE;CACV,CAAC;AAEF,SAAS,eAAe;IACtB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAClD,OAAO,UAAU,KAAK,OAAO,IAAI,UAAU,KAAK,MAAM,IAAI,UAAU,KAAK,MAAM,IAAI,UAAU,KAAK,OAAO;QACvG,CAAC,CAAC,UAAU;QACZ,CAAC,CAAC,MAAM,CAAC;AACb,CAAC;AAED,SAAS,KAAK,CAAC,KAAe,EAAE,OAAe,EAAE,SAAoB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IAC5G,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,eAAe,EAAE,CAAC,EAAE,CAAC;QACvD,MAAM,CAAC,IAAI,KAAK,KAAK,OAAO,IAAI,CAAC,CAAC;IACpC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,KAAK,CAAC,OAAe;QACnB,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,CAAC,OAAe;QAClB,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzB,CAAC;IACD,IAAI,CAAC,OAAe;QAClB,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzB,CAAC;IACD,KAAK,CAAC,OAAe;QACnB,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1B,CAAC;CACF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "retrieval-lens",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server that audits RAG retrieval — logs what chunks the model saw, scores, queries, and sources before any answer was generated.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"rag",
|
|
8
|
+
"retrieval",
|
|
9
|
+
"audit",
|
|
10
|
+
"observability",
|
|
11
|
+
"llm",
|
|
12
|
+
"ai-agents"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"bin": {
|
|
17
|
+
"retrieval-lens": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist/",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc --noEmit && tsc",
|
|
27
|
+
"dev": "tsx watch src/index.ts",
|
|
28
|
+
"test": "vitest run --coverage",
|
|
29
|
+
"lint": "eslint src/ tests/ && tsc --noEmit",
|
|
30
|
+
"inspect": "npx @modelcontextprotocol/inspector dist/index.js",
|
|
31
|
+
"prepublishOnly": "npm run lint && npm test && npm run build"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@libsql/client": "^0.17.3",
|
|
35
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^22.19.20",
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
40
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
41
|
+
"@vitest/coverage-v8": "^2.0.0",
|
|
42
|
+
"eslint": "^9.0.0",
|
|
43
|
+
"tsx": "^4.0.0",
|
|
44
|
+
"typescript": "^5.5.0",
|
|
45
|
+
"vitest": "^2.0.0"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18.0.0"
|
|
49
|
+
}
|
|
50
|
+
}
|