import { feature } from 'bun:bundle'; import type { TextBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'; import * as React from 'react'; import { NO_CONTENT_MESSAGE } from '../../constants/messages.js'; import { COMMAND_MESSAGE_TAG, FORK_BOILERPLATE_TAG, LOCAL_COMMAND_CAVEAT_TAG, TASK_NOTIFICATION_TAG, TEAMMATE_MESSAGE_TAG, TICK_TAG, } from '../../constants/xml.js'; import { isAgentSwarmsEnabled } from '../../utils/agentSwarmsEnabled.js'; import { extractTag, INTERRUPT_MESSAGE, INTERRUPT_MESSAGE_FOR_TOOL_USE } from '../../utils/messages.js'; import { InterruptedByUser } from '../InterruptedByUser.js'; import { MessageResponse } from '../MessageResponse.js'; import { UserAgentNotificationMessage } from './UserAgentNotificationMessage.js'; import { UserBashInputMessage } from './UserBashInputMessage.js'; import { UserBashOutputMessage } from './UserBashOutputMessage.js'; import { UserCommandMessage } from './UserCommandMessage.js'; import { UserLocalCommandOutputMessage } from './UserLocalCommandOutputMessage.js'; import { UserMemoryInputMessage } from './UserMemoryInputMessage.js'; import { UserPlanMessage } from './UserPlanMessage.js'; import { UserPromptMessage } from './UserPromptMessage.js'; import { UserResourceUpdateMessage } from './UserResourceUpdateMessage.js'; import { UserTeammateMessage } from './UserTeammateMessage.js'; type Props = { addMargin: boolean; param: TextBlockParam; verbose: boolean; planContent?: string; isTranscriptMode?: boolean; timestamp?: string; }; export function UserTextMessage({ addMargin, param, verbose, planContent, isTranscriptMode, timestamp, }: Props): React.ReactNode { if (param.text.trim() === NO_CONTENT_MESSAGE) { return null; } // Plan to implement message (cleared context flow) if (planContent) { return ; } if (extractTag(param.text, TICK_TAG)) { return null; } // Hide synthetic caveat messages (should be filtered by isMeta, this is defensive) if (param.text.includes(`<${LOCAL_COMMAND_CAVEAT_TAG}>`)) { return null; } // Show bash output if (param.text.startsWith('; } // Show command output if (param.text.startsWith('; } // Handle interruption messages specially if (param.text === INTERRUPT_MESSAGE || param.text === INTERRUPT_MESSAGE_FOR_TOOL_USE) { return ( ); } // GitHub webhook events (check_run, review comments, pushes) delivered via // bound-session routing after /subscribe-pr. The tag constant is stripped // from external builds — inline the literal so the import doesn't fail. // The require() below DCEs when both flags are off. startsWith (not // includes) and before the includes-checks below: defense-in-depth if // the sanitizer were ever weakened. if (feature('KAIROS_GITHUB_WEBHOOKS')) { if (param.text.startsWith('')) { /* eslint-disable @typescript-eslint/no-require-imports */ const { UserGitHubWebhookMessage } = require('./UserGitHubWebhookMessage.js') as typeof import('./UserGitHubWebhookMessage.js'); /* eslint-enable @typescript-eslint/no-require-imports */ return ; } } // Bash inputs! if (param.text.includes('')) { return ; } // Slash commands/ if (param.text.includes(`<${COMMAND_MESSAGE_TAG}>`)) { return ; } if (param.text.includes('')) { return ; } // Teammate messages - only check when swarms enabled if (isAgentSwarmsEnabled() && param.text.includes(`<${TEAMMATE_MESSAGE_TAG}`)) { return ; } // Task notifications (agent completions, bash completions, etc.) if (param.text.includes(`<${TASK_NOTIFICATION_TAG}`)) { return ; } // MCP resource and polling update notifications if (param.text.includes('; } // Fork child's first message: collapse the rules/format boilerplate, show // only the user prompt. Independent of FORK_SUBAGENT flag — the fork agent // transcript always needs to render the prompt as a normal user bubble. if (param.text.includes(`<${FORK_BOILERPLATE_TAG}>`)) { /* eslint-disable @typescript-eslint/no-require-imports */ const { UserForkBoilerplateMessage } = require('./UserForkBoilerplateMessage.js') as typeof import('./UserForkBoilerplateMessage.js'); /* eslint-enable @typescript-eslint/no-require-imports */ return ( ); } // Cross-session UDS message (from another Claude session's SendMessage). // CROSS_SESSION_MESSAGE_TAG is inlined so the import doesn't ship in // external builds where feature('UDS_INBOX') is false. if (feature('UDS_INBOX')) { if (param.text.includes('; } } // Inbound channel message (MCP server push). if (feature('KAIROS') || feature('KAIROS_CHANNELS')) { if (param.text.includes('