@copilotkitnext/core 0.0.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.
Files changed (63) hide show
  1. package/.turbo/turbo-build.log +22 -0
  2. package/.turbo/turbo-check-types.log +4 -0
  3. package/.turbo/turbo-lint.log +12 -0
  4. package/.turbo/turbo-test.log +96 -0
  5. package/LICENSE +11 -0
  6. package/coverage/base.css +224 -0
  7. package/coverage/block-navigation.js +87 -0
  8. package/coverage/favicon.png +0 -0
  9. package/coverage/index.html +131 -0
  10. package/coverage/lcov-report/base.css +224 -0
  11. package/coverage/lcov-report/block-navigation.js +87 -0
  12. package/coverage/lcov-report/favicon.png +0 -0
  13. package/coverage/lcov-report/index.html +131 -0
  14. package/coverage/lcov-report/prettify.css +1 -0
  15. package/coverage/lcov-report/prettify.js +2 -0
  16. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  17. package/coverage/lcov-report/sorter.js +210 -0
  18. package/coverage/lcov-report/src/agent.ts.html +193 -0
  19. package/coverage/lcov-report/src/core.ts.html +919 -0
  20. package/coverage/lcov-report/src/index.html +146 -0
  21. package/coverage/lcov-report/src/types.ts.html +112 -0
  22. package/coverage/lcov-report/src/utils/index.html +116 -0
  23. package/coverage/lcov-report/src/utils/markdown.ts.html +895 -0
  24. package/coverage/lcov.info +556 -0
  25. package/coverage/prettify.css +1 -0
  26. package/coverage/prettify.js +2 -0
  27. package/coverage/sort-arrow-sprite.png +0 -0
  28. package/coverage/sorter.js +210 -0
  29. package/coverage/src/agent.ts.html +193 -0
  30. package/coverage/src/core.ts.html +919 -0
  31. package/coverage/src/index.html +146 -0
  32. package/coverage/src/types.ts.html +112 -0
  33. package/coverage/src/utils/index.html +116 -0
  34. package/coverage/src/utils/markdown.ts.html +895 -0
  35. package/dist/index.d.mts +93 -0
  36. package/dist/index.d.ts +93 -0
  37. package/dist/index.js +526 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/index.mjs +502 -0
  40. package/dist/index.mjs.map +1 -0
  41. package/eslint.config.mjs +3 -0
  42. package/package.json +46 -0
  43. package/src/__tests__/core-agent-constraints.test.ts +86 -0
  44. package/src/__tests__/core-basic-functionality.test.ts +158 -0
  45. package/src/__tests__/core-basic.test.ts +27 -0
  46. package/src/__tests__/core-edge-cases.test.ts +166 -0
  47. package/src/__tests__/core-follow-up.test.ts +216 -0
  48. package/src/__tests__/core-full.test.ts +320 -0
  49. package/src/__tests__/core-simple.test.ts +24 -0
  50. package/src/__tests__/core-tool-minimal.test.ts +41 -0
  51. package/src/__tests__/core-tool-simple.test.ts +40 -0
  52. package/src/__tests__/core-wildcard.test.ts +45 -0
  53. package/src/__tests__/import.test.ts +13 -0
  54. package/src/__tests__/simple.test.ts +7 -0
  55. package/src/__tests__/test-utils.ts +162 -0
  56. package/src/agent.ts +37 -0
  57. package/src/core.ts +336 -0
  58. package/src/index.ts +4 -0
  59. package/src/types.ts +23 -0
  60. package/src/utils/markdown.ts +271 -0
  61. package/tsconfig.json +12 -0
  62. package/tsup.config.ts +11 -0
  63. package/vitest.config.mjs +15 -0
@@ -0,0 +1,320 @@
1
+ import { describe, it, expect, beforeEach, vi, afterEach } from "vitest";
2
+ import { CopilotKitCore } from "../core";
3
+ import { FrontendTool } from "../types";
4
+ import {
5
+ MockAgent,
6
+ createMessage,
7
+ createAssistantMessage,
8
+ createToolCallMessage,
9
+ createToolResultMessage,
10
+ createTool,
11
+ createMultipleToolCallsMessage,
12
+ } from "./test-utils";
13
+
14
+ describe("CopilotKitCore.runAgent - Full Test Suite", () => {
15
+ let copilotKitCore: CopilotKitCore;
16
+
17
+ beforeEach(() => {
18
+ copilotKitCore = new CopilotKitCore({});
19
+ vi.clearAllMocks();
20
+ });
21
+
22
+ afterEach(() => {
23
+ vi.restoreAllMocks();
24
+ });
25
+
26
+ describe("Tests that should pass", () => {
27
+ it("TEST 1: should run agent without tools", async () => {
28
+ const messages = [
29
+ createMessage({ content: "Hello" }),
30
+ createAssistantMessage({ content: "Hi there!" }),
31
+ ];
32
+ const agent = new MockAgent({ newMessages: messages });
33
+
34
+ const result = await copilotKitCore.runAgent({ agent: agent as any });
35
+
36
+ expect(result.newMessages).toEqual(messages);
37
+ expect(agent.runAgentCalls).toHaveLength(1);
38
+ });
39
+
40
+ it("TEST 2: should execute tool with string result", async () => {
41
+ const toolName = "stringTool";
42
+ const tool = createTool({
43
+ name: toolName,
44
+ handler: vi.fn(async () => "String result"),
45
+ followUp: false,
46
+ });
47
+ copilotKitCore.addTool(tool);
48
+
49
+ const message = createToolCallMessage(toolName, { input: "test" });
50
+ const agent = new MockAgent({ newMessages: [message] });
51
+
52
+ await copilotKitCore.runAgent({ agent: agent as any });
53
+
54
+ expect(tool.handler).toHaveBeenCalledWith({ input: "test" });
55
+ expect(agent.messages.some(m => m.role === "tool")).toBe(true);
56
+ });
57
+
58
+ it("TEST 3: should skip tool when not found", async () => {
59
+ const message = createToolCallMessage("nonExistentTool");
60
+ const agent = new MockAgent({ newMessages: [message] });
61
+
62
+ await copilotKitCore.runAgent({ agent: agent as any });
63
+
64
+ expect(agent.messages.filter(m => m.role === "tool")).toHaveLength(0);
65
+ });
66
+ });
67
+
68
+ describe("Tests that might reveal problems", () => {
69
+ it("TEST 4: should handle follow-up with recursion", async () => {
70
+ console.log("TEST 4: Starting follow-up test");
71
+ const tool = createTool({
72
+ name: "followUpTool",
73
+ handler: vi.fn(async () => "Result"),
74
+ followUp: true, // This should trigger recursion
75
+ });
76
+ copilotKitCore.addTool(tool);
77
+
78
+ const message = createToolCallMessage("followUpTool");
79
+ const followUpMessage = createAssistantMessage({ content: "Follow-up response" });
80
+
81
+ const agent = new MockAgent({ newMessages: [message] });
82
+ let callCount = 0;
83
+ agent.runAgentCallback = () => {
84
+ callCount++;
85
+ console.log(`TEST 4: Call count: ${callCount}`);
86
+ if (callCount === 2) {
87
+ agent.setNewMessages([followUpMessage]);
88
+ }
89
+ };
90
+
91
+ try {
92
+ const result = await copilotKitCore.runAgent({ agent: agent as any });
93
+ console.log(`TEST 4: Success - calls: ${agent.runAgentCalls.length}`);
94
+ expect(agent.runAgentCalls).toHaveLength(2);
95
+ expect(result.newMessages).toContain(followUpMessage);
96
+ } catch (error) {
97
+ console.log(`TEST 4: Error - ${error}`);
98
+ throw error;
99
+ }
100
+ });
101
+
102
+ it("TEST 5: should handle multiple tools with at least one follow-up", async () => {
103
+ console.log("TEST 5: Starting multiple tools test");
104
+ const tool1 = createTool({
105
+ name: "tool1",
106
+ handler: vi.fn(async () => "Result 1"),
107
+ followUp: false,
108
+ });
109
+ const tool2 = createTool({
110
+ name: "tool2",
111
+ handler: vi.fn(async () => "Result 2"),
112
+ followUp: true, // This one needs follow-up
113
+ });
114
+ copilotKitCore.addTool(tool1);
115
+ copilotKitCore.addTool(tool2);
116
+
117
+ const message = createMultipleToolCallsMessage([
118
+ { name: "tool1" },
119
+ { name: "tool2" },
120
+ ]);
121
+
122
+ const agent = new MockAgent({ newMessages: [message] });
123
+ let callCount = 0;
124
+ agent.runAgentCallback = () => {
125
+ callCount++;
126
+ console.log(`TEST 5: Call count: ${callCount}`);
127
+ if (callCount === 2) {
128
+ agent.setNewMessages([]);
129
+ }
130
+ };
131
+
132
+ try {
133
+ await copilotKitCore.runAgent({ agent: agent as any });
134
+ console.log(`TEST 5: Success - calls: ${agent.runAgentCalls.length}`);
135
+ expect(agent.runAgentCalls).toHaveLength(2);
136
+ } catch (error) {
137
+ console.log(`TEST 5: Error - ${error}`);
138
+ throw error;
139
+ }
140
+ });
141
+
142
+ it("TEST 6: should handle tool with undefined follow-up (defaults to true)", async () => {
143
+ console.log("TEST 6: Starting undefined follow-up test");
144
+ const tool: FrontendTool = {
145
+ name: "defaultFollowUpTool",
146
+ handler: vi.fn(async () => "Result"),
147
+ // followUp is undefined - should default to true
148
+ };
149
+ copilotKitCore.addTool(tool);
150
+
151
+ const message = createToolCallMessage("defaultFollowUpTool");
152
+ const followUpMessage = createAssistantMessage({ content: "Follow-up" });
153
+
154
+ const agent = new MockAgent({ newMessages: [message] });
155
+ let callCount = 0;
156
+ agent.runAgentCallback = () => {
157
+ callCount++;
158
+ console.log(`TEST 6: Call count: ${callCount}`);
159
+ if (callCount === 2) {
160
+ agent.setNewMessages([followUpMessage]);
161
+ }
162
+ };
163
+
164
+ try {
165
+ await copilotKitCore.runAgent({ agent: agent as any });
166
+ console.log(`TEST 6: Success - calls: ${agent.runAgentCalls.length}`);
167
+ expect(agent.runAgentCalls).toHaveLength(2);
168
+ } catch (error) {
169
+ console.log(`TEST 6: Error - ${error}`);
170
+ throw error;
171
+ }
172
+ });
173
+
174
+ it("TEST 7: should handle invalid JSON in tool arguments", async () => {
175
+ console.log("TEST 7: Starting invalid JSON test");
176
+ const toolName = "invalidJsonTool";
177
+ const tool = createTool({
178
+ name: toolName,
179
+ handler: vi.fn(async () => "Should not be called"),
180
+ });
181
+ copilotKitCore.addTool(tool);
182
+
183
+ const message = createAssistantMessage({
184
+ content: "",
185
+ toolCalls: [{
186
+ id: "tool-call-1",
187
+ type: "function",
188
+ function: {
189
+ name: toolName,
190
+ arguments: "{ invalid json",
191
+ },
192
+ }],
193
+ });
194
+ const agent = new MockAgent({ newMessages: [message] });
195
+
196
+ try {
197
+ await copilotKitCore.runAgent({ agent: agent as any });
198
+ console.log("TEST 7: ERROR - Should have thrown!");
199
+ expect(true).toBe(false); // Should not reach here
200
+ } catch (error) {
201
+ console.log(`TEST 7: Success - caught error: ${error}`);
202
+ expect(tool.handler).not.toHaveBeenCalled();
203
+ }
204
+ });
205
+
206
+ it("TEST 8: should handle empty string arguments", async () => {
207
+ console.log("TEST 8: Starting empty arguments test");
208
+ const tool = createTool({
209
+ name: "emptyArgsTool",
210
+ handler: vi.fn(async (args) => `Received: ${JSON.stringify(args)}`),
211
+ });
212
+ copilotKitCore.addTool(tool);
213
+
214
+ const message = createAssistantMessage({
215
+ content: "",
216
+ toolCalls: [{
217
+ id: "empty-args-call",
218
+ type: "function",
219
+ function: {
220
+ name: "emptyArgsTool",
221
+ arguments: "",
222
+ },
223
+ }],
224
+ });
225
+
226
+ const agent = new MockAgent({ newMessages: [message] });
227
+
228
+ try {
229
+ await copilotKitCore.runAgent({ agent: agent as any });
230
+ console.log("TEST 8: ERROR - Should have thrown on empty string!");
231
+ expect(true).toBe(false);
232
+ } catch (error) {
233
+ console.log(`TEST 8: Success - caught error: ${error}`);
234
+ expect(tool.handler).not.toHaveBeenCalled();
235
+ }
236
+ });
237
+
238
+ it("TEST 9: should handle chain of follow-ups", async () => {
239
+ console.log("TEST 9: Starting chain test");
240
+ const tool1 = createTool({
241
+ name: "chainTool1",
242
+ handler: vi.fn(async () => "Result 1"),
243
+ followUp: true,
244
+ });
245
+ const tool2 = createTool({
246
+ name: "chainTool2",
247
+ handler: vi.fn(async () => "Result 2"),
248
+ followUp: true,
249
+ });
250
+ copilotKitCore.addTool(tool1);
251
+ copilotKitCore.addTool(tool2);
252
+
253
+ const msg1 = createToolCallMessage("chainTool1");
254
+ const msg2 = createToolCallMessage("chainTool2");
255
+ const finalMsg = createAssistantMessage({ content: "Done" });
256
+
257
+ const agent = new MockAgent({ newMessages: [msg1] });
258
+ let callCount = 0;
259
+ agent.runAgentCallback = () => {
260
+ callCount++;
261
+ console.log(`TEST 9: Call count: ${callCount}`);
262
+ if (callCount === 2) {
263
+ agent.setNewMessages([msg2]);
264
+ } else if (callCount === 3) {
265
+ agent.setNewMessages([finalMsg]);
266
+ }
267
+ };
268
+
269
+ try {
270
+ const result = await copilotKitCore.runAgent({ agent: agent as any });
271
+ console.log(`TEST 9: Success - calls: ${agent.runAgentCalls.length}`);
272
+ expect(agent.runAgentCalls).toHaveLength(3);
273
+ expect(result.newMessages).toEqual([finalMsg]);
274
+ } catch (error) {
275
+ console.log(`TEST 9: Error - ${error}`);
276
+ throw error;
277
+ }
278
+ });
279
+
280
+ it("TEST 10: should handle concurrent tool calls", async () => {
281
+ console.log("TEST 10: Starting concurrent tools test");
282
+ const delays = [50, 30, 70];
283
+ const tools = delays.map((delay, i) =>
284
+ createTool({
285
+ name: `concurrentTool${i}`,
286
+ handler: vi.fn(async () => {
287
+ await new Promise(resolve => setTimeout(resolve, delay));
288
+ return `Result ${i} after ${delay}ms`;
289
+ }),
290
+ followUp: false,
291
+ })
292
+ );
293
+
294
+ tools.forEach(tool => copilotKitCore.addTool(tool));
295
+
296
+ const message = createMultipleToolCallsMessage(
297
+ delays.map((_, i) => ({ name: `concurrentTool${i}` }))
298
+ );
299
+ const agent = new MockAgent({ newMessages: [message] });
300
+
301
+ const startTime = Date.now();
302
+ try {
303
+ await copilotKitCore.runAgent({ agent: agent as any });
304
+ const duration = Date.now() - startTime;
305
+ console.log(`TEST 10: Success - duration: ${duration}ms`);
306
+
307
+ // Should execute sequentially
308
+ const expectedMinDuration = delays.reduce((a, b) => a + b, 0);
309
+ expect(duration).toBeGreaterThanOrEqual(expectedMinDuration - 10);
310
+
311
+ tools.forEach(tool => {
312
+ expect(tool.handler).toHaveBeenCalled();
313
+ });
314
+ } catch (error) {
315
+ console.log(`TEST 10: Error - ${error}`);
316
+ throw error;
317
+ }
318
+ });
319
+ });
320
+ });
@@ -0,0 +1,24 @@
1
+ import { describe, it, expect, beforeEach, vi } from "vitest";
2
+ import { CopilotKitCore } from "../core";
3
+ import { MockAgent, createMessage, createAssistantMessage } from "./test-utils";
4
+
5
+ describe("CopilotKitCore.runAgent Simple", () => {
6
+ let copilotKitCore: CopilotKitCore;
7
+
8
+ beforeEach(() => {
9
+ copilotKitCore = new CopilotKitCore({});
10
+ });
11
+
12
+ it("should run agent without tools", async () => {
13
+ const messages = [
14
+ createMessage({ content: "Hello" }),
15
+ createAssistantMessage({ content: "Hi there!" }),
16
+ ];
17
+ const agent = new MockAgent({ newMessages: messages });
18
+
19
+ const result = await copilotKitCore.runAgent({ agent: agent as any });
20
+
21
+ expect(result.newMessages).toEqual(messages);
22
+ expect(agent.runAgentCalls).toHaveLength(1);
23
+ });
24
+ });
@@ -0,0 +1,41 @@
1
+ import { describe, it, expect, beforeEach, vi } from "vitest";
2
+ import { CopilotKitCore } from "../core";
3
+ import {
4
+ MockAgent,
5
+ createToolCallMessage,
6
+ createTool,
7
+ } from "./test-utils";
8
+
9
+ describe("CopilotKitCore Tool Minimal", () => {
10
+ let copilotKitCore: CopilotKitCore;
11
+
12
+ beforeEach(() => {
13
+ copilotKitCore = new CopilotKitCore({});
14
+ });
15
+
16
+ it("should execute tool with string result", async () => {
17
+ const toolName = "stringTool";
18
+ const tool = createTool({
19
+ name: toolName,
20
+ handler: vi.fn(async () => "String result"),
21
+ });
22
+ copilotKitCore.addTool(tool);
23
+
24
+ const message = createToolCallMessage(toolName, { input: "test" });
25
+ const agent = new MockAgent({ newMessages: [message] });
26
+
27
+ await copilotKitCore.runAgent({ agent: agent as any });
28
+
29
+ expect(tool.handler).toHaveBeenCalledWith({ input: "test" });
30
+ expect(agent.messages.some(m => m.role === "tool")).toBe(true);
31
+ });
32
+
33
+ it("should skip tool call when tool not found", async () => {
34
+ const message = createToolCallMessage("nonExistentTool");
35
+ const agent = new MockAgent({ newMessages: [message] });
36
+
37
+ await copilotKitCore.runAgent({ agent: agent as any });
38
+
39
+ expect(agent.messages.filter(m => m.role === "tool")).toHaveLength(0);
40
+ });
41
+ });
@@ -0,0 +1,40 @@
1
+ import { describe, it, expect, beforeEach, vi } from "vitest";
2
+ import { CopilotKitCore } from "../core";
3
+ import {
4
+ MockAgent,
5
+ createToolCallMessage,
6
+ createTool,
7
+ } from "./test-utils";
8
+
9
+ describe("CopilotKitCore Tool Simple", () => {
10
+ let copilotKitCore: CopilotKitCore;
11
+
12
+ beforeEach(() => {
13
+ copilotKitCore = new CopilotKitCore({});
14
+ });
15
+
16
+ it("should execute a simple tool", async () => {
17
+ console.log("Starting simple tool test");
18
+
19
+ const toolName = "simpleTool";
20
+ const tool = createTool({
21
+ name: toolName,
22
+ handler: vi.fn(async () => {
23
+ console.log("Tool handler called");
24
+ return "Simple result";
25
+ }),
26
+ followUp: false, // Important: no follow-up to avoid recursion
27
+ });
28
+ copilotKitCore.addTool(tool);
29
+
30
+ const message = createToolCallMessage(toolName, { input: "test" });
31
+ const agent = new MockAgent({ newMessages: [message] });
32
+
33
+ console.log("About to run agent");
34
+ await copilotKitCore.runAgent({ agent: agent as any });
35
+ console.log("Agent run complete");
36
+
37
+ expect(tool.handler).toHaveBeenCalledWith({ input: "test" });
38
+ expect(agent.messages.length).toBeGreaterThan(0);
39
+ });
40
+ });
@@ -0,0 +1,45 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { CopilotKitCore } from '../core';
3
+ import { FrontendTool } from '../types';
4
+
5
+ describe('CopilotKitCore - Wildcard Tool Simple', () => {
6
+ it('should add wildcard tool', () => {
7
+ const core = new CopilotKitCore({
8
+ headers: {},
9
+ properties: {},
10
+ });
11
+
12
+ const wildcardTool: FrontendTool = {
13
+ name: '*',
14
+ handler: vi.fn(),
15
+ };
16
+
17
+ core.addTool(wildcardTool);
18
+ expect(core.tools['*']).toBeDefined();
19
+ expect(core.tools['*']?.name).toBe('*');
20
+ });
21
+
22
+ it('should not interfere with specific tools', () => {
23
+ const core = new CopilotKitCore({
24
+ headers: {},
25
+ properties: {},
26
+ });
27
+
28
+ const specificTool: FrontendTool = {
29
+ name: 'specific',
30
+ handler: vi.fn(),
31
+ };
32
+
33
+ const wildcardTool: FrontendTool = {
34
+ name: '*',
35
+ handler: vi.fn(),
36
+ };
37
+
38
+ core.addTool(specificTool);
39
+ core.addTool(wildcardTool);
40
+
41
+ expect(core.tools['specific']).toBeDefined();
42
+ expect(core.tools['*']).toBeDefined();
43
+ expect(Object.keys(core.tools).length).toBe(2);
44
+ });
45
+ });
@@ -0,0 +1,13 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { Message } from "@ag-ui/client";
3
+
4
+ describe("Import Test", () => {
5
+ it("should import Message type", () => {
6
+ const msg: Message = {
7
+ id: "test",
8
+ role: "user",
9
+ content: "test",
10
+ };
11
+ expect(msg.id).toBe("test");
12
+ });
13
+ });
@@ -0,0 +1,7 @@
1
+ import { describe, it, expect } from "vitest";
2
+
3
+ describe("Simple Test", () => {
4
+ it("should pass", () => {
5
+ expect(1 + 1).toBe(2);
6
+ });
7
+ });
@@ -0,0 +1,162 @@
1
+ import { Message } from "@ag-ui/client";
2
+ import { vi } from "vitest";
3
+ import { FrontendTool } from "../types";
4
+
5
+ export interface MockAgentOptions {
6
+ messages?: Message[];
7
+ newMessages?: Message[];
8
+ error?: Error | string;
9
+ runAgentDelay?: number;
10
+ runAgentCallback?: (input: any) => void;
11
+ }
12
+
13
+ export class MockAgent {
14
+ public messages: Message[] = [];
15
+ public addMessages = vi.fn((messages: Message[]) => {
16
+ this.messages.push(...messages);
17
+ });
18
+
19
+ private newMessages: Message[];
20
+ private error?: Error | string;
21
+ private runAgentDelay: number;
22
+ public runAgentCallback?: (input: any) => void;
23
+ public runAgentCalls: any[] = [];
24
+
25
+ constructor(options: MockAgentOptions = {}) {
26
+ this.messages = options.messages || [];
27
+ this.newMessages = options.newMessages || [];
28
+ this.error = options.error;
29
+ this.runAgentDelay = options.runAgentDelay || 0;
30
+ this.runAgentCallback = options.runAgentCallback;
31
+ }
32
+
33
+ async runAgent(input: any): Promise<{ newMessages: Message[] }> {
34
+ this.runAgentCalls.push(input);
35
+
36
+ if (this.runAgentCallback) {
37
+ this.runAgentCallback(input);
38
+ }
39
+
40
+ if (this.runAgentDelay > 0) {
41
+ await new Promise(resolve => setTimeout(resolve, this.runAgentDelay));
42
+ }
43
+
44
+ if (this.error) {
45
+ throw this.error;
46
+ }
47
+
48
+ return { newMessages: this.newMessages };
49
+ }
50
+
51
+ clone(): MockAgent {
52
+ return new MockAgent({
53
+ messages: [...this.messages],
54
+ newMessages: [...this.newMessages],
55
+ error: this.error,
56
+ runAgentDelay: this.runAgentDelay,
57
+ runAgentCallback: this.runAgentCallback,
58
+ });
59
+ }
60
+
61
+ setNewMessages(messages: Message[]): void {
62
+ this.newMessages = messages;
63
+ }
64
+ }
65
+
66
+ export function createMessage(overrides: Partial<Message> = {}): Message {
67
+ return {
68
+ id: `msg-${Math.random().toString(36).substr(2, 9)}`,
69
+ role: "user",
70
+ content: "Test message",
71
+ ...overrides,
72
+ } as Message;
73
+ }
74
+
75
+ export function createAssistantMessage(
76
+ overrides: Partial<Message> = {}
77
+ ): Message {
78
+ return createMessage({
79
+ role: "assistant",
80
+ content: "Assistant message",
81
+ ...overrides,
82
+ });
83
+ }
84
+
85
+ export function createToolCallMessage(
86
+ toolCallName: string,
87
+ args: any = {},
88
+ overrides: Partial<Message> = {}
89
+ ): Message {
90
+ const toolCallId = `tool-call-${Math.random().toString(36).substr(2, 9)}`;
91
+ return createAssistantMessage({
92
+ content: "",
93
+ toolCalls: [
94
+ {
95
+ id: toolCallId,
96
+ type: "function",
97
+ function: {
98
+ name: toolCallName,
99
+ arguments: JSON.stringify(args),
100
+ },
101
+ },
102
+ ],
103
+ ...overrides,
104
+ });
105
+ }
106
+
107
+ export function createToolResultMessage(
108
+ toolCallId: string,
109
+ content: string,
110
+ overrides: Partial<Message> = {}
111
+ ): Message {
112
+ return createMessage({
113
+ role: "tool",
114
+ content,
115
+ toolCallId,
116
+ ...overrides,
117
+ });
118
+ }
119
+
120
+ export function createTool<T extends Record<string, unknown>>(
121
+ overrides: Partial<FrontendTool<T>> = {}
122
+ ): FrontendTool<T> {
123
+ return {
124
+ name: `tool-${Math.random().toString(36).substr(2, 9)}`,
125
+ description: "Test tool",
126
+ handler: vi.fn(async () => "Tool result"),
127
+ followUp: false, // Default to false to avoid unexpected recursion in tests
128
+ ...overrides,
129
+ };
130
+ }
131
+
132
+ export function createMultipleToolCallsMessage(
133
+ toolCalls: Array<{ name: string; args?: any }>,
134
+ overrides: Partial<Message> = {}
135
+ ): Message {
136
+ return createAssistantMessage({
137
+ content: "",
138
+ toolCalls: toolCalls.map((tc) => ({
139
+ id: `tool-call-${Math.random().toString(36).substr(2, 9)}`,
140
+ type: "function",
141
+ function: {
142
+ name: tc.name,
143
+ arguments: JSON.stringify(tc.args || {}),
144
+ },
145
+ })),
146
+ ...overrides,
147
+ });
148
+ }
149
+
150
+ export async function waitForCondition(
151
+ condition: () => boolean,
152
+ timeout: number = 1000,
153
+ interval: number = 10
154
+ ): Promise<void> {
155
+ const start = Date.now();
156
+ while (!condition()) {
157
+ if (Date.now() - start > timeout) {
158
+ throw new Error("Timeout waiting for condition");
159
+ }
160
+ await new Promise(resolve => setTimeout(resolve, interval));
161
+ }
162
+ }
package/src/agent.ts ADDED
@@ -0,0 +1,37 @@
1
+ import {
2
+ BaseEvent,
3
+ HttpAgent,
4
+ HttpAgentConfig,
5
+ RunAgentInput,
6
+ runHttpRequest,
7
+ transformHttpEventStream,
8
+ } from "@ag-ui/client";
9
+ import { Observable } from "rxjs";
10
+
11
+ export interface CopilotKitHttpAgentConfig
12
+ extends Omit<HttpAgentConfig, "url"> {
13
+ runtimeUrl?: string;
14
+ }
15
+
16
+ export class CopilotKitHttpAgent extends HttpAgent {
17
+ isCopilotKitAgent = true;
18
+ runtimeUrl?: string;
19
+
20
+ constructor(config: CopilotKitHttpAgentConfig) {
21
+ super({
22
+ ...config,
23
+ url: `${config.runtimeUrl}/agent/${config.agentId}/run`,
24
+ });
25
+ this.runtimeUrl = config.runtimeUrl;
26
+ }
27
+
28
+ run(input: RunAgentInput): Observable<BaseEvent> {
29
+ const url = (
30
+ input.forwardedProps.__copilotkitConnect === true
31
+ ? `${this.runtimeUrl}/agent/${this.agentId}/connect`
32
+ : this.url
33
+ ) as string;
34
+ const httpEvents = runHttpRequest(url, this.requestInit(input));
35
+ return transformHttpEventStream(httpEvents);
36
+ }
37
+ }