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
| Property | Type | Description |
|---|---|---|
name | string | The tool name that was called (e.g., "order.cancel") |
args | unknown | The arguments passed to the tool |
ok | boolean | Whether the call succeeded |
result | unknown | The result (if ok is true) |
error | string | The 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.