@pentatonic-ai/ai-agent-sdk 0.5.9 → 0.5.10
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pentatonic-ai/ai-agent-sdk",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.10",
|
|
4
4
|
"description": "TES SDK — LLM observability and lifecycle tracking via Pentatonic Thing Event System. Track token usage, tool calls, and conversations. Manage things through event-sourced lifecycle stages with AI enrichment and vector search.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -709,6 +709,37 @@ describe("ingest dedup option", () => {
|
|
|
709
709
|
expect(inserted[0].client_id).toBe("c");
|
|
710
710
|
});
|
|
711
711
|
|
|
712
|
+
it("opts.dedupContent: matches against the raw form, stores the wrapped form", async () => {
|
|
713
|
+
const { db, inserted } = makeMockDb({
|
|
714
|
+
existing: [
|
|
715
|
+
// Row was stored on a previous run with a 10:00 timestamp prefix
|
|
716
|
+
{
|
|
717
|
+
id: "mem_legacy",
|
|
718
|
+
client_id: "c",
|
|
719
|
+
content: "[2026-04-26T10:00:00Z] Caroline went to a support group",
|
|
720
|
+
},
|
|
721
|
+
],
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
const out = await ingest(
|
|
725
|
+
db,
|
|
726
|
+
mockAi,
|
|
727
|
+
mockLlm,
|
|
728
|
+
// The retry would store with a fresh timestamp — strict-equality
|
|
729
|
+
// would miss the dup. dedupContent makes us match on the raw form.
|
|
730
|
+
"[2026-04-26T10:00:01Z] Caroline went to a support group",
|
|
731
|
+
{
|
|
732
|
+
clientId: "c",
|
|
733
|
+
dedup: true,
|
|
734
|
+
dedupContent: "Caroline went to a support group",
|
|
735
|
+
}
|
|
736
|
+
);
|
|
737
|
+
|
|
738
|
+
expect(out.deduped).toBe(true);
|
|
739
|
+
expect(out.id).toBe("mem_legacy");
|
|
740
|
+
expect(inserted).toHaveLength(0);
|
|
741
|
+
});
|
|
742
|
+
|
|
712
743
|
it("dedup check failure falls through to insert (best-effort semantics)", async () => {
|
|
713
744
|
let dupCheckSql = null;
|
|
714
745
|
const flakyDb = async (sql, params) => {
|
|
@@ -31,6 +31,12 @@ import { distill } from "./distill.js";
|
|
|
31
31
|
* `dedup:false` behaviour). The eventual structural fix is a
|
|
32
32
|
* `UNIQUE(client_id, content_hash)` constraint at the schema level;
|
|
33
33
|
* this option is the bridge.
|
|
34
|
+
* @param {string} [opts.dedupContent] - Optional: the string to dedup
|
|
35
|
+
* against, when it differs from what gets stored. Use when callers
|
|
36
|
+
* wrap the stored content in a non-stable prefix (timestamps, run
|
|
37
|
+
* ids) — pass the raw form here so retries of the same logical event
|
|
38
|
+
* match across runs whose prefixes differ by a few ms. Defaults to
|
|
39
|
+
* `content`.
|
|
34
40
|
* @returns {Promise<{id: string, content: string, layerId: string, deduped?: boolean}>}
|
|
35
41
|
*/
|
|
36
42
|
export async function ingest(db, ai, llm, content, opts = {}) {
|
|
@@ -54,17 +60,21 @@ export async function ingest(db, ai, llm, content, opts = {}) {
|
|
|
54
60
|
|
|
55
61
|
// Optional dedup: skip the insert (and all the embedding/HyDE/distill
|
|
56
62
|
// work that would follow) if a row with byte-equal content already
|
|
57
|
-
// exists for this tenant. The
|
|
58
|
-
//
|
|
63
|
+
// exists for this tenant. The dedup key is `opts.dedupContent` if
|
|
64
|
+
// provided (use for callers that wrap the stored form in a non-stable
|
|
65
|
+
// prefix like a timestamp), else `content`. The OR-LIKE branch matches
|
|
66
|
+
// against legacy `[<iso>] <content>` rows so callers that wrote with a
|
|
59
67
|
// timestamp prefix dedup correctly until the legacy corpus ages out.
|
|
60
68
|
if (opts.dedup) {
|
|
69
|
+
const dedupKey =
|
|
70
|
+
typeof opts.dedupContent === "string" ? opts.dedupContent : content;
|
|
61
71
|
try {
|
|
62
72
|
const dupCheck = await db(
|
|
63
73
|
`SELECT id FROM memory_nodes
|
|
64
74
|
WHERE client_id = $1
|
|
65
75
|
AND (content = $2 OR content LIKE '%] ' || $2)
|
|
66
76
|
LIMIT 1`,
|
|
67
|
-
[clientId,
|
|
77
|
+
[clientId, dedupKey]
|
|
68
78
|
);
|
|
69
79
|
if (dupCheck.rows?.length) {
|
|
70
80
|
log(`dedup: matched existing memory ${dupCheck.rows[0].id}`);
|