| ... | ... | @@ -10913,6 +10913,45 @@ export default function ChatView(props: ChatViewProps) { |
| 10913 | 10913 | }, [cancelWorktreeSetup, draftId, setupTarget.environmentId, worktreeSetup]); |
| 10914 | 10914 | const onSendRef = useRef(onSend); |
| 10915 | 10915 | onSendRef.current = onSend; |
| 10916 | const onResumeRef = useRef(onResume); |
| 10917 | onResumeRef.current = onResume; |
| 10918 | const onCompactContextRef = useRef(onCompactContext); |
| 10919 | onCompactContextRef.current = onCompactContext; |
| 10920 | const onComposerSend = useCallback( |
| 10921 | (...args: Parameters<typeof onSend>) => onSendRef.current(...args), |
| 10922 | [], |
| 10923 | ); |
| 10924 | const onComposerResume = useCallback(() => onResumeRef.current(), []); |
| 10925 | const onComposerCompactContext = useCallback(() => onCompactContextRef.current(), []); |
| 10926 | const queuedRunsControl = useMemo( |
| 10927 | () => |
| 10928 | isServerThread && activeThread ? ( |
| 10929 | <QueuedRunsControl |
| 10930 | ref={queuedRunsControlRef} |
| 10931 | steerShortcutLabel={shortcutLabelForCommand(keybindings, "thread.steerQueuedMessage", { |
| 10932 | context: { terminalFocus: false }, |
| 10933 | })} |
| 10934 | editShortcutLabel={shortcutLabelForCommand(keybindings, "thread.editQueuedMessage", { |
| 10935 | context: { composerFocus: true }, |
| 10936 | })} |
| 10937 | environmentId={activeThread.environmentId} |
| 10938 | threadId={activeThread.id} |
| 10939 | optimisticMessages={optimisticUserMessages} |
| 10940 | editingRunId={editingQueuedRun?.runId ?? null} |
| 10941 | onEditQueuedRun={beginEditingQueuedRun} |
| 10942 | onCancelEdit={cancelEditingQueuedRun} |
| 10943 | /> |
| 10944 | ) : null, |
| 10945 | [ |
| 10946 | activeThread, |
| 10947 | beginEditingQueuedRun, |
| 10948 | cancelEditingQueuedRun, |
| 10949 | editingQueuedRun?.runId, |
| 10950 | isServerThread, |
| 10951 | keybindings, |
| 10952 | optimisticUserMessages, |
| 10953 | ], |
| 10954 | ); |
| 10916 | 10955 | // Resend once the cancelled dispatch has settled and the composer is free. |
| 10917 | 10956 | // Every state that makes `onSend` bail and wait is part of the readiness |
| 10918 | 10957 | // check, so the flag survives a reconnect, a reverting checkpoint, or a |
| ... | ... | @@ -10977,12 +11016,21 @@ export default function ChatView(props: ChatViewProps) { |
| 10977 | 11016 | const onOpenTurnDiff = useCallback( |
| 10978 | 11017 | (runId: RunId, filePath?: string) => { |
| 10979 | 11018 | if (!isServerThread || !activeThreadRef) return; |
| 11019 | const diffOpen = |
| 11020 | selectActiveRightPanel(useRightPanelStore.getState().byThreadKey, activeThreadRef) === |
| 11021 | "diff"; |
| 10980 | 11022 | explicitDiffOpenRef.current = diffOpen ? null : activeThreadRef; |
| 10981 | 11023 | useDiffPanelStore.getState().selectTurn(activeThreadRef, runId, filePath); |
| 10982 | 11024 | useRightPanelStore.getState().open(activeThreadRef, "diff"); |
| 10983 | 11025 | onDiffPanelOpen?.(); |
| 10984 | 11026 | }, |
| 10985 | | [activeThreadRef, diffOpen, isServerThread, onDiffPanelOpen], |
| 11027 | [activeThreadRef, isServerThread, onDiffPanelOpen], |
| 11028 | ); |
| 11029 | const onTimelineRollbackCheckpoint = useCallback( |
| 11030 | (input: { readonly checkpointId: string; readonly scopeId: string }) => { |
| 11031 | if (!paintOnlyDisplayedTimeline) void onRollbackCheckpoint(input); |
| 11032 | }, |
| 11033 | [onRollbackCheckpoint, paintOnlyDisplayedTimeline], |
| 10986 | 11034 | ); |
| 10987 | 11035 | // The revert handler is read from a ref at call-time so the callback |
| 10988 | 11036 | // reference is fully stable and never busts TimelineRowCtx identity. |
| ... | ... | @@ -11504,9 +11552,7 @@ export default function ChatView(props: ChatViewProps) { |
| 11504 | 11552 | onOpenThread={onOpenRelatedThread} |
| 11505 | 11553 | parentThreadLink={paintOnlyDisplayedTimeline ? null : parentThreadLink} |
| 11506 | 11554 | onForkFromRun={paintOnlyDisplayedTimeline ? async () => {} : onForkFromRun} |
| 11507 | | onRollbackCheckpoint={(input) => { |
| 11508 | | if (!paintOnlyDisplayedTimeline) void onRollbackCheckpoint(input); |
| 11509 | | }} |
| 11555 | onRollbackCheckpoint={onTimelineRollbackCheckpoint} |
| 11510 | 11556 | supportsConversationRollback={ |
| 11511 | 11557 | !paintOnlyDisplayedTimeline && supportsConversationRollback |
| 11512 | 11558 | } |
| ... | ... | @@ -11711,29 +11757,7 @@ export default function ChatView(props: ChatViewProps) { |
| 11711 | 11757 | : projectCloneSendBlockReason |
| 11712 | 11758 | } |
| 11713 | 11759 | isPreparingWorktree={isPreparingWorktree && !sendQueuesBehindSetup} |
| 11714 | | queuedRunsControl={ |
| 11715 | | isServerThread && activeThread ? ( |
| 11716 | | <QueuedRunsControl |
| 11717 | | ref={queuedRunsControlRef} |
| 11718 | | steerShortcutLabel={shortcutLabelForCommand( |
| 11719 | | keybindings, |
| 11720 | | "thread.steerQueuedMessage", |
| 11721 | | { context: { terminalFocus: false } }, |
| 11722 | | )} |
| 11723 | | editShortcutLabel={shortcutLabelForCommand( |
| 11724 | | keybindings, |
| 11725 | | "thread.editQueuedMessage", |
| 11726 | | { context: { composerFocus: true } }, |
| 11727 | | )} |
| 11728 | | environmentId={activeThread.environmentId} |
| 11729 | | threadId={activeThread.id} |
| 11730 | | optimisticMessages={optimisticUserMessages} |
| 11731 | | editingRunId={editingQueuedRun?.runId ?? null} |
| 11732 | | onEditQueuedRun={beginEditingQueuedRun} |
| 11733 | | onCancelEdit={cancelEditingQueuedRun} |
| 11734 | | /> |
| 11735 | | ) : null |
| 11736 | | } |
| 11760 | queuedRunsControl={queuedRunsControl} |
| 11737 | 11761 | bannerItems={composerBannerItems} |
| 11738 | 11762 | resumeCompactionTokens={resumeCompactionTokens} |
| 11739 | 11763 | keepFullHistory={keepFullHistory} |
| ... | ... | @@ -11807,9 +11831,9 @@ export default function ChatView(props: ChatViewProps) { |
| 11807 | 11831 | onPageScrollKeyDown={onComposerPageScrollKeyDown} |
| 11808 | 11832 | onPageScrollKeyUp={onComposerPageScrollKeyUp} |
| 11809 | 11833 | onPageScrollRelease={onComposerPageScrollRelease} |
| 11810 | | onCompactContext={onCompactContext} |
| 11811 | | onSend={onSend} |
| 11812 | | onResume={onResume} |
| 11834 | onCompactContext={onComposerCompactContext} |
| 11835 | onSend={onComposerSend} |
| 11836 | onResume={onComposerResume} |
| 11813 | 11837 | onInterrupt={onInterrupt} |
| 11814 | 11838 | onImplementPlanInNewThread={onImplementPlanInNewThread} |
| 11815 | 11839 | onRespondToApproval={onRespondToApproval} |