@copilotkit/runtime 1.9.2-next.9 → 1.9.3-next.0

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 (60) hide show
  1. package/CHANGELOG.md +176 -0
  2. package/dist/{chunk-Z5GYTKMD.mjs → chunk-EK5RTZVJ.mjs} +225 -149
  3. package/dist/chunk-EK5RTZVJ.mjs.map +1 -0
  4. package/dist/{chunk-SMDVD4VG.mjs → chunk-KCYFFRJY.mjs} +2 -2
  5. package/dist/{chunk-4JBKY7XT.mjs → chunk-QLLV2QVK.mjs} +48 -28
  6. package/dist/chunk-QLLV2QVK.mjs.map +1 -0
  7. package/dist/{chunk-5YGKE5SN.mjs → chunk-R5D7D7YN.mjs} +2 -2
  8. package/dist/{chunk-UUXRYAB4.mjs → chunk-RCCT2GOF.mjs} +2 -2
  9. package/dist/{chunk-ALZ5H3VD.mjs → chunk-YGS5B7PN.mjs} +2 -2
  10. package/dist/{groq-adapter-172a2ca4.d.ts → groq-adapter-742818f2.d.ts} +5 -1
  11. package/dist/index.d.ts +3 -3
  12. package/dist/index.js +267 -171
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +9 -9
  15. package/dist/{langserve-fc5cac89.d.ts → langserve-3e8d0e06.d.ts} +6 -0
  16. package/dist/lib/index.d.ts +155 -5
  17. package/dist/lib/index.js +221 -168
  18. package/dist/lib/index.js.map +1 -1
  19. package/dist/lib/index.mjs +9 -9
  20. package/dist/lib/integrations/index.d.ts +3 -3
  21. package/dist/lib/integrations/index.js +11 -11
  22. package/dist/lib/integrations/index.js.map +1 -1
  23. package/dist/lib/integrations/index.mjs +8 -8
  24. package/dist/lib/integrations/nest/index.d.ts +2 -2
  25. package/dist/lib/integrations/nest/index.js +11 -11
  26. package/dist/lib/integrations/nest/index.js.map +1 -1
  27. package/dist/lib/integrations/nest/index.mjs +4 -4
  28. package/dist/lib/integrations/node-express/index.d.ts +2 -2
  29. package/dist/lib/integrations/node-express/index.js +11 -11
  30. package/dist/lib/integrations/node-express/index.js.map +1 -1
  31. package/dist/lib/integrations/node-express/index.mjs +4 -4
  32. package/dist/lib/integrations/node-http/index.d.ts +2 -2
  33. package/dist/lib/integrations/node-http/index.js +11 -11
  34. package/dist/lib/integrations/node-http/index.js.map +1 -1
  35. package/dist/lib/integrations/node-http/index.mjs +3 -3
  36. package/dist/service-adapters/index.d.ts +5 -4
  37. package/dist/service-adapters/index.js +47 -27
  38. package/dist/service-adapters/index.js.map +1 -1
  39. package/dist/service-adapters/index.mjs +1 -1
  40. package/dist/{shared-bd953ebf.d.ts → shared-96b46379.d.ts} +16 -18
  41. package/package.json +11 -11
  42. package/src/graphql/resolvers/copilot.resolver.ts +1 -2
  43. package/src/lib/runtime/__tests__/{copilot-runtime-trace.test.ts → copilot-runtime-error.test.ts} +27 -27
  44. package/src/lib/runtime/__tests__/mcp-tools-utils.test.ts +464 -0
  45. package/src/lib/runtime/agui-action.ts +9 -3
  46. package/src/lib/runtime/copilot-runtime.ts +112 -124
  47. package/src/lib/runtime/mcp-tools-utils.ts +84 -18
  48. package/src/lib/runtime/remote-actions.ts +6 -0
  49. package/src/service-adapters/anthropic/anthropic-adapter.ts +64 -4
  50. package/src/service-adapters/anthropic/utils.ts +3 -8
  51. package/src/service-adapters/events.ts +40 -1
  52. package/src/service-adapters/google/google-genai-adapter.ts +5 -0
  53. package/src/service-adapters/openai/openai-adapter.ts +0 -14
  54. package/tests/service-adapters/anthropic/anthropic-adapter.test.ts +172 -387
  55. package/dist/chunk-4JBKY7XT.mjs.map +0 -1
  56. package/dist/chunk-Z5GYTKMD.mjs.map +0 -1
  57. /package/dist/{chunk-SMDVD4VG.mjs.map → chunk-KCYFFRJY.mjs.map} +0 -0
  58. /package/dist/{chunk-5YGKE5SN.mjs.map → chunk-R5D7D7YN.mjs.map} +0 -0
  59. /package/dist/{chunk-UUXRYAB4.mjs.map → chunk-RCCT2GOF.mjs.map} +0 -0
  60. /package/dist/{chunk-ALZ5H3VD.mjs.map → chunk-YGS5B7PN.mjs.map} +0 -0
@@ -0,0 +1,464 @@
1
+ import {
2
+ extractParametersFromSchema,
3
+ convertMCPToolsToActions,
4
+ generateMcpToolInstructions,
5
+ MCPTool,
6
+ } from "../mcp-tools-utils";
7
+
8
+ describe("MCP Tools Utils", () => {
9
+ describe("extractParametersFromSchema", () => {
10
+ it("should extract parameters from schema.parameters.properties", () => {
11
+ const tool: MCPTool = {
12
+ description: "Test tool",
13
+ schema: {
14
+ parameters: {
15
+ properties: {
16
+ name: { type: "string", description: "A name parameter" },
17
+ age: { type: "number", description: "An age parameter" },
18
+ },
19
+ required: ["name"],
20
+ },
21
+ },
22
+ execute: async () => ({}),
23
+ };
24
+
25
+ const result = extractParametersFromSchema(tool);
26
+ expect(result).toHaveLength(2);
27
+ expect(result[0]).toEqual({
28
+ name: "name",
29
+ type: "string",
30
+ description: "A name parameter",
31
+ required: true,
32
+ });
33
+ expect(result[1]).toEqual({
34
+ name: "age",
35
+ type: "number",
36
+ description: "An age parameter",
37
+ required: false,
38
+ });
39
+ });
40
+
41
+ it("should extract parameters from schema.parameters.jsonSchema", () => {
42
+ const tool: MCPTool = {
43
+ description: "Test tool with jsonSchema",
44
+ schema: {
45
+ parameters: {
46
+ jsonSchema: {
47
+ properties: {
48
+ title: { type: "string", description: "A title parameter" },
49
+ count: { type: "number", description: "A count parameter" },
50
+ },
51
+ required: ["title"],
52
+ },
53
+ },
54
+ },
55
+ execute: async () => ({}),
56
+ };
57
+
58
+ const result = extractParametersFromSchema(tool);
59
+ expect(result).toHaveLength(2);
60
+ expect(result[0]).toEqual({
61
+ name: "title",
62
+ type: "string",
63
+ description: "A title parameter",
64
+ required: true,
65
+ });
66
+ expect(result[1]).toEqual({
67
+ name: "count",
68
+ type: "number",
69
+ description: "A count parameter",
70
+ required: false,
71
+ });
72
+ });
73
+
74
+ it("should handle arrays with items", () => {
75
+ const tool: MCPTool = {
76
+ description: "Test tool with array parameters",
77
+ schema: {
78
+ parameters: {
79
+ properties: {
80
+ simpleArray: {
81
+ type: "array",
82
+ items: { type: "string" },
83
+ description: "Array of strings",
84
+ },
85
+ objectArray: {
86
+ type: "array",
87
+ items: {
88
+ type: "object",
89
+ properties: {
90
+ name: { type: "string" },
91
+ value: { type: "number" },
92
+ },
93
+ },
94
+ description: "Array of objects",
95
+ },
96
+ },
97
+ required: ["simpleArray"],
98
+ },
99
+ },
100
+ execute: async () => ({}),
101
+ };
102
+
103
+ const result = extractParametersFromSchema(tool);
104
+ expect(result).toHaveLength(2);
105
+ expect(result[0]).toEqual({
106
+ name: "simpleArray",
107
+ type: "array<string>",
108
+ description: "Array of strings",
109
+ required: true,
110
+ });
111
+ expect(result[1]).toEqual({
112
+ name: "objectArray",
113
+ type: "array",
114
+ description: "Array of objects Array of objects with properties: name, value",
115
+ required: false,
116
+ });
117
+ });
118
+
119
+ it("should handle enums", () => {
120
+ const tool: MCPTool = {
121
+ description: "Test tool with enum parameters",
122
+ schema: {
123
+ parameters: {
124
+ properties: {
125
+ status: {
126
+ type: "string",
127
+ enum: ["active", "inactive", "pending"],
128
+ description: "Status value",
129
+ },
130
+ priority: {
131
+ type: "number",
132
+ enum: [1, 2, 3],
133
+ description: "Priority level",
134
+ },
135
+ },
136
+ required: ["status"],
137
+ },
138
+ },
139
+ execute: async () => ({}),
140
+ };
141
+
142
+ const result = extractParametersFromSchema(tool);
143
+ expect(result).toHaveLength(2);
144
+ expect(result[0]).toEqual({
145
+ name: "status",
146
+ type: "string",
147
+ description: "Status value Allowed values: active | inactive | pending",
148
+ required: true,
149
+ });
150
+ expect(result[1]).toEqual({
151
+ name: "priority",
152
+ type: "number",
153
+ description: "Priority level Allowed values: 1 | 2 | 3",
154
+ required: false,
155
+ });
156
+ });
157
+
158
+ it("should handle nested objects", () => {
159
+ const tool: MCPTool = {
160
+ description: "Test tool with nested object parameters",
161
+ schema: {
162
+ parameters: {
163
+ properties: {
164
+ user: {
165
+ type: "object",
166
+ properties: {
167
+ name: { type: "string" },
168
+ email: { type: "string" },
169
+ preferences: {
170
+ type: "object",
171
+ properties: {
172
+ theme: { type: "string" },
173
+ notifications: { type: "boolean" },
174
+ },
175
+ },
176
+ },
177
+ description: "User object",
178
+ },
179
+ },
180
+ required: ["user"],
181
+ },
182
+ },
183
+ execute: async () => ({}),
184
+ };
185
+
186
+ const result = extractParametersFromSchema(tool);
187
+ expect(result).toHaveLength(1);
188
+ expect(result[0]).toEqual({
189
+ name: "user",
190
+ type: "object",
191
+ description: "User object Object with properties: name, email, preferences",
192
+ required: true,
193
+ });
194
+ });
195
+
196
+ it("should return empty array when no properties", () => {
197
+ const tool: MCPTool = {
198
+ description: "Test tool without properties",
199
+ schema: {
200
+ parameters: {},
201
+ },
202
+ execute: async () => ({}),
203
+ };
204
+
205
+ const result = extractParametersFromSchema(tool);
206
+ expect(result).toHaveLength(0);
207
+ });
208
+ });
209
+
210
+ describe("generateMcpToolInstructions", () => {
211
+ it("should generate instructions with correct parameter schema from schema.parameters.properties", () => {
212
+ const toolsMap: Record<string, MCPTool> = {
213
+ testTool: {
214
+ description: "A test tool",
215
+ schema: {
216
+ parameters: {
217
+ properties: {
218
+ name: { type: "string", description: "The name parameter" },
219
+ age: { type: "number", description: "The age parameter" },
220
+ },
221
+ required: ["name"],
222
+ },
223
+ },
224
+ execute: async () => ({}),
225
+ },
226
+ };
227
+
228
+ const result = generateMcpToolInstructions(toolsMap);
229
+ expect(result).toContain("testTool: A test tool");
230
+ expect(result).toContain("- name* (string) - The name parameter");
231
+ expect(result).toContain("- age (number) - The age parameter");
232
+ });
233
+
234
+ it("should generate instructions with correct parameter schema from schema.parameters.jsonSchema", () => {
235
+ const toolsMap: Record<string, MCPTool> = {
236
+ testTool: {
237
+ description: "A test tool with jsonSchema",
238
+ schema: {
239
+ parameters: {
240
+ jsonSchema: {
241
+ properties: {
242
+ title: { type: "string", description: "The title parameter" },
243
+ count: { type: "number", description: "The count parameter" },
244
+ },
245
+ required: ["title"],
246
+ },
247
+ },
248
+ },
249
+ execute: async () => ({}),
250
+ },
251
+ };
252
+
253
+ const result = generateMcpToolInstructions(toolsMap);
254
+ expect(result).toContain("testTool: A test tool with jsonSchema");
255
+ expect(result).toContain("- title* (string) - The title parameter");
256
+ expect(result).toContain("- count (number) - The count parameter");
257
+ });
258
+
259
+ it("should handle complex schemas with arrays and enums", () => {
260
+ const toolsMap: Record<string, MCPTool> = {
261
+ complexTool: {
262
+ description: "A complex tool",
263
+ schema: {
264
+ parameters: {
265
+ properties: {
266
+ items: {
267
+ type: "array",
268
+ items: {
269
+ type: "object",
270
+ properties: {
271
+ name: { type: "string" },
272
+ value: { type: "number" },
273
+ },
274
+ },
275
+ description: "Array of items",
276
+ },
277
+ status: {
278
+ type: "string",
279
+ enum: ["active", "inactive"],
280
+ description: "Status",
281
+ },
282
+ },
283
+ required: ["items"],
284
+ },
285
+ },
286
+ execute: async () => ({}),
287
+ },
288
+ };
289
+
290
+ const result = generateMcpToolInstructions(toolsMap);
291
+ expect(result).toContain("complexTool: A complex tool");
292
+ expect(result).toContain(
293
+ "- items* (array<object>) - Array of items Array of objects with properties: name, value",
294
+ );
295
+ expect(result).toContain("- status (string) - Status Allowed values: active | inactive");
296
+ });
297
+
298
+ it("should fallback to schema.properties for backward compatibility", () => {
299
+ const toolsMap: Record<string, MCPTool> = {
300
+ backwardCompatTool: {
301
+ description: "A backward compatible tool",
302
+ schema: {
303
+ // Direct properties without nested parameters
304
+ properties: {
305
+ name: { type: "string", description: "The name parameter" },
306
+ },
307
+ required: ["name"],
308
+ } as any,
309
+ execute: async () => ({}),
310
+ },
311
+ };
312
+
313
+ const result = generateMcpToolInstructions(toolsMap);
314
+ expect(result).toContain("backwardCompatTool: A backward compatible tool");
315
+ expect(result).toContain("- name* (string) - The name parameter");
316
+ });
317
+
318
+ it("should show 'No parameters required' when no schema properties", () => {
319
+ const toolsMap: Record<string, MCPTool> = {
320
+ noParamsTool: {
321
+ description: "A tool with no parameters",
322
+ schema: {
323
+ parameters: {},
324
+ },
325
+ execute: async () => ({}),
326
+ },
327
+ };
328
+
329
+ const result = generateMcpToolInstructions(toolsMap);
330
+ expect(result).toContain("noParamsTool: A tool with no parameters");
331
+ expect(result).toContain("No parameters required");
332
+ });
333
+
334
+ it("should handle tools with no schema", () => {
335
+ const toolsMap: Record<string, MCPTool> = {
336
+ noSchemaTool: {
337
+ description: "A tool with no schema",
338
+ execute: async () => ({}),
339
+ },
340
+ };
341
+
342
+ const result = generateMcpToolInstructions(toolsMap);
343
+ expect(result).toContain("noSchemaTool: A tool with no schema");
344
+ expect(result).toContain("No parameters required");
345
+ });
346
+
347
+ it("should return empty string for empty tools map", () => {
348
+ const result = generateMcpToolInstructions({});
349
+ expect(result).toBe("");
350
+ });
351
+ });
352
+
353
+ describe("convertMCPToolsToActions", () => {
354
+ it("should convert MCP tools to CopilotKit actions", () => {
355
+ const mcpTools: Record<string, MCPTool> = {
356
+ testTool: {
357
+ description: "A test tool",
358
+ schema: {
359
+ parameters: {
360
+ properties: {
361
+ name: { type: "string", description: "The name parameter" },
362
+ age: { type: "number", description: "The age parameter" },
363
+ },
364
+ required: ["name"],
365
+ },
366
+ },
367
+ execute: async () => "test result",
368
+ },
369
+ };
370
+
371
+ const result = convertMCPToolsToActions(mcpTools, "http://test-endpoint");
372
+ expect(result).toHaveLength(1);
373
+ expect(result[0].name).toBe("testTool");
374
+ expect(result[0].description).toBe("A test tool");
375
+ expect(result[0].parameters).toHaveLength(2);
376
+ expect(result[0].parameters[0]).toEqual({
377
+ name: "name",
378
+ type: "string",
379
+ description: "The name parameter",
380
+ required: true,
381
+ });
382
+ expect(result[0].parameters[1]).toEqual({
383
+ name: "age",
384
+ type: "number",
385
+ description: "The age parameter",
386
+ required: false,
387
+ });
388
+ });
389
+
390
+ it("should handle tool execution correctly", async () => {
391
+ const mockExecute = jest.fn().mockResolvedValue("mock result");
392
+ const mcpTools: Record<string, MCPTool> = {
393
+ testTool: {
394
+ description: "A test tool",
395
+ schema: {
396
+ parameters: {
397
+ properties: {
398
+ name: { type: "string", description: "The name parameter" },
399
+ },
400
+ required: ["name"],
401
+ },
402
+ },
403
+ execute: mockExecute,
404
+ },
405
+ };
406
+
407
+ const result = convertMCPToolsToActions(mcpTools, "http://test-endpoint");
408
+ const action = result[0];
409
+
410
+ const executeResult = await action.handler({ name: "test" });
411
+ expect(executeResult).toBe("mock result");
412
+ expect(mockExecute).toHaveBeenCalledWith({ name: "test" });
413
+ });
414
+
415
+ it("should stringify non-string results", async () => {
416
+ const mcpTools: Record<string, MCPTool> = {
417
+ testTool: {
418
+ description: "A test tool",
419
+ schema: {
420
+ parameters: {
421
+ properties: {
422
+ name: { type: "string", description: "The name parameter" },
423
+ },
424
+ required: ["name"],
425
+ },
426
+ },
427
+ execute: async () => ({ result: "complex object" }),
428
+ },
429
+ };
430
+
431
+ const result = convertMCPToolsToActions(mcpTools, "http://test-endpoint");
432
+ const action = result[0];
433
+
434
+ const executeResult = await action.handler({ name: "test" });
435
+ expect(executeResult).toBe('{"result":"complex object"}');
436
+ });
437
+
438
+ it("should handle execution errors", async () => {
439
+ const mcpTools: Record<string, MCPTool> = {
440
+ testTool: {
441
+ description: "A test tool",
442
+ schema: {
443
+ parameters: {
444
+ properties: {
445
+ name: { type: "string", description: "The name parameter" },
446
+ },
447
+ required: ["name"],
448
+ },
449
+ },
450
+ execute: async () => {
451
+ throw new Error("Test error");
452
+ },
453
+ },
454
+ };
455
+
456
+ const result = convertMCPToolsToActions(mcpTools, "http://test-endpoint");
457
+ const action = result[0];
458
+
459
+ await expect(action.handler({ name: "test" })).rejects.toThrow(
460
+ "Execution failed for MCP tool 'testTool': Test error",
461
+ );
462
+ });
463
+ });
464
+ });
@@ -22,12 +22,16 @@ export function constructAGUIRemoteAction({
22
22
  agentStates,
23
23
  agent,
24
24
  metaEvents,
25
+ threadMetadata,
26
+ nodeName,
25
27
  }: {
26
28
  logger: Logger;
27
29
  messages: Message[];
28
30
  agentStates?: AgentStateInput[];
29
31
  agent: AbstractAgent;
30
32
  metaEvents?: MetaEventInput[];
33
+ threadMetadata?: Record<string, any>;
34
+ nodeName?: string;
31
35
  }) {
32
36
  const action = {
33
37
  name: agent.agentId,
@@ -67,9 +71,11 @@ export function constructAGUIRemoteAction({
67
71
  };
68
72
  });
69
73
 
70
- const forwardedProps = metaEvents.length
71
- ? { command: { resume: metaEvents[0]?.response } }
72
- : undefined;
74
+ const forwardedProps = {
75
+ ...(metaEvents?.length ? { command: { resume: metaEvents[0]?.response } } : {}),
76
+ ...(threadMetadata ? { threadMetadata } : {}),
77
+ ...(nodeName ? { nodeName } : {}),
78
+ };
73
79
 
74
80
  return agent.legacy_to_be_removed_runAgentBridged({
75
81
  tools,