@copilotkit/runtime-client-gql 1.10.1-next.0 → 1.10.1-next.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/{chunk-AES3X7TL.mjs → chunk-23JYINXK.mjs} +2 -2
  3. package/dist/{chunk-AES3X7TL.mjs.map → chunk-23JYINXK.mjs.map} +1 -1
  4. package/dist/{chunk-7OSRQ2O3.mjs → chunk-SCACOKQX.mjs} +30 -6
  5. package/dist/chunk-SCACOKQX.mjs.map +1 -0
  6. package/dist/{chunk-IGXWE4TX.mjs → chunk-ZYA32QXZ.mjs} +14 -2
  7. package/dist/chunk-ZYA32QXZ.mjs.map +1 -0
  8. package/dist/client/CopilotRuntimeClient.js +1 -1
  9. package/dist/client/CopilotRuntimeClient.js.map +1 -1
  10. package/dist/client/CopilotRuntimeClient.mjs +1 -1
  11. package/dist/client/index.js +1 -1
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/client/index.mjs +1 -1
  14. package/dist/index.js +43 -7
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +3 -3
  17. package/dist/message-conversion/agui-to-gql.js +29 -5
  18. package/dist/message-conversion/agui-to-gql.js.map +1 -1
  19. package/dist/message-conversion/agui-to-gql.mjs +2 -2
  20. package/dist/message-conversion/agui-to-gql.test.js +149 -5
  21. package/dist/message-conversion/agui-to-gql.test.js.map +1 -1
  22. package/dist/message-conversion/agui-to-gql.test.mjs +122 -2
  23. package/dist/message-conversion/agui-to-gql.test.mjs.map +1 -1
  24. package/dist/message-conversion/gql-to-agui.js +13 -1
  25. package/dist/message-conversion/gql-to-agui.js.map +1 -1
  26. package/dist/message-conversion/gql-to-agui.mjs +2 -2
  27. package/dist/message-conversion/gql-to-agui.test.js +127 -1
  28. package/dist/message-conversion/gql-to-agui.test.js.map +1 -1
  29. package/dist/message-conversion/gql-to-agui.test.mjs +116 -2
  30. package/dist/message-conversion/gql-to-agui.test.mjs.map +1 -1
  31. package/dist/message-conversion/index.js +42 -6
  32. package/dist/message-conversion/index.js.map +1 -1
  33. package/dist/message-conversion/index.mjs +3 -3
  34. package/dist/message-conversion/roundtrip-conversion.test.js +119 -6
  35. package/dist/message-conversion/roundtrip-conversion.test.js.map +1 -1
  36. package/dist/message-conversion/roundtrip-conversion.test.mjs +80 -3
  37. package/dist/message-conversion/roundtrip-conversion.test.mjs.map +1 -1
  38. package/package.json +3 -3
  39. package/src/message-conversion/agui-to-gql.test.ts +140 -0
  40. package/src/message-conversion/agui-to-gql.ts +45 -7
  41. package/src/message-conversion/gql-to-agui.test.ts +139 -0
  42. package/src/message-conversion/gql-to-agui.ts +19 -1
  43. package/src/message-conversion/roundtrip-conversion.test.ts +106 -0
  44. package/dist/chunk-7OSRQ2O3.mjs.map +0 -1
  45. package/dist/chunk-IGXWE4TX.mjs.map +0 -1
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  aguiToGQL
3
- } from "../chunk-7OSRQ2O3.mjs";
3
+ } from "../chunk-SCACOKQX.mjs";
4
4
  import {
5
5
  gqlToAGUI
6
- } from "../chunk-IGXWE4TX.mjs";
6
+ } from "../chunk-ZYA32QXZ.mjs";
7
7
  import {
8
8
  describe,
9
9
  globalExpect,
@@ -11,7 +11,7 @@ import {
11
11
  vi
12
12
  } from "../chunk-2R7M2FWR.mjs";
13
13
  import "../chunk-7ECCT6PK.mjs";
14
- import "../chunk-AES3X7TL.mjs";
14
+ import "../chunk-23JYINXK.mjs";
15
15
  import "../chunk-X2UAP3QY.mjs";
16
16
  import "../chunk-HEODM5TW.mjs";
17
17
  import "../chunk-4KTMZMM2.mjs";
@@ -309,5 +309,82 @@ describe("roundtrip message conversion", () => {
309
309
  globalExpect(gqlMsgs2[1].name).toBe("unknownAction");
310
310
  globalExpect(gqlMsgs2[1].arguments).toEqual({ test: "wildcard-gql-value" });
311
311
  });
312
+ test("roundtrip conversion with result parsing edge cases", () => {
313
+ const toolResultMsg = {
314
+ id: "tool-result-json",
315
+ role: "tool",
316
+ content: '{"status": "success", "data": {"value": 42}}',
317
+ toolCallId: "tool-call-json",
318
+ toolName: "jsonAction"
319
+ };
320
+ const gqlMsgs = aguiToGQL(toolResultMsg);
321
+ const aguiMsgs = gqlToAGUI(gqlMsgs);
322
+ globalExpect(gqlMsgs).toHaveLength(1);
323
+ globalExpect(gqlMsgs[0]).toBeInstanceOf(ResultMessage);
324
+ globalExpect(gqlMsgs[0].result).toBe('{"status": "success", "data": {"value": 42}}');
325
+ globalExpect(aguiMsgs).toHaveLength(1);
326
+ globalExpect(aguiMsgs[0].role).toBe("tool");
327
+ globalExpect(aguiMsgs[0].content).toBe('{"status": "success", "data": {"value": 42}}');
328
+ });
329
+ test("roundtrip conversion with object content in tool results", () => {
330
+ const toolResultMsg = {
331
+ id: "tool-result-object",
332
+ role: "tool",
333
+ content: { status: "success", data: { value: 42 } },
334
+ toolCallId: "tool-call-object",
335
+ toolName: "objectAction"
336
+ };
337
+ const gqlMsgs = aguiToGQL(toolResultMsg);
338
+ const aguiMsgs = gqlToAGUI(gqlMsgs);
339
+ globalExpect(gqlMsgs).toHaveLength(1);
340
+ globalExpect(gqlMsgs[0]).toBeInstanceOf(ResultMessage);
341
+ globalExpect(gqlMsgs[0].result).toBe('{"status":"success","data":{"value":42}}');
342
+ globalExpect(aguiMsgs).toHaveLength(1);
343
+ globalExpect(aguiMsgs[0].role).toBe("tool");
344
+ globalExpect(aguiMsgs[0].content).toBe('{"status":"success","data":{"value":42}}');
345
+ });
346
+ test("roundtrip conversion with action execution and result parsing", () => {
347
+ const mockRender = vi.fn((props) => `Rendered: ${JSON.stringify(props.result)}`);
348
+ const actionExecMsg = new ActionExecutionMessage({
349
+ id: "action-with-result",
350
+ name: "testAction",
351
+ arguments: { input: "test-value" },
352
+ parentMessageId: "parent-result"
353
+ });
354
+ const resultMsg = new ResultMessage({
355
+ id: "result-with-json",
356
+ result: '{"output": "processed", "count": 5}',
357
+ actionExecutionId: "action-with-result",
358
+ actionName: "testAction"
359
+ });
360
+ const actions = {
361
+ testAction: {
362
+ name: "testAction",
363
+ render: mockRender
364
+ }
365
+ };
366
+ const aguiMsgs = gqlToAGUI([actionExecMsg, resultMsg], actions);
367
+ globalExpect(aguiMsgs).toHaveLength(2);
368
+ globalExpect(aguiMsgs[0].role).toBe("assistant");
369
+ globalExpect("generativeUI" in aguiMsgs[0]).toBe(true);
370
+ globalExpect(aguiMsgs[1].role).toBe("tool");
371
+ globalExpect(aguiMsgs[1].content).toBe('{"output": "processed", "count": 5}');
372
+ if ("generativeUI" in aguiMsgs[0] && aguiMsgs[0].generativeUI) {
373
+ aguiMsgs[0].generativeUI({ result: '{"parsed": true}' });
374
+ globalExpect(mockRender).toHaveBeenCalledWith(
375
+ globalExpect.objectContaining({
376
+ result: { parsed: true }
377
+ // Should be parsed from string
378
+ })
379
+ );
380
+ }
381
+ const gqlMsgs2 = aguiToGQL(aguiMsgs, actions);
382
+ globalExpect(gqlMsgs2).toHaveLength(3);
383
+ globalExpect(gqlMsgs2[0]).toBeInstanceOf(TextMessage);
384
+ globalExpect(gqlMsgs2[1]).toBeInstanceOf(ActionExecutionMessage);
385
+ globalExpect(gqlMsgs2[2]).toBeInstanceOf(ResultMessage);
386
+ globalExpect(gqlMsgs2[1].arguments).toEqual({ input: "test-value" });
387
+ globalExpect(gqlMsgs2[2].result).toBe('{"output": "processed", "count": 5}');
388
+ });
312
389
  });
313
390
  //# sourceMappingURL=roundtrip-conversion.test.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/message-conversion/roundtrip-conversion.test.ts"],"sourcesContent":["import { describe, test, expect, vi } from \"vitest\";\nimport * as gql from \"../client\";\nimport agui from \"@copilotkit/shared\";\nimport { aguiToGQL } from \"./agui-to-gql\";\nimport { gqlToAGUI } from \"./gql-to-agui\";\n\n// Helper to strip functions for deep equality\nfunction stripFunctions(obj: any): any {\n if (typeof obj === \"function\") return undefined;\n if (Array.isArray(obj)) return obj.map(stripFunctions);\n if (obj && typeof obj === \"object\") {\n const out: any = {};\n for (const k in obj) {\n if (typeof obj[k] !== \"function\") {\n out[k] = stripFunctions(obj[k]);\n }\n }\n return out;\n }\n return obj;\n}\n\ndescribe(\"roundtrip message conversion\", () => {\n test(\"text message AGUI -> GQL -> AGUI\", () => {\n const aguiMsg: agui.Message = {\n id: \"user-1\",\n role: \"user\",\n content: \"Hello!\",\n };\n const gqlMsgs = aguiToGQL(aguiMsg);\n const aguiMsgs2 = gqlToAGUI(gqlMsgs);\n expect(stripFunctions(aguiMsgs2[0])).toEqual(stripFunctions(aguiMsg));\n });\n\n test(\"text message GQL -> AGUI -> GQL\", () => {\n const gqlMsg = new gql.TextMessage({\n id: \"assistant-1\",\n content: \"Hi!\",\n role: gql.Role.Assistant,\n });\n const aguiMsgs = gqlToAGUI(gqlMsg);\n const gqlMsgs2 = aguiToGQL(aguiMsgs);\n // Should be equivalent in content, id, and role\n expect(gqlMsgs2[0].id).toBe(gqlMsg.id);\n expect((gqlMsgs2[0] as any).content).toBe(gqlMsg.content);\n expect((gqlMsgs2[0] as any).role).toBe(gqlMsg.role);\n });\n\n test(\"tool message AGUI -> GQL -> AGUI\", () => {\n const aguiMsg: agui.Message = {\n id: \"tool-1\",\n role: \"tool\",\n content: \"Tool result\",\n toolCallId: \"tool-call-1\",\n toolName: \"testAction\",\n };\n const gqlMsgs = aguiToGQL(aguiMsg);\n const aguiMsgs2 = gqlToAGUI(gqlMsgs);\n expect(stripFunctions(aguiMsgs2[0])).toEqual(stripFunctions(aguiMsg));\n });\n\n test(\"tool message GQL -> AGUI -> GQL\", () => {\n const gqlMsg = new gql.ResultMessage({\n id: \"tool-1\",\n result: \"Tool result\",\n actionExecutionId: \"tool-call-1\",\n actionName: \"testAction\",\n });\n const aguiMsgs = gqlToAGUI(gqlMsg);\n const gqlMsgs2 = aguiToGQL(aguiMsgs);\n expect(gqlMsgs2[0].id).toBe(gqlMsg.id);\n expect((gqlMsgs2[0] as any).result).toBe(gqlMsg.result);\n expect((gqlMsgs2[0] as any).actionExecutionId).toBe(gqlMsg.actionExecutionId);\n });\n\n test(\"action execution AGUI -> GQL -> AGUI\", () => {\n const aguiMsg: agui.Message = {\n id: \"assistant-1\",\n role: \"assistant\",\n content: \"Running action\",\n toolCalls: [\n {\n id: \"tool-call-1\",\n type: \"function\",\n function: {\n name: \"doSomething\",\n arguments: JSON.stringify({ foo: \"bar\" }),\n },\n },\n ],\n };\n const gqlMsgs = aguiToGQL(aguiMsg);\n const aguiMsgs2 = gqlToAGUI(gqlMsgs);\n // Should have an assistant message and an action execution message\n expect(aguiMsgs2[0].role).toBe(\"assistant\");\n expect(aguiMsgs2[1].role).toBe(\"assistant\");\n // Only check toolCalls if present\n if (\"toolCalls\" in aguiMsgs2[1]) {\n expect((aguiMsgs2[1] as any).toolCalls[0].function.name).toBe(\"doSomething\");\n }\n });\n\n test(\"action execution GQL -> AGUI -> GQL\", () => {\n const actionExecMsg = new gql.ActionExecutionMessage({\n id: \"tool-call-1\",\n name: \"doSomething\",\n arguments: { foo: \"bar\" },\n parentMessageId: \"assistant-1\",\n });\n const aguiMsgs = gqlToAGUI([actionExecMsg]);\n const gqlMsgs2 = aguiToGQL(aguiMsgs);\n // The ActionExecutionMessage is at index 1, not index 0\n expect(gqlMsgs2[1].id).toBe(\"tool-call-1\");\n // The name should be extracted from the toolCall function name\n expect((gqlMsgs2[1] as any).name).toBe(\"doSomething\");\n expect((gqlMsgs2[1] as any).arguments).toEqual({ foo: \"bar\" });\n });\n\n test(\"agent state GQL -> AGUI -> GQL\", () => {\n const agentStateMsg = new gql.AgentStateMessage({\n id: \"agent-state-1\",\n agentName: \"testAgent\",\n state: { status: \"running\" },\n role: gql.Role.Assistant,\n });\n const aguiMsgs = gqlToAGUI([agentStateMsg]);\n const gqlMsgs2 = aguiToGQL(aguiMsgs);\n expect(gqlMsgs2[0].id).toBe(\"agent-state-1\");\n // The agentName should be preserved in the roundtrip\n expect((gqlMsgs2[0] as any).agentName).toBe(\"testAgent\");\n });\n\n test(\"action execution with render function roundtrip\", () => {\n const mockRender = vi.fn();\n const aguiMsg: agui.Message = {\n id: \"assistant-1\",\n role: \"assistant\",\n content: \"Running action\",\n toolCalls: [\n {\n id: \"tool-call-1\",\n type: \"function\",\n function: {\n name: \"doSomething\",\n arguments: JSON.stringify({ foo: \"bar\" }),\n },\n },\n ],\n generativeUI: mockRender,\n };\n const actions: Record<string, any> = { doSomething: { name: \"doSomething\" } };\n const gqlMsgs = aguiToGQL(aguiMsg, actions);\n const aguiMsgs2 = gqlToAGUI(gqlMsgs, actions);\n // The render function should be preserved in actions context\n expect(typeof actions.doSomething.render).toBe(\"function\");\n // The roundtripped message should have the same tool call\n if (\"toolCalls\" in aguiMsgs2[1]) {\n expect((aguiMsgs2[1] as any).toolCalls[0].function.name).toBe(\"doSomething\");\n }\n });\n\n test(\"image message GQL -> AGUI -> GQL\", () => {\n const gqlMsg = new gql.ImageMessage({\n id: \"img-1\",\n format: \"jpeg\",\n bytes: \"somebase64string\",\n role: gql.Role.User,\n });\n const aguiMsgs = gqlToAGUI(gqlMsg);\n const gqlMsgs2 = aguiToGQL(aguiMsgs);\n expect(gqlMsgs2[0].id).toBe(gqlMsg.id);\n expect((gqlMsgs2[0] as any).format).toBe(gqlMsg.format);\n expect((gqlMsgs2[0] as any).bytes).toBe(gqlMsg.bytes);\n expect((gqlMsgs2[0] as any).role).toBe(gqlMsg.role);\n });\n\n test(\"image message AGUI -> GQL -> AGUI (assistant and user)\", () => {\n // Assistant image message\n const aguiAssistantImageMsg: agui.Message = {\n id: \"img-assistant-1\",\n role: \"assistant\",\n image: {\n format: \"jpeg\",\n bytes: \"assistantbase64data\",\n },\n content: \"\", // required for type\n };\n const gqlAssistantMsgs = aguiToGQL(aguiAssistantImageMsg);\n const aguiAssistantMsgs2 = gqlToAGUI(gqlAssistantMsgs);\n expect(aguiAssistantMsgs2[0].id).toBe(aguiAssistantImageMsg.id);\n expect(aguiAssistantMsgs2[0].role).toBe(\"assistant\");\n expect((aguiAssistantMsgs2[0] as any).image.format).toBe(\"jpeg\");\n expect((aguiAssistantMsgs2[0] as any).image.bytes).toBe(\"assistantbase64data\");\n\n // User image message\n const aguiUserImageMsg: agui.Message = {\n id: \"img-user-1\",\n role: \"user\",\n image: {\n format: \"png\",\n bytes: \"userbase64data\",\n },\n content: \"\", // required for type\n };\n const gqlUserMsgs = aguiToGQL(aguiUserImageMsg);\n const aguiUserMsgs2 = gqlToAGUI(gqlUserMsgs);\n expect(aguiUserMsgs2[0].id).toBe(aguiUserImageMsg.id);\n expect(aguiUserMsgs2[0].role).toBe(\"user\");\n expect((aguiUserMsgs2[0] as any).image.format).toBe(\"png\");\n expect((aguiUserMsgs2[0] as any).image.bytes).toBe(\"userbase64data\");\n });\n\n test(\"wild card action roundtrip conversion\", () => {\n const mockRender = vi.fn((props) => `Wildcard rendered: ${props.args.test}`);\n const aguiMsg: agui.Message = {\n id: \"assistant-wildcard-1\",\n role: \"assistant\",\n content: \"Running wild card action\",\n toolCalls: [\n {\n id: \"tool-call-wildcard-1\",\n type: \"function\",\n function: {\n name: \"unknownAction\",\n arguments: JSON.stringify({ test: \"wildcard-value\" }),\n },\n },\n ],\n generativeUI: mockRender,\n };\n\n const actions: Record<string, any> = {\n \"*\": { name: \"*\" },\n };\n\n // AGUI -> GQL -> AGUI roundtrip\n const gqlMsgs = aguiToGQL(aguiMsg, actions);\n const aguiMsgs2 = gqlToAGUI(gqlMsgs, actions);\n\n // Verify the wild card action preserved the render function\n expect(typeof actions[\"*\"].render).toBe(\"function\");\n expect(actions[\"*\"].render).toBe(mockRender);\n\n // Verify the roundtripped message structure\n expect(aguiMsgs2).toHaveLength(2);\n expect(aguiMsgs2[0].role).toBe(\"assistant\");\n expect(aguiMsgs2[1].role).toBe(\"assistant\");\n\n // Check that the tool call is preserved\n if (\"toolCalls\" in aguiMsgs2[1]) {\n expect((aguiMsgs2[1] as any).toolCalls[0].function.name).toBe(\"unknownAction\");\n expect((aguiMsgs2[1] as any).toolCalls[0].function.arguments).toBe(\n '{\"test\":\"wildcard-value\"}',\n );\n }\n });\n\n test(\"wild card action with specific action priority roundtrip\", () => {\n const mockRender = vi.fn((props) => `Specific action rendered: ${props.args.test}`);\n const aguiMsg: agui.Message = {\n id: \"assistant-priority-1\",\n role: \"assistant\",\n content: \"Running specific action\",\n toolCalls: [\n {\n id: \"tool-call-priority-1\",\n type: \"function\",\n function: {\n name: \"specificAction\",\n arguments: JSON.stringify({ test: \"specific-value\" }),\n },\n },\n ],\n generativeUI: mockRender,\n };\n\n const actions: Record<string, any> = {\n specificAction: { name: \"specificAction\" },\n \"*\": { name: \"*\" },\n };\n\n // AGUI -> GQL -> AGUI roundtrip\n const gqlMsgs = aguiToGQL(aguiMsg, actions);\n const aguiMsgs2 = gqlToAGUI(gqlMsgs, actions);\n\n // Verify the specific action preserved the render function (not wild card)\n expect(typeof actions.specificAction.render).toBe(\"function\");\n expect(actions.specificAction.render).toBe(mockRender);\n expect(actions[\"*\"].render).toBeUndefined();\n\n // Verify the roundtripped message structure\n expect(aguiMsgs2).toHaveLength(2);\n expect(aguiMsgs2[0].role).toBe(\"assistant\");\n expect(aguiMsgs2[1].role).toBe(\"assistant\");\n\n // Check that the tool call is preserved\n if (\"toolCalls\" in aguiMsgs2[1]) {\n expect((aguiMsgs2[1] as any).toolCalls[0].function.name).toBe(\"specificAction\");\n expect((aguiMsgs2[1] as any).toolCalls[0].function.arguments).toBe(\n '{\"test\":\"specific-value\"}',\n );\n }\n });\n\n test(\"wild card action GQL -> AGUI -> GQL roundtrip\", () => {\n const actionExecMsg = new gql.ActionExecutionMessage({\n id: \"wildcard-action-1\",\n name: \"unknownAction\",\n arguments: { test: \"wildcard-gql-value\" },\n parentMessageId: \"assistant-1\",\n });\n\n const actions: Record<string, any> = {\n \"*\": {\n name: \"*\",\n render: vi.fn((props) => `GQL wildcard rendered: ${props.args.test}`),\n },\n };\n\n // GQL -> AGUI -> GQL roundtrip\n const aguiMsgs = gqlToAGUI([actionExecMsg], actions);\n const gqlMsgs2 = aguiToGQL(aguiMsgs, actions);\n\n // When converting ActionExecutionMessage to AGUI and back, we get:\n // 1. A TextMessage (assistant message with toolCalls)\n // 2. An ActionExecutionMessage (the tool call itself)\n expect(gqlMsgs2).toHaveLength(2);\n expect(gqlMsgs2[0].id).toBe(\"wildcard-action-1\");\n expect((gqlMsgs2[0] as any).role).toBe(gql.Role.Assistant);\n expect(gqlMsgs2[1].id).toBe(\"wildcard-action-1\");\n expect((gqlMsgs2[1] as any).name).toBe(\"unknownAction\");\n expect((gqlMsgs2[1] as any).arguments).toEqual({ test: \"wildcard-gql-value\" });\n });\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/message-conversion/roundtrip-conversion.test.ts"],"sourcesContent":["import { describe, test, expect, vi } from \"vitest\";\nimport * as gql from \"../client\";\nimport agui from \"@copilotkit/shared\";\nimport { aguiToGQL } from \"./agui-to-gql\";\nimport { gqlToAGUI } from \"./gql-to-agui\";\n\n// Helper to strip functions for deep equality\nfunction stripFunctions(obj: any): any {\n if (typeof obj === \"function\") return undefined;\n if (Array.isArray(obj)) return obj.map(stripFunctions);\n if (obj && typeof obj === \"object\") {\n const out: any = {};\n for (const k in obj) {\n if (typeof obj[k] !== \"function\") {\n out[k] = stripFunctions(obj[k]);\n }\n }\n return out;\n }\n return obj;\n}\n\ndescribe(\"roundtrip message conversion\", () => {\n test(\"text message AGUI -> GQL -> AGUI\", () => {\n const aguiMsg: agui.Message = {\n id: \"user-1\",\n role: \"user\",\n content: \"Hello!\",\n };\n const gqlMsgs = aguiToGQL(aguiMsg);\n const aguiMsgs2 = gqlToAGUI(gqlMsgs);\n expect(stripFunctions(aguiMsgs2[0])).toEqual(stripFunctions(aguiMsg));\n });\n\n test(\"text message GQL -> AGUI -> GQL\", () => {\n const gqlMsg = new gql.TextMessage({\n id: \"assistant-1\",\n content: \"Hi!\",\n role: gql.Role.Assistant,\n });\n const aguiMsgs = gqlToAGUI(gqlMsg);\n const gqlMsgs2 = aguiToGQL(aguiMsgs);\n // Should be equivalent in content, id, and role\n expect(gqlMsgs2[0].id).toBe(gqlMsg.id);\n expect((gqlMsgs2[0] as any).content).toBe(gqlMsg.content);\n expect((gqlMsgs2[0] as any).role).toBe(gqlMsg.role);\n });\n\n test(\"tool message AGUI -> GQL -> AGUI\", () => {\n const aguiMsg: agui.Message = {\n id: \"tool-1\",\n role: \"tool\",\n content: \"Tool result\",\n toolCallId: \"tool-call-1\",\n toolName: \"testAction\",\n };\n const gqlMsgs = aguiToGQL(aguiMsg);\n const aguiMsgs2 = gqlToAGUI(gqlMsgs);\n expect(stripFunctions(aguiMsgs2[0])).toEqual(stripFunctions(aguiMsg));\n });\n\n test(\"tool message GQL -> AGUI -> GQL\", () => {\n const gqlMsg = new gql.ResultMessage({\n id: \"tool-1\",\n result: \"Tool result\",\n actionExecutionId: \"tool-call-1\",\n actionName: \"testAction\",\n });\n const aguiMsgs = gqlToAGUI(gqlMsg);\n const gqlMsgs2 = aguiToGQL(aguiMsgs);\n expect(gqlMsgs2[0].id).toBe(gqlMsg.id);\n expect((gqlMsgs2[0] as any).result).toBe(gqlMsg.result);\n expect((gqlMsgs2[0] as any).actionExecutionId).toBe(gqlMsg.actionExecutionId);\n });\n\n test(\"action execution AGUI -> GQL -> AGUI\", () => {\n const aguiMsg: agui.Message = {\n id: \"assistant-1\",\n role: \"assistant\",\n content: \"Running action\",\n toolCalls: [\n {\n id: \"tool-call-1\",\n type: \"function\",\n function: {\n name: \"doSomething\",\n arguments: JSON.stringify({ foo: \"bar\" }),\n },\n },\n ],\n };\n const gqlMsgs = aguiToGQL(aguiMsg);\n const aguiMsgs2 = gqlToAGUI(gqlMsgs);\n // Should have an assistant message and an action execution message\n expect(aguiMsgs2[0].role).toBe(\"assistant\");\n expect(aguiMsgs2[1].role).toBe(\"assistant\");\n // Only check toolCalls if present\n if (\"toolCalls\" in aguiMsgs2[1]) {\n expect((aguiMsgs2[1] as any).toolCalls[0].function.name).toBe(\"doSomething\");\n }\n });\n\n test(\"action execution GQL -> AGUI -> GQL\", () => {\n const actionExecMsg = new gql.ActionExecutionMessage({\n id: \"tool-call-1\",\n name: \"doSomething\",\n arguments: { foo: \"bar\" },\n parentMessageId: \"assistant-1\",\n });\n const aguiMsgs = gqlToAGUI([actionExecMsg]);\n const gqlMsgs2 = aguiToGQL(aguiMsgs);\n // The ActionExecutionMessage is at index 1, not index 0\n expect(gqlMsgs2[1].id).toBe(\"tool-call-1\");\n // The name should be extracted from the toolCall function name\n expect((gqlMsgs2[1] as any).name).toBe(\"doSomething\");\n expect((gqlMsgs2[1] as any).arguments).toEqual({ foo: \"bar\" });\n });\n\n test(\"agent state GQL -> AGUI -> GQL\", () => {\n const agentStateMsg = new gql.AgentStateMessage({\n id: \"agent-state-1\",\n agentName: \"testAgent\",\n state: { status: \"running\" },\n role: gql.Role.Assistant,\n });\n const aguiMsgs = gqlToAGUI([agentStateMsg]);\n const gqlMsgs2 = aguiToGQL(aguiMsgs);\n expect(gqlMsgs2[0].id).toBe(\"agent-state-1\");\n // The agentName should be preserved in the roundtrip\n expect((gqlMsgs2[0] as any).agentName).toBe(\"testAgent\");\n });\n\n test(\"action execution with render function roundtrip\", () => {\n const mockRender = vi.fn();\n const aguiMsg: agui.Message = {\n id: \"assistant-1\",\n role: \"assistant\",\n content: \"Running action\",\n toolCalls: [\n {\n id: \"tool-call-1\",\n type: \"function\",\n function: {\n name: \"doSomething\",\n arguments: JSON.stringify({ foo: \"bar\" }),\n },\n },\n ],\n generativeUI: mockRender,\n };\n const actions: Record<string, any> = { doSomething: { name: \"doSomething\" } };\n const gqlMsgs = aguiToGQL(aguiMsg, actions);\n const aguiMsgs2 = gqlToAGUI(gqlMsgs, actions);\n // The render function should be preserved in actions context\n expect(typeof actions.doSomething.render).toBe(\"function\");\n // The roundtripped message should have the same tool call\n if (\"toolCalls\" in aguiMsgs2[1]) {\n expect((aguiMsgs2[1] as any).toolCalls[0].function.name).toBe(\"doSomething\");\n }\n });\n\n test(\"image message GQL -> AGUI -> GQL\", () => {\n const gqlMsg = new gql.ImageMessage({\n id: \"img-1\",\n format: \"jpeg\",\n bytes: \"somebase64string\",\n role: gql.Role.User,\n });\n const aguiMsgs = gqlToAGUI(gqlMsg);\n const gqlMsgs2 = aguiToGQL(aguiMsgs);\n expect(gqlMsgs2[0].id).toBe(gqlMsg.id);\n expect((gqlMsgs2[0] as any).format).toBe(gqlMsg.format);\n expect((gqlMsgs2[0] as any).bytes).toBe(gqlMsg.bytes);\n expect((gqlMsgs2[0] as any).role).toBe(gqlMsg.role);\n });\n\n test(\"image message AGUI -> GQL -> AGUI (assistant and user)\", () => {\n // Assistant image message\n const aguiAssistantImageMsg: agui.Message = {\n id: \"img-assistant-1\",\n role: \"assistant\",\n image: {\n format: \"jpeg\",\n bytes: \"assistantbase64data\",\n },\n content: \"\", // required for type\n };\n const gqlAssistantMsgs = aguiToGQL(aguiAssistantImageMsg);\n const aguiAssistantMsgs2 = gqlToAGUI(gqlAssistantMsgs);\n expect(aguiAssistantMsgs2[0].id).toBe(aguiAssistantImageMsg.id);\n expect(aguiAssistantMsgs2[0].role).toBe(\"assistant\");\n expect((aguiAssistantMsgs2[0] as any).image.format).toBe(\"jpeg\");\n expect((aguiAssistantMsgs2[0] as any).image.bytes).toBe(\"assistantbase64data\");\n\n // User image message\n const aguiUserImageMsg: agui.Message = {\n id: \"img-user-1\",\n role: \"user\",\n image: {\n format: \"png\",\n bytes: \"userbase64data\",\n },\n content: \"\", // required for type\n };\n const gqlUserMsgs = aguiToGQL(aguiUserImageMsg);\n const aguiUserMsgs2 = gqlToAGUI(gqlUserMsgs);\n expect(aguiUserMsgs2[0].id).toBe(aguiUserImageMsg.id);\n expect(aguiUserMsgs2[0].role).toBe(\"user\");\n expect((aguiUserMsgs2[0] as any).image.format).toBe(\"png\");\n expect((aguiUserMsgs2[0] as any).image.bytes).toBe(\"userbase64data\");\n });\n\n test(\"wild card action roundtrip conversion\", () => {\n const mockRender = vi.fn((props) => `Wildcard rendered: ${props.args.test}`);\n const aguiMsg: agui.Message = {\n id: \"assistant-wildcard-1\",\n role: \"assistant\",\n content: \"Running wild card action\",\n toolCalls: [\n {\n id: \"tool-call-wildcard-1\",\n type: \"function\",\n function: {\n name: \"unknownAction\",\n arguments: JSON.stringify({ test: \"wildcard-value\" }),\n },\n },\n ],\n generativeUI: mockRender,\n };\n\n const actions: Record<string, any> = {\n \"*\": { name: \"*\" },\n };\n\n // AGUI -> GQL -> AGUI roundtrip\n const gqlMsgs = aguiToGQL(aguiMsg, actions);\n const aguiMsgs2 = gqlToAGUI(gqlMsgs, actions);\n\n // Verify the wild card action preserved the render function\n expect(typeof actions[\"*\"].render).toBe(\"function\");\n expect(actions[\"*\"].render).toBe(mockRender);\n\n // Verify the roundtripped message structure\n expect(aguiMsgs2).toHaveLength(2);\n expect(aguiMsgs2[0].role).toBe(\"assistant\");\n expect(aguiMsgs2[1].role).toBe(\"assistant\");\n\n // Check that the tool call is preserved\n if (\"toolCalls\" in aguiMsgs2[1]) {\n expect((aguiMsgs2[1] as any).toolCalls[0].function.name).toBe(\"unknownAction\");\n expect((aguiMsgs2[1] as any).toolCalls[0].function.arguments).toBe(\n '{\"test\":\"wildcard-value\"}',\n );\n }\n });\n\n test(\"wild card action with specific action priority roundtrip\", () => {\n const mockRender = vi.fn((props) => `Specific action rendered: ${props.args.test}`);\n const aguiMsg: agui.Message = {\n id: \"assistant-priority-1\",\n role: \"assistant\",\n content: \"Running specific action\",\n toolCalls: [\n {\n id: \"tool-call-priority-1\",\n type: \"function\",\n function: {\n name: \"specificAction\",\n arguments: JSON.stringify({ test: \"specific-value\" }),\n },\n },\n ],\n generativeUI: mockRender,\n };\n\n const actions: Record<string, any> = {\n specificAction: { name: \"specificAction\" },\n \"*\": { name: \"*\" },\n };\n\n // AGUI -> GQL -> AGUI roundtrip\n const gqlMsgs = aguiToGQL(aguiMsg, actions);\n const aguiMsgs2 = gqlToAGUI(gqlMsgs, actions);\n\n // Verify the specific action preserved the render function (not wild card)\n expect(typeof actions.specificAction.render).toBe(\"function\");\n expect(actions.specificAction.render).toBe(mockRender);\n expect(actions[\"*\"].render).toBeUndefined();\n\n // Verify the roundtripped message structure\n expect(aguiMsgs2).toHaveLength(2);\n expect(aguiMsgs2[0].role).toBe(\"assistant\");\n expect(aguiMsgs2[1].role).toBe(\"assistant\");\n\n // Check that the tool call is preserved\n if (\"toolCalls\" in aguiMsgs2[1]) {\n expect((aguiMsgs2[1] as any).toolCalls[0].function.name).toBe(\"specificAction\");\n expect((aguiMsgs2[1] as any).toolCalls[0].function.arguments).toBe(\n '{\"test\":\"specific-value\"}',\n );\n }\n });\n\n test(\"wild card action GQL -> AGUI -> GQL roundtrip\", () => {\n const actionExecMsg = new gql.ActionExecutionMessage({\n id: \"wildcard-action-1\",\n name: \"unknownAction\",\n arguments: { test: \"wildcard-gql-value\" },\n parentMessageId: \"assistant-1\",\n });\n\n const actions: Record<string, any> = {\n \"*\": {\n name: \"*\",\n render: vi.fn((props) => `GQL wildcard rendered: ${props.args.test}`),\n },\n };\n\n // GQL -> AGUI -> GQL roundtrip\n const aguiMsgs = gqlToAGUI([actionExecMsg], actions);\n const gqlMsgs2 = aguiToGQL(aguiMsgs, actions);\n\n // When converting ActionExecutionMessage to AGUI and back, we get:\n // 1. A TextMessage (assistant message with toolCalls)\n // 2. An ActionExecutionMessage (the tool call itself)\n expect(gqlMsgs2).toHaveLength(2);\n expect(gqlMsgs2[0].id).toBe(\"wildcard-action-1\");\n expect((gqlMsgs2[0] as any).role).toBe(gql.Role.Assistant);\n expect(gqlMsgs2[1].id).toBe(\"wildcard-action-1\");\n expect((gqlMsgs2[1] as any).name).toBe(\"unknownAction\");\n expect((gqlMsgs2[1] as any).arguments).toEqual({ test: \"wildcard-gql-value\" });\n });\n\n test(\"roundtrip conversion with result parsing edge cases\", () => {\n // Test with a tool result that contains a JSON string\n const toolResultMsg: agui.Message = {\n id: \"tool-result-json\",\n role: \"tool\",\n content: '{\"status\": \"success\", \"data\": {\"value\": 42}}',\n toolCallId: \"tool-call-json\",\n toolName: \"jsonAction\",\n };\n\n // Convert AGUI -> GQL -> AGUI\n const gqlMsgs = aguiToGQL(toolResultMsg);\n const aguiMsgs = gqlToAGUI(gqlMsgs);\n\n expect(gqlMsgs).toHaveLength(1);\n expect(gqlMsgs[0]).toBeInstanceOf(gql.ResultMessage);\n expect((gqlMsgs[0] as any).result).toBe('{\"status\": \"success\", \"data\": {\"value\": 42}}');\n\n expect(aguiMsgs).toHaveLength(1);\n expect(aguiMsgs[0].role).toBe(\"tool\");\n expect(aguiMsgs[0].content).toBe('{\"status\": \"success\", \"data\": {\"value\": 42}}');\n });\n\n test(\"roundtrip conversion with object content in tool results\", () => {\n // Test with a tool result that has object content (edge case)\n const toolResultMsg: agui.Message = {\n id: \"tool-result-object\",\n role: \"tool\",\n content: { status: \"success\", data: { value: 42 } } as any,\n toolCallId: \"tool-call-object\",\n toolName: \"objectAction\",\n };\n\n // Convert AGUI -> GQL -> AGUI\n const gqlMsgs = aguiToGQL(toolResultMsg);\n const aguiMsgs = gqlToAGUI(gqlMsgs);\n\n expect(gqlMsgs).toHaveLength(1);\n expect(gqlMsgs[0]).toBeInstanceOf(gql.ResultMessage);\n expect((gqlMsgs[0] as any).result).toBe('{\"status\":\"success\",\"data\":{\"value\":42}}');\n\n expect(aguiMsgs).toHaveLength(1);\n expect(aguiMsgs[0].role).toBe(\"tool\");\n expect(aguiMsgs[0].content).toBe('{\"status\":\"success\",\"data\":{\"value\":42}}');\n });\n\n test(\"roundtrip conversion with action execution and result parsing\", () => {\n const mockRender = vi.fn((props) => `Rendered: ${JSON.stringify(props.result)}`);\n\n // Create action execution message\n const actionExecMsg = new gql.ActionExecutionMessage({\n id: \"action-with-result\",\n name: \"testAction\",\n arguments: { input: \"test-value\" },\n parentMessageId: \"parent-result\",\n });\n\n // Create result message\n const resultMsg = new gql.ResultMessage({\n id: \"result-with-json\",\n result: '{\"output\": \"processed\", \"count\": 5}',\n actionExecutionId: \"action-with-result\",\n actionName: \"testAction\",\n });\n\n const actions = {\n testAction: {\n name: \"testAction\",\n render: mockRender,\n },\n };\n\n // Convert GQL -> AGUI\n const aguiMsgs = gqlToAGUI([actionExecMsg, resultMsg], actions);\n\n // The action execution should have a generativeUI function that parses string results\n expect(aguiMsgs).toHaveLength(2);\n expect(aguiMsgs[0].role).toBe(\"assistant\");\n expect(\"generativeUI\" in aguiMsgs[0]).toBe(true);\n expect(aguiMsgs[1].role).toBe(\"tool\");\n expect(aguiMsgs[1].content).toBe('{\"output\": \"processed\", \"count\": 5}');\n\n // Test that the render function receives parsed results\n if (\"generativeUI\" in aguiMsgs[0] && aguiMsgs[0].generativeUI) {\n aguiMsgs[0].generativeUI({ result: '{\"parsed\": true}' });\n expect(mockRender).toHaveBeenCalledWith(\n expect.objectContaining({\n result: { parsed: true }, // Should be parsed from string\n }),\n );\n }\n\n // Convert back AGUI -> GQL\n const gqlMsgs2 = aguiToGQL(aguiMsgs, actions);\n\n // Should have 3 messages: TextMessage, ActionExecutionMessage, ResultMessage\n expect(gqlMsgs2).toHaveLength(3);\n expect(gqlMsgs2[0]).toBeInstanceOf(gql.TextMessage);\n expect(gqlMsgs2[1]).toBeInstanceOf(gql.ActionExecutionMessage);\n expect(gqlMsgs2[2]).toBeInstanceOf(gql.ResultMessage);\n\n // Check that arguments roundtripped correctly\n expect((gqlMsgs2[1] as any).arguments).toEqual({ input: \"test-value\" });\n expect((gqlMsgs2[2] as any).result).toBe('{\"output\": \"processed\", \"count\": 5}');\n });\n});\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "publishConfig": {
10
10
  "access": "public"
11
11
  },
12
- "version": "1.10.1-next.0",
12
+ "version": "1.10.1-next.2",
13
13
  "sideEffects": false,
14
14
  "main": "./dist/index.js",
15
15
  "module": "./dist/index.mjs",
@@ -45,13 +45,13 @@
45
45
  "tsup": "^6.7.0",
46
46
  "typescript": "^5.4.5",
47
47
  "vitest": "^3.1.3",
48
- "@copilotkit/runtime": "1.10.1-next.0"
48
+ "@copilotkit/runtime": "1.10.1-next.2"
49
49
  },
50
50
  "dependencies": {
51
51
  "@urql/core": "^5.0.3",
52
52
  "untruncate-json": "^0.0.1",
53
53
  "urql": "^4.1.0",
54
- "@copilotkit/shared": "1.10.1-next.0"
54
+ "@copilotkit/shared": "1.10.1-next.2"
55
55
  },
56
56
  "keywords": [
57
57
  "copilotkit",
@@ -1062,5 +1062,145 @@ describe("agui-to-gql", () => {
1062
1062
  expect(actions.wildcard1.render).toBe(mockRender);
1063
1063
  expect(actions.wildcard2.render).toBeUndefined();
1064
1064
  });
1065
+
1066
+ test("should handle tool calls with object arguments (backward compatibility)", () => {
1067
+ const mockRender = () => "Object Args Test";
1068
+ const aguiMessage: agui.Message = {
1069
+ id: "assistant-14",
1070
+ role: "assistant",
1071
+ content: "I'll execute a function",
1072
+ toolCalls: [
1073
+ {
1074
+ id: "tool-call-16",
1075
+ type: "function",
1076
+ function: {
1077
+ name: "objectArgsAction",
1078
+ arguments: { param: "value" } as any, // Object instead of string
1079
+ },
1080
+ },
1081
+ ],
1082
+ generativeUI: mockRender,
1083
+ };
1084
+
1085
+ const actions: Record<string, any> = {
1086
+ "*": { name: "*" },
1087
+ };
1088
+
1089
+ const result = aguiToGQL(aguiMessage, actions);
1090
+
1091
+ expect(result).toHaveLength(2);
1092
+ expect(result[0]).toBeInstanceOf(gql.TextMessage);
1093
+ expect(result[1]).toBeInstanceOf(gql.ActionExecutionMessage);
1094
+ expect((result[1] as any).arguments).toEqual({ param: "value" });
1095
+ expect(actions["*"].render).toBe(mockRender);
1096
+ });
1097
+
1098
+ test("should handle tool calls with null/undefined arguments", () => {
1099
+ const mockRender = () => "Null Args Test";
1100
+ const aguiMessage: agui.Message = {
1101
+ id: "assistant-15",
1102
+ role: "assistant",
1103
+ content: "I'll execute a function",
1104
+ toolCalls: [
1105
+ {
1106
+ id: "tool-call-17",
1107
+ type: "function",
1108
+ function: {
1109
+ name: "nullArgsAction",
1110
+ arguments: null as any,
1111
+ },
1112
+ },
1113
+ ],
1114
+ generativeUI: mockRender,
1115
+ };
1116
+
1117
+ const actions: Record<string, any> = {
1118
+ "*": { name: "*" },
1119
+ };
1120
+
1121
+ const result = aguiToGQL(aguiMessage, actions);
1122
+
1123
+ expect(result).toHaveLength(2);
1124
+ expect(result[0]).toBeInstanceOf(gql.TextMessage);
1125
+ expect(result[1]).toBeInstanceOf(gql.ActionExecutionMessage);
1126
+ expect((result[1] as any).arguments).toEqual({});
1127
+ expect(actions["*"].render).toBe(mockRender);
1128
+ });
1129
+
1130
+ test("should handle tool result messages with object content", () => {
1131
+ const aguiMessage: agui.Message = {
1132
+ id: "tool-result-1",
1133
+ role: "tool",
1134
+ content: { status: "success", data: { value: 42 } } as any,
1135
+ toolCallId: "tool-call-1",
1136
+ toolName: "testAction",
1137
+ };
1138
+
1139
+ const toolCallNames = { "tool-call-1": "testAction" };
1140
+ const result = aguiToGQL(aguiMessage);
1141
+
1142
+ expect(result).toHaveLength(1);
1143
+ expect(result[0]).toBeInstanceOf(gql.ResultMessage);
1144
+ expect((result[0] as any).result).toBe('{"status":"success","data":{"value":42}}');
1145
+ expect((result[0] as any).actionExecutionId).toBe("tool-call-1");
1146
+ expect((result[0] as any).actionName).toBe("testAction");
1147
+ });
1148
+
1149
+ test("should handle tool result messages with non-string content types", () => {
1150
+ const aguiMessage: agui.Message = {
1151
+ id: "tool-result-2",
1152
+ role: "tool",
1153
+ content: 42 as any,
1154
+ toolCallId: "tool-call-2",
1155
+ toolName: "numberAction",
1156
+ };
1157
+
1158
+ const result = aguiToGQL(aguiMessage);
1159
+
1160
+ expect(result).toHaveLength(1);
1161
+ expect(result[0]).toBeInstanceOf(gql.ResultMessage);
1162
+ expect((result[0] as any).result).toBe("42");
1163
+ expect((result[0] as any).actionExecutionId).toBe("tool-call-2");
1164
+ expect((result[0] as any).actionName).toBe("numberAction");
1165
+ });
1166
+
1167
+ test("should handle tool result messages with circular reference content", () => {
1168
+ const circularObj: any = { status: "success" };
1169
+ circularObj.self = circularObj;
1170
+
1171
+ const aguiMessage: agui.Message = {
1172
+ id: "tool-result-3",
1173
+ role: "tool",
1174
+ content: circularObj as any,
1175
+ toolCallId: "tool-call-3",
1176
+ toolName: "circularAction",
1177
+ };
1178
+
1179
+ const result = aguiToGQL(aguiMessage);
1180
+
1181
+ expect(result).toHaveLength(1);
1182
+ expect(result[0]).toBeInstanceOf(gql.ResultMessage);
1183
+ expect((result[0] as any).result).toBe("[object Object]"); // Should fallback to String conversion
1184
+ expect((result[0] as any).actionExecutionId).toBe("tool-call-3");
1185
+ expect((result[0] as any).actionName).toBe("circularAction");
1186
+ });
1187
+
1188
+ test("should handle tool result messages with boolean content", () => {
1189
+ const aguiMessage: agui.Message = {
1190
+ id: "tool-result-4",
1191
+ role: "tool",
1192
+ content: true as any,
1193
+ toolCallId: "tool-call-4",
1194
+ toolName: "booleanAction",
1195
+ };
1196
+
1197
+ const result = aguiToGQL(aguiMessage);
1198
+
1199
+ expect(result).toHaveLength(1);
1200
+ expect(result[0]).toBeInstanceOf(gql.ResultMessage);
1201
+ expect((result[0] as any).result).toBe("true");
1202
+ expect((result[0] as any).actionExecutionId).toBe("tool-call-4");
1203
+ expect((result[0] as any).actionName).toBe("booleanAction");
1204
+ });
1065
1205
  });
1066
1206
  });
@@ -163,13 +163,31 @@ export function aguiToolCallToGQLActionExecution(
163
163
  throw new Error(`Unsupported tool call type: ${toolCall.type}`);
164
164
  }
165
165
 
166
- // Parse arguments with error handling
166
+ // Handle arguments - they should be a JSON string in AGUI format,
167
+ // but we need to convert them to an object for GQL format
167
168
  let argumentsObj: any;
168
- try {
169
- argumentsObj = JSON.parse(toolCall.function.arguments);
170
- } catch (error) {
171
- console.warn(`Failed to parse tool call arguments for ${toolCall.function.name}:`, error);
172
- // Provide fallback empty object to prevent application crash
169
+
170
+ if (typeof toolCall.function.arguments === "string") {
171
+ // Expected case: arguments is a JSON string
172
+ try {
173
+ argumentsObj = JSON.parse(toolCall.function.arguments);
174
+ } catch (error) {
175
+ console.warn(`Failed to parse tool call arguments for ${toolCall.function.name}:`, error);
176
+ // Provide fallback empty object to prevent application crash
177
+ argumentsObj = {};
178
+ }
179
+ } else if (
180
+ typeof toolCall.function.arguments === "object" &&
181
+ toolCall.function.arguments !== null
182
+ ) {
183
+ // Backward compatibility: arguments is already an object
184
+ argumentsObj = toolCall.function.arguments;
185
+ } else {
186
+ // Fallback for undefined, null, or other types
187
+ console.warn(
188
+ `Invalid tool call arguments type for ${toolCall.function.name}:`,
189
+ typeof toolCall.function.arguments,
190
+ );
173
191
  argumentsObj = {};
174
192
  }
175
193
 
@@ -196,9 +214,29 @@ export function aguiToolMessageToGQLResultMessage(
196
214
 
197
215
  const actionName = toolCallNames[message.toolCallId] || "unknown";
198
216
 
217
+ // Handle result content - it could be a string or an object that needs serialization
218
+ let resultContent: string;
219
+ const messageContent = message.content || "";
220
+
221
+ if (typeof messageContent === "string") {
222
+ // Expected case: content is already a string
223
+ resultContent = messageContent;
224
+ } else if (typeof messageContent === "object" && messageContent !== null) {
225
+ // Handle case where content is an object that needs to be serialized
226
+ try {
227
+ resultContent = JSON.stringify(messageContent);
228
+ } catch (error) {
229
+ console.warn(`Failed to stringify tool result for ${actionName}:`, error);
230
+ resultContent = String(messageContent);
231
+ }
232
+ } else {
233
+ // Handle other types (number, boolean, etc.)
234
+ resultContent = String(messageContent);
235
+ }
236
+
199
237
  return new gql.ResultMessage({
200
238
  id: message.id,
201
- result: message.content || "",
239
+ result: resultContent,
202
240
  actionExecutionId: message.toolCallId,
203
241
  actionName: message.toolName || actionName,
204
242
  });
@@ -8,6 +8,7 @@ import {
8
8
  gqlImageMessageToAGUIMessage,
9
9
  gqlActionExecutionMessageToAGUIMessage,
10
10
  } from "./gql-to-agui";
11
+ import { AIMessage } from "@copilotkit/shared";
11
12
 
12
13
  describe("message-conversion", () => {
13
14
  describe("gqlTextMessageToAGUIMessage", () => {
@@ -1364,5 +1365,143 @@ describe("message-conversion", () => {
1364
1365
  name: "unknownAction",
1365
1366
  });
1366
1367
  });
1368
+
1369
+ test("should parse string results in generativeUI props", () => {
1370
+ const actions = {
1371
+ "*": {
1372
+ name: "*",
1373
+ render: vi.fn((props) => `Result: ${JSON.stringify(props.result)}`),
1374
+ },
1375
+ };
1376
+
1377
+ const actionExecMsg = new gql.ActionExecutionMessage({
1378
+ id: "action-string-result",
1379
+ name: "stringResultAction",
1380
+ arguments: { test: "value" },
1381
+ parentMessageId: "parent-string",
1382
+ });
1383
+
1384
+ const actionResults = new Map<string, string>();
1385
+ actionResults.set("action-string-result", '{"parsed": true, "value": 42}');
1386
+
1387
+ const result = gqlActionExecutionMessageToAGUIMessage(actionExecMsg, actions, actionResults);
1388
+
1389
+ expect((result as AIMessage).generativeUI).toBeDefined();
1390
+ // Call the render function to test the result parsing
1391
+ const renderResult = (result as AIMessage).generativeUI!({
1392
+ result: '{"from": "props", "data": "test"}',
1393
+ });
1394
+
1395
+ // Verify the render function was called and the result was parsed
1396
+ expect(actions["*"].render).toHaveBeenCalledWith(
1397
+ expect.objectContaining({
1398
+ result: { from: "props", data: "test" }, // Should be parsed from string
1399
+ args: { test: "value" },
1400
+ status: "complete",
1401
+ messageId: "action-string-result",
1402
+ }),
1403
+ );
1404
+ });
1405
+
1406
+ test("should handle malformed JSON strings gracefully in results", () => {
1407
+ const actions = {
1408
+ "*": {
1409
+ name: "*",
1410
+ render: vi.fn((props) => `Result: ${JSON.stringify(props.result)}`),
1411
+ },
1412
+ };
1413
+
1414
+ const actionExecMsg = new gql.ActionExecutionMessage({
1415
+ id: "action-malformed",
1416
+ name: "malformedAction",
1417
+ arguments: { test: "value" },
1418
+ parentMessageId: "parent-malformed",
1419
+ });
1420
+
1421
+ const actionResults = new Map<string, string>();
1422
+ actionResults.set("action-malformed", "invalid json {");
1423
+
1424
+ const result = gqlActionExecutionMessageToAGUIMessage(actionExecMsg, actions, actionResults);
1425
+
1426
+ expect((result as AIMessage).generativeUI).toBeDefined();
1427
+ // Call the render function to test malformed JSON handling
1428
+ const renderResult = (result as AIMessage).generativeUI!({
1429
+ result: "invalid json {",
1430
+ });
1431
+
1432
+ // Verify the render function was called with the original string (unparsed)
1433
+ expect(actions["*"].render).toHaveBeenCalledWith(
1434
+ expect.objectContaining({
1435
+ result: "invalid json {", // Should remain as string due to parse error
1436
+ args: { test: "value" },
1437
+ status: "complete",
1438
+ messageId: "action-malformed",
1439
+ }),
1440
+ );
1441
+ });
1442
+
1443
+ test("should handle non-string results without parsing", () => {
1444
+ const actions = {
1445
+ "*": {
1446
+ name: "*",
1447
+ render: vi.fn((props) => `Result: ${JSON.stringify(props.result)}`),
1448
+ },
1449
+ };
1450
+
1451
+ const actionExecMsg = new gql.ActionExecutionMessage({
1452
+ id: "action-object-result",
1453
+ name: "objectResultAction",
1454
+ arguments: { test: "value" },
1455
+ parentMessageId: "parent-object",
1456
+ });
1457
+
1458
+ const actionResults = new Map<string, string>();
1459
+ actionResults.set("action-object-result", '{"already": "parsed"}');
1460
+
1461
+ const result = gqlActionExecutionMessageToAGUIMessage(actionExecMsg, actions, actionResults);
1462
+
1463
+ expect((result as AIMessage).generativeUI).toBeDefined();
1464
+ // Call the render function with an object result
1465
+ const renderResult = (result as AIMessage).generativeUI!({
1466
+ result: { from: "props", data: "object" },
1467
+ });
1468
+
1469
+ // Verify the render function was called with the object as-is
1470
+ expect(actions["*"].render).toHaveBeenCalledWith(
1471
+ expect.objectContaining({
1472
+ result: { from: "props", data: "object" }, // Should remain as object
1473
+ args: { test: "value" },
1474
+ status: "complete",
1475
+ messageId: "action-object-result",
1476
+ }),
1477
+ );
1478
+ });
1479
+
1480
+ test("should handle action execution arguments correctly with simplified conversion", () => {
1481
+ const actionExecMsg = new gql.ActionExecutionMessage({
1482
+ id: "action-simplified",
1483
+ name: "simplifiedAction",
1484
+ arguments: { complex: { nested: "value" }, array: [1, 2, 3] },
1485
+ parentMessageId: "parent-simplified",
1486
+ });
1487
+
1488
+ const result = gqlActionExecutionMessageToAGUIMessage(actionExecMsg);
1489
+
1490
+ expect(result).toMatchObject({
1491
+ id: "action-simplified",
1492
+ role: "assistant",
1493
+ toolCalls: [
1494
+ {
1495
+ id: "action-simplified",
1496
+ function: {
1497
+ name: "simplifiedAction",
1498
+ arguments: '{"complex":{"nested":"value"},"array":[1,2,3]}',
1499
+ },
1500
+ type: "function",
1501
+ },
1502
+ ],
1503
+ name: "simplifiedAction",
1504
+ });
1505
+ });
1367
1506
  });
1368
1507
  });
@@ -82,7 +82,7 @@ export function gqlActionExecutionMessageToAGUIMessage(
82
82
 
83
83
  return (props?: any) => {
84
84
  // Determine the correct status based on the same logic as RenderActionExecutionMessage
85
- const actionResult = actionResults?.get(message.id);
85
+ let actionResult: any = actionResults?.get(message.id);
86
86
  let status: "inProgress" | "executing" | "complete" = "inProgress";
87
87
 
88
88
  if (actionResult !== undefined) {
@@ -91,6 +91,24 @@ export function gqlActionExecutionMessageToAGUIMessage(
91
91
  status = "executing";
92
92
  }
93
93
 
94
+ // if props.result is a string, parse it as JSON but don't throw an error if it's not valid JSON
95
+ if (typeof props?.result === "string") {
96
+ try {
97
+ props.result = JSON.parse(props.result);
98
+ } catch (e) {
99
+ /* do nothing */
100
+ }
101
+ }
102
+
103
+ // if actionResult is a string, parse it as JSON but don't throw an error if it's not valid JSON
104
+ if (typeof actionResult === "string") {
105
+ try {
106
+ actionResult = JSON.parse(actionResult);
107
+ } catch (e) {
108
+ /* do nothing */
109
+ }
110
+ }
111
+
94
112
  // Provide the full props structure that the render function expects
95
113
  const renderProps = {
96
114
  status: props?.status || status,