import { type Parameter, getZodParameters } from "@copilotkit/shared"; import { parseJson } from "@copilotkit/shared"; import { defineToolCallRenderer, useCopilotKit } from "../v2"; import type React from "react"; import { useEffect, useRef } from "react"; import { type ActionRenderProps, type ActionRenderPropsNoArgs, ActionRenderPropsWait, type FrontendAction, } from "../types"; type ToolCallRendererDefinition = Parameters[0]; export type UseRenderToolCallArgs = Pick< FrontendAction, "name" | "description" | "parameters" > & { available?: "disabled" | "enabled"; render: T extends [] ? (props: ActionRenderPropsNoArgs) => React.ReactElement : (props: ActionRenderProps) => React.ReactElement; }; export function useRenderToolCall( tool: UseRenderToolCallArgs, dependencies?: any[], ) { const { copilotkit } = useCopilotKit(); // Track whether we've already added this renderer to avoid duplicates const hasAddedRef = useRef(false); useEffect(() => { const { name, parameters, render } = tool; const zodParameters = getZodParameters(parameters); const renderToolCall = name === "*" ? defineToolCallRenderer({ name: "*", render: ((args) => { return render({ ...args, result: args.result ? parseJson(args.result, args.result) : args.result, }); }) as ToolCallRendererDefinition["render"], }) : defineToolCallRenderer({ name, args: zodParameters, render: ((args) => { return render({ ...args, result: args.result ? parseJson(args.result, args.result) : args.result, }); }) as ToolCallRendererDefinition["render"], }); // Remove any existing renderer with the same name const existingIndex = copilotkit.renderToolCalls.findIndex( (r) => r.name === name, ); if (existingIndex !== -1) { copilotkit.renderToolCalls.splice(existingIndex, 1); } // Add the new renderer copilotkit.renderToolCalls.push(renderToolCall); hasAddedRef.current = true; // Cleanup: remove this renderer when the component unmounts or tool changes return () => { if (hasAddedRef.current) { const index = copilotkit.renderToolCalls.findIndex( (r) => r.name === name, ); if (index !== -1) { copilotkit.renderToolCalls.splice(index, 1); } hasAddedRef.current = false; } }; }, [tool, ...(dependencies ?? [])]); }