Repository navigation
perf(shell): cold connects skip idle nested subagent chains, a quarter of the shell rows #35184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
d4e1cee
12313a8
f61dfb6
beadf76
7d352b4
ad29ee5
2b59d9f
c27a651
5fcd5b8
79b49ff
319364b
2d31815
b59f2c4
150caf8
418c0d5
dad1111
b302c2c
d79c6c3
400dcf8
4c18b85
9ac21c0
1a00021
0387a9f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -92,7 +92,7 @@ import { useSelectedThreadWorktree } from "../../state/use-selected-thread-workt | |
| import { useThreadComposerState } from "../../state/use-thread-composer-state"; | ||
| import { resolveMergeBackTargetThreadId } from "@t3tools/client-runtime/state/thread-relationships"; | ||
| import { resolveLatestMergeBackRun } from "@t3tools/client-runtime/state/thread-workflows"; | ||
| import { threadEnvironment } from "../../state/threads"; | ||
| import { threadEnvironment, useOpenThreadFamily } from "../../state/threads"; | ||
| import { EMPTY_ENVIRONMENT_THREAD_STATE } from "@t3tools/client-runtime/state/threads"; | ||
| import { useProjects } from "../../state/entities"; | ||
| import { projectThreadContentPresentation } from "./threadContentPresentation"; | ||
|
|
@@ -105,6 +105,7 @@ import { ThreadFileNavigatorPane } from "../files/thread-file-navigator-pane"; | |
| import { InspectorSheetContext } from "../layout/workspace-inspector-sheet"; | ||
| import type { InspectorContent } from "../layout/inspector-panes"; | ||
| import { | ||
| reopenedThreadIsGone, | ||
| threadDetailErrorIsCurrent, | ||
| threadRouteIsHydrating, | ||
| threadRouteOpensDraft, | ||
|
|
@@ -126,6 +127,10 @@ import { useStartSideChat } from "./useStartSideChat"; | |
| import { useThreadStatusAnnouncements } from "./useThreadStatusAnnouncements"; | ||
| import type { ThreadInspectorMode, ThreadInspectorTarget } from "./thread-inspector-navigation"; | ||
| import { useSelectWorkspaceDetail } from "../layout/workspace/useSelectWorkspaceDetail"; | ||
| import { | ||
| forgetWorkspaceThread, | ||
| workspaceThreadReopening, | ||
| } from "../layout/workspace/workspace-selection-store"; | ||
|
|
||
| function firstRouteParam(value: string | string[] | undefined): string | null { | ||
| const first = Array.isArray(value) ? value[0] : value; | ||
|
|
@@ -225,6 +230,27 @@ function UnavailableThreadDraftRedirect(props: { readonly environmentId: Environ | |
| return <OpeningThreadLoadingScreen />; | ||
| } | ||
|
|
||
| /** A chat the workspace reopened by itself and that cannot open: back to the list, for good. */ | ||
| function ReopenedThreadClose(props: { | ||
| readonly environmentId: EnvironmentId; | ||
| readonly threadId: ThreadId; | ||
| }) { | ||
| const goBack = useWorkspaceBackNavigation("threads"); | ||
| const navigation = useNavigation(); | ||
| const routeKey = useRoute().key; | ||
| const close = useEffectEvent(() => { | ||
| forgetWorkspaceThread(props.environmentId, props.threadId); | ||
| // iOS keeps this screen mounted after a tab switch dropped its route; going back from there | ||
| // would act on the page in front. | ||
| if (navigation.getState()?.routes.some((route) => route.key === routeKey)) goBack(); | ||
| }); | ||
| // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- leaves this route for the list on mount: the workspace reopened the chat by itself and it cannot open | ||
| useEffect(() => { | ||
| close(); | ||
| }, []); | ||
| return <OpeningThreadLoadingScreen />; | ||
| } | ||
|
|
||
| export function ThreadRouteScreen(props: ThreadRouteScreenProps) { | ||
| return ( | ||
| <ThreadScreenHost> | ||
|
|
@@ -244,7 +270,8 @@ function LiveThreadRouteController(props: ThreadRouteScreenProps) { | |
| useAndroidWorkspaceBack("threads"); | ||
| const connectionsReady = useConnectionsReady(); | ||
| const { connectionState } = useRemoteConnectionStatus(); | ||
| const { selectedThread } = useThreadSelection(); | ||
| const { selectedThread, selectedThreadListed, selectedThreadDetailRef } = useThreadSelection(); | ||
| const familyPending = useOpenThreadFamily(selectedThreadDetailRef); | ||
| const params = props.route.params ?? {}; | ||
| const environmentIdRaw = firstRouteParam(params.environmentId); | ||
| const threadIdRaw = firstRouteParam(params.threadId); | ||
|
|
@@ -265,6 +292,19 @@ function LiveThreadRouteController(props: ThreadRouteScreenProps) { | |
| ? null | ||
| : scopedThreadKey(selectedThread.environmentId, selectedThread.id); | ||
| const selectedThreadDetailState = useSelectedThreadDetailState(); | ||
| const reopening = | ||
| routeName === "Thread" && | ||
| !props.inspectorPresentation && | ||
| environmentId !== null && | ||
| threadIdRaw !== null | ||
| ? workspaceThreadReopening(environmentId, ThreadId.make(threadIdRaw)) | ||
| : null; | ||
| // A shell row proves a reopened chat exists. Until one arrives, its detail can still close it. | ||
| const [provenReopening, setProvenReopening] = useState<number | null>(null); | ||
| if (reopening !== null && selectedThreadListed && provenReopening !== reopening) { | ||
| setProvenReopening(reopening); | ||
| } | ||
| const reopenedUnproven = reopening !== null && provenReopening !== reopening; | ||
| const detailError = selectedThreadDetailState.error; | ||
| const [errorBeforeConnected, setErrorBeforeConnected] = useState(() => | ||
| routeConnectionState === "connected" ? Option.none<string>() : detailError, | ||
|
|
@@ -289,6 +329,19 @@ function LiveThreadRouteController(props: ThreadRouteScreenProps) { | |
| return withInspectorHeader(<OpeningThreadLoadingScreen />); | ||
| } | ||
|
|
||
| const closeReopened = ( | ||
| <ReopenedThreadClose environmentId={environmentId} threadId={ThreadId.make(threadIdRaw)} /> | ||
| ); | ||
| if ( | ||
| reopenedUnproven && | ||
| reopenedThreadIsGone({ | ||
| detailStatus: selectedThreadDetailState.status, | ||
| thread: selectedThreadKey === routeThreadKey ? selectedThread : null, | ||
| }) | ||
|
Comment on lines
+337
to
+340
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not close a reopened thread on archived detail before it is synced.
Gate the archived-data close on synced detail, for example a
|
||
| ) { | ||
| return closeReopened; | ||
| } | ||
|
|
||
| if (selectedThread !== null && selectedThreadKey === routeThreadKey) { | ||
| return withInspectorHeader( | ||
| <ThreadRouteContent {...props} selectedThreadDetailState={selectedThreadDetailState} />, | ||
|
|
@@ -310,6 +363,7 @@ function LiveThreadRouteController(props: ThreadRouteScreenProps) { | |
| error: detailError, | ||
| errorBeforeConnected, | ||
| }), | ||
| familyPending, | ||
| }); | ||
|
|
||
| if (stillHydrating) { | ||
|
|
@@ -324,7 +378,12 @@ function LiveThreadRouteController(props: ThreadRouteScreenProps) { | |
| detailStatus: selectedThreadDetailState.status, | ||
| }) | ||
| ) { | ||
| return <UnavailableThreadDraftRedirect environmentId={environmentId} />; | ||
| // A draft nobody asked for must not take the place of a chat that only failed to reopen. | ||
| return reopenedUnproven ? ( | ||
| closeReopened | ||
| ) : ( | ||
| <UnavailableThreadDraftRedirect environmentId={environmentId} /> | ||
| ); | ||
| } | ||
|
|
||
| return withInspectorHeader( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only the focused route should close a reopened chat.
ReopenedThreadClosechecks that its route is in the stack, but not that it is focused. If the chat was opened from inside another chat, its route can remain under the newer chat. ItsgoBack()then can remove the chat the user is working in.The current check passes for a background route. The fix should require the route to be on top:
Suggested fix