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,290 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createEventHandler = createEventHandler;
4
+ const context_limit_js_1 = require("../services/context-limit.js");
5
+ const event_extractor_js_1 = require("../services/event-extractor.js");
6
+ const logger_js_1 = require("../services/logger.js");
7
+ const utils_js_1 = require("../utils.js");
8
+ const asRecord = (value) => value && typeof value === "object" && !Array.isArray(value)
9
+ ? value
10
+ : undefined;
11
+ const asString = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
12
+ const passthroughEventTypes = new Set([
13
+ "task.updated",
14
+ "rules.loaded",
15
+ "environment.updated",
16
+ "subagent.started",
17
+ "subagent.finished",
18
+ "tool.called",
19
+ "tool.completed",
20
+ ]);
21
+ const getEventSessionId = (value, depth = 0) => {
22
+ if (depth > 4)
23
+ return undefined;
24
+ if (Array.isArray(value)) {
25
+ for (const item of value) {
26
+ const sessionId = getEventSessionId(item, depth + 1);
27
+ if (sessionId)
28
+ return sessionId;
29
+ }
30
+ return undefined;
31
+ }
32
+ const record = asRecord(value);
33
+ if (!record)
34
+ return undefined;
35
+ const directSessionId = asString(record.sessionID) ??
36
+ asString(record.sessionId);
37
+ if (directSessionId)
38
+ return directSessionId;
39
+ for (const nested of Object.values(record)) {
40
+ const sessionId = getEventSessionId(nested, depth + 1);
41
+ if (sessionId)
42
+ return sessionId;
43
+ }
44
+ return undefined;
45
+ };
46
+ const getCompactionSummary = (value) => {
47
+ const summary = asRecord(value)?.summary;
48
+ return typeof summary === "string" ? summary : "";
49
+ };
50
+ function createEventHandler(deps) {
51
+ const { sessionManager, redisEvents, redisCache, redisSnapshot, graphitiAsync, sdkClient, directory, } = deps;
52
+ const contextLimitCache = new Map();
53
+ const contextLimitLookupGeneration = new Map();
54
+ let nextContextLimitLookupGeneration = 0;
55
+ const clearContextLimitLookupGeneration = (sessionId, generation) => {
56
+ if (generation === undefined) {
57
+ contextLimitLookupGeneration.delete(sessionId);
58
+ return;
59
+ }
60
+ if (contextLimitLookupGeneration.get(sessionId) === generation) {
61
+ contextLimitLookupGeneration.delete(sessionId);
62
+ }
63
+ };
64
+ return async ({ event }) => {
65
+ try {
66
+ if (event.type === "session.created") {
67
+ const info = event.properties.info;
68
+ const sessionId = info.id;
69
+ const parentId = info.parentID ?? null;
70
+ sessionManager.setParentId(sessionId, parentId);
71
+ sessionManager.markSessionActive(sessionId);
72
+ const { state, resolved, canonicalSessionId } = await sessionManager
73
+ .resolveSessionState(sessionId);
74
+ if (!resolved || !state?.isMain || !canonicalSessionId)
75
+ return;
76
+ sessionManager.markResolvedSessionActive(sessionId, canonicalSessionId);
77
+ for (const structured of (0, event_extractor_js_1.extractStructuredEvents)({
78
+ eventType: event.type,
79
+ sessionId,
80
+ properties: event.properties,
81
+ role: "system",
82
+ })) {
83
+ await redisEvents.recordEvent(canonicalSessionId, state.groupId, structured);
84
+ }
85
+ await Promise.all([
86
+ redisEvents.touchSessionEvents(canonicalSessionId),
87
+ redisSnapshot.touchSnapshot(canonicalSessionId),
88
+ redisCache.touch(state.groupId),
89
+ ]);
90
+ if (canonicalSessionId === sessionId) {
91
+ graphitiAsync.schedulePrimer(state.groupId);
92
+ }
93
+ return;
94
+ }
95
+ if (event.type === "session.idle") {
96
+ const sessionId = event.properties.sessionID;
97
+ const { state, resolved, canonicalSessionId } = await sessionManager
98
+ .resolveSessionState(sessionId);
99
+ if (!resolved || !state?.isMain)
100
+ return;
101
+ if (!canonicalSessionId)
102
+ return;
103
+ const idleGeneration = sessionManager.captureIdleCleanupGeneration(canonicalSessionId);
104
+ if (idleGeneration === null)
105
+ return;
106
+ const events = await redisEvents.getRecentSessionEvents(canonicalSessionId, 40, true);
107
+ await redisSnapshot.rebuildAndSave(canonicalSessionId, events);
108
+ state.hotTierReady = true;
109
+ graphitiAsync.scheduleDrain(state.groupId);
110
+ const refreshQuery = state.latestUserRequest ??
111
+ state.latestRefreshQuery ??
112
+ (await redisCache.getMeta(state.groupId))?.lastQuery;
113
+ if (refreshQuery) {
114
+ state.latestRefreshQuery = refreshQuery;
115
+ graphitiAsync.scheduleCacheRefresh(state.groupId, refreshQuery);
116
+ }
117
+ sessionManager.scheduleIdleSessionCleanup(canonicalSessionId, idleGeneration);
118
+ return;
119
+ }
120
+ if (event.type === "session.deleted") {
121
+ const sessionId = event.properties
122
+ .sessionID;
123
+ const canonicalSessionId = await sessionManager
124
+ .resolveCanonicalSessionId(sessionId);
125
+ clearContextLimitLookupGeneration(sessionId);
126
+ if (canonicalSessionId) {
127
+ clearContextLimitLookupGeneration(canonicalSessionId);
128
+ }
129
+ if (canonicalSessionId && canonicalSessionId !== sessionId) {
130
+ sessionManager.purgeAssistantBufferSource(sessionId);
131
+ }
132
+ sessionManager.deleteSession(sessionId);
133
+ return;
134
+ }
135
+ if (event.type === "session.compacted") {
136
+ const sessionId = event.properties.sessionID;
137
+ const { state, resolved, canonicalSessionId } = await sessionManager
138
+ .resolveSessionState(sessionId);
139
+ if (!resolved || !state?.isMain)
140
+ return;
141
+ if (!canonicalSessionId)
142
+ return;
143
+ const structured = (0, event_extractor_js_1.extractStructuredEvents)({
144
+ eventType: event.type,
145
+ sessionId,
146
+ properties: event.properties,
147
+ messageText: getCompactionSummary(event.properties),
148
+ role: "system",
149
+ });
150
+ for (const item of structured) {
151
+ await redisEvents.recordEvent(canonicalSessionId, state.groupId, item);
152
+ }
153
+ const events = await redisEvents.getRecentSessionEvents(canonicalSessionId, 40, true);
154
+ await redisSnapshot.rebuildAndSave(canonicalSessionId, events);
155
+ graphitiAsync.scheduleDrain(state.groupId);
156
+ const refreshQuery = state.latestUserRequest ??
157
+ state.latestRefreshQuery ??
158
+ (await redisCache.getMeta(state.groupId))?.lastQuery;
159
+ if (refreshQuery) {
160
+ state.latestRefreshQuery = refreshQuery;
161
+ graphitiAsync.scheduleCacheRefresh(state.groupId, refreshQuery);
162
+ }
163
+ return;
164
+ }
165
+ if (event.type === "message.updated") {
166
+ const info = event.properties.info;
167
+ const sessionId = info.sessionID;
168
+ const { state, resolved, canonicalSessionId } = await sessionManager
169
+ .resolveSessionState(sessionId);
170
+ if (!resolved || !state?.isMain)
171
+ return;
172
+ if (!canonicalSessionId)
173
+ return;
174
+ sessionManager.markResolvedSessionActive(sessionId, canonicalSessionId);
175
+ if (info.role !== "assistant") {
176
+ sessionManager.deletePendingAssistant(canonicalSessionId, info.id);
177
+ return;
178
+ }
179
+ const time = info.time;
180
+ if (!time?.completed)
181
+ return;
182
+ if (sessionManager.isAssistantBuffered(canonicalSessionId, info.id)) {
183
+ return;
184
+ }
185
+ const assistantText = sessionManager.finalizeAssistantMessage(state, canonicalSessionId, info.id, "message.updated");
186
+ if (assistantText) {
187
+ for (const structured of (0, event_extractor_js_1.extractStructuredEvents)({
188
+ eventType: event.type,
189
+ sessionId,
190
+ properties: event.properties,
191
+ messageText: assistantText,
192
+ role: "assistant",
193
+ })) {
194
+ await redisEvents.recordEvent(canonicalSessionId, state.groupId, structured);
195
+ }
196
+ }
197
+ if (info.tokens && info.providerID && info.modelID) {
198
+ const lookupSessionId = canonicalSessionId;
199
+ const lookupGeneration = ++nextContextLimitLookupGeneration;
200
+ contextLimitLookupGeneration.set(lookupSessionId, lookupGeneration);
201
+ const cleanupSessionIds = new Set([lookupSessionId]);
202
+ void (async () => {
203
+ const limit = await (0, context_limit_js_1.resolveContextLimit)(info.providerID, info.modelID, sdkClient, directory, contextLimitCache);
204
+ if (contextLimitLookupGeneration.get(lookupSessionId) !==
205
+ lookupGeneration) {
206
+ return;
207
+ }
208
+ const currentCanonicalSessionId = await sessionManager
209
+ .resolveCanonicalSessionId(sessionId);
210
+ if (!currentCanonicalSessionId)
211
+ return;
212
+ cleanupSessionIds.add(currentCanonicalSessionId);
213
+ if (currentCanonicalSessionId !== lookupSessionId &&
214
+ (contextLimitLookupGeneration.get(currentCanonicalSessionId) ??
215
+ -1) >
216
+ lookupGeneration) {
217
+ return;
218
+ }
219
+ if (currentCanonicalSessionId !== lookupSessionId) {
220
+ contextLimitLookupGeneration.set(currentCanonicalSessionId, lookupGeneration);
221
+ }
222
+ if (contextLimitLookupGeneration.get(currentCanonicalSessionId) !==
223
+ lookupGeneration) {
224
+ return;
225
+ }
226
+ const currentState = sessionManager.getState(currentCanonicalSessionId);
227
+ if (!currentState?.isMain)
228
+ return;
229
+ currentState.contextLimit = limit;
230
+ })().catch((err) => logger_js_1.logger.debug("Failed to resolve context limit", err)).finally(() => {
231
+ for (const lookupSessionId of cleanupSessionIds) {
232
+ clearContextLimitLookupGeneration(lookupSessionId, lookupGeneration);
233
+ }
234
+ });
235
+ }
236
+ return;
237
+ }
238
+ if (event.type === "message.part.updated") {
239
+ const part = event.properties.part;
240
+ if (!(0, utils_js_1.isTextPart)(part))
241
+ return;
242
+ const canonicalSessionId = await sessionManager.resolveCanonicalSessionId(part.sessionID) ?? part.sessionID;
243
+ sessionManager.markResolvedSessionActive(part.sessionID, canonicalSessionId);
244
+ sessionManager.bufferAssistantPart(canonicalSessionId, part.messageID, part.text, part.sessionID);
245
+ if (!sessionManager.hasPendingAssistantCompletion(canonicalSessionId, part.messageID)) {
246
+ return;
247
+ }
248
+ const { state, resolved } = await sessionManager.resolveSessionState(part.sessionID);
249
+ if (!resolved || !state?.isMain)
250
+ return;
251
+ const assistantText = sessionManager.finalizeAssistantMessage(state, canonicalSessionId, part.messageID, "message.part.updated");
252
+ if (!assistantText)
253
+ return;
254
+ for (const structured of (0, event_extractor_js_1.extractStructuredEvents)({
255
+ eventType: "message.updated",
256
+ sessionId: part.sessionID,
257
+ properties: event.properties,
258
+ messageText: assistantText,
259
+ role: "assistant",
260
+ })) {
261
+ await redisEvents.recordEvent(canonicalSessionId, state.groupId, structured);
262
+ }
263
+ return;
264
+ }
265
+ if (!passthroughEventTypes.has(event.type)) {
266
+ return;
267
+ }
268
+ const sessionId = getEventSessionId(event.properties);
269
+ if (!sessionId)
270
+ return;
271
+ sessionManager.markSessionActive(sessionId);
272
+ const { state, resolved, canonicalSessionId } = await sessionManager
273
+ .resolveSessionState(sessionId);
274
+ if (!resolved || !state?.isMain)
275
+ return;
276
+ if (!canonicalSessionId)
277
+ return;
278
+ for (const structured of (0, event_extractor_js_1.extractStructuredEvents)({
279
+ eventType: event.type,
280
+ sessionId,
281
+ properties: event.properties,
282
+ })) {
283
+ await redisEvents.recordEvent(canonicalSessionId, state.groupId, structured);
284
+ }
285
+ }
286
+ catch (err) {
287
+ logger_js_1.logger.error("Event handler error", { type: event.type, err });
288
+ }
289
+ };
290
+ }
@@ -0,0 +1,9 @@
1
+ import type { Hooks } from "@opencode-ai/plugin";
2
+ import type { SessionManager } from "../session.js";
3
+ type MessagesTransformHook = NonNullable<Hooks["experimental.chat.messages.transform"]>;
4
+ export interface MessagesHandlerDeps {
5
+ sessionManager: SessionManager;
6
+ }
7
+ export declare function createMessagesHandler(deps: MessagesHandlerDeps): MessagesTransformHook;
8
+ export {};
9
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/src/handlers/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAOjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,KAAK,qBAAqB,GAAG,WAAW,CACtC,KAAK,CAAC,sCAAsC,CAAC,CAC9C,CAAC;AAIF,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,cAAc,CAAC;CAChC;AAkCD,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,mBAAmB,GACxB,qBAAqB,CAyFvB"}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createMessagesHandler = createMessagesHandler;
4
+ const logger_js_1 = require("../services/logger.js");
5
+ const render_utils_js_1 = require("../services/render-utils.js");
6
+ const utils_js_1 = require("../utils.js");
7
+ const asRecord = (value) => value && typeof value === "object" && !Array.isArray(value)
8
+ ? value
9
+ : undefined;
10
+ const getTransformMessage = (input) => {
11
+ const message = asRecord(input)?.message;
12
+ return typeof message === "string" ? message : undefined;
13
+ };
14
+ const getLatestUserText = (output) => {
15
+ const lastUserEntry = output.messages
16
+ .findLast((message) => message.info.role === "user");
17
+ const textPart = lastUserEntry?.parts.find(utils_js_1.isTextPart);
18
+ return textPart
19
+ ? (0, render_utils_js_1.sanitizeMemoryInputPreservingMemoryBlocks)(textPart.text)
20
+ : undefined;
21
+ };
22
+ const scrubPromptMemoryText = (text) => {
23
+ const stripped = (0, render_utils_js_1.stripInjectedMemoryBlocks)(text);
24
+ if (stripped === text)
25
+ return text;
26
+ return stripped.replace(/\r\n/g, "\n")
27
+ .replace(/[\t ]+\n/g, "\n")
28
+ .replace(/\n[\t ]+/g, "\n")
29
+ .replace(/[\t ]{2,}/g, " ")
30
+ .replace(/\n{3,}/g, "\n\n")
31
+ .trim();
32
+ };
33
+ function createMessagesHandler(deps) {
34
+ const { sessionManager } = deps;
35
+ return async (input, output) => {
36
+ const lastUserEntry = output.messages
37
+ .findLast((message) => message.info.role === "user");
38
+ if (!lastUserEntry)
39
+ return;
40
+ const sourceSessionID = lastUserEntry.info.sessionID;
41
+ try {
42
+ const { state, resolved, canonicalSessionId, } = await sessionManager.resolveSessionState(sourceSessionID);
43
+ if (!resolved || !canonicalSessionId)
44
+ return;
45
+ if (!state?.isMain)
46
+ return;
47
+ sessionManager.markResolvedSessionActive(sourceSessionID, canonicalSessionId);
48
+ let rewroteExistingMemory = false;
49
+ for (const entry of output.messages) {
50
+ for (const part of entry.parts) {
51
+ if ((0, utils_js_1.isTextPart)(part) &&
52
+ !rewroteExistingMemory &&
53
+ (part.text.includes("<session_memory") ||
54
+ part.text.includes("<memory") ||
55
+ part.text.includes("<persistent_memory"))) {
56
+ rewroteExistingMemory = true;
57
+ }
58
+ }
59
+ }
60
+ const recallQuery = (0, render_utils_js_1.sanitizeMemoryInput)((0, render_utils_js_1.stripInjectedMemoryBlocks)(getTransformMessage(input) ?? getLatestUserText(output) ?? "")) || undefined;
61
+ const prepared = state.pendingInjection ??
62
+ await sessionManager.prepareInjection(canonicalSessionId, recallQuery);
63
+ if (!prepared)
64
+ return;
65
+ const latestUserText = lastUserEntry.parts.find(utils_js_1.isTextPart)?.text;
66
+ for (const entry of output.messages) {
67
+ for (const part of entry.parts) {
68
+ if ((0, utils_js_1.isTextPart)(part)) {
69
+ part.text = scrubPromptMemoryText(part.text);
70
+ }
71
+ }
72
+ }
73
+ const textPart = lastUserEntry.parts.find(utils_js_1.isTextPart);
74
+ if (!textPart || latestUserText === undefined)
75
+ return;
76
+ const effectiveUserText = (0, render_utils_js_1.sanitizeMemoryInputPreservingMemoryBlocks)(latestUserText);
77
+ if (!effectiveUserText) {
78
+ sessionManager.clearPendingInjection(state, prepared);
79
+ return;
80
+ }
81
+ textPart.text = `${prepared.envelope}\n\n${effectiveUserText}`;
82
+ logger_js_1.logger.info("Injected canonical session_memory block", {
83
+ sessionID: canonicalSessionId,
84
+ sourceSessionID,
85
+ rewroteExistingMemory,
86
+ });
87
+ sessionManager.clearPendingInjection(state, prepared);
88
+ }
89
+ catch (error) {
90
+ logger_js_1.logger.warn("Unable to prepare local session memory for messages transform", {
91
+ sessionID: sourceSessionID,
92
+ error,
93
+ });
94
+ }
95
+ };
96
+ }
@@ -0,0 +1,5 @@
1
+ import type { Plugin } from "@opencode-ai/plugin";
2
+ export declare const warnOnGraphitiStartupUnavailable: (connected: boolean, endpoint: string) => void;
3
+ export declare const warnOnRedisStartupUnavailable: (connected: boolean, endpoint: string) => void;
4
+ export declare const graphiti: Plugin;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAmD/D,eAAO,MAAM,gCAAgC,GAC3C,WAAW,OAAO,EAClB,UAAU,MAAM,KACf,IAMF,CAAC;AAEF,eAAO,MAAM,6BAA6B,GACxC,WAAW,OAAO,EAClB,UAAU,MAAM,KACf,IAMF,CAAC;AAyBF,eAAO,MAAM,QAAQ,EAAE,MA0ItB,CAAC"}
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.graphiti = exports.warnOnRedisStartupUnavailable = exports.warnOnGraphitiStartupUnavailable = void 0;
4
+ const config_js_1 = require("./config.js");
5
+ const chat_js_1 = require("./handlers/chat.js");
6
+ const compacting_js_1 = require("./handlers/compacting.js");
7
+ const event_js_1 = require("./handlers/event.js");
8
+ const messages_js_1 = require("./handlers/messages.js");
9
+ const session_js_1 = require("./session.js");
10
+ const batch_drain_js_1 = require("./services/batch-drain.js");
11
+ const connection_manager_js_1 = require("./services/connection-manager.js");
12
+ const graphiti_async_js_1 = require("./services/graphiti-async.js");
13
+ const graphiti_mcp_js_1 = require("./services/graphiti-mcp.js");
14
+ const opencode_warning_js_1 = require("./services/opencode-warning.js");
15
+ const redis_cache_js_1 = require("./services/redis-cache.js");
16
+ const redis_client_js_1 = require("./services/redis-client.js");
17
+ const redis_events_js_1 = require("./services/redis-events.js");
18
+ const redis_snapshot_js_1 = require("./services/redis-snapshot.js");
19
+ const runtime_teardown_js_1 = require("./services/runtime-teardown.js");
20
+ const utils_js_1 = require("./utils.js");
21
+ const warnOnGraphitiStartupUnavailable = (connected, endpoint) => {
22
+ if (connected)
23
+ return;
24
+ (0, opencode_warning_js_1.notifyGraphitiAvailabilityIssue)(`Graphiti MCP unavailable at ${endpoint}; continuing without persistent memory.`, { endpoint });
25
+ };
26
+ exports.warnOnGraphitiStartupUnavailable = warnOnGraphitiStartupUnavailable;
27
+ const warnOnRedisStartupUnavailable = (connected, endpoint) => {
28
+ if (connected)
29
+ return;
30
+ (0, opencode_warning_js_1.notifyGraphitiAvailabilityIssue)(`Redis unavailable at ${endpoint}; continuing without persistent memory.`, { endpoint });
31
+ };
32
+ exports.warnOnRedisStartupUnavailable = warnOnRedisStartupUnavailable;
33
+ const defaultGraphitiDependencies = {
34
+ loadConfig: config_js_1.loadConfig,
35
+ setOpenCodeClient: opencode_warning_js_1.setOpenCodeClient,
36
+ warnOnGraphitiStartupUnavailable: exports.warnOnGraphitiStartupUnavailable,
37
+ warnOnRedisStartupUnavailable: exports.warnOnRedisStartupUnavailable,
38
+ GraphitiConnectionManager: connection_manager_js_1.GraphitiConnectionManager,
39
+ RedisClient: redis_client_js_1.RedisClient,
40
+ registerRuntimeTeardown: runtime_teardown_js_1.registerRuntimeTeardown,
41
+ GraphitiMcpClient: graphiti_mcp_js_1.GraphitiMcpClient,
42
+ RedisEventsService: redis_events_js_1.RedisEventsService,
43
+ RedisSnapshotService: redis_snapshot_js_1.RedisSnapshotService,
44
+ RedisCacheService: redis_cache_js_1.RedisCacheService,
45
+ BatchDrainService: batch_drain_js_1.BatchDrainService,
46
+ GraphitiAsyncService: graphiti_async_js_1.GraphitiAsyncService,
47
+ SessionManager: session_js_1.SessionManager,
48
+ createEventHandler: event_js_1.createEventHandler,
49
+ createChatHandler: chat_js_1.createChatHandler,
50
+ createCompactingHandler: compacting_js_1.createCompactingHandler,
51
+ createMessagesHandler: messages_js_1.createMessagesHandler,
52
+ makeGroupId: utils_js_1.makeGroupId,
53
+ makeUserGroupId: utils_js_1.makeUserGroupId,
54
+ };
55
+ const graphiti = (input, dependencies = defaultGraphitiDependencies) => {
56
+ const config = dependencies.loadConfig(input.directory);
57
+ dependencies.setOpenCodeClient(input.client);
58
+ let startupUnavailableReported = false;
59
+ let startupChecksRemaining = 2;
60
+ const reportStartupUnavailable = (service) => {
61
+ if (startupUnavailableReported)
62
+ return;
63
+ startupUnavailableReported = true;
64
+ if (service === "graphiti") {
65
+ dependencies.warnOnGraphitiStartupUnavailable(false, config.graphiti.endpoint);
66
+ return;
67
+ }
68
+ dependencies.warnOnRedisStartupUnavailable(false, config.redis.endpoint);
69
+ };
70
+ const reportStartupCheckSucceeded = () => {
71
+ startupChecksRemaining -= 1;
72
+ if (startupUnavailableReported || startupChecksRemaining !== 0)
73
+ return;
74
+ dependencies.warnOnGraphitiStartupUnavailable(true, config.graphiti.endpoint);
75
+ };
76
+ const connectionManager = new dependencies.GraphitiConnectionManager({
77
+ endpoint: config.graphiti.endpoint,
78
+ });
79
+ connectionManager.start();
80
+ void connectionManager.ready()
81
+ .then((connected) => {
82
+ if (!connected) {
83
+ reportStartupUnavailable("graphiti");
84
+ return;
85
+ }
86
+ reportStartupCheckSucceeded();
87
+ })
88
+ .catch(() => {
89
+ reportStartupUnavailable("graphiti");
90
+ });
91
+ const redisClient = new dependencies.RedisClient({
92
+ endpoint: config.redis.endpoint,
93
+ });
94
+ void redisClient.connect()
95
+ .then(() => {
96
+ reportStartupCheckSucceeded();
97
+ })
98
+ .catch(() => {
99
+ reportStartupUnavailable("redis");
100
+ });
101
+ dependencies.registerRuntimeTeardown([
102
+ {
103
+ name: "redis",
104
+ run: () => redisClient.close(),
105
+ },
106
+ {
107
+ name: "graphiti",
108
+ run: () => connectionManager.stop(),
109
+ },
110
+ ]);
111
+ const graphitiClient = new dependencies.GraphitiMcpClient(connectionManager);
112
+ const redisEvents = new dependencies.RedisEventsService(redisClient, {
113
+ sessionTtlSeconds: config.redis.sessionTtlSeconds,
114
+ });
115
+ const redisSnapshot = new dependencies.RedisSnapshotService(redisClient, {
116
+ ttlSeconds: config.redis.sessionTtlSeconds * 2,
117
+ });
118
+ const redisCache = new dependencies.RedisCacheService(redisClient, {
119
+ ttlSeconds: config.redis.cacheTtlSeconds,
120
+ driftThreshold: config.graphiti.driftThreshold,
121
+ });
122
+ const batchDrain = new dependencies.BatchDrainService(redisClient, redisEvents, {
123
+ batchSize: config.redis.batchSize,
124
+ batchMaxBytes: config.redis.batchMaxBytes,
125
+ drainRetryMax: config.redis.drainRetryMax,
126
+ });
127
+ const graphitiAsync = new dependencies.GraphitiAsyncService(graphitiClient, redisCache, batchDrain);
128
+ const defaultGroupId = dependencies.makeGroupId(config.graphiti.groupIdPrefix, input.directory);
129
+ const defaultUserGroupId = dependencies.makeUserGroupId(config.graphiti.groupIdPrefix, input.directory);
130
+ const sessionManager = new dependencies.SessionManager(defaultGroupId, defaultUserGroupId, input.client, redisEvents, redisSnapshot, redisCache, {
131
+ idleRetentionMs: config.redis.sessionTtlSeconds * 1000,
132
+ });
133
+ return Promise.resolve({
134
+ event: dependencies.createEventHandler({
135
+ sessionManager,
136
+ redisEvents,
137
+ redisCache,
138
+ redisSnapshot,
139
+ graphitiAsync,
140
+ defaultGroupId,
141
+ defaultUserGroupId,
142
+ sdkClient: input.client,
143
+ directory: input.directory,
144
+ }),
145
+ "chat.message": dependencies.createChatHandler({
146
+ sessionManager,
147
+ redisEvents,
148
+ graphitiAsync,
149
+ drainTriggerSize: config.redis.batchSize,
150
+ }),
151
+ "experimental.session.compacting": dependencies.createCompactingHandler({
152
+ sessionManager,
153
+ }),
154
+ "experimental.chat.messages.transform": dependencies.createMessagesHandler({
155
+ sessionManager,
156
+ }),
157
+ });
158
+ };
159
+ exports.graphiti = graphiti;
@@ -0,0 +1,23 @@
1
+ import type { GraphitiMcpClient } from "./graphiti-mcp.js";
2
+ import type { RedisClient } from "./redis-client.js";
3
+ import type { RedisEventsService } from "./redis-events.js";
4
+ export interface BatchDrainServiceOptions {
5
+ batchSize: number;
6
+ batchMaxBytes: number;
7
+ drainRetryMax: number;
8
+ claimHeartbeatIntervalMs?: number;
9
+ }
10
+ export declare class BatchDrainService {
11
+ private readonly redis;
12
+ private readonly events;
13
+ private readonly options;
14
+ constructor(redis: RedisClient, events: RedisEventsService, options: BatchDrainServiceOptions);
15
+ private getClaimHeartbeatIntervalMs;
16
+ private getRetryState;
17
+ private setRetryState;
18
+ drainGroup(groupId: string, graphiti: GraphitiMcpClient): Promise<{
19
+ status: "empty" | "backoff" | "success" | "dead-letter" | "retry";
20
+ drained: number;
21
+ }>;
22
+ }
23
+ //# sourceMappingURL=batch-drain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-drain.d.ts","sourceRoot":"","sources":["../../../src/src/services/batch-drain.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAS5D,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AA+BD,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAFP,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,wBAAwB;IAGpD,OAAO,CAAC,2BAA2B;YAiCrB,aAAa;YAab,aAAa;IAYrB,UAAU,CACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CACR;QACE,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,OAAO,CAAC;QAClE,OAAO,EAAE,MAAM,CAAC;KACjB,CACF;CAiJF"}