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,669 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.estimateEventSize = exports.extractStructuredEvents = exports.extractCompactionEvent = exports.extractSessionCreatedEvent = exports.extractAssistantMessageEvent = exports.extractUserMessageEvent = exports.createSessionEvent = void 0;
4
+ const render_utils_js_1 = require("./render-utils.js");
5
+ const MAX_SUMMARY = 200;
6
+ const MAX_BODY = 4096;
7
+ const priorityByCategory = {
8
+ decision: 0,
9
+ preference: 0,
10
+ "rule.load": 0,
11
+ "task.create": 0,
12
+ "task.update": 1,
13
+ "task.complete": 1,
14
+ "file.read": 1,
15
+ "file.write": 1,
16
+ "file.edit": 1,
17
+ "file.search": 2,
18
+ "cwd.change": 2,
19
+ "env.change": 2,
20
+ error: 2,
21
+ "git.activity": 3,
22
+ "subagent.start": 1,
23
+ "subagent.finish": 3,
24
+ "integration.call": 3,
25
+ intent: 0,
26
+ "data.import": 4,
27
+ discovery: 4,
28
+ message: 4,
29
+ "session.meta": 3,
30
+ };
31
+ const textEncoder = new TextEncoder();
32
+ const eventRoles = new Set(["user", "assistant", "tool", "system"]);
33
+ const normalizeWhitespace = (text) => text.replace(/\s+/g, " ").trim();
34
+ const normalizeMemoryWhitespace = (text) => normalizeWhitespace((0, render_utils_js_1.sanitizeMemoryInput)(text));
35
+ const summarize = (text) => normalizeWhitespace(text).slice(0, MAX_SUMMARY);
36
+ const truncateBody = (text) => text.slice(0, MAX_BODY);
37
+ const truncateDetail = (text) => text.slice(0, 600);
38
+ const truncateContinuity = (text) => text.slice(0, 800);
39
+ const USER_DECISION_PATTERN = /\b(?:must|should|keep|prefer|never|always|do not|don't|avoid|require|only)\b/i;
40
+ const USER_TASK_PATTERN = /\b(?:implement|update|fix|continue|finish|complete|add|remove|refactor|investigate|revisit|clean(?:up)?|align|strip|prevent|enforce|make|keep)\b/i;
41
+ const ASSISTANT_META_PATTERN = /\b(?:plan per target|i(?:'m| am| will| can| should| need to)|reading|checking|inspecting|updating|running|prepared|schedule(?:d)?|inject(?:ed|ion)|hot-tier|continuity)/i;
42
+ const makeId = () => crypto.randomUUID?.() ??
43
+ `${Date.now()}-${Math.random().toString(16).slice(2)}`;
44
+ const asRecord = (value) => value && typeof value === "object" && !Array.isArray(value)
45
+ ? value
46
+ : undefined;
47
+ const asString = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
48
+ const asEventRole = (value) => {
49
+ const role = asString(value);
50
+ return role && eventRoles.has(role)
51
+ ? role
52
+ : undefined;
53
+ };
54
+ const asNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
55
+ const toText = (value) => {
56
+ if (typeof value === "string") {
57
+ const normalized = normalizeWhitespace(value);
58
+ return normalized || undefined;
59
+ }
60
+ if (typeof value === "number" || typeof value === "boolean") {
61
+ return String(value);
62
+ }
63
+ if (Array.isArray(value)) {
64
+ const joined = value.map((item) => toText(item)).filter(Boolean).join(" ");
65
+ return joined || undefined;
66
+ }
67
+ const record = asRecord(value);
68
+ if (!record)
69
+ return undefined;
70
+ for (const key of [
71
+ "text",
72
+ "summary",
73
+ "message",
74
+ "content",
75
+ "body",
76
+ "description",
77
+ "prompt",
78
+ "query",
79
+ "title",
80
+ "name",
81
+ "value",
82
+ "reason",
83
+ "goal",
84
+ "status",
85
+ "intent",
86
+ ]) {
87
+ const result = toText(record[key]);
88
+ if (result)
89
+ return result;
90
+ }
91
+ return undefined;
92
+ };
93
+ const sanitizeExtractedText = (value) => value ? normalizeMemoryWhitespace(value) : "";
94
+ const sanitizeRefs = (refs) => refs.map((ref) => (0, render_utils_js_1.sanitizeMemoryInput)(ref)).filter(Boolean);
95
+ const shouldRejectUserText = (text) => !text || (0, render_utils_js_1.looksLikeToolTranscript)(text) || (0, render_utils_js_1.looksTranscriptHeavy)(text);
96
+ const shouldPromoteUserDecision = (text) => USER_DECISION_PATTERN.test(text) && !(0, render_utils_js_1.looksLikeOperationalChatter)(text);
97
+ const shouldPromoteUserTask = (text) => USER_TASK_PATTERN.test(text) && !(0, render_utils_js_1.looksLikeOperationalChatter)(text);
98
+ const shouldPromoteAssistantSignal = (text) => !(0, render_utils_js_1.looksLikeOperationalChatter)(text) && !ASSISTANT_META_PATTERN.test(text) &&
99
+ !(0, render_utils_js_1.looksTranscriptHeavy)(text) && (0, render_utils_js_1.isHighValueMemoryText)(text);
100
+ const shouldCaptureToolError = (tool, text) => {
101
+ const lowerTool = tool.toLowerCase();
102
+ const lowerText = text.toLowerCase();
103
+ return !hasLowerKeyword(lowerTool, "read", "open", "grep", "search", "glob") &&
104
+ hasLowerKeyword(lowerText, "error", "failed", "exception", "unable", "exit");
105
+ };
106
+ const sourceKindForRole = (role) => role === "assistant"
107
+ ? "assistant-response"
108
+ : role === "user"
109
+ ? "user-request"
110
+ : role === "tool"
111
+ ? "tool-activity"
112
+ : "system-state";
113
+ const pickStrings = (values, limit = 8) => {
114
+ const seen = new Set();
115
+ const result = [];
116
+ for (const value of values) {
117
+ const text = toText(value);
118
+ if (!text || seen.has(text))
119
+ continue;
120
+ seen.add(text);
121
+ result.push(text);
122
+ if (result.length >= limit)
123
+ break;
124
+ }
125
+ return result;
126
+ };
127
+ const pickKeywords = (values, limit = 8) => pickStrings(values, limit).map((value) => summarize(value));
128
+ const collectInlinePathRefs = (text) => {
129
+ const refs = new Set();
130
+ for (const match of text.matchAll(/(?:[A-Za-z0-9._-]+\/)+[A-Za-z0-9._-]+(?:\.[A-Za-z0-9]{1,8})?/g)) {
131
+ const value = match[0]?.trim();
132
+ if (value)
133
+ refs.add(value);
134
+ }
135
+ return [...refs];
136
+ };
137
+ const collectPathRefs = (value, refs = new Set()) => {
138
+ if (!value)
139
+ return [...refs];
140
+ if (typeof value === "string") {
141
+ const trimmed = value.trim();
142
+ if (trimmed &&
143
+ (trimmed.includes("/") || trimmed.includes("\\") ||
144
+ /\.[A-Za-z0-9]{1,8}$/.test(trimmed))) {
145
+ refs.add(trimmed);
146
+ }
147
+ return [...refs];
148
+ }
149
+ if (Array.isArray(value)) {
150
+ for (const item of value)
151
+ collectPathRefs(item, refs);
152
+ return [...refs];
153
+ }
154
+ const record = asRecord(value);
155
+ if (!record)
156
+ return [...refs];
157
+ const nestedCall = asRecord(record.call);
158
+ if (nestedCall?.tool !== undefined) {
159
+ collectPathRefs(nestedCall, refs);
160
+ collectPathRefs(nestedCall.tool, refs);
161
+ }
162
+ for (const [key, item] of Object.entries(record)) {
163
+ if (/(path|paths|file|files|ref|refs|cwd|directory)/i.test(key)) {
164
+ collectPathRefs(item, refs);
165
+ }
166
+ }
167
+ return [...refs];
168
+ };
169
+ const hasLowerKeyword = (haystack, ...needles) => {
170
+ if (!haystack)
171
+ return false;
172
+ return needles.some((needle) => haystack.includes(needle));
173
+ };
174
+ const hasKeyword = (haystack, ...needles) => hasLowerKeyword(haystack?.toLowerCase(), ...needles);
175
+ const compactParts = (...parts) => {
176
+ const fragments = [];
177
+ for (const part of parts) {
178
+ const value = part ? normalizeWhitespace(part) : "";
179
+ if (!value)
180
+ continue;
181
+ const normalized = value.toLowerCase();
182
+ if (fragments.some((fragment) => fragment.toLowerCase() === normalized)) {
183
+ continue;
184
+ }
185
+ fragments.push(value);
186
+ }
187
+ const compact = fragments.join(" — ");
188
+ return compact || undefined;
189
+ };
190
+ const collectMetadataKeywords = (props) => pickKeywords([
191
+ props.tool,
192
+ props.name,
193
+ props.integration,
194
+ props.status,
195
+ props.result,
196
+ props.reason,
197
+ props.cwd,
198
+ ]);
199
+ const compactToolMetadata = (props, extra = {}) => {
200
+ const metadata = {};
201
+ for (const [key, value] of Object.entries({
202
+ tool: props.tool,
203
+ name: props.name,
204
+ integration: props.integration,
205
+ status: props.status,
206
+ result: props.result,
207
+ exitCode: props.exitCode,
208
+ cwd: props.cwd,
209
+ blocking: props.blocking,
210
+ resolved: props.resolved,
211
+ ...extra,
212
+ })) {
213
+ if (typeof value === "string" || typeof value === "number" ||
214
+ typeof value === "boolean") {
215
+ metadata[key] = value;
216
+ }
217
+ }
218
+ return metadata;
219
+ };
220
+ const buildContinuityText = (summary, detail, refs, keywords) => {
221
+ const fragments = [];
222
+ for (const candidate of [summary, detail, refs?.join(" "), keywords?.join(" ")]) {
223
+ const value = candidate ? normalizeWhitespace(candidate) : "";
224
+ if (!value)
225
+ continue;
226
+ const normalized = value.toLowerCase();
227
+ let replaced = false;
228
+ for (let index = fragments.length - 1; index >= 0; index -= 1) {
229
+ const existing = fragments[index];
230
+ const existingNormalized = existing.toLowerCase();
231
+ if (existingNormalized === normalized ||
232
+ existingNormalized.includes(normalized)) {
233
+ replaced = true;
234
+ break;
235
+ }
236
+ if (normalized.includes(existingNormalized)) {
237
+ fragments.splice(index, 1);
238
+ }
239
+ }
240
+ if (!replaced)
241
+ fragments.push(value);
242
+ }
243
+ const continuity = fragments.join(" ");
244
+ return continuity ? truncateContinuity(continuity) : undefined;
245
+ };
246
+ const compactMessageBody = (text) => {
247
+ const normalized = normalizeWhitespace(text);
248
+ if (!normalized)
249
+ return undefined;
250
+ if ((0, render_utils_js_1.looksTranscriptHeavy)(normalized) || (0, render_utils_js_1.looksLikeToolTranscript)(normalized)) {
251
+ return undefined;
252
+ }
253
+ return truncateBody(normalized.slice(0, 480));
254
+ };
255
+ const buildToolActivityContext = (tool, text, refs, props, options = {}) => {
256
+ const normalizedText = (0, render_utils_js_1.looksTranscriptHeavy)(text) || (0, render_utils_js_1.looksLikeToolTranscript)(text)
257
+ ? ""
258
+ : sanitizeExtractedText(text);
259
+ const cleanRefs = sanitizeRefs(refs);
260
+ const refSummary = cleanRefs.slice(0, 3).join(", ");
261
+ const statusSummary = compactParts(asString(props.status), asString(props.result), typeof props.exitCode === "number" ? `exit ${props.exitCode}` : undefined);
262
+ const summary = compactParts(options.summaryPrefix ?? tool, refSummary, statusSummary) ?? `${tool} activity`;
263
+ const detail = compactParts(summarize(normalizedText), statusSummary, cleanRefs.length > 0
264
+ ? `refs ${cleanRefs.slice(0, 4).join(", ")}`
265
+ : undefined);
266
+ const keywords = pickKeywords([
267
+ tool,
268
+ ...cleanRefs,
269
+ ...collectMetadataKeywords(props),
270
+ ...(options.extraKeywords ?? []),
271
+ ]);
272
+ return {
273
+ summary,
274
+ body: options.preserveBody ? compactMessageBody(normalizedText) : undefined,
275
+ detail,
276
+ continuityText: buildContinuityText(summary, detail, cleanRefs, keywords),
277
+ keywords,
278
+ sourceKind: options.sourceKind ?? "tool-activity",
279
+ refs: cleanRefs,
280
+ metadata: compactToolMetadata(props, options.extraMetadata),
281
+ };
282
+ };
283
+ const normalizeInput = (input) => {
284
+ const props = input.properties ?? {};
285
+ const text = sanitizeExtractedText(input.messageText ?? toText(props) ?? "");
286
+ const refs = [
287
+ ...new Set([...collectPathRefs(props), ...collectInlinePathRefs(text)]),
288
+ ];
289
+ return {
290
+ eventType: input.eventType,
291
+ props,
292
+ sessionId: input.sessionId,
293
+ text,
294
+ refs,
295
+ role: input.role ?? "system",
296
+ messageCount: asNumber(input.messageCount) ?? 1,
297
+ };
298
+ };
299
+ const createEvent = (category, role, context) => ({
300
+ id: makeId(),
301
+ ts: Date.now(),
302
+ category,
303
+ priority: priorityByCategory[category],
304
+ role,
305
+ summary: summarize(context.summary),
306
+ body: context.body ? truncateBody(context.body) : undefined,
307
+ detail: context.detail ? truncateDetail(context.detail) : undefined,
308
+ continuityText: context.continuityText
309
+ ? truncateContinuity(context.continuityText)
310
+ : undefined,
311
+ keywords: context.keywords?.filter(Boolean).slice(0, 8),
312
+ sourceKind: context.sourceKind,
313
+ refs: context.refs?.filter(Boolean),
314
+ metadata: context.metadata,
315
+ });
316
+ const createSessionEvent = (category, role, context) => createEvent(category, role, context);
317
+ exports.createSessionEvent = createSessionEvent;
318
+ const extractUserMessageEvent = (text, messageCount) => createEvent(messageCount <= 1 ? "intent" : "message", "user", {
319
+ summary: text,
320
+ body: compactMessageBody(text),
321
+ detail: summarize(text),
322
+ continuityText: buildContinuityText(text, summarize(text)),
323
+ keywords: pickKeywords([text]),
324
+ sourceKind: "user-request",
325
+ });
326
+ exports.extractUserMessageEvent = extractUserMessageEvent;
327
+ const extractAssistantMessageEvent = (text) => createEvent("message", "assistant", {
328
+ summary: summarize(text),
329
+ detail: compactParts("Assistant response", summarize(text)),
330
+ continuityText: buildContinuityText(summarize(text), summarize(text)),
331
+ keywords: pickKeywords([text]),
332
+ sourceKind: "assistant-response",
333
+ });
334
+ exports.extractAssistantMessageEvent = extractAssistantMessageEvent;
335
+ const extractSessionCreatedEvent = (sessionId) => createEvent("session.meta", "system", {
336
+ summary: `Session created${sessionId ? `: ${sessionId}` : ""}`,
337
+ detail: sessionId
338
+ ? `Session ${sessionId} initialized`
339
+ : "Session initialized",
340
+ continuityText: sessionId
341
+ ? `session created ${sessionId}`
342
+ : "session created",
343
+ keywords: pickKeywords([sessionId, "session", "created"]),
344
+ sourceKind: "system-state",
345
+ refs: sessionId ? [sessionId] : undefined,
346
+ metadata: sessionId ? { sessionId } : undefined,
347
+ });
348
+ exports.extractSessionCreatedEvent = extractSessionCreatedEvent;
349
+ const extractCompactionEvent = (summary) => createEvent("task.update", "system", {
350
+ summary: `Session compacted: ${summary}`,
351
+ detail: summarize(summary),
352
+ continuityText: buildContinuityText(`Session compacted: ${summary}`, summary),
353
+ keywords: pickKeywords([summary, "compacted"]),
354
+ sourceKind: "system-state",
355
+ metadata: { compacted: true },
356
+ });
357
+ exports.extractCompactionEvent = extractCompactionEvent;
358
+ const inferTaskCategory = (text) => {
359
+ if (hasKeyword(text, "complete", "completed", "done", "finished", "resolved", "fixed")) {
360
+ return "task.complete";
361
+ }
362
+ if (hasKeyword(text, "start", "create", "begin", "plan", "goal", "implement")) {
363
+ return "task.create";
364
+ }
365
+ return "task.update";
366
+ };
367
+ const extractFromHookPayload = (input) => {
368
+ const normalized = normalizeInput(input);
369
+ const { eventType, props, sessionId, text, refs, role, messageCount } = normalized;
370
+ if (eventType === "session.created") {
371
+ return [
372
+ (0, exports.extractSessionCreatedEvent)(sessionId ?? asString(asRecord(props.info)?.id)),
373
+ ];
374
+ }
375
+ if (eventType === "session.compacted" && text) {
376
+ return [(0, exports.extractCompactionEvent)(text)];
377
+ }
378
+ if (eventType === "message.updated" && role === "assistant" && text) {
379
+ return [(0, exports.extractAssistantMessageEvent)(text)];
380
+ }
381
+ if (eventType === "chat.message" && text) {
382
+ return [(0, exports.extractUserMessageEvent)(text, messageCount)];
383
+ }
384
+ const genericSummary = text || eventType;
385
+ return [createEvent("session.meta", role, {
386
+ summary: genericSummary,
387
+ detail: summarize(text),
388
+ continuityText: buildContinuityText(genericSummary, summarize(text), refs),
389
+ keywords: pickKeywords([eventType, text, ...refs]),
390
+ sourceKind: role === "tool"
391
+ ? "tool-activity"
392
+ : role === "assistant"
393
+ ? "assistant-response"
394
+ : role === "user"
395
+ ? "user-request"
396
+ : "system-state",
397
+ refs,
398
+ metadata: { eventType },
399
+ })];
400
+ };
401
+ const extractStructuredEvents = (input) => {
402
+ const normalized = normalizeInput(input);
403
+ const { eventType, props, text, refs, role, messageCount } = normalized;
404
+ if (eventType === "chat.message") {
405
+ if (shouldRejectUserText(text))
406
+ return [];
407
+ const events = [(0, exports.extractUserMessageEvent)(text, messageCount)];
408
+ const lower = text.toLowerCase();
409
+ if (shouldPromoteUserDecision(text) &&
410
+ hasLowerKeyword(lower, "prefer", "please", "always", "never")) {
411
+ events.push(createEvent("preference", "user", {
412
+ summary: text,
413
+ detail: summarize(text),
414
+ continuityText: buildContinuityText(text, summarize(text)),
415
+ keywords: pickKeywords([text, "preference"]),
416
+ sourceKind: "user-request",
417
+ }));
418
+ }
419
+ if (shouldPromoteUserDecision(text) &&
420
+ hasLowerKeyword(lower, "decide", "decision", "must", "should", "keep ")) {
421
+ events.push(createEvent("decision", "user", {
422
+ summary: text,
423
+ detail: summarize(text),
424
+ continuityText: buildContinuityText(text, summarize(text)),
425
+ keywords: pickKeywords([text, "decision"]),
426
+ sourceKind: "user-request",
427
+ }));
428
+ }
429
+ if (hasLowerKeyword(lower, "import", "paste", "uploaded", "dataset", "csv", "json")) {
430
+ events.push(createEvent("data.import", "user", {
431
+ summary: text,
432
+ detail: compactParts("Imported or referenced data", summarize(text)),
433
+ continuityText: buildContinuityText(text, summarize(text), refs),
434
+ keywords: pickKeywords([text, ...refs, "data"]),
435
+ sourceKind: "user-request",
436
+ refs,
437
+ }));
438
+ }
439
+ if (shouldPromoteUserTask(text) && messageCount > 1) {
440
+ events.push(createEvent(inferTaskCategory(text), "user", {
441
+ summary: text,
442
+ detail: compactParts("User task", summarize(text)),
443
+ continuityText: buildContinuityText(text, summarize(text), refs),
444
+ keywords: pickKeywords([text, ...refs, "task"]),
445
+ sourceKind: "user-request",
446
+ refs,
447
+ }));
448
+ }
449
+ return events;
450
+ }
451
+ if (eventType === "message.updated") {
452
+ const resolvedRole = input.role ?? asEventRole(asRecord(props.info)?.role);
453
+ if (resolvedRole === "assistant" && text) {
454
+ if (!shouldPromoteAssistantSignal(text)) {
455
+ return [];
456
+ }
457
+ const events = [(0, exports.extractAssistantMessageEvent)(text)];
458
+ if (hasKeyword(text, "discovered", "found", "identified", "confirmed")) {
459
+ events.push(createEvent("discovery", "assistant", {
460
+ summary: text,
461
+ detail: summarize(text),
462
+ continuityText: buildContinuityText(text, summarize(text), refs),
463
+ keywords: pickKeywords([text, ...refs, "discovery"]),
464
+ sourceKind: "assistant-response",
465
+ refs,
466
+ }));
467
+ }
468
+ return events;
469
+ }
470
+ }
471
+ if (eventType === "task.updated") {
472
+ const task = asRecord(props.task) ?? props;
473
+ const summary = toText(task) ?? "Task updated";
474
+ return [createEvent(inferTaskCategory(summary), "system", {
475
+ summary,
476
+ detail: compactParts("Task update", summarize(summary)),
477
+ continuityText: buildContinuityText(summary, summarize(summary), refs),
478
+ keywords: pickKeywords([summary, task.id, task.path, ...refs]),
479
+ sourceKind: "system-state",
480
+ refs: pickStrings([task.id, task.path, ...refs]),
481
+ metadata: compactToolMetadata(task),
482
+ })];
483
+ }
484
+ if (eventType === "rules.loaded") {
485
+ const summary = pickStrings([props.name, props.path, props.source, text]).join(" — ") ||
486
+ "Rules loaded";
487
+ return [createEvent("rule.load", "system", {
488
+ summary,
489
+ detail: compactParts("Rules loaded", text || summary),
490
+ continuityText: buildContinuityText(summary, text || summary, refs),
491
+ keywords: pickKeywords([summary, ...refs, "rules"]),
492
+ sourceKind: "system-state",
493
+ refs,
494
+ metadata: compactToolMetadata(props),
495
+ })];
496
+ }
497
+ if (eventType === "tool.called" || eventType === "tool.completed") {
498
+ const tool = asString(props.tool) ?? asString(props.name) ??
499
+ toText(asRecord(props.call)?.tool) ?? "tool";
500
+ const summaryText = text || `${tool} activity`;
501
+ const lowerTool = tool.toLowerCase();
502
+ const lowerText = summaryText.toLowerCase();
503
+ if (hasLowerKeyword(lowerTool, "read", "open") ||
504
+ hasLowerKeyword(lowerText, "read file", "opened")) {
505
+ return [
506
+ createEvent("file.read", "tool", buildToolActivityContext(tool, summaryText, refs, props, {
507
+ summaryPrefix: "Read",
508
+ extraKeywords: ["file", "read"],
509
+ })),
510
+ ];
511
+ }
512
+ if (hasLowerKeyword(lowerTool, "write", "create") ||
513
+ hasLowerKeyword(lowerText, "wrote", "created file")) {
514
+ return [
515
+ createEvent("file.write", "tool", buildToolActivityContext(tool, summaryText, refs, props, {
516
+ summaryPrefix: "Wrote",
517
+ extraKeywords: ["file", "write"],
518
+ })),
519
+ ];
520
+ }
521
+ if (hasLowerKeyword(lowerTool, "edit", "patch", "replace") ||
522
+ hasLowerKeyword(lowerText, "updated file", "edited")) {
523
+ return [
524
+ createEvent("file.edit", "tool", buildToolActivityContext(tool, summaryText, refs, props, {
525
+ summaryPrefix: "Edited",
526
+ extraKeywords: ["file", "edit"],
527
+ })),
528
+ ];
529
+ }
530
+ if (hasLowerKeyword(lowerTool, "grep", "search", "glob") ||
531
+ hasLowerKeyword(lowerText, "searched", "query")) {
532
+ return [
533
+ createEvent("file.search", "tool", buildToolActivityContext(tool, summaryText, refs, props, {
534
+ summaryPrefix: "Searched",
535
+ extraKeywords: ["search"],
536
+ })),
537
+ ];
538
+ }
539
+ if (hasLowerKeyword(lowerTool, "git") ||
540
+ hasLowerKeyword(lowerText, "branch", "commit", "merge", "rebase", "push", "stash")) {
541
+ return [
542
+ createEvent("git.activity", "tool", buildToolActivityContext(tool, summaryText, refs, props, {
543
+ summaryPrefix: "Git",
544
+ extraKeywords: ["git"],
545
+ preserveBody: true,
546
+ })),
547
+ ];
548
+ }
549
+ const isIntegrationActivity = hasLowerKeyword(lowerTool, "graphiti", "mcp", "redis", "http") ||
550
+ asString(props.integration);
551
+ const isUnresolvedToolFailure = props.resolved === false;
552
+ if (shouldCaptureToolError(tool, summaryText) &&
553
+ (!isIntegrationActivity || isUnresolvedToolFailure)) {
554
+ return [createEvent("error", "tool", {
555
+ ...buildToolActivityContext(tool, summaryText, refs, props, {
556
+ summaryPrefix: "Tool error",
557
+ preserveBody: true,
558
+ extraKeywords: ["error", "failed"],
559
+ extraMetadata: isUnresolvedToolFailure ? { resolved: false } : {},
560
+ }),
561
+ })];
562
+ }
563
+ if (isIntegrationActivity) {
564
+ return [
565
+ createEvent("integration.call", "tool", buildToolActivityContext(tool, summaryText, refs, props, {
566
+ summaryPrefix: "Integration",
567
+ extraKeywords: ["integration"],
568
+ })),
569
+ ];
570
+ }
571
+ }
572
+ if (eventType === "environment.updated") {
573
+ const summary = text || "Environment updated";
574
+ const entries = [];
575
+ if (hasKeyword(summary, "cwd", "directory", "working directory")) {
576
+ entries.push(createEvent("cwd.change", "system", {
577
+ summary,
578
+ detail: compactParts("Working directory updated", text),
579
+ continuityText: buildContinuityText(summary, text, refs),
580
+ keywords: pickKeywords([summary, ...refs, "cwd"]),
581
+ sourceKind: "system-state",
582
+ refs,
583
+ metadata: compactToolMetadata(props),
584
+ }));
585
+ }
586
+ entries.push(createEvent("env.change", "system", {
587
+ summary,
588
+ detail: compactParts("Environment updated", text),
589
+ continuityText: buildContinuityText(summary, text, refs),
590
+ keywords: pickKeywords([summary, ...refs, "environment"]),
591
+ sourceKind: "system-state",
592
+ refs,
593
+ metadata: compactToolMetadata(props),
594
+ }));
595
+ return entries;
596
+ }
597
+ if (eventType === "subagent.started" || eventType === "subagent.finished") {
598
+ return [
599
+ createEvent(eventType === "subagent.started" ? "subagent.start" : "subagent.finish", "system", {
600
+ summary: text || eventType,
601
+ detail: compactParts(eventType === "subagent.started"
602
+ ? "Subagent started"
603
+ : "Subagent finished", text),
604
+ continuityText: buildContinuityText(text || eventType, text, refs),
605
+ keywords: pickKeywords([
606
+ text,
607
+ props.agentId,
608
+ props.sessionId,
609
+ ...refs,
610
+ ]),
611
+ sourceKind: "system-state",
612
+ refs: pickStrings([props.agentId, props.sessionId, ...refs]),
613
+ metadata: compactToolMetadata(props),
614
+ }),
615
+ ];
616
+ }
617
+ if (eventType === "session.idle") {
618
+ return [createEvent("session.meta", "system", {
619
+ summary: text || "Session idle",
620
+ detail: compactParts("Session idle", text),
621
+ continuityText: buildContinuityText(text || "Session idle", text, refs),
622
+ keywords: pickKeywords([text, eventType, ...refs]),
623
+ sourceKind: "system-state",
624
+ refs,
625
+ metadata: { ...props, eventType },
626
+ })];
627
+ }
628
+ if (text) {
629
+ const lower = text.toLowerCase();
630
+ if (role !== "assistant" &&
631
+ hasLowerKeyword(lower, "error", "failed", "exception", "blocker")) {
632
+ return [createEvent("error", role, {
633
+ summary: text,
634
+ detail: summarize(text),
635
+ continuityText: buildContinuityText(text, summarize(text), refs),
636
+ keywords: pickKeywords([text, ...refs, "error"]),
637
+ sourceKind: sourceKindForRole(role),
638
+ refs,
639
+ metadata: { ...props, resolved: false, eventType },
640
+ })];
641
+ }
642
+ if (role !== "assistant" &&
643
+ hasLowerKeyword(lower, "discover", "found", "inspect", "observed")) {
644
+ return [createEvent("discovery", role, {
645
+ summary: text,
646
+ detail: summarize(text),
647
+ continuityText: buildContinuityText(text, summarize(text), refs),
648
+ keywords: pickKeywords([text, ...refs, "discovery"]),
649
+ sourceKind: sourceKindForRole(role),
650
+ refs,
651
+ metadata: { ...props, eventType },
652
+ })];
653
+ }
654
+ return [createEvent("message", role, {
655
+ summary: text,
656
+ body: role === "user" ? compactMessageBody(text) : undefined,
657
+ detail: summarize(text),
658
+ continuityText: buildContinuityText(text, summarize(text), refs),
659
+ keywords: pickKeywords([text, ...refs]),
660
+ sourceKind: sourceKindForRole(role),
661
+ refs,
662
+ metadata: { ...props, eventType },
663
+ })];
664
+ }
665
+ return extractFromHookPayload(input);
666
+ };
667
+ exports.extractStructuredEvents = extractStructuredEvents;
668
+ const estimateEventSize = (event) => textEncoder.encode(JSON.stringify(event)).length;
669
+ exports.estimateEventSize = estimateEventSize;
@@ -0,0 +1,22 @@
1
+ import type { BatchDrainService } from "./batch-drain.js";
2
+ import type { GraphitiMcpClient } from "./graphiti-mcp.js";
3
+ import type { RedisCacheService } from "./redis-cache.js";
4
+ export declare class GraphitiAsyncService {
5
+ private readonly graphiti;
6
+ private readonly cache;
7
+ private readonly drain;
8
+ private readonly drainRetryDelayMs;
9
+ private readonly drainInFlight;
10
+ private readonly drainRetryTimers;
11
+ private readonly drainRecoveryTimers;
12
+ private readonly refreshInFlight;
13
+ private readonly primerInFlight;
14
+ constructor(graphiti: GraphitiMcpClient, cache: RedisCacheService, drain: BatchDrainService, drainRetryDelayMs?: number);
15
+ private armDrainRetry;
16
+ private armDrainRecovery;
17
+ private clearDrainRecovery;
18
+ schedulePrimer(groupId: string): void;
19
+ scheduleCacheRefresh(groupId: string, query: string): void;
20
+ scheduleDrain(groupId: string): void;
21
+ }
22
+ //# sourceMappingURL=graphiti-async.d.ts.map