@copilotkit/runtime 1.66.2 → 1.66.4

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 (75) hide show
  1. package/dist/agent/converters/aisdk.cjs +17 -9
  2. package/dist/agent/converters/aisdk.cjs.map +1 -1
  3. package/dist/agent/converters/aisdk.d.cts +1 -1
  4. package/dist/agent/converters/aisdk.d.cts.map +1 -1
  5. package/dist/agent/converters/aisdk.d.mts +1 -1
  6. package/dist/agent/converters/aisdk.d.mts.map +1 -1
  7. package/dist/agent/converters/aisdk.mjs +17 -9
  8. package/dist/agent/converters/aisdk.mjs.map +1 -1
  9. package/dist/agent/converters/tanstack.cjs +17 -9
  10. package/dist/agent/converters/tanstack.cjs.map +1 -1
  11. package/dist/agent/converters/tanstack.d.cts +1 -1
  12. package/dist/agent/converters/tanstack.d.cts.map +1 -1
  13. package/dist/agent/converters/tanstack.d.mts +1 -1
  14. package/dist/agent/converters/tanstack.d.mts.map +1 -1
  15. package/dist/agent/converters/tanstack.mjs +17 -9
  16. package/dist/agent/converters/tanstack.mjs.map +1 -1
  17. package/dist/agent/index.cjs +6 -4
  18. package/dist/agent/index.cjs.map +1 -1
  19. package/dist/agent/index.d.cts.map +1 -1
  20. package/dist/agent/index.d.mts.map +1 -1
  21. package/dist/agent/index.mjs +6 -4
  22. package/dist/agent/index.mjs.map +1 -1
  23. package/dist/agent/state-delta.cjs +322 -0
  24. package/dist/agent/state-delta.cjs.map +1 -0
  25. package/dist/agent/state-delta.mjs +321 -0
  26. package/dist/agent/state-delta.mjs.map +1 -0
  27. package/dist/package.cjs +1 -1
  28. package/dist/runtime/package.mjs +1 -1
  29. package/dist/v2/index.cjs +6 -1
  30. package/dist/v2/index.d.cts +2 -2
  31. package/dist/v2/index.d.mts +2 -2
  32. package/dist/v2/index.mjs +2 -2
  33. package/dist/v2/runtime/core/channel-manager.cjs +110 -9
  34. package/dist/v2/runtime/core/channel-manager.cjs.map +1 -1
  35. package/dist/v2/runtime/core/channel-manager.d.cts +79 -8
  36. package/dist/v2/runtime/core/channel-manager.d.cts.map +1 -1
  37. package/dist/v2/runtime/core/channel-manager.d.mts +79 -8
  38. package/dist/v2/runtime/core/channel-manager.d.mts.map +1 -1
  39. package/dist/v2/runtime/core/channel-manager.mjs +110 -9
  40. package/dist/v2/runtime/core/channel-manager.mjs.map +1 -1
  41. package/dist/v2/runtime/core/runtime.cjs.map +1 -1
  42. package/dist/v2/runtime/core/runtime.d.cts +1 -0
  43. package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
  44. package/dist/v2/runtime/core/runtime.d.mts +1 -0
  45. package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
  46. package/dist/v2/runtime/core/runtime.mjs.map +1 -1
  47. package/dist/v2/runtime/handlers/shared/agent-utils.cjs +2 -5
  48. package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -1
  49. package/dist/v2/runtime/handlers/shared/agent-utils.mjs +2 -5
  50. package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -1
  51. package/dist/v2/runtime/handlers/shared/mcp-apps-servers.cjs +23 -0
  52. package/dist/v2/runtime/handlers/shared/mcp-apps-servers.cjs.map +1 -0
  53. package/dist/v2/runtime/handlers/shared/mcp-apps-servers.mjs +22 -0
  54. package/dist/v2/runtime/handlers/shared/mcp-apps-servers.mjs.map +1 -0
  55. package/dist/v2/runtime/index.d.cts +1 -1
  56. package/dist/v2/runtime/index.d.mts +1 -1
  57. package/dist/v2/runtime/open-generative-ui-middleware.cjs +1 -0
  58. package/dist/v2/runtime/open-generative-ui-middleware.cjs.map +1 -1
  59. package/dist/v2/runtime/open-generative-ui-middleware.mjs +1 -0
  60. package/dist/v2/runtime/open-generative-ui-middleware.mjs.map +1 -1
  61. package/dist/v2/runtime/runner/in-memory.cjs +335 -101
  62. package/dist/v2/runtime/runner/in-memory.cjs.map +1 -1
  63. package/dist/v2/runtime/runner/in-memory.d.cts +246 -6
  64. package/dist/v2/runtime/runner/in-memory.d.cts.map +1 -1
  65. package/dist/v2/runtime/runner/in-memory.d.mts +246 -6
  66. package/dist/v2/runtime/runner/in-memory.d.mts.map +1 -1
  67. package/dist/v2/runtime/runner/in-memory.mjs +331 -102
  68. package/dist/v2/runtime/runner/in-memory.mjs.map +1 -1
  69. package/dist/v2/runtime/runner/index.d.cts +1 -1
  70. package/dist/v2/runtime/runner/index.d.mts +1 -1
  71. package/dist/v2/runtime/runner/index.mjs +1 -1
  72. package/package.json +5 -5
  73. package/skills/runtime/references/agent-runners-in-memory.md +49 -34
  74. package/skills/runtime/references/agent-runners.md +47 -21
  75. package/skills/runtime/references/wiring-mcp-apps-middleware.md +5 -0
@@ -6,6 +6,71 @@ let rxjs = require("rxjs");
6
6
  let _ag_ui_client = require("@ag-ui/client");
7
7
 
8
8
  //#region src/v2/runtime/runner/in-memory.ts
9
+ const ɵINMEMORY_DEFAULTS = {
10
+ maxThreads: 1e3,
11
+ maxRunsPerThread: 100,
12
+ maxBytes: 512 * 1024 ** 2
13
+ };
14
+ /**
15
+ * A limit value is well-formed iff it is a non-negative integer OR `+Infinity`.
16
+ * `+Infinity` is the documented "disabled/unbounded" sentinel and `0` is the
17
+ * documented run-cap disable sentinel; both are non-negative and pass. Every
18
+ * enforcement site (`evictThreadsIfNeeded`, `enforceRunCap`,
19
+ * `evictByBytesIfNeeded`) compares its counter against the limit with `>` in a
20
+ * `while`/`if` guard, so only these shapes keep those loops finite and correct.
21
+ * Rejected: negatives (drive `count > -1` true on an empty collection, so
22
+ * `enforceRunCap` `shift()!`s `undefined` and throws), `-Infinity` (loops never
23
+ * terminate their intent — always "over"), `NaN` (every `>` is false, silently
24
+ * disabling the bound), and non-integer finites (fractional caps are nonsense).
25
+ */
26
+ function ɵisValidLimit(value) {
27
+ return value === Infinity || Number.isInteger(value) && value >= 0;
28
+ }
29
+ /**
30
+ * Normalize a fully-resolved limits bag so every field is well-formed before it
31
+ * can reach an enforcement loop. Each field is validated independently against
32
+ * {@link ɵisValidLimit}; an invalid value is CLAMPED to its
33
+ * {@link ɵINMEMORY_DEFAULTS} floor and a single `console.warn` naming the field
34
+ * and the received value is emitted.
35
+ *
36
+ * Clamp-and-warn (rather than throw) is deliberate and matches this file's
37
+ * established posture toward bad input: `ɵestimateBytes` swallows serialization
38
+ * failures and returns 0, the limits-clobber path warns rather than throwing,
39
+ * and both the eviction and clobber logs are wrapped so "logging must never
40
+ * break construction/a run". Constructing a bounded in-memory runner is a
41
+ * best-effort, non-durable convenience; a typo'd bound must degrade to a safe
42
+ * default, never abort construction or (worse) surface later as an unhandled
43
+ * rejection from the fire-and-forget finalize path.
44
+ */
45
+ function ɵnormalizeLimits(limits) {
46
+ const normalized = { ...limits };
47
+ for (const field of Object.keys(ɵINMEMORY_DEFAULTS)) {
48
+ const value = limits[field];
49
+ if (!ɵisValidLimit(value)) {
50
+ const fallback = ɵINMEMORY_DEFAULTS[field];
51
+ normalized[field] = fallback;
52
+ try {
53
+ console.warn(`[CopilotKit] InMemoryAgentRunner: invalid ${field} value ${String(value)} (expected a non-negative integer or Infinity); falling back to ${String(fallback)}.`);
54
+ } catch {}
55
+ }
56
+ }
57
+ return normalized;
58
+ }
59
+ const EVICTION_GUIDANCE = "[CopilotKit] InMemoryAgentRunner evicted in-memory thread history to stay under memory limits. This runner is bounded and non-durable by design. For durable or production threads, configure an Intelligence backend.";
60
+ const LIMITS_CLOBBER_GUIDANCE = "[CopilotKit] InMemoryAgentRunner was constructed with in-memory limits that differ from the already-configured process-global store; the last-constructed runner's limits apply to ALL in-memory threads (the store is shared per-process). Configure a single consistent set of limits, or use an Intelligence backend for isolated bounds.";
61
+ /**
62
+ * Best-effort approximate byte size of a value, via serialized length.
63
+ * Never throws — returns 0 when the value cannot be serialized. This is an
64
+ * approximation (UTF-16 length, not exact heap bytes), used only for relative
65
+ * accounting against `maxBytes`.
66
+ */
67
+ function ɵestimateBytes(value) {
68
+ try {
69
+ return JSON.stringify(value)?.length ?? 0;
70
+ } catch {
71
+ return 0;
72
+ }
73
+ }
9
74
  var InMemoryEventStore = class {
10
75
  constructor(threadId) {
11
76
  this.threadId = threadId;
@@ -16,39 +81,240 @@ var InMemoryEventStore = class {
16
81
  this.agent = null;
17
82
  this.runSubject = null;
18
83
  this.stopRequested = false;
84
+ this.activeFinalize = null;
19
85
  this.currentEvents = null;
86
+ this.messagesSnapshot = [];
87
+ this.approxMessagesSnapshotBytes = 0;
88
+ this.createdAt = null;
89
+ }
90
+ };
91
+ var ɵBoundedThreadStore = class {
92
+ constructor(limits) {
93
+ this.map = /* @__PURE__ */ new Map();
94
+ this.totalBytes = 0;
95
+ this.warned = false;
96
+ this.limitsExplicitlySet = false;
97
+ this.clobberWarned = false;
98
+ this.limits = ɵnormalizeLimits(limits);
99
+ }
100
+ get byteTotal() {
101
+ return this.totalBytes;
102
+ }
103
+ /**
104
+ * The store's CURRENT effective bounds. Exposed (with the `ɵ` internal-API
105
+ * prefix) so a partial `setLimits` can coalesce unspecified fields against the
106
+ * live config rather than the hardcoded {@link ɵINMEMORY_DEFAULTS} — a partial
107
+ * update must be a partial update, never a silent reset of the fields the
108
+ * caller did not mention. Returns a copy so callers cannot mutate the store's
109
+ * bounds through it.
110
+ */
111
+ get ɵlimits() {
112
+ return { ...this.limits };
113
+ }
114
+ /**
115
+ * Reconfigure the process-global store's bounds. Called by the
116
+ * {@link InMemoryAgentRunner} constructor when limits are passed. Because the
117
+ * store is a per-process singleton, this replaces the bounds for ALL in-memory
118
+ * threads. Emits {@link LIMITS_CLOBBER_GUIDANCE} at most ONCE per store when a
119
+ * SECOND (or later) explicit set arrives whose resolved values differ from the
120
+ * prior explicit set — i.e. a genuine clobber of an already-customized config.
121
+ * The first explicit customization (defaults → custom) is the intended
122
+ * override and never warns; identical re-sets never warn.
123
+ */
124
+ setLimits(limits) {
125
+ const normalized = ɵnormalizeLimits(limits);
126
+ if (this.limitsExplicitlySet && !this.clobberWarned && (normalized.maxThreads !== this.limits.maxThreads || normalized.maxRunsPerThread !== this.limits.maxRunsPerThread || normalized.maxBytes !== this.limits.maxBytes)) {
127
+ this.clobberWarned = true;
128
+ try {
129
+ console.warn(LIMITS_CLOBBER_GUIDANCE);
130
+ } catch {}
131
+ }
132
+ this.limitsExplicitlySet = true;
133
+ this.limits = normalized;
134
+ }
135
+ get size() {
136
+ return this.map.size;
137
+ }
138
+ /** Re-insert at the tail so Map iteration order stays LRU-first. */
139
+ touchOrder(threadId, store) {
140
+ this.map.delete(threadId);
141
+ this.map.set(threadId, store);
142
+ }
143
+ getOrCreate(threadId) {
144
+ const existing = this.map.get(threadId);
145
+ if (existing) {
146
+ this.touchOrder(threadId, existing);
147
+ return existing;
148
+ }
149
+ const store = new InMemoryEventStore(threadId);
150
+ this.map.set(threadId, store);
151
+ this.evictThreadsIfNeeded(threadId);
152
+ return store;
153
+ }
154
+ get(threadId, opts) {
155
+ const store = this.map.get(threadId);
156
+ if (store && opts.touch) this.touchOrder(threadId, store);
157
+ return store;
158
+ }
159
+ peek(threadId) {
160
+ return this.map.get(threadId);
161
+ }
162
+ /**
163
+ * Evict the least-recently-used thread that is neither running NOR
164
+ * mid-finalization. Returns false if none evictable. The `protect` thread
165
+ * (typically the one just created) is never evicted, so a fresh thread is not
166
+ * immediately dropped when it is the only non-running candidate.
167
+ *
168
+ * A thread is skipped while `isRunning` OR `stopRequested` is set.
169
+ * `stop()` flips `isRunning` to false the moment it aborts the agent, but the
170
+ * run keeps finalizing asynchronously (the abort trips the `catch` in
171
+ * `runAgent`, which later calls `appendRun`). During that window
172
+ * `stopRequested` stays true; evicting the thread then would make the pending
173
+ * `appendRun` hit `if (!store) return` and silently drop the aborted run's
174
+ * history. Guarding on `stopRequested` keeps the thread alive until
175
+ * finalization completes.
176
+ */
177
+ evictOneLru(protect) {
178
+ for (const [threadId, store] of this.map) {
179
+ if (threadId === protect) continue;
180
+ if (store.isRunning || store.stopRequested) continue;
181
+ this.removeThread(threadId, store);
182
+ this.noteEviction();
183
+ return true;
184
+ }
185
+ return false;
186
+ }
187
+ appendRun(threadId, run) {
188
+ const store = this.map.get(threadId);
189
+ if (!store) return;
190
+ if (store.createdAt === null) store.createdAt = run.createdAt;
191
+ if (run.messages.length > 0) {
192
+ this.totalBytes -= store.approxMessagesSnapshotBytes;
193
+ store.messagesSnapshot = run.messages;
194
+ store.approxMessagesSnapshotBytes = ɵestimateBytes(run.messages);
195
+ this.totalBytes += store.approxMessagesSnapshotBytes;
196
+ }
197
+ run.messages = [];
198
+ run.approxMessageBytes = 0;
199
+ run.approxEventBytes = ɵestimateBytes(run.events);
200
+ store.historicRuns.push(run);
201
+ this.totalBytes += run.approxEventBytes;
202
+ this.touchOrder(threadId, store);
203
+ this.enforceRunCap(store);
204
+ this.evictByBytesIfNeeded(threadId);
205
+ }
206
+ enforceRunCap(store) {
207
+ const cap = this.limits.maxRunsPerThread;
208
+ if (!cap || cap === Infinity) return;
209
+ while (store.historicRuns.length > cap) {
210
+ const dropped = store.historicRuns.shift();
211
+ this.totalBytes -= dropped.approxEventBytes ?? 0;
212
+ this.noteEviction();
213
+ }
214
+ }
215
+ /**
216
+ * Trim the store back under the byte ceiling by evicting LRU non-running
217
+ * threads. `protect` (the just-appended thread) is never self-evicted, so a
218
+ * fresh run pushes OTHER threads out rather than dropping itself.
219
+ */
220
+ evictByBytesIfNeeded(protect) {
221
+ while (this.totalBytes > this.limits.maxBytes) if (!this.evictOneLru(protect)) break;
222
+ }
223
+ removeThread(threadId, store) {
224
+ for (const run of store.historicRuns) this.totalBytes -= run.approxEventBytes ?? 0;
225
+ this.totalBytes -= store.approxMessagesSnapshotBytes;
226
+ this.map.delete(threadId);
227
+ }
228
+ evictThreadsIfNeeded(protect) {
229
+ while (this.map.size > this.limits.maxThreads) if (!this.evictOneLru(protect)) break;
230
+ }
231
+ noteEviction() {
232
+ if (this.warned) return;
233
+ this.warned = true;
234
+ try {
235
+ console.warn(EVICTION_GUIDANCE);
236
+ } catch {}
237
+ }
238
+ listThreads() {
239
+ const threads = [];
240
+ for (const [threadId, store] of this.map) {
241
+ if (store.historicRuns.length === 0) continue;
242
+ const lastRun = store.historicRuns[store.historicRuns.length - 1];
243
+ threads.push({
244
+ id: threadId,
245
+ name: null,
246
+ agentId: lastRun.agentId,
247
+ organizationId: "",
248
+ createdById: "",
249
+ archived: false,
250
+ createdAt: new Date(store.createdAt ?? lastRun.createdAt).toISOString(),
251
+ updatedAt: new Date(lastRun.createdAt).toISOString()
252
+ });
253
+ }
254
+ return threads.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
255
+ }
256
+ clear() {
257
+ this.map.clear();
258
+ this.totalBytes = 0;
259
+ this.warned = false;
20
260
  }
21
261
  };
22
- const GLOBAL_STORE = /* @__PURE__ */ new Map();
262
+ /**
263
+ * Process-wide singleton backing every {@link InMemoryAgentRunner}. Exported
264
+ * (with the `ɵ` internal-API prefix) so tests can inspect the exact store the
265
+ * runner writes to; not part of the public API.
266
+ */
267
+ const ɵGLOBAL_STORE = new ɵBoundedThreadStore(ɵINMEMORY_DEFAULTS);
268
+ const sharedStore = ɵGLOBAL_STORE;
23
269
  var InMemoryAgentRunner = class extends require_agent_runner.AgentRunner {
270
+ /**
271
+ * @param options Per-runner behavior (`onConcurrentRun`) plus optional bounds
272
+ * for the in-memory store ({@link InMemoryLimits}).
273
+ *
274
+ * Note the differing scopes: `onConcurrentRun` is per-runner instance, while
275
+ * the limits reconfigure the PROCESS-GLOBAL store shared by every
276
+ * `InMemoryAgentRunner`. Omit the limits for safe defaults
277
+ * ({@link ɵINMEMORY_DEFAULTS}); passing none leaves the store untouched. When
278
+ * multiple runners are constructed with differing limits, the last-constructed
279
+ * wins — in practice the OSS/SSE default construction passes nothing. If a
280
+ * second (or later) runner is constructed with limits that DIFFER from an
281
+ * already-customized store, a one-time `console.warn` is emitted to signal that
282
+ * the shared store's bounds are being clobbered for ALL in-memory threads.
283
+ */
24
284
  constructor(options) {
25
285
  super();
26
286
  this.ɵsupportsLocalThreadEndpoints = true;
27
- this.onConcurrentRun = options?.onConcurrentRun ?? "throw";
287
+ const { onConcurrentRun, ...limits } = options ?? {};
288
+ this.onConcurrentRun = onConcurrentRun ?? "throw";
289
+ if (limits.maxThreads !== void 0 || limits.maxRunsPerThread !== void 0 || limits.maxBytes !== void 0) {
290
+ const current = sharedStore.ɵlimits;
291
+ sharedStore.setLimits({
292
+ maxThreads: limits.maxThreads ?? current.maxThreads,
293
+ maxRunsPerThread: limits.maxRunsPerThread ?? current.maxRunsPerThread,
294
+ maxBytes: limits.maxBytes ?? current.maxBytes
295
+ });
296
+ }
28
297
  }
29
298
  run(request) {
30
- let existingStore = GLOBAL_STORE.get(request.threadId);
31
- if (!existingStore) {
32
- existingStore = new InMemoryEventStore(request.threadId);
33
- GLOBAL_STORE.set(request.threadId, existingStore);
34
- }
35
- const store = existingStore;
36
- if (store.isRunning) {
299
+ const store = sharedStore.getOrCreate(request.threadId);
300
+ if (store.isRunning || store.stopRequested) {
37
301
  if (this.onConcurrentRun !== "supersede") throw new Error("Thread already running");
38
302
  const priorAgent = store.agent;
39
- store.stopRequested = true;
303
+ const priorFinalize = store.activeFinalize;
304
+ if (priorFinalize) priorFinalize.stopRequested = true;
40
305
  store.isRunning = false;
41
306
  if (priorAgent) try {
42
307
  priorAgent.abortRun();
43
308
  } catch (error) {
44
309
  console.error("Failed to abort superseded run", error);
45
310
  }
46
- store.stopRequested = false;
47
311
  }
48
312
  store.isRunning = true;
49
313
  store.currentRunId = request.input.runId;
50
314
  store.agent = request.agent;
51
315
  store.stopRequested = false;
316
+ const finalizeControl = { stopRequested: false };
317
+ store.activeFinalize = finalizeControl;
52
318
  const seenMessageIds = /* @__PURE__ */ new Set();
53
319
  const currentRunEvents = [];
54
320
  store.currentEvents = currentRunEvents;
@@ -61,12 +327,48 @@ var InMemoryAgentRunner = class extends require_agent_runner.AgentRunner {
61
327
  }
62
328
  }
63
329
  const nextSubject = new rxjs.ReplaySubject(Infinity);
64
- const prevSubject = store.subject;
65
330
  store.subject = nextSubject;
66
331
  const runSubject = new rxjs.ReplaySubject(Infinity);
67
332
  store.runSubject = runSubject;
68
333
  const runAgent = async () => {
69
334
  const parentRunId = store.historicRuns[store.historicRuns.length - 1]?.runId ?? null;
335
+ const finalizeRun = (opts) => {
336
+ const isError = opts.interruptionMessage !== void 0;
337
+ const preFinalizeEventCount = currentRunEvents.length;
338
+ const appendedEvents = (0, _copilotkit_shared.finalizeRunEvents)(currentRunEvents, {
339
+ stopRequested: finalizeControl.stopRequested,
340
+ ...isError ? { interruptionMessage: opts.interruptionMessage } : {}
341
+ });
342
+ for (const event of appendedEvents) {
343
+ runSubject.next(event);
344
+ nextSubject.next(event);
345
+ }
346
+ const ownsThread = store.currentRunId === request.input.runId;
347
+ if (ownsThread && (!isError || preFinalizeEventCount > 0)) {
348
+ const compactedEvents = (0, _ag_ui_client.compactEvents)(currentRunEvents);
349
+ sharedStore.appendRun(request.threadId, {
350
+ threadId: request.threadId,
351
+ runId: request.input.runId,
352
+ agentId: request.agent.agentId ?? "default",
353
+ parentRunId,
354
+ events: compactedEvents,
355
+ messages: Array.isArray(request.agent.messages) ? [...request.agent.messages] : [],
356
+ createdAt: Date.now()
357
+ });
358
+ }
359
+ if (ownsThread) {
360
+ store.currentEvents = null;
361
+ store.currentRunId = null;
362
+ store.agent = null;
363
+ store.runSubject = null;
364
+ store.stopRequested = false;
365
+ store.isRunning = false;
366
+ store.activeFinalize = null;
367
+ }
368
+ runSubject.complete();
369
+ nextSubject.complete();
370
+ if (store.subject === nextSubject) store.subject = null;
371
+ };
70
372
  try {
71
373
  await request.agent.runAgent(request.input, {
72
374
  onEvent: ({ event }) => {
@@ -95,77 +397,16 @@ var InMemoryAgentRunner = class extends require_agent_runner.AgentRunner {
95
397
  }
96
398
  }
97
399
  });
98
- const appendedEvents = (0, _copilotkit_shared.finalizeRunEvents)(currentRunEvents, { stopRequested: store.stopRequested });
99
- for (const event of appendedEvents) {
100
- runSubject.next(event);
101
- nextSubject.next(event);
102
- }
103
- if (store.currentRunId === request.input.runId) {
104
- const compactedEvents = (0, _ag_ui_client.compactEvents)(currentRunEvents);
105
- store.historicRuns.push({
106
- threadId: request.threadId,
107
- runId: request.input.runId,
108
- agentId: request.agent.agentId ?? "default",
109
- parentRunId,
110
- events: compactedEvents,
111
- messages: Array.isArray(request.agent.messages) ? [...request.agent.messages] : [],
112
- createdAt: Date.now()
113
- });
114
- }
115
- if (store.currentRunId === request.input.runId) {
116
- store.currentEvents = null;
117
- store.currentRunId = null;
118
- store.agent = null;
119
- store.runSubject = null;
120
- store.stopRequested = false;
121
- store.isRunning = false;
122
- }
123
- runSubject.complete();
124
- nextSubject.complete();
400
+ finalizeRun({});
125
401
  } catch (error) {
126
- const interruptionMessage = error instanceof Error ? error.message : String(error);
127
- const appendedEvents = (0, _copilotkit_shared.finalizeRunEvents)(currentRunEvents, {
128
- stopRequested: store.stopRequested,
129
- interruptionMessage
130
- });
131
- for (const event of appendedEvents) {
132
- runSubject.next(event);
133
- nextSubject.next(event);
134
- }
135
- if (store.currentRunId === request.input.runId && currentRunEvents.length > 0) {
136
- const compactedEvents = (0, _ag_ui_client.compactEvents)(currentRunEvents);
137
- store.historicRuns.push({
138
- threadId: request.threadId,
139
- runId: request.input.runId,
140
- agentId: request.agent.agentId ?? "default",
141
- parentRunId,
142
- events: compactedEvents,
143
- messages: Array.isArray(request.agent.messages) ? [...request.agent.messages] : [],
144
- createdAt: Date.now()
145
- });
146
- }
147
- if (store.currentRunId === request.input.runId) {
148
- store.currentEvents = null;
149
- store.currentRunId = null;
150
- store.agent = null;
151
- store.runSubject = null;
152
- store.stopRequested = false;
153
- store.isRunning = false;
154
- }
155
- runSubject.complete();
156
- nextSubject.complete();
402
+ finalizeRun({ interruptionMessage: error instanceof Error ? error.message : String(error) });
157
403
  }
158
404
  };
159
- if (prevSubject) prevSubject.subscribe({
160
- next: (e) => nextSubject.next(e),
161
- error: (err) => nextSubject.error(err),
162
- complete: () => {}
163
- });
164
405
  runAgent();
165
406
  return runSubject.asObservable();
166
407
  }
167
408
  connect(request) {
168
- const store = GLOBAL_STORE.get(request.threadId);
409
+ const store = sharedStore.get(request.threadId, { touch: true });
169
410
  const connectionSubject = new rxjs.ReplaySubject(Infinity);
170
411
  if (!store) {
171
412
  connectionSubject.complete();
@@ -191,20 +432,23 @@ var InMemoryAgentRunner = class extends require_agent_runner.AgentRunner {
191
432
  return connectionSubject.asObservable();
192
433
  }
193
434
  isRunning(request) {
194
- const store = GLOBAL_STORE.get(request.threadId);
435
+ const store = sharedStore.peek(request.threadId);
195
436
  return Promise.resolve(store?.isRunning ?? false);
196
437
  }
197
438
  stop(request) {
198
- const store = GLOBAL_STORE.get(request.threadId);
439
+ const store = sharedStore.peek(request.threadId);
199
440
  if (!store || !store.isRunning) return Promise.resolve(false);
200
441
  if (request.runId !== void 0 && store.currentRunId !== request.runId) return Promise.resolve(false);
201
442
  if (store.stopRequested) return Promise.resolve(false);
202
443
  store.stopRequested = true;
203
444
  store.isRunning = false;
445
+ const finalizeControl = store.activeFinalize;
446
+ if (finalizeControl) finalizeControl.stopRequested = true;
204
447
  const agent = store.agent;
205
448
  if (!agent) {
206
449
  store.stopRequested = false;
207
450
  store.isRunning = false;
451
+ if (finalizeControl) finalizeControl.stopRequested = false;
208
452
  return Promise.resolve(false);
209
453
  }
210
454
  try {
@@ -214,6 +458,7 @@ var InMemoryAgentRunner = class extends require_agent_runner.AgentRunner {
214
458
  console.error("Failed to abort agent run", error);
215
459
  store.stopRequested = false;
216
460
  store.isRunning = true;
461
+ if (finalizeControl) finalizeControl.stopRequested = false;
217
462
  return Promise.resolve(false);
218
463
  }
219
464
  }
@@ -225,23 +470,7 @@ var InMemoryAgentRunner = class extends require_agent_runner.AgentRunner {
225
470
  * `ThreadRecord` so the HTTP handler can use the same response envelope.
226
471
  */
227
472
  listThreads() {
228
- const threads = [];
229
- for (const [threadId, store] of GLOBAL_STORE) {
230
- if (store.historicRuns.length === 0) continue;
231
- const firstRun = store.historicRuns[0];
232
- const lastRun = store.historicRuns[store.historicRuns.length - 1];
233
- threads.push({
234
- id: threadId,
235
- name: null,
236
- agentId: lastRun.agentId,
237
- organizationId: "",
238
- createdById: "",
239
- archived: false,
240
- createdAt: new Date(firstRun.createdAt).toISOString(),
241
- updatedAt: new Date(lastRun.createdAt).toISOString()
242
- });
243
- }
244
- return threads.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
473
+ return sharedStore.listThreads();
245
474
  }
246
475
  /**
247
476
  * Returns all messages for a thread, using the snapshot captured at the end
@@ -253,9 +482,9 @@ var InMemoryAgentRunner = class extends require_agent_runner.AgentRunner {
253
482
  * with the Intelligence platform's `ThreadMessage` type.
254
483
  */
255
484
  getThreadMessages(threadId) {
256
- const store = GLOBAL_STORE.get(threadId);
257
- if (!store || store.historicRuns.length === 0) return [];
258
- return store.historicRuns[store.historicRuns.length - 1].messages;
485
+ const store = sharedStore.peek(threadId);
486
+ if (!store) return [];
487
+ return [...store.messagesSnapshot];
259
488
  }
260
489
  /**
261
490
  * Returns all AG-UI events for a thread, compacted across historic runs.
@@ -266,7 +495,7 @@ var InMemoryAgentRunner = class extends require_agent_runner.AgentRunner {
266
495
  * late-joining inspector sees matches what this method returns.
267
496
  */
268
497
  getThreadEvents(threadId) {
269
- const store = GLOBAL_STORE.get(threadId);
498
+ const store = sharedStore.peek(threadId);
270
499
  if (!store || store.historicRuns.length === 0) return [];
271
500
  const all = [];
272
501
  for (const run of store.historicRuns) all.push(...run.events);
@@ -288,7 +517,7 @@ var InMemoryAgentRunner = class extends require_agent_runner.AgentRunner {
288
517
  const event = events[i];
289
518
  if (event.type === _ag_ui_client.EventType.STATE_SNAPSHOT) {
290
519
  const snapshot = event.snapshot;
291
- if (snapshot && typeof snapshot === "object") return snapshot;
520
+ if (snapshot && typeof snapshot === "object" && !Array.isArray(snapshot)) return { ...snapshot };
292
521
  return null;
293
522
  }
294
523
  }
@@ -304,10 +533,15 @@ var InMemoryAgentRunner = class extends require_agent_runner.AgentRunner {
304
533
  * not be wiped this way.
305
534
  */
306
535
  clearThreads() {
307
- GLOBAL_STORE.clear();
536
+ sharedStore.clear();
308
537
  }
309
538
  };
310
539
 
311
540
  //#endregion
312
541
  exports.InMemoryAgentRunner = InMemoryAgentRunner;
542
+ exports.ɵBoundedThreadStore = ɵBoundedThreadStore;
543
+ exports.ɵGLOBAL_STORE = ɵGLOBAL_STORE;
544
+ exports.ɵINMEMORY_DEFAULTS = ɵINMEMORY_DEFAULTS;
545
+ exports.ɵestimateBytes = ɵestimateBytes;
546
+ exports.ɵnormalizeLimits = ɵnormalizeLimits;
313
547
  //# sourceMappingURL=in-memory.cjs.map