@copilotkitnext/runtime 0.0.3 → 0.0.5
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/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/.turbo/turbo-build.log +0 -23
- package/.turbo/turbo-check-types.log +0 -4
- package/.turbo/turbo-lint.log +0 -56
- package/.turbo/turbo-test$colon$coverage.log +0 -149
- package/.turbo/turbo-test.log +0 -108
- package/src/__tests__/get-runtime-info.test.ts +0 -117
- package/src/__tests__/handle-run.test.ts +0 -69
- package/src/__tests__/handle-transcribe.test.ts +0 -289
- package/src/__tests__/in-process-agent-runner-messages.test.ts +0 -599
- package/src/__tests__/in-process-agent-runner.test.ts +0 -726
- package/src/__tests__/middleware.test.ts +0 -432
- package/src/__tests__/routing.test.ts +0 -257
- package/src/endpoint.ts +0 -150
- package/src/handler.ts +0 -3
- package/src/handlers/get-runtime-info.ts +0 -50
- package/src/handlers/handle-connect.ts +0 -144
- package/src/handlers/handle-run.ts +0 -156
- package/src/handlers/handle-transcribe.ts +0 -126
- package/src/index.ts +0 -8
- package/src/middleware.ts +0 -232
- package/src/runner/__tests__/enterprise-runner.test.ts +0 -992
- package/src/runner/__tests__/event-compaction.test.ts +0 -253
- package/src/runner/__tests__/in-memory-runner.test.ts +0 -483
- package/src/runner/__tests__/sqlite-runner.test.ts +0 -975
- package/src/runner/agent-runner.ts +0 -27
- package/src/runner/enterprise.ts +0 -653
- package/src/runner/event-compaction.ts +0 -250
- package/src/runner/in-memory.ts +0 -328
- package/src/runner/index.ts +0 -0
- package/src/runner/sqlite.ts +0 -481
- package/src/runtime.ts +0 -53
- package/src/transcription-service/transcription-service-openai.ts +0 -29
- package/src/transcription-service/transcription-service.ts +0 -11
- package/tsconfig.json +0 -13
- package/tsup.config.ts +0 -11
|
@@ -1,599 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
-
import { InMemoryAgentRunner } from "../runner/in-memory";
|
|
3
|
-
import {
|
|
4
|
-
AbstractAgent,
|
|
5
|
-
BaseEvent,
|
|
6
|
-
RunAgentInput,
|
|
7
|
-
Message,
|
|
8
|
-
RunStartedEvent,
|
|
9
|
-
EventType,
|
|
10
|
-
} from "@ag-ui/client";
|
|
11
|
-
import { EMPTY, firstValueFrom, Observable } from "rxjs";
|
|
12
|
-
import { toArray } from "rxjs/operators";
|
|
13
|
-
|
|
14
|
-
// Type helpers for event filtering
|
|
15
|
-
type EventWithType = BaseEvent & { type: string };
|
|
16
|
-
type EventWithId = BaseEvent & { id: string };
|
|
17
|
-
type EventWithMessageId = BaseEvent & { messageId: string };
|
|
18
|
-
type EventWithMessageIdAndDelta = BaseEvent & {
|
|
19
|
-
messageId: string;
|
|
20
|
-
delta: string;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
// Mock agent that can handle messages and callbacks
|
|
24
|
-
class MessageAwareAgent extends AbstractAgent {
|
|
25
|
-
private events: BaseEvent[] = [];
|
|
26
|
-
public receivedMessages: Message[] = [];
|
|
27
|
-
public onNewMessageCalled = 0;
|
|
28
|
-
public onRunStartedCalled = 0;
|
|
29
|
-
|
|
30
|
-
constructor(events: BaseEvent[] = []) {
|
|
31
|
-
super();
|
|
32
|
-
this.events = events;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
protected run(input: RunAgentInput): Observable<BaseEvent> {
|
|
36
|
-
return EMPTY;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async runAgent(
|
|
40
|
-
input: RunAgentInput,
|
|
41
|
-
options: {
|
|
42
|
-
onEvent: (event: { event: BaseEvent }) => void;
|
|
43
|
-
onNewMessage?: (args: { message: Message }) => void;
|
|
44
|
-
onRunStartedEvent?: (args: { event: BaseEvent }) => void;
|
|
45
|
-
}
|
|
46
|
-
// @ts-expect-error
|
|
47
|
-
): Promise<RunAgentResult> {
|
|
48
|
-
// Call onRunStartedEvent if provided
|
|
49
|
-
if (options.onRunStartedEvent) {
|
|
50
|
-
this.onRunStartedCalled++;
|
|
51
|
-
const runStartedEvent = {
|
|
52
|
-
type: EventType.RUN_STARTED,
|
|
53
|
-
threadId: input.threadId,
|
|
54
|
-
runId: input.runId,
|
|
55
|
-
} as RunStartedEvent;
|
|
56
|
-
options.onRunStartedEvent({ event: runStartedEvent });
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Emit the agent's own events
|
|
60
|
-
for (const event of this.events) {
|
|
61
|
-
options.onEvent({ event });
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Return a promise as expected
|
|
65
|
-
return Promise.resolve();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
describe("InMemoryAgentRunner - Message Injection", () => {
|
|
70
|
-
let runner: InMemoryAgentRunner;
|
|
71
|
-
|
|
72
|
-
beforeEach(() => {
|
|
73
|
-
runner = new InMemoryAgentRunner();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
describe("Message Injection on Run", () => {
|
|
77
|
-
it("should inject user messages as events when running an agent", async () => {
|
|
78
|
-
const threadId = "test-thread-messages-1";
|
|
79
|
-
const userMessage: Message = {
|
|
80
|
-
id: "user-msg-1",
|
|
81
|
-
role: "user",
|
|
82
|
-
content: "Hello, agent!",
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const agentEvents: BaseEvent[] = [
|
|
86
|
-
{
|
|
87
|
-
type: EventType.CUSTOM,
|
|
88
|
-
id: "agent-response-1",
|
|
89
|
-
timestamp: Date.now(),
|
|
90
|
-
name: "agent-response",
|
|
91
|
-
value: { text: "Hello, user!" },
|
|
92
|
-
} as BaseEvent,
|
|
93
|
-
];
|
|
94
|
-
|
|
95
|
-
const agent = new MessageAwareAgent(agentEvents);
|
|
96
|
-
const input: RunAgentInput = {
|
|
97
|
-
messages: [userMessage],
|
|
98
|
-
state: {},
|
|
99
|
-
threadId,
|
|
100
|
-
runId: "run-1",
|
|
101
|
-
tools: [],
|
|
102
|
-
context: [],
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
// Run the agent
|
|
106
|
-
const runObservable = runner.run({ threadId, agent, input });
|
|
107
|
-
const runEvents = await firstValueFrom(runObservable.pipe(toArray()));
|
|
108
|
-
|
|
109
|
-
// run() should only return agent events, not injected messages
|
|
110
|
-
expect(runEvents).toHaveLength(1);
|
|
111
|
-
expect((runEvents[0] as EventWithId).id).toBe("agent-response-1");
|
|
112
|
-
|
|
113
|
-
// connect() should have all events including injected messages
|
|
114
|
-
const connectObservable = runner.connect({ threadId });
|
|
115
|
-
const allEvents = await firstValueFrom(connectObservable.pipe(toArray()));
|
|
116
|
-
|
|
117
|
-
// Should have: user message events (Start, Content, End) + agent event = 4 events
|
|
118
|
-
expect(allEvents.length).toBe(4);
|
|
119
|
-
|
|
120
|
-
// Find the injected user message events
|
|
121
|
-
const textStartEvents = allEvents.filter(
|
|
122
|
-
(e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_START
|
|
123
|
-
);
|
|
124
|
-
const textContentEvents = allEvents.filter(
|
|
125
|
-
(e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_CONTENT
|
|
126
|
-
);
|
|
127
|
-
const textEndEvents = allEvents.filter(
|
|
128
|
-
(e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_END
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
expect(textStartEvents).toHaveLength(1);
|
|
132
|
-
expect(textStartEvents[0]).toMatchObject({
|
|
133
|
-
type: EventType.TEXT_MESSAGE_START,
|
|
134
|
-
messageId: "user-msg-1",
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
expect(textContentEvents).toHaveLength(1);
|
|
138
|
-
expect(textContentEvents[0]).toMatchObject({
|
|
139
|
-
type: EventType.TEXT_MESSAGE_CONTENT,
|
|
140
|
-
messageId: "user-msg-1",
|
|
141
|
-
delta: "Hello, agent!",
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
expect(textEndEvents).toHaveLength(1);
|
|
145
|
-
expect(textEndEvents[0]).toMatchObject({
|
|
146
|
-
type: EventType.TEXT_MESSAGE_END,
|
|
147
|
-
messageId: "user-msg-1",
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
// Verify the agent callbacks
|
|
151
|
-
expect(agent.onNewMessageCalled).toBe(0); // onNewMessage is not called by the test agent
|
|
152
|
-
expect(agent.onRunStartedCalled).toBe(1);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it("should inject assistant messages as proper TextMessage events", async () => {
|
|
156
|
-
const threadId = "test-thread-messages-2";
|
|
157
|
-
const assistantMessage: Message = {
|
|
158
|
-
id: "assistant-msg-1",
|
|
159
|
-
role: "assistant",
|
|
160
|
-
content: "I can help you with that!",
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
const agent = new MessageAwareAgent([]);
|
|
164
|
-
const input: RunAgentInput = {
|
|
165
|
-
messages: [assistantMessage],
|
|
166
|
-
state: {},
|
|
167
|
-
threadId,
|
|
168
|
-
runId: "run-2",
|
|
169
|
-
tools: [],
|
|
170
|
-
context: [],
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
// Run the agent
|
|
174
|
-
await firstValueFrom(
|
|
175
|
-
runner.run({ threadId, agent, input }).pipe(toArray())
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
// Check events via connect
|
|
179
|
-
const allEvents = await firstValueFrom(
|
|
180
|
-
runner.connect({ threadId }).pipe(toArray())
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
// Find the injected message events
|
|
184
|
-
const textStartEvents = allEvents.filter(
|
|
185
|
-
(e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_START
|
|
186
|
-
);
|
|
187
|
-
const textContentEvents = allEvents.filter(
|
|
188
|
-
(e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_CONTENT
|
|
189
|
-
);
|
|
190
|
-
const textEndEvents = allEvents.filter(
|
|
191
|
-
(e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_END
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
expect(textStartEvents).toHaveLength(1);
|
|
195
|
-
expect(textStartEvents[0]).toMatchObject({
|
|
196
|
-
type: EventType.TEXT_MESSAGE_START,
|
|
197
|
-
messageId: "assistant-msg-1",
|
|
198
|
-
role: "assistant",
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
expect(textContentEvents).toHaveLength(1);
|
|
202
|
-
expect(textContentEvents[0]).toMatchObject({
|
|
203
|
-
type: EventType.TEXT_MESSAGE_CONTENT,
|
|
204
|
-
messageId: "assistant-msg-1",
|
|
205
|
-
delta: "I can help you with that!",
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
expect(textEndEvents).toHaveLength(1);
|
|
209
|
-
expect(textEndEvents[0]).toMatchObject({
|
|
210
|
-
type: EventType.TEXT_MESSAGE_END,
|
|
211
|
-
messageId: "assistant-msg-1",
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it("should inject tool call messages as proper ToolCall events", async () => {
|
|
216
|
-
const threadId = "test-thread-messages-3";
|
|
217
|
-
const toolCallMessage: Message = {
|
|
218
|
-
id: "assistant-msg-2",
|
|
219
|
-
role: "assistant",
|
|
220
|
-
content: "",
|
|
221
|
-
toolCalls: [
|
|
222
|
-
{
|
|
223
|
-
id: "tool-call-1",
|
|
224
|
-
type: "function",
|
|
225
|
-
function: {
|
|
226
|
-
name: "get_weather",
|
|
227
|
-
arguments: '{"location": "New York"}',
|
|
228
|
-
},
|
|
229
|
-
},
|
|
230
|
-
],
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
const agent = new MessageAwareAgent([]);
|
|
234
|
-
const input: RunAgentInput = {
|
|
235
|
-
messages: [toolCallMessage],
|
|
236
|
-
state: {},
|
|
237
|
-
threadId,
|
|
238
|
-
runId: "run-3",
|
|
239
|
-
tools: [],
|
|
240
|
-
context: [],
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
// Run the agent
|
|
244
|
-
await firstValueFrom(
|
|
245
|
-
runner.run({ threadId, agent, input }).pipe(toArray())
|
|
246
|
-
);
|
|
247
|
-
|
|
248
|
-
// Check events via connect
|
|
249
|
-
const allEvents = await firstValueFrom(
|
|
250
|
-
runner.connect({ threadId }).pipe(toArray())
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
// Find the injected tool call events
|
|
254
|
-
const toolStartEvents = allEvents.filter(
|
|
255
|
-
(e) => (e as EventWithType).type === EventType.TOOL_CALL_START
|
|
256
|
-
);
|
|
257
|
-
const toolArgsEvents = allEvents.filter(
|
|
258
|
-
(e) => (e as EventWithType).type === EventType.TOOL_CALL_ARGS
|
|
259
|
-
);
|
|
260
|
-
const toolEndEvents = allEvents.filter(
|
|
261
|
-
(e) => (e as EventWithType).type === EventType.TOOL_CALL_END
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
expect(toolStartEvents).toHaveLength(1);
|
|
265
|
-
expect(toolStartEvents[0]).toMatchObject({
|
|
266
|
-
type: EventType.TOOL_CALL_START,
|
|
267
|
-
toolCallId: "tool-call-1",
|
|
268
|
-
toolCallName: "get_weather",
|
|
269
|
-
parentMessageId: "assistant-msg-2",
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
expect(toolArgsEvents).toHaveLength(1);
|
|
273
|
-
expect(toolArgsEvents[0]).toMatchObject({
|
|
274
|
-
type: EventType.TOOL_CALL_ARGS,
|
|
275
|
-
toolCallId: "tool-call-1",
|
|
276
|
-
delta: '{"location": "New York"}',
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
expect(toolEndEvents).toHaveLength(1);
|
|
280
|
-
expect(toolEndEvents[0]).toMatchObject({
|
|
281
|
-
type: EventType.TOOL_CALL_END,
|
|
282
|
-
toolCallId: "tool-call-1",
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
it("should inject developer and system messages as TextMessage events", async () => {
|
|
287
|
-
const threadId = "test-thread-messages-dev-sys";
|
|
288
|
-
const developerMessage: Message = {
|
|
289
|
-
id: "dev-msg-1",
|
|
290
|
-
role: "developer",
|
|
291
|
-
content: "You are a helpful assistant.",
|
|
292
|
-
};
|
|
293
|
-
const systemMessage: Message = {
|
|
294
|
-
id: "sys-msg-1",
|
|
295
|
-
role: "system",
|
|
296
|
-
content: "System prompt: Be concise.",
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
const agent = new MessageAwareAgent([]);
|
|
300
|
-
const input: RunAgentInput = {
|
|
301
|
-
messages: [developerMessage, systemMessage],
|
|
302
|
-
state: {},
|
|
303
|
-
threadId,
|
|
304
|
-
runId: "run-dev-sys",
|
|
305
|
-
tools: [],
|
|
306
|
-
context: [],
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
// Run the agent
|
|
310
|
-
await firstValueFrom(
|
|
311
|
-
runner.run({ threadId, agent, input }).pipe(toArray())
|
|
312
|
-
);
|
|
313
|
-
|
|
314
|
-
// Check events via connect
|
|
315
|
-
const allEvents = await firstValueFrom(
|
|
316
|
-
runner.connect({ threadId }).pipe(toArray())
|
|
317
|
-
);
|
|
318
|
-
|
|
319
|
-
// Find the injected message events
|
|
320
|
-
const textStartEvents = allEvents.filter(
|
|
321
|
-
(e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_START
|
|
322
|
-
);
|
|
323
|
-
const textContentEvents = allEvents.filter(
|
|
324
|
-
(e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_CONTENT
|
|
325
|
-
);
|
|
326
|
-
const textEndEvents = allEvents.filter(
|
|
327
|
-
(e) => (e as EventWithType).type === EventType.TEXT_MESSAGE_END
|
|
328
|
-
);
|
|
329
|
-
|
|
330
|
-
// Should have 2 sets of text message events (one for each message)
|
|
331
|
-
expect(textStartEvents).toHaveLength(2);
|
|
332
|
-
expect(textContentEvents).toHaveLength(2);
|
|
333
|
-
expect(textEndEvents).toHaveLength(2);
|
|
334
|
-
|
|
335
|
-
// Verify developer message events
|
|
336
|
-
expect(
|
|
337
|
-
textStartEvents.some(
|
|
338
|
-
(e) => (e as EventWithMessageId).messageId === "dev-msg-1"
|
|
339
|
-
)
|
|
340
|
-
).toBe(true);
|
|
341
|
-
expect(
|
|
342
|
-
textContentEvents.some((e) => {
|
|
343
|
-
const evt = e as EventWithMessageIdAndDelta;
|
|
344
|
-
return (
|
|
345
|
-
evt.messageId === "dev-msg-1" &&
|
|
346
|
-
evt.delta === "You are a helpful assistant."
|
|
347
|
-
);
|
|
348
|
-
})
|
|
349
|
-
).toBe(true);
|
|
350
|
-
|
|
351
|
-
// Verify system message events
|
|
352
|
-
expect(
|
|
353
|
-
textStartEvents.some(
|
|
354
|
-
(e) => (e as EventWithMessageId).messageId === "sys-msg-1"
|
|
355
|
-
)
|
|
356
|
-
).toBe(true);
|
|
357
|
-
expect(
|
|
358
|
-
textContentEvents.some((e) => {
|
|
359
|
-
const evt = e as EventWithMessageIdAndDelta;
|
|
360
|
-
return (
|
|
361
|
-
evt.messageId === "sys-msg-1" &&
|
|
362
|
-
evt.delta === "System prompt: Be concise."
|
|
363
|
-
);
|
|
364
|
-
})
|
|
365
|
-
).toBe(true);
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
it("should inject tool result messages as ToolCallResult events", async () => {
|
|
369
|
-
const threadId = "test-thread-messages-4";
|
|
370
|
-
const toolResultMessage: Message = {
|
|
371
|
-
id: "tool-result-1",
|
|
372
|
-
role: "tool",
|
|
373
|
-
content: "72°F and sunny",
|
|
374
|
-
toolCallId: "tool-call-1",
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
const agent = new MessageAwareAgent([]);
|
|
378
|
-
const input: RunAgentInput = {
|
|
379
|
-
messages: [toolResultMessage],
|
|
380
|
-
state: {},
|
|
381
|
-
threadId,
|
|
382
|
-
runId: "run-4",
|
|
383
|
-
tools: [],
|
|
384
|
-
context: [],
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
// Run the agent
|
|
388
|
-
await firstValueFrom(
|
|
389
|
-
runner.run({ threadId, agent, input }).pipe(toArray())
|
|
390
|
-
);
|
|
391
|
-
|
|
392
|
-
// Check events via connect
|
|
393
|
-
const allEvents = await firstValueFrom(
|
|
394
|
-
runner.connect({ threadId }).pipe(toArray())
|
|
395
|
-
);
|
|
396
|
-
|
|
397
|
-
// Find the injected tool result events
|
|
398
|
-
const toolResultEvents = allEvents.filter(
|
|
399
|
-
(e) => (e as EventWithType).type === EventType.TOOL_CALL_RESULT
|
|
400
|
-
);
|
|
401
|
-
|
|
402
|
-
expect(toolResultEvents).toHaveLength(1);
|
|
403
|
-
expect(toolResultEvents[0]).toMatchObject({
|
|
404
|
-
type: EventType.TOOL_CALL_RESULT,
|
|
405
|
-
messageId: "tool-result-1",
|
|
406
|
-
toolCallId: "tool-call-1",
|
|
407
|
-
content: "72°F and sunny",
|
|
408
|
-
role: "tool",
|
|
409
|
-
});
|
|
410
|
-
});
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
describe("Consecutive Runs with Different Messages", () => {
|
|
414
|
-
it("should accumulate messages across multiple runs", async () => {
|
|
415
|
-
const threadId = "test-thread-consecutive-1";
|
|
416
|
-
|
|
417
|
-
// First run with a user message
|
|
418
|
-
const userMessage1: Message = {
|
|
419
|
-
id: "user-msg-1",
|
|
420
|
-
role: "user",
|
|
421
|
-
content: "What's the weather?",
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
const agent1 = new MessageAwareAgent([
|
|
425
|
-
{
|
|
426
|
-
type: EventType.CUSTOM,
|
|
427
|
-
id: "agent-1-response",
|
|
428
|
-
timestamp: Date.now(),
|
|
429
|
-
name: "agent-response",
|
|
430
|
-
value: { text: "Let me check..." },
|
|
431
|
-
} as BaseEvent,
|
|
432
|
-
]);
|
|
433
|
-
|
|
434
|
-
const input1: RunAgentInput = {
|
|
435
|
-
messages: [userMessage1],
|
|
436
|
-
state: {},
|
|
437
|
-
threadId,
|
|
438
|
-
runId: "run-1",
|
|
439
|
-
tools: [],
|
|
440
|
-
context: [],
|
|
441
|
-
};
|
|
442
|
-
|
|
443
|
-
await firstValueFrom(
|
|
444
|
-
runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray())
|
|
445
|
-
);
|
|
446
|
-
|
|
447
|
-
// Second run with assistant and tool messages
|
|
448
|
-
const assistantMessage: Message = {
|
|
449
|
-
id: "assistant-msg-1",
|
|
450
|
-
role: "assistant",
|
|
451
|
-
content: "",
|
|
452
|
-
toolCalls: [
|
|
453
|
-
{
|
|
454
|
-
id: "tool-call-1",
|
|
455
|
-
type: "function",
|
|
456
|
-
function: {
|
|
457
|
-
name: "get_weather",
|
|
458
|
-
arguments: '{"location": "current"}',
|
|
459
|
-
},
|
|
460
|
-
},
|
|
461
|
-
],
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
const toolResultMessage: Message = {
|
|
465
|
-
id: "tool-result-1",
|
|
466
|
-
role: "tool",
|
|
467
|
-
content: "72°F and sunny in New York",
|
|
468
|
-
toolCallId: "tool-call-1",
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
const agent2 = new MessageAwareAgent([
|
|
472
|
-
{
|
|
473
|
-
type: EventType.CUSTOM,
|
|
474
|
-
id: "agent-2-response",
|
|
475
|
-
timestamp: Date.now(),
|
|
476
|
-
name: "agent-response",
|
|
477
|
-
value: { text: "It's 72°F and sunny!" },
|
|
478
|
-
} as BaseEvent,
|
|
479
|
-
]);
|
|
480
|
-
|
|
481
|
-
const input2: RunAgentInput = {
|
|
482
|
-
messages: [userMessage1, assistantMessage, toolResultMessage],
|
|
483
|
-
state: {},
|
|
484
|
-
threadId,
|
|
485
|
-
runId: "run-2",
|
|
486
|
-
tools: [],
|
|
487
|
-
context: [],
|
|
488
|
-
};
|
|
489
|
-
|
|
490
|
-
await firstValueFrom(
|
|
491
|
-
runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray())
|
|
492
|
-
);
|
|
493
|
-
|
|
494
|
-
// Connect should have all events from both runs
|
|
495
|
-
const allEvents = await firstValueFrom(
|
|
496
|
-
runner.connect({ threadId }).pipe(toArray())
|
|
497
|
-
);
|
|
498
|
-
|
|
499
|
-
// Should have events from both runs plus injected message events
|
|
500
|
-
expect(allEvents.length).toBeGreaterThan(4);
|
|
501
|
-
|
|
502
|
-
// Verify we have both agent responses
|
|
503
|
-
const agentResponses = allEvents.filter(
|
|
504
|
-
(e) => e.type === EventType.CUSTOM
|
|
505
|
-
);
|
|
506
|
-
expect(
|
|
507
|
-
agentResponses.some((e) => (e as EventWithId).id === "agent-1-response")
|
|
508
|
-
).toBe(true);
|
|
509
|
-
expect(
|
|
510
|
-
agentResponses.some((e) => (e as EventWithId).id === "agent-2-response")
|
|
511
|
-
).toBe(true);
|
|
512
|
-
|
|
513
|
-
// Verify we have the tool call events
|
|
514
|
-
const toolCallStarts = allEvents.filter(
|
|
515
|
-
(e) => (e as EventWithType).type === EventType.TOOL_CALL_START
|
|
516
|
-
);
|
|
517
|
-
expect(toolCallStarts).toHaveLength(1);
|
|
518
|
-
|
|
519
|
-
// Verify we have the tool result event
|
|
520
|
-
const toolResults = allEvents.filter(
|
|
521
|
-
(e) => (e as EventWithType).type === EventType.TOOL_CALL_RESULT
|
|
522
|
-
);
|
|
523
|
-
expect(toolResults).toHaveLength(1);
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
it("should track seen message IDs and not duplicate messages", async () => {
|
|
527
|
-
const threadId = "test-thread-duplicate-1";
|
|
528
|
-
|
|
529
|
-
const sharedMessage: Message = {
|
|
530
|
-
id: "shared-msg-1",
|
|
531
|
-
role: "assistant",
|
|
532
|
-
content: "This message appears in both runs",
|
|
533
|
-
};
|
|
534
|
-
|
|
535
|
-
const newMessage: Message = {
|
|
536
|
-
id: "new-msg-1",
|
|
537
|
-
role: "assistant",
|
|
538
|
-
content: "This is a new message",
|
|
539
|
-
};
|
|
540
|
-
|
|
541
|
-
// First run with shared message
|
|
542
|
-
const agent1 = new MessageAwareAgent([]);
|
|
543
|
-
const input1: RunAgentInput = {
|
|
544
|
-
messages: [sharedMessage],
|
|
545
|
-
state: {},
|
|
546
|
-
threadId,
|
|
547
|
-
runId: "run-1",
|
|
548
|
-
tools: [],
|
|
549
|
-
context: [],
|
|
550
|
-
};
|
|
551
|
-
|
|
552
|
-
await firstValueFrom(
|
|
553
|
-
runner.run({ threadId, agent: agent1, input: input1 }).pipe(toArray())
|
|
554
|
-
);
|
|
555
|
-
|
|
556
|
-
// Second run with shared message and new message
|
|
557
|
-
const agent2 = new MessageAwareAgent([]);
|
|
558
|
-
const input2: RunAgentInput = {
|
|
559
|
-
messages: [sharedMessage, newMessage],
|
|
560
|
-
state: {},
|
|
561
|
-
threadId,
|
|
562
|
-
runId: "run-2",
|
|
563
|
-
tools: [],
|
|
564
|
-
context: [],
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
await firstValueFrom(
|
|
568
|
-
runner.run({ threadId, agent: agent2, input: input2 }).pipe(toArray())
|
|
569
|
-
);
|
|
570
|
-
|
|
571
|
-
// Connect should have events without duplicates
|
|
572
|
-
const allEvents = await firstValueFrom(
|
|
573
|
-
runner.connect({ threadId }).pipe(toArray())
|
|
574
|
-
);
|
|
575
|
-
|
|
576
|
-
// Count TextMessageStart events for our messages
|
|
577
|
-
const textStartEvents = allEvents.filter((e) => {
|
|
578
|
-
const evt = e as EventWithType & { messageId?: string };
|
|
579
|
-
return (
|
|
580
|
-
evt.type === EventType.TEXT_MESSAGE_START &&
|
|
581
|
-
(evt.messageId === "shared-msg-1" || evt.messageId === "new-msg-1")
|
|
582
|
-
);
|
|
583
|
-
});
|
|
584
|
-
|
|
585
|
-
// Should have exactly 2 TextMessageStart events (one for each unique message)
|
|
586
|
-
expect(textStartEvents).toHaveLength(2);
|
|
587
|
-
expect(
|
|
588
|
-
textStartEvents.some(
|
|
589
|
-
(e) => (e as EventWithMessageId).messageId === "shared-msg-1"
|
|
590
|
-
)
|
|
591
|
-
).toBe(true);
|
|
592
|
-
expect(
|
|
593
|
-
textStartEvents.some(
|
|
594
|
-
(e) => (e as EventWithMessageId).messageId === "new-msg-1"
|
|
595
|
-
)
|
|
596
|
-
).toBe(true);
|
|
597
|
-
});
|
|
598
|
-
});
|
|
599
|
-
});
|