11import { useRef , useEffect } from "react" ;
2- import { FrontendAction } from "../types/frontend-action" ;
2+ import { FrontendAction , ActionRenderProps , ActionRenderPropsWait } from "../types/frontend-action" ;
33import { useCopilotContext } from "../context/copilot-context" ;
44import { Parameter , randomId } from "@copilotkit/shared" ;
55
@@ -18,6 +18,44 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
1818) : void {
1919 const { setAction, removeAction, actions, chatComponentsCache } = useCopilotContext ( ) ;
2020 const idRef = useRef < string > ( randomId ( ) ) ;
21+ const renderAndWaitRef = useRef < RenderAndWait | null > ( null ) ;
22+
23+ // clone the action to avoid mutating the original object
24+ action = { ...action } ;
25+
26+ // If the developer provides a renderAndWait function, we transform the action
27+ // to use a promise internally, so that we can treat it like a normal action.
28+ if ( action . renderAndWait ) {
29+ const renderAndWait = action . renderAndWait ! ;
30+
31+ // remove the renderAndWait function from the action
32+ action . renderAndWait = undefined ;
33+
34+ // add a handler that will be called when the action is executed
35+ action . handler = ( async ( ) => {
36+ // we create a new promise when the handler is called
37+ let resolve : ( result : any ) => void ;
38+ let reject : ( error : any ) => void ;
39+ const promise = new Promise < any > ( ( resolvePromise , rejectPromise ) => {
40+ resolve = resolvePromise ;
41+ reject = rejectPromise ;
42+ } ) ;
43+ renderAndWaitRef . current = { promise, resolve : resolve ! , reject : reject ! } ;
44+ // then we await the promise (it will be resolved in the original renderAndWait function)
45+ return await promise ;
46+ } ) as any ;
47+
48+ // add a render function that will be called when the action is rendered
49+ action . render = ( ( props : ActionRenderProps < any > ) : React . ReactElement => {
50+ const waitProps : ActionRenderPropsWait < any > = {
51+ status : props . status as any ,
52+ args : props . args ,
53+ result : props . result ,
54+ handler : props . status === "executing" ? renderAndWaitRef . current ! . resolve : undefined ,
55+ } ;
56+ return renderAndWait ( waitProps ) ;
57+ } ) as any ;
58+ }
2159
2260 // If the developer doesn't provide dependencies, we assume they want to
2361 // update handler and render function when the action object changes.
@@ -62,6 +100,52 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
62100 ] ) ;
63101}
64102
103+ interface RenderAndWait {
104+ promise : Promise < any > ;
105+ resolve : ( result : any ) => void ;
106+ reject : ( error : any ) => void ;
107+ }
108+
109+ function transformRenderAndWaitAction < T extends Parameter [ ] | [ ] > (
110+ action : FrontendAction < T > ,
111+ ) : FrontendAction < T > {
112+ console . log ( "transformRenderAndWaitAction" , action ) ;
113+
114+ let resolvePromise : ( result : any ) => void ;
115+ const promise = new Promise < any > ( ( resolve , reject ) => {
116+ resolvePromise = function ( result : any ) {
117+ console . log ( "resolvePromise" , result ) ;
118+ resolve ( result ) ;
119+ } ;
120+ } ) ;
121+ let handler = async ( ) => {
122+ try {
123+ console . log ( "awaiting promise" ) ;
124+ const result = await promise ;
125+ console . log ( "result" , result ) ;
126+ return result ;
127+ } catch ( error ) {
128+ console . error ( "Error in handler:" , error ) ;
129+ throw error ;
130+ }
131+ } ;
132+ const render = ( props : ActionRenderProps < any > ) : React . ReactElement => {
133+ const waitProps : ActionRenderPropsWait < any > = {
134+ status : props . status as any ,
135+ args : props . args ,
136+ result : props . result ,
137+ handler : props . status === "executing" ? resolvePromise : undefined ,
138+ } ;
139+ return action . renderAndWait ! ( waitProps ) ;
140+ } ;
141+ return {
142+ ...action ,
143+ render : render as any ,
144+ handler : handler as any ,
145+ renderAndWait : undefined ,
146+ } ;
147+ }
148+
65149// Usage Example:
66150// useCopilotAction({
67151// name: "myAction",
0 commit comments