From 156d0686c46aafb0fa9d291da6421fb6f64dddc0 Mon Sep 17 00:00:00 2001 From: Hiep Le <69354317+hieptl@users.noreply.github.com> Date: Fri, 28 Nov 2025 23:16:34 +0700 Subject: [PATCH] fix(frontend): the content of the BrowserObservation event is not being rendered correctly (#11832) --- .../get-action-content.ts | 66 ++++++++++++++----- .../get-event-content.tsx | 11 +++- .../get-observation-content.ts | 17 +++-- 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/frontend/src/components/v1/chat/event-content-helpers/get-action-content.ts b/frontend/src/components/v1/chat/event-content-helpers/get-action-content.ts index 702c308733..1489493652 100644 --- a/frontend/src/components/v1/chat/event-content-helpers/get-action-content.ts +++ b/frontend/src/components/v1/chat/event-content-helpers/get-action-content.ts @@ -132,27 +132,61 @@ type BrowserAction = const getBrowserActionContent = (action: BrowserAction): string => { switch (action.kind) { - case "BrowserNavigateAction": - if ("url" in action) { - return `Browsing ${action.url}`; + case "BrowserNavigateAction": { + let content = `Browsing ${action.url}`; + if (action.new_tab) { + content += `\n**New Tab:** Yes`; + } + return content; + } + case "BrowserClickAction": { + let content = `**Element Index:** ${action.index}`; + if (action.new_tab) { + content += `\n**New Tab:** Yes`; + } + return content; + } + case "BrowserTypeAction": { + const textPreview = + action.text.length > 50 + ? `${action.text.slice(0, 50)}...` + : action.text; + return `**Element Index:** ${action.index}\n**Text:** ${textPreview}`; + } + case "BrowserGetStateAction": { + if (action.include_screenshot) { + return `**Include Screenshot:** Yes`; } - break; - case "BrowserClickAction": - case "BrowserTypeAction": - case "BrowserGetStateAction": - case "BrowserGetContentAction": - case "BrowserScrollAction": - case "BrowserGoBackAction": - case "BrowserListTabsAction": - case "BrowserSwitchTabAction": - case "BrowserCloseTabAction": - // These browser actions typically don't need detailed content display return getNoContentActionContent(); + } + case "BrowserGetContentAction": { + const parts: string[] = []; + if (action.extract_links) { + parts.push(`**Extract Links:** Yes`); + } + if (action.start_from_char > 0) { + parts.push(`**Start From Character:** ${action.start_from_char}`); + } + return parts.length > 0 ? parts.join("\n") : getNoContentActionContent(); + } + case "BrowserScrollAction": { + return `**Direction:** ${action.direction}`; + } + case "BrowserGoBackAction": { + return getNoContentActionContent(); + } + case "BrowserListTabsAction": { + return getNoContentActionContent(); + } + case "BrowserSwitchTabAction": { + return `**Tab ID:** ${action.tab_id}`; + } + case "BrowserCloseTabAction": { + return `**Tab ID:** ${action.tab_id}`; + } default: return getNoContentActionContent(); } - - return getNoContentActionContent(); }; export const getActionContent = (event: ActionEvent): string => { diff --git a/frontend/src/components/v1/chat/event-content-helpers/get-event-content.tsx b/frontend/src/components/v1/chat/event-content-helpers/get-event-content.tsx index f6c67d9fcc..d9b9bf2d2d 100644 --- a/frontend/src/components/v1/chat/event-content-helpers/get-event-content.tsx +++ b/frontend/src/components/v1/chat/event-content-helpers/get-event-content.tsx @@ -85,11 +85,20 @@ const getActionEventTitle = (event: OpenHandsEvent): React.ReactNode => { actionKey = "ACTION_MESSAGE$TASK_TRACKING"; break; case "BrowserNavigateAction": + case "BrowserClickAction": + case "BrowserTypeAction": + case "BrowserGetStateAction": + case "BrowserGetContentAction": + case "BrowserScrollAction": + case "BrowserGoBackAction": + case "BrowserListTabsAction": + case "BrowserSwitchTabAction": + case "BrowserCloseTabAction": actionKey = "ACTION_MESSAGE$BROWSE"; break; default: // For unknown actions, use the type name - return actionType.replace("Action", "").toUpperCase(); + return String(actionType).replace("Action", "").toUpperCase(); } if (actionKey) { diff --git a/frontend/src/components/v1/chat/event-content-helpers/get-observation-content.ts b/frontend/src/components/v1/chat/event-content-helpers/get-observation-content.ts index c7fe0be374..a227e99cfc 100644 --- a/frontend/src/components/v1/chat/event-content-helpers/get-observation-content.ts +++ b/frontend/src/components/v1/chat/event-content-helpers/get-observation-content.ts @@ -80,14 +80,23 @@ const getBrowserObservationContent = ( ): string => { const { observation } = event; + // Extract text content from the observation + const textContent = + "content" in observation && Array.isArray(observation.content) + ? observation.content + .filter((c) => c.type === "text") + .map((c) => c.text) + .join("\n") + : ""; + let contentDetails = ""; - if ("error" in observation && observation.error) { - contentDetails += `**Error:**\n${observation.error}\n\n`; + if ("is_error" in observation && observation.is_error) { + contentDetails += `**Error:**\n${textContent}`; + } else { + contentDetails += `**Output:**\n${textContent}`; } - contentDetails += `**Output:**\n${observation.output}`; - if (contentDetails.length > MAX_CONTENT_LENGTH) { contentDetails = `${contentDetails.slice(0, MAX_CONTENT_LENGTH)}...(truncated)`; }