{"version":3,"sources":["../src/hooks/use-chat.ts"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport {\n  FunctionCallHandler,\n  AI_CLOUD_PUBLIC_API_KEY_HEADER,\n  CoAgentStateRenderHandler,\n  randomId,\n  parseJson,\n  AiSDKError,\n  AiSDKErrorCode,\n} from \"@vn-sdk/shared\";\nimport {\n  Message,\n  TextMessage,\n  ResultMessage,\n  convertMessagesToGqlInput,\n  filterAdjacentAgentStateMessages,\n  filterAgentStateMessages,\n  convertGqlOutputToMessages,\n  MessageStatusCode,\n  MessageRole,\n  Role,\n  AiRequestType,\n  ForwardedParametersInput,\n  loadMessagesFromJsonRepresentation,\n  ExtensionsInput,\n  AiRuntimeClient,\n  langGraphInterruptEvent,\n  MetaEvent,\n  MetaEventName,\n  ActionExecutionMessage,\n  VnSdkLangGraphInterruptEvent,\n  LangGraphInterruptEvent,\n  MetaEventInput,\n  AgentStateInput,\n} from \"@vn-sdk/runtime-client-gql\";\n\nimport { AiApiConfig } from \"../context\";\nimport { FrontendAction, processActionsForRuntimeRequest } from \"../types/frontend-action\";\nimport { AiAgentState } from \"../types/ai-agent-state\";\nimport { AgentSession, useAiContext } from \"../context/ai-context\";\nimport { useAiRuntimeClient } from \"./use-ai-runtime-client\";\nimport { useAsyncCallback, useErrorToast } from \"../components/error-boundary/error-utils\";\nimport { useToast } from \"../components/toast/toast-provider\";\nimport {\n  LangGraphInterruptAction,\n  LangGraphInterruptActionSetter,\n} from \"../types/interrupt-action\";\n\nexport type UseChatOptions = {\n  /**\n   * System messages of the chat. Defaults to an empty array.\n   */\n  initialMessages?: Message[];\n  /**\n   * Callback function to be called when a function call is received.\n   * If the function returns a `ChatRequest` object, the request will be sent\n   * automatically to the API and will be used to update the chat.\n   */\n  onFunctionCall?: FunctionCallHandler;\n\n  /**\n   * Callback function to be called when a coagent action is received.\n   */\n  onAiAgentStateRender?: CoAgentStateRenderHandler;\n\n  /**\n   * Function definitions to be sent to the API.\n   */\n  actions: FrontendAction<any>[];\n\n  /**\n   * The VN SDK API configuration.\n   */\n  aiConfig: AiApiConfig;\n\n  /**\n   * The current list of messages in the chat.\n   */\n  messages: Message[];\n  /**\n   * The setState-powered method to update the chat messages.\n   */\n  setMessages: React.Dispatch<React.SetStateAction<Message[]>>;\n\n  /**\n   * A callback to get the latest system message.\n   */\n  makeSystemMessageCallback: () => TextMessage;\n\n  /**\n   * Whether the API request is in progress\n   */\n  isLoading: boolean;\n\n  /**\n   * setState-powered method to update the isChatLoading value\n   */\n  setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;\n\n  /**\n   * The current list of coagent states.\n   */\n  aiAgentStatesRef: React.RefObject<Record<string, AiAgentState>>;\n\n  /**\n   * setState-powered method to update the agent states\n   */\n  setAiAgentStatesWithRef: React.Dispatch<React.SetStateAction<Record<string, AiAgentState>>>;\n\n  /**\n   * The current agent session.\n   */\n  agentSession: AgentSession | null;\n\n  /**\n   * setState-powered method to update the agent session\n   */\n  setAgentSession: React.Dispatch<React.SetStateAction<AgentSession | null>>;\n\n  /**\n   * The forwarded parameters.\n   */\n  forwardedParameters?: Pick<ForwardedParametersInput, \"temperature\">;\n\n  /**\n   * The current thread ID.\n   */\n  threadId: string;\n  /**\n   * set the current thread ID\n   */\n  setThreadId: (threadId: string) => void;\n  /**\n   * The current run ID.\n   */\n  runId: string | null;\n  /**\n   * set the current run ID\n   */\n  setRunId: (runId: string | null) => void;\n  /**\n   * The global chat abort controller.\n   */\n  chatAbortControllerRef: React.MutableRefObject<AbortController | null>;\n  /**\n   * The agent lock.\n   */\n  agentLock: string | null;\n  /**\n   * The extensions.\n   */\n  extensions: ExtensionsInput;\n  /**\n   * The setState-powered method to update the extensions.\n   */\n  setExtensions: React.Dispatch<React.SetStateAction<ExtensionsInput>>;\n\n  langGraphInterruptAction: LangGraphInterruptAction | null;\n\n  setLangGraphInterruptAction: LangGraphInterruptActionSetter;\n\n  disableSystemMessage?: boolean;\n};\n\nexport type UseChatHelpers = {\n  /**\n   * Append a user message to the chat list. This triggers the API call to fetch\n   * the assistant's response.\n   * @param message The message to append\n   */\n  append: (message: Message, options?: AppendMessageOptions) => Promise<void>;\n  /**\n   * Reload the last AI chat response for the given chat history. If the last\n   * message isn't from the assistant, it will request the API to generate a\n   * new response.\n   */\n  reload: (messageId: string) => Promise<void>;\n  /**\n   * Abort the current request immediately, keep the generated tokens if any.\n   */\n  stop: () => void;\n\n  /**\n   * Run the chat completion.\n   */\n  runChatCompletion: () => Promise<Message[]>;\n};\n\nexport interface AppendMessageOptions {\n  /**\n   * Whether to run the chat completion after appending the message. Defaults to `true`.\n   */\n  followUp?: boolean;\n  /**\n   * Whether to clear the suggestions after appending the message. Defaults to `true`.\n   */\n  clearSuggestions?: boolean;\n}\n\nexport function useChat(options: UseChatOptions): UseChatHelpers {\n  const {\n    messages,\n    setMessages,\n    makeSystemMessageCallback,\n    aiConfig,\n    setIsLoading,\n    initialMessages,\n    isLoading,\n    actions,\n    onFunctionCall,\n    onAiAgentStateRender,\n    setAiAgentStatesWithRef,\n    aiAgentStatesRef,\n    agentSession,\n    setAgentSession,\n    threadId,\n    setThreadId,\n    runId,\n    setRunId,\n    chatAbortControllerRef,\n    agentLock,\n    extensions,\n    setExtensions,\n    langGraphInterruptAction,\n    setLangGraphInterruptAction,\n    disableSystemMessage = false,\n  } = options;\n  const runChatCompletionRef = useRef<(previousMessages: Message[]) => Promise<Message[]>>();\n  const addErrorToast = useErrorToast();\n  const { setBannerError } = useToast();\n\n  // Get onError from context since it's not part of aiConfig\n  const { onError, showDevConsole, getAllContext } = useAiContext();\n\n  const copilotReadableContext = getAllContext();\n\n  const context = useMemo(\n    () =>\n      copilotReadableContext.map((contextItem) => {\n        const [description, ...valueParts] = contextItem.value.split(\":\");\n        return {\n          description: description.trim(),\n          value: valueParts.join(\":\").trim(),\n        };\n      }),\n    [copilotReadableContext],\n  );\n\n  // Add tracing functionality to use-chat\n  const traceUIError = async (error: AiSDKError, originalError?: any) => {\n    try {\n      const traceEvent = {\n        type: \"error\" as const,\n        timestamp: Date.now(),\n        context: {\n          source: \"ui\" as const,\n          request: {\n            operation: \"useChatCompletion\",\n            url: aiConfig.chatApiEndpoint,\n            startTime: Date.now(),\n          },\n          technical: {\n            environment: \"browser\",\n            userAgent: typeof navigator !== \"undefined\" ? navigator.userAgent : undefined,\n            stackTrace: originalError instanceof Error ? originalError.stack : undefined,\n          },\n        },\n        error,\n      };\n\n      await onError(traceEvent);\n    } catch (traceError) {\n      console.error(\"Error in use-chat onError handler:\", traceError);\n    }\n  };\n  // We need to keep a ref of coagent states and session because of renderAndWait - making sure\n  // the latest state is sent to the API\n  // This is a workaround and needs to be addressed in the future\n  const agentSessionRef = useRef<AgentSession | null>(agentSession);\n  agentSessionRef.current = agentSession;\n\n  const runIdRef = useRef<string | null>(runId);\n  runIdRef.current = runId;\n  const extensionsRef = useRef<ExtensionsInput>(extensions);\n  extensionsRef.current = extensions;\n\n  const publicApiKey = aiConfig.publicApiKey;\n\n  const headers = {\n    ...(aiConfig.headers || {}),\n    ...(publicApiKey ? { [AI_CLOUD_PUBLIC_API_KEY_HEADER]: publicApiKey } : {}),\n  };\n\n  const runtimeClient = useAiRuntimeClient({\n    url: aiConfig.chatApiEndpoint,\n    publicApiKey: aiConfig.publicApiKey,\n    headers,\n    credentials: aiConfig.credentials,\n    showDevConsole,\n    onError,\n  });\n\n  const pendingAppendsRef = useRef<{ message: Message; followUp: boolean }[]>([]);\n\n  const runChatCompletion = useAsyncCallback(\n    async (previousMessages: Message[]): Promise<Message[]> => {\n      setIsLoading(true);\n      const interruptEvent = langGraphInterruptAction?.event;\n      // In case an interrupt event exist and valid but has no response yet, we cannot process further messages to an agent\n      if (\n        interruptEvent?.name === MetaEventName.LangGraphInterruptEvent &&\n        interruptEvent?.value &&\n        !interruptEvent?.response &&\n        agentSessionRef.current\n      ) {\n        addErrorToast([\n          new Error(\n            \"A message was sent while interrupt is active. This will cause failure on the agent side\",\n          ),\n        ]);\n      }\n\n      // this message is just a placeholder. It will disappear once the first real message\n      // is received\n      let newMessages: Message[] = [\n        new TextMessage({\n          content: \"\",\n          role: Role.Assistant,\n        }),\n      ];\n\n      chatAbortControllerRef.current = new AbortController();\n\n      setMessages([...previousMessages, ...newMessages]);\n\n      const messagesWithContext = disableSystemMessage\n        ? [...(initialMessages || []), ...previousMessages]\n        : [makeSystemMessageCallback(), ...(initialMessages || []), ...previousMessages];\n\n      // ----- Set mcpServers in properties -----\n      // Create a copy of properties to avoid modifying the original object\n      const finalProperties = { ...(aiConfig.properties || {}) };\n\n      // Look for mcpServers in either direct property or properties\n      let mcpServersToUse = null;\n\n      // First check direct mcpServers property\n      if (\n        aiConfig.mcpServers &&\n        Array.isArray(aiConfig.mcpServers) &&\n        aiConfig.mcpServers.length > 0\n      ) {\n        mcpServersToUse = aiConfig.mcpServers;\n      }\n      // Then check mcpServers in properties\n      else if (\n        aiConfig.properties?.mcpServers &&\n        Array.isArray(aiConfig.properties.mcpServers) &&\n        aiConfig.properties.mcpServers.length > 0\n      ) {\n        mcpServersToUse = aiConfig.properties.mcpServers;\n      }\n\n      // Apply the mcpServers to properties if found\n      if (mcpServersToUse) {\n        // Set in finalProperties\n        finalProperties.mcpServers = mcpServersToUse;\n\n        // Also set in aiConfig directly for future use\n        aiConfig.mcpServers = mcpServersToUse;\n      }\n      // -------------------------------------------------------------\n\n      const isAgentRun = agentSessionRef.current !== null;\n\n      const stream = runtimeClient.asStream(\n        runtimeClient.generateCopilotResponse({\n          data: {\n            frontend: {\n              actions: processActionsForRuntimeRequest(actions),\n              url: window.location.href,\n            },\n            threadId: threadId,\n            runId: runIdRef.current,\n            extensions: extensionsRef.current,\n            metaEvents: composeAndFlushMetaEventsInput([langGraphInterruptAction?.event]),\n            messages: convertMessagesToGqlInput(filterAgentStateMessages(messagesWithContext)),\n            ...(aiConfig.cloud\n              ? {\n                  cloud: {\n                    ...(aiConfig.cloud.guardrails?.input?.restrictToTopic?.enabled\n                      ? {\n                          guardrails: {\n                            inputValidationRules: {\n                              allowList:\n                                aiConfig.cloud.guardrails.input.restrictToTopic.validTopics,\n                              denyList:\n                                aiConfig.cloud.guardrails.input.restrictToTopic.invalidTopics,\n                            },\n                          },\n                        }\n                      : {}),\n                  },\n                }\n              : {}),\n            metadata: {\n              requestType: AiRequestType.Chat,\n            },\n            ...(agentSessionRef.current\n              ? {\n                  agentSession: agentSessionRef.current,\n                }\n              : {}),\n            agentStates: Object.values(aiAgentStatesRef.current!).map((state) => {\n              const stateObject: AgentStateInput = {\n                agentName: state.name,\n                state: JSON.stringify(state.state),\n              };\n\n              if (state.config !== undefined) {\n                stateObject.config = JSON.stringify(state.config);\n              }\n\n              return stateObject;\n            }),\n            forwardedParameters: options.forwardedParameters || {},\n            context,\n          },\n          properties: finalProperties,\n          signal: chatAbortControllerRef.current?.signal,\n        }),\n      );\n\n      const guardrailsEnabled =\n        aiConfig.cloud?.guardrails?.input?.restrictToTopic.enabled || false;\n\n      const reader = stream.getReader();\n\n      let executedAiAgentStateRenders: string[] = [];\n      let followUp: FrontendAction[\"followUp\"] = undefined;\n\n      let messages: Message[] = [];\n      let syncedMessages: Message[] = [];\n      let interruptMessages: Message[] = [];\n\n      try {\n        while (true) {\n          let done, value;\n\n          try {\n            const readResult = await reader.read();\n            done = readResult.done;\n            value = readResult.value;\n          } catch (readError) {\n            break;\n          }\n\n          if (done) {\n            if (chatAbortControllerRef.current.signal.aborted) {\n              return [];\n            }\n            break;\n          }\n\n          if (!value?.generateCopilotResponse) {\n            continue;\n          }\n\n          runIdRef.current = value.generateCopilotResponse.runId || null;\n\n          // in the output, graphql inserts __typename, which leads to an error when sending it along\n          // as input to the next request.\n          extensionsRef.current = AiRuntimeClient.removeGraphQLTypename(\n            value.generateCopilotResponse.extensions || {},\n          );\n\n          // setThreadId(threadIdRef.current);\n          setRunId(runIdRef.current);\n          setExtensions(extensionsRef.current);\n          let rawMessagesResponse = value.generateCopilotResponse.messages;\n\n          const metaEvents: any[] | undefined = value.generateCopilotResponse?.metaEvents ?? [];\n          (metaEvents ?? []).forEach((ev) => {\n            if (ev.name === MetaEventName.LangGraphInterruptEvent) {\n              let eventValue = langGraphInterruptEvent(ev as LangGraphInterruptEvent).value;\n              eventValue = parseJson(eventValue, eventValue);\n              setLangGraphInterruptAction(threadId, {\n                event: {\n                  ...langGraphInterruptEvent(ev as LangGraphInterruptEvent),\n                  value: eventValue,\n                },\n              });\n            }\n            if (ev.name === MetaEventName.VnSdkLangGraphInterruptEvent) {\n              const data = (ev as VnSdkLangGraphInterruptEvent).data;\n\n              // @ts-ignore -- same type of messages\n              rawMessagesResponse = [...rawMessagesResponse, ...data.messages];\n              interruptMessages = convertGqlOutputToMessages(\n                // @ts-ignore\n                filterAdjacentAgentStateMessages(data.messages),\n              );\n            }\n          });\n\n          messages = convertGqlOutputToMessages(\n            filterAdjacentAgentStateMessages(rawMessagesResponse),\n          );\n\n          newMessages = [];\n\n          // Handle error statuses BEFORE checking if there are messages\n          // (errors can come in chunks with no messages)\n\n          // request failed, display error message and quit\n          if (\n            value.generateCopilotResponse.status?.__typename === \"FailedResponseStatus\" &&\n            value.generateCopilotResponse.status.reason === \"GUARDRAILS_VALIDATION_FAILED\"\n          ) {\n            const guardrailsReason =\n              value.generateCopilotResponse.status.details?.guardrailsReason || \"\";\n\n            newMessages = [\n              new TextMessage({\n                role: MessageRole.Assistant,\n                content: guardrailsReason,\n              }),\n            ];\n\n            // Trace guardrails validation failure\n            const guardrailsError = new AiSDKError({\n              message: `Guardrails validation failed: ${guardrailsReason}`,\n              code: AiSDKErrorCode.MISUSE,\n            });\n            await traceUIError(guardrailsError, {\n              statusReason: value.generateCopilotResponse.status.reason,\n              statusDetails: value.generateCopilotResponse.status.details,\n            });\n            // TODO: if onError & renderError should work without key, insert here\n\n            setMessages([...previousMessages, ...newMessages]);\n            break;\n          }\n\n          // Handle UNKNOWN_ERROR failures (like authentication errors) by routing to banner error system\n          if (\n            value.generateCopilotResponse.status?.__typename === \"FailedResponseStatus\" &&\n            value.generateCopilotResponse.status.reason === \"UNKNOWN_ERROR\"\n          ) {\n            const errorMessage =\n              value.generateCopilotResponse.status.details?.description ||\n              \"An unknown error occurred\";\n\n            // Try to extract original error information from the response details\n            const statusDetails = value.generateCopilotResponse.status.details;\n            const originalError = statusDetails?.originalError || statusDetails?.error;\n\n            // Extract structured error information if available (prioritize top-level over extensions)\n            const originalCode = originalError?.code || originalError?.extensions?.code;\n            const originalSeverity = originalError?.severity || originalError?.extensions?.severity;\n            const originalVisibility =\n              originalError?.visibility || originalError?.extensions?.visibility;\n\n            // Use the original error code if available, otherwise default to NETWORK_ERROR\n            let errorCode = AiSDKErrorCode.NETWORK_ERROR;\n            if (originalCode && Object.values(AiSDKErrorCode).includes(originalCode)) {\n              errorCode = originalCode;\n            }\n\n            // Create a structured AiSDKError preserving original error information\n            const structuredError = new AiSDKError({\n              message: errorMessage,\n              code: errorCode,\n              severity: originalSeverity,\n              visibility: originalVisibility,\n            });\n\n            // Display the error in the banner\n            setBannerError(structuredError);\n\n            // Trace the error for debugging/observability\n            await traceUIError(structuredError, {\n              statusReason: value.generateCopilotResponse.status.reason,\n              statusDetails: value.generateCopilotResponse.status.details,\n              originalErrorCode: originalCode,\n              preservedStructure: !!originalCode,\n            });\n            // TODO: if onError & renderError should work without key, insert here\n\n            // Stop processing and break from the loop\n            setIsLoading(false);\n            throw new Error(structuredError.message);\n          }\n\n          // add messages to the chat\n          else if (messages.length > 0) {\n            newMessages = [...messages];\n\n            for (const message of messages) {\n              // execute onAiAgentStateRender handler\n              if (\n                message.isAgentStateMessage() &&\n                !message.active &&\n                !executedAiAgentStateRenders.includes(message.id) &&\n                onAiAgentStateRender\n              ) {\n                // Do not execute a coagent action if guardrails are enabled but the status is not known\n                if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {\n                  break;\n                }\n                // execute coagent action\n                await onAiAgentStateRender({\n                  name: message.agentName,\n                  nodeName: message.nodeName,\n                  state: message.state,\n                });\n                executedAiAgentStateRenders.push(message.id);\n              }\n            }\n\n            const lastAgentStateMessage = [...messages]\n              .reverse()\n              .find((message) => message.isAgentStateMessage());\n\n            if (lastAgentStateMessage) {\n              if (\n                lastAgentStateMessage.state.messages &&\n                lastAgentStateMessage.state.messages.length > 0\n              ) {\n                syncedMessages = loadMessagesFromJsonRepresentation(\n                  lastAgentStateMessage.state.messages,\n                );\n              }\n              setAiAgentStatesWithRef((prevAgentStates) => ({\n                ...prevAgentStates,\n                [lastAgentStateMessage.agentName]: {\n                  name: lastAgentStateMessage.agentName,\n                  state: lastAgentStateMessage.state,\n                  running: lastAgentStateMessage.running,\n                  active: lastAgentStateMessage.active,\n                  threadId: lastAgentStateMessage.threadId,\n                  nodeName: lastAgentStateMessage.nodeName,\n                  runId: lastAgentStateMessage.runId,\n                  // Preserve existing config from previous state\n                  config: prevAgentStates[lastAgentStateMessage.agentName]?.config,\n                },\n              }));\n              if (lastAgentStateMessage.running) {\n                setAgentSession({\n                  threadId: lastAgentStateMessage.threadId,\n                  agentName: lastAgentStateMessage.agentName,\n                  nodeName: lastAgentStateMessage.nodeName,\n                });\n              } else {\n                if (agentLock) {\n                  setAgentSession({\n                    threadId: randomId(),\n                    agentName: agentLock,\n                    nodeName: undefined,\n                  });\n                } else {\n                  setAgentSession(null);\n                }\n              }\n            }\n          }\n\n          if (newMessages.length > 0) {\n            // Update message state\n            setMessages([...previousMessages, ...newMessages]);\n          }\n        }\n        let finalMessages = constructFinalMessages(\n          [...syncedMessages, ...interruptMessages],\n          previousMessages,\n          newMessages,\n        );\n\n        let didExecuteAction = false;\n\n        // ----- Helper function to execute an action and manage its lifecycle -----\n        const executeActionFromMessage = async (\n          currentAction: FrontendAction<any>,\n          actionMessage: ActionExecutionMessage,\n        ) => {\n          const isInterruptAction = interruptMessages.find((m) => m.id === actionMessage.id);\n          // Determine follow-up behavior: use action's specific setting if defined, otherwise default based on interrupt status.\n          followUp = currentAction?.followUp ?? !isInterruptAction;\n\n          // Call _setActivatingMessageId before executing the action for HITL correlation\n          if ((currentAction as any)?._setActivatingMessageId) {\n            (currentAction as any)._setActivatingMessageId(actionMessage.id);\n          }\n\n          const resultMessage = await executeAction({\n            onFunctionCall: onFunctionCall!,\n            message: actionMessage,\n            chatAbortControllerRef,\n            onError: (error: Error) => {\n              addErrorToast([error]);\n              // console.error is kept here as it's a genuine error in action execution\n              console.error(`Failed to execute action ${actionMessage.name}: ${error}`);\n            },\n            setMessages,\n            getFinalMessages: () => finalMessages,\n            isRenderAndWait: (currentAction as any)?._isRenderAndWait || false,\n          });\n          didExecuteAction = true;\n          const messageIndex = finalMessages.findIndex((msg) => msg.id === actionMessage.id);\n          finalMessages.splice(messageIndex + 1, 0, resultMessage);\n\n          // If the executed action was a renderAndWaitForResponse type, update messages immediately\n          // to reflect its completion in the UI, making it interactive promptly.\n          if ((currentAction as any)?._isRenderAndWait) {\n            const messagesForImmediateUpdate = [...finalMessages];\n            flushSync(() => {\n              setMessages(messagesForImmediateUpdate);\n            });\n          }\n\n          // Clear _setActivatingMessageId after the action is done\n          if ((currentAction as any)?._setActivatingMessageId) {\n            (currentAction as any)._setActivatingMessageId(null);\n          }\n\n          return resultMessage;\n        };\n        // ----------------------------------------------------------------------\n\n        // execute regular action executions that are specific to the frontend (last actions)\n        if (onFunctionCall) {\n          // Find consecutive action execution messages at the end\n          const lastMessages = [];\n\n          for (let i = finalMessages.length - 1; i >= 0; i--) {\n            const message = finalMessages[i];\n            if (\n              (message.isActionExecutionMessage() || message.isResultMessage()) &&\n              message.status.code !== MessageStatusCode.Pending\n            ) {\n              lastMessages.unshift(message);\n            } else if (!message.isAgentStateMessage()) {\n              break;\n            }\n          }\n\n          for (const message of lastMessages) {\n            // We update the message state before calling the handler so that the render\n            // function can be called with `executing` state\n            setMessages(finalMessages);\n\n            const action = actions.find(\n              (action) => action.name === (message as ActionExecutionMessage).name,\n            );\n            if (action && action.available === \"frontend\") {\n              // never execute frontend actions\n              continue;\n            }\n            const currentResultMessagePairedFeAction = message.isResultMessage()\n              ? getPairedFeAction(actions, message)\n              : null;\n\n            // execution message which has an action registered with the hook (remote availability):\n            // execute that action first, and then the \"paired FE action\"\n            if (action && message.isActionExecutionMessage()) {\n              // For HITL actions, check if they've already been processed to avoid redundant handler calls.\n              const isRenderAndWaitAction = (action as any)?._isRenderAndWait || false;\n              const alreadyProcessed =\n                isRenderAndWaitAction &&\n                finalMessages.some(\n                  (fm) => fm.isResultMessage() && fm.actionExecutionId === message.id,\n                );\n\n              if (alreadyProcessed) {\n                // Skip re-execution if already processed\n              } else {\n                // Call the single, externally defined executeActionFromMessage\n                const resultMessage = await executeActionFromMessage(\n                  action,\n                  message as ActionExecutionMessage,\n                );\n                const pairedFeAction = getPairedFeAction(actions, resultMessage);\n\n                if (pairedFeAction) {\n                  const newExecutionMessage = new ActionExecutionMessage({\n                    name: pairedFeAction.name,\n                    arguments: parseJson(resultMessage.result, resultMessage.result),\n                    status: message.status,\n                    createdAt: message.createdAt,\n                    parentMessageId: message.parentMessageId,\n                  });\n                  // Call the single, externally defined executeActionFromMessage\n                  await executeActionFromMessage(pairedFeAction, newExecutionMessage);\n                }\n              }\n            } else if (message.isResultMessage() && currentResultMessagePairedFeAction) {\n              // Actions which are set up in runtime actions array: Grab the result, executed paired FE action with it as args.\n              const newExecutionMessage = new ActionExecutionMessage({\n                name: currentResultMessagePairedFeAction.name,\n                arguments: parseJson(message.result, message.result),\n                status: message.status,\n                createdAt: message.createdAt,\n              });\n              finalMessages.push(newExecutionMessage);\n              // Call the single, externally defined executeActionFromMessage\n              await executeActionFromMessage(\n                currentResultMessagePairedFeAction,\n                newExecutionMessage,\n              );\n            }\n          }\n\n          setMessages(finalMessages);\n        }\n\n        // Conditionally run chat completion again if followUp is not explicitly false\n        // and an action was executed or the last message is a server-side result (for non-agent runs).\n        if (\n          followUp !== false &&\n          (didExecuteAction ||\n            // the last message is a server side result\n            (!isAgentRun &&\n              finalMessages.length &&\n              finalMessages[finalMessages.length - 1].isResultMessage())) &&\n          // the user did not stop generation\n          !chatAbortControllerRef.current?.signal.aborted\n        ) {\n          // run the completion again and return the result\n\n          // wait for next tick to make sure all the react state updates\n          // - tried using react-dom's flushSync, but it did not work\n          await new Promise((resolve) => setTimeout(resolve, 10));\n\n          return await runChatCompletionRef.current!(finalMessages);\n        } else if (chatAbortControllerRef.current?.signal.aborted) {\n          // filter out all the action execution messages that do not have a consecutive matching result message\n          const repairedMessages = finalMessages.filter((message, actionExecutionIndex) => {\n            if (message.isActionExecutionMessage()) {\n              return finalMessages.find(\n                (msg, resultIndex) =>\n                  msg.isResultMessage() &&\n                  msg.actionExecutionId === message.id &&\n                  resultIndex === actionExecutionIndex + 1,\n              );\n            }\n            return true;\n          });\n          const repairedMessageIds = repairedMessages.map((message) => message.id);\n          setMessages(repairedMessages);\n\n          // LangGraph needs two pieces of information to continue execution:\n          // 1. The threadId\n          // 2. The nodeName it came from\n          // When stopping the agent, we don't know the nodeName the agent would have ended with\n          // Therefore, we set the nodeName to the most reasonable thing we can guess, which\n          // is \"__end__\"\n          if (agentSessionRef.current?.nodeName) {\n            setAgentSession({\n              threadId: agentSessionRef.current.threadId,\n              agentName: agentSessionRef.current.agentName,\n              nodeName: \"__end__\",\n            });\n          }\n          // only return new messages that were not filtered out\n          return newMessages.filter((message) => repairedMessageIds.includes(message.id));\n        } else {\n          return newMessages.slice();\n        }\n      } finally {\n        setIsLoading(false);\n      }\n    },\n    [\n      messages,\n      setMessages,\n      makeSystemMessageCallback,\n      aiConfig,\n      setIsLoading,\n      initialMessages,\n      isLoading,\n      actions,\n      onFunctionCall,\n      onAiAgentStateRender,\n      setAiAgentStatesWithRef,\n      aiAgentStatesRef,\n      agentSession,\n      setAgentSession,\n      disableSystemMessage,\n      context,\n    ],\n  );\n\n  runChatCompletionRef.current = runChatCompletion;\n\n  const runChatCompletionAndHandleFunctionCall = useAsyncCallback(\n    async (messages: Message[]): Promise<void> => {\n      await runChatCompletionRef.current!(messages);\n    },\n    [messages],\n  );\n\n  useEffect(() => {\n    if (!isLoading && pendingAppendsRef.current.length > 0) {\n      const pending = pendingAppendsRef.current.splice(0);\n      const followUp = pending.some((p) => p.followUp);\n      const newMessages = [...messages, ...pending.map((p) => p.message)];\n      setMessages(newMessages);\n      if (followUp) {\n        runChatCompletionAndHandleFunctionCall(newMessages);\n      }\n    }\n  }, [isLoading, messages, setMessages, runChatCompletionAndHandleFunctionCall]);\n\n  // Go over all events and see that they include data that should be returned to the agent\n  const composeAndFlushMetaEventsInput = useCallback(\n    (metaEvents: (MetaEvent | undefined | null)[]) => {\n      return metaEvents.reduce((acc: MetaEventInput[], event) => {\n        if (!event) return acc;\n\n        switch (event.name) {\n          case MetaEventName.LangGraphInterruptEvent:\n            if (event.response) {\n              // Flush interrupt event from state\n              setLangGraphInterruptAction(threadId, null);\n              const value = (event as LangGraphInterruptEvent).value;\n              return [\n                ...acc,\n                {\n                  name: event.name,\n                  value: typeof value === \"string\" ? value : JSON.stringify(value),\n                  response:\n                    typeof event.response === \"string\"\n                      ? event.response\n                      : JSON.stringify(event.response),\n                },\n              ];\n            }\n            return acc;\n          default:\n            return acc;\n        }\n      }, []);\n    },\n    [setLangGraphInterruptAction],\n  );\n\n  const append = useAsyncCallback(\n    async (message: Message, options?: AppendMessageOptions): Promise<void> => {\n      const followUp = options?.followUp ?? true;\n      if (isLoading) {\n        pendingAppendsRef.current.push({ message, followUp });\n        return;\n      }\n\n      const newMessages = [...messages, message];\n      setMessages(newMessages);\n      if (followUp) {\n        return runChatCompletionAndHandleFunctionCall(newMessages);\n      }\n    },\n    [isLoading, messages, setMessages, runChatCompletionAndHandleFunctionCall],\n  );\n\n  const reload = useAsyncCallback(\n    async (reloadMessageId: string): Promise<void> => {\n      if (isLoading || messages.length === 0) {\n        return;\n      }\n\n      const reloadMessageIndex = messages.findIndex((msg) => msg.id === reloadMessageId);\n      if (reloadMessageIndex === -1) {\n        console.warn(`Message with id ${reloadMessageId} not found`);\n        return;\n      }\n\n      // @ts-expect-error -- message has role\n      const reloadMessageRole = messages[reloadMessageIndex].role;\n      if (reloadMessageRole !== MessageRole.Assistant) {\n        console.warn(`Regenerate cannot be performed on ${reloadMessageRole} role`);\n        return;\n      }\n      let historyCutoff: Message[] = [messages[0]];\n\n      if (messages.length > 2 && reloadMessageIndex !== 0) {\n        // message to regenerate from is now first.\n        // Work backwards to find the first the closest user message\n        const lastUserMessageBeforeRegenerate = messages\n          .slice(0, reloadMessageIndex)\n          .reverse()\n          .find(\n            (msg) =>\n              // @ts-expect-error -- message has role\n              msg.role === MessageRole.User,\n          );\n        const indexOfLastUserMessageBeforeRegenerate = messages.findIndex(\n          (msg) => msg.id === lastUserMessageBeforeRegenerate!.id,\n        );\n\n        // Include the user message, remove everything after it\n        historyCutoff = messages.slice(0, indexOfLastUserMessageBeforeRegenerate + 1);\n      } else if (messages.length > 2 && reloadMessageIndex === 0) {\n        historyCutoff = [messages[0], messages[1]];\n      }\n\n      setMessages(historyCutoff);\n\n      return runChatCompletionAndHandleFunctionCall(historyCutoff);\n    },\n    [isLoading, messages, setMessages, runChatCompletionAndHandleFunctionCall],\n  );\n\n  const stop = (): void => {\n    chatAbortControllerRef.current?.abort(\"Stop was called\");\n  };\n\n  return {\n    append,\n    reload,\n    stop,\n    runChatCompletion: () => runChatCompletionRef.current!(messages),\n  };\n}\n\nfunction constructFinalMessages(\n  syncedMessages: Message[],\n  previousMessages: Message[],\n  newMessages: Message[],\n): Message[] {\n  const finalMessages =\n    syncedMessages.length > 0 ? [...syncedMessages] : [...previousMessages, ...newMessages];\n\n  if (syncedMessages.length > 0) {\n    const messagesWithAgentState = [...previousMessages, ...newMessages];\n\n    let previousMessageId: string | undefined = undefined;\n\n    for (const message of messagesWithAgentState) {\n      if (message.isAgentStateMessage()) {\n        // insert this message into finalMessages after the position of previousMessageId\n        const index = finalMessages.findIndex((msg) => msg.id === previousMessageId);\n        if (index !== -1) {\n          finalMessages.splice(index + 1, 0, message);\n        }\n      }\n\n      previousMessageId = message.id;\n    }\n  }\n\n  return finalMessages;\n}\n\nasync function executeAction({\n  onFunctionCall,\n  message,\n  chatAbortControllerRef,\n  onError,\n  setMessages,\n  getFinalMessages,\n  isRenderAndWait,\n}: {\n  onFunctionCall: FunctionCallHandler;\n  message: ActionExecutionMessage;\n  chatAbortControllerRef: React.MutableRefObject<AbortController | null>;\n  onError: (error: Error) => void;\n  setMessages: React.Dispatch<React.SetStateAction<Message[]>>;\n  getFinalMessages: () => Message[];\n  isRenderAndWait: boolean;\n}) {\n  let result: any;\n  let error: Error | null = null;\n\n  const currentMessagesForHandler = getFinalMessages();\n\n  // The handler (onFunctionCall) runs its synchronous part here, potentially setting up\n  // renderAndWaitRef.current for HITL actions via useAiAction's transformed handler.\n  const handlerReturnedPromise = onFunctionCall({\n    messages: currentMessagesForHandler,\n    name: message.name,\n    args: message.arguments,\n  });\n\n  // For HITL actions, call flushSync immediately after their handler has set up the promise\n  // and before awaiting the promise. This ensures the UI updates to an interactive state.\n  if (isRenderAndWait) {\n    const currentMessagesForRender = getFinalMessages();\n    flushSync(() => {\n      setMessages([...currentMessagesForRender]);\n    });\n  }\n\n  try {\n    result = await Promise.race([\n      handlerReturnedPromise, // Await the promise returned by the handler\n      new Promise((resolve) =>\n        chatAbortControllerRef.current?.signal.addEventListener(\"abort\", () =>\n          resolve(\"Operation was aborted by the user\"),\n        ),\n      ),\n      // if the user stopped generation, we also abort consecutive actions\n      new Promise((resolve) => {\n        if (chatAbortControllerRef.current?.signal.aborted) {\n          resolve(\"Operation was aborted by the user\");\n        }\n      }),\n    ]);\n  } catch (e) {\n    onError(e as Error);\n  }\n  return new ResultMessage({\n    id: \"result-\" + message.id,\n    result: ResultMessage.encodeResult(\n      error\n        ? {\n            content: result,\n            error: JSON.parse(JSON.stringify(error, Object.getOwnPropertyNames(error))),\n          }\n        : result,\n    ),\n    actionExecutionId: message.id,\n    actionName: message.name,\n  });\n}\n\nfunction getPairedFeAction(\n  actions: FrontendAction<any>[],\n  message: ActionExecutionMessage | ResultMessage,\n) {\n  let actionName = null;\n  if (message.isActionExecutionMessage()) {\n    actionName = message.name;\n  } else if (message.isResultMessage()) {\n    actionName = message.actionName;\n  }\n  return actions.find(\n    (action) =>\n      (action.name === actionName && action.available === \"frontend\") ||\n      action.pairedAction === actionName,\n  );\n}\n"],"mappings":"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","names":["messages","_a","action","options"]}