@folterung/project-memory 0.1.19 → 0.1.21
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 +13 -8
- package/package.json +4 -2
- package/packages/cli/coverage/lcov-report/chunking/chunker.ts.html +81 -81
- package/packages/cli/coverage/lcov-report/chunking/hash.ts.html +12 -12
- package/packages/cli/coverage/lcov-report/chunking/index.html +1 -1
- package/packages/cli/coverage/lcov-report/chunking/types.ts.html +23 -23
- package/packages/cli/coverage/lcov-report/config/index.html +1 -1
- package/packages/cli/coverage/lcov-report/config/load.ts.html +1 -1
- package/packages/cli/coverage/lcov-report/config/types.ts.html +1 -1
- package/packages/cli/coverage/lcov-report/embedding/index.html +1 -1
- package/packages/cli/coverage/lcov-report/embedding/stub.ts.html +1 -1
- package/packages/cli/coverage/lcov-report/index.html +18 -18
- package/packages/cli/coverage/lcov-report/qdrant/index.html +1 -1
- package/packages/cli/coverage/lcov-report/qdrant/upsert.ts.html +1 -1
- package/packages/cli/coverage/lcov-report/scope/allowlist.ts.html +51 -51
- package/packages/cli/coverage/lcov-report/scope/ignore.ts.html +1 -1
- package/packages/cli/coverage/lcov-report/scope/index.html +19 -19
- package/packages/cli/coverage/lcov.info +221 -213
- package/packages/cli/coverage/tmp/{coverage-7460-1770137208481-0.json → coverage-24604-1770174821315-0.json} +1 -1
- package/packages/cli/coverage/tmp/coverage-24605-1770174821362-0.json +1 -0
- package/packages/cli/coverage/tmp/{coverage-7462-1770137208524-0.json → coverage-24606-1770174821361-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-7463-1770137208524-0.json → coverage-24607-1770174821359-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-7464-1770137208531-0.json → coverage-24608-1770174821367-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-7465-1770137208526-0.json → coverage-24609-1770174821359-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-7466-1770137208528-0.json → coverage-24610-1770174821360-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-7467-1770137208579-0.json → coverage-24611-1770174821416-0.json} +1 -1
- package/packages/cli/coverage/tmp/coverage-24612-1770174821392-0.json +1 -0
- package/packages/cli/coverage/tmp/{coverage-7469-1770137208543-0.json → coverage-24613-1770174821380-0.json} +1 -1
- package/packages/cli/dist/chunking/chunker.test.js +19 -0
- package/packages/cli/dist/chunking/chunker.test.js.map +1 -1
- package/packages/cli/dist/cli/index.js +1 -1
- package/packages/cli/dist/cli/index.js.map +1 -1
- package/packages/cli/dist/phase1/pipeline.js +17 -7
- package/packages/cli/dist/phase1/pipeline.js.map +1 -1
- package/packages/cli/dist/phase2/deep-index.js +18 -6
- package/packages/cli/dist/phase2/deep-index.js.map +1 -1
- package/packages/cli/dist/scope/allowlist.test.js +14 -1
- package/packages/cli/dist/scope/allowlist.test.js.map +1 -1
- package/packages/cli/src/chunking/chunker.test.ts +21 -0
- package/packages/cli/src/cli/index.ts +1 -1
- package/packages/cli/src/phase1/pipeline.ts +15 -8
- package/packages/cli/src/phase2/deep-index.ts +15 -6
- package/packages/cli/src/scope/allowlist.test.ts +16 -1
- package/packages/mcp-server/dist/index.js +174 -16
- package/packages/mcp-server/dist/index.js.map +1 -1
- package/packages/mcp-server/dist/system-instructions.md +2 -0
- package/packages/mcp-server/src/index.ts +204 -16
- package/packages/mcp-server/system-instructions.md +2 -0
- package/packages/server/coverage/lcov-report/api/index.html +146 -0
- package/packages/server/coverage/lcov-report/api/points.ts.html +361 -0
- package/packages/server/coverage/lcov-report/api/search.ts.html +436 -0
- package/packages/server/coverage/lcov-report/api/store.ts.html +487 -0
- package/packages/server/coverage/lcov-report/embedding/index.html +116 -0
- package/packages/server/coverage/lcov-report/embedding/stub.ts.html +184 -0
- package/packages/server/coverage/lcov-report/index.html +40 -10
- package/packages/server/coverage/lcov-report/qdrant/client.ts.html +517 -0
- package/packages/server/coverage/lcov-report/qdrant/index.html +116 -0
- package/packages/server/coverage/lcov-report/stub.ts.html +1 -1
- package/packages/server/coverage/lcov.info +674 -27
- package/packages/server/coverage/tmp/{coverage-7549-1770137209315-0.json → coverage-24692-1770174822211-0.json} +1 -1
- package/packages/server/coverage/tmp/coverage-24693-1770174822463-0.json +1 -0
- package/packages/server/coverage/tmp/coverage-24694-1770174822454-0.json +1 -0
- package/packages/server/coverage/tmp/coverage-24695-1770174822463-0.json +1 -0
- package/packages/server/coverage/tmp/{coverage-7550-1770137209349-0.json → coverage-24696-1770174822253-0.json} +1 -1
- package/packages/server/dist/api/points.d.ts +24 -0
- package/packages/server/dist/api/points.js +60 -0
- package/packages/server/dist/api/points.js.map +1 -0
- package/packages/server/dist/api/points.test.d.ts +1 -0
- package/packages/server/dist/api/points.test.js +105 -0
- package/packages/server/dist/api/points.test.js.map +1 -0
- package/packages/server/dist/api/search.d.ts +16 -0
- package/packages/server/dist/api/search.js +26 -8
- package/packages/server/dist/api/search.js.map +1 -1
- package/packages/server/dist/api/search.test.d.ts +1 -0
- package/packages/server/dist/api/search.test.js +102 -0
- package/packages/server/dist/api/search.test.js.map +1 -0
- package/packages/server/dist/api/store.d.ts +7 -0
- package/packages/server/dist/api/store.js +50 -7
- package/packages/server/dist/api/store.js.map +1 -1
- package/packages/server/dist/api/store.test.d.ts +1 -0
- package/packages/server/dist/api/store.test.js +85 -0
- package/packages/server/dist/api/store.test.js.map +1 -0
- package/packages/server/dist/index.js +2 -0
- package/packages/server/dist/index.js.map +1 -1
- package/packages/server/dist/qdrant/client.d.ts +4 -0
- package/packages/server/dist/qdrant/client.js +12 -0
- package/packages/server/dist/qdrant/client.js.map +1 -1
- package/packages/server/package.json +1 -1
- package/packages/server/src/api/points.test.ts +113 -0
- package/packages/server/src/api/points.ts +92 -0
- package/packages/server/src/api/search.test.ts +110 -0
- package/packages/server/src/api/search.ts +59 -13
- package/packages/server/src/api/store.test.ts +91 -0
- package/packages/server/src/api/store.ts +60 -12
- package/packages/server/src/index.ts +2 -0
- package/packages/server/src/qdrant/client.ts +15 -0
- package/packages/cli/coverage/tmp/coverage-7461-1770137208528-0.json +0 -1
- package/packages/cli/coverage/tmp/coverage-7468-1770137208547-0.json +0 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { FastifyInstance } from "fastify";
|
|
2
|
+
import type { QdrantClient } from "@qdrant/js-client-rest";
|
|
3
|
+
export interface PointsBatchBody {
|
|
4
|
+
ids: string[];
|
|
5
|
+
}
|
|
6
|
+
export interface PointItem {
|
|
7
|
+
id: string;
|
|
8
|
+
text: string;
|
|
9
|
+
path?: string;
|
|
10
|
+
startLine?: number;
|
|
11
|
+
endLine?: number;
|
|
12
|
+
symbol?: string;
|
|
13
|
+
kind?: string;
|
|
14
|
+
indexedAt?: string;
|
|
15
|
+
storedAt?: string;
|
|
16
|
+
source?: string;
|
|
17
|
+
supersededById?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function registerPointsRoutes(app: FastifyInstance, options: {
|
|
20
|
+
qdrantHost?: string;
|
|
21
|
+
qdrantPort?: number;
|
|
22
|
+
collection?: string;
|
|
23
|
+
qdrantClient?: QdrantClient;
|
|
24
|
+
}): void;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createQdrantClient } from "../qdrant/client.js";
|
|
2
|
+
import { retrievePointsById } from "../qdrant/client.js";
|
|
3
|
+
const BATCH_MAX_IDS = 20;
|
|
4
|
+
function payloadToItem(id, payload) {
|
|
5
|
+
return {
|
|
6
|
+
id,
|
|
7
|
+
text: payload.text ?? "",
|
|
8
|
+
path: payload.path,
|
|
9
|
+
startLine: payload.startLine,
|
|
10
|
+
endLine: payload.endLine,
|
|
11
|
+
symbol: payload.symbol,
|
|
12
|
+
kind: payload.kind,
|
|
13
|
+
indexedAt: payload.indexedAt,
|
|
14
|
+
storedAt: payload.storedAt,
|
|
15
|
+
source: payload.source,
|
|
16
|
+
supersededById: payload.supersededById,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function registerPointsRoutes(app, options) {
|
|
20
|
+
const client = options.qdrantClient ??
|
|
21
|
+
createQdrantClient(options.qdrantHost ?? "127.0.0.1", options.qdrantPort ?? 6333);
|
|
22
|
+
const collection = options.collection ?? "project_memory";
|
|
23
|
+
app.post("/points/batch", {
|
|
24
|
+
schema: {
|
|
25
|
+
body: {
|
|
26
|
+
type: "object",
|
|
27
|
+
required: ["ids"],
|
|
28
|
+
properties: {
|
|
29
|
+
ids: {
|
|
30
|
+
type: "array",
|
|
31
|
+
items: { type: "string" },
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
}, async (request, reply) => {
|
|
37
|
+
const { ids } = request.body ?? {};
|
|
38
|
+
if (!Array.isArray(ids) || ids.length === 0) {
|
|
39
|
+
await reply.status(400).send({
|
|
40
|
+
statusCode: 400,
|
|
41
|
+
error: "Bad Request",
|
|
42
|
+
message: "ids must be a non-empty array (max " + BATCH_MAX_IDS + " items)",
|
|
43
|
+
});
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (ids.length > BATCH_MAX_IDS) {
|
|
47
|
+
await reply.status(400).send({
|
|
48
|
+
statusCode: 400,
|
|
49
|
+
error: "Bad Request",
|
|
50
|
+
message: "ids must contain at most " + BATCH_MAX_IDS + " items",
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const uniqueIds = [...new Set(ids)];
|
|
55
|
+
const points = await retrievePointsById(client, collection, uniqueIds);
|
|
56
|
+
const items = points.map((p) => payloadToItem(p.id, p.payload));
|
|
57
|
+
await reply.send({ items });
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=points.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"points.js","sourceRoot":"","sources":["../../src/api/points.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGzD,MAAM,aAAa,GAAG,EAAE,CAAC;AAoBzB,SAAS,aAAa,CAAC,EAAU,EAAE,OAAqB;IACtD,OAAO;QACL,EAAE;QACF,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE;QACxB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,SAAS,EAAE,OAAO,CAAC,SAA+B;QAClD,OAAO,EAAE,OAAO,CAAC,OAA6B;QAC9C,MAAM,EAAE,OAAO,CAAC,MAA4B;QAC5C,IAAI,EAAE,OAAO,CAAC,IAA0B;QACxC,SAAS,EAAE,OAAO,CAAC,SAA+B;QAClD,QAAQ,EAAE,OAAO,CAAC,QAA8B;QAChD,MAAM,EAAE,OAAO,CAAC,MAA4B;QAC5C,cAAc,EAAE,OAAO,CAAC,cAAoC;KAC7D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,GAAoB,EACpB,OAAuG;IAEvG,MAAM,MAAM,GACV,OAAO,CAAC,YAAY;QACpB,kBAAkB,CAAC,OAAO,CAAC,UAAU,IAAI,WAAW,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;IACpF,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,gBAAgB,CAAC;IAE1D,GAAG,CAAC,IAAI,CACN,eAAe,EACf;QACE,MAAM,EAAE;YACN,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,CAAC,KAAK,CAAC;gBACjB,UAAU,EAAE;oBACV,GAAG,EAAE;wBACH,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;qBAC1B;iBACF;aACF;SACF;KACF,EACD,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvB,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5C,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC3B,UAAU,EAAE,GAAG;gBACf,KAAK,EAAE,aAAa;gBACpB,OAAO,EAAE,qCAAqC,GAAG,aAAa,GAAG,SAAS;aAC3E,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,GAAG,aAAa,EAAE,CAAC;YAC/B,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC3B,UAAU,EAAE,GAAG;gBACf,KAAK,EAAE,aAAa;gBACpB,OAAO,EAAE,2BAA2B,GAAG,aAAa,GAAG,QAAQ;aAChE,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAa,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QACvE,MAAM,KAAK,GAAgB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7E,MAAM,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9B,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { strict as assert } from "node:assert";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import Fastify from "fastify";
|
|
4
|
+
import { registerPointsRoutes } from "./points.js";
|
|
5
|
+
function createMockPointsClient() {
|
|
6
|
+
return {
|
|
7
|
+
retrieve: async (_collection, opts) => opts.ids.map((id) => ({
|
|
8
|
+
id,
|
|
9
|
+
payload: {
|
|
10
|
+
kind: "chunk",
|
|
11
|
+
text: `Full text for ${id}`,
|
|
12
|
+
path: "src/example.ts",
|
|
13
|
+
startLine: 1,
|
|
14
|
+
endLine: 10,
|
|
15
|
+
symbol: "example",
|
|
16
|
+
indexedAt: "2026-02-03T12:00:00.000Z",
|
|
17
|
+
source: "chunk",
|
|
18
|
+
},
|
|
19
|
+
})),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
describe("points batch API", () => {
|
|
23
|
+
it("returns 400 when ids is empty", async () => {
|
|
24
|
+
const app = Fastify();
|
|
25
|
+
registerPointsRoutes(app, { qdrantClient: createMockPointsClient() });
|
|
26
|
+
const res = await app.inject({
|
|
27
|
+
method: "POST",
|
|
28
|
+
url: "/points/batch",
|
|
29
|
+
payload: { ids: [] },
|
|
30
|
+
});
|
|
31
|
+
assert.strictEqual(res.statusCode, 400);
|
|
32
|
+
assert.match(JSON.parse(res.body).message, /non-empty/);
|
|
33
|
+
});
|
|
34
|
+
it("returns 400 when ids is not an array", async () => {
|
|
35
|
+
const app = Fastify();
|
|
36
|
+
registerPointsRoutes(app, { qdrantClient: createMockPointsClient() });
|
|
37
|
+
const res = await app.inject({
|
|
38
|
+
method: "POST",
|
|
39
|
+
url: "/points/batch",
|
|
40
|
+
payload: {},
|
|
41
|
+
});
|
|
42
|
+
assert.strictEqual(res.statusCode, 400);
|
|
43
|
+
});
|
|
44
|
+
it("returns 400 when ids exceeds max", async () => {
|
|
45
|
+
const app = Fastify();
|
|
46
|
+
registerPointsRoutes(app, { qdrantClient: createMockPointsClient() });
|
|
47
|
+
const ids = Array.from({ length: 25 }, (_, i) => `id-${i}`);
|
|
48
|
+
const res = await app.inject({
|
|
49
|
+
method: "POST",
|
|
50
|
+
url: "/points/batch",
|
|
51
|
+
payload: { ids },
|
|
52
|
+
});
|
|
53
|
+
assert.strictEqual(res.statusCode, 400);
|
|
54
|
+
assert.match(JSON.parse(res.body).message, /at most 20/);
|
|
55
|
+
});
|
|
56
|
+
it("returns 200 with items array and full metadata", async () => {
|
|
57
|
+
const app = Fastify();
|
|
58
|
+
registerPointsRoutes(app, { qdrantClient: createMockPointsClient() });
|
|
59
|
+
const res = await app.inject({
|
|
60
|
+
method: "POST",
|
|
61
|
+
url: "/points/batch",
|
|
62
|
+
payload: { ids: ["point-1", "point-2"] },
|
|
63
|
+
});
|
|
64
|
+
assert.strictEqual(res.statusCode, 200);
|
|
65
|
+
const body = JSON.parse(res.body);
|
|
66
|
+
assert.ok(Array.isArray(body.items));
|
|
67
|
+
assert.strictEqual(body.items.length, 2);
|
|
68
|
+
const item = body.items[0];
|
|
69
|
+
assert.strictEqual(item.id, "point-1");
|
|
70
|
+
assert.strictEqual(item.text, "Full text for point-1");
|
|
71
|
+
assert.strictEqual(item.path, "src/example.ts");
|
|
72
|
+
assert.strictEqual(item.startLine, 1);
|
|
73
|
+
assert.strictEqual(item.endLine, 10);
|
|
74
|
+
assert.strictEqual(item.symbol, "example");
|
|
75
|
+
assert.strictEqual(item.kind, "chunk");
|
|
76
|
+
assert.strictEqual(item.indexedAt, "2026-02-03T12:00:00.000Z");
|
|
77
|
+
assert.strictEqual(item.source, "chunk");
|
|
78
|
+
});
|
|
79
|
+
it("deduplicates ids", async () => {
|
|
80
|
+
const app = Fastify();
|
|
81
|
+
registerPointsRoutes(app, { qdrantClient: createMockPointsClient() });
|
|
82
|
+
const res = await app.inject({
|
|
83
|
+
method: "POST",
|
|
84
|
+
url: "/points/batch",
|
|
85
|
+
payload: { ids: ["a", "a", "b"] },
|
|
86
|
+
});
|
|
87
|
+
assert.strictEqual(res.statusCode, 200);
|
|
88
|
+
const body = JSON.parse(res.body);
|
|
89
|
+
assert.strictEqual(body.items.length, 2);
|
|
90
|
+
});
|
|
91
|
+
it("returns empty items when client returns no points", async () => {
|
|
92
|
+
const emptyMock = { retrieve: async () => [] };
|
|
93
|
+
const app = Fastify();
|
|
94
|
+
registerPointsRoutes(app, { qdrantClient: emptyMock });
|
|
95
|
+
const res = await app.inject({
|
|
96
|
+
method: "POST",
|
|
97
|
+
url: "/points/batch",
|
|
98
|
+
payload: { ids: ["missing-id"] },
|
|
99
|
+
});
|
|
100
|
+
assert.strictEqual(res.statusCode, 200);
|
|
101
|
+
const body = JSON.parse(res.body);
|
|
102
|
+
assert.strictEqual(body.items.length, 0);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
//# sourceMappingURL=points.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"points.test.js","sourceRoot":"","sources":["../../src/api/points.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import type { FastifyInstance } from "fastify";
|
|
2
|
+
import type { QdrantClient } from "@qdrant/js-client-rest";
|
|
2
3
|
export interface SearchBody {
|
|
3
4
|
query: string;
|
|
4
5
|
limit?: number;
|
|
6
|
+
refsOnly?: boolean;
|
|
7
|
+
intent?: "factual" | "planning" | "navigation";
|
|
8
|
+
kinds?: string[];
|
|
9
|
+
limitSystemMap?: number;
|
|
10
|
+
limitModuleSummary?: number;
|
|
11
|
+
limitChunks?: number;
|
|
5
12
|
}
|
|
6
13
|
export interface SearchResponse {
|
|
7
14
|
systemMaps: Array<{
|
|
@@ -19,10 +26,19 @@ export interface SearchResponse {
|
|
|
19
26
|
text: string;
|
|
20
27
|
path?: string;
|
|
21
28
|
score?: number;
|
|
29
|
+
startLine?: number;
|
|
30
|
+
endLine?: number;
|
|
31
|
+
symbol?: string;
|
|
32
|
+
kind?: string;
|
|
33
|
+
indexedAt?: string;
|
|
34
|
+
storedAt?: string;
|
|
35
|
+
source?: string;
|
|
36
|
+
supersededById?: string;
|
|
22
37
|
}>;
|
|
23
38
|
}
|
|
24
39
|
export declare function registerSearchRoutes(app: FastifyInstance, options: {
|
|
25
40
|
qdrantHost?: string;
|
|
26
41
|
qdrantPort?: number;
|
|
27
42
|
collection?: string;
|
|
43
|
+
qdrantClient?: QdrantClient;
|
|
28
44
|
}): void;
|
|
@@ -2,7 +2,8 @@ import { createQdrantClient } from "../qdrant/client.js";
|
|
|
2
2
|
import { embedText } from "../embedding/stub.js";
|
|
3
3
|
import { searchPoints, searchPointsKinds } from "../qdrant/client.js";
|
|
4
4
|
export function registerSearchRoutes(app, options) {
|
|
5
|
-
const client =
|
|
5
|
+
const client = options.qdrantClient ??
|
|
6
|
+
createQdrantClient(options.qdrantHost ?? "127.0.0.1", options.qdrantPort ?? 6333);
|
|
6
7
|
const collection = options.collection ?? "project_memory";
|
|
7
8
|
app.post("/search", {
|
|
8
9
|
schema: {
|
|
@@ -12,33 +13,50 @@ export function registerSearchRoutes(app, options) {
|
|
|
12
13
|
properties: {
|
|
13
14
|
query: { type: "string" },
|
|
14
15
|
limit: { type: "number" },
|
|
16
|
+
refsOnly: { type: "boolean" },
|
|
17
|
+
intent: { type: "string", enum: ["factual", "planning", "navigation"] },
|
|
18
|
+
kinds: { type: "array", items: { type: "string" } },
|
|
19
|
+
limitSystemMap: { type: "number" },
|
|
20
|
+
limitModuleSummary: { type: "number" },
|
|
21
|
+
limitChunks: { type: "number" },
|
|
15
22
|
},
|
|
16
23
|
},
|
|
17
24
|
},
|
|
18
25
|
}, async (request, reply) => {
|
|
19
|
-
const { query, limit = 20 } = request.body;
|
|
26
|
+
const { query, limit = 20, refsOnly = false, kinds, limitSystemMap = 5, limitModuleSummary = 10, limitChunks, } = request.body;
|
|
20
27
|
const vector = embedText(query ?? "");
|
|
28
|
+
const chunkKinds = kinds && kinds.length > 0 ? kinds : ["chunk", "entrypoint", "agent_note"];
|
|
29
|
+
const chunkLimit = limitChunks ?? limit;
|
|
21
30
|
const [systemMaps, moduleSummaries, chunks] = await Promise.all([
|
|
22
|
-
searchPoints(client, collection, vector,
|
|
23
|
-
searchPoints(client, collection, vector,
|
|
24
|
-
searchPointsKinds(client, collection, vector,
|
|
31
|
+
searchPoints(client, collection, vector, limitSystemMap, "system_map"),
|
|
32
|
+
searchPoints(client, collection, vector, limitModuleSummary, "module_summary"),
|
|
33
|
+
searchPointsKinds(client, collection, vector, chunkLimit, chunkKinds),
|
|
25
34
|
]);
|
|
35
|
+
const textForChunk = (raw, refsOnlyMode) => refsOnlyMode && raw.length > 80 ? raw.slice(0, 80) + "…" : raw;
|
|
26
36
|
const response = {
|
|
27
37
|
systemMaps: systemMaps.map((r) => ({
|
|
28
38
|
id: r.id,
|
|
29
|
-
text: r.payload.text ?? "",
|
|
39
|
+
text: textForChunk(r.payload.text ?? "", refsOnly),
|
|
30
40
|
path: r.payload.path,
|
|
31
41
|
})),
|
|
32
42
|
moduleSummaries: moduleSummaries.map((r) => ({
|
|
33
43
|
id: r.id,
|
|
34
|
-
text: r.payload.text ?? "",
|
|
44
|
+
text: textForChunk(r.payload.text ?? "", refsOnly),
|
|
35
45
|
path: r.payload.path,
|
|
36
46
|
})),
|
|
37
47
|
chunks: chunks.map((r) => ({
|
|
38
48
|
id: r.id,
|
|
39
|
-
text: r.payload.text ?? "",
|
|
49
|
+
text: textForChunk(r.payload.text ?? "", refsOnly),
|
|
40
50
|
path: r.payload.path,
|
|
41
51
|
score: r.score,
|
|
52
|
+
startLine: r.payload.startLine,
|
|
53
|
+
endLine: r.payload.endLine,
|
|
54
|
+
symbol: r.payload.symbol,
|
|
55
|
+
kind: r.payload.kind,
|
|
56
|
+
indexedAt: r.payload.indexedAt,
|
|
57
|
+
storedAt: r.payload.storedAt,
|
|
58
|
+
source: r.payload.source,
|
|
59
|
+
supersededById: r.payload.supersededById,
|
|
42
60
|
})),
|
|
43
61
|
};
|
|
44
62
|
await reply.send(response);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/api/search.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/api/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { strict as assert } from "node:assert";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import Fastify from "fastify";
|
|
4
|
+
import { registerSearchRoutes } from "./search.js";
|
|
5
|
+
function createMockSearchClient() {
|
|
6
|
+
const chunkPayload = {
|
|
7
|
+
kind: "chunk",
|
|
8
|
+
text: "some code content here that could be long",
|
|
9
|
+
path: "src/foo.ts",
|
|
10
|
+
startLine: 42,
|
|
11
|
+
endLine: 80,
|
|
12
|
+
symbol: "handleSubmit",
|
|
13
|
+
indexedAt: "2026-02-03T12:00:00.000Z",
|
|
14
|
+
source: "chunk",
|
|
15
|
+
};
|
|
16
|
+
const searchResult = [
|
|
17
|
+
{
|
|
18
|
+
id: "chunk-id-1",
|
|
19
|
+
score: 0.9,
|
|
20
|
+
payload: chunkPayload,
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
return {
|
|
24
|
+
getCollection: async () => ({ config: { params: { vectors: { default: {} } } } }),
|
|
25
|
+
search: async () => searchResult,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
describe("search API", () => {
|
|
29
|
+
it("returns 200 with systemMaps, moduleSummaries, chunks", async () => {
|
|
30
|
+
const app = Fastify();
|
|
31
|
+
registerSearchRoutes(app, { qdrantClient: createMockSearchClient() });
|
|
32
|
+
const res = await app.inject({
|
|
33
|
+
method: "POST",
|
|
34
|
+
url: "/search",
|
|
35
|
+
payload: { query: "auth flow", limit: 20 },
|
|
36
|
+
});
|
|
37
|
+
assert.strictEqual(res.statusCode, 200);
|
|
38
|
+
const body = JSON.parse(res.body);
|
|
39
|
+
assert.ok(Array.isArray(body.systemMaps));
|
|
40
|
+
assert.ok(Array.isArray(body.moduleSummaries));
|
|
41
|
+
assert.ok(Array.isArray(body.chunks));
|
|
42
|
+
});
|
|
43
|
+
it("returns chunks with anchor and freshness fields when present in payload", async () => {
|
|
44
|
+
const app = Fastify();
|
|
45
|
+
registerSearchRoutes(app, { qdrantClient: createMockSearchClient() });
|
|
46
|
+
const res = await app.inject({
|
|
47
|
+
method: "POST",
|
|
48
|
+
url: "/search",
|
|
49
|
+
payload: { query: "test" },
|
|
50
|
+
});
|
|
51
|
+
assert.strictEqual(res.statusCode, 200);
|
|
52
|
+
const body = JSON.parse(res.body);
|
|
53
|
+
assert.ok(body.chunks.length >= 1);
|
|
54
|
+
const c = body.chunks[0];
|
|
55
|
+
assert.strictEqual(c.path, "src/foo.ts");
|
|
56
|
+
assert.strictEqual(c.startLine, 42);
|
|
57
|
+
assert.strictEqual(c.endLine, 80);
|
|
58
|
+
assert.strictEqual(c.symbol, "handleSubmit");
|
|
59
|
+
assert.strictEqual(c.kind, "chunk");
|
|
60
|
+
assert.strictEqual(c.indexedAt, "2026-02-03T12:00:00.000Z");
|
|
61
|
+
assert.strictEqual(c.source, "chunk");
|
|
62
|
+
});
|
|
63
|
+
it("refsOnly truncates chunk text to 80 chars", async () => {
|
|
64
|
+
const longText = "x".repeat(100);
|
|
65
|
+
const app = Fastify();
|
|
66
|
+
const mockClient = {
|
|
67
|
+
getCollection: async () => ({ config: { params: { vectors: { default: {} } } } }),
|
|
68
|
+
search: async () => [
|
|
69
|
+
{
|
|
70
|
+
id: "id1",
|
|
71
|
+
score: 0.9,
|
|
72
|
+
payload: { kind: "chunk", text: longText },
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
registerSearchRoutes(app, { qdrantClient: mockClient });
|
|
77
|
+
const res = await app.inject({
|
|
78
|
+
method: "POST",
|
|
79
|
+
url: "/search",
|
|
80
|
+
payload: { query: "test", refsOnly: true },
|
|
81
|
+
});
|
|
82
|
+
assert.strictEqual(res.statusCode, 200);
|
|
83
|
+
const body = JSON.parse(res.body);
|
|
84
|
+
assert.ok(body.chunks[0].text.length <= 81);
|
|
85
|
+
assert.match(body.chunks[0].text, /…$/);
|
|
86
|
+
});
|
|
87
|
+
it("accepts optional kinds and intent", async () => {
|
|
88
|
+
const app = Fastify();
|
|
89
|
+
registerSearchRoutes(app, { qdrantClient: createMockSearchClient() });
|
|
90
|
+
const res = await app.inject({
|
|
91
|
+
method: "POST",
|
|
92
|
+
url: "/search",
|
|
93
|
+
payload: {
|
|
94
|
+
query: "session summary",
|
|
95
|
+
kinds: ["agent_note"],
|
|
96
|
+
intent: "planning",
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
assert.strictEqual(res.statusCode, 200);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=search.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.test.js","sourceRoot":"","sources":["../../src/api/search.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { FastifyInstance } from "fastify";
|
|
2
|
+
import type { QdrantClient } from "@qdrant/js-client-rest";
|
|
2
3
|
export interface StoreBody {
|
|
3
4
|
content: string;
|
|
4
5
|
title?: string;
|
|
5
6
|
path?: string;
|
|
7
|
+
startLine?: number;
|
|
8
|
+
endLine?: number;
|
|
9
|
+
symbol?: string;
|
|
10
|
+
scope?: string;
|
|
11
|
+
supersedesId?: string;
|
|
6
12
|
}
|
|
7
13
|
export declare function registerStoreRoutes(app: FastifyInstance, options: {
|
|
8
14
|
qdrantHost?: string;
|
|
9
15
|
qdrantPort?: number;
|
|
10
16
|
collection?: string;
|
|
17
|
+
qdrantClient?: QdrantClient;
|
|
11
18
|
}): void;
|
|
@@ -9,11 +9,14 @@ function buildTextToEmbed(body) {
|
|
|
9
9
|
parts.push(`File: ${body.path}`);
|
|
10
10
|
if (body.title)
|
|
11
11
|
parts.push(`Title: ${body.title}`);
|
|
12
|
+
if (body.symbol)
|
|
13
|
+
parts.push(`Symbol: ${body.symbol}`);
|
|
12
14
|
parts.push(body.content);
|
|
13
15
|
return parts.join("\n\n");
|
|
14
16
|
}
|
|
15
17
|
export function registerStoreRoutes(app, options) {
|
|
16
|
-
const client =
|
|
18
|
+
const client = options.qdrantClient ??
|
|
19
|
+
createQdrantClient(options.qdrantHost ?? "127.0.0.1", options.qdrantPort ?? 6333);
|
|
17
20
|
const collection = options.collection ?? "project_memory";
|
|
18
21
|
app.post("/store", {
|
|
19
22
|
schema: {
|
|
@@ -24,15 +27,43 @@ export function registerStoreRoutes(app, options) {
|
|
|
24
27
|
content: { type: "string" },
|
|
25
28
|
title: { type: ["string", "null"] },
|
|
26
29
|
path: { type: ["string", "null"] },
|
|
30
|
+
startLine: { type: ["number", "null"] },
|
|
31
|
+
endLine: { type: ["number", "null"] },
|
|
32
|
+
symbol: { type: ["string", "null"] },
|
|
33
|
+
scope: { type: ["string", "null"] },
|
|
34
|
+
supersedesId: { type: ["string", "null"] },
|
|
27
35
|
},
|
|
28
36
|
},
|
|
29
37
|
},
|
|
30
38
|
}, async (request, reply) => {
|
|
31
39
|
const raw = request.body;
|
|
40
|
+
const startLine = raw.startLine != null ? Number(raw.startLine) : undefined;
|
|
41
|
+
const endLine = raw.endLine != null ? Number(raw.endLine) : undefined;
|
|
42
|
+
if (startLine != null && (!Number.isInteger(startLine) || startLine < 1)) {
|
|
43
|
+
await reply.status(400).send({
|
|
44
|
+
statusCode: 400,
|
|
45
|
+
error: "Bad Request",
|
|
46
|
+
message: "startLine must be a positive integer when provided",
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (endLine != null && (!Number.isInteger(endLine) || endLine < 1)) {
|
|
51
|
+
await reply.status(400).send({
|
|
52
|
+
statusCode: 400,
|
|
53
|
+
error: "Bad Request",
|
|
54
|
+
message: "endLine must be a positive integer when provided",
|
|
55
|
+
});
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
32
58
|
const body = {
|
|
33
59
|
content: raw.content ?? "",
|
|
34
60
|
title: raw.title ?? undefined,
|
|
35
61
|
path: raw.path ?? undefined,
|
|
62
|
+
startLine,
|
|
63
|
+
endLine,
|
|
64
|
+
symbol: raw.symbol ?? undefined,
|
|
65
|
+
scope: raw.scope ?? undefined,
|
|
66
|
+
supersedesId: raw.supersedesId ?? undefined,
|
|
36
67
|
};
|
|
37
68
|
const content = body.content.trim();
|
|
38
69
|
if (!content) {
|
|
@@ -46,17 +77,29 @@ export function registerStoreRoutes(app, options) {
|
|
|
46
77
|
const textToEmbed = buildTextToEmbed({ ...body, content });
|
|
47
78
|
const vector = embedText(textToEmbed);
|
|
48
79
|
const id = randomUUID();
|
|
80
|
+
const storedAt = new Date().toISOString();
|
|
81
|
+
const source = body.title?.trim().toLowerCase().startsWith("session summary")
|
|
82
|
+
? "session-summary"
|
|
83
|
+
: "store";
|
|
84
|
+
const payload = {
|
|
85
|
+
kind: KIND_AGENT_NOTE,
|
|
86
|
+
path: body.path,
|
|
87
|
+
title: body.title,
|
|
88
|
+
text: content,
|
|
89
|
+
storedAt,
|
|
90
|
+
source,
|
|
91
|
+
...(body.startLine != null && { startLine: body.startLine }),
|
|
92
|
+
...(body.endLine != null && { endLine: body.endLine }),
|
|
93
|
+
...(body.symbol != null && { symbol: body.symbol }),
|
|
94
|
+
...(body.scope != null && { scope: body.scope }),
|
|
95
|
+
...(body.supersedesId != null && { supersedesId: body.supersedesId }),
|
|
96
|
+
};
|
|
49
97
|
await ensureCollection(client, collection);
|
|
50
98
|
await upsertPoints(client, collection, [
|
|
51
99
|
{
|
|
52
100
|
id,
|
|
53
101
|
vector,
|
|
54
|
-
payload
|
|
55
|
-
kind: KIND_AGENT_NOTE,
|
|
56
|
-
path: body.path,
|
|
57
|
-
title: body.title,
|
|
58
|
-
text: content,
|
|
59
|
-
},
|
|
102
|
+
payload,
|
|
60
103
|
},
|
|
61
104
|
]);
|
|
62
105
|
await reply.send({ id: `${KIND_AGENT_NOTE}:${id}`, message: "Stored." });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/api/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/api/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|