feat(chat): allow prompting subagent sessions
This commit is contained in:
@@ -404,6 +404,7 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({ autoOpenDraft = tr
|
||||
// UI store
|
||||
const isExpandedInput = useUIStore((state) => state.isExpandedInput);
|
||||
const stickyUserHeader = useUIStore((state) => state.stickyUserHeader);
|
||||
const allowPromptingSubagentSessions = useUIStore((state) => state.allowPromptingSubagentSessions);
|
||||
const isTimelineDialogOpen = useUIStore((s) => s.isTimelineDialogOpen);
|
||||
const setTimelineDialogOpen = useUIStore((s) => s.setTimelineDialogOpen);
|
||||
|
||||
@@ -585,7 +586,7 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({ autoOpenDraft = tr
|
||||
{t('chat.container.returnToParent.label')}
|
||||
</Button>
|
||||
) : null;
|
||||
const promptReadOnly = readOnly || Boolean(parentSession);
|
||||
const promptReadOnly = readOnly || (Boolean(parentSession) && !allowPromptingSubagentSessions);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (autoOpenDraft && !currentSessionId && !draftOpen) {
|
||||
@@ -839,7 +840,7 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({ autoOpenDraft = tr
|
||||
: 'flex-1 items-center justify-center bg-background px-0 pb-[6vh]'
|
||||
)}
|
||||
>
|
||||
{promptReadOnly ? <ReadOnlyPromptBanner /> : <ChatInput scrollToBottom={scrollToBottomOnSend} />}
|
||||
{promptReadOnly ? <ReadOnlyPromptBanner /> : <ChatInput scrollToBottom={scrollToBottomOnSend} />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -899,7 +900,7 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({ autoOpenDraft = tr
|
||||
: 'bg-background'
|
||||
)}
|
||||
>
|
||||
{promptReadOnly ? <ReadOnlyPromptBanner /> : <ChatInput scrollToBottom={scrollToBottomOnSend} />}
|
||||
{promptReadOnly ? <ReadOnlyPromptBanner /> : <ChatInput scrollToBottom={scrollToBottomOnSend} />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -934,7 +935,7 @@ export const ChatContainer: React.FC<ChatContainerProps> = ({ autoOpenDraft = tr
|
||||
: 'bg-background'
|
||||
)}
|
||||
>
|
||||
{promptReadOnly ? <ReadOnlyPromptBanner /> : <ChatInput scrollToBottom={scrollToBottomOnSend} />}
|
||||
{promptReadOnly ? <ReadOnlyPromptBanner /> : <ChatInput scrollToBottom={scrollToBottomOnSend} />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -436,9 +436,10 @@ const writeRevealedToolIds = (messageId: string, value: Set<string>): void => {
|
||||
revealedToolIdsByMessage.set(messageId, new Set(value));
|
||||
};
|
||||
|
||||
const UserMessageBody = React.memo(({ messageId, parts, isMobile, alwaysShowActions = isMobile, hasTouchInput, hasTextContent, onCopyMessage, copiedMessage, onShowPopup, agentMention, onRevert, onFork, userActionsMode = 'inline', stickyUserHeaderEnabled = true }: {
|
||||
const UserMessageBody = React.memo(({ messageId, parts, messageCreatedAt, isMobile, alwaysShowActions = isMobile, hasTouchInput, hasTextContent, onCopyMessage, copiedMessage, onShowPopup, agentMention, onRevert, onFork, userActionsMode = 'inline', stickyUserHeaderEnabled = true }: {
|
||||
messageId: string;
|
||||
parts: Part[];
|
||||
messageCreatedAt?: number | null;
|
||||
isMobile: boolean;
|
||||
alwaysShowActions?: boolean;
|
||||
hasTouchInput?: boolean;
|
||||
@@ -452,8 +453,9 @@ const UserMessageBody = React.memo(({ messageId, parts, isMobile, alwaysShowActi
|
||||
userActionsMode?: 'inline' | 'external-content' | 'external-actions';
|
||||
stickyUserHeaderEnabled?: boolean;
|
||||
}) => {
|
||||
const { t } = useI18n();
|
||||
const { locale, t } = useI18n();
|
||||
const chatSurfaceMode = useChatSurfaceMode();
|
||||
const timeFormatPreference = useUIStore((state) => state.timeFormatPreference);
|
||||
const [copyHintVisible, setCopyHintVisible] = React.useState(false);
|
||||
const copyHintTimeoutRef = React.useRef<number | null>(null);
|
||||
|
||||
@@ -528,6 +530,12 @@ const UserMessageBody = React.memo(({ messageId, parts, isMobile, alwaysShowActi
|
||||
);
|
||||
|
||||
const effectiveOnFork = chatSurfaceMode === 'mini-chat' ? undefined : onFork;
|
||||
const timestamp = React.useMemo(() => {
|
||||
void locale;
|
||||
if (typeof messageCreatedAt !== 'number' || messageCreatedAt <= 0) return null;
|
||||
const formatted = formatTimestampForDisplay(messageCreatedAt, timeFormatPreference);
|
||||
return formatted.length > 0 ? formatted : null;
|
||||
}, [locale, messageCreatedAt, timeFormatPreference]);
|
||||
const actionsBlock = ((canCopyMessage && hasCopyableText) || onRevert || effectiveOnFork) && showUserActions ? (
|
||||
<div className={cn(
|
||||
'group/user-actions',
|
||||
@@ -556,6 +564,20 @@ const UserMessageBody = React.memo(({ messageId, parts, isMobile, alwaysShowActi
|
||||
: 'pointer-events-none opacity-0 transition-opacity duration-150 group-hover/message:pointer-events-auto group-hover/message:opacity-100 group-hover/user-actions:pointer-events-auto group-hover/user-actions:opacity-100 group-hover/user-shell:pointer-events-auto group-hover/user-shell:opacity-100'
|
||||
)}
|
||||
>
|
||||
{timestamp ? (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span
|
||||
className="mr-1 flex items-center gap-1 text-sm tabular-nums text-muted-foreground/60"
|
||||
aria-label={`Message time: ${timestamp}`}
|
||||
>
|
||||
<Icon name="time" className="h-3.5 w-3.5" />
|
||||
<span className="message-footer__label">{timestamp}</span>
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{timestamp}</TooltipContent>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{onRevert && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
@@ -2125,6 +2147,7 @@ const MessageBody = React.memo(({ isUser, ...props }: MessageBodyProps) => {
|
||||
<UserMessageBody
|
||||
messageId={props.messageId}
|
||||
parts={props.parts}
|
||||
messageCreatedAt={props.messageCreatedAt}
|
||||
isMobile={props.isMobile}
|
||||
alwaysShowActions={props.alwaysShowActions}
|
||||
hasTouchInput={props.hasTouchInput}
|
||||
|
||||
Reference in New Issue
Block a user