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,621 @@
1
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
3
+ import manifest from "../../deno.js";
4
+ import { logger } from "./logger.js";
5
+ export class GraphitiOfflineError extends Error {
6
+ constructor(state, message) {
7
+ super(message ??
8
+ (state === "closing"
9
+ ? "Graphiti connection manager is closing"
10
+ : state === "stopped"
11
+ ? "Graphiti connection manager is stopped"
12
+ : "Graphiti connection manager is offline"));
13
+ Object.defineProperty(this, "state", {
14
+ enumerable: true,
15
+ configurable: true,
16
+ writable: true,
17
+ value: state
18
+ });
19
+ Object.defineProperty(this, "kind", {
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true,
23
+ value: "offline"
24
+ });
25
+ this.name = "GraphitiOfflineError";
26
+ }
27
+ }
28
+ export class GraphitiQueueTimeoutError extends Error {
29
+ constructor(message = "Graphiti request timed out while waiting for connection") {
30
+ super(message);
31
+ Object.defineProperty(this, "kind", {
32
+ enumerable: true,
33
+ configurable: true,
34
+ writable: true,
35
+ value: "queue-timeout"
36
+ });
37
+ this.name = "GraphitiQueueTimeoutError";
38
+ }
39
+ }
40
+ export class GraphitiRequestTimeoutError extends Error {
41
+ constructor(message = "Graphiti request timed out") {
42
+ super(message);
43
+ Object.defineProperty(this, "kind", {
44
+ enumerable: true,
45
+ configurable: true,
46
+ writable: true,
47
+ value: "request-timeout"
48
+ });
49
+ this.name = "GraphitiRequestTimeoutError";
50
+ }
51
+ }
52
+ export class GraphitiTransportError extends Error {
53
+ constructor(message = "Graphiti transport failure") {
54
+ super(message);
55
+ Object.defineProperty(this, "kind", {
56
+ enumerable: true,
57
+ configurable: true,
58
+ writable: true,
59
+ value: "transport-failure"
60
+ });
61
+ this.name = "GraphitiTransportError";
62
+ }
63
+ }
64
+ export class GraphitiSessionExpiredError extends Error {
65
+ constructor(message = "Graphiti session expired") {
66
+ super(message);
67
+ Object.defineProperty(this, "kind", {
68
+ enumerable: true,
69
+ configurable: true,
70
+ writable: true,
71
+ value: "session-expired"
72
+ });
73
+ this.name = "GraphitiSessionExpiredError";
74
+ }
75
+ }
76
+ export function isGraphitiOfflineError(err) {
77
+ return err instanceof GraphitiOfflineError;
78
+ }
79
+ export function isGraphitiTimeoutError(err) {
80
+ return err instanceof GraphitiQueueTimeoutError ||
81
+ err instanceof GraphitiRequestTimeoutError;
82
+ }
83
+ const validateEndpoint = (endpoint) => {
84
+ const normalized = endpoint.trim();
85
+ if (!normalized) {
86
+ throw new Error("Graphiti endpoint must not be empty");
87
+ }
88
+ new URL(normalized);
89
+ return normalized;
90
+ };
91
+ function createMcpConnection(endpoint) {
92
+ const client = new Client({
93
+ name: manifest.name,
94
+ version: manifest.version,
95
+ });
96
+ const transport = new StreamableHTTPClientTransport(new URL(endpoint));
97
+ return {
98
+ connect: () => client.connect(transport),
99
+ close: () => client.close(),
100
+ callTool: (request) => client.callTool(request),
101
+ };
102
+ }
103
+ function getErrorMessage(err) {
104
+ if (typeof err === "string")
105
+ return err;
106
+ if (!err || typeof err !== "object")
107
+ return "";
108
+ const { message, cause } = err;
109
+ if (typeof message === "string")
110
+ return message;
111
+ if (cause)
112
+ return getErrorMessage(cause);
113
+ return "";
114
+ }
115
+ function isRequestTimeout(err) {
116
+ if (!err || typeof err !== "object") {
117
+ return typeof err === "string" && /request timed out/i.test(err);
118
+ }
119
+ const { code } = err;
120
+ return code === -32001 || /request timed out/i.test(getErrorMessage(err));
121
+ }
122
+ function isSessionExpired(err) {
123
+ return !!(err &&
124
+ typeof err === "object" &&
125
+ "code" in err &&
126
+ err.code === 404);
127
+ }
128
+ function isTransportFailure(err) {
129
+ if (!err)
130
+ return false;
131
+ if (isRequestTimeout(err) || isSessionExpired(err))
132
+ return false;
133
+ const message = getErrorMessage(err);
134
+ if (/(socket hang up|fetch failed|network|connection reset|connection refused|econnrefused|terminated|broken pipe|stream closed|unexpected end|transport)/i
135
+ .test(message)) {
136
+ return true;
137
+ }
138
+ if (typeof err === "object") {
139
+ const { name } = err;
140
+ return name === "TypeError" && message.length > 0;
141
+ }
142
+ return false;
143
+ }
144
+ export class GraphitiConnectionManager {
145
+ constructor(options) {
146
+ Object.defineProperty(this, "endpoint", {
147
+ enumerable: true,
148
+ configurable: true,
149
+ writable: true,
150
+ value: void 0
151
+ });
152
+ Object.defineProperty(this, "requestDeadlineMs", {
153
+ enumerable: true,
154
+ configurable: true,
155
+ writable: true,
156
+ value: void 0
157
+ });
158
+ Object.defineProperty(this, "queueCapacity", {
159
+ enumerable: true,
160
+ configurable: true,
161
+ writable: true,
162
+ value: void 0
163
+ });
164
+ Object.defineProperty(this, "startupTimeoutMs", {
165
+ enumerable: true,
166
+ configurable: true,
167
+ writable: true,
168
+ value: void 0
169
+ });
170
+ Object.defineProperty(this, "reconnectInitialDelayMs", {
171
+ enumerable: true,
172
+ configurable: true,
173
+ writable: true,
174
+ value: void 0
175
+ });
176
+ Object.defineProperty(this, "reconnectMaxDelayMs", {
177
+ enumerable: true,
178
+ configurable: true,
179
+ writable: true,
180
+ value: void 0
181
+ });
182
+ Object.defineProperty(this, "reconnectMultiplier", {
183
+ enumerable: true,
184
+ configurable: true,
185
+ writable: true,
186
+ value: void 0
187
+ });
188
+ Object.defineProperty(this, "reconnectJitter", {
189
+ enumerable: true,
190
+ configurable: true,
191
+ writable: true,
192
+ value: void 0
193
+ });
194
+ Object.defineProperty(this, "connectionFactory", {
195
+ enumerable: true,
196
+ configurable: true,
197
+ writable: true,
198
+ value: void 0
199
+ });
200
+ Object.defineProperty(this, "random", {
201
+ enumerable: true,
202
+ configurable: true,
203
+ writable: true,
204
+ value: void 0
205
+ });
206
+ Object.defineProperty(this, "now", {
207
+ enumerable: true,
208
+ configurable: true,
209
+ writable: true,
210
+ value: void 0
211
+ });
212
+ Object.defineProperty(this, "setTimerImpl", {
213
+ enumerable: true,
214
+ configurable: true,
215
+ writable: true,
216
+ value: void 0
217
+ });
218
+ Object.defineProperty(this, "clearTimerImpl", {
219
+ enumerable: true,
220
+ configurable: true,
221
+ writable: true,
222
+ value: void 0
223
+ });
224
+ Object.defineProperty(this, "state", {
225
+ enumerable: true,
226
+ configurable: true,
227
+ writable: true,
228
+ value: "offline"
229
+ });
230
+ Object.defineProperty(this, "connection", {
231
+ enumerable: true,
232
+ configurable: true,
233
+ writable: true,
234
+ value: null
235
+ });
236
+ Object.defineProperty(this, "connectPromise", {
237
+ enumerable: true,
238
+ configurable: true,
239
+ writable: true,
240
+ value: null
241
+ });
242
+ Object.defineProperty(this, "reconnectTimer", {
243
+ enumerable: true,
244
+ configurable: true,
245
+ writable: true,
246
+ value: null
247
+ });
248
+ Object.defineProperty(this, "pendingRequests", {
249
+ enumerable: true,
250
+ configurable: true,
251
+ writable: true,
252
+ value: []
253
+ });
254
+ Object.defineProperty(this, "readyWaiters", {
255
+ enumerable: true,
256
+ configurable: true,
257
+ writable: true,
258
+ value: new Set()
259
+ });
260
+ Object.defineProperty(this, "reconnectDelayMs", {
261
+ enumerable: true,
262
+ configurable: true,
263
+ writable: true,
264
+ value: void 0
265
+ });
266
+ Object.defineProperty(this, "started", {
267
+ enumerable: true,
268
+ configurable: true,
269
+ writable: true,
270
+ value: false
271
+ });
272
+ Object.defineProperty(this, "flushingQueue", {
273
+ enumerable: true,
274
+ configurable: true,
275
+ writable: true,
276
+ value: false
277
+ });
278
+ Object.defineProperty(this, "stopPromise", {
279
+ enumerable: true,
280
+ configurable: true,
281
+ writable: true,
282
+ value: null
283
+ });
284
+ this.endpoint = validateEndpoint(options.endpoint);
285
+ this.requestDeadlineMs = options.requestDeadlineMs ?? 15_000;
286
+ this.queueCapacity = options.queueCapacity ?? 32;
287
+ this.startupTimeoutMs = options.startupTimeoutMs ?? this.requestDeadlineMs;
288
+ this.reconnectInitialDelayMs = options.reconnectInitialDelayMs ?? 1_000;
289
+ this.reconnectMaxDelayMs = options.reconnectMaxDelayMs ?? 60_000;
290
+ this.reconnectMultiplier = options.reconnectMultiplier ?? 2;
291
+ this.reconnectJitter = options.reconnectJitter ?? 0.25;
292
+ this.connectionFactory = options.connectionFactory ?? createMcpConnection;
293
+ this.random = options.random ?? Math.random;
294
+ this.now = options.now ?? Date.now;
295
+ this.setTimerImpl = options.setTimer ??
296
+ ((callback, delayMs) => setTimeout(callback, delayMs));
297
+ this.clearTimerImpl = options.clearTimer ??
298
+ ((timer) => clearTimeout(timer));
299
+ this.reconnectDelayMs = this.reconnectInitialDelayMs;
300
+ }
301
+ getState() {
302
+ return this.state;
303
+ }
304
+ start() {
305
+ if (this.state === "closing" || this.state === "stopped") {
306
+ throw new GraphitiOfflineError(this.state, this.state === "closing"
307
+ ? "Graphiti connection manager is closing"
308
+ : "Graphiti connection manager has been stopped and cannot be restarted");
309
+ }
310
+ if (this.started)
311
+ return;
312
+ this.started = true;
313
+ void this.reconnect();
314
+ }
315
+ async stop() {
316
+ if (this.state === "stopped")
317
+ return;
318
+ if (this.stopPromise) {
319
+ await this.stopPromise;
320
+ return;
321
+ }
322
+ this.stopPromise = (async () => {
323
+ this.started = false;
324
+ this.state = "closing";
325
+ this.cancelReconnectTimer();
326
+ this.rejectAllPending(new GraphitiOfflineError("stopped", "Graphiti connection manager stopped"));
327
+ this.resolveReadyWaiters(false);
328
+ const connection = this.connection;
329
+ this.connection = null;
330
+ if (connection) {
331
+ try {
332
+ await connection.close();
333
+ }
334
+ catch {
335
+ // Ignore close errors while shutting down.
336
+ }
337
+ }
338
+ this.state = "stopped";
339
+ })();
340
+ await this.stopPromise;
341
+ }
342
+ async ready(timeoutMs = this.startupTimeoutMs) {
343
+ if (this.state === "connected")
344
+ return true;
345
+ if (this.state === "closing" || this.state === "stopped")
346
+ return false;
347
+ return await new Promise((resolve) => {
348
+ let settled = false;
349
+ let timer = null;
350
+ const finish = (value) => {
351
+ if (settled)
352
+ return;
353
+ settled = true;
354
+ if (timer !== null)
355
+ this.clearTimerImpl(timer);
356
+ this.readyWaiters.delete(finish);
357
+ resolve(value);
358
+ };
359
+ this.readyWaiters.add(finish);
360
+ if (timeoutMs >= 0) {
361
+ timer = this.setTimerImpl(() => finish(false), timeoutMs);
362
+ }
363
+ });
364
+ }
365
+ async callTool(name, args, deadlineMs = this.requestDeadlineMs) {
366
+ const sanitizedArgs = Object.fromEntries(Object.entries(args).filter(([_, value]) => value !== null && value !== undefined));
367
+ if (this.state === "closing" || this.state === "stopped") {
368
+ throw new GraphitiOfflineError(this.state);
369
+ }
370
+ if (this.state === "offline") {
371
+ throw new GraphitiOfflineError("offline");
372
+ }
373
+ if (this.state === "connecting") {
374
+ return await this.enqueueRequest(name, sanitizedArgs, deadlineMs);
375
+ }
376
+ return await this.executeConnectedCallWithinDeadline(name, sanitizedArgs, this.now() + deadlineMs);
377
+ }
378
+ async reconnect() {
379
+ if (this.state === "closing" || this.state === "stopped")
380
+ return false;
381
+ if (this.connectPromise)
382
+ return await this.connectPromise;
383
+ this.cancelReconnectTimer();
384
+ this.state = "connecting";
385
+ const attempt = this.performReconnect();
386
+ this.connectPromise = attempt.finally(() => {
387
+ this.connectPromise = null;
388
+ });
389
+ return await this.connectPromise;
390
+ }
391
+ async performReconnect() {
392
+ const previousConnection = this.connection;
393
+ this.connection = null;
394
+ let nextConnection = null;
395
+ if (previousConnection) {
396
+ try {
397
+ await previousConnection.close();
398
+ }
399
+ catch {
400
+ // Ignore stale close failures during reconnect.
401
+ }
402
+ }
403
+ try {
404
+ nextConnection = this.connectionFactory(this.endpoint);
405
+ await nextConnection.connect();
406
+ if (this.state === "closing") {
407
+ try {
408
+ await nextConnection.close();
409
+ }
410
+ catch {
411
+ // Ignore close failures while shutting down.
412
+ }
413
+ return false;
414
+ }
415
+ this.connection = nextConnection;
416
+ this.state = "connected";
417
+ this.reconnectDelayMs = this.reconnectInitialDelayMs;
418
+ this.resolveReadyWaiters(true);
419
+ logger.info("Connected to Graphiti MCP server at", this.endpoint);
420
+ void this.flushPendingQueue();
421
+ return true;
422
+ }
423
+ catch (err) {
424
+ if (nextConnection) {
425
+ try {
426
+ await nextConnection.close();
427
+ }
428
+ catch {
429
+ // Ignore close failures for failed connects.
430
+ }
431
+ }
432
+ if (this.state !== "closing" && this.state !== "stopped") {
433
+ this.state = "offline";
434
+ this.scheduleReconnect();
435
+ logger.warn("Failed to connect to Graphiti MCP server", err);
436
+ }
437
+ return false;
438
+ }
439
+ }
440
+ async executeConnectedCall(name, args, deadlineMs) {
441
+ return await this.executeConnectedCallWithinDeadline(name, args, this.now() + deadlineMs);
442
+ }
443
+ async executeConnectedCallWithinDeadline(name, args, deadlineAt, attempt = 0) {
444
+ if (this.state !== "connected" || !this.connection) {
445
+ throw new GraphitiOfflineError("offline");
446
+ }
447
+ const deadlineMs = this.getRemainingDeadlineMs(deadlineAt);
448
+ if (deadlineMs <= 0) {
449
+ throw new GraphitiRequestTimeoutError();
450
+ }
451
+ try {
452
+ return await this.runWithRequestDeadline(this.connection.callTool({ name, arguments: args }), deadlineMs);
453
+ }
454
+ catch (err) {
455
+ if (isRequestTimeout(err)) {
456
+ throw new GraphitiRequestTimeoutError(getErrorMessage(err) || undefined);
457
+ }
458
+ if (isSessionExpired(err)) {
459
+ const typedError = new GraphitiSessionExpiredError(getErrorMessage(err) || undefined);
460
+ if (attempt >= 1) {
461
+ void this.reconnect();
462
+ throw typedError;
463
+ }
464
+ const connected = await this.reconnectWithinDeadline(deadlineAt);
465
+ if (!connected)
466
+ throw typedError;
467
+ return await this.executeConnectedCallWithinDeadline(name, args, deadlineAt, attempt + 1);
468
+ }
469
+ if (isTransportFailure(err)) {
470
+ const typedError = new GraphitiTransportError(getErrorMessage(err) || undefined);
471
+ if (attempt >= 1) {
472
+ void this.reconnect();
473
+ throw typedError;
474
+ }
475
+ const connected = await this.reconnectWithinDeadline(deadlineAt);
476
+ if (!connected)
477
+ throw typedError;
478
+ return await this.executeConnectedCallWithinDeadline(name, args, deadlineAt, attempt + 1);
479
+ }
480
+ throw err;
481
+ }
482
+ }
483
+ getRemainingDeadlineMs(deadlineAt) {
484
+ return deadlineAt - this.now();
485
+ }
486
+ async reconnectWithinDeadline(deadlineAt) {
487
+ const deadlineMs = this.getRemainingDeadlineMs(deadlineAt);
488
+ if (deadlineMs <= 0) {
489
+ throw new GraphitiRequestTimeoutError();
490
+ }
491
+ return await this.runWithRequestDeadline(this.reconnect(), deadlineMs);
492
+ }
493
+ runWithRequestDeadline(task, deadlineMs) {
494
+ return new Promise((resolve, reject) => {
495
+ let settled = false;
496
+ const timer = this.setTimerImpl(() => {
497
+ if (settled)
498
+ return;
499
+ settled = true;
500
+ reject(new GraphitiRequestTimeoutError());
501
+ }, deadlineMs);
502
+ task.then((value) => {
503
+ if (settled)
504
+ return;
505
+ settled = true;
506
+ this.clearTimerImpl(timer);
507
+ resolve(value);
508
+ }, (error) => {
509
+ if (settled)
510
+ return;
511
+ settled = true;
512
+ this.clearTimerImpl(timer);
513
+ reject(error);
514
+ });
515
+ });
516
+ }
517
+ enqueueRequest(name, args, deadlineMs) {
518
+ if (deadlineMs <= 0) {
519
+ return Promise.reject(new GraphitiQueueTimeoutError());
520
+ }
521
+ return new Promise((resolve, reject) => {
522
+ const deadlineAt = this.now() + deadlineMs;
523
+ const pending = {
524
+ name,
525
+ args,
526
+ deadlineAt,
527
+ resolve,
528
+ reject,
529
+ timer: null,
530
+ };
531
+ pending.timer = this.setTimerImpl(() => {
532
+ this.removePendingRequest(pending);
533
+ reject(new GraphitiQueueTimeoutError());
534
+ }, deadlineMs);
535
+ if (this.pendingRequests.length >= this.queueCapacity) {
536
+ const dropped = this.pendingRequests.shift();
537
+ if (dropped) {
538
+ this.clearPendingTimer(dropped);
539
+ dropped.reject(new GraphitiQueueTimeoutError("Graphiti request dropped because the connecting queue is full"));
540
+ }
541
+ }
542
+ this.pendingRequests.push(pending);
543
+ });
544
+ }
545
+ async flushPendingQueue() {
546
+ if (this.flushingQueue || this.state !== "connected")
547
+ return;
548
+ this.flushingQueue = true;
549
+ try {
550
+ while (this.state === "connected" && this.pendingRequests.length > 0) {
551
+ const next = this.pendingRequests.shift();
552
+ if (!next)
553
+ continue;
554
+ this.clearPendingTimer(next);
555
+ if (this.getRemainingDeadlineMs(next.deadlineAt) <= 0) {
556
+ next.reject(new GraphitiQueueTimeoutError());
557
+ continue;
558
+ }
559
+ try {
560
+ const result = await this.executeConnectedCallWithinDeadline(next.name, next.args, next.deadlineAt);
561
+ next.resolve(result);
562
+ }
563
+ catch (err) {
564
+ next.reject(err);
565
+ }
566
+ }
567
+ }
568
+ finally {
569
+ this.flushingQueue = false;
570
+ }
571
+ }
572
+ removePendingRequest(target) {
573
+ const index = this.pendingRequests.indexOf(target);
574
+ if (index >= 0) {
575
+ this.pendingRequests.splice(index, 1);
576
+ }
577
+ this.clearPendingTimer(target);
578
+ }
579
+ clearPendingTimer(request) {
580
+ if (request.timer !== null) {
581
+ this.clearTimerImpl(request.timer);
582
+ request.timer = null;
583
+ }
584
+ }
585
+ rejectAllPending(error) {
586
+ const pending = [...this.pendingRequests];
587
+ this.pendingRequests = [];
588
+ for (const request of pending) {
589
+ this.clearPendingTimer(request);
590
+ request.reject(error);
591
+ }
592
+ }
593
+ scheduleReconnect() {
594
+ if (!this.started || this.state === "closing" || this.state === "stopped" ||
595
+ this.reconnectTimer !== null) {
596
+ return;
597
+ }
598
+ const jitterFactor = 1 + ((this.random() * 2) - 1) * this.reconnectJitter;
599
+ const delayMs = Math.max(0, Math.round(this.reconnectDelayMs * jitterFactor));
600
+ this.reconnectTimer = this.setTimerImpl(() => {
601
+ this.reconnectTimer = null;
602
+ if (this.state === "closing" || this.state === "stopped")
603
+ return;
604
+ void this.reconnect();
605
+ }, delayMs);
606
+ this.reconnectDelayMs = Math.min(this.reconnectMaxDelayMs, Math.max(this.reconnectInitialDelayMs, Math.round(this.reconnectDelayMs * this.reconnectMultiplier)));
607
+ }
608
+ cancelReconnectTimer() {
609
+ if (this.reconnectTimer !== null) {
610
+ this.clearTimerImpl(this.reconnectTimer);
611
+ this.reconnectTimer = null;
612
+ }
613
+ }
614
+ resolveReadyWaiters(value) {
615
+ const waiters = [...this.readyWaiters];
616
+ this.readyWaiters.clear();
617
+ for (const waiter of waiters) {
618
+ waiter(value);
619
+ }
620
+ }
621
+ }
@@ -0,0 +1,7 @@
1
+ /** Milliseconds in one day. */
2
+ export declare const DAY_MS: number;
3
+ /** Default token context limit when the provider does not report one. */
4
+ export declare const DEFAULT_CONTEXT_LIMIT = 200000;
5
+ /** Maximum project-scope facts fetched per search query. */
6
+ export declare const PROJECT_MAX_FACTS = 50;
7
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/src/services/constants.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,eAAO,MAAM,MAAM,QAAsB,CAAC;AAE1C,yEAAyE;AACzE,eAAO,MAAM,qBAAqB,SAAU,CAAC;AAE7C,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,KAAK,CAAC"}
@@ -0,0 +1,6 @@
1
+ /** Milliseconds in one day. */
2
+ export const DAY_MS = 24 * 60 * 60 * 1000;
3
+ /** Default token context limit when the provider does not report one. */
4
+ export const DEFAULT_CONTEXT_LIMIT = 200_000;
5
+ /** Maximum project-scope facts fetched per search query. */
6
+ export const PROJECT_MAX_FACTS = 50;
@@ -0,0 +1,3 @@
1
+ import type { OpencodeClient } from "@opencode-ai/sdk";
2
+ export declare function resolveContextLimit(providerID: string, modelID: string, client: OpencodeClient, directory: string | undefined, cache: Map<string, number>): Promise<number>;
3
+ //# sourceMappingURL=context-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-limit.d.ts","sourceRoot":"","sources":["../../../src/src/services/context-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAkBvD,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACzB,OAAO,CAAC,MAAM,CAAC,CAoCjB"}
@@ -0,0 +1,44 @@
1
+ import { DEFAULT_CONTEXT_LIMIT } from "./constants.js";
2
+ import { logger } from "./logger.js";
3
+ import { extractSdkProviders } from "./sdk-normalize.js";
4
+ const UNKNOWN_CONTEXT_LIMIT = -1;
5
+ const getContextLimitCacheKey = (providerID, modelID, directory) => {
6
+ const normalizedDirectory = directory?.trim();
7
+ return normalizedDirectory
8
+ ? `${normalizedDirectory}\u0000${providerID}/${modelID}`
9
+ : `${providerID}/${modelID}`;
10
+ };
11
+ export async function resolveContextLimit(providerID, modelID, client, directory, cache) {
12
+ const normalizedDirectory = directory?.trim();
13
+ const modelKey = getContextLimitCacheKey(providerID, modelID, normalizedDirectory);
14
+ const cached = cache.get(modelKey);
15
+ if (cached !== undefined) {
16
+ return cached > 0 ? cached : DEFAULT_CONTEXT_LIMIT;
17
+ }
18
+ try {
19
+ const response = await client.provider.list({
20
+ query: normalizedDirectory ? { directory: normalizedDirectory } : {},
21
+ });
22
+ const list = extractSdkProviders(response);
23
+ for (const provider of list) {
24
+ if (provider.id !== providerID)
25
+ continue;
26
+ const models = provider.models ?? [];
27
+ for (const model of models) {
28
+ if (model.id !== modelID)
29
+ continue;
30
+ const contextLimit = model.limit?.context;
31
+ if (typeof contextLimit === "number" && contextLimit > 0) {
32
+ cache.set(modelKey, contextLimit);
33
+ return contextLimit;
34
+ }
35
+ }
36
+ }
37
+ }
38
+ catch (err) {
39
+ logger.warn("Failed to fetch provider context limit", err);
40
+ return DEFAULT_CONTEXT_LIMIT;
41
+ }
42
+ cache.set(modelKey, UNKNOWN_CONTEXT_LIMIT);
43
+ return DEFAULT_CONTEXT_LIMIT;
44
+ }