fix(frontend): the content of the BrowserObservation event is not being rendered correctly (#11832)

This commit is contained in:
Hiep Le 2025-11-28 23:16:34 +07:00 committed by GitHub
parent d0b1d29379
commit 156d0686c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 73 additions and 21 deletions

View File

@ -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 => {

View File

@ -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) {

View File

@ -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)`;
}