@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.
- package/dist/agent/converters/aisdk.cjs +17 -9
- package/dist/agent/converters/aisdk.cjs.map +1 -1
- package/dist/agent/converters/aisdk.d.cts +1 -1
- package/dist/agent/converters/aisdk.d.cts.map +1 -1
- package/dist/agent/converters/aisdk.d.mts +1 -1
- package/dist/agent/converters/aisdk.d.mts.map +1 -1
- package/dist/agent/converters/aisdk.mjs +17 -9
- package/dist/agent/converters/aisdk.mjs.map +1 -1
- package/dist/agent/converters/tanstack.cjs +17 -9
- package/dist/agent/converters/tanstack.cjs.map +1 -1
- package/dist/agent/converters/tanstack.d.cts +1 -1
- package/dist/agent/converters/tanstack.d.cts.map +1 -1
- package/dist/agent/converters/tanstack.d.mts +1 -1
- package/dist/agent/converters/tanstack.d.mts.map +1 -1
- package/dist/agent/converters/tanstack.mjs +17 -9
- package/dist/agent/converters/tanstack.mjs.map +1 -1
- package/dist/agent/index.cjs +6 -4
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts.map +1 -1
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +6 -4
- package/dist/agent/index.mjs.map +1 -1
- package/dist/agent/state-delta.cjs +322 -0
- package/dist/agent/state-delta.cjs.map +1 -0
- package/dist/agent/state-delta.mjs +321 -0
- package/dist/agent/state-delta.mjs.map +1 -0
- package/dist/package.cjs +1 -1
- package/dist/runtime/package.mjs +1 -1
- package/dist/v2/index.cjs +6 -1
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/runtime/core/channel-manager.cjs +110 -9
- package/dist/v2/runtime/core/channel-manager.cjs.map +1 -1
- package/dist/v2/runtime/core/channel-manager.d.cts +79 -8
- package/dist/v2/runtime/core/channel-manager.d.cts.map +1 -1
- package/dist/v2/runtime/core/channel-manager.d.mts +79 -8
- package/dist/v2/runtime/core/channel-manager.d.mts.map +1 -1
- package/dist/v2/runtime/core/channel-manager.mjs +110 -9
- package/dist/v2/runtime/core/channel-manager.mjs.map +1 -1
- package/dist/v2/runtime/core/runtime.cjs.map +1 -1
- package/dist/v2/runtime/core/runtime.d.cts +1 -0
- package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
- package/dist/v2/runtime/core/runtime.d.mts +1 -0
- package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
- package/dist/v2/runtime/core/runtime.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs +2 -5
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs +2 -5
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -1
- package/dist/v2/runtime/handlers/shared/mcp-apps-servers.cjs +23 -0
- package/dist/v2/runtime/handlers/shared/mcp-apps-servers.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/mcp-apps-servers.mjs +22 -0
- package/dist/v2/runtime/handlers/shared/mcp-apps-servers.mjs.map +1 -0
- package/dist/v2/runtime/index.d.cts +1 -1
- package/dist/v2/runtime/index.d.mts +1 -1
- package/dist/v2/runtime/open-generative-ui-middleware.cjs +1 -0
- package/dist/v2/runtime/open-generative-ui-middleware.cjs.map +1 -1
- package/dist/v2/runtime/open-generative-ui-middleware.mjs +1 -0
- package/dist/v2/runtime/open-generative-ui-middleware.mjs.map +1 -1
- package/dist/v2/runtime/runner/in-memory.cjs +335 -101
- package/dist/v2/runtime/runner/in-memory.cjs.map +1 -1
- package/dist/v2/runtime/runner/in-memory.d.cts +246 -6
- package/dist/v2/runtime/runner/in-memory.d.cts.map +1 -1
- package/dist/v2/runtime/runner/in-memory.d.mts +246 -6
- package/dist/v2/runtime/runner/in-memory.d.mts.map +1 -1
- package/dist/v2/runtime/runner/in-memory.mjs +331 -102
- package/dist/v2/runtime/runner/in-memory.mjs.map +1 -1
- package/dist/v2/runtime/runner/index.d.cts +1 -1
- package/dist/v2/runtime/runner/index.d.mts +1 -1
- package/dist/v2/runtime/runner/index.mjs +1 -1
- package/package.json +5 -5
- package/skills/runtime/references/agent-runners-in-memory.md +49 -34
- package/skills/runtime/references/agent-runners.md +47 -21
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
31
|
-
if (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
435
|
+
const store = sharedStore.peek(request.threadId);
|
|
195
436
|
return Promise.resolve(store?.isRunning ?? false);
|
|
196
437
|
}
|
|
197
438
|
stop(request) {
|
|
198
|
-
const store =
|
|
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
|
-
|
|
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 =
|
|
257
|
-
if (!store
|
|
258
|
-
return
|
|
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 =
|
|
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
|
-
|
|
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
|