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.
@@ -34,9 +72,6 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
3472 }
3573
3674 useEffect ( ( ) => {
37- if ( action . disabled ) {
38- return ;
39- }
4075 setAction ( idRef . current , action as any ) ;
4176 if ( chatComponentsCache . current !== null && action . render !== undefined ) {
4277 chatComponentsCache . current . actions [ action . name ] = action . render ;
@@ -62,6 +97,12 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
6297 ] ) ;
6398}
6499
100+ interface RenderAndWait {
101+ promise : Promise < any > ;
102+ resolve : ( result : any ) => void ;
103+ reject : ( error : any ) => void ;
104+ }
105+
65106// Usage Example:
66107// useCopilotAction({
67108// name: "myAction",
0 commit comments