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.
Files changed (179) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +358 -0
  3. package/esm/_dnt.polyfills.d.ts +166 -0
  4. package/esm/_dnt.polyfills.d.ts.map +1 -0
  5. package/esm/_dnt.polyfills.js +177 -0
  6. package/esm/_dnt.shims.d.ts +6 -0
  7. package/esm/_dnt.shims.d.ts.map +1 -0
  8. package/esm/_dnt.shims.js +61 -0
  9. package/esm/deno.d.ts +45 -0
  10. package/esm/deno.d.ts.map +1 -0
  11. package/esm/deno.js +39 -0
  12. package/esm/mod.d.ts +3 -0
  13. package/esm/mod.d.ts.map +1 -0
  14. package/esm/mod.js +2 -0
  15. package/esm/package.json +3 -0
  16. package/esm/src/config.d.ts +20 -0
  17. package/esm/src/config.d.ts.map +1 -0
  18. package/esm/src/config.js +246 -0
  19. package/esm/src/handlers/chat.d.ts +14 -0
  20. package/esm/src/handlers/chat.d.ts.map +1 -0
  21. package/esm/src/handlers/chat.js +60 -0
  22. package/esm/src/handlers/compacting.d.ts +9 -0
  23. package/esm/src/handlers/compacting.d.ts.map +1 -0
  24. package/esm/src/handlers/compacting.js +30 -0
  25. package/esm/src/handlers/event.d.ts +22 -0
  26. package/esm/src/handlers/event.d.ts.map +1 -0
  27. package/esm/src/handlers/event.js +287 -0
  28. package/esm/src/handlers/messages.d.ts +9 -0
  29. package/esm/src/handlers/messages.d.ts.map +1 -0
  30. package/esm/src/handlers/messages.js +93 -0
  31. package/esm/src/index.d.ts +5 -0
  32. package/esm/src/index.d.ts.map +1 -0
  33. package/esm/src/index.js +153 -0
  34. package/esm/src/services/batch-drain.d.ts +23 -0
  35. package/esm/src/services/batch-drain.d.ts.map +1 -0
  36. package/esm/src/services/batch-drain.js +217 -0
  37. package/esm/src/services/connection-manager.d.ts +104 -0
  38. package/esm/src/services/connection-manager.d.ts.map +1 -0
  39. package/esm/src/services/connection-manager.js +621 -0
  40. package/esm/src/services/constants.d.ts +7 -0
  41. package/esm/src/services/constants.d.ts.map +1 -0
  42. package/esm/src/services/constants.js +6 -0
  43. package/esm/src/services/context-limit.d.ts +3 -0
  44. package/esm/src/services/context-limit.d.ts.map +1 -0
  45. package/esm/src/services/context-limit.js +44 -0
  46. package/esm/src/services/event-extractor.d.ts +29 -0
  47. package/esm/src/services/event-extractor.d.ts.map +1 -0
  48. package/esm/src/services/event-extractor.js +659 -0
  49. package/esm/src/services/graphiti-async.d.ts +22 -0
  50. package/esm/src/services/graphiti-async.d.ts.map +1 -0
  51. package/esm/src/services/graphiti-async.js +219 -0
  52. package/esm/src/services/graphiti-mcp.d.ts +57 -0
  53. package/esm/src/services/graphiti-mcp.d.ts.map +1 -0
  54. package/esm/src/services/graphiti-mcp.js +194 -0
  55. package/esm/src/services/logger.d.ts +9 -0
  56. package/esm/src/services/logger.d.ts.map +1 -0
  57. package/esm/src/services/logger.js +104 -0
  58. package/esm/src/services/opencode-warning.d.ts +8 -0
  59. package/esm/src/services/opencode-warning.d.ts.map +1 -0
  60. package/esm/src/services/opencode-warning.js +104 -0
  61. package/esm/src/services/redis-cache.d.ts +27 -0
  62. package/esm/src/services/redis-cache.d.ts.map +1 -0
  63. package/esm/src/services/redis-cache.js +215 -0
  64. package/esm/src/services/redis-client.d.ts +89 -0
  65. package/esm/src/services/redis-client.d.ts.map +1 -0
  66. package/esm/src/services/redis-client.js +906 -0
  67. package/esm/src/services/redis-events.d.ts +46 -0
  68. package/esm/src/services/redis-events.d.ts.map +1 -0
  69. package/esm/src/services/redis-events.js +517 -0
  70. package/esm/src/services/redis-snapshot.d.ts +16 -0
  71. package/esm/src/services/redis-snapshot.d.ts.map +1 -0
  72. package/esm/src/services/redis-snapshot.js +184 -0
  73. package/esm/src/services/render-utils.d.ts +23 -0
  74. package/esm/src/services/render-utils.d.ts.map +1 -0
  75. package/esm/src/services/render-utils.js +149 -0
  76. package/esm/src/services/runtime-teardown.d.ts +23 -0
  77. package/esm/src/services/runtime-teardown.d.ts.map +1 -0
  78. package/esm/src/services/runtime-teardown.js +119 -0
  79. package/esm/src/services/sdk-normalize.d.ts +55 -0
  80. package/esm/src/services/sdk-normalize.d.ts.map +1 -0
  81. package/esm/src/services/sdk-normalize.js +61 -0
  82. package/esm/src/session.d.ts +74 -0
  83. package/esm/src/session.d.ts.map +1 -0
  84. package/esm/src/session.js +694 -0
  85. package/esm/src/types/index.d.ts +120 -0
  86. package/esm/src/types/index.d.ts.map +1 -0
  87. package/esm/src/types/index.js +28 -0
  88. package/esm/src/utils.d.ts +27 -0
  89. package/esm/src/utils.d.ts.map +1 -0
  90. package/esm/src/utils.js +76 -0
  91. package/package.json +59 -0
  92. package/script/_dnt.polyfills.d.ts +166 -0
  93. package/script/_dnt.polyfills.d.ts.map +1 -0
  94. package/script/_dnt.polyfills.js +180 -0
  95. package/script/_dnt.shims.d.ts +6 -0
  96. package/script/_dnt.shims.d.ts.map +1 -0
  97. package/script/_dnt.shims.js +65 -0
  98. package/script/deno.d.ts +45 -0
  99. package/script/deno.d.ts.map +1 -0
  100. package/script/deno.js +41 -0
  101. package/script/mod.d.ts +3 -0
  102. package/script/mod.d.ts.map +1 -0
  103. package/script/mod.js +6 -0
  104. package/script/package.json +3 -0
  105. package/script/src/config.d.ts +20 -0
  106. package/script/src/config.d.ts.map +1 -0
  107. package/script/src/config.js +256 -0
  108. package/script/src/handlers/chat.d.ts +14 -0
  109. package/script/src/handlers/chat.d.ts.map +1 -0
  110. package/script/src/handlers/chat.js +63 -0
  111. package/script/src/handlers/compacting.d.ts +9 -0
  112. package/script/src/handlers/compacting.d.ts.map +1 -0
  113. package/script/src/handlers/compacting.js +33 -0
  114. package/script/src/handlers/event.d.ts +22 -0
  115. package/script/src/handlers/event.d.ts.map +1 -0
  116. package/script/src/handlers/event.js +290 -0
  117. package/script/src/handlers/messages.d.ts +9 -0
  118. package/script/src/handlers/messages.d.ts.map +1 -0
  119. package/script/src/handlers/messages.js +96 -0
  120. package/script/src/index.d.ts +5 -0
  121. package/script/src/index.d.ts.map +1 -0
  122. package/script/src/index.js +159 -0
  123. package/script/src/services/batch-drain.d.ts +23 -0
  124. package/script/src/services/batch-drain.d.ts.map +1 -0
  125. package/script/src/services/batch-drain.js +221 -0
  126. package/script/src/services/connection-manager.d.ts +104 -0
  127. package/script/src/services/connection-manager.d.ts.map +1 -0
  128. package/script/src/services/connection-manager.js +635 -0
  129. package/script/src/services/constants.d.ts +7 -0
  130. package/script/src/services/constants.d.ts.map +1 -0
  131. package/script/src/services/constants.js +9 -0
  132. package/script/src/services/context-limit.d.ts +3 -0
  133. package/script/src/services/context-limit.d.ts.map +1 -0
  134. package/script/src/services/context-limit.js +47 -0
  135. package/script/src/services/event-extractor.d.ts +29 -0
  136. package/script/src/services/event-extractor.d.ts.map +1 -0
  137. package/script/src/services/event-extractor.js +669 -0
  138. package/script/src/services/graphiti-async.d.ts +22 -0
  139. package/script/src/services/graphiti-async.d.ts.map +1 -0
  140. package/script/src/services/graphiti-async.js +223 -0
  141. package/script/src/services/graphiti-mcp.d.ts +57 -0
  142. package/script/src/services/graphiti-mcp.d.ts.map +1 -0
  143. package/script/src/services/graphiti-mcp.js +198 -0
  144. package/script/src/services/logger.d.ts +9 -0
  145. package/script/src/services/logger.d.ts.map +1 -0
  146. package/script/src/services/logger.js +142 -0
  147. package/script/src/services/opencode-warning.d.ts +8 -0
  148. package/script/src/services/opencode-warning.d.ts.map +1 -0
  149. package/script/src/services/opencode-warning.js +114 -0
  150. package/script/src/services/redis-cache.d.ts +27 -0
  151. package/script/src/services/redis-cache.d.ts.map +1 -0
  152. package/script/src/services/redis-cache.js +219 -0
  153. package/script/src/services/redis-client.d.ts +89 -0
  154. package/script/src/services/redis-client.d.ts.map +1 -0
  155. package/script/src/services/redis-client.js +943 -0
  156. package/script/src/services/redis-events.d.ts +46 -0
  157. package/script/src/services/redis-events.d.ts.map +1 -0
  158. package/script/src/services/redis-events.js +535 -0
  159. package/script/src/services/redis-snapshot.d.ts +16 -0
  160. package/script/src/services/redis-snapshot.d.ts.map +1 -0
  161. package/script/src/services/redis-snapshot.js +189 -0
  162. package/script/src/services/render-utils.d.ts +23 -0
  163. package/script/src/services/render-utils.d.ts.map +1 -0
  164. package/script/src/services/render-utils.js +165 -0
  165. package/script/src/services/runtime-teardown.d.ts +23 -0
  166. package/script/src/services/runtime-teardown.d.ts.map +1 -0
  167. package/script/src/services/runtime-teardown.js +155 -0
  168. package/script/src/services/sdk-normalize.d.ts +55 -0
  169. package/script/src/services/sdk-normalize.d.ts.map +1 -0
  170. package/script/src/services/sdk-normalize.js +67 -0
  171. package/script/src/session.d.ts +74 -0
  172. package/script/src/session.d.ts.map +1 -0
  173. package/script/src/session.js +698 -0
  174. package/script/src/types/index.d.ts +120 -0
  175. package/script/src/types/index.d.ts.map +1 -0
  176. package/script/src/types/index.js +33 -0
  177. package/script/src/utils.d.ts +27 -0
  178. package/script/src/utils.d.ts.map +1 -0
  179. package/script/src/utils.js +87 -0
@@ -0,0 +1,698 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SessionManager = void 0;
4
+ const constants_js_1 = require("./services/constants.js");
5
+ const logger_js_1 = require("./services/logger.js");
6
+ const redis_cache_js_1 = require("./services/redis-cache.js");
7
+ const render_utils_js_1 = require("./services/render-utils.js");
8
+ const index_js_1 = require("./types/index.js");
9
+ const findLatestUserRequest = (events) => {
10
+ for (let index = events.length - 1; index >= 0; index -= 1) {
11
+ const event = events[index];
12
+ if (event.role !== "user")
13
+ continue;
14
+ const candidate = (0, render_utils_js_1.sanitizeMemoryInput)((0, index_js_1.getSessionEventPrimaryText)(event));
15
+ if (candidate)
16
+ return candidate;
17
+ }
18
+ return "";
19
+ };
20
+ const RECENT_BASELINE_LIMIT = 20;
21
+ const RECALL_RESULT_LIMIT = 12;
22
+ const EXPLICIT_NOT_FOUND_CODES = new Set([
23
+ "not_found",
24
+ "session_not_found",
25
+ ]);
26
+ const asRecord = (value) => typeof value === "object" && value !== null
27
+ ? value
28
+ : null;
29
+ const normalizeErrorToken = (value) => {
30
+ if (typeof value !== "string")
31
+ return null;
32
+ const normalized = value.trim().toLowerCase();
33
+ return normalized.length > 0 ? normalized : null;
34
+ };
35
+ const isExplicitNotFoundCode = (value) => {
36
+ const normalized = normalizeErrorToken(value);
37
+ return normalized !== null && EXPLICIT_NOT_FOUND_CODES.has(normalized);
38
+ };
39
+ const isExplicitSessionNotFoundMessage = (value) => {
40
+ if (typeof value !== "string")
41
+ return false;
42
+ return /\bsession not found\b/i.test(value);
43
+ };
44
+ const isExplicitSessionNotFoundError = (error) => {
45
+ const queue = [error];
46
+ const visited = new Set();
47
+ while (queue.length > 0) {
48
+ const current = queue.shift();
49
+ const record = asRecord(current);
50
+ if (!record)
51
+ continue;
52
+ if (visited.has(record))
53
+ continue;
54
+ visited.add(record);
55
+ const status = record.status;
56
+ const statusCode = record.statusCode;
57
+ if (status === 404 || statusCode === 404)
58
+ return true;
59
+ if (isExplicitNotFoundCode(record.code) ||
60
+ isExplicitNotFoundCode(record.errorCode) ||
61
+ isExplicitNotFoundCode(record.type) ||
62
+ isExplicitSessionNotFoundMessage(record.message)) {
63
+ return true;
64
+ }
65
+ queue.push(record.cause, record.data, record.body, record.error, record.response);
66
+ }
67
+ return false;
68
+ };
69
+ const mergeSessionEvents = (recentEvents, recalledEvents) => {
70
+ const merged = new Map();
71
+ for (const event of recentEvents) {
72
+ if (!merged.has(event.id))
73
+ merged.set(event.id, event);
74
+ }
75
+ for (const event of recalledEvents) {
76
+ if (!merged.has(event.id))
77
+ merged.set(event.id, event);
78
+ }
79
+ return [...merged.values()].sort((left, right) => {
80
+ if (left.ts !== right.ts)
81
+ return left.ts - right.ts;
82
+ return left.id.localeCompare(right.id);
83
+ });
84
+ };
85
+ const collectRecentUniqueValues = (events, collect, limit, excludedNormalized = new Set()) => (0, render_utils_js_1.uniqueNormalizedValues)(events.flatMap((event) => {
86
+ const value = collect(event);
87
+ if (value === null || value === undefined)
88
+ return [];
89
+ return Array.isArray(value) ? value : [value];
90
+ }).reverse(), limit, excludedNormalized);
91
+ const addNormalizedValues = (target, values) => {
92
+ for (const value of values) {
93
+ const normalized = (0, render_utils_js_1.normalizeMemoryText)(value);
94
+ if (normalized)
95
+ target.add(normalized);
96
+ }
97
+ };
98
+ const filterDuplicateSnapshotLeaves = (snapshot, excludedNormalized) => {
99
+ if (!snapshot)
100
+ return "";
101
+ let filtered = snapshot.replace(/<([a-z_]+)>([^<>]*)<\/\1>/gi, (match, tag, text) => {
102
+ if (tag.toLowerCase() === "snapshot")
103
+ return match;
104
+ const normalized = (0, render_utils_js_1.normalizeMemoryText)(text);
105
+ return normalized && excludedNormalized.has(normalized) ? "" : match;
106
+ });
107
+ filtered = filtered.replace(/<(?!snapshot\b)([a-z_]+)>\s*<\/\1>/gi, "");
108
+ return filtered;
109
+ };
110
+ const collectSectionValues = (events, predicate, limit, excludedNormalized = new Set()) => collectRecentUniqueValues(events, (event) => predicate(event)
111
+ ? (0, render_utils_js_1.sanitizeMemoryInput)((0, index_js_1.getSessionEventPrimaryText)(event))
112
+ : null, limit, excludedNormalized);
113
+ const collectPathValues = (events, limit, excludedNormalized = new Set()) => collectRecentUniqueValues(events, (event) => event.category.startsWith("file.") ? event.refs ?? [] : [], limit, excludedNormalized);
114
+ class SessionManager {
115
+ constructor(defaultGroupId, defaultUserGroupId, sdkClient, redisEvents, redisSnapshot, redisCache, options = {}) {
116
+ Object.defineProperty(this, "defaultGroupId", {
117
+ enumerable: true,
118
+ configurable: true,
119
+ writable: true,
120
+ value: defaultGroupId
121
+ });
122
+ Object.defineProperty(this, "defaultUserGroupId", {
123
+ enumerable: true,
124
+ configurable: true,
125
+ writable: true,
126
+ value: defaultUserGroupId
127
+ });
128
+ Object.defineProperty(this, "sdkClient", {
129
+ enumerable: true,
130
+ configurable: true,
131
+ writable: true,
132
+ value: sdkClient
133
+ });
134
+ Object.defineProperty(this, "redisEvents", {
135
+ enumerable: true,
136
+ configurable: true,
137
+ writable: true,
138
+ value: redisEvents
139
+ });
140
+ Object.defineProperty(this, "redisSnapshot", {
141
+ enumerable: true,
142
+ configurable: true,
143
+ writable: true,
144
+ value: redisSnapshot
145
+ });
146
+ Object.defineProperty(this, "redisCache", {
147
+ enumerable: true,
148
+ configurable: true,
149
+ writable: true,
150
+ value: redisCache
151
+ });
152
+ Object.defineProperty(this, "sessions", {
153
+ enumerable: true,
154
+ configurable: true,
155
+ writable: true,
156
+ value: new Map()
157
+ });
158
+ Object.defineProperty(this, "parentIdCache", {
159
+ enumerable: true,
160
+ configurable: true,
161
+ writable: true,
162
+ value: new Map()
163
+ });
164
+ Object.defineProperty(this, "canonicalSessionIdCache", {
165
+ enumerable: true,
166
+ configurable: true,
167
+ writable: true,
168
+ value: new Map()
169
+ });
170
+ Object.defineProperty(this, "temporaryRootSessionIds", {
171
+ enumerable: true,
172
+ configurable: true,
173
+ writable: true,
174
+ value: new Set()
175
+ });
176
+ Object.defineProperty(this, "pendingAssistantMessages", {
177
+ enumerable: true,
178
+ configurable: true,
179
+ writable: true,
180
+ value: new Map()
181
+ });
182
+ Object.defineProperty(this, "pendingAssistantCompletions", {
183
+ enumerable: true,
184
+ configurable: true,
185
+ writable: true,
186
+ value: new Set()
187
+ });
188
+ Object.defineProperty(this, "bufferedAssistantMessageIds", {
189
+ enumerable: true,
190
+ configurable: true,
191
+ writable: true,
192
+ value: new Map()
193
+ });
194
+ Object.defineProperty(this, "sessionLifecycles", {
195
+ enumerable: true,
196
+ configurable: true,
197
+ writable: true,
198
+ value: new Map()
199
+ });
200
+ Object.defineProperty(this, "idleRetentionMs", {
201
+ enumerable: true,
202
+ configurable: true,
203
+ writable: true,
204
+ value: void 0
205
+ });
206
+ Object.defineProperty(this, "setTimerImpl", {
207
+ enumerable: true,
208
+ configurable: true,
209
+ writable: true,
210
+ value: void 0
211
+ });
212
+ Object.defineProperty(this, "clearTimerImpl", {
213
+ enumerable: true,
214
+ configurable: true,
215
+ writable: true,
216
+ value: void 0
217
+ });
218
+ this.idleRetentionMs = Math.max(0, options.idleRetentionMs ?? 0);
219
+ this.setTimerImpl = options.setTimer ??
220
+ ((callback, delayMs) => setTimeout(callback, delayMs));
221
+ this.clearTimerImpl = options.clearTimer ??
222
+ ((timer) => clearTimeout(timer));
223
+ }
224
+ createDefaultState(groupId, userGroupId) {
225
+ return {
226
+ groupId,
227
+ userGroupId,
228
+ injectedMemories: false,
229
+ messageCount: 0,
230
+ contextLimit: constants_js_1.DEFAULT_CONTEXT_LIMIT,
231
+ isMain: true,
232
+ hotTierReady: false,
233
+ latestUserRequest: undefined,
234
+ latestRefreshQuery: undefined,
235
+ pendingInjection: undefined,
236
+ pendingInjectionGeneration: 0,
237
+ };
238
+ }
239
+ getState(sessionId) {
240
+ return this.sessions.get(sessionId);
241
+ }
242
+ setState(sessionId, state) {
243
+ this.sessions.set(sessionId, state);
244
+ }
245
+ markSessionActive(sessionId) {
246
+ this.markLifecycleActive(sessionId);
247
+ const canonicalSessionId = this.canonicalSessionIdCache.get(sessionId);
248
+ if (canonicalSessionId && canonicalSessionId !== sessionId) {
249
+ this.markLifecycleActive(canonicalSessionId);
250
+ }
251
+ }
252
+ markResolvedSessionActive(sessionId, canonicalSessionId) {
253
+ this.markLifecycleActive(sessionId);
254
+ if (canonicalSessionId && canonicalSessionId !== sessionId) {
255
+ this.markLifecycleActive(canonicalSessionId);
256
+ }
257
+ }
258
+ markLifecycleActive(sessionId) {
259
+ const lifecycle = this.getLifecycle(sessionId);
260
+ lifecycle.activityGeneration += 1;
261
+ if (lifecycle.idleCleanupTimer !== null) {
262
+ this.clearTimerImpl(lifecycle.idleCleanupTimer);
263
+ lifecycle.idleCleanupTimer = null;
264
+ }
265
+ }
266
+ captureIdleCleanupGeneration(sessionId) {
267
+ const state = this.sessions.get(sessionId);
268
+ if (!state?.isMain)
269
+ return null;
270
+ return this.getLifecycle(sessionId).activityGeneration;
271
+ }
272
+ scheduleIdleSessionCleanup(sessionId, expectedActivityGeneration) {
273
+ const state = this.sessions.get(sessionId);
274
+ if (!state?.isMain) {
275
+ this.deleteSession(sessionId);
276
+ return;
277
+ }
278
+ const lifecycle = this.getLifecycle(sessionId);
279
+ if (expectedActivityGeneration !== undefined &&
280
+ lifecycle.activityGeneration !== expectedActivityGeneration) {
281
+ return;
282
+ }
283
+ if (this.idleRetentionMs <= 0) {
284
+ this.deleteSession(sessionId);
285
+ return;
286
+ }
287
+ if (lifecycle.idleCleanupTimer !== null) {
288
+ this.clearTimerImpl(lifecycle.idleCleanupTimer);
289
+ lifecycle.idleCleanupTimer = null;
290
+ }
291
+ const activityGeneration = expectedActivityGeneration ??
292
+ lifecycle.activityGeneration;
293
+ const timerHandle = this.setTimerImpl(() => {
294
+ const currentLifecycle = this.sessionLifecycles.get(sessionId);
295
+ if (!currentLifecycle)
296
+ return;
297
+ if (currentLifecycle.idleCleanupTimer !== timerHandle)
298
+ return;
299
+ if (currentLifecycle.activityGeneration !== activityGeneration)
300
+ return;
301
+ this.deleteSession(sessionId);
302
+ }, this.idleRetentionMs);
303
+ lifecycle.idleCleanupTimer = timerHandle;
304
+ }
305
+ setParentId(sessionId, parentId) {
306
+ const wasTemporaryRoot = this.temporaryRootSessionIds.has(sessionId);
307
+ this.parentIdCache.set(sessionId, parentId);
308
+ if (!parentId) {
309
+ this.temporaryRootSessionIds.delete(sessionId);
310
+ this.canonicalSessionIdCache.set(sessionId, sessionId);
311
+ return;
312
+ }
313
+ const parentCanonical = this.canonicalSessionIdCache.get(parentId);
314
+ if (parentCanonical) {
315
+ this.canonicalSessionIdCache.set(sessionId, parentCanonical);
316
+ if (parentCanonical !== sessionId) {
317
+ this.migrateTemporaryRootRuntimeState(sessionId, parentCanonical);
318
+ }
319
+ if (wasTemporaryRoot) {
320
+ this.temporaryRootSessionIds.delete(sessionId);
321
+ }
322
+ return;
323
+ }
324
+ this.canonicalSessionIdCache.delete(sessionId);
325
+ }
326
+ mergeSessionState(target, source) {
327
+ target.injectedMemories ||= source.injectedMemories;
328
+ target.messageCount += source.messageCount;
329
+ target.contextLimit = Math.max(target.contextLimit, source.contextLimit);
330
+ target.isMain ||= source.isMain;
331
+ target.hotTierReady ||= source.hotTierReady;
332
+ if (source.latestUserRequest) {
333
+ target.latestUserRequest = source.latestUserRequest;
334
+ }
335
+ if (source.latestRefreshQuery) {
336
+ target.latestRefreshQuery = source.latestRefreshQuery;
337
+ }
338
+ if (source.pendingInjection !== undefined) {
339
+ target.pendingInjection = source.pendingInjection;
340
+ }
341
+ target.pendingInjectionGeneration = Math.max(target.pendingInjectionGeneration, source.pendingInjectionGeneration);
342
+ }
343
+ migrateTemporaryRootRuntimeState(sessionId, canonicalSessionId) {
344
+ if (sessionId === canonicalSessionId)
345
+ return;
346
+ const sourceState = this.sessions.get(sessionId);
347
+ const targetState = this.sessions.get(canonicalSessionId);
348
+ if (sourceState) {
349
+ if (targetState) {
350
+ this.mergeSessionState(targetState, sourceState);
351
+ }
352
+ else {
353
+ this.sessions.set(canonicalSessionId, sourceState);
354
+ }
355
+ this.sessions.delete(sessionId);
356
+ }
357
+ const sourceLifecycle = this.sessionLifecycles.get(sessionId);
358
+ const targetLifecycle = this.sessionLifecycles.get(canonicalSessionId);
359
+ if (sourceLifecycle) {
360
+ const targetIdleCleanupTimer = targetLifecycle?.idleCleanupTimer ?? null;
361
+ if (sourceLifecycle.idleCleanupTimer !== null) {
362
+ this.clearTimerImpl(sourceLifecycle.idleCleanupTimer);
363
+ }
364
+ if (targetIdleCleanupTimer !== null) {
365
+ this.clearTimerImpl(targetIdleCleanupTimer);
366
+ }
367
+ this.sessionLifecycles.set(canonicalSessionId, {
368
+ activityGeneration: Math.max(targetLifecycle?.activityGeneration ?? 0, sourceLifecycle.activityGeneration),
369
+ idleCleanupTimer: null,
370
+ });
371
+ this.sessionLifecycles.delete(sessionId);
372
+ }
373
+ const sessionPrefix = `${sessionId}:`;
374
+ for (const [key, buffered] of [...this.pendingAssistantMessages.entries()]) {
375
+ if (!key.startsWith(sessionPrefix))
376
+ continue;
377
+ const messageId = key.slice(sessionPrefix.length);
378
+ const canonicalKey = `${canonicalSessionId}:${messageId}`;
379
+ if (!this.pendingAssistantMessages.has(canonicalKey)) {
380
+ this.pendingAssistantMessages.set(canonicalKey, {
381
+ ...buffered,
382
+ sessionId: canonicalSessionId,
383
+ });
384
+ }
385
+ this.pendingAssistantMessages.delete(key);
386
+ }
387
+ for (const [key, sourceSessionId] of [...this.bufferedAssistantMessageIds
388
+ .entries()]) {
389
+ if (!key.startsWith(sessionPrefix))
390
+ continue;
391
+ const messageId = key.slice(sessionPrefix.length);
392
+ const canonicalKey = `${canonicalSessionId}:${messageId}`;
393
+ if (!this.bufferedAssistantMessageIds.has(canonicalKey)) {
394
+ this.bufferedAssistantMessageIds.set(canonicalKey, sourceSessionId);
395
+ }
396
+ this.bufferedAssistantMessageIds.delete(key);
397
+ }
398
+ for (const key of [...this.pendingAssistantCompletions]) {
399
+ if (!key.startsWith(sessionPrefix))
400
+ continue;
401
+ const messageId = key.slice(sessionPrefix.length);
402
+ this.pendingAssistantCompletions.add(`${canonicalSessionId}:${messageId}`);
403
+ this.pendingAssistantCompletions.delete(key);
404
+ }
405
+ for (const [cachedSessionId, cachedCanonicalSessionId] of [
406
+ ...this.canonicalSessionIdCache.entries(),
407
+ ]) {
408
+ if (cachedCanonicalSessionId === sessionId) {
409
+ this.canonicalSessionIdCache.set(cachedSessionId, canonicalSessionId);
410
+ }
411
+ }
412
+ }
413
+ async resolveParentId(sessionId) {
414
+ if (this.parentIdCache.has(sessionId)) {
415
+ return this.parentIdCache.get(sessionId) ?? null;
416
+ }
417
+ try {
418
+ const response = await this.sdkClient.session.get({
419
+ path: { id: sessionId },
420
+ });
421
+ const sessionInfo = typeof response === "object" && response !== null &&
422
+ "data" in response
423
+ ? response.data
424
+ : response;
425
+ if (!sessionInfo)
426
+ return undefined;
427
+ const parentId = sessionInfo.parentID ?? null;
428
+ this.parentIdCache.set(sessionId, parentId);
429
+ return parentId;
430
+ }
431
+ catch (err) {
432
+ if (isExplicitSessionNotFoundError(err)) {
433
+ this.parentIdCache.set(sessionId, null);
434
+ this.canonicalSessionIdCache.set(sessionId, sessionId);
435
+ this.temporaryRootSessionIds.add(sessionId);
436
+ logger_js_1.logger.debug("Session not found during parent resolution; treating as temporary root", { sessionId });
437
+ return null;
438
+ }
439
+ logger_js_1.logger.debug("Failed to resolve session parentID", { sessionId, err });
440
+ return undefined;
441
+ }
442
+ }
443
+ async resolveCanonicalSessionId(sessionId, visited = new Set()) {
444
+ const cached = this.canonicalSessionIdCache.get(sessionId);
445
+ if (cached)
446
+ return cached;
447
+ if (visited.has(sessionId)) {
448
+ logger_js_1.logger.debug("Detected cycle while resolving canonical session", {
449
+ sessionId,
450
+ visited: [...visited],
451
+ });
452
+ return undefined;
453
+ }
454
+ visited.add(sessionId);
455
+ const parentId = await this.resolveParentId(sessionId);
456
+ if (parentId === undefined)
457
+ return undefined;
458
+ if (!parentId) {
459
+ this.canonicalSessionIdCache.set(sessionId, sessionId);
460
+ return sessionId;
461
+ }
462
+ const canonicalSessionId = await this.resolveCanonicalSessionId(parentId, visited);
463
+ if (!canonicalSessionId)
464
+ return undefined;
465
+ if (canonicalSessionId !== sessionId) {
466
+ this.migrateTemporaryRootRuntimeState(sessionId, canonicalSessionId);
467
+ this.temporaryRootSessionIds.delete(sessionId);
468
+ }
469
+ this.canonicalSessionIdCache.set(sessionId, canonicalSessionId);
470
+ return canonicalSessionId;
471
+ }
472
+ async resolveSessionState(sessionId) {
473
+ const canonicalSessionId = await this.resolveCanonicalSessionId(sessionId);
474
+ if (!canonicalSessionId) {
475
+ return { state: null, resolved: false, canonicalSessionId: undefined };
476
+ }
477
+ let state = this.sessions.get(canonicalSessionId);
478
+ if (!state) {
479
+ state = this.createDefaultState(this.defaultGroupId, this.defaultUserGroupId);
480
+ this.sessions.set(canonicalSessionId, state);
481
+ }
482
+ return { state, resolved: true, canonicalSessionId };
483
+ }
484
+ bufferAssistantPart(sessionId, messageId, text, sourceSessionId = sessionId) {
485
+ const key = `${sessionId}:${messageId}`;
486
+ this.pendingAssistantMessages.set(key, {
487
+ sessionId,
488
+ text,
489
+ sourceSessionId,
490
+ });
491
+ }
492
+ isAssistantBuffered(sessionId, messageId) {
493
+ return this.bufferedAssistantMessageIds.has(`${sessionId}:${messageId}`);
494
+ }
495
+ hasPendingAssistantCompletion(sessionId, messageId) {
496
+ return this.pendingAssistantCompletions.has(`${sessionId}:${messageId}`);
497
+ }
498
+ finalizeAssistantMessage(_state, sessionId, messageId, source) {
499
+ const key = `${sessionId}:${messageId}`;
500
+ if (this.bufferedAssistantMessageIds.has(key))
501
+ return null;
502
+ const buffered = this.pendingAssistantMessages.get(key);
503
+ const messageText = buffered?.text?.trim() ?? "";
504
+ if (!messageText) {
505
+ this.pendingAssistantCompletions.add(key);
506
+ return null;
507
+ }
508
+ this.pendingAssistantCompletions.delete(key);
509
+ this.pendingAssistantMessages.delete(key);
510
+ this.bufferedAssistantMessageIds.set(key, buffered?.sourceSessionId ?? sessionId);
511
+ logger_js_1.logger.info("Assistant message completed", {
512
+ hook: source,
513
+ sessionId,
514
+ messageID: messageId,
515
+ messageLength: messageText.length,
516
+ });
517
+ return messageText;
518
+ }
519
+ deletePendingAssistant(sessionId, messageId) {
520
+ const key = `${sessionId}:${messageId}`;
521
+ this.pendingAssistantMessages.delete(key);
522
+ this.pendingAssistantCompletions.delete(key);
523
+ }
524
+ clearPendingInjection(state, prepared) {
525
+ if (!prepared)
526
+ return;
527
+ if (state.pendingInjection === prepared) {
528
+ state.pendingInjection = undefined;
529
+ }
530
+ }
531
+ purgeAssistantBufferSource(sourceSessionId) {
532
+ for (const [key, buffered] of [...this.pendingAssistantMessages.entries()]) {
533
+ if (buffered.sourceSessionId === sourceSessionId) {
534
+ this.pendingAssistantMessages.delete(key);
535
+ this.pendingAssistantCompletions.delete(key);
536
+ }
537
+ }
538
+ for (const [key, bufferedSourceSessionId] of [
539
+ ...this.bufferedAssistantMessageIds.entries(),
540
+ ]) {
541
+ if (bufferedSourceSessionId === sourceSessionId) {
542
+ this.bufferedAssistantMessageIds.delete(key);
543
+ }
544
+ }
545
+ }
546
+ async prepareInjection(sessionId, lastRequest) {
547
+ const state = this.sessions.get(sessionId);
548
+ if (!state?.isMain)
549
+ return null;
550
+ const generation = state.pendingInjectionGeneration + 1;
551
+ state.pendingInjectionGeneration = generation;
552
+ const [recentEvents, snapshot, cache, cacheMeta] = await Promise.all([
553
+ this.redisEvents.getRecentSessionEvents(sessionId, RECENT_BASELINE_LIMIT, true),
554
+ this.redisSnapshot.getSnapshot(sessionId),
555
+ this.redisCache.get(state.groupId),
556
+ this.redisCache.getMeta(state.groupId),
557
+ ]);
558
+ const canonicalLatestRequest = (0, render_utils_js_1.sanitizeMemoryInput)(state.latestUserRequest ?? "");
559
+ const directFallbackRequest = (0, render_utils_js_1.sanitizeMemoryInput)(lastRequest ?? "");
560
+ const cachedFallbackRequest = (0, render_utils_js_1.sanitizeMemoryInput)(state.latestRefreshQuery ?? cacheMeta?.lastQuery ?? "");
561
+ const historyFallbackRequest = findLatestUserRequest(recentEvents);
562
+ const latestRequest = canonicalLatestRequest || directFallbackRequest ||
563
+ cachedFallbackRequest || historyFallbackRequest;
564
+ const recalledEvents = latestRequest
565
+ ? await this.redisEvents.recallSessionEvents(sessionId, latestRequest, {
566
+ resultLimit: RECALL_RESULT_LIMIT,
567
+ })
568
+ : [];
569
+ const events = mergeSessionEvents(recentEvents, recalledEvents);
570
+ const occupiedNormalized = new Set();
571
+ const normalizedLatestRequest = (0, render_utils_js_1.normalizeMemoryText)(latestRequest);
572
+ if (normalizedLatestRequest) {
573
+ occupiedNormalized.add(normalizedLatestRequest);
574
+ }
575
+ const activeTasks = collectSectionValues(events, (event) => ["task.create", "task.update", "task.complete"].includes(event.category), 4, occupiedNormalized);
576
+ addNormalizedValues(occupiedNormalized, activeTasks);
577
+ const decisions = collectSectionValues(events, (event) => ["decision", "preference"].includes(event.category), 5, occupiedNormalized);
578
+ addNormalizedValues(occupiedNormalized, decisions);
579
+ const files = collectPathValues(events, 6, occupiedNormalized);
580
+ addNormalizedValues(occupiedNormalized, files);
581
+ const rules = collectSectionValues(events, (event) => event.category === "rule.load", 6, occupiedNormalized);
582
+ addNormalizedValues(occupiedNormalized, rules);
583
+ const unresolvedErrors = collectRecentUniqueValues(events, (event) => event.category === "error" && event.metadata?.resolved !== true &&
584
+ event.role !== "assistant"
585
+ ? (0, render_utils_js_1.sanitizeMemoryInput)((0, index_js_1.getSessionEventPrimaryText)(event))
586
+ : null, 4, occupiedNormalized);
587
+ addNormalizedValues(occupiedNormalized, unresolvedErrors);
588
+ const gitState = collectSectionValues(events, (event) => event.category === "git.activity", 4, occupiedNormalized);
589
+ addNormalizedValues(occupiedNormalized, gitState);
590
+ const subagentWork = collectSectionValues(events, (event) => event.category === "subagent.start" ||
591
+ event.category === "subagent.finish", 4, occupiedNormalized);
592
+ addNormalizedValues(occupiedNormalized, subagentWork);
593
+ const filteredSnapshot = filterDuplicateSnapshotLeaves(snapshot, occupiedNormalized);
594
+ const persistent = this.redisCache.renderPersistentMemory(cache, redis_cache_js_1.PERSISTENT_MEMORY_BODY_BUDGET);
595
+ const refreshDecision = this.redisCache.classifyRefresh(cache, latestRequest);
596
+ const sections = [
597
+ `<last_request>${(0, render_utils_js_1.escapeXml)(latestRequest)}</last_request>`,
598
+ (0, render_utils_js_1.renderXmlListSection)("active_tasks", "task", activeTasks, { itemCharLimit: 280, includeEmpty: true }),
599
+ (0, render_utils_js_1.renderXmlListSection)("key_decisions", "decision", decisions, {
600
+ itemCharLimit: 280,
601
+ includeEmpty: true,
602
+ }),
603
+ (0, render_utils_js_1.renderXmlListSection)("files_in_play", "file", files, {
604
+ itemCharLimit: 280,
605
+ includeEmpty: true,
606
+ }),
607
+ (0, render_utils_js_1.renderXmlListSection)("project_rules", "rule", rules, {
608
+ itemCharLimit: 280,
609
+ includeEmpty: true,
610
+ }),
611
+ unresolvedErrors.length > 0
612
+ ? (0, render_utils_js_1.renderXmlListSection)("unresolved_errors", "error", unresolvedErrors, {
613
+ itemCharLimit: 280,
614
+ })
615
+ : "",
616
+ gitState.length > 0
617
+ ? (0, render_utils_js_1.renderXmlListSection)("git_state", "item", gitState, {
618
+ itemCharLimit: 280,
619
+ })
620
+ : "",
621
+ subagentWork.length > 0
622
+ ? (0, render_utils_js_1.renderXmlListSection)("subagent_work", "item", subagentWork, {
623
+ itemCharLimit: 280,
624
+ })
625
+ : "",
626
+ filteredSnapshot
627
+ ? `<session_snapshot>${filteredSnapshot}</session_snapshot>`
628
+ : "",
629
+ persistent.body
630
+ ? `<persistent_memory node_refs="${(0, render_utils_js_1.escapeXml)(persistent.nodeRefs.join(","))}">${persistent.body}</persistent_memory>`
631
+ : "",
632
+ ].filter(Boolean);
633
+ const envelope = `<session_memory source="falkordb+graphiti-cache" version="1">${sections.join("")}</session_memory>`;
634
+ const prepared = {
635
+ envelope,
636
+ nodeRefs: persistent.nodeRefs,
637
+ refreshDecision,
638
+ };
639
+ const currentState = this.sessions.get(sessionId);
640
+ if (currentState !== state || !currentState.isMain)
641
+ return null;
642
+ if (state.pendingInjectionGeneration !== generation)
643
+ return null;
644
+ state.pendingInjection = prepared;
645
+ state.hotTierReady = true;
646
+ state.latestRefreshQuery = latestRequest || cacheMeta?.lastQuery;
647
+ return prepared;
648
+ }
649
+ deleteSession(sessionId) {
650
+ const lifecycle = this.sessionLifecycles.get(sessionId);
651
+ if (lifecycle?.idleCleanupTimer != null) {
652
+ this.clearTimerImpl(lifecycle.idleCleanupTimer);
653
+ }
654
+ this.sessionLifecycles.delete(sessionId);
655
+ this.sessions.delete(sessionId);
656
+ this.parentIdCache.delete(sessionId);
657
+ this.canonicalSessionIdCache.delete(sessionId);
658
+ this.temporaryRootSessionIds.delete(sessionId);
659
+ for (const [childSessionId, parentId] of [...this.parentIdCache.entries()]) {
660
+ if (parentId === sessionId)
661
+ this.parentIdCache.delete(childSessionId);
662
+ }
663
+ for (const [childSessionId, canonicalSessionId] of [
664
+ ...this.canonicalSessionIdCache.entries(),
665
+ ]) {
666
+ if (canonicalSessionId === sessionId) {
667
+ this.canonicalSessionIdCache.delete(childSessionId);
668
+ }
669
+ }
670
+ const prefix = `${sessionId}:`;
671
+ for (const key of [...this.pendingAssistantMessages.keys()]) {
672
+ if (key.startsWith(prefix)) {
673
+ this.pendingAssistantMessages.delete(key);
674
+ this.pendingAssistantCompletions.delete(key);
675
+ }
676
+ }
677
+ for (const [key] of [...this.bufferedAssistantMessageIds.entries()]) {
678
+ if (key.startsWith(prefix))
679
+ this.bufferedAssistantMessageIds.delete(key);
680
+ }
681
+ for (const key of [...this.pendingAssistantCompletions]) {
682
+ if (key.startsWith(prefix))
683
+ this.pendingAssistantCompletions.delete(key);
684
+ }
685
+ }
686
+ getLifecycle(sessionId) {
687
+ let lifecycle = this.sessionLifecycles.get(sessionId);
688
+ if (!lifecycle) {
689
+ lifecycle = {
690
+ activityGeneration: 0,
691
+ idleCleanupTimer: null,
692
+ };
693
+ this.sessionLifecycles.set(sessionId, lifecycle);
694
+ }
695
+ return lifecycle;
696
+ }
697
+ }
698
+ exports.SessionManager = SessionManager;