@copilotkitnext/runtime 0.0.1 → 0.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@copilotkitnext/runtime",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Server-side runtime package for CopilotKit2",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -35,7 +35,7 @@
35
35
  "ioredis": "^5.7.0",
36
36
  "kysely": "^0.28.5",
37
37
  "rxjs": "7.8.1",
38
- "@copilotkitnext/shared": "0.0.1"
38
+ "@copilotkitnext/shared": "0.0.2"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "better-sqlite3": "^12.2.0",
@@ -6,7 +6,7 @@ import {
6
6
  type AgentRunnerStopRequest,
7
7
  } from "./agent-runner";
8
8
  import { Observable, ReplaySubject } from "rxjs";
9
- import {
9
+ import {
10
10
  BaseEvent,
11
11
  Message,
12
12
  EventType,
@@ -16,7 +16,8 @@ import {
16
16
  ToolCallStartEvent,
17
17
  ToolCallArgsEvent,
18
18
  ToolCallEndEvent,
19
- ToolCallResultEvent
19
+ ToolCallResultEvent,
20
+ MessagesSnapshotEvent,
20
21
  } from "@ag-ui/client";
21
22
  import { compactEvents } from "./event-compaction";
22
23
 
@@ -42,7 +43,7 @@ class InMemoryEventStore {
42
43
 
43
44
  /** Current run ID */
44
45
  currentRunId: string | null = null;
45
-
46
+
46
47
  /** Historic completed runs */
47
48
  historicRuns: HistoricRun[] = [];
48
49
  }
@@ -137,12 +138,12 @@ export class InMemoryAgentRunner extends AgentRunner {
137
138
  // Track seen message IDs and current run events for this run
138
139
  const seenMessageIds = new Set<string>();
139
140
  const currentRunEvents: BaseEvent[] = [];
140
-
141
+
141
142
  // Get all previously seen message IDs from historic runs
142
143
  const historicMessageIds = new Set<string>();
143
144
  for (const run of store.historicRuns) {
144
145
  for (const event of run.events) {
145
- if ('messageId' in event && typeof event.messageId === 'string') {
146
+ if ("messageId" in event && typeof event.messageId === "string") {
146
147
  historicMessageIds.add(event.messageId);
147
148
  }
148
149
  }
@@ -163,10 +164,23 @@ export class InMemoryAgentRunner extends AgentRunner {
163
164
  // Get parent run ID for chaining
164
165
  const lastRun = store.historicRuns[store.historicRuns.length - 1];
165
166
  const parentRunId = lastRun?.runId ?? null;
166
-
167
+
167
168
  try {
168
169
  await request.agent.runAgent(request.input, {
169
170
  onEvent: ({ event }) => {
171
+ if (event.type === EventType.MESSAGES_SNAPSHOT) {
172
+ const messagesSnapshotEvent = event as MessagesSnapshotEvent;
173
+ const fixedMessages = [];
174
+ const messageIds = new Set<string>();
175
+ for (const message of messagesSnapshotEvent.messages) {
176
+ if (messageIds.has(message.id)) {
177
+ continue;
178
+ }
179
+ fixedMessages.push(message);
180
+ messageIds.add(message.id);
181
+ }
182
+ messagesSnapshotEvent.messages = fixedMessages;
183
+ }
170
184
  runSubject.next(event); // For run() return - only agent events
171
185
  nextSubject.next(event); // For connect() / store - all events
172
186
  currentRunEvents.push(event); // Accumulate for storage
@@ -184,14 +198,14 @@ export class InMemoryAgentRunner extends AgentRunner {
184
198
  if (!seenMessageIds.has(message.id)) {
185
199
  seenMessageIds.add(message.id);
186
200
  const events = this.convertMessageToEvents(message);
187
-
201
+
188
202
  // Check if this message is NEW (not in historic runs)
189
203
  const isNewMessage = !historicMessageIds.has(message.id);
190
-
204
+
191
205
  for (const event of events) {
192
206
  // Always emit to stream for context
193
207
  nextSubject.next(event);
194
-
208
+
195
209
  // Store if this is a NEW message for this run
196
210
  if (isNewMessage) {
197
211
  currentRunEvents.push(event);
@@ -202,11 +216,12 @@ export class InMemoryAgentRunner extends AgentRunner {
202
216
  }
203
217
  },
204
218
  });
205
-
219
+
206
220
  // Store the completed run in memory with ONLY its events
207
221
  if (store.currentRunId) {
208
222
  // Compact the events before storing (like SQLite does)
209
223
  const compactedEvents = compactEvents(currentRunEvents);
224
+
210
225
  store.historicRuns.push({
211
226
  threadId: request.threadId,
212
227
  runId: store.currentRunId,
@@ -215,7 +230,7 @@ export class InMemoryAgentRunner extends AgentRunner {
215
230
  createdAt: Date.now(),
216
231
  });
217
232
  }
218
-
233
+
219
234
  // Complete the run
220
235
  store.isRunning = false;
221
236
  store.currentRunId = null;
@@ -234,7 +249,7 @@ export class InMemoryAgentRunner extends AgentRunner {
234
249
  createdAt: Date.now(),
235
250
  });
236
251
  }
237
-
252
+
238
253
  // Complete the run
239
254
  store.isRunning = false;
240
255
  store.currentRunId = null;
@@ -276,37 +291,41 @@ export class InMemoryAgentRunner extends AgentRunner {
276
291
  for (const run of store.historicRuns) {
277
292
  allHistoricEvents.push(...run.events);
278
293
  }
279
-
294
+
280
295
  // Apply compaction to all historic events together (like SQLite)
281
296
  const compactedEvents = compactEvents(allHistoricEvents);
282
-
297
+
283
298
  // Emit compacted events and track message IDs
284
299
  const emittedMessageIds = new Set<string>();
285
300
  for (const event of compactedEvents) {
286
301
  connectionSubject.next(event);
287
- if ('messageId' in event && typeof event.messageId === 'string') {
302
+ if ("messageId" in event && typeof event.messageId === "string") {
288
303
  emittedMessageIds.add(event.messageId);
289
304
  }
290
305
  }
291
-
306
+
292
307
  // Bridge active run to connection if exists
293
308
  if (store.subject && store.isRunning) {
294
309
  store.subject.subscribe({
295
310
  next: (event) => {
296
311
  // Skip message events that we've already emitted from historic
297
- if ('messageId' in event && typeof event.messageId === 'string' && emittedMessageIds.has(event.messageId)) {
312
+ if (
313
+ "messageId" in event &&
314
+ typeof event.messageId === "string" &&
315
+ emittedMessageIds.has(event.messageId)
316
+ ) {
298
317
  return;
299
318
  }
300
319
  connectionSubject.next(event);
301
320
  },
302
321
  complete: () => connectionSubject.complete(),
303
- error: (err) => connectionSubject.error(err)
322
+ error: (err) => connectionSubject.error(err),
304
323
  });
305
324
  } else {
306
325
  // No active run, complete after historic events
307
326
  connectionSubject.complete();
308
327
  }
309
-
328
+
310
329
  return connectionSubject.asObservable();
311
330
  }
312
331
 
@@ -319,4 +338,4 @@ export class InMemoryAgentRunner extends AgentRunner {
319
338
  stop(_request: AgentRunnerStopRequest): Promise<boolean | undefined> {
320
339
  throw new Error("Method not implemented.");
321
340
  }
322
- }
341
+ }
package/README-RUNNERS.md DELETED
@@ -1,78 +0,0 @@
1
- # Agent Runners
2
-
3
- CopilotKit Runtime provides two agent runners for different use cases:
4
-
5
- ## InMemoryAgentRunner (Default)
6
-
7
- The default runner that stores all data in memory. Perfect for development and applications that don't need persistence.
8
-
9
- ```typescript
10
- import { CopilotRuntime, InMemoryAgentRunner } from "@copilotkitnext/runtime";
11
-
12
- // Default - uses InMemoryAgentRunner automatically
13
- const runtime = new CopilotRuntime({
14
- agents: myAgents,
15
- });
16
-
17
- // Or explicitly
18
- const runtime = new CopilotRuntime({
19
- agents: myAgents,
20
- runner: new InMemoryAgentRunner(),
21
- });
22
- ```
23
-
24
- **Features:**
25
-
26
- - No external dependencies
27
- - Fast performance
28
- - Data is lost when process restarts
29
- - Perfect for development and stateless applications
30
-
31
- ## SqliteAgentRunner
32
-
33
- Provides persistent storage using SQLite. Ideal for applications that need to preserve conversation history across restarts.
34
-
35
- ```typescript
36
- import { CopilotRuntime, SqliteAgentRunner } from "@copilotkitnext/runtime";
37
-
38
- const runtime = new CopilotRuntime({
39
- agents: myAgents,
40
- runner: new SqliteAgentRunner("./data/copilot.db"),
41
- });
42
-
43
- // Or use in-memory SQLite (data persists during runtime only)
44
- const runtime = new CopilotRuntime({
45
- agents: myAgents,
46
- runner: new SqliteAgentRunner(":memory:"),
47
- });
48
- ```
49
-
50
- **Features:**
51
-
52
- - Persistent storage across restarts
53
- - Maintains conversation history
54
- - Parent-child run relationships
55
- - Event compaction for historic runs
56
-
57
- **Requirements:**
58
-
59
- - Requires `better-sqlite3` to be installed:
60
- ```bash
61
- npm install better-sqlite3
62
- ```
63
-
64
- ## Choosing the Right Runner
65
-
66
- - **Use InMemoryAgentRunner when:**
67
- - Building prototypes or demos
68
- - Running in serverless environments
69
- - You don't need conversation history
70
- - You want zero external dependencies
71
-
72
- - **Use SqliteAgentRunner when:**
73
- - You need persistent conversation history
74
- - Building production applications
75
- - You want to analyze historic conversations
76
- - Running on a traditional server
77
-
78
- Both runners implement the same `AgentRunner` interface, so you can switch between them without changing your application code.