@@ -4,7 +4,7 @@ import { useEffect, useReducer, useState } from "react";
44import {
55 useAgentContext ,
66 useHumanInTheLoop ,
7- useFrontendTool ,
7+ useComponent ,
88} from "@copilotkit/react-core/v2" ;
99import { z } from "zod" ;
1010import type { NewCardRequest , Transaction } from "@/app/api/v1/data" ;
@@ -319,60 +319,59 @@ export default function Page() {
319319 } ,
320320 } ) ;
321321
322- // Showcase usage of generative UI
323- useFrontendTool ( {
324- name : "showTransactions" ,
325- description :
326- "Displays a list of transactions upon request. At least one parameter is required per request" ,
327- available : PERMISSIONS . SHOW_TRANSACTIONS . includes ( currentUser . role ) ,
328- parameters : z . object ( {
329- card4Digits : z
330- . string ( )
331- . describe ( "the last 4 digits of the card" )
332- . optional ( ) ,
333- policyId : z
334- . string ( )
335- . describe ( "the id of the policy (figured out by copilot)" )
336- . optional ( ) ,
337- transactionTitle : z
338- . string ( )
339- . describe ( "the title of the transaction" )
340- . optional ( ) ,
341- } ) ,
342- handler : async ( ) => {
343- await new Promise ( ( resolve ) => setTimeout ( resolve , 3000 ) ) ;
344- } ,
345- render : ( { status, args } ) => {
346- const { card4Digits, policyId, transactionTitle } = args ;
347-
348- let filteredTransactions = transactions ;
349- if ( card4Digits ) {
350- filteredTransactions = filterTransactionsByCardLast4 (
351- transactions ,
352- cards ,
353- card4Digits ,
354- ) ;
355- } else if ( policyId ) {
356- filteredTransactions = filterTransactionsByPolicyId (
357- transactions ,
358- policyId ,
359- ) ;
360- } else if ( transactionTitle ) {
361- filteredTransactions = filterTransactionByTitle (
362- transactions ,
363- transactionTitle ,
364- ) ;
365- }
366-
367- if ( status === "inProgress" ) {
368- return "Loading..." ;
369- } else if ( ! filteredTransactions ) {
370- return "Problem fetching transactions" ;
371- } else {
322+ // Showcase usage of generative UI. Display-only components use `useComponent`
323+ // (not `useFrontendTool`): its render is unconditional, so the rendered card
324+ // persists in the transcript after the tool call completes. A handler-driven
325+ // `useFrontendTool` render only shows transiently while executing.
326+ useComponent (
327+ {
328+ name : "showTransactions" ,
329+ description :
330+ "Displays a list of transactions upon request. At least one parameter is required per request" ,
331+ parameters : z . object ( {
332+ card4Digits : z
333+ . string ( )
334+ . describe ( "the last 4 digits of the card" )
335+ . optional ( ) ,
336+ policyId : z
337+ . string ( )
338+ . describe ( "the id of the policy (figured out by copilot)" )
339+ . optional ( ) ,
340+ transactionTitle : z
341+ . string ( )
342+ . describe ( "the title of the transaction" )
343+ . optional ( ) ,
344+ } ) ,
345+ render : ( { card4Digits, policyId, transactionTitle } ) => {
346+ let filteredTransactions = transactions ;
347+ if ( card4Digits ) {
348+ filteredTransactions = filterTransactionsByCardLast4 (
349+ transactions ,
350+ cards ,
351+ card4Digits ,
352+ ) ;
353+ } else if ( policyId ) {
354+ filteredTransactions = filterTransactionsByPolicyId (
355+ transactions ,
356+ policyId ,
357+ ) ;
358+ } else if ( transactionTitle ) {
359+ filteredTransactions = filterTransactionByTitle (
360+ transactions ,
361+ transactionTitle ,
362+ ) ;
363+ }
364+
365+ if ( ! filteredTransactions ) {
366+ return < > Problem fetching transactions</ > ;
367+ }
372368 return < TransactionsList transactions = { filteredTransactions } compact /> ;
373- }
369+ } ,
374370 } ,
375- } ) ;
371+ // Re-register the renderer when the underlying data loads/changes; otherwise
372+ // the closure captures the initial empty `transactions`/`cards`.
373+ [ transactions , cards ] ,
374+ ) ;
376375
377376 // Enable pin changing with co pilot
378377 useHumanInTheLoop ( {
0 commit comments