Fix draft agent handoff continuity
Move optimistic user message reconciliation into the stream reducers and keep draft-created agents in a handoff lifecycle until authoritative history lands.
This commit is contained in:
@@ -48,14 +48,14 @@ function ProbePanel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tab: WorkspaceTabDescriptor = {
|
||||
const agentTab: WorkspaceTabDescriptor = {
|
||||
key: "agent_agent-a",
|
||||
tabId: "agent_agent-a",
|
||||
kind: "agent",
|
||||
target: { kind: "agent", agentId: "agent-a" },
|
||||
};
|
||||
|
||||
function buildContent() {
|
||||
function buildContent(tab: WorkspaceTabDescriptor = agentTab) {
|
||||
return buildWorkspacePaneContentModel({
|
||||
tab,
|
||||
normalizedServerId: "server-a",
|
||||
@@ -120,4 +120,43 @@ describe("WorkspacePaneContent", () => {
|
||||
focusPane: expect.any(Function),
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps pane content mounted when a draft tab is retargeted in place", () => {
|
||||
container = document.createElement("div");
|
||||
document.body.appendChild(container);
|
||||
root = createRoot(container);
|
||||
|
||||
const draftContent = buildContent({
|
||||
key: "draft-a",
|
||||
tabId: "draft-a",
|
||||
kind: "draft",
|
||||
target: { kind: "draft", draftId: "draft-a" },
|
||||
});
|
||||
const agentContent = buildContent({
|
||||
key: "draft-a",
|
||||
tabId: "draft-a",
|
||||
kind: "agent",
|
||||
target: { kind: "agent", agentId: "agent-a" },
|
||||
});
|
||||
|
||||
act(() => {
|
||||
root?.render(
|
||||
<WorkspacePaneContent content={draftContent} isPaneFocused isWorkspaceFocused={true} />,
|
||||
);
|
||||
});
|
||||
act(() => {
|
||||
root?.render(
|
||||
<WorkspacePaneContent content={agentContent} isPaneFocused isWorkspaceFocused={true} />,
|
||||
);
|
||||
});
|
||||
|
||||
expect(mountCount).toHaveBeenCalledTimes(1);
|
||||
expect(unmountCount).not.toHaveBeenCalled();
|
||||
expect(snapshots).toHaveLength(2);
|
||||
expect(snapshots[1]?.paneContextValue.tabId).toBe("draft-a");
|
||||
expect(snapshots[1]?.paneContextValue.target).toEqual({
|
||||
kind: "agent",
|
||||
agentId: "agent-a",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ export function buildWorkspacePaneContentModel({
|
||||
const registration = getPanelRegistration(tab.kind);
|
||||
invariant(registration, `No panel registration for kind: ${tab.kind}`);
|
||||
return {
|
||||
key: `${normalizedServerId}:${normalizedWorkspaceId}:${tab.tabId}:${tab.kind}`,
|
||||
key: `${normalizedServerId}:${normalizedWorkspaceId}:${tab.tabId}`,
|
||||
Component: registration.component,
|
||||
paneContextValue: {
|
||||
serverId: normalizedServerId,
|
||||
|
||||
@@ -1746,9 +1746,6 @@ function WorkspaceScreenContent({
|
||||
const unpinWorkspaceAgent = useWorkspaceLayoutStore((state) => state.unpinAgent);
|
||||
const hideWorkspaceAgent = useWorkspaceLayoutStore((state) => state.hideAgent);
|
||||
const retargetWorkspaceTab = useWorkspaceLayoutStore((state) => state.retargetTab);
|
||||
const convertWorkspaceDraftToAgent = useWorkspaceLayoutStore(
|
||||
(state) => state.convertDraftToAgent,
|
||||
);
|
||||
const reconcileWorkspaceTabs = useWorkspaceLayoutStore((state) => state.reconcileTabs);
|
||||
const splitWorkspacePane = useWorkspaceLayoutStore((state) => state.splitPane);
|
||||
const splitWorkspacePaneEmpty = useWorkspaceLayoutStore((state) => state.splitPaneEmpty);
|
||||
@@ -2842,10 +2839,6 @@ function WorkspaceScreenContent({
|
||||
if (!persistenceKey) {
|
||||
return;
|
||||
}
|
||||
if (input.tab.kind === "draft" && target.kind === "agent") {
|
||||
convertWorkspaceDraftToAgent(persistenceKey, input.tab.tabId, target.agentId);
|
||||
return;
|
||||
}
|
||||
retargetWorkspaceTab(persistenceKey, input.tab.tabId, target);
|
||||
},
|
||||
onOpenWorkspaceFile: (request: WorkspaceFileOpenRequest) => {
|
||||
@@ -2875,7 +2868,6 @@ function WorkspaceScreenContent({
|
||||
openImportSheet,
|
||||
openWorkspaceChildTabFocused,
|
||||
persistenceKey,
|
||||
convertWorkspaceDraftToAgent,
|
||||
retargetWorkspaceTab,
|
||||
],
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user