refactor(app): move agent tab visibility policy (#851)

This commit is contained in:
Mohamed Boudra
2026-05-09 23:28:35 +08:00
committed by GitHub
parent bb5ac5b1d0
commit 263886fc1c
5 changed files with 78 additions and 23 deletions

View File

@@ -133,9 +133,10 @@ import {
} from "@/screens/workspace/workspace-route-state";
import { renderWorkspaceRouteGate } from "@/screens/workspace/workspace-route-state-views";
import {
buildWorkspaceTabSnapshot,
deriveWorkspaceAgentVisibility,
workspaceAgentVisibilityEqual,
} from "@/screens/workspace/workspace-agent-visibility";
} from "@/workspace-tabs/agent-visibility";
import { deriveWorkspacePaneState } from "@/screens/workspace/workspace-pane-state";
import {
buildWorkspacePaneContentModel,
@@ -1919,16 +1920,17 @@ function WorkspaceScreenContent({
return pending?.serverId === normalizedServerId && pending.lifecycle === "active";
});
reconcileWorkspaceTabs(persistenceKey, {
agentsHydrated: hasHydratedAgents,
terminalsHydrated: terminalsQuery.isSuccess,
activeAgentIds: Array.from(workspaceAgentVisibility.activeAgentIds),
autoOpenAgentIds: Array.from(workspaceAgentVisibility.autoOpenAgentIds),
knownAgentIds: Array.from(workspaceAgentVisibility.knownAgentIds),
knownTerminalIds,
standaloneTerminalIds,
hasActivePendingDraftCreate: hasActivePendingDraftCreateInWorkspace,
});
reconcileWorkspaceTabs(
persistenceKey,
buildWorkspaceTabSnapshot({
agentVisibility: workspaceAgentVisibility,
agentsHydrated: hasHydratedAgents,
terminalsHydrated: terminalsQuery.isSuccess,
knownTerminalIds,
standaloneTerminalIds,
hasActivePendingDraftCreate: hasActivePendingDraftCreateInWorkspace,
}),
);
}, [
hasHydratedAgents,
hasHydratedWorkspaceLayoutStore,

View File

@@ -1,9 +1,10 @@
import type { DaemonClient } from "@server/client/daemon-client";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
buildWorkspaceTabSnapshot,
deriveWorkspaceAgentVisibility,
type WorkspaceAgentVisibility,
} from "@/screens/workspace/workspace-agent-visibility";
} from "@/workspace-tabs/agent-visibility";
import { selectSubagentsForParent } from "@/subagents";
import { buildWorkspaceTabPersistenceKey, useWorkspaceLayoutStore } from "./workspace-layout-store";
import { useSessionStore, type Agent } from "./session-store";
@@ -151,15 +152,17 @@ function deriveVisibilityFromSession(): WorkspaceAgentVisibility {
}
function reconcileWorkspaceTabs(workspaceKey: string, visibility: WorkspaceAgentVisibility): void {
useWorkspaceLayoutStore.getState().reconcileTabs(workspaceKey, {
agentsHydrated: true,
terminalsHydrated: true,
activeAgentIds: visibility.activeAgentIds,
autoOpenAgentIds: visibility.autoOpenAgentIds,
knownAgentIds: visibility.knownAgentIds,
standaloneTerminalIds: [],
hasActivePendingDraftCreate: false,
});
useWorkspaceLayoutStore.getState().reconcileTabs(
workspaceKey,
buildWorkspaceTabSnapshot({
agentVisibility: visibility,
agentsHydrated: true,
terminalsHydrated: true,
knownTerminalIds: [],
standaloneTerminalIds: [],
hasActivePendingDraftCreate: false,
}),
);
}
function getWorkspaceTabIds(workspaceKey: string): string[] {

View File

@@ -1,5 +1,5 @@
// Pure-data entry point for callers that don't want React Native deps in
// their dependency graph (e.g. workspace-agent-visibility.ts is plain JS
// their dependency graph (e.g. workspace-tabs/agent-visibility.ts is plain
// data derivation and its tests run without an RN environment).
//
// The full module entry `@/subagents` re-exports these too, alongside the

View File

@@ -1,10 +1,11 @@
import { describe, expect, it } from "vitest";
import type { Agent } from "@/stores/session-store";
import {
buildWorkspaceTabSnapshot,
deriveWorkspaceAgentVisibility,
shouldPruneWorkspaceAgentTab,
workspaceAgentVisibilityEqual,
} from "@/screens/workspace/workspace-agent-visibility";
} from "@/workspace-tabs/agent-visibility";
function makeAgent(input: {
id: string;
@@ -265,6 +266,34 @@ describe("workspace agent visibility", () => {
expect(result.knownAgentIds).toEqual(new Set(["recent-agent"]));
});
it("builds the tab reconciliation snapshot without callers unpacking agent visibility", () => {
const agentVisibility = {
activeAgentIds: new Set(["active-agent"]),
autoOpenAgentIds: new Set(["root-agent"]),
knownAgentIds: new Set(["active-agent", "archived-agent"]),
};
expect(
buildWorkspaceTabSnapshot({
agentVisibility,
agentsHydrated: true,
terminalsHydrated: true,
knownTerminalIds: ["terminal-1", "script-terminal"],
standaloneTerminalIds: ["terminal-1"],
hasActivePendingDraftCreate: false,
}),
).toEqual({
agentsHydrated: true,
terminalsHydrated: true,
activeAgentIds: agentVisibility.activeAgentIds,
autoOpenAgentIds: agentVisibility.autoOpenAgentIds,
knownAgentIds: agentVisibility.knownAgentIds,
knownTerminalIds: ["terminal-1", "script-terminal"],
standaloneTerminalIds: ["terminal-1"],
hasActivePendingDraftCreate: false,
});
});
describe("workspaceAgentVisibilityEqual", () => {
it("returns true for identical sets", () => {
const a = {

View File

@@ -1,4 +1,5 @@
import type { Agent } from "@/stores/session-store";
import type { WorkspaceTabSnapshot } from "@/stores/workspace-layout-actions";
import { shouldAutoOpenAgentTab } from "@/subagents/policies";
import { normalizeWorkspacePath } from "@/utils/workspace-identity";
@@ -52,6 +53,26 @@ export function deriveWorkspaceAgentVisibility(input: {
return { activeAgentIds, autoOpenAgentIds, knownAgentIds };
}
export function buildWorkspaceTabSnapshot(input: {
agentVisibility: WorkspaceAgentVisibility;
agentsHydrated: boolean;
terminalsHydrated: boolean;
knownTerminalIds: Iterable<string>;
standaloneTerminalIds: Iterable<string>;
hasActivePendingDraftCreate: boolean;
}): WorkspaceTabSnapshot {
return {
agentsHydrated: input.agentsHydrated,
terminalsHydrated: input.terminalsHydrated,
activeAgentIds: input.agentVisibility.activeAgentIds,
autoOpenAgentIds: input.agentVisibility.autoOpenAgentIds,
knownAgentIds: input.agentVisibility.knownAgentIds,
knownTerminalIds: input.knownTerminalIds,
standaloneTerminalIds: input.standaloneTerminalIds,
hasActivePendingDraftCreate: input.hasActivePendingDraftCreate,
};
}
export function workspaceAgentVisibilityEqual(
a: WorkspaceAgentVisibility,
b: WorkspaceAgentVisibility,