diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 156b0b3a4a..27e7e028ed 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -33,6 +33,7 @@ import { Persist, persisted } from "@/utils/persist" import { usePermission } from "@/context/permission" import { useLanguage } from "@/context/language" import { usePlatform } from "@/context/platform" +import { useServer } from "@/context/server" import { useSessionLayout } from "@/pages/session/session-layout" import { createSessionTabs } from "@/pages/session/helpers" import { createTextFragment, getCursorPosition, setCursorPosition, setRangeEdge } from "./prompt-input/editor-dom" @@ -112,6 +113,7 @@ export const PromptInput: Component = (props) => { const dialog = useDialog() const providers = useProviders() const command = useCommand() + const server = useServer() const permission = usePermission() const language = useLanguage() const platform = usePlatform() @@ -1252,11 +1254,11 @@ export const PromptInput: Component = (props) => { } } - const agentsQuery = useQuery(() => loadAgentsQuery(sdk.directory)) + const agentsQuery = useQuery(() => loadAgentsQuery(sdk.directory, server.key)) const agentsLoading = () => agentsQuery.isLoading - const globalProvidersQuery = useQuery(() => loadProvidersQuery(null)) - const providersQuery = useQuery(() => loadProvidersQuery(sdk.directory)) + const globalProvidersQuery = useQuery(() => loadProvidersQuery(null, server.key)) + const providersQuery = useQuery(() => loadProvidersQuery(sdk.directory, server.key)) const providersLoading = () => agentsLoading() || providersQuery.isLoading || globalProvidersQuery.isLoading diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx index 1a672639b5..dea01eae66 100644 --- a/packages/app/src/context/global-sync.tsx +++ b/packages/app/src/context/global-sync.tsx @@ -15,6 +15,7 @@ import { useLanguage } from "@/context/language" import { Persist, persisted } from "@/utils/persist" import type { InitError } from "../pages/error" import { useGlobalSDK } from "./global-sdk" +import { useServer } from "./server" import { bootstrapDirectory, bootstrapGlobal, clearProviderRev } from "./global-sync/bootstrap" import { createChildStoreManager } from "./global-sync/child-store" import { applyDirectoryEvent, applyGlobalEvent, cleanupDroppedSessionCaches } from "./global-sync/event-reducer" @@ -42,11 +43,12 @@ type GlobalStore = { reload: undefined | "pending" | "complete" } -export const loadSessionsQuery = (directory: string) => - queryOptions({ queryKey: [directory, "loadSessions"], queryFn: skipToken }) +export const loadSessionsQuery = (directory: string, serverKey: string | undefined) => + queryOptions({ queryKey: [serverKey, directory, "loadSessions"], queryFn: skipToken }) function createGlobalSync() { const globalSDK = useGlobalSDK() + const server = useServer() const language = useLanguage() const owner = getOwner() if (!owner) throw new Error("GlobalSync must be created within owner") @@ -205,7 +207,7 @@ function createGlobalSync() { const limit = Math.max(store.limit + SESSION_RECENT_LIMIT, SESSION_RECENT_LIMIT) const promise = queryClient .fetchQuery({ - ...loadSessionsQuery(directory), + ...loadSessionsQuery(directory, server.key), queryFn: () => loadRootSessionsWithFallback({ directory, @@ -269,6 +271,7 @@ function createGlobalSync() { const sdk = sdkFor(directory) await bootstrapDirectory({ directory, + serverKey: server.key, global: { config: globalStore.config, path: globalStore.path, @@ -355,6 +358,7 @@ function createGlobalSync() { try { await bootstrapGlobal({ globalSDK: globalSDK.client, + serverKey: server.key, requestFailedTitle: language.t("common.requestFailed"), translate: language.t, formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }), diff --git a/packages/app/src/context/global-sync/bootstrap.ts b/packages/app/src/context/global-sync/bootstrap.ts index 17fe726f90..71fa1d7dc3 100644 --- a/packages/app/src/context/global-sync/bootstrap.ts +++ b/packages/app/src/context/global-sync/bootstrap.ts @@ -69,6 +69,7 @@ function runAll(list: Array<() => Promise>) { export async function bootstrapGlobal(input: { globalSDK: OpencodeClient + serverKey: string | undefined requestFailedTitle: string translate: (key: string, vars?: Record) => string formatMoreCount: (count: number) => string @@ -84,7 +85,7 @@ export async function bootstrapGlobal(input: { ), () => input.queryClient.fetchQuery({ - ...loadProvidersQuery(null), + ...loadProvidersQuery(null, input.serverKey), queryFn: () => retry(() => input.globalSDK.provider.list().then((x) => { @@ -180,14 +181,15 @@ function warmSessions(input: { ).then(() => undefined) } -export const loadProvidersQuery = (directory: string | null) => - queryOptions({ queryKey: [directory, "providers"], queryFn: skipToken }) +export const loadProvidersQuery = (directory: string | null, serverKey: string | undefined) => + queryOptions({ queryKey: [serverKey, directory, "providers"], queryFn: skipToken }) -export const loadAgentsQuery = (directory: string | null) => - queryOptions({ queryKey: [directory, "agents"], queryFn: skipToken }) +export const loadAgentsQuery = (directory: string | null, serverKey: string | undefined) => + queryOptions({ queryKey: [serverKey, directory, "agents"], queryFn: skipToken }) export async function bootstrapDirectory(input: { directory: string + serverKey: string | undefined sdk: OpencodeClient store: Store setStore: SetStoreFunction @@ -239,7 +241,7 @@ export async function bootstrapDirectory(input: { const slow = [ () => input.queryClient.ensureQueryData({ - ...loadAgentsQuery(input.directory), + ...loadAgentsQuery(input.directory, input.serverKey), queryFn: () => retry(() => input.sdk.app.agents().then((x) => input.setStore("agent", normalizeAgentList(x.data)))).then( () => null, @@ -349,7 +351,7 @@ export async function bootstrapDirectory(input: { const rev = (providerRev.get(input.directory) ?? 0) + 1 providerRev.set(input.directory, rev) void input.queryClient.ensureQueryData({ - ...loadSessionsQuery(input.directory), + ...loadProvidersQuery(input.directory, input.serverKey), queryFn: () => retry(() => input.sdk.provider.list()) .then((x) => { diff --git a/packages/app/src/pages/layout/sidebar-workspace.tsx b/packages/app/src/pages/layout/sidebar-workspace.tsx index a0b8276ef7..e0b0fb47d3 100644 --- a/packages/app/src/pages/layout/sidebar-workspace.tsx +++ b/packages/app/src/pages/layout/sidebar-workspace.tsx @@ -16,6 +16,7 @@ import { type Session } from "@opencode-ai/sdk/v2/client" import { type LocalProject } from "@/context/layout" import { loadSessionsQuery, useGlobalSync } from "@/context/global-sync" import { useLanguage } from "@/context/language" +import { useServer } from "@/context/server" import { NewSessionItem, SessionItem, SessionSkeleton } from "./sidebar-items" import { sortedRootSessions, workspaceKey } from "./helpers" import { useQuery } from "@tanstack/solid-query" @@ -327,6 +328,7 @@ export const SortableWorkspace = (props: { // these memos with stale props. const local = createMemo(() => props.directory === (props.project?.worktree ?? "")) const active = createMemo(() => workspaceKey(props.ctx.currentDir()) === workspaceKey(props.directory)) + const server = useServer() const workspaceValue = createMemo(() => { const branch = workspaceStore.vcs?.branch const name = branch ?? getFilename(props.directory) @@ -338,7 +340,7 @@ export const SortableWorkspace = (props: { const boot = createMemo(() => open() || active()) const count = createMemo(() => sessions()?.length ?? 0) const hasMore = createMemo(() => workspaceStore.sessionTotal > count()) - const query = useQuery(() => ({ ...loadSessionsQuery(props.project.worktree) })) + const query = useQuery(() => ({ ...loadSessionsQuery(props.project.worktree, server.key) })) const busy = createMemo(() => props.ctx.isBusy(props.directory)) const loading = () => query.isLoading const touch = createMediaQuery("(hover: none)") @@ -465,6 +467,7 @@ export const LocalWorkspace = (props: { }): JSX.Element => { const globalSync = useGlobalSync() const language = useLanguage() + const server = useServer() // Same guard pattern as SortableWorkspace: the parent passes // `project={project()!}` but `project()` can transiently flip to // undefined during a server-switch cascade before this component @@ -484,7 +487,7 @@ export const LocalWorkspace = (props: { }) const booted = createMemo((prev) => prev || workspace()?.store.status === "complete", false) const count = createMemo(() => sessions()?.length ?? 0) - const query = useQuery(() => ({ ...loadSessionsQuery(worktree()) })) + const query = useQuery(() => ({ ...loadSessionsQuery(worktree(), server.key) })) const loading = createMemo(() => query.isPending && count() === 0) const hasMore = createMemo(() => (workspace()?.store.sessionTotal ?? 0) > count()) const loadMore = async () => {