summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/app/store.svelte.ts20
-rw-r--r--src/features/tabs/tabs-store.svelte.ts5
-rw-r--r--src/features/tabs/tabs.ts11
3 files changed, 35 insertions, 1 deletions
diff --git a/src/app/store.svelte.ts b/src/app/store.svelte.ts
index 629e6c6..8997ce0 100644
--- a/src/app/store.svelte.ts
+++ b/src/app/store.svelte.ts
@@ -1106,8 +1106,15 @@ export function createAppStore(opts?: CreateAppStoreOptions): AppStore {
workspaceId: conv.workspaceId,
});
} else {
- // Already open — update the title from the backend if it differs.
+ // Already open — reconcile title + workspace from the authoritative
+ // backend list. A raced `conversation.open` (summon) may have stamped
+ // the tab with the wrong workspace ("default"); the backend's
+ // authoritative conversation record is the source of truth, so a
+ // differing tab workspace is corrected here.
tabsStore.setTitle(conv.id, conv.title);
+ if (tabsStore.tabs.find((t) => t.conversationId === conv.id)?.workspaceId !== conv.workspaceId) {
+ tabsStore.setWorkspaceId(conv.id, conv.workspaceId);
+ }
}
}
@@ -1146,6 +1153,17 @@ export function createAppStore(opts?: CreateAppStoreOptions): AppStore {
// `queued` = the turn is in flight but waiting for a concurrency slot
// (broadcast-only, never persisted — CR-13); the tab shows a ring.
conversationStatuses = new Map(conversationStatuses).set(conversationId, status);
+ // Reconcile the already-open tab's workspace from this authoritative
+ // lifecycle event (the payload workspace is the conversation's actual
+ // persisted workspace). A raced `conversation.open` may have stamped the
+ // wrong workspace ("default") — correct it here.
+ if (
+ chatStores.has(conversationId) &&
+ (tabsStore.tabs.find((t) => t.conversationId === conversationId)?.workspaceId ??
+ workspaceId) !== workspaceId
+ ) {
+ tabsStore.setWorkspaceId(conversationId, workspaceId);
+ }
// If this is a new active OR queued conversation we don't have a tab for,
// open one — so a cross-device turn (incl. one waiting in the concurrency
// queue) is visible. `idle` never opens a tab.
diff --git a/src/features/tabs/tabs-store.svelte.ts b/src/features/tabs/tabs-store.svelte.ts
index d044b1f..acf56fe 100644
--- a/src/features/tabs/tabs-store.svelte.ts
+++ b/src/features/tabs/tabs-store.svelte.ts
@@ -8,6 +8,7 @@ import {
selectTab as reduceSelectTab,
setModel as reduceSetModel,
setTitle as reduceSetTitle,
+ setWorkspaceId as reduceSetWorkspaceId,
activeTab as selectActiveTab,
} from "./tabs";
@@ -28,6 +29,7 @@ export interface TabsStore {
closeTab(conversationId: string): void;
setModel(conversationId: string, model: string): void;
setTitle(conversationId: string, title: string): void;
+ setWorkspaceId(conversationId: string, workspaceId: string): void;
}
export function createTabsStore(storage: TabsStorage): TabsStore {
@@ -69,5 +71,8 @@ export function createTabsStore(storage: TabsStorage): TabsStore {
setTitle(conversationId: string, title: string): void {
apply(reduceSetTitle(state, conversationId, title));
},
+ setWorkspaceId(conversationId: string, workspaceId: string): void {
+ apply(reduceSetWorkspaceId(state, conversationId, workspaceId));
+ },
};
}
diff --git a/src/features/tabs/tabs.ts b/src/features/tabs/tabs.ts
index 63cda35..9fc9306 100644
--- a/src/features/tabs/tabs.ts
+++ b/src/features/tabs/tabs.ts
@@ -82,6 +82,17 @@ export function setTitle(state: TabsState, conversationId: string, title: string
return { tabs, activeConversationId: state.activeConversationId };
}
+export function setWorkspaceId(
+ state: TabsState,
+ conversationId: string,
+ workspaceId: string,
+): TabsState {
+ const tabs = state.tabs.map((t) =>
+ t.conversationId === conversationId ? { ...t, workspaceId } : t,
+ );
+ return { tabs, activeConversationId: state.activeConversationId };
+}
+
export function activeTab(state: TabsState): Tab | null {
if (state.activeConversationId === null) return null;
return state.tabs.find((t) => t.conversationId === state.activeConversationId) ?? null;