Yak Docs
Customization

UI Synchronization

When the AI assistant executes tool calls that modify data (e.g., updating an order, creating a record), you may need to refresh parts of your UI. Yak provides hooks and callbacks to react to completed tool calls.

React Hook: useYakToolEvent

Subscribe to tool call completion events from any component inside YakProvider:

import { useYakToolEvent } from "@yak-io/nextjs/client";
// or: import { useYakToolEvent } from "@yak-io/react";

function OrderPage({ orderId }: { orderId: string }) {
  const queryClient = useQueryClient();

  useYakToolEvent((event) => {
    if (event.ok && event.name.startsWith("order.")) {
      queryClient.invalidateQueries({ queryKey: ["order", orderId] });
    }
  });

  return <OrderDetails orderId={orderId} />;
}

The hook automatically unsubscribes when the component unmounts, making it safe for page-specific invalidation.

Event Object

PropertyTypeDescription
namestringThe tool name that was called (e.g., "order.cancel")
argsunknownThe arguments passed to the tool
okbooleanWhether the call succeeded
resultunknownThe result (if ok is true)
errorstringThe error message (if ok is false)

tRPC Example

Invalidate tRPC queries when related tools are called:

import { useYakToolEvent } from "@yak-io/nextjs/client";
import { trpc } from "@/utils/trpc";

function PlanPage({ planId }: { planId: string }) {
  const utils = trpc.useUtils();

  useYakToolEvent((event) => {
    if (event.ok) {
      if (event.name.startsWith("plan.")) {
        utils.plan.get.invalidate({ id: planId });
      }
      if (event.name.startsWith("planItem.")) {
        utils.planItem.list.invalidate({ planId });
      }
    }
  });

  return <PlanDetails planId={planId} />;
}

JavaScript SDK: onToolCallComplete

For non-React integrations, use the onToolCallComplete callback on YakClient:

import { YakClient } from "@yak-io/javascript";

const client = new YakClient({
  appId: "your-app-id",
  onToolCall: async (name, args) => {
    return executeToolCall(name, args);
  },
  onToolCallComplete: (event) => {
    if (event.ok && event.name.startsWith("order.")) {
      // Refresh your data
      queryClient.invalidateQueries({ queryKey: ["orders"] });
    }
  },
});

Each page or component can subscribe to its own relevant events independently. This keeps synchronization logic co-located with the UI that needs refreshing.

On this page