chore: test deploy snapshot

This commit is contained in:
2026-05-27 10:43:01 +09:00
parent c1d0f4c1db
commit 4c4b3c8d2c
78 changed files with 10392 additions and 2301 deletions

View File

@@ -40,6 +40,7 @@ type PendingChatRequest = {
};
type PendingContextConfirm = {
requestId?: string;
sessionId: string;
mode: 'queue' | 'direct';
text: string;
@@ -374,6 +375,7 @@ export function useConversationComposerController({
const executeSendMessage = useCallback(
async (request: PendingContextConfirm) => {
const {
requestId: requestedRequestId,
sessionId,
mode,
text,
@@ -490,7 +492,7 @@ export function useConversationComposerController({
return false;
}
const requestId = createClientRequestId();
const requestId = requestedRequestId?.trim() || createClientRequestId();
const outgoingRequest: PendingChatRequest = {
sessionId: targetSessionId,
requestId,
@@ -535,6 +537,7 @@ export function useConversationComposerController({
chatTypeLabel: requestChatTypeLabel,
requestOrigin: origin ?? 'composer',
parentRequestId: parentRequestId?.trim() || null,
promptContextRef: promptContextRef ?? null,
status: 'queued',
statusMessage: '대기열 등록',
userMessageId: optimisticUserMessage.id,
@@ -582,6 +585,7 @@ export function useConversationComposerController({
chatTypeLabel: requestChatTypeLabel,
requestOrigin: origin ?? 'composer',
parentRequestId: parentRequestId?.trim() || null,
promptContextRef: promptContextRef ?? null,
status: 'accepted',
statusMessage: '요청을 접수했습니다.',
userMessageId: optimisticUserMessage.id,

View File

@@ -36,6 +36,7 @@ function mergeConversationRequests(
...item,
requestOrigin: item.requestOrigin ?? previousItem.requestOrigin ?? null,
parentRequestId: item.parentRequestId?.trim() || previousItem.parentRequestId?.trim() || null,
promptContextRef: item.promptContextRef ?? previousItem.promptContextRef ?? null,
statusMessage: nextStatusMessage,
userMessageId: item.userMessageId ?? previousItem.userMessageId,
userText: nextUserText,

View File

@@ -14,7 +14,6 @@ type UseConversationViewControllerOptions = {
activeView: 'chat' | 'runtime' | 'errors';
isMobileViewport: boolean;
previewItems: PreviewItem[];
selectedChatTypeId: string | null;
composerRef: { current: { focus: (options?: { cursor?: 'start' | 'end' | 'all' }) => void } | null };
setActiveSystemStatus: (value: string | null) => void;
setComposerAttachments: React.Dispatch<React.SetStateAction<ChatComposerAttachment[]>>;
@@ -30,7 +29,6 @@ export function useConversationViewController({
composerRef,
isMobileViewport,
previewItems,
selectedChatTypeId,
setActiveSystemStatus,
setComposerAttachments,
setCopiedMessageId,
@@ -39,6 +37,8 @@ export function useConversationViewController({
setIsSystemStatusPending,
}: UseConversationViewControllerOptions) {
const previousSessionIdRef = useRef(activeSessionId);
const previousActiveViewRef = useRef(activeView);
const hasInitializedComposerFocusRef = useRef(false);
const [activePreviewId, setActivePreviewId] = useState<string | null>(null);
const [activePreviewOverride, setActivePreviewOverride] = useState<PreviewItem | null>(null);
const [isPreviewModalOpen, setIsPreviewModalOpen] = useState(false);
@@ -158,12 +158,22 @@ export function useConversationViewController({
}, [activePreview, isPreviewModalOpen]);
useEffect(() => {
const previousActiveView = previousActiveViewRef.current;
previousActiveViewRef.current = activeView;
if (activeView !== 'chat' || isMobileViewport) {
return;
}
const shouldFocusComposer = !hasInitializedComposerFocusRef.current || previousActiveView !== 'chat';
hasInitializedComposerFocusRef.current = true;
if (!shouldFocusComposer) {
return;
}
composerRef.current?.focus({ cursor: 'end' });
}, [activeView, composerRef, isMobileViewport, selectedChatTypeId]);
}, [activeView, composerRef, isMobileViewport]);
useEffect(() => {
if (activeView !== 'chat') {

View File

@@ -7,9 +7,6 @@ import type {
const SCROLL_JUMP_HIDE_THRESHOLD = 24;
const SCROLL_JUMP_MIN_OVERFLOW = 48;
const SCROLL_JUMP_DIRECTION_THRESHOLD = 6;
const SCROLL_JUMP_IDLE_HIDE_DELAY_MS = 900;
type UseConversationViewportControllerOptions = {
activeConversation: ChatConversationSummary | null;
activeQueuedComposerRequestsCount: number;
@@ -55,7 +52,6 @@ export function useConversationViewportController({
const systemStatusTimerRef = useRef<number | null>(null);
const restoreAutoScrollFrameRef = useRef<number | null>(null);
const showScrollToBottomRef = useRef(false);
const scrollJumpIdleTimerRef = useRef<number | null>(null);
const shouldStickToBottomRef = useRef(true);
const lastViewportScrollTopRef = useRef(0);
const autoScrollSuspendedUntilRef = useRef(0);
@@ -80,13 +76,6 @@ export function useConversationViewportController({
}
}, []);
const clearScrollJumpIdleTimer = useCallback(() => {
if (scrollJumpIdleTimerRef.current !== null) {
window.clearTimeout(scrollJumpIdleTimerRef.current);
scrollJumpIdleTimerRef.current = null;
}
}, []);
const syncShowScrollToBottom = useCallback((nextValue: boolean) => {
if (showScrollToBottomRef.current === nextValue) {
return;
@@ -174,22 +163,12 @@ export function useConversationViewportController({
lastViewportScrollTopRef.current = currentScrollTop;
if (maxScrollDistance < SCROLL_JUMP_MIN_OVERFLOW || shouldStickToBottom) {
clearScrollJumpIdleTimer();
syncShowScrollToBottom(false);
return;
}
if (Math.abs(scrollDelta) >= SCROLL_JUMP_DIRECTION_THRESHOLD) {
clearScrollJumpIdleTimer();
scrollJumpIdleTimerRef.current = window.setTimeout(() => {
scrollJumpIdleTimerRef.current = null;
syncShowScrollToBottom(false);
}, SCROLL_JUMP_IDLE_HIDE_DELAY_MS);
}
syncShowScrollToBottom(true);
}, [
clearScrollJumpIdleTimer,
isAutoScrollSuspended,
releaseAutoScrollSuspension,
syncShowScrollToBottom,
@@ -528,13 +507,12 @@ export function useConversationViewportController({
useEffect(() => {
return () => {
clearSystemStatusTimer();
clearScrollJumpIdleTimer();
if (restoreAutoScrollFrameRef.current !== null) {
window.cancelAnimationFrame(restoreAutoScrollFrameRef.current);
}
};
}, [clearScrollJumpIdleTimer, clearSystemStatusTimer]);
}, [clearSystemStatusTimer]);
return {
activeSystemStatus,