chore: test deploy snapshot

This commit is contained in:
2026-05-29 18:08:38 +09:00
parent 5b3e70910c
commit ffbdbf46b6
2 changed files with 133 additions and 28 deletions

View File

@@ -3049,6 +3049,19 @@ export function MainChatPanel({
const requestItems = Array.isArray(requestItemsState) ? requestItemsState : []; const requestItems = Array.isArray(requestItemsState) ? requestItemsState : [];
const isCreatingImportedDraftConversationRef = useRef(false); const isCreatingImportedDraftConversationRef = useRef(false);
const hasAttemptedInitialConversationRef = useRef(false); const hasAttemptedInitialConversationRef = useRef(false);
const pendingConversationSummaryUpdatesRef = useRef(
new Map<
string,
{
incomingMessage: ChatMessage;
hasMeaningfulCodexResponse: boolean;
hasPendingAttentionResponse: boolean;
isForegroundSession: boolean;
responseTimestamp: string;
}
>(),
);
const conversationSummaryUpdateFrameRef = useRef<number | null>(null);
const setDraft = useCallback((value: SetStateAction<string>) => { const setDraft = useCallback((value: SetStateAction<string>) => {
const nextValue = typeof value === 'function' ? value(draftRef.current) : value; const nextValue = typeof value === 'function' ? value(draftRef.current) : value;
draftRef.current = nextValue; draftRef.current = nextValue;
@@ -3066,6 +3079,63 @@ export function MainChatPanel({
const setDraftValue = useCallback((value: string) => { const setDraftValue = useCallback((value: string) => {
setDraft(value); setDraft(value);
}, [setDraft]); }, [setDraft]);
const enqueueConversationSummaryUpdate = useCallback(
(payload: {
sessionId: string;
incomingMessage: ChatMessage;
hasMeaningfulCodexResponse: boolean;
hasPendingAttentionResponse: boolean;
isForegroundSession: boolean;
responseTimestamp: string;
}) => {
pendingConversationSummaryUpdatesRef.current.set(payload.sessionId, payload);
if (conversationSummaryUpdateFrameRef.current !== null) {
return;
}
conversationSummaryUpdateFrameRef.current = window.requestAnimationFrame(() => {
conversationSummaryUpdateFrameRef.current = null;
const batchedUpdates = new Map(pendingConversationSummaryUpdatesRef.current);
pendingConversationSummaryUpdatesRef.current.clear();
if (batchedUpdates.size === 0) {
return;
}
setConversationItems((previous) =>
sortChatConversationSummaries(
previous.map((item) => {
const update = batchedUpdates.get(item.sessionId);
if (!update) {
return item;
}
return {
...item,
lastMessagePreview: createConversationPreviewText(update.incomingMessage.text),
lastResponsePreview:
update.incomingMessage.author === 'codex' && !isPreparingChatReplyText(update.incomingMessage.text)
? createConversationPreviewText(update.incomingMessage.text)
: item.lastResponsePreview,
lastMessageAt: update.responseTimestamp,
updatedAt: update.responseTimestamp,
hasUnreadResponse:
update.hasMeaningfulCodexResponse && !update.isForegroundSession ? true : item.hasUnreadResponse,
hasPendingAttention:
update.hasPendingAttentionResponse && update.incomingMessage.author === 'codex'
? true
: item.hasPendingAttention,
};
}),
),
);
});
},
[setConversationItems],
);
const setRequestItems = useCallback((next: SetStateAction<ChatConversationRequest[]>) => { const setRequestItems = useCallback((next: SetStateAction<ChatConversationRequest[]>) => {
setRequestItemsState((previous) => { setRequestItemsState((previous) => {
const safePrevious = Array.isArray(previous) ? previous : []; const safePrevious = Array.isArray(previous) ? previous : [];
@@ -3092,6 +3162,14 @@ export function MainChatPanel({
activeSessionIdRef.current = activeSessionId; activeSessionIdRef.current = activeSessionId;
}, [activeSessionId]); }, [activeSessionId]);
useEffect(() => {
return () => {
if (conversationSummaryUpdateFrameRef.current !== null) {
window.cancelAnimationFrame(conversationSummaryUpdateFrameRef.current);
}
};
}, []);
useEffect(() => { useEffect(() => {
if (mode !== 'live' || location.pathname !== chatRoutePath) { if (mode !== 'live' || location.pathname !== chatRoutePath) {
return; return;
@@ -4337,28 +4415,14 @@ export function MainChatPanel({
}); });
const responseTimestamp = new Date().toISOString(); const responseTimestamp = new Date().toISOString();
setConversationItems((previous) => enqueueConversationSummaryUpdate({
sortChatConversationSummaries( sessionId,
previous.map((item) => incomingMessage,
item.sessionId === sessionId hasMeaningfulCodexResponse,
? { hasPendingAttentionResponse,
...item, isForegroundSession,
lastMessagePreview: createConversationPreviewText(incomingMessage.text), responseTimestamp,
lastResponsePreview: });
incomingMessage.author === 'codex' && !isPreparingChatReplyText(incomingMessage.text)
? createConversationPreviewText(incomingMessage.text)
: item.lastResponsePreview,
lastMessageAt: responseTimestamp,
updatedAt: responseTimestamp,
hasUnreadResponse:
hasMeaningfulCodexResponse && !isForegroundSession ? true : item.hasUnreadResponse,
hasPendingAttention:
hasPendingAttentionResponse && incomingMessage.author === 'codex' ? true : item.hasPendingAttention,
}
: item,
),
),
);
const eventConversation = conversationItemsRef.current.find((item) => item.sessionId === sessionId) ?? null; const eventConversation = conversationItemsRef.current.find((item) => item.sessionId === sessionId) ?? null;

View File

@@ -521,6 +521,12 @@ type MessageRenderPayload = {
promptTargets: Extract<ChatMessagePart, { type: 'prompt' }>[]; promptTargets: Extract<ChatMessagePart, { type: 'prompt' }>[];
}; };
type MessageRenderPayloadCacheEntry = {
messageText: string;
messageParts: ChatMessagePart[] | undefined;
payload: MessageRenderPayload;
};
const RANK_LINE_PATTERN = /(?:\b(?:rank|score)\b|랭크|점수)\s*[:=]?\s*[-+]?\d+(?:\.\d+)?(?:e[-+]?\d+)?\b/i; const RANK_LINE_PATTERN = /(?:\b(?:rank|score)\b|랭크|점수)\s*[:=]?\s*[-+]?\d+(?:\.\d+)?(?:e[-+]?\d+)?\b/i;
const TITLE_VALUE_PATTERN = /^(?:[-*]\s*)?(?:\d+\.\s*)?(?:title|제목)\s*[:=-]\s*(.+)$/i; const TITLE_VALUE_PATTERN = /^(?:[-*]\s*)?(?:\d+\.\s*)?(?:title|제목)\s*[:=-]\s*(.+)$/i;
const LINK_VALUE_PATTERN = /^(?:[-*]\s*)?(?:\d+\.\s*)?(?:link|url|href|링크)\s*[:=-]\s*(https?:\/\/\S+|\/\S+)$/i; const LINK_VALUE_PATTERN = /^(?:[-*]\s*)?(?:\d+\.\s*)?(?:link|url|href|링크)\s*[:=-]\s*(https?:\/\/\S+|\/\S+)$/i;
@@ -3654,6 +3660,7 @@ export function ChatConversationView({
const suppressImmediateSendClickRef = useRef(false); const suppressImmediateSendClickRef = useRef(false);
const composerDraftValueRef = useRef(draft); const composerDraftValueRef = useRef(draft);
const lastSyncedComposerDraftRef = useRef(draft); const lastSyncedComposerDraftRef = useRef(draft);
const messageRenderPayloadCacheRef = useRef(new Map<number, MessageRenderPayloadCacheEntry>());
const setComposerDraftValue = (nextValue: string) => { const setComposerDraftValue = (nextValue: string) => {
composerDraftValueRef.current = nextValue; composerDraftValueRef.current = nextValue;
@@ -3788,6 +3795,10 @@ export function ChatConversationView({
forceComposerDraftSync(); forceComposerDraftSync();
}; };
useEffect(() => {
messageRenderPayloadCacheRef.current.clear();
}, [sessionId]);
const shouldShowConversationLoadingOverlay = isConversationLoading && visibleMessages.length === 0; const shouldShowConversationLoadingOverlay = isConversationLoading && visibleMessages.length === 0;
const orderedMessages = useMemo(() => { const orderedMessages = useMemo(() => {
@@ -3954,14 +3965,44 @@ export function ChatConversationView({
setExpandedSystemExecutionActivityRequestId(null); setExpandedSystemExecutionActivityRequestId(null);
}, [systemExecutionDisplayMode]); }, [systemExecutionDisplayMode]);
const messageRenderPayloadById = useMemo( const getCachedMessageRenderPayload = useCallback(
() => (message: ChatMessage) => {
new Map( const cached = messageRenderPayloadCacheRef.current.get(message.id);
orderedMessages.map((message) => [message.id, extractMessageRenderPayload(message)] as const),
), if (cached && cached.messageText === message.text && cached.messageParts === message.parts) {
[orderedMessages], return cached.payload;
}
const payload = extractMessageRenderPayload(message);
messageRenderPayloadCacheRef.current.set(message.id, {
messageText: message.text,
messageParts: message.parts,
payload,
});
return payload;
},
[],
); );
const messageRenderPayloadById = useMemo(() => {
const activeMessageIds = new Set<number>();
const nextMap = new Map<number, MessageRenderPayload>();
orderedMessages.forEach((message) => {
activeMessageIds.add(message.id);
nextMap.set(message.id, getCachedMessageRenderPayload(message));
});
const cachedMessageIds = Array.from(messageRenderPayloadCacheRef.current.keys());
cachedMessageIds.forEach((messageId) => {
if (!activeMessageIds.has(messageId)) {
messageRenderPayloadCacheRef.current.delete(messageId);
}
});
return nextMap;
}, [orderedMessages, getCachedMessageRenderPayload]);
useEffect(() => { useEffect(() => {
setOpenedPreviewUrls([]); setOpenedPreviewUrls([]);
setExpandedGroupIds([]); setExpandedGroupIds([]);