@copilotkit/react-core 1.51.3-next.8 → 1.51.3

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 (38) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/{chunk-BUSWSDYO.mjs → chunk-7JTI6ZL4.mjs} +2 -2
  3. package/dist/{chunk-GPEJNVE5.mjs → chunk-RBGVEVWY.mjs} +2 -2
  4. package/dist/{chunk-E7SE25ZU.mjs → chunk-SRJT5VVY.mjs} +2 -2
  5. package/dist/{chunk-CDUIA2WM.mjs → chunk-VGL3DGUW.mjs} +16 -13
  6. package/dist/chunk-VGL3DGUW.mjs.map +1 -0
  7. package/dist/hooks/index.js +14 -11
  8. package/dist/hooks/index.js.map +1 -1
  9. package/dist/hooks/index.mjs +4 -4
  10. package/dist/hooks/use-copilot-action.js +14 -11
  11. package/dist/hooks/use-copilot-action.js.map +1 -1
  12. package/dist/hooks/use-copilot-action.mjs +2 -2
  13. package/dist/hooks/use-copilot-authenticated-action.js +14 -11
  14. package/dist/hooks/use-copilot-authenticated-action.js.map +1 -1
  15. package/dist/hooks/use-copilot-authenticated-action.mjs +3 -3
  16. package/dist/hooks/use-default-tool.js +14 -11
  17. package/dist/hooks/use-default-tool.js.map +1 -1
  18. package/dist/hooks/use-default-tool.mjs +3 -3
  19. package/dist/hooks/use-frontend-tool.js +14 -11
  20. package/dist/hooks/use-frontend-tool.js.map +1 -1
  21. package/dist/hooks/use-frontend-tool.mjs +1 -1
  22. package/dist/index.js +14 -11
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.mjs +4 -4
  25. package/dist/index.umd.js +5 -5
  26. package/dist/index.umd.js.map +1 -1
  27. package/dist/setupTests.js +2 -0
  28. package/dist/setupTests.js.map +1 -1
  29. package/dist/setupTests.mjs +2 -0
  30. package/dist/setupTests.mjs.map +1 -1
  31. package/package.json +7 -7
  32. package/src/hooks/__tests__/use-frontend-tool-remount.e2e.test.tsx +92 -0
  33. package/src/hooks/use-frontend-tool.ts +20 -14
  34. package/src/setupTests.ts +3 -0
  35. package/dist/chunk-CDUIA2WM.mjs.map +0 -1
  36. /package/dist/{chunk-BUSWSDYO.mjs.map → chunk-7JTI6ZL4.mjs.map} +0 -0
  37. /package/dist/{chunk-GPEJNVE5.mjs.map → chunk-RBGVEVWY.mjs.map} +0 -0
  38. /package/dist/{chunk-E7SE25ZU.mjs.map → chunk-SRJT5VVY.mjs.map} +0 -0
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  // src/setupTests.ts
4
+ var import_zod = require("zod");
4
5
  jest.mock("@segment/analytics-node", () => ({
5
6
  Analytics: jest.fn().mockImplementation(() => ({
6
7
  track: jest.fn(),
@@ -19,6 +20,7 @@ jest.mock("@copilotkit/shared", () => ({
19
20
  }
20
21
  }),
21
22
  dataToUUID: jest.fn((data) => JSON.stringify(data)),
23
+ getZodParameters: jest.fn(() => import_zod.z.object({})),
22
24
  randomId: jest.fn(() => "test-random-id"),
23
25
  CopilotKitAgentDiscoveryError: jest.fn(),
24
26
  randomUUID: jest.fn(() => "mock-thread-id")
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/setupTests.ts"],"sourcesContent":["// Mock modules that cause ES module issues\njest.mock(\"@segment/analytics-node\", () => ({\n Analytics: jest.fn().mockImplementation(() => ({\n track: jest.fn(),\n identify: jest.fn(),\n page: jest.fn(),\n group: jest.fn(),\n alias: jest.fn(),\n })),\n}));\n\njest.mock(\"@copilotkit/shared\", () => ({\n parseJson: jest.fn((jsonString, defaultValue) => {\n try {\n return JSON.parse(jsonString);\n } catch {\n return defaultValue;\n }\n }),\n dataToUUID: jest.fn((data) => JSON.stringify(data)),\n randomId: jest.fn(() => \"test-random-id\"),\n CopilotKitAgentDiscoveryError: jest.fn(),\n randomUUID: jest.fn(() => \"mock-thread-id\"),\n}));\n\n// Mock react-dom/test-utils to avoid compatibility issues\njest.mock(\"react-dom/test-utils\", () => ({\n act: jest.fn((fn) => fn()),\n}));\n"],"mappings":";;;AACA,KAAK,KAAK,2BAA2B,OAAO;AAAA,EAC1C,WAAW,KAAK,GAAG,EAAE,mBAAmB,OAAO;AAAA,IAC7C,OAAO,KAAK,GAAG;AAAA,IACf,UAAU,KAAK,GAAG;AAAA,IAClB,MAAM,KAAK,GAAG;AAAA,IACd,OAAO,KAAK,GAAG;AAAA,IACf,OAAO,KAAK,GAAG;AAAA,EACjB,EAAE;AACJ,EAAE;AAEF,KAAK,KAAK,sBAAsB,OAAO;AAAA,EACrC,WAAW,KAAK,GAAG,CAAC,YAAY,iBAAiB;AAC/C,QAAI;AACF,aAAO,KAAK,MAAM,UAAU;AAAA,IAC9B,SAAQ,GAAN;AACA,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAAA,EACD,YAAY,KAAK,GAAG,CAAC,SAAS,KAAK,UAAU,IAAI,CAAC;AAAA,EAClD,UAAU,KAAK,GAAG,MAAM,gBAAgB;AAAA,EACxC,+BAA+B,KAAK,GAAG;AAAA,EACvC,YAAY,KAAK,GAAG,MAAM,gBAAgB;AAC5C,EAAE;AAGF,KAAK,KAAK,wBAAwB,OAAO;AAAA,EACvC,KAAK,KAAK,GAAG,CAAC,OAAO,GAAG,CAAC;AAC3B,EAAE;","names":[]}
1
+ {"version":3,"sources":["../src/setupTests.ts"],"sourcesContent":["import { z } from \"zod\";\n\n// Mock modules that cause ES module issues\njest.mock(\"@segment/analytics-node\", () => ({\n Analytics: jest.fn().mockImplementation(() => ({\n track: jest.fn(),\n identify: jest.fn(),\n page: jest.fn(),\n group: jest.fn(),\n alias: jest.fn(),\n })),\n}));\n\njest.mock(\"@copilotkit/shared\", () => ({\n parseJson: jest.fn((jsonString, defaultValue) => {\n try {\n return JSON.parse(jsonString);\n } catch {\n return defaultValue;\n }\n }),\n dataToUUID: jest.fn((data) => JSON.stringify(data)),\n getZodParameters: jest.fn(() => z.object({})),\n randomId: jest.fn(() => \"test-random-id\"),\n CopilotKitAgentDiscoveryError: jest.fn(),\n randomUUID: jest.fn(() => \"mock-thread-id\"),\n}));\n\n// Mock react-dom/test-utils to avoid compatibility issues\njest.mock(\"react-dom/test-utils\", () => ({\n act: jest.fn((fn) => fn()),\n}));\n"],"mappings":";;;AAAA,iBAAkB;AAGlB,KAAK,KAAK,2BAA2B,OAAO;AAAA,EAC1C,WAAW,KAAK,GAAG,EAAE,mBAAmB,OAAO;AAAA,IAC7C,OAAO,KAAK,GAAG;AAAA,IACf,UAAU,KAAK,GAAG;AAAA,IAClB,MAAM,KAAK,GAAG;AAAA,IACd,OAAO,KAAK,GAAG;AAAA,IACf,OAAO,KAAK,GAAG;AAAA,EACjB,EAAE;AACJ,EAAE;AAEF,KAAK,KAAK,sBAAsB,OAAO;AAAA,EACrC,WAAW,KAAK,GAAG,CAAC,YAAY,iBAAiB;AAC/C,QAAI;AACF,aAAO,KAAK,MAAM,UAAU;AAAA,IAC9B,SAAQ,GAAN;AACA,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAAA,EACD,YAAY,KAAK,GAAG,CAAC,SAAS,KAAK,UAAU,IAAI,CAAC;AAAA,EAClD,kBAAkB,KAAK,GAAG,MAAM,aAAE,OAAO,CAAC,CAAC,CAAC;AAAA,EAC5C,UAAU,KAAK,GAAG,MAAM,gBAAgB;AAAA,EACxC,+BAA+B,KAAK,GAAG;AAAA,EACvC,YAAY,KAAK,GAAG,MAAM,gBAAgB;AAC5C,EAAE;AAGF,KAAK,KAAK,wBAAwB,OAAO;AAAA,EACvC,KAAK,KAAK,GAAG,CAAC,OAAO,GAAG,CAAC;AAC3B,EAAE;","names":[]}
@@ -1,4 +1,5 @@
1
1
  // src/setupTests.ts
2
+ import { z } from "zod";
2
3
  jest.mock("@segment/analytics-node", () => ({
3
4
  Analytics: jest.fn().mockImplementation(() => ({
4
5
  track: jest.fn(),
@@ -17,6 +18,7 @@ jest.mock("@copilotkit/shared", () => ({
17
18
  }
18
19
  }),
19
20
  dataToUUID: jest.fn((data) => JSON.stringify(data)),
21
+ getZodParameters: jest.fn(() => z.object({})),
20
22
  randomId: jest.fn(() => "test-random-id"),
21
23
  CopilotKitAgentDiscoveryError: jest.fn(),
22
24
  randomUUID: jest.fn(() => "mock-thread-id")
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/setupTests.ts"],"sourcesContent":["// Mock modules that cause ES module issues\njest.mock(\"@segment/analytics-node\", () => ({\n Analytics: jest.fn().mockImplementation(() => ({\n track: jest.fn(),\n identify: jest.fn(),\n page: jest.fn(),\n group: jest.fn(),\n alias: jest.fn(),\n })),\n}));\n\njest.mock(\"@copilotkit/shared\", () => ({\n parseJson: jest.fn((jsonString, defaultValue) => {\n try {\n return JSON.parse(jsonString);\n } catch {\n return defaultValue;\n }\n }),\n dataToUUID: jest.fn((data) => JSON.stringify(data)),\n randomId: jest.fn(() => \"test-random-id\"),\n CopilotKitAgentDiscoveryError: jest.fn(),\n randomUUID: jest.fn(() => \"mock-thread-id\"),\n}));\n\n// Mock react-dom/test-utils to avoid compatibility issues\njest.mock(\"react-dom/test-utils\", () => ({\n act: jest.fn((fn) => fn()),\n}));\n"],"mappings":";AACA,KAAK,KAAK,2BAA2B,OAAO;AAAA,EAC1C,WAAW,KAAK,GAAG,EAAE,mBAAmB,OAAO;AAAA,IAC7C,OAAO,KAAK,GAAG;AAAA,IACf,UAAU,KAAK,GAAG;AAAA,IAClB,MAAM,KAAK,GAAG;AAAA,IACd,OAAO,KAAK,GAAG;AAAA,IACf,OAAO,KAAK,GAAG;AAAA,EACjB,EAAE;AACJ,EAAE;AAEF,KAAK,KAAK,sBAAsB,OAAO;AAAA,EACrC,WAAW,KAAK,GAAG,CAAC,YAAY,iBAAiB;AAC/C,QAAI;AACF,aAAO,KAAK,MAAM,UAAU;AAAA,IAC9B,SAAQ,GAAN;AACA,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAAA,EACD,YAAY,KAAK,GAAG,CAAC,SAAS,KAAK,UAAU,IAAI,CAAC;AAAA,EAClD,UAAU,KAAK,GAAG,MAAM,gBAAgB;AAAA,EACxC,+BAA+B,KAAK,GAAG;AAAA,EACvC,YAAY,KAAK,GAAG,MAAM,gBAAgB;AAC5C,EAAE;AAGF,KAAK,KAAK,wBAAwB,OAAO;AAAA,EACvC,KAAK,KAAK,GAAG,CAAC,OAAO,GAAG,CAAC;AAC3B,EAAE;","names":[]}
1
+ {"version":3,"sources":["../src/setupTests.ts"],"sourcesContent":["import { z } from \"zod\";\n\n// Mock modules that cause ES module issues\njest.mock(\"@segment/analytics-node\", () => ({\n Analytics: jest.fn().mockImplementation(() => ({\n track: jest.fn(),\n identify: jest.fn(),\n page: jest.fn(),\n group: jest.fn(),\n alias: jest.fn(),\n })),\n}));\n\njest.mock(\"@copilotkit/shared\", () => ({\n parseJson: jest.fn((jsonString, defaultValue) => {\n try {\n return JSON.parse(jsonString);\n } catch {\n return defaultValue;\n }\n }),\n dataToUUID: jest.fn((data) => JSON.stringify(data)),\n getZodParameters: jest.fn(() => z.object({})),\n randomId: jest.fn(() => \"test-random-id\"),\n CopilotKitAgentDiscoveryError: jest.fn(),\n randomUUID: jest.fn(() => \"mock-thread-id\"),\n}));\n\n// Mock react-dom/test-utils to avoid compatibility issues\njest.mock(\"react-dom/test-utils\", () => ({\n act: jest.fn((fn) => fn()),\n}));\n"],"mappings":";AAAA,SAAS,SAAS;AAGlB,KAAK,KAAK,2BAA2B,OAAO;AAAA,EAC1C,WAAW,KAAK,GAAG,EAAE,mBAAmB,OAAO;AAAA,IAC7C,OAAO,KAAK,GAAG;AAAA,IACf,UAAU,KAAK,GAAG;AAAA,IAClB,MAAM,KAAK,GAAG;AAAA,IACd,OAAO,KAAK,GAAG;AAAA,IACf,OAAO,KAAK,GAAG;AAAA,EACjB,EAAE;AACJ,EAAE;AAEF,KAAK,KAAK,sBAAsB,OAAO;AAAA,EACrC,WAAW,KAAK,GAAG,CAAC,YAAY,iBAAiB;AAC/C,QAAI;AACF,aAAO,KAAK,MAAM,UAAU;AAAA,IAC9B,SAAQ,GAAN;AACA,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAAA,EACD,YAAY,KAAK,GAAG,CAAC,SAAS,KAAK,UAAU,IAAI,CAAC;AAAA,EAClD,kBAAkB,KAAK,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAAA,EAC5C,UAAU,KAAK,GAAG,MAAM,gBAAgB;AAAA,EACxC,+BAA+B,KAAK,GAAG;AAAA,EACvC,YAAY,KAAK,GAAG,MAAM,gBAAgB;AAC5C,EAAE;AAGF,KAAK,KAAK,wBAAwB,OAAO;AAAA,EACvC,KAAK,KAAK,GAAG,CAAC,OAAO,GAAG,CAAC;AAC3B,EAAE;","names":[]}
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "publishConfig": {
10
10
  "access": "public"
11
11
  },
12
- "version": "1.51.3-next.8",
12
+ "version": "1.51.3",
13
13
  "sideEffects": [
14
14
  "**/*.css"
15
15
  ],
@@ -53,18 +53,18 @@
53
53
  "tsup": "^6.7.0",
54
54
  "typescript": "^5.2.3",
55
55
  "zod": ">=3.0.0",
56
- "eslint-config-custom": "1.4.6",
57
- "tsconfig": "1.4.6"
56
+ "eslint-config-custom": "1.4.7",
57
+ "tsconfig": "1.4.7"
58
58
  },
59
59
  "dependencies": {
60
60
  "@ag-ui/client": "^0.0.43",
61
61
  "@scarf/scarf": "^1.3.0",
62
62
  "react-markdown": "^8.0.7",
63
63
  "untruncate-json": "^0.0.1",
64
- "@copilotkit/runtime-client-gql": "1.51.3-next.8",
65
- "@copilotkit/shared": "1.51.3-next.8",
66
- "@copilotkitnext/core": "1.51.3-next.8",
67
- "@copilotkitnext/react": "1.51.3-next.8"
64
+ "@copilotkit/runtime-client-gql": "1.51.3",
65
+ "@copilotkit/shared": "1.51.3",
66
+ "@copilotkitnext/core": "1.51.3",
67
+ "@copilotkitnext/react": "1.51.3"
68
68
  },
69
69
  "keywords": [
70
70
  "copilotkit",
@@ -0,0 +1,92 @@
1
+ import React, { useEffect } from "react";
2
+ import { render, waitFor } from "@testing-library/react";
3
+ import { ToolCallStatus } from "@copilotkitnext/core";
4
+ import { useFrontendTool } from "../use-frontend-tool";
5
+
6
+ jest.mock("@copilotkitnext/react", () => {
7
+ let currentRender: any = null;
8
+ const listeners = new Set<() => void>();
9
+
10
+ return {
11
+ useFrontendTool: jest.fn((tool: { render?: any }) => {
12
+ React.useEffect(() => {
13
+ currentRender = tool.render ?? null;
14
+ listeners.forEach((listener) => listener());
15
+ }, [tool.render]);
16
+ }),
17
+ __getCurrentRender: () => currentRender,
18
+ __subscribeRender: (listener: () => void) => {
19
+ listeners.add(listener);
20
+ return () => listeners.delete(listener);
21
+ },
22
+ };
23
+ });
24
+
25
+ const toolRenderModule = jest.requireMock("@copilotkitnext/react") as {
26
+ __getCurrentRender: () => any;
27
+ __subscribeRender: (listener: () => void) => () => void;
28
+ };
29
+
30
+ function ToolRenderHost() {
31
+ const render = React.useSyncExternalStore(
32
+ toolRenderModule.__subscribeRender,
33
+ toolRenderModule.__getCurrentRender,
34
+ toolRenderModule.__getCurrentRender,
35
+ );
36
+
37
+ if (!render) {
38
+ return null;
39
+ }
40
+
41
+ const RenderComponent = render;
42
+ return (
43
+ <RenderComponent
44
+ name="actionOne"
45
+ args={{}}
46
+ status={ToolCallStatus.InProgress}
47
+ result={undefined}
48
+ />
49
+ );
50
+ }
51
+
52
+ function RunActionButton({ onMount, onUnmount }: { onMount: jest.Mock; onUnmount: jest.Mock }) {
53
+ useEffect(() => {
54
+ onMount();
55
+ return () => onUnmount();
56
+ }, [onMount, onUnmount]);
57
+
58
+ return <div data-testid="run-action">Run</div>;
59
+ }
60
+
61
+ describe("useFrontendTool dependency changes", () => {
62
+ it("should not remount rendered tool UI when deps change", async () => {
63
+ const mounted = jest.fn();
64
+ const unmounted = jest.fn();
65
+
66
+ const ToolUser = ({ version }: { version: number }) => {
67
+ useFrontendTool(
68
+ {
69
+ name: "actionOne",
70
+ description: "Execute action one",
71
+ render: () => <RunActionButton onMount={mounted} onUnmount={unmounted} />,
72
+ },
73
+ [version],
74
+ );
75
+
76
+ return <ToolRenderHost />;
77
+ };
78
+
79
+ const ui = render(<ToolUser version={0} />);
80
+
81
+ await waitFor(() => {
82
+ expect(mounted).toHaveBeenCalledTimes(1);
83
+ });
84
+
85
+ ui.rerender(<ToolUser version={1} />);
86
+
87
+ await waitFor(() => {
88
+ expect(unmounted).toHaveBeenCalledTimes(0);
89
+ expect(mounted).toHaveBeenCalledTimes(1);
90
+ });
91
+ });
92
+ });
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef } from "react";
1
+ import React, { useEffect, useMemo, useRef } from "react";
2
2
  import { ActionRenderProps, FrontendAction } from "../types/frontend-action";
3
3
  import { Parameter, getZodParameters, MappedParameterTypes } from "@copilotkit/shared";
4
4
  import { parseJson } from "@copilotkit/shared";
@@ -43,28 +43,34 @@ export function useFrontendTool<const T extends Parameter[] = []>(
43
43
  const { name, description, parameters, render, followUp } = tool;
44
44
  const zodParameters = getZodParameters(parameters);
45
45
 
46
- const normalizedRender: FrontendToolOptions<T>["render"] | undefined = (() => {
46
+ const renderRef = useRef<typeof render>(render);
47
+
48
+ useEffect(() => {
49
+ renderRef.current = render;
50
+ }, [render, ...(dependencies ?? [])]);
51
+
52
+ const normalizedRender: FrontendToolOptions<T>["render"] | undefined = useMemo(() => {
47
53
  if (typeof render === "undefined") {
48
54
  return undefined;
49
55
  }
50
56
 
51
- if (typeof render === "string") {
52
- const staticRender = render;
53
- return (() =>
54
- React.createElement(
55
- React.Fragment,
56
- null,
57
- staticRender,
58
- )) as FrontendToolOptions<T>["render"];
59
- }
60
-
61
57
  return ((args: FrontendToolRenderArgs<T>) => {
58
+ const currentRender = renderRef.current;
59
+
60
+ if (typeof currentRender === "undefined") {
61
+ return null;
62
+ }
63
+
64
+ if (typeof currentRender === "string") {
65
+ return React.createElement(React.Fragment, null, currentRender);
66
+ }
67
+
62
68
  const renderArgs = {
63
69
  ...args,
64
70
  result: typeof args.result === "string" ? parseJson(args.result, args.result) : args.result,
65
71
  } as ActionRenderProps<T>;
66
72
 
67
- const rendered = render(renderArgs);
73
+ const rendered = currentRender(renderArgs);
68
74
 
69
75
  if (typeof rendered === "string") {
70
76
  return React.createElement(React.Fragment, null, rendered);
@@ -72,7 +78,7 @@ export function useFrontendTool<const T extends Parameter[] = []>(
72
78
 
73
79
  return rendered ?? null;
74
80
  }) as FrontendToolOptions<T>["render"];
75
- })();
81
+ }, []);
76
82
 
77
83
  // Handler ref to avoid stale closures
78
84
  const handlerRef = useRef<typeof tool.handler>(tool.handler);
package/src/setupTests.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { z } from "zod";
2
+
1
3
  // Mock modules that cause ES module issues
2
4
  jest.mock("@segment/analytics-node", () => ({
3
5
  Analytics: jest.fn().mockImplementation(() => ({
@@ -18,6 +20,7 @@ jest.mock("@copilotkit/shared", () => ({
18
20
  }
19
21
  }),
20
22
  dataToUUID: jest.fn((data) => JSON.stringify(data)),
23
+ getZodParameters: jest.fn(() => z.object({})),
21
24
  randomId: jest.fn(() => "test-random-id"),
22
25
  CopilotKitAgentDiscoveryError: jest.fn(),
23
26
  randomUUID: jest.fn(() => "mock-thread-id"),
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/use-frontend-tool.ts"],"sourcesContent":["import React, { useEffect, useRef } from \"react\";\nimport { ActionRenderProps, FrontendAction } from \"../types/frontend-action\";\nimport { Parameter, getZodParameters, MappedParameterTypes } from \"@copilotkit/shared\";\nimport { parseJson } from \"@copilotkit/shared\";\nimport { ToolCallStatus } from \"@copilotkitnext/core\";\nimport {\n type ReactFrontendTool,\n useFrontendTool as useFrontendToolVNext,\n} from \"@copilotkitnext/react\";\n\ntype FrontendToolOptions<T extends Parameter[] | []> = ReactFrontendTool<MappedParameterTypes<T>>;\ntype FrontendToolRenderArgs<T extends Parameter[] | []> =\n | {\n name: string;\n args: Partial<MappedParameterTypes<T>>;\n status: ToolCallStatus.InProgress;\n result: undefined;\n }\n | {\n name: string;\n args: MappedParameterTypes<T>;\n status: ToolCallStatus.Executing;\n result: undefined;\n }\n | {\n name: string;\n args: MappedParameterTypes<T>;\n status: ToolCallStatus.Complete;\n result: string;\n };\n\nexport type UseFrontendToolArgs<T extends Parameter[] | [] = []> = {\n available?: \"disabled\" | \"enabled\";\n} & Pick<\n FrontendAction<T>,\n \"name\" | \"description\" | \"parameters\" | \"handler\" | \"followUp\" | \"render\"\n>;\n\nexport function useFrontendTool<const T extends Parameter[] = []>(\n tool: UseFrontendToolArgs<T>,\n dependencies?: any[],\n) {\n const { name, description, parameters, render, followUp } = tool;\n const zodParameters = getZodParameters(parameters);\n\n const normalizedRender: FrontendToolOptions<T>[\"render\"] | undefined = (() => {\n if (typeof render === \"undefined\") {\n return undefined;\n }\n\n if (typeof render === \"string\") {\n const staticRender = render;\n return (() =>\n React.createElement(\n React.Fragment,\n null,\n staticRender,\n )) as FrontendToolOptions<T>[\"render\"];\n }\n\n return ((args: FrontendToolRenderArgs<T>) => {\n const renderArgs = {\n ...args,\n result: typeof args.result === \"string\" ? parseJson(args.result, args.result) : args.result,\n } as ActionRenderProps<T>;\n\n const rendered = render(renderArgs);\n\n if (typeof rendered === \"string\") {\n return React.createElement(React.Fragment, null, rendered);\n }\n\n return rendered ?? null;\n }) as FrontendToolOptions<T>[\"render\"];\n })();\n\n // Handler ref to avoid stale closures\n const handlerRef = useRef<typeof tool.handler>(tool.handler);\n\n useEffect(() => {\n handlerRef.current = tool.handler;\n }, [tool.handler, ...(dependencies ?? [])]);\n\n const normalizedHandler = tool.handler\n ? (args: MappedParameterTypes<T>) => handlerRef.current?.(args)\n : undefined;\n\n useFrontendToolVNext<MappedParameterTypes<T>>({\n name,\n description,\n parameters: zodParameters,\n handler: normalizedHandler,\n followUp,\n render: normalizedRender,\n });\n}\n"],"mappings":";;;;;;AAAA,OAAO,SAAS,WAAW,cAAc;AAEzC,SAAoB,wBAA8C;AAClE,SAAS,iBAAiB;AAE1B;AAAA,EAEE,mBAAmB;AAAA,OACd;AA8BA,SAAS,gBACd,MACA,cACA;AACA,QAAM,EAAE,MAAM,aAAa,YAAY,QAAQ,SAAS,IAAI;AAC5D,QAAM,gBAAgB,iBAAiB,UAAU;AAEjD,QAAM,oBAAkE,MAAM;AAC5E,QAAI,OAAO,WAAW,aAAa;AACjC,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,WAAW,UAAU;AAC9B,YAAM,eAAe;AACrB,aAAQ,MACN,MAAM;AAAA,QACJ,MAAM;AAAA,QACN;AAAA,QACA;AAAA,MACF;AAAA,IACJ;AAEA,WAAQ,CAAC,SAAoC;AAC3C,YAAM,aAAa,iCACd,OADc;AAAA,QAEjB,QAAQ,OAAO,KAAK,WAAW,WAAW,UAAU,KAAK,QAAQ,KAAK,MAAM,IAAI,KAAK;AAAA,MACvF;AAEA,YAAM,WAAW,OAAO,UAAU;AAElC,UAAI,OAAO,aAAa,UAAU;AAChC,eAAO,MAAM,cAAc,MAAM,UAAU,MAAM,QAAQ;AAAA,MAC3D;AAEA,aAAO,8BAAY;AAAA,IACrB;AAAA,EACF,GAAG;AAGH,QAAM,aAAa,OAA4B,KAAK,OAAO;AAE3D,YAAU,MAAM;AACd,eAAW,UAAU,KAAK;AAAA,EAC5B,GAAG,CAAC,KAAK,SAAS,GAAI,sCAAgB,CAAC,CAAE,CAAC;AAE1C,QAAM,oBAAoB,KAAK,UAC3B,CAAC,SAA+B;AApFtC;AAoFyC,4BAAW,YAAX,oCAAqB;AAAA,MACxD;AAEJ,uBAA8C;AAAA,IAC5C;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,SAAS;AAAA,IACT;AAAA,IACA,QAAQ;AAAA,EACV,CAAC;AACH;","names":[]}