authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-10-07 22:48:56-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-07 22:48:56-07:00
log6c1ce06996979fcfe120ec8c8cb4f78a5c8a7365
tree64ac3a951150688dc6a4ffb9cc9331b3353255f6
parent7873504964c3008ed2a87ada7be62d611e7a281a
signature Signed by PGP key B5690EEEBB952194

perf(mobile): skip impossible thread-key lookups (#16263)


1 files changed, 15 insertions(+), 6 deletions(-)

apps/mobile/src/features/threads/threadListV2.ts+15-6
...@@ -237,13 +237,15 @@ export function getThreadListV2OrderedSection(input: {...@@ -237,13 +237,15 @@ export function getThreadListV2OrderedSection(input: {
237 readonly snoozeEnvironmentIds?: ReadonlySet<EnvironmentId>;237 readonly snoozeEnvironmentIds?: ReadonlySet<EnvironmentId>;
238 readonly queuedThreadKeys?: ReadonlySet<string>;238 readonly queuedThreadKeys?: ReadonlySet<string>;
239}): EnvironmentThreadShell[] {239}): EnvironmentThreadShell[] {
240 // An empty set is treated as absent so `?.` skips building the key.
241 const queuedThreadKeys = input.queuedThreadKeys?.size ? input.queuedThreadKeys : undefined;
240 const threads = input.threads.filter((thread) => {242 const threads = input.threads.filter((thread) => {
241 if (thread.archivedAt !== null || thread.lineage.relationshipToParent === "subagent")243 if (thread.archivedAt !== null || thread.lineage.relationshipToParent === "subagent")
242 return false;244 return false;
243 if (245 if (
244 (input.settlementEnvironmentIds?.has(thread.environmentId) ?? true) &&246 (input.settlementEnvironmentIds?.has(thread.environmentId) ?? true) &&
245 thread.settledOverride === "settled" &&247 thread.settledOverride === "settled" &&
246 input.queuedThreadKeys?.has(`${thread.environmentId}:${thread.id}`) !== true248 queuedThreadKeys?.has(`${thread.environmentId}:${thread.id}`) !== true
247 ) {249 ) {
248 return false;250 return false;
249 }251 }
...@@ -509,6 +511,8 @@ export function buildThreadListV2ListItems(input: {...@@ -509,6 +511,8 @@ export function buildThreadListV2ListItems(input: {
509 onto both shelf headers so the disabled state reaches recycled cells. */511 onto both shelf headers so the disabled state reaches recycled cells. */
510 readonly shelfPreferencesLoading?: boolean;512 readonly shelfPreferencesLoading?: boolean;
511}): ThreadListV2ListItem[] {513}): ThreadListV2ListItem[] {
514 // An empty set is treated as absent so `?.` skips building the key.
515 const queuedThreadKeys = input.queuedThreadKeys?.size ? input.queuedThreadKeys : undefined;
512 const threadItems = input.items.map((item): ThreadListV2ListItem => {516 const threadItems = input.items.map((item): ThreadListV2ListItem => {
513 const snoozeWakeLabelText =517 const snoozeWakeLabelText =
514 item.snoozed && item.thread.snoozedUntil != null && input.snoozeLabelNow !== undefined518 item.snoozed && item.thread.snoozedUntil != null && input.snoozeLabelNow !== undefined
...@@ -539,7 +543,7 @@ export function buildThreadListV2ListItems(input: {...@@ -539,7 +543,7 @@ export function buildThreadListV2ListItems(input: {
539 snoozePresetMinute,543 snoozePresetMinute,
540 showTrailingDivider: false,544 showTrailingDivider: false,
541 hasQueuedMessages:545 hasQueuedMessages:
542 input.queuedThreadKeys?.has(`${item.thread.environmentId}:${item.thread.id}`) === true,546 queuedThreadKeys?.has(`${item.thread.environmentId}:${item.thread.id}`) === true,
543 canMoveUp: move?.canMoveUp === true,547 canMoveUp: move?.canMoveUp === true,
544 canMoveDown: move?.canMoveDown === true,548 canMoveDown: move?.canMoveDown === true,
545 };549 };
...@@ -675,6 +679,8 @@ export function buildThreadListV2Items(input: {...@@ -675,6 +679,8 @@ export function buildThreadListV2Items(input: {
675 const settled: EnvironmentThreadShell[] = [];679 const settled: EnvironmentThreadShell[] = [];
676 const snoozed: EnvironmentThreadShell[] = [];680 const snoozed: EnvironmentThreadShell[] = [];
677 let nextSnoozeWakeAt: string | null = null;681 let nextSnoozeWakeAt: string | null = null;
682 // An empty set is treated as absent so `?.` skips building the key.
683 const queuedThreadKeys = input.queuedThreadKeys?.size ? input.queuedThreadKeys : undefined;
678 for (const thread of input.threads) {684 for (const thread of input.threads) {
679 if (thread.archivedAt !== null || thread.lineage.relationshipToParent === "subagent") continue;685 if (thread.archivedAt !== null || thread.lineage.relationshipToParent === "subagent") continue;
680 // The server stamps settledOverride for the tail.686 // The server stamps settledOverride for the tail.
...@@ -712,7 +718,7 @@ export function buildThreadListV2Items(input: {...@@ -712,7 +718,7 @@ export function buildThreadListV2Items(input: {
712 continue;718 continue;
713 }719 }
714 const hasQueuedMessages =720 const hasQueuedMessages =
715 input.queuedThreadKeys?.has(`${thread.environmentId}:${thread.id}`) === true;721 queuedThreadKeys?.has(`${thread.environmentId}:${thread.id}`) === true;
716 if (supportsSettlement && thread.settledOverride === "settled" && !hasQueuedMessages) {722 if (supportsSettlement && thread.settledOverride === "settled" && !hasQueuedMessages) {
717 settled.push(thread);723 settled.push(thread);
718 } else if (thread.pinnedAt != null) {724 } else if (thread.pinnedAt != null) {
...@@ -752,9 +758,12 @@ export function buildThreadListV2Items(input: {...@@ -752,9 +758,12 @@ export function buildThreadListV2Items(input: {
752 const settledLimit = input.settledLimit ?? Number.POSITIVE_INFINITY;758 const settledLimit = input.settledLimit ?? Number.POSITIVE_INFINITY;
753 const pagedSettled =759 const pagedSettled =
754 orderedSettled.length > settledLimit ? orderedSettled.slice(0, settledLimit) : orderedSettled;760 orderedSettled.length > settledLimit ? orderedSettled.slice(0, settledLimit) : orderedSettled;
755 const selectedSettled = orderedSettled761 const selectedSettled =
756 .slice(pagedSettled.length)762 selectedThreadKey === null
757 .find((thread) => `${thread.environmentId}:${thread.id}` === selectedThreadKey);763 ? undefined
764 : orderedSettled
765 .slice(pagedSettled.length)
766 .find((thread) => `${thread.environmentId}:${thread.id}` === selectedThreadKey);
758 if (selectedSettled !== undefined) pagedSettled.push(selectedSettled);767 if (selectedSettled !== undefined) pagedSettled.push(selectedSettled);
759 const visibleSettled =768 const visibleSettled =
760 input.settledShelfExpanded !== false769 input.settledShelfExpanded !== false