{restaurant.name}
{restaurant.rating ? ({restaurant.rating}
) : null}{restaurant.detail}
) : null} {restaurant.address ? ({restaurant.address}
) : null}"use client"; import type { ReactActivityMessageRenderer } from "@copilotkit/react-core/v2"; import { z } from "zod"; type A2UIOperation = { beginRendering?: { surfaceId?: string }; surfaceUpdate?: { components?: Array<{ id?: string; component?: { Text?: { text?: { literalString?: string }; }; }; }>; }; dataModelUpdate?: { contents?: A2UIDataEntry[]; }; }; type A2UIDataEntry = { key: string; valueString?: string; valueMap?: A2UIDataEntry[]; }; type Restaurant = { name?: string; rating?: string; detail?: string; infoLink?: string; imageUrl?: string; address?: string; }; function getOperations(content: unknown): A2UIOperation[] { if (!content || typeof content !== "object") { return []; } const payload = content as { a2ui_operations?: A2UIOperation[]; operations?: A2UIOperation[]; }; const operations = payload.a2ui_operations ?? payload.operations; if (Array.isArray(operations)) { return operations; } if (!operations || typeof operations !== "object") { return []; } if ( "beginRendering" in operations || "surfaceUpdate" in operations || "dataModelUpdate" in operations ) { return [operations as A2UIOperation]; } return Object.values(operations).filter( (operation): operation is A2UIOperation => !!operation && typeof operation === "object", ); } function getTitle(operations: A2UIOperation[]): string { for (const operation of operations) { const title = operation.surfaceUpdate?.components?.find( (component) => component.id === "title-heading", )?.component?.Text?.text?.literalString; if (title) { return title; } } return "Top Restaurants"; } function dataEntriesToObject(entries: A2UIDataEntry[] = []): Restaurant { return Object.fromEntries( entries.map((entry) => [entry.key, entry.valueString ?? ""]), ); } function getRestaurants(operations: A2UIOperation[]): Restaurant[] { const dataModel = operations.find( (operation) => operation.dataModelUpdate, )?.dataModelUpdate; const itemsEntry = dataModel?.contents?.find( (entry) => entry.key === "items", ); return (itemsEntry?.valueMap ?? []).map((entry) => dataEntriesToObject(entry.valueMap), ); } function readableInfoLink(infoLink: string | undefined): string | null { if (!infoLink) { return null; } const match = infoLink.match(/\[([^\]]+)\]\(([^)]+)\)/); return match?.[2] ?? infoLink; } function A2UIV08Surface({ content }: { content: unknown }) { const operations = getOperations(content); const restaurants = getRestaurants(operations); const title = getTitle(operations); if (!operations.length) { return (
{restaurant.rating}
) : null}{restaurant.detail}
) : null} {restaurant.address ? ({restaurant.address}
) : null}