opencode-graphiti 0.0.0-development
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/LICENSE +21 -0
- package/README.md +358 -0
- package/esm/_dnt.polyfills.d.ts +166 -0
- package/esm/_dnt.polyfills.d.ts.map +1 -0
- package/esm/_dnt.polyfills.js +177 -0
- package/esm/_dnt.shims.d.ts +6 -0
- package/esm/_dnt.shims.d.ts.map +1 -0
- package/esm/_dnt.shims.js +61 -0
- package/esm/deno.d.ts +45 -0
- package/esm/deno.d.ts.map +1 -0
- package/esm/deno.js +39 -0
- package/esm/mod.d.ts +3 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +2 -0
- package/esm/package.json +3 -0
- package/esm/src/config.d.ts +20 -0
- package/esm/src/config.d.ts.map +1 -0
- package/esm/src/config.js +246 -0
- package/esm/src/handlers/chat.d.ts +14 -0
- package/esm/src/handlers/chat.d.ts.map +1 -0
- package/esm/src/handlers/chat.js +60 -0
- package/esm/src/handlers/compacting.d.ts +9 -0
- package/esm/src/handlers/compacting.d.ts.map +1 -0
- package/esm/src/handlers/compacting.js +30 -0
- package/esm/src/handlers/event.d.ts +22 -0
- package/esm/src/handlers/event.d.ts.map +1 -0
- package/esm/src/handlers/event.js +287 -0
- package/esm/src/handlers/messages.d.ts +9 -0
- package/esm/src/handlers/messages.d.ts.map +1 -0
- package/esm/src/handlers/messages.js +93 -0
- package/esm/src/index.d.ts +5 -0
- package/esm/src/index.d.ts.map +1 -0
- package/esm/src/index.js +153 -0
- package/esm/src/services/batch-drain.d.ts +23 -0
- package/esm/src/services/batch-drain.d.ts.map +1 -0
- package/esm/src/services/batch-drain.js +217 -0
- package/esm/src/services/connection-manager.d.ts +104 -0
- package/esm/src/services/connection-manager.d.ts.map +1 -0
- package/esm/src/services/connection-manager.js +621 -0
- package/esm/src/services/constants.d.ts +7 -0
- package/esm/src/services/constants.d.ts.map +1 -0
- package/esm/src/services/constants.js +6 -0
- package/esm/src/services/context-limit.d.ts +3 -0
- package/esm/src/services/context-limit.d.ts.map +1 -0
- package/esm/src/services/context-limit.js +44 -0
- package/esm/src/services/event-extractor.d.ts +29 -0
- package/esm/src/services/event-extractor.d.ts.map +1 -0
- package/esm/src/services/event-extractor.js +659 -0
- package/esm/src/services/graphiti-async.d.ts +22 -0
- package/esm/src/services/graphiti-async.d.ts.map +1 -0
- package/esm/src/services/graphiti-async.js +219 -0
- package/esm/src/services/graphiti-mcp.d.ts +57 -0
- package/esm/src/services/graphiti-mcp.d.ts.map +1 -0
- package/esm/src/services/graphiti-mcp.js +194 -0
- package/esm/src/services/logger.d.ts +9 -0
- package/esm/src/services/logger.d.ts.map +1 -0
- package/esm/src/services/logger.js +104 -0
- package/esm/src/services/opencode-warning.d.ts +8 -0
- package/esm/src/services/opencode-warning.d.ts.map +1 -0
- package/esm/src/services/opencode-warning.js +104 -0
- package/esm/src/services/redis-cache.d.ts +27 -0
- package/esm/src/services/redis-cache.d.ts.map +1 -0
- package/esm/src/services/redis-cache.js +215 -0
- package/esm/src/services/redis-client.d.ts +89 -0
- package/esm/src/services/redis-client.d.ts.map +1 -0
- package/esm/src/services/redis-client.js +906 -0
- package/esm/src/services/redis-events.d.ts +46 -0
- package/esm/src/services/redis-events.d.ts.map +1 -0
- package/esm/src/services/redis-events.js +517 -0
- package/esm/src/services/redis-snapshot.d.ts +16 -0
- package/esm/src/services/redis-snapshot.d.ts.map +1 -0
- package/esm/src/services/redis-snapshot.js +184 -0
- package/esm/src/services/render-utils.d.ts +23 -0
- package/esm/src/services/render-utils.d.ts.map +1 -0
- package/esm/src/services/render-utils.js +149 -0
- package/esm/src/services/runtime-teardown.d.ts +23 -0
- package/esm/src/services/runtime-teardown.d.ts.map +1 -0
- package/esm/src/services/runtime-teardown.js +119 -0
- package/esm/src/services/sdk-normalize.d.ts +55 -0
- package/esm/src/services/sdk-normalize.d.ts.map +1 -0
- package/esm/src/services/sdk-normalize.js +61 -0
- package/esm/src/session.d.ts +74 -0
- package/esm/src/session.d.ts.map +1 -0
- package/esm/src/session.js +694 -0
- package/esm/src/types/index.d.ts +120 -0
- package/esm/src/types/index.d.ts.map +1 -0
- package/esm/src/types/index.js +28 -0
- package/esm/src/utils.d.ts +27 -0
- package/esm/src/utils.d.ts.map +1 -0
- package/esm/src/utils.js +76 -0
- package/package.json +59 -0
- package/script/_dnt.polyfills.d.ts +166 -0
- package/script/_dnt.polyfills.d.ts.map +1 -0
- package/script/_dnt.polyfills.js +180 -0
- package/script/_dnt.shims.d.ts +6 -0
- package/script/_dnt.shims.d.ts.map +1 -0
- package/script/_dnt.shims.js +65 -0
- package/script/deno.d.ts +45 -0
- package/script/deno.d.ts.map +1 -0
- package/script/deno.js +41 -0
- package/script/mod.d.ts +3 -0
- package/script/mod.d.ts.map +1 -0
- package/script/mod.js +6 -0
- package/script/package.json +3 -0
- package/script/src/config.d.ts +20 -0
- package/script/src/config.d.ts.map +1 -0
- package/script/src/config.js +256 -0
- package/script/src/handlers/chat.d.ts +14 -0
- package/script/src/handlers/chat.d.ts.map +1 -0
- package/script/src/handlers/chat.js +63 -0
- package/script/src/handlers/compacting.d.ts +9 -0
- package/script/src/handlers/compacting.d.ts.map +1 -0
- package/script/src/handlers/compacting.js +33 -0
- package/script/src/handlers/event.d.ts +22 -0
- package/script/src/handlers/event.d.ts.map +1 -0
- package/script/src/handlers/event.js +290 -0
- package/script/src/handlers/messages.d.ts +9 -0
- package/script/src/handlers/messages.d.ts.map +1 -0
- package/script/src/handlers/messages.js +96 -0
- package/script/src/index.d.ts +5 -0
- package/script/src/index.d.ts.map +1 -0
- package/script/src/index.js +159 -0
- package/script/src/services/batch-drain.d.ts +23 -0
- package/script/src/services/batch-drain.d.ts.map +1 -0
- package/script/src/services/batch-drain.js +221 -0
- package/script/src/services/connection-manager.d.ts +104 -0
- package/script/src/services/connection-manager.d.ts.map +1 -0
- package/script/src/services/connection-manager.js +635 -0
- package/script/src/services/constants.d.ts +7 -0
- package/script/src/services/constants.d.ts.map +1 -0
- package/script/src/services/constants.js +9 -0
- package/script/src/services/context-limit.d.ts +3 -0
- package/script/src/services/context-limit.d.ts.map +1 -0
- package/script/src/services/context-limit.js +47 -0
- package/script/src/services/event-extractor.d.ts +29 -0
- package/script/src/services/event-extractor.d.ts.map +1 -0
- package/script/src/services/event-extractor.js +669 -0
- package/script/src/services/graphiti-async.d.ts +22 -0
- package/script/src/services/graphiti-async.d.ts.map +1 -0
- package/script/src/services/graphiti-async.js +223 -0
- package/script/src/services/graphiti-mcp.d.ts +57 -0
- package/script/src/services/graphiti-mcp.d.ts.map +1 -0
- package/script/src/services/graphiti-mcp.js +198 -0
- package/script/src/services/logger.d.ts +9 -0
- package/script/src/services/logger.d.ts.map +1 -0
- package/script/src/services/logger.js +142 -0
- package/script/src/services/opencode-warning.d.ts +8 -0
- package/script/src/services/opencode-warning.d.ts.map +1 -0
- package/script/src/services/opencode-warning.js +114 -0
- package/script/src/services/redis-cache.d.ts +27 -0
- package/script/src/services/redis-cache.d.ts.map +1 -0
- package/script/src/services/redis-cache.js +219 -0
- package/script/src/services/redis-client.d.ts +89 -0
- package/script/src/services/redis-client.d.ts.map +1 -0
- package/script/src/services/redis-client.js +943 -0
- package/script/src/services/redis-events.d.ts +46 -0
- package/script/src/services/redis-events.d.ts.map +1 -0
- package/script/src/services/redis-events.js +535 -0
- package/script/src/services/redis-snapshot.d.ts +16 -0
- package/script/src/services/redis-snapshot.d.ts.map +1 -0
- package/script/src/services/redis-snapshot.js +189 -0
- package/script/src/services/render-utils.d.ts +23 -0
- package/script/src/services/render-utils.d.ts.map +1 -0
- package/script/src/services/render-utils.js +165 -0
- package/script/src/services/runtime-teardown.d.ts +23 -0
- package/script/src/services/runtime-teardown.d.ts.map +1 -0
- package/script/src/services/runtime-teardown.js +155 -0
- package/script/src/services/sdk-normalize.d.ts +55 -0
- package/script/src/services/sdk-normalize.d.ts.map +1 -0
- package/script/src/services/sdk-normalize.js +67 -0
- package/script/src/session.d.ts +74 -0
- package/script/src/session.d.ts.map +1 -0
- package/script/src/session.js +698 -0
- package/script/src/types/index.d.ts +120 -0
- package/script/src/types/index.d.ts.map +1 -0
- package/script/src/types/index.js +33 -0
- package/script/src/utils.d.ts +27 -0
- package/script/src/utils.d.ts.map +1 -0
- package/script/src/utils.js +87 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const console = globalThis.console;
|
|
2
|
+
const PREFIX = "[graphiti]";
|
|
3
|
+
let openCodeClient;
|
|
4
|
+
let scheduleTask = (callback) => {
|
|
5
|
+
setTimeout(callback, 0);
|
|
6
|
+
};
|
|
7
|
+
let suppressConsoleWarningsDuringTestsOverride;
|
|
8
|
+
export const shouldSuppressConsoleWarningsDuringTests = () => {
|
|
9
|
+
if (suppressConsoleWarningsDuringTestsOverride !== undefined) {
|
|
10
|
+
return suppressConsoleWarningsDuringTestsOverride;
|
|
11
|
+
}
|
|
12
|
+
const stack = new Error().stack;
|
|
13
|
+
return typeof stack === "string" && stack.includes("ext:cli/40_test.js");
|
|
14
|
+
};
|
|
15
|
+
const warnToConsole = (message, extra, error) => {
|
|
16
|
+
if (shouldSuppressConsoleWarningsDuringTests())
|
|
17
|
+
return;
|
|
18
|
+
if (extra === undefined) {
|
|
19
|
+
if (error === undefined) {
|
|
20
|
+
console.warn(PREFIX, message);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
console.warn(PREFIX, message, error);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (error === undefined) {
|
|
27
|
+
console.warn(PREFIX, message, extra);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
console.warn(PREFIX, message, extra, error);
|
|
31
|
+
};
|
|
32
|
+
const asRecord = (value) => {
|
|
33
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
return { data: value };
|
|
37
|
+
};
|
|
38
|
+
const getClient = () => {
|
|
39
|
+
return openCodeClient;
|
|
40
|
+
};
|
|
41
|
+
const runSafely = (task, onError) => {
|
|
42
|
+
try {
|
|
43
|
+
scheduleTask(() => {
|
|
44
|
+
try {
|
|
45
|
+
void Promise.resolve(task()).catch((err) => onError?.(err));
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
onError?.(err);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const scheduleStructuredWarning = (message, extra) => {
|
|
58
|
+
const client = getClient();
|
|
59
|
+
if (!client?.app?.log)
|
|
60
|
+
return false;
|
|
61
|
+
return runSafely(() => client.app.log({
|
|
62
|
+
body: {
|
|
63
|
+
service: "graphiti",
|
|
64
|
+
level: "warn",
|
|
65
|
+
message,
|
|
66
|
+
...(extra === undefined ? {} : { extra: asRecord(extra) }),
|
|
67
|
+
},
|
|
68
|
+
}), (error) => warnToConsole(message, extra, error));
|
|
69
|
+
};
|
|
70
|
+
const scheduleWarningToast = (message, extra) => {
|
|
71
|
+
const client = getClient();
|
|
72
|
+
if (!client?.tui?.showToast)
|
|
73
|
+
return false;
|
|
74
|
+
return runSafely(() => client.tui.showToast({
|
|
75
|
+
body: {
|
|
76
|
+
message,
|
|
77
|
+
variant: "warning",
|
|
78
|
+
},
|
|
79
|
+
}), (error) => warnToConsole(message, extra, error));
|
|
80
|
+
};
|
|
81
|
+
export const setOpenCodeClient = (client) => {
|
|
82
|
+
openCodeClient = client;
|
|
83
|
+
};
|
|
84
|
+
export const setWarningTaskScheduler = (scheduler) => {
|
|
85
|
+
scheduleTask = scheduler ?? ((callback) => {
|
|
86
|
+
setTimeout(callback, 0);
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
export const setSuppressConsoleWarningsDuringTestsOverride = (value) => {
|
|
90
|
+
suppressConsoleWarningsDuringTestsOverride = value;
|
|
91
|
+
};
|
|
92
|
+
export const logStructuredWarning = (message, extra) => {
|
|
93
|
+
return scheduleStructuredWarning(message, extra);
|
|
94
|
+
};
|
|
95
|
+
export const showWarningToast = (message, extra) => {
|
|
96
|
+
return scheduleWarningToast(message, extra);
|
|
97
|
+
};
|
|
98
|
+
export const notifyGraphitiAvailabilityIssue = (message, extra) => {
|
|
99
|
+
const logged = scheduleStructuredWarning(message, extra);
|
|
100
|
+
const toasted = scheduleWarningToast(message, extra);
|
|
101
|
+
if (!logged && !toasted) {
|
|
102
|
+
warnToConsole(message, extra);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CacheRefreshDecision, PersistentMemoryCacheEntry, PersistentMemoryCacheMeta } from "../types/index.js";
|
|
2
|
+
import type { RedisClient } from "./redis-client.js";
|
|
3
|
+
export interface RedisCacheServiceOptions {
|
|
4
|
+
ttlSeconds: number;
|
|
5
|
+
driftThreshold: number;
|
|
6
|
+
}
|
|
7
|
+
export declare const PERSISTENT_MEMORY_BODY_BUDGET = 1800;
|
|
8
|
+
export declare class RedisCacheService {
|
|
9
|
+
private readonly redis;
|
|
10
|
+
private readonly options;
|
|
11
|
+
constructor(redis: RedisClient, options: RedisCacheServiceOptions);
|
|
12
|
+
get(groupId: string): Promise<PersistentMemoryCacheEntry | null>;
|
|
13
|
+
getMeta(groupId: string): Promise<PersistentMemoryCacheMeta | null>;
|
|
14
|
+
rememberRefreshQuery(groupId: string, query: string): Promise<void>;
|
|
15
|
+
touchEntry(groupId: string): Promise<void>;
|
|
16
|
+
touchMeta(groupId: string): Promise<void>;
|
|
17
|
+
touch(groupId: string): Promise<void>;
|
|
18
|
+
set(groupId: string, entry: PersistentMemoryCacheEntry): Promise<void>;
|
|
19
|
+
isStale(entry: PersistentMemoryCacheEntry): boolean;
|
|
20
|
+
classifyRefresh(entry: PersistentMemoryCacheEntry | null, query: string): CacheRefreshDecision;
|
|
21
|
+
shouldRefresh(entry: PersistentMemoryCacheEntry | null, query: string): boolean;
|
|
22
|
+
renderPersistentMemory(entry: PersistentMemoryCacheEntry | null, budget?: number): {
|
|
23
|
+
body: string;
|
|
24
|
+
nodeRefs: string[];
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=redis-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-cache.d.ts","sourceRoot":"","sources":["../../../src/src/services/redis-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EAEpB,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAkBrD,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB;AAKD,eAAO,MAAM,6BAA6B,OAAQ,CAAC;AAgDnD,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,wBAAwB;IAG9C,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC;IAUhE,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC;IAenE,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWnE,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1C,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOzC,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOrC,GAAG,CACP,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,IAAI,CAAC;IA+BhB,OAAO,CAAC,KAAK,EAAE,0BAA0B,GAAG,OAAO;IAInD,eAAe,CACb,KAAK,EAAE,0BAA0B,GAAG,IAAI,EACxC,KAAK,EAAE,MAAM,GACZ,oBAAoB;IAmDvB,aAAa,CACX,KAAK,EAAE,0BAA0B,GAAG,IAAI,EACxC,KAAK,EAAE,MAAM,GACZ,OAAO;IAIV,sBAAsB,CACpB,KAAK,EAAE,0BAA0B,GAAG,IAAI,EACxC,MAAM,SAAgC,GACrC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE;CAwDxC"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { memoryCacheKey, memoryCacheMetaKey } from "./redis-events.js";
|
|
2
|
+
import { escapeXml, isHighValueMemoryText, looksLikeOperationalChatter, looksLikeToolTranscript, looksTranscriptHeavy, normalizeMemoryText, sanitizeMemoryInput, stripInjectedMemoryBlocks, } from "./render-utils.js";
|
|
3
|
+
const formatNode = (node) => sanitizeMemoryInput(stripInjectedMemoryBlocks(node.summary ? `${node.name}: ${node.summary}` : node.name));
|
|
4
|
+
const TOKEN_PATTERN = /[a-z0-9._/-]{2,}/g;
|
|
5
|
+
const NODE_RENDER_LIMIT = 180;
|
|
6
|
+
const EPISODE_RENDER_LIMIT = 180;
|
|
7
|
+
export const PERSISTENT_MEMORY_BODY_BUDGET = 1_800;
|
|
8
|
+
const isLowValuePersistentText = (value) => {
|
|
9
|
+
const sanitized = sanitizeMemoryInput(value);
|
|
10
|
+
if (!sanitized)
|
|
11
|
+
return true;
|
|
12
|
+
if (looksLikeToolTranscript(sanitized))
|
|
13
|
+
return true;
|
|
14
|
+
if (looksLikeOperationalChatter(sanitized))
|
|
15
|
+
return true;
|
|
16
|
+
if (looksTranscriptHeavy(sanitized))
|
|
17
|
+
return true;
|
|
18
|
+
return !isHighValueMemoryText(sanitized);
|
|
19
|
+
};
|
|
20
|
+
const distinctByNormalized = (values, getText) => {
|
|
21
|
+
const seen = new Set();
|
|
22
|
+
const result = [];
|
|
23
|
+
for (const value of values) {
|
|
24
|
+
const normalized = normalizeMemoryText(getText(value));
|
|
25
|
+
if (!normalized || seen.has(normalized))
|
|
26
|
+
continue;
|
|
27
|
+
seen.add(normalized);
|
|
28
|
+
result.push(value);
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
};
|
|
32
|
+
const normalizeQuery = (query) => query.trim().toLowerCase();
|
|
33
|
+
const tokenizeQuery = (query) => {
|
|
34
|
+
const normalized = normalizeQuery(query);
|
|
35
|
+
return new Set(normalized.match(TOKEN_PATTERN) ?? []);
|
|
36
|
+
};
|
|
37
|
+
const jaccardSimilarity = (left, right) => {
|
|
38
|
+
const leftTokens = tokenizeQuery(left);
|
|
39
|
+
const rightTokens = tokenizeQuery(right);
|
|
40
|
+
if (leftTokens.size === 0 && rightTokens.size === 0)
|
|
41
|
+
return 1;
|
|
42
|
+
if (leftTokens.size === 0 || rightTokens.size === 0)
|
|
43
|
+
return 0;
|
|
44
|
+
let intersection = 0;
|
|
45
|
+
for (const token of leftTokens) {
|
|
46
|
+
if (rightTokens.has(token))
|
|
47
|
+
intersection += 1;
|
|
48
|
+
}
|
|
49
|
+
const union = new Set([...leftTokens, ...rightTokens]).size;
|
|
50
|
+
return union === 0 ? 0 : intersection / union;
|
|
51
|
+
};
|
|
52
|
+
export class RedisCacheService {
|
|
53
|
+
constructor(redis, options) {
|
|
54
|
+
Object.defineProperty(this, "redis", {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
configurable: true,
|
|
57
|
+
writable: true,
|
|
58
|
+
value: redis
|
|
59
|
+
});
|
|
60
|
+
Object.defineProperty(this, "options", {
|
|
61
|
+
enumerable: true,
|
|
62
|
+
configurable: true,
|
|
63
|
+
writable: true,
|
|
64
|
+
value: options
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async get(groupId) {
|
|
68
|
+
const raw = await this.redis.getString(memoryCacheKey(groupId));
|
|
69
|
+
if (!raw)
|
|
70
|
+
return null;
|
|
71
|
+
try {
|
|
72
|
+
return JSON.parse(raw);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async getMeta(groupId) {
|
|
79
|
+
const raw = await this.redis.getHashAll(memoryCacheMetaKey(groupId));
|
|
80
|
+
if (Object.keys(raw).length === 0)
|
|
81
|
+
return null;
|
|
82
|
+
const hasLastRefresh = Object.hasOwn(raw, "lastRefresh");
|
|
83
|
+
const parsedLastRefresh = hasLastRefresh ? Number(raw.lastRefresh) : NaN;
|
|
84
|
+
return {
|
|
85
|
+
lastQuery: raw.lastQuery?.trim() || undefined,
|
|
86
|
+
lastRefresh: Number.isFinite(parsedLastRefresh)
|
|
87
|
+
? parsedLastRefresh
|
|
88
|
+
: undefined,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
async rememberRefreshQuery(groupId, query) {
|
|
92
|
+
const normalized = sanitizeMemoryInput(stripInjectedMemoryBlocks(query));
|
|
93
|
+
if (!normalized)
|
|
94
|
+
return;
|
|
95
|
+
await this.redis.setHashFields(memoryCacheMetaKey(groupId), { lastQuery: normalized }, this.options.ttlSeconds);
|
|
96
|
+
}
|
|
97
|
+
async touchEntry(groupId) {
|
|
98
|
+
await this.redis.touch(memoryCacheKey(groupId), this.options.ttlSeconds);
|
|
99
|
+
}
|
|
100
|
+
async touchMeta(groupId) {
|
|
101
|
+
await this.redis.touch(memoryCacheMetaKey(groupId), this.options.ttlSeconds);
|
|
102
|
+
}
|
|
103
|
+
async touch(groupId) {
|
|
104
|
+
await Promise.all([
|
|
105
|
+
this.touchEntry(groupId),
|
|
106
|
+
this.touchMeta(groupId),
|
|
107
|
+
]);
|
|
108
|
+
}
|
|
109
|
+
async set(groupId, entry) {
|
|
110
|
+
const sanitizedEntry = {
|
|
111
|
+
query: sanitizeMemoryInput(stripInjectedMemoryBlocks(entry.query)),
|
|
112
|
+
refreshedAt: entry.refreshedAt,
|
|
113
|
+
nodes: entry.nodes.map((node) => ({
|
|
114
|
+
...node,
|
|
115
|
+
name: sanitizeMemoryInput(stripInjectedMemoryBlocks(node.name)),
|
|
116
|
+
summary: node.summary
|
|
117
|
+
? sanitizeMemoryInput(stripInjectedMemoryBlocks(node.summary))
|
|
118
|
+
: undefined,
|
|
119
|
+
})).filter((node) => node.name),
|
|
120
|
+
episodeSummaries: entry.episodeSummaries?.map((episode) => sanitizeMemoryInput(stripInjectedMemoryBlocks(episode))).filter(Boolean),
|
|
121
|
+
nodeRefs: [...entry.nodeRefs],
|
|
122
|
+
};
|
|
123
|
+
await this.redis.setString(memoryCacheKey(groupId), JSON.stringify(sanitizedEntry), this.options.ttlSeconds);
|
|
124
|
+
await this.redis.setHashFields(memoryCacheMetaKey(groupId), {
|
|
125
|
+
lastQuery: sanitizedEntry.query,
|
|
126
|
+
lastRefresh: sanitizedEntry.refreshedAt,
|
|
127
|
+
}, this.options.ttlSeconds);
|
|
128
|
+
}
|
|
129
|
+
isStale(entry) {
|
|
130
|
+
return Date.now() - entry.refreshedAt > this.options.ttlSeconds * 1000;
|
|
131
|
+
}
|
|
132
|
+
classifyRefresh(entry, query) {
|
|
133
|
+
if (!entry) {
|
|
134
|
+
return {
|
|
135
|
+
classification: "miss",
|
|
136
|
+
shouldRefresh: true,
|
|
137
|
+
similarity: 0,
|
|
138
|
+
threshold: this.options.driftThreshold,
|
|
139
|
+
cachedQuery: null,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (this.isStale(entry)) {
|
|
143
|
+
return {
|
|
144
|
+
classification: "stale",
|
|
145
|
+
shouldRefresh: true,
|
|
146
|
+
similarity: 0,
|
|
147
|
+
threshold: this.options.driftThreshold,
|
|
148
|
+
cachedQuery: entry.query,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const normalizedQuery = normalizeQuery(query);
|
|
152
|
+
const normalizedCachedQuery = normalizeQuery(entry.query);
|
|
153
|
+
const hasPrimerEpisodes = (entry.episodeSummaries?.length ?? 0) > 0;
|
|
154
|
+
const hasNodes = entry.nodes.length > 0;
|
|
155
|
+
if (normalizedCachedQuery === "primer" &&
|
|
156
|
+
normalizedQuery &&
|
|
157
|
+
hasPrimerEpisodes &&
|
|
158
|
+
!hasNodes) {
|
|
159
|
+
return {
|
|
160
|
+
classification: "primer-only",
|
|
161
|
+
shouldRefresh: true,
|
|
162
|
+
similarity: 0,
|
|
163
|
+
threshold: this.options.driftThreshold,
|
|
164
|
+
cachedQuery: entry.query,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
const similarity = jaccardSimilarity(entry.query, query);
|
|
168
|
+
const aligned = similarity >= this.options.driftThreshold;
|
|
169
|
+
return {
|
|
170
|
+
classification: aligned ? "aligned" : "drifted",
|
|
171
|
+
shouldRefresh: !aligned,
|
|
172
|
+
similarity,
|
|
173
|
+
threshold: this.options.driftThreshold,
|
|
174
|
+
cachedQuery: entry.query,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
shouldRefresh(entry, query) {
|
|
178
|
+
return this.classifyRefresh(entry, query).shouldRefresh;
|
|
179
|
+
}
|
|
180
|
+
renderPersistentMemory(entry, budget = PERSISTENT_MEMORY_BODY_BUDGET) {
|
|
181
|
+
if (!entry)
|
|
182
|
+
return { body: "", nodeRefs: [] };
|
|
183
|
+
const nodes = distinctByNormalized(entry.nodes.filter((node) => {
|
|
184
|
+
const rendered = formatNode(node);
|
|
185
|
+
return !isLowValuePersistentText(rendered);
|
|
186
|
+
}), (node) => formatNode(node));
|
|
187
|
+
const episodes = distinctByNormalized((entry.episodeSummaries ?? []).filter((episode) => !isLowValuePersistentText(episode)), (episode) => sanitizeMemoryInput(stripInjectedMemoryBlocks(episode)));
|
|
188
|
+
const sections = [];
|
|
189
|
+
const nodeRefs = [];
|
|
190
|
+
let remaining = Math.max(0, budget);
|
|
191
|
+
for (const node of nodes.slice(0, 3)) {
|
|
192
|
+
const renderedNode = formatNode(node).slice(0, NODE_RENDER_LIMIT);
|
|
193
|
+
if (!renderedNode)
|
|
194
|
+
continue;
|
|
195
|
+
const section = `<node>${escapeXml(renderedNode)}</node>`;
|
|
196
|
+
if (section.length > remaining)
|
|
197
|
+
break;
|
|
198
|
+
sections.push(section);
|
|
199
|
+
nodeRefs.push(node.uuid);
|
|
200
|
+
remaining -= section.length;
|
|
201
|
+
}
|
|
202
|
+
for (const episode of episodes.slice(0, 2)) {
|
|
203
|
+
const renderedEpisode = sanitizeMemoryInput(episode).slice(0, EPISODE_RENDER_LIMIT);
|
|
204
|
+
const sanitizedEpisode = sanitizeMemoryInput(stripInjectedMemoryBlocks(renderedEpisode)).slice(0, EPISODE_RENDER_LIMIT);
|
|
205
|
+
if (!sanitizedEpisode)
|
|
206
|
+
continue;
|
|
207
|
+
const section = `<episode>${escapeXml(sanitizedEpisode)}</episode>`;
|
|
208
|
+
if (section.length > remaining)
|
|
209
|
+
break;
|
|
210
|
+
sections.push(section);
|
|
211
|
+
remaining -= section.length;
|
|
212
|
+
}
|
|
213
|
+
return { body: sections.join(""), nodeRefs };
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
type RedisEvent = "close" | "end" | "error" | "ready";
|
|
2
|
+
type RedisRuntime = {
|
|
3
|
+
ping(): Promise<unknown>;
|
|
4
|
+
quit(): Promise<unknown>;
|
|
5
|
+
lpush(key: string, value: string): Promise<number>;
|
|
6
|
+
rpush(key: string, value: string): Promise<number>;
|
|
7
|
+
lmove(source: string, destination: string, sourceSide: "LEFT" | "RIGHT", destinationSide: "LEFT" | "RIGHT"): Promise<string | null>;
|
|
8
|
+
lrange(key: string, start: number, stop: number): Promise<string[]>;
|
|
9
|
+
llen(key: string): Promise<number>;
|
|
10
|
+
ltrim(key: string, start: number, stop: number): Promise<unknown>;
|
|
11
|
+
lindex(key: string, index: number): Promise<string | null>;
|
|
12
|
+
lset(key: string, index: number, value: string): Promise<unknown>;
|
|
13
|
+
get(key: string): Promise<string | null>;
|
|
14
|
+
hset?(key: string, values: Record<string, string>): Promise<number>;
|
|
15
|
+
hgetall?(key: string): Promise<Record<string, string>>;
|
|
16
|
+
set(key: string, value: string, ...args: Array<string | number>): Promise<unknown>;
|
|
17
|
+
expire(key: string, ttlSeconds: number): Promise<number>;
|
|
18
|
+
del(key: string): Promise<number>;
|
|
19
|
+
eval?(script: string, numKeys: number, ...args: string[]): Promise<number>;
|
|
20
|
+
connect?(): Promise<void>;
|
|
21
|
+
on?(event: RedisEvent, listener: (...args: unknown[]) => void): unknown;
|
|
22
|
+
off?(event: RedisEvent, listener: (...args: unknown[]) => void): unknown;
|
|
23
|
+
};
|
|
24
|
+
type RedisRuntimeFactory = (endpoint: string) => Promise<RedisRuntime> | RedisRuntime;
|
|
25
|
+
export interface RedisClientOptions {
|
|
26
|
+
endpoint: string;
|
|
27
|
+
reconnectBaseDelayMs?: number;
|
|
28
|
+
reconnectMaxDelayMs?: number;
|
|
29
|
+
runtimeFactory?: RedisRuntimeFactory;
|
|
30
|
+
}
|
|
31
|
+
export declare class RedisClient {
|
|
32
|
+
private readonly options;
|
|
33
|
+
private readonly memory;
|
|
34
|
+
private readonly hashFallbackKeys;
|
|
35
|
+
private readonly pendingFallbackReplays;
|
|
36
|
+
private readonly runtimeListeners;
|
|
37
|
+
private redis;
|
|
38
|
+
private connected;
|
|
39
|
+
private closed;
|
|
40
|
+
private finalizingRuntime;
|
|
41
|
+
private reconnectTimer;
|
|
42
|
+
private reconnectAttempts;
|
|
43
|
+
private connectAttempt;
|
|
44
|
+
constructor(options: RedisClientOptions);
|
|
45
|
+
connect(): Promise<void>;
|
|
46
|
+
isConnected(): boolean;
|
|
47
|
+
close(): Promise<void>;
|
|
48
|
+
private getReconnectDelayMs;
|
|
49
|
+
private clearReconnectTimer;
|
|
50
|
+
private scheduleReconnect;
|
|
51
|
+
private createRuntime;
|
|
52
|
+
private attachRuntimeListeners;
|
|
53
|
+
private detachRuntimeListeners;
|
|
54
|
+
private replaceRuntime;
|
|
55
|
+
private disposeFailedRuntime;
|
|
56
|
+
private handleDisconnect;
|
|
57
|
+
private tryConnectOnce;
|
|
58
|
+
private useRuntime;
|
|
59
|
+
private queuePendingFallbackReplay;
|
|
60
|
+
private replayPendingFallbackMutations;
|
|
61
|
+
private queuePendingStringSnapshotReplay;
|
|
62
|
+
private queuePendingHashSnapshotReplay;
|
|
63
|
+
private isDurableDrainKey;
|
|
64
|
+
private replaceMemoryList;
|
|
65
|
+
private syncNonDurableSourceListAfterLiveMove;
|
|
66
|
+
private syncNonDurableDestinationListAfterLiveMove;
|
|
67
|
+
private useMutationRuntime;
|
|
68
|
+
prependToList(key: string, value: string, ttlSeconds?: number): Promise<number>;
|
|
69
|
+
appendToList(key: string, value: string, ttlSeconds?: number): Promise<number>;
|
|
70
|
+
getRecentList(key: string, limit: number): Promise<string[]>;
|
|
71
|
+
getOldestList(key: string, limit: number): Promise<string[]>;
|
|
72
|
+
getListRange(key: string, start: number, stop: number): Promise<string[]>;
|
|
73
|
+
getListItem(key: string, index: number): Promise<string | null>;
|
|
74
|
+
setListItem(key: string, index: number, value: string): Promise<void>;
|
|
75
|
+
getListLength(key: string): Promise<number>;
|
|
76
|
+
moveListItem(source: string, destination: string, sourceSide: "LEFT" | "RIGHT", destinationSide: "LEFT" | "RIGHT"): Promise<string | null>;
|
|
77
|
+
trimOldest(key: string, count: number): Promise<void>;
|
|
78
|
+
getString(key: string): Promise<string | null>;
|
|
79
|
+
setString(key: string, value: string, ttlSeconds?: number): Promise<void>;
|
|
80
|
+
setStringIfAbsent(key: string, value: string, ttlSeconds?: number): Promise<boolean>;
|
|
81
|
+
touch(key: string, ttlSeconds: number): Promise<void>;
|
|
82
|
+
getHashAll(key: string): Promise<Record<string, string>>;
|
|
83
|
+
setHashFields(key: string, values: Record<string, string | number | undefined>, ttlSeconds?: number): Promise<void>;
|
|
84
|
+
compareAndTouch(key: string, expectedValue: string, ttlSeconds: number): Promise<boolean>;
|
|
85
|
+
deleteKey(key: string): Promise<void>;
|
|
86
|
+
deleteKeyIfValue(key: string, expectedValue: string): Promise<boolean>;
|
|
87
|
+
}
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=redis-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-client.d.ts","sourceRoot":"","sources":["../../../src/src/services/redis-client.ts"],"names":[],"mappings":"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"}
|