@copilotkit/runtime-client-gql 1.10.1-next.0 → 1.10.1-next.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.
- package/CHANGELOG.md +10 -0
- package/dist/{chunk-AES3X7TL.mjs → chunk-5V6B3OXS.mjs} +2 -2
- package/dist/{chunk-AES3X7TL.mjs.map → chunk-5V6B3OXS.mjs.map} +1 -1
- package/dist/{chunk-7OSRQ2O3.mjs → chunk-SCACOKQX.mjs} +30 -6
- package/dist/chunk-SCACOKQX.mjs.map +1 -0
- package/dist/{chunk-IGXWE4TX.mjs → chunk-ZYA32QXZ.mjs} +14 -2
- package/dist/chunk-ZYA32QXZ.mjs.map +1 -0
- package/dist/client/CopilotRuntimeClient.js +1 -1
- package/dist/client/CopilotRuntimeClient.js.map +1 -1
- package/dist/client/CopilotRuntimeClient.mjs +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +1 -1
- package/dist/index.js +43 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/message-conversion/agui-to-gql.js +29 -5
- package/dist/message-conversion/agui-to-gql.js.map +1 -1
- package/dist/message-conversion/agui-to-gql.mjs +2 -2
- package/dist/message-conversion/agui-to-gql.test.js +149 -5
- package/dist/message-conversion/agui-to-gql.test.js.map +1 -1
- package/dist/message-conversion/agui-to-gql.test.mjs +122 -2
- package/dist/message-conversion/agui-to-gql.test.mjs.map +1 -1
- package/dist/message-conversion/gql-to-agui.js +13 -1
- package/dist/message-conversion/gql-to-agui.js.map +1 -1
- package/dist/message-conversion/gql-to-agui.mjs +2 -2
- package/dist/message-conversion/gql-to-agui.test.js +127 -1
- package/dist/message-conversion/gql-to-agui.test.js.map +1 -1
- package/dist/message-conversion/gql-to-agui.test.mjs +116 -2
- package/dist/message-conversion/gql-to-agui.test.mjs.map +1 -1
- package/dist/message-conversion/index.js +42 -6
- package/dist/message-conversion/index.js.map +1 -1
- package/dist/message-conversion/index.mjs +3 -3
- package/dist/message-conversion/roundtrip-conversion.test.js +119 -6
- package/dist/message-conversion/roundtrip-conversion.test.js.map +1 -1
- package/dist/message-conversion/roundtrip-conversion.test.mjs +80 -3
- package/dist/message-conversion/roundtrip-conversion.test.mjs.map +1 -1
- package/package.json +3 -3
- package/src/message-conversion/agui-to-gql.test.ts +140 -0
- package/src/message-conversion/agui-to-gql.ts +45 -7
- package/src/message-conversion/gql-to-agui.test.ts +139 -0
- package/src/message-conversion/gql-to-agui.ts +19 -1
- package/src/message-conversion/roundtrip-conversion.test.ts +106 -0
- package/dist/chunk-7OSRQ2O3.mjs.map +0 -1
- package/dist/chunk-IGXWE4TX.mjs.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
aguiToGQL
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-SCACOKQX.mjs";
|
|
4
4
|
import {
|
|
5
5
|
gqlToAGUI
|
|
6
|
-
} from "../chunk-
|
|
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-
|
|
14
|
+
import "../chunk-5V6B3OXS.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.
|
|
12
|
+
"version": "1.10.1-next.1",
|
|
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.
|
|
48
|
+
"@copilotkit/runtime": "1.10.1-next.1"
|
|
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.
|
|
54
|
+
"@copilotkit/shared": "1.10.1-next.1"
|
|
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
|
-
//
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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:
|
|
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
|
-
|
|
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,
|