From 41ef0324ec6e07103bb8e484a1dda2429b29ad8a Mon Sep 17 00:00:00 2001 From: flamboh Date: Tue, 20 Oct 2026 04:44:39 +0000 Subject: [PATCH 1/6] fix(mobile): new-task context no longer changes every render --- .../threads/new-task-flow-provider.tsx | 126 +++++++++--------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/apps/mobile/src/features/threads/new-task-flow-provider.tsx b/apps/mobile/src/features/threads/new-task-flow-provider.tsx index 23618df9c8e60..5073f28b482ae 100644 --- a/apps/mobile/src/features/threads/new-task-flow-provider.tsx +++ b/apps/mobile/src/features/threads/new-task-flow-provider.tsx @@ -357,68 +357,6 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { isScratchProject(selectedProject, selectedEnvironmentServerConfig?.scratchWorkspaceRoot); const serverConfigs = useServerConfigs(); const { connectedEnvironments } = useRemoteConnectionStatus(); - const scratchEnvironments = connectedEnvironments.filter( - (environment) => - availableScratchWorkspaceRoot( - environment.connectionState, - serverConfigs.get(environment.environmentId), - ) !== null, - ); - - const selectedRepositoryKey = selectedProject?.repositoryIdentity - ? repositoryGroupingKeyOf(selectedProject.repositoryIdentity) - : null; - // `|| null` (not `??`): a pending-task placeholder project can have an empty - // workspaceRoot, and an "" basename would reject every real host below. - const selectedWorkspaceBasename = selectedProject?.workspaceRoot.split("/").at(-1) || null; - const selectedProjectTitle = selectedProject?.title ?? null; - const environments = (() => { - if (isScratchDraft) { - return scratchEnvironments.map((environment) => ({ - environmentId: environment.environmentId, - environmentLabel: environment.environmentLabel, - })); - } - const seen = new Set(); - const result: Array<{ - readonly environmentId: EnvironmentId; - readonly environmentLabel: string; - }> = []; - const hostsSelectedRepository = (project: EnvironmentProject) => { - if (selectedRepositoryKey === null && selectedWorkspaceBasename === null) { - return true; - } - const projectKey = project.repositoryIdentity - ? repositoryGroupingKeyOf(project.repositoryIdentity) - : null; - if (selectedRepositoryKey !== null && projectKey !== null) { - return projectKey === selectedRepositoryKey; - } - return ( - project.workspaceRoot.split("/").at(-1) === selectedWorkspaceBasename || - (selectedProjectTitle !== null && project.title === selectedProjectTitle) - ); - }; - for (const project of projects) { - if (!hostsSelectedRepository(project)) { - continue; - } - if (seen.has(project.environmentId)) { - continue; - } - const environment = savedConnectionsById[project.environmentId]; - if (!environment) { - continue; - } - seen.add(project.environmentId); - result.push({ - environmentId: project.environmentId, - environmentLabel: environment.environmentLabel, - }); - } - return result; - })(); - const selectedProjectDraftKey = editingPendingTask ? pendingTaskDraftKey(editingPendingTask.messageId) : selectedProject @@ -481,6 +419,7 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { }) : null, ); + const storedStickyModelSelection = useStickyComposerModelSelection(); const t3ProjectFileData = t3ProjectFileQuery.data as ProjectReadFileResult | null; const t3ProjectFile = t3ProjectFileData === null || t3ProjectFileData.exists === false || t3ProjectFileData.truncated @@ -547,7 +486,6 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { projectSettings.settings.defaultModelSelection, selectedProject?.id ?? null, ); - const storedStickyModelSelection = useStickyComposerModelSelection(); const stickyModelSelection = resolveDefaultableModelSelection( selectedEnvironmentServerConfig, storedStickyModelSelection, @@ -1142,6 +1080,68 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { [], ); + const scratchEnvironments = connectedEnvironments.filter( + (environment) => + availableScratchWorkspaceRoot( + environment.connectionState, + serverConfigs.get(environment.environmentId), + ) !== null, + ); + + const selectedRepositoryKey = selectedProject?.repositoryIdentity + ? repositoryGroupingKeyOf(selectedProject.repositoryIdentity) + : null; + // `|| null` (not `??`): a pending-task placeholder project can have an empty + // workspaceRoot, and an "" basename would reject every real host below. + const selectedWorkspaceBasename = selectedProject?.workspaceRoot.split("/").at(-1) || null; + const selectedProjectTitle = selectedProject?.title ?? null; + const environments = (() => { + if (isScratchDraft) { + return scratchEnvironments.map((environment) => ({ + environmentId: environment.environmentId, + environmentLabel: environment.environmentLabel, + })); + } + const seen = new Set(); + const result: Array<{ + readonly environmentId: EnvironmentId; + readonly environmentLabel: string; + }> = []; + const hostsSelectedRepository = (project: EnvironmentProject) => { + if (selectedRepositoryKey === null && selectedWorkspaceBasename === null) { + return true; + } + const projectKey = project.repositoryIdentity + ? repositoryGroupingKeyOf(project.repositoryIdentity) + : null; + if (selectedRepositoryKey !== null && projectKey !== null) { + return projectKey === selectedRepositoryKey; + } + return ( + project.workspaceRoot.split("/").at(-1) === selectedWorkspaceBasename || + (selectedProjectTitle !== null && project.title === selectedProjectTitle) + ); + }; + for (const project of projects) { + if (!hostsSelectedRepository(project)) { + continue; + } + if (seen.has(project.environmentId)) { + continue; + } + const environment = savedConnectionsById[project.environmentId]; + if (!environment) { + continue; + } + seen.add(project.environmentId); + result.push({ + environmentId: project.environmentId, + environmentLabel: environment.environmentLabel, + }); + } + return result; + })(); + const value = { projectScopes, selectedEnvironmentId, From 009bff2da40e8919ba876e788a1d86b85329265e Mon Sep 17 00:00:00 2001 From: flamboh Date: Wed, 21 Oct 2026 19:15:34 +0000 Subject: [PATCH 2/6] test(mobile): pin the compiler cache for the new-task context --- apps/mobile/src/reactCompilerCoverage.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/mobile/src/reactCompilerCoverage.test.ts b/apps/mobile/src/reactCompilerCoverage.test.ts index f51c729f319e4..24e64098a2fb6 100644 --- a/apps/mobile/src/reactCompilerCoverage.test.ts +++ b/apps/mobile/src/reactCompilerCoverage.test.ts @@ -191,6 +191,14 @@ describe("React Compiler coverage", () => { ).toEqual([true]); }); + // The compiler once silently dropped these caches, so the new-task context + // value changed on every provider render and re-rendered every consumer. + it("caches the new-task model options and host environments", () => { + const file = "src/features/threads/new-task-flow-provider.tsx"; + expect(compilerCachedCalls(file, "buildModelOptions")).toEqual([true]); + expect(compilerCachedCalls(file, "repositoryGroupingKeyOf")).toEqual([true, true]); + }); + it("lists only files that exist", () => { expect(Object.keys(KNOWN_BAILOUTS).filter((file) => !sourceFiles.includes(file))).toEqual([]); }); From 7955f1178cee78e12245fdb2e7ccd6b73f405f89 Mon Sep 17 00:00:00 2001 From: flamboh Date: Tue, 20 Oct 2026 04:44:35 +0000 Subject: [PATCH 3/6] fix(mobile): branch list hook returns the same values across renders --- apps/mobile/src/state/queries.ts | 61 ++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/apps/mobile/src/state/queries.ts b/apps/mobile/src/state/queries.ts index 2f64e6f164af4..ce13c00523186 100644 --- a/apps/mobile/src/state/queries.ts +++ b/apps/mobile/src/state/queries.ts @@ -43,7 +43,7 @@ const COMPOSER_PATH_SEARCH_LIMIT = 20; const THREAD_SEARCH_DEBOUNCE_MS = 200; const VCS_REF_LIST_LIMIT = 100; const EMPTY_REFS: ReadonlyArray = []; -const INITIAL_BRANCH_CURSORS = [undefined] as const; +const INITIAL_BRANCH_CURSORS = [null] as const; const EMPTY_THREAD_SEARCH_MATCHES: ReadonlyArray = Object.freeze([]); const EMPTY_THREAD_SEARCH_ATOM = Atom.make({ matches: EMPTY_THREAD_SEARCH_MATCHES, @@ -202,6 +202,37 @@ export function useBranches(input: { ); } +const branchPageAtom = ( + environmentId: EnvironmentId, + cwd: string, + query: string, + cursor: number | null, +) => + vcsEnvironment.listRefs({ + environmentId, + input: { + cwd, + ...(query.length > 0 ? { query } : {}), + ...(cursor === null ? {} : { cursor }), + limit: VCS_REF_LIST_LIMIT, + }, + }); +const branchPagesAtom = Atom.family((key: string) => { + const [environmentId, cwd, query, cursors] = JSON.parse(key) as [ + EnvironmentId, + string, + string, + ReadonlyArray, + ]; + const pageAtoms = cursors.map((cursor) => branchPageAtom(environmentId, cwd, query, cursor)); + return Atom.make((get) => pageAtoms.map((atom) => get(atom))).pipe( + Atom.withLabel(`mobile:vcs-ref-pages:${key}`), + ); +}); +const EMPTY_BRANCH_PAGES_ATOM = Atom.make( + (): ReadonlyArray>> => [], +).pipe(Atom.withLabel("mobile:vcs-ref-pages:empty")); + export function usePaginatedBranches(target: VcsRefTarget) { const query = target.query?.trim() ?? ""; const targetKey = @@ -210,30 +241,17 @@ export function usePaginatedBranches(target: VcsRefTarget) { : null; const [pagination, setPagination] = useState<{ readonly targetKey: string | null; - readonly cursors: ReadonlyArray; + readonly cursors: ReadonlyArray; }>({ targetKey, cursors: INITIAL_BRANCH_CURSORS, }); const cursors = pagination.targetKey === targetKey ? pagination.cursors : INITIAL_BRANCH_CURSORS; - const pageAtoms = - target.environmentId !== null && target.cwd !== null - ? cursors.map((cursor) => - vcsEnvironment.listRefs({ - environmentId: target.environmentId!, - input: { - cwd: target.cwd!, - ...(query.length > 0 ? { query } : {}), - ...(cursor === undefined ? {} : { cursor }), - limit: VCS_REF_LIST_LIMIT, - }, - }), - ) - : []; - const pagesAtom = Atom.make((get) => pageAtoms.map((atom) => get(atom))).pipe( - Atom.withLabel(`mobile:vcs-ref-pages:${targetKey ?? "empty"}`), + const pagesKey = + targetKey === null ? null : JSON.stringify([target.environmentId, target.cwd, query, cursors]); + const results = useAtomValue( + pagesKey === null ? EMPTY_BRANCH_PAGES_ATOM : branchPagesAtom(pagesKey), ); - const results = useAtomValue(pagesAtom); const values = results.flatMap((result) => { const value = Option.getOrNull(AsyncResult.value(result)); return value === null ? [] : [value]; @@ -272,10 +290,9 @@ export function usePaginatedBranches(target: VcsRefTarget) { })() : null; const refresh = () => { - const firstPage = pageAtoms[0]; setPagination({ targetKey, cursors: INITIAL_BRANCH_CURSORS }); - if (firstPage !== undefined) { - appAtomRegistry.refresh(firstPage); + if (target.environmentId !== null && target.cwd !== null) { + appAtomRegistry.refresh(branchPageAtom(target.environmentId, target.cwd, query, null)); } }; const loadNext = () => { From d0b3980a63f44f4ab3da19612b0568d129a4c8b8 Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Mon, 26 Oct 2026 19:09:03 +0000 Subject: [PATCH 4/6] fix(mobile): simplify branch caching and cover compiled rerenders --- .../threads/new-task-flow-provider.tsx | 2 +- .../src/state/queries.debounce.test.tsx | 105 +++++++++++++++++- apps/mobile/src/state/queries.ts | 68 +++++------- 3 files changed, 131 insertions(+), 44 deletions(-) diff --git a/apps/mobile/src/features/threads/new-task-flow-provider.tsx b/apps/mobile/src/features/threads/new-task-flow-provider.tsx index 91eacc1f92260..fbcd2427c2722 100644 --- a/apps/mobile/src/features/threads/new-task-flow-provider.tsx +++ b/apps/mobile/src/features/threads/new-task-flow-provider.tsx @@ -428,6 +428,7 @@ export function NewTaskFlowProvider( : null, ); const storedStickyModelSelection = useStickyComposerModelSelection(); + const selectedProjectOlderSettledCount = useOlderSettledCount(selectedProject); const t3ProjectFileData = t3ProjectFileQuery.data as ProjectReadFileResult | null; const t3ProjectFile = t3ProjectFileData === null || t3ProjectFileData.exists === false || t3ProjectFileData.truncated @@ -440,7 +441,6 @@ export function NewTaskFlowProvider( t3ProjectFile, ); const canChooseWorkspace = !isScratchDraft; - const selectedProjectOlderSettledCount = useOlderSettledCount(selectedProject); const selectedProjectHasThreads = selectedProject !== null && (selectedProjectOlderSettledCount > 0 || diff --git a/apps/mobile/src/state/queries.debounce.test.tsx b/apps/mobile/src/state/queries.debounce.test.tsx index 0a4c8ff828f3a..dcef7887012df 100644 --- a/apps/mobile/src/state/queries.debounce.test.tsx +++ b/apps/mobile/src/state/queries.debounce.test.tsx @@ -1,11 +1,16 @@ import { AuthFilesystemReadScope, EnvironmentId } from "@t3tools/contracts"; -import { act } from "react"; +import { RegistryContext } from "@effect/atom-react"; +import type { VcsRefTarget } from "@t3tools/client-runtime/state/vcs"; +import { AsyncResult, Atom, AtomRegistry } from "effect/reactivity"; +import { act, useLayoutEffect } from "react"; import { createRoot } from "react-dom/client"; import { expect, it, vi } from "vite-plus/test"; const mocks = vi.hoisted(() => ({ sessionAtom: {}, searchEntries: vi.fn(() => null), + listRefs: vi.fn(), + refresh: vi.fn(), })); vi.mock("./session", () => ({ @@ -21,9 +26,9 @@ vi.mock("./pull-requests", () => ({ composerPullRequests: {} })); vi.mock("./projects", () => ({ projectEnvironment: { searchEntries: mocks.searchEntries }, })); -vi.mock("./atom-registry", () => ({ appAtomRegistry: {} })); +vi.mock("./atom-registry", () => ({ appAtomRegistry: { refresh: mocks.refresh } })); vi.mock("./orchestration", () => ({ orchestrationEnvironment: {} })); -vi.mock("./vcs", () => ({ vcsEnvironment: {} })); +vi.mock("./vcs", () => ({ vcsEnvironment: { listRefs: mocks.listRefs } })); vi.mock("./threads", () => ({ olderSettledThreads: {}, threadFamilies: {} })); vi.mock("./query", () => ({ useEnvironmentQuery: (atom: unknown) => ({ @@ -37,7 +42,11 @@ vi.mock("./query", () => ({ }), })); -import { useComposerPathSearch, type ComposerPathSearchTarget } from "./queries"; +import { + useComposerPathSearch, + usePaginatedBranches, + type ComposerPathSearchTarget, +} from "./queries"; function setup() { (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; @@ -104,3 +113,91 @@ it.each([ input: { cwd: changed.cwd, query: changed.query, limit: 20 }, }); }); + +it("keeps compiled branch results stable and resets pagination for a new target or refresh", () => { + (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; + const registry = AtomRegistry.make(); + const pages = Atom.family((key: string) => { + const [, cwd, cursor] = JSON.parse(key) as [string, string, number | null]; + return Atom.make( + AsyncResult.success({ + refs: [ + { name: `${cwd}-${cursor ?? 0}`, current: false, isDefault: false, worktreePath: null }, + ], + isRepo: true, + hasPrimaryRemote: true, + nextCursor: cursor === null ? 100 : null, + totalCount: 2, + }), + ); + }); + mocks.listRefs.mockImplementation( + ({ + environmentId, + input, + }: { + environmentId: EnvironmentId; + input: { cwd: string; cursor?: number }; + }) => pages(JSON.stringify([environmentId, input.cwd, input.cursor ?? null])), + ); + mocks.refresh.mockClear(); + const root = createRoot(document.createElement("div")); + using _cleanup = { + [Symbol.dispose]() { + act(() => root.unmount()); + registry.dispose(); + }, + }; + let current: ReturnType; + function Probe({ target }: { target: VcsRefTarget }) { + const result = usePaginatedBranches(target); + useLayoutEffect(() => { + current = result; + }); + return null; + } + const render = (cwd: string | null, options: Partial = {}) => + act(() => + root.render( + + + , + ), + ); + render("/repo"); + const first = current!; + render("/repo"); + expect(current!.data).toBe(first.data); + expect(current!.refs).toBe(first.refs); + expect(current!.refresh).toBe(first.refresh); + expect(current!.loadNext).toBe(first.loadNext); + act(() => + registry.set( + pages(JSON.stringify([target.environmentId, "/repo", null])), + AsyncResult.success({ + ...first.data!, + refs: [{ name: "/repo-0", current: true, isDefault: false, worktreePath: null }], + }), + ), + ); + expect(current!.refs[0]?.current).toBe(true); + act(() => current!.loadNext()); + expect(current!.refs.map((ref) => ref.name)).toEqual(["/repo-0", "/repo-100"]); + act(() => current!.refresh()); + expect(current!.refs.map((ref) => ref.name)).toEqual(["/repo-0"]); + expect(mocks.refresh).toHaveBeenCalledExactlyOnceWith( + pages(JSON.stringify([target.environmentId, "/repo", null])), + ); + act(() => current!.loadNext()); + render("/other"); + expect(current!.refs.map((ref) => ref.name)).toEqual(["/other-0"]); + act(() => current!.loadNext()); + render("/other", { query: "feature" }); + expect(current!.refs).toHaveLength(1); + act(() => current!.loadNext()); + render("/other", { environmentId: EnvironmentId.make("other-environment"), query: "feature" }); + expect(current!.refs).toHaveLength(1); + render(null); + expect(current!.data).toBeNull(); + expect(current!.refs).toEqual([]); +}); diff --git a/apps/mobile/src/state/queries.ts b/apps/mobile/src/state/queries.ts index c1c47861c7420..246aec3a79938 100644 --- a/apps/mobile/src/state/queries.ts +++ b/apps/mobile/src/state/queries.ts @@ -50,7 +50,7 @@ const COMPOSER_PATH_SEARCH_LIMIT = 20; const THREAD_SEARCH_DEBOUNCE_MS = 120; const VCS_REF_LIST_LIMIT = 100; const EMPTY_REFS: ReadonlyArray = []; -const INITIAL_BRANCH_CURSORS = [null] as const; +const INITIAL_BRANCH_CURSORS = [undefined] as const; const EMPTY_THREAD_SEARCH_MATCHES: ReadonlyArray = Object.freeze([]); const EMPTY_THREAD_SEARCH_ATOM = Atom.make({ matches: EMPTY_THREAD_SEARCH_MATCHES, @@ -269,37 +269,6 @@ export function useBranches(input: { ); } -const branchPageAtom = ( - environmentId: EnvironmentId, - cwd: string, - query: string, - cursor: number | null, -) => - vcsEnvironment.listRefs({ - environmentId, - input: { - cwd, - ...(query.length > 0 ? { query } : {}), - ...(cursor === null ? {} : { cursor }), - limit: VCS_REF_LIST_LIMIT, - }, - }); -const branchPagesAtom = Atom.family((key: string) => { - const [environmentId, cwd, query, cursors] = JSON.parse(key) as [ - EnvironmentId, - string, - string, - ReadonlyArray, - ]; - const pageAtoms = cursors.map((cursor) => branchPageAtom(environmentId, cwd, query, cursor)); - return Atom.make((get) => pageAtoms.map((atom) => get(atom))).pipe( - Atom.withLabel(`mobile:vcs-ref-pages:${key}`), - ); -}); -const EMPTY_BRANCH_PAGES_ATOM = Atom.make( - (): ReadonlyArray>> => [], -).pipe(Atom.withLabel("mobile:vcs-ref-pages:empty")); - export function usePaginatedBranches(target: VcsRefTarget) { const query = target.query?.trim() ?? ""; const targetKey = @@ -308,17 +277,37 @@ export function usePaginatedBranches(target: VcsRefTarget) { : null; const [pagination, setPagination] = useState<{ readonly targetKey: string | null; - readonly cursors: ReadonlyArray; + readonly cursors: ReadonlyArray; }>({ targetKey, cursors: INITIAL_BRANCH_CURSORS, }); const cursors = pagination.targetKey === targetKey ? pagination.cursors : INITIAL_BRANCH_CURSORS; - const pagesKey = - targetKey === null ? null : JSON.stringify([target.environmentId, target.cwd, query, cursors]); - const results = useAtomValue( - pagesKey === null ? EMPTY_BRANCH_PAGES_ATOM : branchPagesAtom(pagesKey), + const pageAtoms = useMemo( + () => + target.environmentId !== null && target.cwd !== null + ? cursors.map((cursor) => + vcsEnvironment.listRefs({ + environmentId: target.environmentId!, + input: { + cwd: target.cwd!, + ...(query.length > 0 ? { query } : {}), + ...(cursor === undefined ? {} : { cursor }), + limit: VCS_REF_LIST_LIMIT, + }, + }), + ) + : [], + [target.environmentId, target.cwd, query, cursors], + ); + const pagesAtom = useMemo( + () => + Atom.make((get) => pageAtoms.map((atom) => get(atom))).pipe( + Atom.withLabel(`mobile:vcs-ref-pages:${targetKey ?? "empty"}`), + ), + [pageAtoms, targetKey], ); + const results = useAtomValue(pagesAtom); const values = results.flatMap((result) => { const value = Option.getOrNull(AsyncResult.value(result)); return value === null ? [] : [value]; @@ -357,9 +346,10 @@ export function usePaginatedBranches(target: VcsRefTarget) { })() : null; const refresh = () => { + const firstPage = pageAtoms[0]; setPagination({ targetKey, cursors: INITIAL_BRANCH_CURSORS }); - if (target.environmentId !== null && target.cwd !== null) { - appAtomRegistry.refresh(branchPageAtom(target.environmentId, target.cwd, query, null)); + if (firstPage !== undefined) { + appAtomRegistry.refresh(firstPage); } }; const loadNext = () => { From 2be8c4cb315940ec742f318271778bde5149faa1 Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Fri, 30 Oct 2026 00:02:15 +0000 Subject: [PATCH 5/6] fix(mobile): retain branch memo hook import after merge --- apps/mobile/src/state/queries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mobile/src/state/queries.ts b/apps/mobile/src/state/queries.ts index bbdecb11b1288..8721b9ecfda88 100644 --- a/apps/mobile/src/state/queries.ts +++ b/apps/mobile/src/state/queries.ts @@ -31,7 +31,7 @@ import * as Cause from "effect/Cause"; import { turnItemDetailRevision } from "@t3tools/client-runtime/work-log/item-detail"; import * as Option from "effect/Option"; import { AsyncResult, Atom } from "effect/reactivity"; -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { appAtomRegistry } from "./atom-registry"; import { orchestrationEnvironment } from "./orchestration"; From 510f5894e71c69443ad9e4d742d9aa2ff07d0fda Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Fri, 30 Oct 2026 00:05:41 +0000 Subject: [PATCH 6/6] fix(mobile): keep model clock before cached derivation --- apps/mobile/src/features/threads/new-task-flow-provider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mobile/src/features/threads/new-task-flow-provider.tsx b/apps/mobile/src/features/threads/new-task-flow-provider.tsx index 1ebcc95016c7f..4aa44e73c5586 100644 --- a/apps/mobile/src/features/threads/new-task-flow-provider.tsx +++ b/apps/mobile/src/features/threads/new-task-flow-provider.tsx @@ -328,6 +328,7 @@ export function NewTaskFlowProvider( const linkedEnvironments = useLinkedEnvironments(selectedProject?.environmentId ?? null); const storedStickyModelSelection = useStickyComposerModelSelection(); + const modelSelectionNow = useNowMinuteMs(); const projectDefaults = useNewTaskProjectDefaults(selectedProject); const selectedEnvironmentServerConfig = projectDefaults.serverConfig; const isScratchDraft = projectDefaults.isScratch; @@ -425,7 +426,6 @@ export function NewTaskFlowProvider( selectedProjectDraft.modelSelection ?? null, selectedProject?.id ?? null, ); - const modelSelectionNow = useNowMinuteMs(); const projectDefaultModelSelection = resolveDefaultableModelSelection( selectedEnvironmentServerConfig, projectSettings.settings.defaultModelSelection,