| @@ -111,14 +111,13 @@ import type { UnifiedSettings } from "@t3tools/contracts/settings"; · 110 unmodified lines |
| 111 | import type { SessionPhase, Thread } from "../../types"; | 111 | import type { SessionPhase, Thread } from "../../types"; |
| 112 | import type { PendingUserInputDraftAnswer } from "../../pendingUserInput"; | 112 | import type { PendingUserInputDraftAnswer } from "../../pendingUserInput"; |
| 113 | import type { PendingApproval, PendingUserInput } from "../../session-logic"; | 113 | import type { PendingApproval, PendingUserInput } from "../../session-logic"; |
| 114 | import { | 114 | import { type ContextWindowSnapshot, formatProviderDisplayName } from "../../lib/contextWindow"; |
| 115 | deriveLatestContextWindowSnapshot, | | |
| 116 | formatProviderDisplayName, | | |
| 117 | } from "../../lib/contextWindow"; | | |
| 118 | import { formatProviderSkillDisplayName } from "../../providerSkillPresentation"; | 115 | import { formatProviderSkillDisplayName } from "../../providerSkillPresentation"; |
| 119 | import { searchProviderSkills } from "../../providerSkillSearch"; | 116 | import { searchProviderSkills } from "../../providerSkillSearch"; |
| 120 | import { useMediaQuery } from "../../hooks/useMediaQuery"; | 117 | import { useMediaQuery } from "../../hooks/useMediaQuery"; |
| 121 | import type { ReviewCommentContext } from "../../reviewCommentContext"; | 118 | import type { ReviewCommentContext } from "../../reviewCommentContext"; |
| | 119 | import { useStore } from "../../store"; |
| | 120 | import { createContextWindowSnapshotSelectorByRef } from "../../storeSelectors"; |
| 122 | | 121 | |
| 123 | const IMAGE_SIZE_LIMIT_LABEL = `${Math.round(PROVIDER_SEND_TURN_MAX_IMAGE_BYTES / (1024 * 1024))}MB`; | 122 | const IMAGE_SIZE_LIMIT_LABEL = `${Math.round(PROVIDER_SEND_TURN_MAX_IMAGE_BYTES / (1024 * 1024))}MB`; |
| 124 | | 123 | |
| @@ -323,7 +322,7 @@ const ComposerFooterModeControls = memo(function ComposerFooterModeControls(prop · 198 unmodified lines |
| 323 | | 322 | |
| 324 | const ComposerFooterPrimaryActions = memo(function ComposerFooterPrimaryActions(props: { | 323 | const ComposerFooterPrimaryActions = memo(function ComposerFooterPrimaryActions(props: { |
| 325 | compact: boolean; | 324 | compact: boolean; |
| 326 | activeContextWindow: ReturnType<typeof deriveLatestContextWindowSnapshot>; | 325 | activeContextWindow: ContextWindowSnapshot | null; |
| 327 | activeThreadProviderDisplayName: string | null; | 326 | activeThreadProviderDisplayName: string | null; |
| 328 | isPreparingWorktree: boolean; | 327 | isPreparingWorktree: boolean; |
| 329 | pendingAction: { | 328 | pendingAction: { |
| @@ -432,7 +431,7 @@ export interface ChatComposerProps { · 102 unmodified lines |
| 432 | // Thread context | 431 | // Thread context |
| 433 | activeThreadId: ThreadId | null; | 432 | activeThreadId: ThreadId | null; |
| 434 | activeThreadEnvironmentId: EnvironmentId | undefined; | 433 | activeThreadEnvironmentId: EnvironmentId | undefined; |
| 435 | activeThread: Thread | undefined; | 434 | activeThreadSessionProviderInstanceId: ProviderInstanceId | undefined; |
| 436 | isServerThread: boolean; | 435 | isServerThread: boolean; |
| 437 | isLocalDraftThread: boolean; | 436 | isLocalDraftThread: boolean; |
| 438 | | 437 | |
| @@ -481,9 +480,6 @@ export interface ChatComposerProps { · 42 unmodified lines |
| 481 | activeProjectDefaultModelSelection: ModelSelection | null | undefined; | 480 | activeProjectDefaultModelSelection: ModelSelection | null | undefined; |
| 482 | activeThreadModelSelection: ModelSelection | null | undefined; | 481 | activeThreadModelSelection: ModelSelection | null | undefined; |
| 483 | | 482 | |
| 484 | // Context window | | |
| 485 | activeThreadActivities: Thread["activities"] | undefined; | | |
| 486 | | | |
| 487 | // Misc | 483 | // Misc |
| 488 | resolvedTheme: "light" | "dark"; | 484 | resolvedTheme: "light" | "dark"; |
| 489 | settings: UnifiedSettings; | 485 | settings: UnifiedSettings; |
| @@ -547,7 +543,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) · 57 unmodified lines |
| 547 | draftId, | 543 | draftId, |
| 548 | activeThreadId, | 544 | activeThreadId, |
| 549 | activeThreadEnvironmentId: _activeThreadEnvironmentId, | 545 | activeThreadEnvironmentId: _activeThreadEnvironmentId, |
| 550 | activeThread, | 546 | activeThreadSessionProviderInstanceId, |
| 551 | isServerThread: _isServerThread, | 547 | isServerThread: _isServerThread, |
| 552 | isLocalDraftThread: _isLocalDraftThread, | 548 | isLocalDraftThread: _isLocalDraftThread, |
| 553 | phase, | 549 | phase, |
| @@ -576,7 +572,6 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) · 22 unmodified lines |
| 576 | providerStatuses, | 572 | providerStatuses, |
| 577 | activeProjectDefaultModelSelection, | 573 | activeProjectDefaultModelSelection, |
| 578 | activeThreadModelSelection, | 574 | activeThreadModelSelection, |
| 579 | activeThreadActivities, | | |
| 580 | resolvedTheme, | 575 | resolvedTheme, |
| 581 | settings, | 576 | settings, |
| 582 | keybindings, | 577 | keybindings, |
| @@ -663,7 +658,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) · 80 unmodified lines |
| 663 | ); | 658 | ); |
| 664 | const selectedProviderByThreadId = composerDraft.activeProvider ?? null; | 659 | const selectedProviderByThreadId = composerDraft.activeProvider ?? null; |
| 665 | const threadProvider = | 660 | const threadProvider = |
| 666 | activeThread?.session?.providerInstanceId ?? | 661 | activeThreadSessionProviderInstanceId ?? |
| 667 | activeThreadModelSelection?.instanceId ?? | 662 | activeThreadModelSelection?.instanceId ?? |
| 668 | activeProjectDefaultModelSelection?.instanceId ?? | 663 | activeProjectDefaultModelSelection?.instanceId ?? |
| 669 | null; | 664 | null; |
| @@ -677,16 +672,17 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) · 7 unmodified lines |
| 677 | ) ?? ProviderDriverKind.make("codex"); | 672 | ) ?? ProviderDriverKind.make("codex"); |
| 678 | const selectedProvider: ProviderDriverKind = lockedProvider ?? unlockedSelectedProvider; | 673 | const selectedProvider: ProviderDriverKind = lockedProvider ?? unlockedSelectedProvider; |
| 679 | const lockedContinuationGroupKey = useMemo((): string | null => { | 674 | const lockedContinuationGroupKey = useMemo((): string | null => { |
| 680 | if (!lockedProvider || !activeThread) return null; | 675 | if (!lockedProvider || !activeThreadId) return null; |
| 681 | const lockedInstanceId = | 676 | const lockedInstanceId = |
| 682 | activeThread.session?.providerInstanceId ?? activeThreadModelSelection?.instanceId; | 677 | activeThreadSessionProviderInstanceId ?? activeThreadModelSelection?.instanceId; |
| 683 | if (!lockedInstanceId) return null; | 678 | if (!lockedInstanceId) return null; |
| 684 | return ( | 679 | return ( |
| 685 | providerInstanceEntries.find((entry) => entry.instanceId === lockedInstanceId) | 680 | providerInstanceEntries.find((entry) => entry.instanceId === lockedInstanceId) |
| 686 | ?.continuationGroupKey ?? null | 681 | ?.continuationGroupKey ?? null |
| 687 | ); | 682 | ); |
| 688 | }, [ | 683 | }, [ |
| 689 | activeThread, | 684 | activeThreadId, |
| | 685 | activeThreadSessionProviderInstanceId, |
| 690 | activeThreadModelSelection?.instanceId, | 686 | activeThreadModelSelection?.instanceId, |
| 691 | lockedProvider, | 687 | lockedProvider, |
| 692 | providerInstanceEntries, | 688 | providerInstanceEntries, |
| @@ -705,7 +701,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) · 12 unmodified lines |
| 705 | const selectedInstanceId = useMemo<ProviderInstanceId>(() => { | 701 | const selectedInstanceId = useMemo<ProviderInstanceId>(() => { |
| 706 | const candidates: Array<string | null | undefined> = [ | 702 | const candidates: Array<string | null | undefined> = [ |
| 707 | composerDraft.activeProvider, | 703 | composerDraft.activeProvider, |
| 708 | activeThread?.session?.providerInstanceId, | 704 | activeThreadSessionProviderInstanceId, |
| 709 | activeThreadModelSelection?.instanceId, | 705 | activeThreadModelSelection?.instanceId, |
| 710 | activeProjectDefaultModelSelection?.instanceId, | 706 | activeProjectDefaultModelSelection?.instanceId, |
| 711 | ]; | 707 | ]; |
| @@ -747,7 +743,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) · 35 unmodified lines |
| 747 | ); | 743 | ); |
| 748 | }, [ | 744 | }, [ |
| 749 | activeProjectDefaultModelSelection?.instanceId, | 745 | activeProjectDefaultModelSelection?.instanceId, |
| 750 | activeThread?.session?.providerInstanceId, | 746 | activeThreadSessionProviderInstanceId, |
| 751 | activeThreadModelSelection?.instanceId, | 747 | activeThreadModelSelection?.instanceId, |
| 752 | composerDraft.activeProvider, | 748 | composerDraft.activeProvider, |
| 753 | explicitSelectedInstanceId, | 749 | explicitSelectedInstanceId, |
| @@ -841,10 +837,11 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) · 87 unmodified lines |
| 841 | // ------------------------------------------------------------------ | 837 | // ------------------------------------------------------------------ |
| 842 | // Context window | 838 | // Context window |
| 843 | // ------------------------------------------------------------------ | 839 | // ------------------------------------------------------------------ |
| 844 | const activeContextWindow = useMemo( | 840 | const contextWindowSelector = useMemo( |
| 845 | () => deriveLatestContextWindowSnapshot(activeThreadActivities ?? []), | 841 | () => createContextWindowSnapshotSelectorByRef(routeThreadRef), |
| 846 | [activeThreadActivities], | 842 | [routeThreadRef], |
| 847 | ); | 843 | ); |
| | 844 | const activeContextWindow = useStore(contextWindowSelector); |
| 848 | const activeThreadProviderDisplayName = useMemo(() => { | 845 | const activeThreadProviderDisplayName = useMemo(() => { |
| 849 | if (!activeThreadModelSelection) return null; | 846 | if (!activeThreadModelSelection) return null; |
| 850 | const entry = providerStatuses.find( | 847 | const entry = providerStatuses.find( |
| @@ -1969,7 +1966,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) · 1118 unmodified lines |
| 1969 | ); | 1966 | ); |
| 1970 | }, | 1967 | }, |
| 1971 | addTerminalContext: (selection: TerminalContextSelection) => { | 1968 | addTerminalContext: (selection: TerminalContextSelection) => { |
| 1972 | if (!activeThread) return; | 1969 | if (!activeThreadId) return; |
| 1973 | const snapshot = composerEditorRef.current?.readSnapshot() ?? { | 1970 | const snapshot = composerEditorRef.current?.readSnapshot() ?? { |
| 1974 | value: promptRef.current, | 1971 | value: promptRef.current, |
| 1975 | cursor: composerCursor, | 1972 | cursor: composerCursor, |
| @@ -1989,7 +1986,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) · 13 unmodified lines |
| 1989 | insertion.prompt, | 1986 | insertion.prompt, |
| 1990 | { | 1987 | { |
| 1991 | id: randomUUID(), | 1988 | id: randomUUID(), |
| 1992 | threadId: activeThread.id, | 1989 | threadId: activeThreadId, |
| 1993 | createdAt: new Date().toISOString(), | 1990 | createdAt: new Date().toISOString(), |
| 1994 | ...selection, | 1991 | ...selection, |
| 1995 | }, | 1992 | }, |
| @@ -2019,7 +2016,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) · 23 unmodified lines |
| 2019 | }), | 2016 | }), |
| 2020 | }), | 2017 | }), |
| 2021 | [ | 2018 | [ |
| 2022 | activeThread, | 2019 | activeThreadId, |
| 2023 | composerDraftTarget, | 2020 | composerDraftTarget, |
| 2024 | composerCursor, | 2021 | composerCursor, |
| 2025 | composerTerminalContexts, | 2022 | composerTerminalContexts, |