Files
orcs-code/src/components/Message.tsx
Anandan 462a985d7e Remove embedded source map directives from tracked sources (#329)
Inline base64 source maps had been checked into tracked src files. This strips those comments from the repository without changing runtime behavior or adding ongoing guardrails, per the requested one-time cleanup scope.

Constraint: Keep this change limited to tracked source cleanup only
Rejected: Add CI/source verification guard | user requested one-time cleanup only
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: If these directives reappear, fix the producing transform instead of reintroducing repo-side cleanup code
Tested: rg -n "sourceMappingURL" ., bun run smoke, bun run verify:privacy, bun run test:provider, npm run test:provider-recommendation
Not-tested: bun run typecheck (repository has many pre-existing unrelated failures)

Co-authored-by: anandh8x <test@example.com>
2026-04-04 21:19:27 +08:00

627 lines
24 KiB
TypeScript

import { c as _c } from "react-compiler-runtime";
import { feature } from 'bun:bundle';
import type { BetaContentBlock } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs';
import type { ImageBlockParam, TextBlockParam, ThinkingBlockParam, ToolResultBlockParam, ToolUseBlockParam } from '@anthropic-ai/sdk/resources/index.mjs';
import * as React from 'react';
import type { Command } from '../commands.js';
import { useTerminalSize } from '../hooks/useTerminalSize.js';
import { Box } from '../ink.js';
import type { Tools } from '../Tool.js';
import { type ConnectorTextBlock, isConnectorTextBlock } from '../types/connectorText.js';
import type { AssistantMessage, AttachmentMessage as AttachmentMessageType, CollapsedReadSearchGroup as CollapsedReadSearchGroupType, GroupedToolUseMessage as GroupedToolUseMessageType, NormalizedUserMessage, ProgressMessage, SystemMessage } from '../types/message.js';
import { type AdvisorBlock, isAdvisorBlock } from '../utils/advisor.js';
import { isFullscreenEnvEnabled } from '../utils/fullscreen.js';
import { logError } from '../utils/log.js';
import type { buildMessageLookups } from '../utils/messages.js';
import { CompactSummary } from './CompactSummary.js';
import { AdvisorMessage } from './messages/AdvisorMessage.js';
import { AssistantRedactedThinkingMessage } from './messages/AssistantRedactedThinkingMessage.js';
import { AssistantTextMessage } from './messages/AssistantTextMessage.js';
import { AssistantThinkingMessage } from './messages/AssistantThinkingMessage.js';
import { AssistantToolUseMessage } from './messages/AssistantToolUseMessage.js';
import { AttachmentMessage } from './messages/AttachmentMessage.js';
import { CollapsedReadSearchContent } from './messages/CollapsedReadSearchContent.js';
import { CompactBoundaryMessage } from './messages/CompactBoundaryMessage.js';
import { GroupedToolUseContent } from './messages/GroupedToolUseContent.js';
import { SystemTextMessage } from './messages/SystemTextMessage.js';
import { UserImageMessage } from './messages/UserImageMessage.js';
import { UserTextMessage } from './messages/UserTextMessage.js';
import { UserToolResultMessage } from './messages/UserToolResultMessage/UserToolResultMessage.js';
import { OffscreenFreeze } from './OffscreenFreeze.js';
import { ExpandShellOutputProvider } from './shell/ExpandShellOutputContext.js';
export type Props = {
message: NormalizedUserMessage | AssistantMessage | AttachmentMessageType | SystemMessage | GroupedToolUseMessageType | CollapsedReadSearchGroupType;
lookups: ReturnType<typeof buildMessageLookups>;
// TODO: Find a way to remove this, and leave spacing to the consumer
/** Absolute width for the container Box. When provided, eliminates a wrapper Box in the caller. */
containerWidth?: number;
addMargin: boolean;
tools: Tools;
commands: Command[];
verbose: boolean;
inProgressToolUseIDs: Set<string>;
progressMessagesForMessage: ProgressMessage[];
shouldAnimate: boolean;
shouldShowDot: boolean;
style?: 'condensed';
width?: number | string;
isTranscriptMode: boolean;
isStatic: boolean;
onOpenRateLimitOptions?: () => void;
isActiveCollapsedGroup?: boolean;
isUserContinuation?: boolean;
/** ID of the last thinking block (uuid:index) to show, used for hiding past thinking in transcript mode */
lastThinkingBlockId?: string | null;
/** UUID of the latest user bash output message (for auto-expanding) */
latestBashOutputUUID?: string | null;
};
function MessageImpl(t0) {
const $ = _c(94);
const {
message,
lookups,
containerWidth,
addMargin,
tools,
commands,
verbose,
inProgressToolUseIDs,
progressMessagesForMessage,
shouldAnimate,
shouldShowDot,
style,
width,
isTranscriptMode,
onOpenRateLimitOptions,
isActiveCollapsedGroup,
isUserContinuation: t1,
lastThinkingBlockId,
latestBashOutputUUID
} = t0;
const isUserContinuation = t1 === undefined ? false : t1;
switch (message.type) {
case "attachment":
{
let t2;
if ($[0] !== addMargin || $[1] !== isTranscriptMode || $[2] !== message.attachment || $[3] !== verbose) {
t2 = <AttachmentMessage addMargin={addMargin} attachment={message.attachment} verbose={verbose} isTranscriptMode={isTranscriptMode} />;
$[0] = addMargin;
$[1] = isTranscriptMode;
$[2] = message.attachment;
$[3] = verbose;
$[4] = t2;
} else {
t2 = $[4];
}
return t2;
}
case "assistant":
{
const t2 = containerWidth ?? "100%";
let t3;
if ($[5] !== addMargin || $[6] !== commands || $[7] !== inProgressToolUseIDs || $[8] !== isTranscriptMode || $[9] !== lastThinkingBlockId || $[10] !== lookups || $[11] !== message.advisorModel || $[12] !== message.message.content || $[13] !== message.uuid || $[14] !== onOpenRateLimitOptions || $[15] !== progressMessagesForMessage || $[16] !== shouldAnimate || $[17] !== shouldShowDot || $[18] !== tools || $[19] !== verbose || $[20] !== width) {
let t4;
if ($[22] !== addMargin || $[23] !== commands || $[24] !== inProgressToolUseIDs || $[25] !== isTranscriptMode || $[26] !== lastThinkingBlockId || $[27] !== lookups || $[28] !== message.advisorModel || $[29] !== message.uuid || $[30] !== onOpenRateLimitOptions || $[31] !== progressMessagesForMessage || $[32] !== shouldAnimate || $[33] !== shouldShowDot || $[34] !== tools || $[35] !== verbose || $[36] !== width) {
t4 = (_, index_0) => <AssistantMessageBlock key={index_0} param={_} addMargin={addMargin} tools={tools} commands={commands} verbose={verbose} inProgressToolUseIDs={inProgressToolUseIDs} progressMessagesForMessage={progressMessagesForMessage} shouldAnimate={shouldAnimate} shouldShowDot={shouldShowDot} width={width} inProgressToolCallCount={inProgressToolUseIDs.size} isTranscriptMode={isTranscriptMode} lookups={lookups} onOpenRateLimitOptions={onOpenRateLimitOptions} thinkingBlockId={`${message.uuid}:${index_0}`} lastThinkingBlockId={lastThinkingBlockId} advisorModel={message.advisorModel} />;
$[22] = addMargin;
$[23] = commands;
$[24] = inProgressToolUseIDs;
$[25] = isTranscriptMode;
$[26] = lastThinkingBlockId;
$[27] = lookups;
$[28] = message.advisorModel;
$[29] = message.uuid;
$[30] = onOpenRateLimitOptions;
$[31] = progressMessagesForMessage;
$[32] = shouldAnimate;
$[33] = shouldShowDot;
$[34] = tools;
$[35] = verbose;
$[36] = width;
$[37] = t4;
} else {
t4 = $[37];
}
t3 = message.message.content.map(t4);
$[5] = addMargin;
$[6] = commands;
$[7] = inProgressToolUseIDs;
$[8] = isTranscriptMode;
$[9] = lastThinkingBlockId;
$[10] = lookups;
$[11] = message.advisorModel;
$[12] = message.message.content;
$[13] = message.uuid;
$[14] = onOpenRateLimitOptions;
$[15] = progressMessagesForMessage;
$[16] = shouldAnimate;
$[17] = shouldShowDot;
$[18] = tools;
$[19] = verbose;
$[20] = width;
$[21] = t3;
} else {
t3 = $[21];
}
let t4;
if ($[38] !== t2 || $[39] !== t3) {
t4 = <Box flexDirection="column" width={t2}>{t3}</Box>;
$[38] = t2;
$[39] = t3;
$[40] = t4;
} else {
t4 = $[40];
}
return t4;
}
case "user":
{
if (message.isCompactSummary) {
const t2 = isTranscriptMode ? "transcript" : "prompt";
let t3;
if ($[41] !== message || $[42] !== t2) {
t3 = <CompactSummary message={message} screen={t2} />;
$[41] = message;
$[42] = t2;
$[43] = t3;
} else {
t3 = $[43];
}
return t3;
}
let imageIndices;
if ($[44] !== message.imagePasteIds || $[45] !== message.message.content) {
imageIndices = [];
let imagePosition = 0;
for (const param of message.message.content) {
if (param.type === "image") {
const id = message.imagePasteIds?.[imagePosition];
imagePosition++;
imageIndices.push(id ?? imagePosition);
} else {
imageIndices.push(imagePosition);
}
}
$[44] = message.imagePasteIds;
$[45] = message.message.content;
$[46] = imageIndices;
} else {
imageIndices = $[46];
}
const isLatestBashOutput = latestBashOutputUUID === message.uuid;
const t2 = containerWidth ?? "100%";
let t3;
if ($[47] !== addMargin || $[48] !== imageIndices || $[49] !== isTranscriptMode || $[50] !== isUserContinuation || $[51] !== lookups || $[52] !== message || $[53] !== progressMessagesForMessage || $[54] !== style || $[55] !== tools || $[56] !== verbose) {
t3 = message.message.content.map((param_0, index) => <UserMessage key={index} message={message} addMargin={addMargin} tools={tools} progressMessagesForMessage={progressMessagesForMessage} param={param_0} style={style} verbose={verbose} imageIndex={imageIndices[index]} isUserContinuation={isUserContinuation} lookups={lookups} isTranscriptMode={isTranscriptMode} />);
$[47] = addMargin;
$[48] = imageIndices;
$[49] = isTranscriptMode;
$[50] = isUserContinuation;
$[51] = lookups;
$[52] = message;
$[53] = progressMessagesForMessage;
$[54] = style;
$[55] = tools;
$[56] = verbose;
$[57] = t3;
} else {
t3 = $[57];
}
let t4;
if ($[58] !== t2 || $[59] !== t3) {
t4 = <Box flexDirection="column" width={t2}>{t3}</Box>;
$[58] = t2;
$[59] = t3;
$[60] = t4;
} else {
t4 = $[60];
}
const content = t4;
let t5;
if ($[61] !== content || $[62] !== isLatestBashOutput) {
t5 = isLatestBashOutput ? <ExpandShellOutputProvider>{content}</ExpandShellOutputProvider> : content;
$[61] = content;
$[62] = isLatestBashOutput;
$[63] = t5;
} else {
t5 = $[63];
}
return t5;
}
case "system":
{
if (message.subtype === "compact_boundary") {
if (isFullscreenEnvEnabled()) {
return null;
}
let t2;
if ($[64] === Symbol.for("react.memo_cache_sentinel")) {
t2 = <CompactBoundaryMessage />;
$[64] = t2;
} else {
t2 = $[64];
}
return t2;
}
if (message.subtype === "microcompact_boundary") {
return null;
}
if (feature("HISTORY_SNIP")) {
const {
isSnipBoundaryMessage
} = require("../services/compact/snipProjection.js") as typeof import('../services/compact/snipProjection.js');
const {
isSnipMarkerMessage
} = require("../services/compact/snipCompact.js") as typeof import('../services/compact/snipCompact.js');
if (isSnipBoundaryMessage(message)) {
let t2;
if ($[65] === Symbol.for("react.memo_cache_sentinel")) {
t2 = require("./messages/SnipBoundaryMessage.js");
$[65] = t2;
} else {
t2 = $[65];
}
const {
SnipBoundaryMessage
} = t2 as typeof import('./messages/SnipBoundaryMessage.js');
let t3;
if ($[66] !== message) {
t3 = <SnipBoundaryMessage message={message} />;
$[66] = message;
$[67] = t3;
} else {
t3 = $[67];
}
return t3;
}
if (isSnipMarkerMessage(message)) {
return null;
}
}
if (message.subtype === "local_command") {
let t2;
if ($[68] !== message.content) {
t2 = {
type: "text",
text: message.content
};
$[68] = message.content;
$[69] = t2;
} else {
t2 = $[69];
}
let t3;
if ($[70] !== addMargin || $[71] !== isTranscriptMode || $[72] !== t2 || $[73] !== verbose) {
t3 = <UserTextMessage addMargin={addMargin} param={t2} verbose={verbose} isTranscriptMode={isTranscriptMode} />;
$[70] = addMargin;
$[71] = isTranscriptMode;
$[72] = t2;
$[73] = verbose;
$[74] = t3;
} else {
t3 = $[74];
}
return t3;
}
let t2;
if ($[75] !== addMargin || $[76] !== isTranscriptMode || $[77] !== message || $[78] !== verbose) {
t2 = <SystemTextMessage message={message} addMargin={addMargin} verbose={verbose} isTranscriptMode={isTranscriptMode} />;
$[75] = addMargin;
$[76] = isTranscriptMode;
$[77] = message;
$[78] = verbose;
$[79] = t2;
} else {
t2 = $[79];
}
return t2;
}
case "grouped_tool_use":
{
let t2;
if ($[80] !== inProgressToolUseIDs || $[81] !== lookups || $[82] !== message || $[83] !== shouldAnimate || $[84] !== tools) {
t2 = <GroupedToolUseContent message={message} tools={tools} lookups={lookups} inProgressToolUseIDs={inProgressToolUseIDs} shouldAnimate={shouldAnimate} />;
$[80] = inProgressToolUseIDs;
$[81] = lookups;
$[82] = message;
$[83] = shouldAnimate;
$[84] = tools;
$[85] = t2;
} else {
t2 = $[85];
}
return t2;
}
case "collapsed_read_search":
{
const t2 = verbose || isTranscriptMode;
let t3;
if ($[86] !== inProgressToolUseIDs || $[87] !== isActiveCollapsedGroup || $[88] !== lookups || $[89] !== message || $[90] !== shouldAnimate || $[91] !== t2 || $[92] !== tools) {
t3 = <OffscreenFreeze><CollapsedReadSearchContent message={message} inProgressToolUseIDs={inProgressToolUseIDs} shouldAnimate={shouldAnimate} verbose={t2} tools={tools} lookups={lookups} isActiveGroup={isActiveCollapsedGroup} /></OffscreenFreeze>;
$[86] = inProgressToolUseIDs;
$[87] = isActiveCollapsedGroup;
$[88] = lookups;
$[89] = message;
$[90] = shouldAnimate;
$[91] = t2;
$[92] = tools;
$[93] = t3;
} else {
t3 = $[93];
}
return t3;
}
}
}
function UserMessage(t0) {
const $ = _c(20);
const {
message,
addMargin,
tools,
progressMessagesForMessage,
param,
style,
verbose,
imageIndex,
isUserContinuation,
lookups,
isTranscriptMode
} = t0;
const {
columns
} = useTerminalSize();
switch (param.type) {
case "text":
{
let t1;
if ($[0] !== addMargin || $[1] !== isTranscriptMode || $[2] !== message.planContent || $[3] !== message.timestamp || $[4] !== param || $[5] !== verbose) {
t1 = <UserTextMessage addMargin={addMargin} param={param} verbose={verbose} planContent={message.planContent} isTranscriptMode={isTranscriptMode} timestamp={message.timestamp} />;
$[0] = addMargin;
$[1] = isTranscriptMode;
$[2] = message.planContent;
$[3] = message.timestamp;
$[4] = param;
$[5] = verbose;
$[6] = t1;
} else {
t1 = $[6];
}
return t1;
}
case "image":
{
const t1 = addMargin && !isUserContinuation;
let t2;
if ($[7] !== imageIndex || $[8] !== t1) {
t2 = <UserImageMessage imageId={imageIndex} addMargin={t1} />;
$[7] = imageIndex;
$[8] = t1;
$[9] = t2;
} else {
t2 = $[9];
}
return t2;
}
case "tool_result":
{
const t1 = columns - 5;
let t2;
if ($[10] !== isTranscriptMode || $[11] !== lookups || $[12] !== message || $[13] !== param || $[14] !== progressMessagesForMessage || $[15] !== style || $[16] !== t1 || $[17] !== tools || $[18] !== verbose) {
t2 = <UserToolResultMessage param={param} message={message} lookups={lookups} progressMessagesForMessage={progressMessagesForMessage} style={style} tools={tools} verbose={verbose} width={t1} isTranscriptMode={isTranscriptMode} />;
$[10] = isTranscriptMode;
$[11] = lookups;
$[12] = message;
$[13] = param;
$[14] = progressMessagesForMessage;
$[15] = style;
$[16] = t1;
$[17] = tools;
$[18] = verbose;
$[19] = t2;
} else {
t2 = $[19];
}
return t2;
}
default:
{
return;
}
}
}
function AssistantMessageBlock(t0) {
const $ = _c(45);
const {
param,
addMargin,
tools,
commands,
verbose,
inProgressToolUseIDs,
progressMessagesForMessage,
shouldAnimate,
shouldShowDot,
width,
inProgressToolCallCount,
isTranscriptMode,
lookups,
onOpenRateLimitOptions,
thinkingBlockId,
lastThinkingBlockId,
advisorModel
} = t0;
if (feature("CONNECTOR_TEXT")) {
if (isConnectorTextBlock(param)) {
let t1;
if ($[0] !== param.connector_text) {
t1 = {
type: "text",
text: param.connector_text
};
$[0] = param.connector_text;
$[1] = t1;
} else {
t1 = $[1];
}
let t2;
if ($[2] !== addMargin || $[3] !== onOpenRateLimitOptions || $[4] !== shouldShowDot || $[5] !== t1 || $[6] !== verbose || $[7] !== width) {
t2 = <AssistantTextMessage param={t1} addMargin={addMargin} shouldShowDot={shouldShowDot} verbose={verbose} width={width} onOpenRateLimitOptions={onOpenRateLimitOptions} />;
$[2] = addMargin;
$[3] = onOpenRateLimitOptions;
$[4] = shouldShowDot;
$[5] = t1;
$[6] = verbose;
$[7] = width;
$[8] = t2;
} else {
t2 = $[8];
}
return t2;
}
}
switch (param.type) {
case "tool_use":
{
let t1;
if ($[9] !== addMargin || $[10] !== commands || $[11] !== inProgressToolCallCount || $[12] !== inProgressToolUseIDs || $[13] !== isTranscriptMode || $[14] !== lookups || $[15] !== param || $[16] !== progressMessagesForMessage || $[17] !== shouldAnimate || $[18] !== shouldShowDot || $[19] !== tools || $[20] !== verbose) {
t1 = <AssistantToolUseMessage param={param} addMargin={addMargin} tools={tools} commands={commands} verbose={verbose} inProgressToolUseIDs={inProgressToolUseIDs} progressMessagesForMessage={progressMessagesForMessage} shouldAnimate={shouldAnimate} shouldShowDot={shouldShowDot} inProgressToolCallCount={inProgressToolCallCount} lookups={lookups} isTranscriptMode={isTranscriptMode} />;
$[9] = addMargin;
$[10] = commands;
$[11] = inProgressToolCallCount;
$[12] = inProgressToolUseIDs;
$[13] = isTranscriptMode;
$[14] = lookups;
$[15] = param;
$[16] = progressMessagesForMessage;
$[17] = shouldAnimate;
$[18] = shouldShowDot;
$[19] = tools;
$[20] = verbose;
$[21] = t1;
} else {
t1 = $[21];
}
return t1;
}
case "text":
{
let t1;
if ($[22] !== addMargin || $[23] !== onOpenRateLimitOptions || $[24] !== param || $[25] !== shouldShowDot || $[26] !== verbose || $[27] !== width) {
t1 = <AssistantTextMessage param={param} addMargin={addMargin} shouldShowDot={shouldShowDot} verbose={verbose} width={width} onOpenRateLimitOptions={onOpenRateLimitOptions} />;
$[22] = addMargin;
$[23] = onOpenRateLimitOptions;
$[24] = param;
$[25] = shouldShowDot;
$[26] = verbose;
$[27] = width;
$[28] = t1;
} else {
t1 = $[28];
}
return t1;
}
case "redacted_thinking":
{
if (!isTranscriptMode && !verbose) {
return null;
}
let t1;
if ($[29] !== addMargin) {
t1 = <AssistantRedactedThinkingMessage addMargin={addMargin} />;
$[29] = addMargin;
$[30] = t1;
} else {
t1 = $[30];
}
return t1;
}
case "thinking":
{
if (!isTranscriptMode && !verbose) {
return null;
}
const isLastThinking = !lastThinkingBlockId || thinkingBlockId === lastThinkingBlockId;
const t1 = isTranscriptMode && !isLastThinking;
let t2;
if ($[31] !== addMargin || $[32] !== isTranscriptMode || $[33] !== param || $[34] !== t1 || $[35] !== verbose) {
t2 = <AssistantThinkingMessage addMargin={addMargin} param={param} isTranscriptMode={isTranscriptMode} verbose={verbose} hideInTranscript={t1} />;
$[31] = addMargin;
$[32] = isTranscriptMode;
$[33] = param;
$[34] = t1;
$[35] = verbose;
$[36] = t2;
} else {
t2 = $[36];
}
return t2;
}
case "server_tool_use":
case "advisor_tool_result":
{
if (isAdvisorBlock(param)) {
const t1 = verbose || isTranscriptMode;
let t2;
if ($[37] !== addMargin || $[38] !== advisorModel || $[39] !== lookups.erroredToolUseIDs || $[40] !== lookups.resolvedToolUseIDs || $[41] !== param || $[42] !== shouldAnimate || $[43] !== t1) {
t2 = <AdvisorMessage block={param} addMargin={addMargin} resolvedToolUseIDs={lookups.resolvedToolUseIDs} erroredToolUseIDs={lookups.erroredToolUseIDs} shouldAnimate={shouldAnimate} verbose={t1} advisorModel={advisorModel} />;
$[37] = addMargin;
$[38] = advisorModel;
$[39] = lookups.erroredToolUseIDs;
$[40] = lookups.resolvedToolUseIDs;
$[41] = param;
$[42] = shouldAnimate;
$[43] = t1;
$[44] = t2;
} else {
t2 = $[44];
}
return t2;
}
logError(new Error(`Unable to render server tool block: ${param.type}`));
return null;
}
default:
{
logError(new Error(`Unable to render message type: ${param.type}`));
return null;
}
}
}
export function hasThinkingContent(m: {
type: string;
message?: {
content: Array<{
type: string;
}>;
};
}): boolean {
if (m.type !== 'assistant' || !m.message) return false;
return m.message.content.some(b => b.type === 'thinking' || b.type === 'redacted_thinking');
}
/** Exported for testing */
export function areMessagePropsEqual(prev: Props, next: Props): boolean {
if (prev.message.uuid !== next.message.uuid) return false;
// Only re-render on lastThinkingBlockId change if this message actually
// has thinking content — otherwise every message in scrollback re-renders
// whenever streaming thinking starts/stops (CC-941).
if (prev.lastThinkingBlockId !== next.lastThinkingBlockId && hasThinkingContent(next.message)) {
return false;
}
// Verbose toggle changes thinking block visibility/expansion
if (prev.verbose !== next.verbose) return false;
// Only re-render if this message's "is latest bash output" status changed,
// not when the global latestBashOutputUUID changes to a different message
const prevIsLatest = prev.latestBashOutputUUID === prev.message.uuid;
const nextIsLatest = next.latestBashOutputUUID === next.message.uuid;
if (prevIsLatest !== nextIsLatest) return false;
if (prev.isTranscriptMode !== next.isTranscriptMode) return false;
// containerWidth is an absolute number in the no-metadata path (wrapper
// Box is skipped). Static messages must re-render on terminal resize.
if (prev.containerWidth !== next.containerWidth) return false;
if (prev.isStatic && next.isStatic) return true;
return false;
}
export const Message = React.memo(MessageImpl, areMessagePropsEqual);