diff --git a/frontend/src/hooks/use-v0-handle-runtime-active.ts b/frontend/src/hooks/use-v0-handle-runtime-active.ts new file mode 100644 index 0000000000..bfc07c472f --- /dev/null +++ b/frontend/src/hooks/use-v0-handle-runtime-active.ts @@ -0,0 +1,10 @@ +import { RUNTIME_INACTIVE_STATES } from "#/types/agent-state"; +import { useAgentStore } from "#/stores/agent-store"; + +export const useV0HandleRuntimeActive = () => { + const { curAgentState } = useAgentStore(); + + const runtimeActive = !RUNTIME_INACTIVE_STATES.includes(curAgentState); + + return { runtimeActive }; +}; diff --git a/frontend/src/hooks/use-v0-handle-ws-events.ts b/frontend/src/hooks/use-v0-handle-ws-events.ts new file mode 100644 index 0000000000..c2b9590a11 --- /dev/null +++ b/frontend/src/hooks/use-v0-handle-ws-events.ts @@ -0,0 +1,48 @@ +import React from "react"; +import { useWsClient } from "#/context/ws-client-provider"; +import { generateAgentStateChangeEvent } from "#/services/agent-state-service"; +import { AgentState } from "#/types/agent-state"; +import { displayErrorToast } from "#/utils/custom-toast-handlers"; +import { useEventStore } from "#/stores/use-event-store"; + +interface ServerError { + error: boolean | string; + message: string; + [key: string]: unknown; +} + +const isServerError = (data: object): data is ServerError => "error" in data; + +export const useV0HandleWSEvents = () => { + const { send } = useWsClient(); + const events = useEventStore((state) => state.events); + + React.useEffect(() => { + if (!events.length) { + return; + } + const event = events[events.length - 1]; + + if (isServerError(event)) { + if (event.error_code === 401) { + displayErrorToast("Session expired."); + return; + } + + if (typeof event.error === "string") { + displayErrorToast(event.error); + } else { + displayErrorToast(event.message); + } + return; + } + + if ("type" in event && event.type === "error") { + const message: string = `${event.message}`; + if (message.startsWith("Agent reached maximum")) { + // We set the agent state to paused here - if the user clicks resume, it auto updates the max iterations + send(generateAgentStateChangeEvent(AgentState.PAUSED)); + } + } + }, [events.length]); +}; diff --git a/frontend/src/routes/microagent-management.tsx b/frontend/src/routes/microagent-management.tsx index cd2e70e909..839afde59c 100644 --- a/frontend/src/routes/microagent-management.tsx +++ b/frontend/src/routes/microagent-management.tsx @@ -3,7 +3,7 @@ import { GetConfigResponse } from "#/api/option-service/option.types"; import OptionService from "#/api/option-service/option-service.api"; import { MicroagentManagementContent } from "#/components/features/microagent-management/microagent-management-content"; import { ConversationSubscriptionsProvider } from "#/context/conversation-subscriptions-provider"; -import { EventHandler } from "#/wrapper/event-handler"; +import { V0EventHandler } from "#/wrapper/v0-event-handler"; export const clientLoader = async () => { let config = queryClient.getQueryData(["config"]); @@ -18,9 +18,9 @@ export const clientLoader = async () => { function MicroagentManagement() { return ( - + - + ); } diff --git a/frontend/src/wrapper/v0-event-handler.tsx b/frontend/src/wrapper/v0-event-handler.tsx new file mode 100644 index 0000000000..68d7cd980b --- /dev/null +++ b/frontend/src/wrapper/v0-event-handler.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import { useV0HandleWSEvents } from "#/hooks/use-v0-handle-ws-events"; +import { useV0HandleRuntimeActive } from "#/hooks/use-v0-handle-runtime-active"; + +export function V0EventHandler({ children }: React.PropsWithChildren) { + useV0HandleWSEvents(); + useV0HandleRuntimeActive(); + + return children; +}