feat(xai): surface hosted X Search activity (#5050)

This commit is contained in:
chengyongru
2026-07-23 13:42:09 +08:00
committed by GitHub
parent f3099286ea
commit 9cf2fb19c2
14 changed files with 431 additions and 8 deletions
@@ -10,7 +10,7 @@ import {
export function WebSearchRun({ run, turnActive }: { run: WebSearchRunModel; turnActive: boolean }) {
const active = run.status === "running" && turnActive;
const status = run.status === "running" && !turnActive ? "done" : run.status;
const label = presentWebSearchAction(run.query, status);
const label = presentWebSearchAction(run.query, status, run.target);
return (
<>
@@ -77,6 +77,7 @@ const EXCLUDED_TOOLS = new Set([
"terminal",
"web_fetch",
"web_search",
"x_search",
"write_file",
]);
@@ -30,7 +30,7 @@ export function describeTraceLine(
const query = traceFieldFromArgs(args, ["query", "q", "text"]) || args || trimmed;
return {
kind: "search",
label: presentWebSearchAction(query, status),
label: presentWebSearchAction(query, status, name === "x_search" ? "x" : "web"),
detail: "",
};
}
@@ -5,6 +5,7 @@ import { redactActivityText, safeActivityDetail } from "./activity-text";
import { displayWebHost, formatCompactWebUrl, parseSafeActivityHttpUrl } from "./web-url";
export type WebSearchStatus = "running" | "done" | "error";
export type WebSearchTarget = "web" | "x";
export interface WebSearchSource {
title: string;
@@ -16,6 +17,7 @@ export interface WebSearchSource {
export interface WebSearchRunModel {
key: string;
query: string;
target: WebSearchTarget;
status: WebSearchStatus;
sources: WebSearchSource[];
error?: string;
@@ -49,10 +51,11 @@ export function webSearchRunsByTraceLine(
function webSearchRunFromEvent(event: ToolProgressEvent): WebSearchRunModel | null {
const name = compactToolName(toolEventName(event));
if (name !== "web_search") return null;
if (name !== "web_search" && name !== "x_search") return null;
const args = toolEventArguments(event);
const query = stringField(args, ["query", "q", "text"]);
const target: WebSearchTarget = name === "x_search" ? "x" : "web";
const status: WebSearchStatus = event.phase === "error"
? "error"
: event.phase === "end"
@@ -60,10 +63,11 @@ function webSearchRunFromEvent(event: ToolProgressEvent): WebSearchRunModel | nu
: "running";
return {
key: event.call_id ? `call:${event.call_id}` : formatToolCallTrace(event) ?? `web_search:${query}`,
key: event.call_id ? `call:${event.call_id}` : formatToolCallTrace(event) ?? `${name}:${query}`,
query,
target,
status,
sources: status === "done" ? webSearchSources(event.result) : [],
sources: status === "done" && target === "web" ? webSearchSources(event.result) : [],
error: status === "error" ? readableError(event.error) : undefined,
};
}
@@ -89,6 +93,7 @@ function presentWebSearchQuery(query: string): WebSearchQueryPresentation {
export function presentWebSearchAction(
query: string,
status: WebSearchStatus,
target: WebSearchTarget = "web",
): string {
const presentation = presentWebSearchQuery(query);
const verb = status === "error"
@@ -96,8 +101,11 @@ export function presentWebSearchAction(
: status === "running"
? "Searching"
: "Searched";
const target = [presentation.scope, presentation.query].filter(Boolean).join(" · ");
return target ? `${verb} ${target}` : verb;
const queryTarget = [presentation.scope, presentation.query].filter(Boolean).join(" · ");
if (target === "x") {
return queryTarget ? `${verb} X · ${queryTarget}` : `${verb} X`;
}
return queryTarget ? `${verb} ${queryTarget}` : verb;
}
function mergeWebSearchRun(