@kernl-sdk/pg 0.1.22 → 0.1.24
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +17 -0
- package/dist/__tests__/memory-integration.test.d.ts.map +1 -1
- package/dist/__tests__/memory-integration.test.js +54 -5
- package/dist/thread/store.d.ts.map +1 -1
- package/dist/thread/store.js +5 -1
- package/package.json +6 -6
- package/src/__tests__/memory-integration.test.ts +67 -9
- package/src/thread/store.ts +9 -1
package/.turbo/turbo-build.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @kernl/pg
|
|
2
2
|
|
|
3
|
+
## 0.1.24
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [572ae80]
|
|
8
|
+
- kernl@0.9.0
|
|
9
|
+
- @kernl-sdk/retrieval@0.1.4
|
|
10
|
+
- @kernl-sdk/storage@0.1.24
|
|
11
|
+
|
|
12
|
+
## 0.1.23
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies [e90b227]
|
|
17
|
+
- kernl@0.8.4
|
|
18
|
+
- @kernl-sdk/storage@0.1.23
|
|
19
|
+
|
|
3
20
|
## 0.1.22
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/memory-integration.test.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"memory-integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/memory-integration.test.ts"],"names":[],"mappings":"AAKA,OAAO,sBAAsB,CAAC"}
|
|
@@ -26,7 +26,7 @@ describe.sequential("Memory Integration with PGVector", { timeout: 30000 }, () =
|
|
|
26
26
|
vector: pgvector({ pool }),
|
|
27
27
|
},
|
|
28
28
|
memory: {
|
|
29
|
-
|
|
29
|
+
embedding: "openai/text-embedding-3-small",
|
|
30
30
|
dimensions: 1536,
|
|
31
31
|
},
|
|
32
32
|
});
|
|
@@ -204,7 +204,7 @@ describe.sequential("Memory Integration with PGVector", { timeout: 30000 }, () =
|
|
|
204
204
|
vector: pgvector({ pool }),
|
|
205
205
|
},
|
|
206
206
|
memory: {
|
|
207
|
-
|
|
207
|
+
embedding: "openai/text-embedding-3-small",
|
|
208
208
|
dimensions: 1536,
|
|
209
209
|
},
|
|
210
210
|
});
|
|
@@ -253,13 +253,62 @@ describe.sequential("Memory Integration with PGVector", { timeout: 30000 }, () =
|
|
|
253
253
|
id: "m1",
|
|
254
254
|
metadata: { version: 2, updated: true },
|
|
255
255
|
});
|
|
256
|
-
// Verify metadata updated in
|
|
257
|
-
const
|
|
258
|
-
expect(
|
|
256
|
+
// Verify metadata updated in primary DB (metadata is not indexed)
|
|
257
|
+
const dbResult = await pool.query('SELECT metadata FROM "kernl"."memories" WHERE id = $1', ["m1"]);
|
|
258
|
+
expect(dbResult.rows[0].metadata).toEqual({
|
|
259
259
|
version: 2,
|
|
260
260
|
updated: true,
|
|
261
261
|
});
|
|
262
262
|
});
|
|
263
|
+
it("isolates memories by agentId", async () => {
|
|
264
|
+
// Register two agents
|
|
265
|
+
const model = {
|
|
266
|
+
spec: "1.0",
|
|
267
|
+
provider: "test",
|
|
268
|
+
modelId: "test-model",
|
|
269
|
+
};
|
|
270
|
+
const agent1 = new Agent({
|
|
271
|
+
id: "test-agent-1",
|
|
272
|
+
name: "Test Agent 1",
|
|
273
|
+
instructions: () => "test instructions",
|
|
274
|
+
model,
|
|
275
|
+
});
|
|
276
|
+
const agent2 = new Agent({
|
|
277
|
+
id: "test-agent-2",
|
|
278
|
+
name: "Test Agent 2",
|
|
279
|
+
instructions: () => "test instructions",
|
|
280
|
+
model,
|
|
281
|
+
});
|
|
282
|
+
kernl.register(agent1);
|
|
283
|
+
kernl.register(agent2);
|
|
284
|
+
// Create memories for each agent in the same namespace
|
|
285
|
+
await agent1.memories.create({
|
|
286
|
+
namespace: "shared-ns",
|
|
287
|
+
collection: "facts",
|
|
288
|
+
content: { text: "Agent 1 knows about cats" },
|
|
289
|
+
});
|
|
290
|
+
await agent2.memories.create({
|
|
291
|
+
namespace: "shared-ns",
|
|
292
|
+
collection: "facts",
|
|
293
|
+
content: { text: "Agent 2 knows about cats" },
|
|
294
|
+
});
|
|
295
|
+
// Search from agent1 - should only see agent1's memory
|
|
296
|
+
const results1 = await agent1.memories.search({
|
|
297
|
+
query: "cats",
|
|
298
|
+
filter: { scope: { namespace: "shared-ns" } },
|
|
299
|
+
limit: 10,
|
|
300
|
+
});
|
|
301
|
+
// Search from agent2 - should only see agent2's memory
|
|
302
|
+
const results2 = await agent2.memories.search({
|
|
303
|
+
query: "cats",
|
|
304
|
+
filter: { scope: { namespace: "shared-ns" } },
|
|
305
|
+
limit: 10,
|
|
306
|
+
});
|
|
307
|
+
expect(results1).toHaveLength(1);
|
|
308
|
+
expect(results1[0].document?.agentId).toBe("test-agent-1");
|
|
309
|
+
expect(results2).toHaveLength(1);
|
|
310
|
+
expect(results2[0].document?.agentId).toBe("test-agent-2");
|
|
311
|
+
});
|
|
263
312
|
it("creates memories with multimodal content", async () => {
|
|
264
313
|
await kernl.memories.create({
|
|
265
314
|
id: "m1",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/thread/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAE3C,OAAO,
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/thread/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAE3C,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAC1B,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAIL,KAAK,YAAY,EAElB,MAAM,oBAAoB,CAAC;AAI5B;;;;;GAKG;AACH,qBAAa,aAAc,YAAW,WAAW;IAC/C,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,UAAU,CAA0D;IAC5E,OAAO,CAAC,UAAU,CAAsB;gBAE5B,EAAE,EAAE,IAAI,GAAG,UAAU,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAMlE;;;;OAIG;IACH,IAAI,CAAC,UAAU,EAAE;QAAE,MAAM,EAAE,aAAa,CAAC;QAAC,MAAM,EAAE,aAAa,CAAA;KAAE,GAAG,IAAI;IAIxE;;OAEG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAuGvE;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAuC1D;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IA4BhD;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAkB/D;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQxC;;OAEG;IACG,OAAO,CACX,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,oBAAoB,GAC1B,OAAO,CAAC,WAAW,EAAE,CAAC;IAuCzB;;;;;;;;;OASG;IACG,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAmClD;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,YAAY,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,EAAE,CAAA;KAAE,GAAG,MAAM;CA0C1E"}
|
package/dist/thread/store.js
CHANGED
|
@@ -267,8 +267,12 @@ export class PGThreadStore {
|
|
|
267
267
|
if (!agent || !model) {
|
|
268
268
|
throw new Error(`Thread ${record.id} references non-existent agent/model (agent: ${record.agent_id}, model: ${record.model})`);
|
|
269
269
|
}
|
|
270
|
+
// safety: threads only exist for llm agents
|
|
271
|
+
if (agent.kind !== "llm") {
|
|
272
|
+
throw new Error(`Thread ${record.id} references non-llm agent ${record.agent_id} (kind: ${agent.kind})`);
|
|
273
|
+
}
|
|
270
274
|
return new Thread({
|
|
271
|
-
agent,
|
|
275
|
+
agent: agent,
|
|
272
276
|
history: events,
|
|
273
277
|
context: new Context(record.namespace, record.context),
|
|
274
278
|
model,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kernl-sdk/pg",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"description": "PostgreSQL storage adapter for kernl",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kernl",
|
|
@@ -35,15 +35,15 @@
|
|
|
35
35
|
"tsc-alias": "^1.8.10",
|
|
36
36
|
"typescript": "5.9.2",
|
|
37
37
|
"vitest": "^4.0.8",
|
|
38
|
-
"@kernl-sdk/
|
|
39
|
-
"@kernl-sdk/
|
|
38
|
+
"@kernl-sdk/ai": "^0.3.1",
|
|
39
|
+
"@kernl-sdk/protocol": "^0.3.0"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"pg": "^8.16.3",
|
|
43
|
-
"kernl": "^0.
|
|
44
|
-
"@kernl-sdk/retrieval": "^0.1.
|
|
43
|
+
"kernl": "^0.9.0",
|
|
44
|
+
"@kernl-sdk/retrieval": "^0.1.4",
|
|
45
45
|
"@kernl-sdk/shared": "^0.3.0",
|
|
46
|
-
"@kernl-sdk/storage": "0.1.
|
|
46
|
+
"@kernl-sdk/storage": "0.1.24"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"clean": "rm -rf dist",
|
|
@@ -2,6 +2,7 @@ import { describe, it, expect, beforeAll, afterAll, beforeEach } from "vitest";
|
|
|
2
2
|
import { Pool } from "pg";
|
|
3
3
|
import { Kernl, Agent } from "kernl";
|
|
4
4
|
import type { LanguageModel } from "@kernl-sdk/protocol";
|
|
5
|
+
import type { SearchHit } from "@kernl-sdk/retrieval";
|
|
5
6
|
import "@kernl-sdk/ai/openai"; // Register OpenAI embedding provider
|
|
6
7
|
|
|
7
8
|
import { postgres, pgvector } from "../index";
|
|
@@ -38,7 +39,7 @@ describe.sequential(
|
|
|
38
39
|
vector: pgvector({ pool }),
|
|
39
40
|
},
|
|
40
41
|
memory: {
|
|
41
|
-
|
|
42
|
+
embedding: "openai/text-embedding-3-small",
|
|
42
43
|
dimensions: 1536,
|
|
43
44
|
},
|
|
44
45
|
});
|
|
@@ -149,7 +150,7 @@ describe.sequential(
|
|
|
149
150
|
expect(results.length).toBeGreaterThan(0);
|
|
150
151
|
|
|
151
152
|
// Should find TypeScript-related memories with higher scores
|
|
152
|
-
const ids = results.map((r) => r.document?.id);
|
|
153
|
+
const ids = results.map((r: SearchHit) => r.document?.id);
|
|
153
154
|
expect(ids).toContain("m1"); // Direct match
|
|
154
155
|
expect(ids).toContain("m3"); // Related to TypeScript
|
|
155
156
|
});
|
|
@@ -255,7 +256,7 @@ describe.sequential(
|
|
|
255
256
|
vector: pgvector({ pool }),
|
|
256
257
|
},
|
|
257
258
|
memory: {
|
|
258
|
-
|
|
259
|
+
embedding: "openai/text-embedding-3-small",
|
|
259
260
|
dimensions: 1536,
|
|
260
261
|
},
|
|
261
262
|
});
|
|
@@ -292,7 +293,7 @@ describe.sequential(
|
|
|
292
293
|
});
|
|
293
294
|
|
|
294
295
|
expect(results.length).toBeGreaterThan(0);
|
|
295
|
-
const match = results.find((r) => r.document?.id === "m1");
|
|
296
|
+
const match = results.find((r: SearchHit) => r.document?.id === "m1");
|
|
296
297
|
expect(match).toBeDefined();
|
|
297
298
|
expect(match?.document?.text).toBe("Updated content about cats");
|
|
298
299
|
});
|
|
@@ -313,18 +314,75 @@ describe.sequential(
|
|
|
313
314
|
metadata: { version: 2, updated: true },
|
|
314
315
|
});
|
|
315
316
|
|
|
316
|
-
// Verify metadata updated in
|
|
317
|
-
const
|
|
318
|
-
'SELECT metadata FROM "kernl"."
|
|
317
|
+
// Verify metadata updated in primary DB (metadata is not indexed)
|
|
318
|
+
const dbResult = await pool.query(
|
|
319
|
+
'SELECT metadata FROM "kernl"."memories" WHERE id = $1',
|
|
319
320
|
["m1"],
|
|
320
321
|
);
|
|
321
322
|
|
|
322
|
-
expect(
|
|
323
|
+
expect(dbResult.rows[0].metadata).toEqual({
|
|
323
324
|
version: 2,
|
|
324
325
|
updated: true,
|
|
325
326
|
});
|
|
326
327
|
});
|
|
327
328
|
|
|
329
|
+
it("isolates memories by agentId", async () => {
|
|
330
|
+
// Register two agents
|
|
331
|
+
const model = {
|
|
332
|
+
spec: "1.0" as const,
|
|
333
|
+
provider: "test",
|
|
334
|
+
modelId: "test-model",
|
|
335
|
+
} as unknown as LanguageModel;
|
|
336
|
+
|
|
337
|
+
const agent1 = new Agent({
|
|
338
|
+
id: "test-agent-1",
|
|
339
|
+
name: "Test Agent 1",
|
|
340
|
+
instructions: () => "test instructions",
|
|
341
|
+
model,
|
|
342
|
+
});
|
|
343
|
+
const agent2 = new Agent({
|
|
344
|
+
id: "test-agent-2",
|
|
345
|
+
name: "Test Agent 2",
|
|
346
|
+
instructions: () => "test instructions",
|
|
347
|
+
model,
|
|
348
|
+
});
|
|
349
|
+
kernl.register(agent1);
|
|
350
|
+
kernl.register(agent2);
|
|
351
|
+
|
|
352
|
+
// Create memories for each agent in the same namespace
|
|
353
|
+
await agent1.memories.create({
|
|
354
|
+
namespace: "shared-ns",
|
|
355
|
+
collection: "facts",
|
|
356
|
+
content: { text: "Agent 1 knows about cats" },
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
await agent2.memories.create({
|
|
360
|
+
namespace: "shared-ns",
|
|
361
|
+
collection: "facts",
|
|
362
|
+
content: { text: "Agent 2 knows about cats" },
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// Search from agent1 - should only see agent1's memory
|
|
366
|
+
const results1 = await agent1.memories.search({
|
|
367
|
+
query: "cats",
|
|
368
|
+
filter: { scope: { namespace: "shared-ns" } },
|
|
369
|
+
limit: 10,
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
// Search from agent2 - should only see agent2's memory
|
|
373
|
+
const results2 = await agent2.memories.search({
|
|
374
|
+
query: "cats",
|
|
375
|
+
filter: { scope: { namespace: "shared-ns" } },
|
|
376
|
+
limit: 10,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
expect(results1).toHaveLength(1);
|
|
380
|
+
expect(results1[0].document?.agentId).toBe("test-agent-1");
|
|
381
|
+
|
|
382
|
+
expect(results2).toHaveLength(1);
|
|
383
|
+
expect(results2[0].document?.agentId).toBe("test-agent-2");
|
|
384
|
+
});
|
|
385
|
+
|
|
328
386
|
it("creates memories with multimodal content", async () => {
|
|
329
387
|
await kernl.memories.create({
|
|
330
388
|
id: "m1",
|
|
@@ -348,7 +406,7 @@ describe.sequential(
|
|
|
348
406
|
});
|
|
349
407
|
|
|
350
408
|
expect(results.length).toBeGreaterThan(0);
|
|
351
|
-
const match = results.find((r) => r.document?.id === "m1");
|
|
409
|
+
const match = results.find((r: SearchHit) => r.document?.id === "m1");
|
|
352
410
|
expect(match).toBeDefined();
|
|
353
411
|
});
|
|
354
412
|
},
|
package/src/thread/store.ts
CHANGED
|
@@ -2,6 +2,7 @@ import assert from "assert";
|
|
|
2
2
|
import type { Pool, PoolClient } from "pg";
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
+
Agent,
|
|
5
6
|
Context,
|
|
6
7
|
type AgentRegistry,
|
|
7
8
|
type ModelRegistry,
|
|
@@ -371,8 +372,15 @@ export class PGThreadStore implements ThreadStore {
|
|
|
371
372
|
);
|
|
372
373
|
}
|
|
373
374
|
|
|
375
|
+
// safety: threads only exist for llm agents
|
|
376
|
+
if (agent.kind !== "llm") {
|
|
377
|
+
throw new Error(
|
|
378
|
+
`Thread ${record.id} references non-llm agent ${record.agent_id} (kind: ${agent.kind})`,
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
374
382
|
return new Thread({
|
|
375
|
-
agent,
|
|
383
|
+
agent: agent as Agent,
|
|
376
384
|
history: events,
|
|
377
385
|
context: new Context(record.namespace, record.context),
|
|
378
386
|
model,
|