@copilotkitnext/runtime 0.0.22-alpha.0 → 0.0.22-alpha.1

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.
@@ -2,353 +2,250 @@
2
2
  var AgentRunner = class {
3
3
  };
4
4
 
5
- // src/runner/base.ts
5
+ // src/runner/in-memory.ts
6
6
  import { ReplaySubject } from "rxjs";
7
- import { EventType as EventType2, compactEvents } from "@ag-ui/client";
7
+ import {
8
+ EventType,
9
+ compactEvents
10
+ } from "@ag-ui/client";
8
11
  import { finalizeRunEvents } from "@copilotkitnext/shared";
9
-
10
- // src/runner/utils.ts
11
- import { EventType } from "@ag-ui/client";
12
- function buildHistoricMessageIdIndex(runs) {
13
- const ids = /* @__PURE__ */ new Set();
14
- for (const run of runs) {
15
- for (const event of run.events) {
16
- const msgId = event.messageId;
17
- if (typeof msgId === "string") ids.add(msgId);
18
- if (event.type === EventType.RUN_STARTED) {
19
- const e = event;
20
- for (const m of e.input?.messages ?? []) {
21
- if (m?.id) ids.add(m.id);
22
- }
23
- }
12
+ var InMemoryEventStore = class {
13
+ constructor(threadId) {
14
+ this.threadId = threadId;
15
+ }
16
+ /** The subject that current consumers subscribe to. */
17
+ subject = null;
18
+ /** True while a run is actively producing events. */
19
+ isRunning = false;
20
+ /** Current run ID */
21
+ currentRunId = null;
22
+ /** Historic completed runs */
23
+ historicRuns = [];
24
+ /** Currently running agent instance (if any). */
25
+ agent = null;
26
+ /** Subject returned from run() while the run is active. */
27
+ runSubject = null;
28
+ /** True once stop() has been requested but the run has not yet finalized. */
29
+ stopRequested = false;
30
+ /** Reference to the events emitted in the current run. */
31
+ currentEvents = null;
32
+ };
33
+ var GLOBAL_STORE = /* @__PURE__ */ new Map();
34
+ var InMemoryAgentRunner = class extends AgentRunner {
35
+ run(request) {
36
+ let existingStore = GLOBAL_STORE.get(request.threadId);
37
+ if (!existingStore) {
38
+ existingStore = new InMemoryEventStore(request.threadId);
39
+ GLOBAL_STORE.set(request.threadId, existingStore);
24
40
  }
25
- }
26
- return ids;
27
- }
28
- function sanitizeRunStarted(event, input, historicIds) {
29
- if (event.input) return event;
30
- const sanitizedMessages = input.messages ? input.messages.filter((m) => !historicIds.has(m.id)) : void 0;
31
- const updatedInput = {
32
- ...input,
33
- ...sanitizedMessages !== void 0 ? { messages: sanitizedMessages } : {}
34
- };
35
- return { ...event, input: updatedInput };
36
- }
37
- function deriveThreadMetadata(params) {
38
- const { threadId, runs, isRunning, resourceId, properties } = params;
39
- const createdAt = runs.length > 0 ? Math.min(...runs.map((r) => r.createdAt)) : Date.now();
40
- const lastActivityAt = runs.length > 0 ? Math.max(...runs.map((r) => r.createdAt)) : createdAt;
41
- let messageCount = 0;
42
- let firstMessage;
43
- for (const run of runs) {
44
- for (const event of run.events) {
45
- if (event.role && typeof event.content === "string") {
46
- messageCount += 1;
47
- if (!firstMessage) firstMessage = event.content;
48
- }
49
- if (event.type === EventType.RUN_STARTED) {
50
- const e = event;
51
- for (const m of e.input?.messages ?? []) {
52
- messageCount += 1;
53
- if (!firstMessage && typeof m.content === "string") {
54
- firstMessage = m.content;
41
+ const store = existingStore;
42
+ if (store.isRunning) {
43
+ throw new Error("Thread already running");
44
+ }
45
+ store.isRunning = true;
46
+ store.currentRunId = request.input.runId;
47
+ store.agent = request.agent;
48
+ store.stopRequested = false;
49
+ const seenMessageIds = /* @__PURE__ */ new Set();
50
+ const currentRunEvents = [];
51
+ store.currentEvents = currentRunEvents;
52
+ const historicMessageIds = /* @__PURE__ */ new Set();
53
+ for (const run of store.historicRuns) {
54
+ for (const event of run.events) {
55
+ if ("messageId" in event && typeof event.messageId === "string") {
56
+ historicMessageIds.add(event.messageId);
57
+ }
58
+ if (event.type === EventType.RUN_STARTED) {
59
+ const runStarted = event;
60
+ const messages = runStarted.input?.messages ?? [];
61
+ for (const message of messages) {
62
+ historicMessageIds.add(message.id);
55
63
  }
56
64
  }
57
65
  }
58
66
  }
59
- }
60
- return {
61
- threadId,
62
- createdAt,
63
- lastActivityAt,
64
- isRunning,
65
- messageCount,
66
- firstMessage,
67
- resourceId,
68
- properties
69
- };
70
- }
71
- function matchesScope(thread, scope) {
72
- if (!scope) return true;
73
- const { resourceId, properties } = scope;
74
- if (resourceId !== void 0) {
75
- if (Array.isArray(resourceId)) {
76
- if (!resourceId.includes(thread.resourceId ?? "")) return false;
77
- } else {
78
- if ((thread.resourceId ?? "") !== resourceId) return false;
79
- }
80
- }
81
- if (properties) {
82
- const t = thread.properties ?? {};
83
- for (const [k, v] of Object.entries(properties)) {
84
- if (t[k] !== v) return false;
85
- }
86
- }
87
- return true;
88
- }
89
-
90
- // src/runner/base.ts
91
- var AgentRunnerBase = class extends AgentRunner {
92
- active = /* @__PURE__ */ new Map();
93
- threadScope = /* @__PURE__ */ new Map();
94
- constructor() {
95
- super();
96
- }
97
- run(request) {
98
- const { threadId, input, agent, scope } = request;
99
- if (scope !== void 0) {
100
- if (!this.threadScope.has(threadId)) this.threadScope.set(threadId, scope ?? null);
101
- }
102
- if (this.active.has(threadId)) {
103
- throw new Error("Thread already running");
104
- }
67
+ const nextSubject = new ReplaySubject(Infinity);
68
+ const prevSubject = store.subject;
69
+ store.subject = nextSubject;
105
70
  const runSubject = new ReplaySubject(Infinity);
106
- void (async () => {
107
- this.active.set(threadId, { agent, stopRequested: false });
108
- const acquired = await this.acquireRun(threadId, input.runId);
109
- if (!acquired) {
110
- this.active.delete(threadId);
111
- runSubject.error(new Error("Thread already running"));
112
- return;
113
- }
114
- const currentRunEvents = [];
115
- const priorRuns = await this.listRuns(threadId);
116
- const historicIds = buildHistoricMessageIdIndex(priorRuns);
117
- const onEvent = (event) => {
118
- let processed = event;
119
- if (event.type === EventType2.RUN_STARTED) {
120
- processed = sanitizeRunStarted(event, input, historicIds);
121
- }
122
- runSubject.next(processed);
123
- currentRunEvents.push(processed);
124
- this.publishLive(threadId, processed);
125
- };
71
+ store.runSubject = runSubject;
72
+ const runAgent = async () => {
73
+ const lastRun = store.historicRuns[store.historicRuns.length - 1];
74
+ const parentRunId = lastRun?.runId ?? null;
126
75
  try {
127
- await agent.runAgent(input, {
128
- onEvent: ({ event }) => onEvent(event),
76
+ await request.agent.runAgent(request.input, {
77
+ onEvent: ({ event }) => {
78
+ let processedEvent = event;
79
+ if (event.type === EventType.RUN_STARTED) {
80
+ const runStartedEvent = event;
81
+ if (!runStartedEvent.input) {
82
+ const sanitizedMessages = request.input.messages ? request.input.messages.filter(
83
+ (message) => !historicMessageIds.has(message.id)
84
+ ) : void 0;
85
+ const updatedInput = {
86
+ ...request.input,
87
+ ...sanitizedMessages !== void 0 ? { messages: sanitizedMessages } : {}
88
+ };
89
+ processedEvent = {
90
+ ...runStartedEvent,
91
+ input: updatedInput
92
+ };
93
+ }
94
+ }
95
+ runSubject.next(processedEvent);
96
+ nextSubject.next(processedEvent);
97
+ currentRunEvents.push(processedEvent);
98
+ },
129
99
  onNewMessage: ({ message }) => {
100
+ if (!seenMessageIds.has(message.id)) {
101
+ seenMessageIds.add(message.id);
102
+ }
130
103
  },
131
104
  onRunStartedEvent: () => {
105
+ if (request.input.messages) {
106
+ for (const message of request.input.messages) {
107
+ if (!seenMessageIds.has(message.id)) {
108
+ seenMessageIds.add(message.id);
109
+ }
110
+ }
111
+ }
132
112
  }
133
113
  });
134
- const ctx = this.active.get(threadId);
135
- const appended = finalizeRunEvents(currentRunEvents, { stopRequested: ctx?.stopRequested ?? false });
136
- for (const e of appended) {
137
- runSubject.next(e);
138
- this.publishLive(threadId, e);
114
+ const appendedEvents = finalizeRunEvents(currentRunEvents, {
115
+ stopRequested: store.stopRequested
116
+ });
117
+ for (const event of appendedEvents) {
118
+ runSubject.next(event);
119
+ nextSubject.next(event);
139
120
  }
140
- const parentRunId = priorRuns.at(-1)?.runId ?? null;
141
- const compacted = compactEvents(currentRunEvents);
142
- await this.saveRun(threadId, input.runId, compacted, input, parentRunId);
143
- } catch (error) {
144
- const ctx = this.active.get(threadId);
145
- const appended = finalizeRunEvents(currentRunEvents, {
146
- stopRequested: ctx?.stopRequested ?? false,
147
- interruptionMessage: error instanceof Error ? error.message : void 0
121
+ if (store.currentRunId) {
122
+ const compactedEvents = compactEvents(currentRunEvents);
123
+ store.historicRuns.push({
124
+ threadId: request.threadId,
125
+ runId: store.currentRunId,
126
+ parentRunId,
127
+ events: compactedEvents,
128
+ createdAt: Date.now()
129
+ });
130
+ }
131
+ store.currentEvents = null;
132
+ store.currentRunId = null;
133
+ store.agent = null;
134
+ store.runSubject = null;
135
+ store.stopRequested = false;
136
+ store.isRunning = false;
137
+ runSubject.complete();
138
+ nextSubject.complete();
139
+ } catch {
140
+ const appendedEvents = finalizeRunEvents(currentRunEvents, {
141
+ stopRequested: store.stopRequested
148
142
  });
149
- for (const e of appended) {
150
- runSubject.next(e);
151
- this.publishLive(threadId, e);
143
+ for (const event of appendedEvents) {
144
+ runSubject.next(event);
145
+ nextSubject.next(event);
152
146
  }
153
- if (currentRunEvents.length > 0) {
154
- const parentRunId = priorRuns.at(-1)?.runId ?? null;
155
- const compacted = compactEvents(currentRunEvents);
156
- await this.saveRun(threadId, input.runId, compacted, input, parentRunId);
147
+ if (store.currentRunId && currentRunEvents.length > 0) {
148
+ const compactedEvents = compactEvents(currentRunEvents);
149
+ store.historicRuns.push({
150
+ threadId: request.threadId,
151
+ runId: store.currentRunId,
152
+ parentRunId,
153
+ events: compactedEvents,
154
+ createdAt: Date.now()
155
+ });
157
156
  }
158
- } finally {
159
- await this.releaseRun(threadId);
160
- this.active.delete(threadId);
161
- this.completeLive(threadId);
157
+ store.currentEvents = null;
158
+ store.currentRunId = null;
159
+ store.agent = null;
160
+ store.runSubject = null;
161
+ store.stopRequested = false;
162
+ store.isRunning = false;
162
163
  runSubject.complete();
164
+ nextSubject.complete();
163
165
  }
164
- })();
166
+ };
167
+ if (prevSubject) {
168
+ prevSubject.subscribe({
169
+ next: (e) => nextSubject.next(e),
170
+ error: (err) => nextSubject.error(err),
171
+ complete: () => {
172
+ }
173
+ });
174
+ }
175
+ runAgent();
165
176
  return runSubject.asObservable();
166
177
  }
167
178
  connect(request) {
168
- const { threadId } = request;
169
- const subject = new ReplaySubject(Infinity);
170
- void (async () => {
171
- const priorRuns = await this.listRuns(threadId);
172
- const allHistoric = [];
173
- for (const r of priorRuns) allHistoric.push(...r.events);
174
- const compacted = compactEvents(allHistoric);
175
- const emittedIds = /* @__PURE__ */ new Set();
176
- for (const e of compacted) {
177
- subject.next(e);
178
- const id = e.messageId;
179
- if (typeof id === "string") emittedIds.add(id);
180
- }
181
- const running = await this.isRunningState(threadId);
182
- if (!running) {
183
- subject.complete();
184
- return;
179
+ const store = GLOBAL_STORE.get(request.threadId);
180
+ const connectionSubject = new ReplaySubject(Infinity);
181
+ if (!store) {
182
+ connectionSubject.complete();
183
+ return connectionSubject.asObservable();
184
+ }
185
+ const allHistoricEvents = [];
186
+ for (const run of store.historicRuns) {
187
+ allHistoricEvents.push(...run.events);
188
+ }
189
+ const compactedEvents = compactEvents(allHistoricEvents);
190
+ const emittedMessageIds = /* @__PURE__ */ new Set();
191
+ for (const event of compactedEvents) {
192
+ connectionSubject.next(event);
193
+ if ("messageId" in event && typeof event.messageId === "string") {
194
+ emittedMessageIds.add(event.messageId);
185
195
  }
186
- const live = this.subscribeLive(threadId);
187
- let completed = false;
188
- live.subscribe({
189
- next: (e) => {
190
- const id = e.messageId;
191
- if (typeof id === "string" && emittedIds.has(id)) return;
192
- subject.next(e);
193
- if (e.type === EventType2.RUN_FINISHED || e.type === EventType2.RUN_ERROR) {
194
- if (!completed) {
195
- completed = true;
196
- subject.complete();
197
- }
196
+ }
197
+ if (store.subject && (store.isRunning || store.stopRequested)) {
198
+ store.subject.subscribe({
199
+ next: (event) => {
200
+ if ("messageId" in event && typeof event.messageId === "string" && emittedMessageIds.has(event.messageId)) {
201
+ return;
198
202
  }
203
+ connectionSubject.next(event);
199
204
  },
200
- error: (err) => subject.error(err),
201
- complete: () => {
202
- if (!completed) {
203
- completed = true;
204
- subject.complete();
205
- }
206
- }
205
+ complete: () => connectionSubject.complete(),
206
+ error: (err) => connectionSubject.error(err)
207
207
  });
208
- })();
209
- return subject.asObservable();
210
- }
211
- async isRunning(request) {
212
- return this.isRunningState(request.threadId);
213
- }
214
- async stop(request) {
215
- const ctx = this.active.get(request.threadId);
216
- if (!ctx?.agent) return false;
217
- if (ctx.stopRequested) return false;
218
- ctx.stopRequested = true;
219
- await this.releaseRun(request.threadId);
220
- try {
221
- ctx.agent.abortRun();
222
- return true;
223
- } catch {
224
- ctx.stopRequested = false;
225
- return false;
226
- }
227
- }
228
- async listThreads(request) {
229
- const limit = request.limit ?? 20;
230
- const offset = request.offset ?? 0;
231
- const page = await this.pageThreads({ scope: request.scope, limit: limit + offset, offset: 0 });
232
- const resultThreads = [];
233
- for (const id of page.threadIds) {
234
- const md = await this.getThreadMetadata(id, request.scope);
235
- if (!md) continue;
236
- if (request.scope ? matchesScope(md, request.scope) : true) {
237
- resultThreads.push(md);
238
- }
208
+ } else {
209
+ connectionSubject.complete();
239
210
  }
240
- resultThreads.sort((a, b) => b.lastActivityAt - a.lastActivityAt);
241
- const sliced = resultThreads.slice(offset, offset + limit);
242
- return { threads: sliced, total: page.total };
211
+ return connectionSubject.asObservable();
243
212
  }
244
- async getThreadMetadata(threadId, scope) {
245
- const runs = await this.listRuns(threadId);
246
- if (runs.length === 0) return null;
247
- const isRunning = await this.isRunningState(threadId);
248
- const s = this.threadScope.get(threadId) ?? null;
249
- return deriveThreadMetadata({
250
- threadId,
251
- runs,
252
- isRunning,
253
- resourceId: s?.resourceId ?? void 0,
254
- properties: s?.properties
255
- });
213
+ isRunning(request) {
214
+ const store = GLOBAL_STORE.get(request.threadId);
215
+ return Promise.resolve(store?.isRunning ?? false);
256
216
  }
257
- async deleteThread(threadId, scope) {
258
- const running = await this.isRunningState(threadId);
259
- if (running) {
260
- throw new Error("Cannot delete a running thread");
217
+ stop(request) {
218
+ const store = GLOBAL_STORE.get(request.threadId);
219
+ if (!store || !store.isRunning) {
220
+ return Promise.resolve(false);
261
221
  }
262
- await this.deleteThreadStorage(threadId, scope);
263
- if (this.closeLive) {
264
- await this.closeLive(threadId);
222
+ if (store.stopRequested) {
223
+ return Promise.resolve(false);
265
224
  }
266
- this.threadScope.delete(threadId);
267
- }
268
- };
269
-
270
- // src/runner/in-memory-runner.ts
271
- import { ReplaySubject as ReplaySubject2 } from "rxjs";
272
- var InMemoryAgentRunner = class extends AgentRunnerBase {
273
- state = /* @__PURE__ */ new Map();
274
- runs = /* @__PURE__ */ new Map();
275
- channels = /* @__PURE__ */ new Map();
276
- constructor() {
277
- super();
278
- }
279
- // Live channel helpers
280
- ensureChannel(threadId) {
281
- let s = this.channels.get(threadId);
282
- if (!s || s.closed) {
283
- s = new ReplaySubject2(Infinity);
284
- this.channels.set(threadId, s);
225
+ store.stopRequested = true;
226
+ store.isRunning = false;
227
+ const agent = store.agent;
228
+ if (!agent) {
229
+ store.stopRequested = false;
230
+ store.isRunning = false;
231
+ return Promise.resolve(false);
285
232
  }
286
- return s;
287
- }
288
- // Hooks implementation
289
- async acquireRun(threadId, runId) {
290
- const entry = this.state.get(threadId) ?? { isRunning: false, runId: null };
291
- if (entry.isRunning) return false;
292
- entry.isRunning = true;
293
- entry.runId = runId;
294
- this.state.set(threadId, entry);
295
- return true;
296
- }
297
- async releaseRun(threadId) {
298
- const entry = this.state.get(threadId) ?? { isRunning: false, runId: null };
299
- entry.isRunning = false;
300
- this.state.set(threadId, entry);
301
- }
302
- async isRunningState(threadId) {
303
- return this.state.get(threadId)?.isRunning ?? false;
304
- }
305
- async listRuns(threadId) {
306
- return this.runs.get(threadId) ?? [];
307
- }
308
- async saveRun(threadId, runId, events, input, parentRunId) {
309
- const list = this.runs.get(threadId) ?? [];
310
- list.push({ runId, events, createdAt: Date.now() });
311
- this.runs.set(threadId, list);
312
- }
313
- async pageThreads(params) {
314
- const all = [];
315
- for (const [id, arr] of this.runs.entries()) {
316
- const last = arr.length > 0 ? Math.max(...arr.map((r) => r.createdAt)) : 0;
317
- all.push({ id, last });
233
+ try {
234
+ agent.abortRun();
235
+ return Promise.resolve(true);
236
+ } catch (error) {
237
+ console.error("Failed to abort agent run", error);
238
+ store.stopRequested = false;
239
+ store.isRunning = true;
240
+ return Promise.resolve(false);
318
241
  }
319
- all.sort((a, b) => b.last - a.last);
320
- const total = all.length;
321
- const offset = params.offset ?? 0;
322
- const limit = params.limit ?? 20;
323
- const ids = all.slice(offset, offset + limit).map((x) => x.id);
324
- return { threadIds: ids, total };
325
- }
326
- async deleteThreadStorage(threadId) {
327
- this.runs.delete(threadId);
328
- this.state.delete(threadId);
329
- }
330
- publishLive(threadId, event) {
331
- const s = this.ensureChannel(threadId);
332
- s.next(event);
333
- }
334
- completeLive(threadId) {
335
- const s = this.ensureChannel(threadId);
336
- if (!s.closed) s.complete();
337
- }
338
- subscribeLive(threadId) {
339
- return this.ensureChannel(threadId).asObservable();
340
- }
341
- async closeLive(threadId) {
342
- const s = this.channels.get(threadId);
343
- if (s && !s.closed) s.complete();
344
- this.channels.delete(threadId);
345
242
  }
346
243
  };
347
244
 
348
245
  // package.json
349
246
  var package_default = {
350
247
  name: "@copilotkitnext/runtime",
351
- version: "0.0.22-alpha.0",
248
+ version: "0.0.22-alpha.1",
352
249
  description: "Server-side runtime package for CopilotKit2",
353
250
  main: "dist/index.js",
354
251
  types: "dist/index.d.ts",
@@ -392,9 +289,9 @@ var package_default = {
392
289
  vitest: "^3.0.5"
393
290
  },
394
291
  dependencies: {
395
- "@ag-ui/client": "0.0.40-alpha.11",
396
- "@ag-ui/core": "0.0.40-alpha.11",
397
- "@ag-ui/encoder": "0.0.40-alpha.11",
292
+ "@ag-ui/client": "0.0.41-alpha.0",
293
+ "@ag-ui/core": "0.0.41-alpha.0",
294
+ "@ag-ui/encoder": "0.0.41-alpha.0",
398
295
  "@copilotkitnext/shared": "workspace:*",
399
296
  cors: "^2.8.5",
400
297
  express: "^4.21.2",
@@ -707,7 +604,7 @@ async function handleConnectAgent({
707
604
  }
708
605
 
709
606
  // src/handlers/handle-stop.ts
710
- import { EventType as EventType3 } from "@ag-ui/client";
607
+ import { EventType as EventType2 } from "@ag-ui/client";
711
608
  async function handleStopAgent({
712
609
  runtime,
713
610
  request,
@@ -745,7 +642,7 @@ async function handleStopAgent({
745
642
  JSON.stringify({
746
643
  stopped: true,
747
644
  interrupt: {
748
- type: EventType3.RUN_ERROR,
645
+ type: EventType2.RUN_ERROR,
749
646
  message: "Run stopped by user",
750
647
  code: "STOPPED"
751
648
  }
@@ -1025,7 +922,6 @@ export {
1025
922
  handleConnectAgent,
1026
923
  handleStopAgent,
1027
924
  AgentRunner,
1028
- AgentRunnerBase,
1029
925
  InMemoryAgentRunner,
1030
926
  VERSION,
1031
927
  CopilotRuntime,
@@ -1037,4 +933,4 @@ export {
1037
933
  expectString,
1038
934
  createJsonRequest
1039
935
  };
1040
- //# sourceMappingURL=chunk-LDTC5BLU.mjs.map
936
+ //# sourceMappingURL=chunk-ELMYXVVN.mjs.map