import { useHasToolReview, useRecordedToolReview } from "../components/tool-review-history";
import { ToolActionReviewCard } from "../components/tool-action-review";
import { SecretRefText } from "../components/secret-ref-chip";
import type { ToolReviewStatus } from "@opengeni/sdk";
import { KnowledgeReceiptRow } from "./knowledge-receipt";
import { defaultUrlTransform } from "react-markdown";
import { isRetainedImageContentType, useRetainedImageObjectUrl } from "./retained-image";
import { parseSandboxFileArtifactReceipt, type RetainedArtifactReference } from "@opengeni/sdk";
import {
BrainCircuitIcon,
CameraIcon,
CameraOffIcon,
DownloadIcon,
FileSearchIcon,
GlobeIcon,
ImageIcon,
KeyRoundIcon,
LockIcon,
MessagesSquareIcon,
MousePointer2Icon,
PackageSearchIcon,
PanelsTopLeftIcon,
VideoIcon,
} from "lucide-react";
import { useContext, useState, type ReactNode } from "react";
import { formatBytes, tryParseJson } from "../lib/format";
import { useTimelineComputeLabel } from "./compute-label";
import { useToolDetails } from "./tool-details";
import type { ToolCallItem } from "./types";
import { ConnectorLogoIcon, useToolConnectorLogo } from "./provider-logo";
import { toolIcon } from "./tool-icon";
import {
generatedImageReceipt,
mediaPreviewFact,
parseToolArgs,
retainedScreenshotMetadata,
retainedToolResultImages,
unwrapMcpOutput,
screenshotDataUrl,
} from "./parsers";
import {
createToolRegistry,
type ToolRegistry,
type ToolRegistryEntry,
type ToolRenderer,
type ToolRendererProps,
} from "./registry";
import {
BodyNote,
MediaEmpty,
MediaSkeleton,
PayloadBlock,
ScreenshotFigure,
TermBlock,
Thumbnail,
ActivityDisclosure,
CompactActivityContext,
type DisclosureChip,
} from "./shared";
import { RawPatch, ToolDiff } from "./tool-diff";
import {
applyPatchPresentation,
askPresentation,
execPresentation,
genericToolIconKind,
parseDisclosedTools,
parseSearchHits,
pathBasename,
pathDirname,
machinePresentation,
runOnPresentation,
plainToolRow,
presentedToolKind,
presentsToolOutputPreview,
toolRowPresentation,
toolSearchPreview,
toolSearchQuery,
truncatePreview,
webSearchPresentation,
writeStdinPresentation,
type PresentedToolKind,
type ToolBody,
type ToolPreview,
type ToolRowPresentation,
type WebSearchResult,
} from "./tool-presentation";
import { isPatchFilename, PatchApplyCommand } from "./patch-apply-command";
import { mcpToolLeaf, toolDisplayName } from "./tool-display-name";
import { useOpenGeniLinkResolver } from "../components/open-geni-links";
import { useOpenGeniText, type OpenGeniText } from "../messages/runtime";
/* ----------------------------------------------------------------------------
Per-tool renderers
Each renderer takes one projected `ToolCallItem` and returns an `ActivityDisclosure`
tuned for that tool's real wire shape. The defaults below populate the
registry; the mapping is registered at the bottom of the file.
Restraint is the rule: compact title + one quiet preview, secondary detail
only on expand. No loud right-side badges — at most a single settle chip.
-------------------------------------------------------------------------- */
const ICON_SIZE = "size-3.5";
/**
* The single in-flight locus for a running row: a pulse dot immediately left of
* the status word, riding the preview line — NOT a detached gutter badge. The
* title already shimmers; this keeps the live signal in one place the eye reads
* left-to-right.
*/
function RunningPreview({ children }: { children: ReactNode }) {
const compact = useContext(CompactActivityContext);
return (
{!compact && (
)}
{children}
);
}
/**
* The collapsed-row path preview. Diff magnitude is rendered as a SINGLE muted
* "+N −M" glyph pair — the saturated add/del green/red is reserved exclusively
* for the expanded DiffView gutter, so the one-line rail stays a calm, single
* hue (the file path) with no competing colored numerics.
*/
function PathPreview({
path,
add,
del,
}: {
path: string;
add?: number | undefined;
del?: number | undefined;
}) {
return (
{pathDirname(path)}
{pathBasename(path)}
{add != null || del != null ? (
{add != null ? `+${add}` : ""}
{add != null && del != null ? " " : ""}
{del != null ? `−${del}` : ""}
) : null}
);
}
/* ---- shared-model rows ------------------------------------------------------
exec_command, write_stdin, apply_patch, web search, request_human_input,
run_on and the generic fallback draw their row from the renderer-neutral
presentation model in ./tool-presentation, which non-DOM renderers share.
-------------------------------------------------------------------------- */
function presentedPreviewNode(msg: OpenGeniText, preview: ToolPreview): ReactNode {
switch (preview.kind) {
case "text":
return preview.running ? {preview.text} : preview.text;
case "path":
return ;
case "files":
return (
{msg("timeline.toolRenderers.filesCount", { count: preview.count })}
+{preview.add} −{preview.del}
);
case "malformed":
return (
{preview.name}
{msg("timeline.toolRenderers.malformedPatch")}
);
}
}
function PresentedBody({ body }: { body: ToolBody }) {
switch (body.kind) {
case "term":
return (
<>
{/* Exec rows pass command={null}: the row title already carries `$ cmd`. */}
{body.note ? {body.note} : null}
>
);
case "note":
return body.tone ? (
{body.text}
) : (
{body.text}
);
case "payloads":
return (
<>
{body.note ?
{body.note}
: null}
{body.blocks.map((block) =>
block.failed ? (
) : (
),
)}
>
);
case "patch":
if (body.bare) {
return ;
}
return (
<>
{body.files.map((entry) =>
entry.file ? (
) : (
),
)}
>
);
case "web-results":
return ;
case "none":
return null;
}
}
function WebSearchResults({ results }: { results: WebSearchResult[] | null }) {
const msg = useOpenGeniText();
const resultOccurrences = new Map();
const keyedResults = results?.map((result) => {
const contentKey = `${result.domain}\u0000${result.title}\u0000${result.snippet}`;
const occurrence = (resultOccurrences.get(contentKey) ?? 0) + 1;
resultOccurrences.set(contentKey, occurrence);
return { key: `${contentKey}\u0000${occurrence}`, result };
});
if (!keyedResults || !keyedResults.length) {
return {msg("timeline.toolRenderers.resultsFoldedIntoModelContext")} ;
}
return (
{keyedResults.map(({ key, result }) => (
{result.title} {result.domain}
{result.snippet}
))}
);
}
/** Draw one shared-model row with the web disclosure primitives. */
function PresentedToolRow({
presentation,
item,
logo = null,
}: {
presentation: ToolRowPresentation;
/** The call the row presents; plain tool details reduce the row from it. */
item: ToolCallItem;
/** A connector's logo, drawn in place of the row's icon. */
logo?: string | null;
}) {
const msg = useOpenGeniText();
const computeLabel = useTimelineComputeLabel();
const p =
useToolDetails() === "plain"
? plainToolRow(msg, item, presentation, { computeLabel })
: presentation;
const Icon = toolIcon(p.icon);
return (
} />}
iconTone={p.iconTone}
// A chip inside the row's own toggle never links.
title={ }
{...(p.titleMono ? { titleMono: true } : {})}
{...(p.running ? { running: true } : {})}
{...(p.chip ? { chip: p.chip } : {})}
{...(p.failed !== undefined ? { failed: p.failed } : {})}
{...(p.cancelled !== undefined ? { cancelled: p.cancelled } : {})}
preview={p.preview ? presentedPreviewNode(msg, p.preview) : undefined}
expandable={p.body.kind !== "none"}
>
);
}
function ExecRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
const computeLabel = useTimelineComputeLabel();
return (
);
}
function WriteStdinRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
return ;
}
function ApplyPatchRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
const presentation = applyPatchPresentation(msg, item);
return presentation ? (
) : (
);
}
function WebSearchRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
return ;
}
function AskRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
return ;
}
function RunOnRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
return ;
}
/**
* Finding machines, moving onto one and back, and using its screen. A look at
* the screen, or an action on it, shows the screenshot it took.
*/
function MachineRenderer({ item, loadRetainedScreenshot }: ToolRendererProps) {
const msg = useOpenGeniText();
const presentation = machinePresentation(msg, item);
const retained = mcpToolLeaf(item.name).startsWith("computer_")
? retainedScreenshotMetadata(item.output)
: null;
if (!retained?.available) return ;
return (
}
lightboxLabel={msg("timeline.toolRenderers.screenshot")}
batched={null}
failed={item.status === "failed"}
cancelled={item.status === "cancelled"}
/>
);
}
/**
* Baseline craft for unmatched tools: family icon + title-cased leaf + honest
* status preview (Running… / Done / error snippet). No argument-field sniffing —
* JSON stays in the expandable body only.
*
* A tool the shared presenter knows but no dedicated renderer claims (screen
* steps such as `cua_get_desktop_state`, `interaction_discover`) still reads
* the way the presenter words it, so the web row and other renderers agree.
*/
function UnreviewedGenericRenderer({ item, loadRetainedScreenshot }: ToolRendererProps) {
const msg = useOpenGeniText();
const details = useToolDetails();
const logo = useToolConnectorLogo(item.display);
const { images, output } = retainedToolResultImages(item.output);
if (images.length === 0 || item.status === "running") {
return (
);
}
// A tool that returned images shows them like a viewed image, with its
// ordinary result text (and any further images) in the expanded body.
const presentation = toolRowPresentation(msg, { ...item, output }, { details });
const Icon = toolIcon(presentation.icon);
const [first, ...rest] = images;
return (
} />}
lightboxLabel={presentation.title}
batched={null}
failed={presentation.failed ?? false}
cancelled={presentation.cancelled ?? false}
>
{rest.map((image, index) => (
}
lightboxLabel={presentation.title}
batched={null}
failed={false}
cancelled={false}
/>
))}
);
}
/* ---- computer_call --------------------------------------------------------- */
type ComputerAction = {
type?: string;
x?: number;
y?: number;
text?: string;
keys?: string[];
button?: string;
};
function computerVerb(msg: OpenGeniText, action: ComputerAction | undefined): string {
if (!action || !action.type) {
return msg("timeline.toolRenderers.acted");
}
switch (action.type) {
case "screenshot":
return msg("timeline.toolRenderers.screenshot");
case "click":
return msg("timeline.toolRenderers.clickedXY", { x: action.x, y: action.y });
case "double_click":
return msg("timeline.toolRenderers.doubleClickedXY", { x: action.x, y: action.y });
case "move":
return msg("timeline.toolRenderers.movedXY", { x: action.x, y: action.y });
case "scroll":
return msg("timeline.toolRenderers.scrolled");
case "type": {
const t = action.text ?? "";
return msg("timeline.toolRenderers.typedSliceValue", {
slice: t.slice(0, 28),
value: t.length > 28 ? "…" : "",
});
}
case "keypress":
return msg("timeline.toolRenderers.pressedJoin", { join: (action.keys ?? []).join("+") });
case "drag":
return msg("timeline.toolRenderers.dragged");
case "wait":
return msg("timeline.toolRenderers.waited");
default:
return action.type;
}
}
/** Coerce a function-tool arguments payload into the ComputerAction fields. */
function asComputerArgs(args: unknown): Partial {
if (!args) {
return {};
}
const parsed = typeof args === "string" ? tryParseJson(args) : args;
if (!parsed || typeof parsed !== "object") {
return {};
}
const record = parsed as Record;
return {
...(typeof record.x === "number" ? { x: record.x } : {}),
...(typeof record.y === "number" ? { y: record.y } : {}),
...(typeof record.text === "string" ? { text: record.text } : {}),
...(Array.isArray(record.keys) ? { keys: record.keys as string[] } : {}),
...(typeof record.button === "string" ? { button: record.button } : {}),
};
}
function ComputerCallRenderer({ item, loadRetainedScreenshot }: ToolRendererProps) {
const msg = useOpenGeniText();
const raw = (item.raw ?? {}) as {
action?: ComputerAction;
actions?: ComputerAction[];
providerData?: { approvalStatus?: string };
};
// Function-mode computer tools (computer_screenshot / computer_click / …,
// used on codex + chat-wire providers since the explicit tool-transport
// change) carry the action in the tool NAME + arguments instead of raw.action.
// Normalize them into the same ComputerAction shape so one renderer serves
// every transport.
const functionAction: ComputerAction | undefined =
!raw.action && item.name.startsWith("computer_") && item.name !== "computer_call"
? {
type: item.name.slice("computer_".length),
...asComputerArgs(item.arguments),
}
: undefined;
const action = raw.action ?? functionAction;
const actions = raw.actions ?? (action ? [action] : []);
const verb = computerVerb(msg, action);
const out = item.output;
const running = item.status === "running";
const rejected = raw.providerData?.approvalStatus === "rejected";
const readOnly = typeof out === "string" && out.includes("read-only");
const shotUrl = screenshotDataUrl(out);
const retained = retainedScreenshotMetadata(out);
const omittedMedia = mediaPreviewFact(out);
const empty = out === "" || out == null;
const batched = actions.length > 1 ? actions.map((a) => computerVerb(msg, a)).join(" · ") : null;
// Fold the batched-action count into the title (one media affordance per row),
// rather than a separate "+N more" mono label competing beside the thumbnail.
const countSuffix = actions.length > 1 ? ` ·${actions.length}` : "";
const isShot = action?.type === "screenshot";
if (running) {
return (
) : (
)
}
iconTone="running"
title={verb}
running
media={ }
>
{msg("timeline.toolRenderers.capturingFrame")}
);
}
if (readOnly) {
return (
}
iconTone="failed"
title={verb}
chip={{ tone: "bad", text: "read-only" }}
preview="write actions disabled"
>
{msg("timeline.toolRenderers.computerUseIsReadOnly")}
);
}
if (rejected) {
return (
}
iconTone="muted"
title={verb}
preview={msg("timeline.toolRenderers.approvalRejectedThisActionDid2")}
>
{msg("timeline.toolRenderers.approvalRejectedThisActionDid")}
);
}
const isFailed = item.status === "failed";
const isCancelled = item.status === "cancelled";
if (retained) {
if (!retained.available) {
const state =
retained.reason === "expired" || retained.reason === "deleted"
? retained.reason
: "unavailable";
return (
}
iconTone={isFailed ? "failed" : "muted"}
title={`${verb}${countSuffix} · ${state}`}
failed={isFailed}
cancelled={isCancelled}
preview={`screenshot ${state}`}
media={ }
>
{msg("timeline.toolRenderers.screenshotStateReplaceall", {
state,
replaceAll: retained.reason.replaceAll("_", " "),
})}
);
}
return (
}
lightboxLabel={msg("timeline.toolRenderers.screenshot")}
batched={batched}
failed={isFailed}
cancelled={isCancelled}
/>
);
}
if (shotUrl) {
const caption = `${verb}${actions.length > 1 ? ` (+${actions.length - 1} more)` : ""}`;
return (
) : (
)
}
iconTone={isFailed ? "failed" : "accent"}
title={`${verb}${countSuffix}`}
failed={isFailed}
cancelled={isCancelled}
media={ }
>
{batched ? (
{msg("timeline.toolRenderers.batchedBatched", { batched })}
) : null}
);
}
if (omittedMedia) {
return (
}
iconTone={isFailed ? "failed" : "muted"}
title={msg("timeline.toolRenderers.verbCountsuffixImageOmittedNot", { verb, countSuffix })}
failed={isFailed}
cancelled={isCancelled}
preview={msg("timeline.toolRenderers.inlineImageOmittedNotRetained")}
media={ }
>
{msg("timeline.toolRenderers.theInlineMediatypeOutputWas", {
mediaType: omittedMedia.mediaType,
})}
{batched ? (
{msg("timeline.toolRenderers.batchedBatched", { batched })}
) : null}
);
}
if (empty) {
return (
}
iconTone={isFailed ? "failed" : "muted"}
title={verb}
failed={isFailed}
cancelled={isCancelled}
media={ }
>
{isFailed
? msg("timeline.toolRenderers.computerCallFailedNoImage")
: isCancelled
? msg("timeline.toolRenderers.computerCallInterruptedNoImage")
: msg("timeline.toolRenderers.noImageTheSessionReturned")}
);
}
// a non-screenshot action whose output is not an image (click/keypress)
return (
}
iconTone={isFailed ? "failed" : "accent"}
title={verb}
failed={isFailed}
cancelled={isCancelled}
preview={batched ?? undefined}
expandable={batched != null}
>
{batched ? {batched} : null}
);
}
/** Browser tool images share authenticated screenshot loading, with their own media kind. */
function BrowserScreenshotRenderer(props: ToolRendererProps) {
const msg = useOpenGeniText();
const { item, loadRetainedScreenshot } = props;
const leaf = mcpToolLeaf(item.name);
const title =
leaf === "browser_observe"
? msg("timeline.toolRenderers.observedBrowser")
: leaf === "browser_act"
? msg("timeline.toolRenderers.usedBrowser")
: msg("timeline.toolRenderers.browserScreenshot");
const retained = retainedScreenshotMetadata(item.output);
const isFailed = item.status === "failed";
const isCancelled = item.status === "cancelled";
if (item.status === "running" && leaf === "browser_screenshot") {
return (
}
iconTone="running"
title={title}
running
media={ }
>
{msg("timeline.toolRenderers.capturingFrame")}
);
}
if (!retained) return ;
if (!retained.available) {
const state =
retained.reason === "expired" || retained.reason === "deleted"
? retained.reason
: "unavailable";
return (
}
iconTone={isFailed ? "failed" : "muted"}
title={`${title} · ${state}`}
failed={isFailed}
cancelled={isCancelled}
preview={`screenshot ${state}`}
media={ }
>
{msg("timeline.toolRenderers.screenshotStateReplaceall", {
state,
replaceAll: retained.reason.replaceAll("_", " "),
})}
);
}
return (
}
lightboxLabel={msg("timeline.toolRenderers.browserScreenshot")}
batched={null}
failed={isFailed}
cancelled={isCancelled}
/>
);
}
type RetainedSessionImageDisclosureProps = {
artifact: RetainedArtifactReference;
load: ToolRendererProps["loadRetainedArtifact"];
title: string;
caption: string;
noun: "image" | "screenshot";
icon: ReactNode;
lightboxLabel: string;
batched: string | null;
failed: boolean;
cancelled: boolean;
filename?: string;
defaultOpen?: boolean;
children?: ReactNode;
};
function RetainedSessionImageDisclosure(props: RetainedSessionImageDisclosureProps) {
const compact = useContext(CompactActivityContext);
// The rolling progress label has no screenshot loader by design. Do not run
// the full image hook there: it would report the missing loader as an error.
if (compact) {
return (
);
}
return ;
}
function LoadedRetainedSessionImageDisclosure({
artifact,
load,
title,
caption,
noun,
icon,
lightboxLabel,
batched,
failed,
cancelled,
filename,
defaultOpen,
children,
}: RetainedSessionImageDisclosureProps) {
const msg = useOpenGeniText();
const state = useRetainedImageObjectUrl(artifact, load);
const downloadFilename = filename ?? retainedImageFilename(artifact);
const figure = {
src: state.kind === "ready" ? state.url : "",
caption,
alt: caption,
expandLabel: msg("timeline.toolRenderers.expandNoun", { noun }),
lightboxLabel,
downloadFilename,
};
return (
) : state.kind === "loading" ? (
) : (
)
}
>
{state.kind === "ready" ? (
) : state.kind === "loading" ? (
{msg("timeline.toolRenderers.loadingTheRetainedNoun", { noun })}
) : state.kind === "unavailable" ? (
{noun === "screenshot"
? msg("timeline.toolRenderers.screenshot")
: msg("timeline.toolRenderers.image")}{" "}
{state.label}.
) : (
)}
{batched ? (
{msg("timeline.toolRenderers.batchedBatched", { batched })}
) : null}
{children}
);
}
function ImageRetrievalError({ noun = "image", retry }: { noun?: string; retry: () => void }) {
const msg = useOpenGeniText();
return (
{noun === "screenshot"
? msg("timeline.toolRenderers.screenshot")
: msg("timeline.toolRenderers.image")}{" "}
{msg("timeline.toolRenderers.retrievalFailed")}{" "}
{msg("timeline.toolRenderers.retry")}
);
}
function GeneratedImageRenderer({ item, loadRetainedArtifact }: ToolRendererProps) {
const msg = useOpenGeniText();
const args = parseToolArgs(item.arguments);
const prompt = typeof args.prompt === "string" ? args.prompt : "";
const raw =
item.raw && typeof item.raw === "object" && !Array.isArray(item.raw)
? (item.raw as Record)
: null;
// Function tools settle through agent.toolCall.output; OpenAI's hosted image
// call is already complete on agent.toolCall.created and carries the compact
// receipt in raw.output. Both paths deliberately converge on one renderer.
const receipt = generatedImageReceipt(item.output) ?? generatedImageReceipt(raw?.output);
if (item.status === "running") {
return (
}
iconTone="running"
title={msg("timeline.toolRenderers.generatingImage")}
running
preview={
{truncatePreview(prompt, 72) || msg("timeline.toolRenderers.creating")}
}
media={ }
>
{prompt ? {prompt} : null}
);
}
if (!receipt) return ;
return (
);
}
function GeneratedVideoRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
const args = parseToolArgs(item.arguments);
const prompt = typeof args.prompt === "string" ? args.prompt : "";
const parsedOutput = typeof item.output === "string" ? tryParseJson(item.output) : item.output;
const accepted =
parsedOutput &&
typeof parsedOutput === "object" &&
!Array.isArray(parsedOutput) &&
(parsedOutput as Record).status === "accepted";
const failed = item.status === "failed";
const cancelled = item.status === "cancelled";
const running = item.status === "running";
return (
}
iconTone={failed ? "failed" : running ? "running" : accepted ? "accent" : "muted"}
title={
running
? msg("timeline.toolRenderers.startingVideoGeneration")
: accepted
? msg("timeline.toolRenderers.generatingVideo")
: msg("timeline.toolRenderers.generateVideo")
}
running={running}
failed={failed}
cancelled={cancelled}
preview={
truncatePreview(prompt, 88) ||
(accepted ? msg("timeline.toolRenderers.requestAccepted") : undefined)
}
>
{prompt ? {prompt} : null}
{accepted ? (
{msg("timeline.toolRenderers.theVideoWillAppearHere")}
) : item.output !== undefined ? (
) : null}
);
}
function SandboxFilePublishRenderer({ item, loadRetainedArtifact }: ToolRendererProps) {
const msg = useOpenGeniText();
const plain = useToolDetails() === "plain";
const { text: output, isError } = unwrapMcpOutput(item.output);
const receipt = parseSandboxFileArtifactReceipt(output);
const [downloadState, setDownloadState] = useState<"idle" | "loading" | "error">("idle");
if (item.status === "running") {
return (
}
iconTone="running"
title={msg("timeline.toolRenderers.publishingFile")}
running
preview={
{msg("timeline.toolRenderers.retainingWorkspaceBytes")}
}
/>
);
}
if (!receipt || isError || item.status === "failed") {
return ;
}
// The closed SDK receipt has already checked the workspace-qualified route.
const workspaceId = /^\/v1\/workspaces\/([0-9a-f-]+)\/artifacts\//.exec(
receipt.artifact.retrieval.path,
)?.[1];
const openLink = workspaceId ? (
event.stopPropagation()}
onKeyDown={(event) => event.stopPropagation()}
>
{msg("timeline.toolRenderers.openInArtifacts")}
) : null;
const download = async () => {
if (!loadRetainedArtifact) {
setDownloadState("error");
return;
}
setDownloadState("loading");
let objectUrl: string | null = null;
try {
const source = await loadRetainedArtifact(receipt.artifact, new AbortController().signal);
if (!source) throw new Error("artifact unavailable");
const url =
source instanceof Uint8Array
? (objectUrl = URL.createObjectURL(
new Blob([source as unknown as BlobPart], {
type: receipt.artifact.contentType,
}),
))
: source.url;
const anchor = document.createElement("a");
anchor.href = url;
anchor.download = receipt.filename;
anchor.rel = "noopener";
anchor.click();
setDownloadState("idle");
} catch {
setDownloadState("error");
} finally {
const urlToRevoke = objectUrl;
if (urlToRevoke) setTimeout(() => URL.revokeObjectURL(urlToRevoke), 0);
}
};
const downloadButton = (
void download()}
disabled={downloadState === "loading"}
className="inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2.5 py-1.5 text-og-sm font-medium text-og-fg transition-colors hover:border-og-border-strong hover:bg-og-surface-2 disabled:cursor-wait disabled:opacity-60"
>
{downloadState === "loading"
? msg("timeline.toolRenderers.preparing")
: downloadState === "error"
? msg("timeline.toolRenderers.retryDownload")
: msg("timeline.toolRenderers.download")}
);
if (isRetainedImageContentType(receipt.artifact.contentType)) {
return (
}
lightboxLabel={msg("timeline.toolRenderers.image")}
batched={null}
failed={false}
cancelled={false}
filename={receipt.filename}
defaultOpen
>
{downloadButton}
{openLink}
);
}
return (
}
iconTone="accent"
title={msg("timeline.toolRenderers.publishedFilename", { filename: receipt.filename })}
defaultOpen
preview={formatBytes(receipt.artifact.originalBytes)}
>
{downloadButton}
{openLink}
{plain ? null : isPatchFilename(receipt.filename) ? (
) : null}
);
}
type PublishedSiteReceipt = {
workspaceId: string;
artifactId: string;
title: string;
revision: number;
replayed: boolean;
};
function publishedSiteReceipt(output: unknown): PublishedSiteReceipt | null {
const { text, isError } = unwrapMcpOutput(output);
if (isError) return null;
const parsed = tryParseJson(text);
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
const artifact = (parsed as Record).artifact;
const version = (parsed as Record).version;
if (
!artifact ||
typeof artifact !== "object" ||
Array.isArray(artifact) ||
!version ||
typeof version !== "object" ||
Array.isArray(version)
) {
return null;
}
const artifactRecord = artifact as Record;
const versionRecord = version as Record;
if (
typeof artifactRecord.workspaceId !== "string" ||
typeof artifactRecord.id !== "string" ||
typeof artifactRecord.title !== "string" ||
typeof versionRecord.revision !== "number" ||
!Number.isInteger(versionRecord.revision) ||
versionRecord.revision < 1
) {
return null;
}
return {
workspaceId: artifactRecord.workspaceId,
artifactId: artifactRecord.id,
title: artifactRecord.title,
revision: versionRecord.revision,
replayed: (parsed as Record).replayed === true,
};
}
const SITE_OPEN_CLASS =
"inline-flex min-h-7 items-center rounded-og-sm px-2 text-og-sm font-medium text-og-accent-strong hover:bg-og-surface-2 hover:underline focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:min-h-10";
function SiteOpenLink({ receipt }: { receipt: PublishedSiteReceipt }) {
const msg = useOpenGeniText();
const [pending, setPending] = useState(false);
const [failed, setFailed] = useState(false);
// The console route only exists in the Opengeni console; a host decides.
const resolution = useOpenGeniLinkResolver()?.({
kind: "site",
artifactId: receipt.artifactId,
workspaceId: receipt.workspaceId,
});
const destination = resolution?.href ? defaultUrlTransform(resolution.href) : "";
if (destination) {
return (
event.stopPropagation()}
onKeyDown={(event) => event.stopPropagation()}
>
{msg("timeline.toolRenderers.open")}
);
}
if (resolution?.open) {
const open = resolution.open;
return (
{
event.stopPropagation();
if (pending) return;
setPending(true);
setFailed(false);
void Promise.resolve()
.then(open)
.catch(() => setFailed(true))
.finally(() => setPending(false));
}}
onKeyDown={(event) => event.stopPropagation()}
>
{pending
? msg("timeline.toolRenderers.opening")
: failed
? msg("timeline.toolRenderers.retryOpen")
: msg("timeline.toolRenderers.open")}
);
}
return null;
}
function SiteArtifactRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
const leaf = mcpToolLeaf(item.name);
const publishingExisting = leaf === "artifacts_publish";
if (item.status === "running") {
return (
}
iconTone="running"
title={
publishingExisting
? msg("timeline.toolRenderers.publishingSiteUpdate")
: msg("timeline.toolRenderers.publishingSite")
}
running
preview={
{msg("timeline.toolRenderers.retainingSourceAndCompiledHtml")}
}
/>
);
}
const receipt = publishedSiteReceipt(item.output);
if (!receipt || item.status === "failed") return ;
return (
}
iconTone="accent"
title={
publishingExisting
? msg("timeline.toolRenderers.updatedTitle", { title: receipt.title })
: msg("timeline.toolRenderers.publishedTitle", { title: receipt.title })
}
media={ }
>
{msg("timeline.toolRenderers.versionRevisionIsLive", { revision: receipt.revision })}
{receipt.replayed
? ` ${msg("timeline.toolRenderers.replayedFromTheOriginalPublication")}`
: "."}
);
}
function GeneratedImageDisclosure({
receipt,
load,
prompt,
failed,
cancelled,
}: {
receipt: NonNullable>;
load: ToolRendererProps["loadRetainedArtifact"];
prompt: string;
failed: boolean;
cancelled: boolean;
}) {
const msg = useOpenGeniText();
const state = useRetainedImageObjectUrl(receipt.artifact, load);
const dimensions = receipt.artifact.dimensions!;
const title = failed
? msg("timeline.toolRenderers.imageGenerationFailed")
: msg("timeline.toolRenderers.generatedImage");
const caption =
prompt ||
msg("timeline.toolRenderers.generatedImageWidthHeight", {
width: dimensions.width,
height: dimensions.height,
});
return (
}
iconTone={failed ? "failed" : state.kind === "ready" ? "accent" : "muted"}
title={title}
defaultOpen={!failed && !cancelled}
failed={failed}
cancelled={cancelled}
preview={
state.kind === "loading"
? msg("timeline.toolRenderers.loadingImage")
: state.kind === "error"
? msg("timeline.toolRenderers.imageRetrievalFailed")
: state.kind === "unavailable"
? `image ${state.label}`
: truncatePreview(prompt, 88) || `${dimensions.width}×${dimensions.height}`
}
media={
state.kind === "ready" ? (
) : state.kind === "loading" ? (
) : (
)
}
>
{state.kind === "ready" ? (
) : state.kind === "loading" ? (
{msg("timeline.toolRenderers.loadingTheGeneratedImage")}
) : state.kind === "unavailable" ? (
{msg("timeline.toolRenderers.imageLabel", { label: state.label })}
) : (
)}
{dimensions.width}×{dimensions.height} · {receipt.sandboxPath}
);
}
function retainedImageFilename(artifact: RetainedArtifactReference): string {
const extension =
artifact.contentType === "image/jpeg"
? "jpg"
: artifact.contentType === "image/webp"
? "webp"
: "png";
return `${artifact.kind}-${artifact.artifactId}.${extension}`;
}
/* ---- web_search ------------------------------------------------------------ */
/* ---- view_image ------------------------------------------------------------ */
// Fragments of the tool's own (English) error output; matched, never displayed.
const VIEW_IMAGE_ERRORS = (msg: OpenGeniText) => [
msg("timeline.toolRenderers.wasNotFound"),
msg("timeline.toolRenderers.isNotAFile"),
msg("timeline.toolRenderers.exceededTheAllowedSize"),
msg("timeline.toolRenderers.isNotASupportedImage"),
msg("timeline.toolRenderers.unableToReadImage"),
];
function ViewImageRenderer({ item, loadRetainedScreenshot }: ToolRendererProps) {
const msg = useOpenGeniText();
const args = parseToolArgs(item.arguments);
const path = typeof args.path === "string" ? args.path : "";
const out = item.output;
const text = typeof out === "string" ? out : "";
const retained = retainedScreenshotMetadata(out);
const omittedMedia = mediaPreviewFact(out);
if (item.status === "running") {
return (
}
iconTone="running"
title={msg("timeline.toolRenderers.viewPathbasename", { pathBasename: pathBasename(path) })}
running
preview={{msg("timeline.toolRenderers.reading")} }
media={ }
>
{msg("timeline.toolRenderers.readingImage")}
);
}
const viewFailed = item.status === "failed";
const viewCancelled = item.status === "cancelled";
if (retained) {
const title = msg("timeline.toolRenderers.viewedPathbasename", {
pathBasename: pathBasename(path),
});
if (!retained.available) {
const state =
retained.reason === "expired" || retained.reason === "deleted"
? retained.reason
: "unavailable";
return (
}
iconTone={viewFailed ? "failed" : "muted"}
title={`${title} · ${state}`}
failed={viewFailed}
cancelled={viewCancelled}
preview={`image ${state}`}
media={ }
>
{msg("timeline.toolRenderers.imageStateReplaceall", {
state,
replaceAll: retained.reason.replaceAll("_", " "),
})}
);
}
return (
}
lightboxLabel={msg("timeline.toolRenderers.image")}
batched={null}
failed={viewFailed}
cancelled={viewCancelled}
/>
);
}
const errMatch = VIEW_IMAGE_ERRORS(msg).find((p) => text.includes(p));
if (errMatch) {
const tooBig = text.includes("exceeded the allowed size");
return (
}
iconTone="failed"
title={msg("timeline.toolRenderers.viewPathbasename", { pathBasename: pathBasename(path) })}
chip={{
tone: "bad",
text: tooBig ? msg("timeline.toolRenderers.tooLarge") : msg("timeline.chip.error"),
}}
preview={text}
>
{text}
);
}
if (text.startsWith("OpenAI file reference:")) {
return (
}
iconTone={viewFailed ? "failed" : "muted"}
title={msg("timeline.toolRenderers.viewedPathbasename", {
pathBasename: pathBasename(path),
})}
failed={viewFailed}
cancelled={viewCancelled}
preview={path}
>
{text}
);
}
if (omittedMedia) {
return (
}
iconTone={viewFailed ? "failed" : "muted"}
title={msg("timeline.toolRenderers.viewedPathbasenameImageOmittedNot", {
pathBasename: pathBasename(path),
})}
failed={viewFailed}
cancelled={viewCancelled}
preview={msg("timeline.toolRenderers.inlineImageOmittedNotRetained")}
media={ }
>
{msg("timeline.toolRenderers.theInlineMediatypeOutputWas", {
mediaType: omittedMedia.mediaType,
})}
);
}
if (text.includes("No image data")) {
return (
}
iconTone={viewFailed ? "failed" : "muted"}
title={msg("timeline.toolRenderers.viewedPathbasename", {
pathBasename: pathBasename(path),
})}
failed={viewFailed}
cancelled={viewCancelled}
preview={msg("timeline.toolRenderers.noImage")}
>
{viewFailed
? msg("timeline.toolRenderers.viewImageFailedNoImage")
: viewCancelled
? msg("timeline.toolRenderers.viewImageInterrupted")
: msg("timeline.toolRenderers.noImageTheSandboxSession")}
);
}
if (text.startsWith("data:")) {
return (
}
iconTone={viewFailed ? "failed" : "accent"}
title={msg("timeline.toolRenderers.viewedPathbasename", {
pathBasename: pathBasename(path),
})}
failed={viewFailed}
cancelled={viewCancelled}
media={ }
>
);
}
return ;
}
/* ---- environment_set_variable (secret-safe, write-only) -------------------- */
/** Plain tool details read this tool through the shared row model (no raw detail). */
function SecretSetRenderer(props: ToolRendererProps) {
return useToolDetails() === "plain" ? (
) : (
);
}
function FullSecretSetRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
const args = parseToolArgs(item.arguments);
const name = typeof args.name === "string" ? args.name : "variable";
if (item.status === "running") {
return (
}
iconTone="running"
title={msg("timeline.toolRenderers.setName", { name })}
running
preview={{msg("timeline.toolRenderers.setting")} }
>
);
}
if (item.status === "failed") {
const errorText = typeof item.output === "string" ? item.output : null;
return (
}
iconTone="failed"
title={msg("timeline.toolRenderers.setName", { name })}
failed
preview={errorText ?? msg("timeline.toolRenderers.variableWriteFailed")}
>
{errorText ? (
) : (
{msg("timeline.toolRenderers.theToolCallFailedWith")}
)}
);
}
return (
}
iconTone="muted"
title={msg("timeline.toolRenderers.setName", { name })}
cancelled={item.status === "cancelled"}
preview="exact value preserved"
>
{msg("timeline.toolRenderers.theConfiguredValueIsPreserved")}
);
}
/* ---- tool_search (progressive MCP disclosure) ------------------------------ */
/** Plain tool details read this tool through the shared row model (no raw detail). */
function ToolSearchRenderer(props: ToolRendererProps) {
return useToolDetails() === "plain" ? (
) : (
);
}
function FullToolSearchRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
const query = toolSearchQuery(item);
const icon = ;
const running = item.status === "running";
const queryPreview = query ? truncatePreview(query, 64) : "";
if (running) {
return (
{queryPreview}
) : (
{msg("timeline.toolRenderers.matchingCapabilities")}
)
}
>
{query ? (
{msg("timeline.toolRenderers.capabilityQueryQuery", { query })}
) : null}
);
}
const { text: outText, isError } = unwrapMcpOutput(item.output);
if ((isError || item.status === "failed") && item.status !== "cancelled") {
return (
{query ? (
{msg("timeline.toolRenderers.capabilityQueryQuery", { query })}
) : null}
);
}
const tools = parseDisclosedTools(item.output);
const preview = toolSearchPreview(msg, tools, item.status === "cancelled");
return (
{query ? (
{msg("timeline.toolRenderers.capabilityQueryQuery", { query })}
) : null}
{tools && tools.length > 0 ? (
{tools.slice(0, 12).map((tool) => (
{tool.source ? (
{tool.source}
) : null}
{tool.leaf}
))}
{tools.length > 12 ? (
+{tools.length - 12} {msg("timeline.toolRenderers.more")}
) : null}
) : tools && tools.length === 0 ? (
{msg("timeline.toolRenderers.noDeferredToolsMatchedThis")}
) : null}
{tools == null && outText ? (
) : null}
);
}
/* ---- docs / knowledge search ----------------------------------------------- */
/** Plain tool details read this tool through the shared row model (no raw detail). */
function DocsSearchRenderer(props: ToolRendererProps) {
return useToolDetails() === "plain" ? (
) : (
);
}
function FullDocsSearchRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
const args = parseToolArgs(item.arguments);
const query = typeof args.query === "string" ? args.query.trim() : "";
const title = query
? msg("timeline.toolRenderers.searchTruncatepreview", {
truncatePreview: truncatePreview(query, 48),
})
: toolDisplayName(msg, item.name, item.display);
const running = item.status === "running";
if (running) {
return (
}
iconTone="running"
title={title}
running
preview={{msg("timeline.toolRenderers.searching")} }
>
);
}
const { text: outText, isError } = unwrapMcpOutput(item.output);
if ((isError || item.status === "failed") && item.status !== "cancelled") {
return (
}
iconTone="failed"
title={title}
failed
preview={truncatePreview(outText, 80) || msg("timeline.toolRenderers.searchFailed")}
>
);
}
const hits = parseSearchHits(msg, outText);
const preview =
item.status === "cancelled"
? undefined
: hits
? hits.length === 0
? msg("timeline.toolRenderers.noHits")
: msg("counts.hits", { count: hits.length })
: msg("timeline.toolRenderers.done");
return (
}
iconTone="muted"
title={title}
cancelled={item.status === "cancelled"}
preview={preview}
>
{hits && hits.length > 0 ? (
{hits.slice(0, 8).map((hit) => (
{hit.title}
{hit.snippet ? (
{hit.snippet}
) : null}
))}
) : null}
);
}
/* ---- set_session_title / set_other_session_title --------------------------- */
/** Plain tool details read this tool through the shared row model (no raw detail). */
function SetSessionTitleRenderer(props: ToolRendererProps) {
return useToolDetails() === "plain" ? (
) : (
);
}
function FullSetSessionTitleRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
const args = parseToolArgs(item.arguments);
const titleArg = typeof args.title === "string" ? args.title.trim() : "";
const display = toolDisplayName(msg, item.name, item.display);
const previewTitle = titleArg ? truncatePreview(titleArg, 72) : "";
const icon = ;
if (item.status === "running") {
return (
{previewTitle}
) : (
{msg("timeline.toolRenderers.settingTitle")}
)
}
>
);
}
const { text: outText, isError } = unwrapMcpOutput(item.output);
if ((isError || item.status === "failed") && item.status !== "cancelled") {
return (
);
}
// Prefer the submitted title; fall back to a title field in the tool result.
let settledTitle = previewTitle;
if (!settledTitle) {
const parsed = tryParseJson(outText);
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
const fromResult = (parsed as { title?: unknown }).title;
if (typeof fromResult === "string" && fromResult.trim()) {
settledTitle = truncatePreview(fromResult.trim(), 72);
}
}
}
return (
{outText ? (
) : null}
);
}
/* ---- company memory propose (docs MCP) ------------------------------------- */
/** Plain tool details read this tool through the shared row model (no raw detail). */
function MemoryProposeRenderer(props: ToolRendererProps) {
return useToolDetails() === "plain" ? (
) : (
);
}
function FullMemoryProposeRenderer({ item }: ToolRendererProps) {
const msg = useOpenGeniText();
const args = parseToolArgs(item.arguments);
const text = typeof args.text === "string" ? args.text.trim() : "";
const title = msg("timeline.toolRenderers.proposeMemory");
const running = item.status === "running";
if (running) {
return (
}
iconTone="running"
title={title}
running
preview={{msg("timeline.toolRenderers.proposing")} }
>
);
}
const { text: outText, isError } = unwrapMcpOutput(item.output);
if ((isError || item.status === "failed") && item.status !== "cancelled") {
return (
}
iconTone="failed"
title={title}
failed
preview={truncatePreview(outText, 80) || msg("timeline.toolRenderers.proposeFailed")}
>
{text ? {text} : null}
);
}
return (
}
iconTone="muted"
title={title}
cancelled={item.status === "cancelled"}
preview={text ? truncatePreview(text, 90) : msg("timeline.toolRenderers.done")}
>
{text ? {text} : null}
);
}
/* ---- request_human_input --------------------------------------------------- */
/* ---- run_on ---------------------------------------------------------------- */
/* ---- generic fallback (first-party MCP, external MCP, unknown) ------------- */
/**
* Baseline craft for unmatched tools: family icon + title-cased leaf + honest
* status preview (Running… / Done / error snippet). No argument-field sniffing —
* JSON stays in the expandable body only.
*/
function GenericRenderer(props: ToolRendererProps) {
const reviewed = useHasToolReview(props.item.callId);
if (reviewed && props.item.callId) return ;
return ;
}
/** Settled review states earn one quiet gutter word; success and waiting stay chip-free. */
const REVIEW_CHIP = (msg: OpenGeniText): Partial> => ({
rejected: { tone: "interrupted", text: msg("timeline.chip.declined") },
cancelled: { tone: "interrupted", text: msg("timeline.toolRenderers.notRun") },
expired: { tone: "interrupted", text: msg("timeline.chip.expired") },
stale: { tone: "interrupted", text: msg("timeline.toolRenderers.notRun") },
revoked: { tone: "interrupted", text: msg("timeline.toolRenderers.notRun") },
blocked: { tone: "interrupted", text: msg("timeline.chip.blocked") },
unknown: { tone: "bad", text: msg("timeline.toolRenderers.outcomeUnknown") },
partial: { tone: "bad", text: msg("timeline.toolRenderers.partlyDone") },
failed: { tone: "bad", text: msg("timeline.chip.failed") },
});
/**
* A call that went through approval keeps the ordinary row shape, titled with
* what was approved. The expanded body is the saved review plus the result.
*/
function ReviewedGenericRenderer(props: ToolRendererProps) {
const msg = useOpenGeniText();
const { item } = props;
const { review, onViewDetails } = useRecordedToolReview(item.callId);
const logo = useToolConnectorLogo(item.display);
if (!review) return ;
const ReviewIcon = toolIcon(genericToolIconKind(item.name));
const icon = } />;
const waiting = review.status === "pending";
const running =
!waiting &&
(review.status === "executing" || review.status === "approved") &&
item.status === "running";
const { text: outText, isError } = unwrapMcpOutput(retainedToolResultImages(item.output).output);
const chip =
REVIEW_CHIP(msg)[review.status] ??
(isError && !running && !waiting
? ({ tone: "bad", text: msg("timeline.chip.error") } as const)
: undefined);
return (
{msg("timeline.toolRenderers.running")}
) : item.display?.connector ? (
// The logo names the connector; only a second account needs words.
(item.display.accountLabel ?? undefined)
) : (
(review.accountLabel ?? undefined)
)
}
>
{outText ? (
) : null}
);
}
/* ---- the default registry -------------------------------------------------- */
function KnowledgeSaveRenderer({ item }: ToolRendererProps) {
const output = unwrapMcpOutput(item.output);
const parsed = tryParseJson(output.text);
if (item.status === "running" || output.isError || !parsed || typeof parsed !== "object")
return ;
const value = parsed as Record;
const receipt = (value.status === "retained" ? value.receipt : value) as
| Record
| undefined;
if (
!receipt ||
typeof receipt.entryId !== "string" ||
!["published", "pending", "rejected", "archived"].includes(String(receipt.outcome))
)
return ;
const args = parseToolArgs(item.arguments);
const entry = args.entry as Record | undefined;
return (
);
}
const BASE_ENTRIES: ToolRegistryEntry[] = [
...[
"knowledge_save",
"knowledge_archive",
"knowledge_retain_file",
"knowledge_retain_message",
"task_note_promote_knowledge",
].flatMap((name) =>
[name, `opengeni__${name}`, `mcp__opengeni__${name}`].map((trustedName) => ({
match: "name" as const,
name: trustedName,
matchPrefixedLeaf: false,
render: KnowledgeSaveRenderer,
})),
),
// Provider-native items carry `raw.type` on the wire — this is their source of
// truth and is consulted first by the registry.
{ match: "rawType", type: "apply_patch_call", render: ApplyPatchRenderer },
{ match: "rawType", type: "computer_call", render: ComputerCallRenderer },
{ match: "rawType", type: "tool_search_call", render: ToolSearchRenderer },
// First-party sandbox + MCP tools resolve by name (exact or MCP leaf).
{ match: "name", name: "exec_command", render: ExecRenderer },
{ match: "name", name: "request_human_input", render: AskRenderer },
{ match: "name", name: "run_on", render: RunOnRenderer },
{ match: "name", name: "sandboxes_list", render: MachineRenderer },
{ match: "name", name: "sandbox_swap", render: MachineRenderer },
{ match: "name", name: "computer_open", render: MachineRenderer },
{ match: "name", name: "computer_observe", render: MachineRenderer },
{ match: "name", name: "computer_act", render: MachineRenderer },
{ match: "name", name: "write_stdin", render: WriteStdinRenderer },
{ match: "name", name: "apply_patch_call", render: ApplyPatchRenderer },
{ match: "name", name: "apply_patch", render: ApplyPatchRenderer },
{ match: "name", name: "computer_call", render: ComputerCallRenderer },
{
match: "name",
name: "browser_screenshot",
render: BrowserScreenshotRenderer,
},
{ match: "name", name: "browser_observe", render: BrowserScreenshotRenderer },
{ match: "name", name: "browser_act", render: BrowserScreenshotRenderer },
// Function-mode computer tools (codex / chat-wire transports).
{ match: "name", name: "computer_screenshot", render: ComputerCallRenderer },
{ match: "name", name: "computer_click", render: ComputerCallRenderer },
{
match: "name",
name: "computer_double_click",
render: ComputerCallRenderer,
},
{ match: "name", name: "computer_move", render: ComputerCallRenderer },
{ match: "name", name: "computer_scroll", render: ComputerCallRenderer },
{ match: "name", name: "computer_type", render: ComputerCallRenderer },
{ match: "name", name: "computer_keypress", render: ComputerCallRenderer },
{ match: "name", name: "computer_drag", render: ComputerCallRenderer },
{ match: "name", name: "web_search_call", render: WebSearchRenderer },
{
match: "name",
name: "image_generation_call",
render: GeneratedImageRenderer,
},
{ match: "name", name: "generate_image", render: GeneratedImageRenderer },
{ match: "name", name: "generate_video", render: GeneratedVideoRenderer },
{ match: "name", name: "tool_search", render: ToolSearchRenderer },
{ match: "name", name: "view_image", render: ViewImageRenderer },
{
match: "name",
name: "sandbox_file_publish",
render: SandboxFilePublishRenderer,
},
{
match: "name",
name: "artifacts_create",
render: SiteArtifactRenderer,
matchPrefixedLeaf: false,
},
{
match: "name",
name: "artifacts_publish",
render: SiteArtifactRenderer,
matchPrefixedLeaf: false,
},
{
match: "name",
name: "opengeni__artifacts_create",
render: SiteArtifactRenderer,
matchPrefixedLeaf: false,
},
{
match: "name",
name: "opengeni__artifacts_publish",
render: SiteArtifactRenderer,
matchPrefixedLeaf: false,
},
{
match: "name",
name: "environment_set_variable",
render: SecretSetRenderer,
},
{
match: "name",
name: "variable_set_set_variable",
render: SecretSetRenderer,
},
{ match: "name", name: "search_documents", render: DocsSearchRenderer },
{ match: "name", name: "knowledge_search", render: DocsSearchRenderer },
{ match: "name", name: "memory_propose", render: MemoryProposeRenderer },
{ match: "name", name: "set_session_title", render: SetSessionTitleRenderer },
{
match: "name",
name: "set_other_session_title",
render: SetSessionTitleRenderer,
},
];
/** Built-in renderers that draw their row from the shared presentation. */
const PRESENTATION_RENDERERS: ReadonlyMap = new Map<
ToolRenderer,
PresentedToolKind
>([
[ExecRenderer, "exec"],
[WriteStdinRenderer, "write_stdin"],
[ApplyPatchRenderer, "apply_patch"],
[GenericRenderer, "generic"],
]);
/**
* Whether `renderer` can draw `item` while its output is a bounded preview
* (see {@link presentsToolOutputPreview}). Every other row (media, receipts,
* cards that parse their result, consumer renderers) needs its exact output
* before it renders.
*/
export function rendersToolOutputPreview(renderer: ToolRenderer, item: ToolCallItem): boolean {
if (!item.outputPreview) return true;
return (
PRESENTATION_RENDERERS.get(renderer) === presentedToolKind(item) &&
presentsToolOutputPreview(item)
);
}
/** The built-in tool renderer registry: every first-party tool plus a fallback. */
export const defaultToolRegistry: ToolRegistry = createToolRegistry(BASE_ENTRIES, GenericRenderer);
/** Build a registry that extends the built-ins with consumer entries/fallback. */
export function createDefaultToolRegistry(
options: Parameters[2] = {},
): ToolRegistry {
return createToolRegistry(BASE_ENTRIES, GenericRenderer, options);
}