@mcp-abap-adt/qdrant-rag 26.0.0 → 28.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/README.md +22 -0
- package/dist/__tests__/catalog.test.d.ts +2 -0
- package/dist/__tests__/catalog.test.d.ts.map +1 -0
- package/dist/__tests__/catalog.test.js +241 -0
- package/dist/__tests__/catalog.test.js.map +1 -0
- package/dist/__tests__/credential.test.d.ts +2 -0
- package/dist/__tests__/credential.test.d.ts.map +1 -0
- package/dist/__tests__/credential.test.js +93 -0
- package/dist/__tests__/credential.test.js.map +1 -0
- package/dist/__tests__/qdrant-stub.d.ts +52 -0
- package/dist/__tests__/qdrant-stub.d.ts.map +1 -0
- package/dist/__tests__/qdrant-stub.js +206 -0
- package/dist/__tests__/qdrant-stub.js.map +1 -0
- package/dist/__tests__/rag-filter-conformance.test.d.ts +2 -0
- package/dist/__tests__/rag-filter-conformance.test.d.ts.map +1 -0
- package/dist/__tests__/rag-filter-conformance.test.js +25 -0
- package/dist/__tests__/rag-filter-conformance.test.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/qdrant-rag-provider.d.ts +41 -11
- package/dist/qdrant-rag-provider.d.ts.map +1 -1
- package/dist/qdrant-rag-provider.js +296 -29
- package/dist/qdrant-rag-provider.js.map +1 -1
- package/dist/qdrant-rag-provider.test.js +0 -11
- package/dist/qdrant-rag-provider.test.js.map +1 -1
- package/dist/qdrant-rag.d.ts +23 -2
- package/dist/qdrant-rag.d.ts.map +1 -1
- package/dist/qdrant-rag.js +45 -19
- package/dist/qdrant-rag.js.map +1 -1
- package/dist/qdrant-rag.test.js +51 -3
- package/dist/qdrant-rag.test.js.map +1 -1
- package/package.json +5 -4
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
export async function startQdrantStub(catalog = 'rag_collection_catalog') {
|
|
3
|
+
const collections = new Map();
|
|
4
|
+
const requests = [];
|
|
5
|
+
let stub;
|
|
6
|
+
const route = (r, reply) => {
|
|
7
|
+
const body = (r.body ?? {});
|
|
8
|
+
const missing = (name) => reply(404, {
|
|
9
|
+
status: { error: `Collection \`${name}\` doesn't exist!` },
|
|
10
|
+
});
|
|
11
|
+
const coll = r.path.match(/^\/collections\/([^/]+)$/);
|
|
12
|
+
if (coll) {
|
|
13
|
+
const name = coll[1];
|
|
14
|
+
const c = collections.get(name);
|
|
15
|
+
if (r.method === 'GET') {
|
|
16
|
+
if (!c) {
|
|
17
|
+
missing(name);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
reply(200, {
|
|
21
|
+
result: {
|
|
22
|
+
status: 'green',
|
|
23
|
+
config: { params: { vectors: { size: c.size } } },
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (r.method === 'PUT') {
|
|
29
|
+
if (c) {
|
|
30
|
+
reply(409, {
|
|
31
|
+
status: { error: `Collection \`${name}\` already exists!` },
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const vectors = body.vectors;
|
|
36
|
+
collections.set(name, { size: vectors.size, points: new Map() });
|
|
37
|
+
reply(200, { result: true });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (r.method === 'DELETE') {
|
|
41
|
+
collections.delete(name);
|
|
42
|
+
reply(200, { result: true });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (r.path === '/collections' && r.method === 'GET') {
|
|
47
|
+
reply(200, {
|
|
48
|
+
result: {
|
|
49
|
+
collections: [...collections.keys()].map((name) => ({ name })),
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const pts = r.path.match(/^\/collections\/([^/]+)\/points(\/scroll|\/delete|\/search)?$/);
|
|
55
|
+
if (pts) {
|
|
56
|
+
const name = pts[1];
|
|
57
|
+
const action = pts[2];
|
|
58
|
+
const c = collections.get(name);
|
|
59
|
+
if (!c) {
|
|
60
|
+
missing(name);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (r.method === 'PUT' && action === undefined) {
|
|
64
|
+
if (name === catalog)
|
|
65
|
+
stub?.beforeCatalogWrite?.();
|
|
66
|
+
const insertOnly = body.update_mode === 'insert_only';
|
|
67
|
+
for (const p of body.points) {
|
|
68
|
+
if (insertOnly && c.points.has(p.id))
|
|
69
|
+
continue;
|
|
70
|
+
c.points.set(p.id, p);
|
|
71
|
+
}
|
|
72
|
+
reply(200, { result: { status: 'completed' } });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (r.method === 'POST' && action === undefined) {
|
|
76
|
+
const ids = body.ids;
|
|
77
|
+
reply(200, {
|
|
78
|
+
result: ids.flatMap((id) => {
|
|
79
|
+
const p = c.points.get(id);
|
|
80
|
+
return p ? [{ id, payload: p.payload }] : [];
|
|
81
|
+
}),
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (r.method === 'POST' && action === '/scroll') {
|
|
86
|
+
const ids = [...c.points.keys()].sort();
|
|
87
|
+
const start = body.offset === undefined ? 0 : ids.indexOf(String(body.offset));
|
|
88
|
+
const limit = Number(body.limit ?? 10);
|
|
89
|
+
reply(200, {
|
|
90
|
+
result: {
|
|
91
|
+
points: ids
|
|
92
|
+
.slice(start, start + limit)
|
|
93
|
+
.map((id) => ({ id, payload: c.points.get(id)?.payload })),
|
|
94
|
+
next_page_offset: ids[start + limit] ?? null,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (r.method === 'POST' && action === '/delete') {
|
|
100
|
+
for (const id of body.points ?? [])
|
|
101
|
+
c.points.delete(id);
|
|
102
|
+
if (body.filter !== undefined)
|
|
103
|
+
c.points.clear();
|
|
104
|
+
reply(200, { result: { status: 'completed' } });
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (r.method === 'POST' && action === '/search') {
|
|
108
|
+
// Qdrant's documented search: the filter is applied inside the
|
|
109
|
+
// search, then points are ordered by cosine similarity and cut at
|
|
110
|
+
// `limit` — so the conformance cases see what a real server returns.
|
|
111
|
+
const query = body.vector;
|
|
112
|
+
const filter = body.filter;
|
|
113
|
+
const limit = Number(body.limit ?? 10);
|
|
114
|
+
const hits = [...c.points.values()]
|
|
115
|
+
.filter((p) => filter === undefined || matchesFilter(p.payload, filter))
|
|
116
|
+
.map((p) => ({
|
|
117
|
+
id: p.id,
|
|
118
|
+
score: cosine(query, p.vector),
|
|
119
|
+
payload: p.payload,
|
|
120
|
+
}))
|
|
121
|
+
.sort((a, b) => b.score - a.score)
|
|
122
|
+
.slice(0, limit);
|
|
123
|
+
reply(200, { result: hits });
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
reply(404, { status: { error: 'not found' } });
|
|
128
|
+
};
|
|
129
|
+
const server = http.createServer((req, res) => {
|
|
130
|
+
let raw = '';
|
|
131
|
+
req.on('data', (chunk) => {
|
|
132
|
+
raw += chunk.toString('utf8');
|
|
133
|
+
});
|
|
134
|
+
req.on('end', () => {
|
|
135
|
+
const request = {
|
|
136
|
+
method: req.method ?? 'GET',
|
|
137
|
+
path: new URL(req.url ?? '/', 'http://stub').pathname,
|
|
138
|
+
body: raw ? JSON.parse(raw) : undefined,
|
|
139
|
+
};
|
|
140
|
+
requests.push(request);
|
|
141
|
+
const reply = (status, body) => {
|
|
142
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
143
|
+
res.end(JSON.stringify(body));
|
|
144
|
+
};
|
|
145
|
+
if (stub?.failOn?.(request)) {
|
|
146
|
+
reply(500, { status: { error: 'refused by the test' } });
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
route(request, reply);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
|
|
153
|
+
const addr = server.address();
|
|
154
|
+
if (typeof addr !== 'object' || addr === null)
|
|
155
|
+
throw new Error('the stub did not bind');
|
|
156
|
+
stub = {
|
|
157
|
+
baseUrl: `http://127.0.0.1:${addr.port}`,
|
|
158
|
+
collections,
|
|
159
|
+
requests,
|
|
160
|
+
close: () => new Promise((resolve, reject) => server.close((err) => (err ? reject(err) : resolve()))),
|
|
161
|
+
};
|
|
162
|
+
return stub;
|
|
163
|
+
}
|
|
164
|
+
function holds(payload, cond) {
|
|
165
|
+
if ('is_empty' in cond) {
|
|
166
|
+
const v = payload[cond.is_empty.key];
|
|
167
|
+
return (v === undefined || v === null || (Array.isArray(v) && v.length === 0));
|
|
168
|
+
}
|
|
169
|
+
if ('match' in cond) {
|
|
170
|
+
return cond.key in payload && payload[cond.key] === cond.match.value;
|
|
171
|
+
}
|
|
172
|
+
if ('range' in cond) {
|
|
173
|
+
const v = payload[cond.key];
|
|
174
|
+
if (typeof v !== 'number')
|
|
175
|
+
return false;
|
|
176
|
+
const { gt, gte, lt, lte } = cond.range;
|
|
177
|
+
return ((gt === undefined || v > gt) &&
|
|
178
|
+
(gte === undefined || v >= gte) &&
|
|
179
|
+
(lt === undefined || v < lt) &&
|
|
180
|
+
(lte === undefined || v <= lte));
|
|
181
|
+
}
|
|
182
|
+
return matchesFilter(payload, cond);
|
|
183
|
+
}
|
|
184
|
+
export function matchesFilter(payload, filter) {
|
|
185
|
+
if (filter.must && !filter.must.every((c) => holds(payload, c)))
|
|
186
|
+
return false;
|
|
187
|
+
if (filter.should &&
|
|
188
|
+
filter.should.length > 0 &&
|
|
189
|
+
!filter.should.some((c) => holds(payload, c)))
|
|
190
|
+
return false;
|
|
191
|
+
if (filter.must_not?.some((c) => holds(payload, c)))
|
|
192
|
+
return false;
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
function cosine(a, b) {
|
|
196
|
+
let dot = 0;
|
|
197
|
+
let na = 0;
|
|
198
|
+
let nb = 0;
|
|
199
|
+
for (let i = 0; i < a.length; i++) {
|
|
200
|
+
dot += a[i] * b[i];
|
|
201
|
+
na += a[i] ** 2;
|
|
202
|
+
nb += b[i] ** 2;
|
|
203
|
+
}
|
|
204
|
+
return dot / (Math.sqrt(na) * Math.sqrt(nb) || 1);
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=qdrant-stub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qdrant-stub.js","sourceRoot":"","sources":["../../src/__tests__/qdrant-stub.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rag-filter-conformance.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/rag-filter-conformance.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { after, before, describe, it } from 'node:test';
|
|
2
|
+
import { conformanceEmbedder, ragFilterConformanceCases, } from '@mcp-abap-adt/llm-agent/testing/rag-filter-conformance';
|
|
3
|
+
import { QdrantRag } from '../qdrant-rag.js';
|
|
4
|
+
import { startQdrantStub } from './qdrant-stub.js';
|
|
5
|
+
// The shared conformance kit over QdrantRag, against a stub that evaluates the
|
|
6
|
+
// search filter with Qdrant's documented semantics. The same cases run live
|
|
7
|
+
// against a real Qdrant in the release check.
|
|
8
|
+
describe('QdrantRag — filter conformance (stub)', () => {
|
|
9
|
+
let stub;
|
|
10
|
+
let n = 0;
|
|
11
|
+
before(async () => {
|
|
12
|
+
stub = await startQdrantStub();
|
|
13
|
+
});
|
|
14
|
+
after(async () => {
|
|
15
|
+
await stub.close();
|
|
16
|
+
});
|
|
17
|
+
for (const c of ragFilterConformanceCases) {
|
|
18
|
+
it(c.name, () => c.run(async () => new QdrantRag({
|
|
19
|
+
url: stub.baseUrl,
|
|
20
|
+
collectionName: `conf_${n++}`,
|
|
21
|
+
embedder: conformanceEmbedder(),
|
|
22
|
+
})));
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=rag-filter-conformance.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rag-filter-conformance.test.js","sourceRoot":"","sources":["../../src/__tests__/rag-filter-conformance.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EACL,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,wDAAwD,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAmB,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEpE,+EAA+E;AAC/E,4EAA4E;AAC5E,8CAA8C;AAC9C,QAAQ,CAAC,uCAAuC,EAAE,GAAG,EAAE;IACrD,IAAI,IAAgB,CAAC;IACrB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,CAAC,KAAK,IAAI,EAAE;QAChB,IAAI,GAAG,MAAM,eAAe,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,KAAK,IAAI,EAAE;QACf,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,KAAK,MAAM,CAAC,IAAI,yBAAyB,EAAE,CAAC;QAC1C,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,CACd,CAAC,CAAC,GAAG,CACH,KAAK,IAAI,EAAE,CACT,IAAI,SAAS,CAAC;YACZ,GAAG,EAAE,IAAI,CAAC,OAAO;YACjB,cAAc,EAAE,QAAQ,CAAC,EAAE,EAAE;YAC7B,QAAQ,EAAE,mBAAmB,EAAE;SAChC,CAAC,CACL,CACF,CAAC;IACJ,CAAC;AACH,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { QdrantRagConfig } from './qdrant-rag.js';
|
|
2
2
|
export { QdrantRag } from './qdrant-rag.js';
|
|
3
3
|
export type { QdrantRagProviderConfig } from './qdrant-rag-provider.js';
|
|
4
|
-
export { QdrantRagProvider } from './qdrant-rag-provider.js';
|
|
4
|
+
export { DEFAULT_CATALOG_COLLECTION, QdrantRagProvider, } from './qdrant-rag-provider.js';
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,EACL,0BAA0B,EAC1B,iBAAiB,GAClB,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EACL,0BAA0B,EAC1B,iBAAiB,GAClB,MAAM,0BAA0B,CAAC"}
|
|
@@ -1,9 +1,21 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IApiKeyCredential } from '@mcp-abap-adt/interfaces-auth';
|
|
2
|
+
import type { IEmbedder, IIdStrategy, IRag, IRagEditor, RagCatalogDescription, RagCollectionRecord, RagCollectionScope, RagProviderCreateCollectionOptions } from '@mcp-abap-adt/llm-agent';
|
|
2
3
|
import { AbstractRagProvider as BaseRagProvider, RagError, type Result } from '@mcp-abap-adt/llm-agent';
|
|
4
|
+
/** The collection a QdrantRagProvider keeps one point per collection in, by default. */
|
|
5
|
+
export declare const DEFAULT_CATALOG_COLLECTION = "rag_collection_catalog";
|
|
6
|
+
type Handles = {
|
|
7
|
+
rag: IRag;
|
|
8
|
+
editor: IRagEditor;
|
|
9
|
+
};
|
|
3
10
|
export interface QdrantRagProviderConfig {
|
|
4
11
|
name: string;
|
|
5
12
|
url: string;
|
|
6
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Asked for fresh on every request — never cached — so a rotating key
|
|
15
|
+
* rotates. Optional: an unauthenticated Qdrant deployment works today
|
|
16
|
+
* without one.
|
|
17
|
+
*/
|
|
18
|
+
credential?: IApiKeyCredential;
|
|
7
19
|
embedder: IEmbedder;
|
|
8
20
|
editable?: boolean;
|
|
9
21
|
timeoutMs?: number;
|
|
@@ -13,6 +25,8 @@ export interface QdrantRagProviderConfig {
|
|
|
13
25
|
sessionId?: string;
|
|
14
26
|
userId?: string;
|
|
15
27
|
}) => IIdStrategy;
|
|
28
|
+
/** The collection holding one record point per collection. Default `rag_collection_catalog`. */
|
|
29
|
+
catalogCollection?: string;
|
|
16
30
|
}
|
|
17
31
|
export declare class QdrantRagProvider extends BaseRagProvider {
|
|
18
32
|
readonly name: string;
|
|
@@ -20,19 +34,35 @@ export declare class QdrantRagProvider extends BaseRagProvider {
|
|
|
20
34
|
readonly editable: boolean;
|
|
21
35
|
readonly supportedScopes: readonly RagCollectionScope[];
|
|
22
36
|
private readonly url;
|
|
23
|
-
private readonly
|
|
37
|
+
private readonly credential?;
|
|
24
38
|
private readonly embedder;
|
|
25
39
|
private readonly timeoutMs?;
|
|
40
|
+
private readonly catalog;
|
|
41
|
+
private catalogReady?;
|
|
26
42
|
constructor(cfg: QdrantRagProviderConfig);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Creates the collection — sized by one probe embedding — with a request that
|
|
45
|
+
* fails if it exists, then commits the creation by writing the record last,
|
|
46
|
+
* create-if-absent (§6.3).
|
|
47
|
+
*/
|
|
48
|
+
createCollection(name: string, opts: RagProviderCreateCollectionOptions): Promise<Result<Handles, RagError>>;
|
|
49
|
+
/** The catalog, paged and read back through the shared row check. Creates nothing. */
|
|
50
|
+
describeCollections(): Promise<Result<RagCatalogDescription, RagError>>;
|
|
51
|
+
/** Handles for a collection that exists. Issues no request, and the handles never create. */
|
|
52
|
+
openCollection(record: RagCollectionRecord): Promise<Result<Handles, RagError>>;
|
|
53
|
+
/** The record first, then the collection (§6.3). */
|
|
35
54
|
deleteCollection(name: string): Promise<Result<void, RagError>>;
|
|
36
55
|
listCollections(): Promise<Result<string[], RagError>>;
|
|
56
|
+
private createStore;
|
|
57
|
+
private writeRecord;
|
|
58
|
+
private handles;
|
|
59
|
+
private duplicate;
|
|
60
|
+
private refuseCatalogName;
|
|
61
|
+
private ensureCatalog;
|
|
62
|
+
private collectionExists;
|
|
63
|
+
/** The catalog point's payload, or undefined when there is none (or no catalog yet). */
|
|
64
|
+
private readRecord;
|
|
65
|
+
private request;
|
|
37
66
|
}
|
|
67
|
+
export {};
|
|
38
68
|
//# sourceMappingURL=qdrant-rag-provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qdrant-rag-provider.d.ts","sourceRoot":"","sources":["../src/qdrant-rag-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,IAAI,EACJ,UAAU,EACV,
|
|
1
|
+
{"version":3,"file":"qdrant-rag-provider.d.ts","sourceRoot":"","sources":["../src/qdrant-rag-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,IAAI,EACJ,UAAU,EACV,qBAAqB,EAGrB,mBAAmB,EACnB,kBAAkB,EAClB,kCAAkC,EACnC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,mBAAmB,IAAI,eAAe,EAMtC,QAAQ,EACR,KAAK,MAAM,EAGZ,MAAM,yBAAyB,CAAC;AAGjC,wFAAwF;AACxF,eAAO,MAAM,0BAA0B,2BAA2B,CAAC;AAKnE,KAAK,OAAO,GAAG;IAAE,GAAG,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC;AAGjD,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ;;;;OAIG;IACH,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAChD,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE;QACzB,KAAK,EAAE,kBAAkB,CAAC;QAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,KAAK,WAAW,CAAC;IAClB,gGAAgG;IAChG,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,qBAAa,iBAAkB,SAAQ,eAAe;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAExD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAoB;IAChD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,YAAY,CAAC,CAAgB;gBAEzB,GAAG,EAAE,uBAAuB;IAaxC;;;;OAIG;IACG,gBAAgB,CACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,kCAAkC,GACvC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IA4CrC,sFAAsF;IAChF,mBAAmB,IAAI,OAAO,CAClC,MAAM,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CACxC;IAyDD,6FAA6F;IACvF,cAAc,CAClB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAUrC,oDAAoD;IAC9C,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAmD/D,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,QAAQ,CAAC,CAAC;YA0B9C,WAAW;YAmCX,WAAW;IAwDzB,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,SAAS;IAajB,OAAO,CAAC,iBAAiB;IAWzB,OAAO,CAAC,aAAa;YAuBP,gBAAgB;IAU9B,wFAAwF;YAC1E,UAAU;YAuBV,OAAO;CAUtB"}
|