import { describe, expect, it } from "vitest"; import { agentGuiWorkbenchPrefillPromptActivationType, agentGuiWorkbenchProviderFromLaunchRequest, agentGuiWorkbenchUnifiedDockEntryId, createAgentGuiWorkbenchDraftLaunchRequest, createAgentGuiWorkbenchInstanceId, createAgentGuiWorkbenchLaunchDescriptor, createAgentGuiWorkbenchSessionLaunchRequest } from "./launch.ts"; describe("agent gui workbench launch contract", () => { it("keeps runtime instance ids opaque", () => { expect(agentGuiWorkbenchUnifiedDockEntryId()).toBe("agent-gui:unified"); const first = createAgentGuiWorkbenchInstanceId(); const second = createAgentGuiWorkbenchInstanceId(); expect(first).toMatch(/^agent-gui:instance:/); expect(second).toMatch(/^agent-gui:instance:/); expect(first).not.toBe(second); }); it("requires launch providers in payloads", () => { expect( agentGuiWorkbenchProviderFromLaunchRequest({ dockEntryId: "agent-gui:codex", payload: { provider: "claude-code" }, typeId: "agent-gui" }) ).toBe("claude-code"); expect(() => agentGuiWorkbenchProviderFromLaunchRequest({ dockEntryId: "agent-gui:hermes", payload: {}, typeId: "agent-gui" }) ).toThrow("agent_gui_workbench.launch_provider_required"); expect(() => agentGuiWorkbenchProviderFromLaunchRequest({ payload: null, typeId: "agent-gui" }) ).toThrow("agent_gui_workbench.launch_provider_required"); }); it("uses the unified dock identity in launch descriptors", () => { const descriptor = createAgentGuiWorkbenchLaunchDescriptor({ dockEntryId: "agent-gui:claude-code", payload: { provider: "codex" }, typeId: "agent-gui" }); expect(descriptor.dockEntryId).toBe("agent-gui:unified"); expect(descriptor.instanceId).toMatch(/^agent-gui:instance:/); expect(descriptor.provider).toBe("codex"); }); it("launches sessions into provider panels until current session state can reuse a node", () => { const descriptor = createAgentGuiWorkbenchLaunchDescriptor({ dockEntryId: "agent-gui:unified", payload: { agentSessionId: "session-2", provider: "codex" }, typeId: "agent-gui" }); expect(descriptor).toMatchObject({ activation: { payload: { agentSessionId: "session-2" }, type: "agent-gui:open-session" }, dockEntryId: "agent-gui:unified", openInNewWindow: false, provider: "codex", reusePolicy: { agentSessionId: "session-2", kind: "current-session" }, targetAgentSessionId: "session-2" }); expect(descriptor.instanceId).toMatch(/^agent-gui:instance:/); }); it("launches sessions with target metadata into target panels", () => { expect( createAgentGuiWorkbenchLaunchDescriptor({ dockEntryId: "agent-gui", payload: { agentSessionId: "session-2", agentTargetId: "local:codex", provider: "codex" }, typeId: "agent-gui" }) ).toMatchObject({ openInNewWindow: false, reusePolicy: { agentSessionId: "session-2", kind: "current-session" }, targetAgentSessionId: "session-2" }); }); it("can launch an existing session into a new internal window", () => { const descriptor = createAgentGuiWorkbenchLaunchDescriptor({ dockEntryId: "agent-gui:codex", payload: { agentSessionId: "session-2", openInNewWindow: true, provider: "codex" }, typeId: "agent-gui" }); expect(descriptor.activation).toEqual({ payload: { agentSessionId: "session-2" }, type: "agent-gui:open-session" }); expect(descriptor.instanceId).toMatch(/^agent-gui:instance:/); expect(descriptor.openInNewWindow).toBe(true); expect(descriptor.reusePolicy).toEqual({ kind: "none" }); expect(descriptor.targetAgentSessionId).toBe("session-2"); }); it("keeps provider metadata separate from opaque aggregate instances", () => { const descriptor = createAgentGuiWorkbenchLaunchDescriptor({ dockEntryId: agentGuiWorkbenchUnifiedDockEntryId(), payload: { provider: "claude-code" }, typeId: "agent-gui" }); expect(descriptor.dockEntryId).toBe("agent-gui:unified"); expect(descriptor.instanceId).toMatch(/^agent-gui:instance:/); expect(descriptor.provider).toBe("claude-code"); expect(descriptor.reusePolicy).toEqual({ kind: "dock-entry" }); }); it("keeps a managed edit prompt attached to the exact source session", () => { const descriptor = createAgentGuiWorkbenchLaunchDescriptor( createAgentGuiWorkbenchSessionLaunchRequest({ agentSessionId: " source-session-9 ", composerAppend: { draftPrompt: " Modify the managed issue ", focusComposer: true }, provider: "codex" }) ); expect(descriptor.activation).toEqual({ payload: { agentSessionId: "source-session-9", composerAppend: { draftPrompt: "Modify the managed issue", focusComposer: true } }, type: "agent-gui:open-session" }); expect(descriptor.reusePolicy).toEqual({ agentSessionId: "source-session-9", kind: "current-session" }); }); it("reuses unified aggregate dock nodes for empty launches", () => { expect( createAgentGuiWorkbenchLaunchDescriptor({ dockEntryId: agentGuiWorkbenchUnifiedDockEntryId(), payload: { provider: "codex" }, typeId: "agent-gui" }) ).toMatchObject({ dockEntryId: "agent-gui:unified", openInNewWindow: false, provider: "codex", reusePolicy: { kind: "dock-entry" }, targetAgentSessionId: null }); }); it("can force a new in-workspace instance without opening a new window", () => { const descriptor = createAgentGuiWorkbenchLaunchDescriptor( createAgentGuiWorkbenchSessionLaunchRequest({ forceNewInstance: true, provider: "codex" }) ); expect(descriptor.openInNewWindow).toBe(false); expect(descriptor.reusePolicy).toEqual({ kind: "none" }); expect(descriptor.targetAgentSessionId).toBeNull(); }); it("does not reuse an existing session when a new instance is required", () => { const descriptor = createAgentGuiWorkbenchLaunchDescriptor( createAgentGuiWorkbenchSessionLaunchRequest({ agentSessionId: "session-replay", forceNewInstance: true, provider: "codex" }) ); expect(descriptor.openInNewWindow).toBe(false); expect(descriptor.reusePolicy).toEqual({ kind: "none" }); expect(descriptor.targetAgentSessionId).toBe("session-replay"); }); it("does not reuse dock nodes for empty launches into new windows", () => { expect( createAgentGuiWorkbenchLaunchDescriptor({ dockEntryId: agentGuiWorkbenchUnifiedDockEntryId(), payload: { openInNewWindow: true, provider: "codex" }, typeId: "agent-gui" }) ).toMatchObject({ dockEntryId: "agent-gui:unified", openInNewWindow: true, provider: "codex", reusePolicy: { kind: "none" }, targetAgentSessionId: null }); }); it("treats dock popup new-window launches as new windows", () => { expect( createAgentGuiWorkbenchLaunchDescriptor({ dockEntryId: agentGuiWorkbenchUnifiedDockEntryId(), launchSource: "dock-popup-new-window", payload: { provider: "codex" }, typeId: "agent-gui" }) ).toMatchObject({ dockEntryId: "agent-gui:unified", openInNewWindow: true, provider: "codex", reusePolicy: { kind: "none" }, targetAgentSessionId: null }); }); it("creates draft prompt launch requests for the unified dock entry", () => { expect( createAgentGuiWorkbenchDraftLaunchRequest({ agentTargetId: "local:codex", draftPrompt: "Review this issue", provider: "codex", userProjectPath: "/Users/example/project" }) ).toEqual({ dockEntryId: "agent-gui:unified", payload: { agentTargetId: "local:codex", draftPrompt: "Review this issue", provider: "codex", userProjectPath: "/Users/example/project" }, reason: "host", typeId: "agent-gui" }); }); it("launches draft prompts without reusing an unrelated unified node", () => { expect( createAgentGuiWorkbenchLaunchDescriptor( createAgentGuiWorkbenchDraftLaunchRequest({ agentTargetId: "local:codex", draftPrompt: "Review this issue", provider: "codex" }) ) ).toMatchObject({ activation: { payload: { agentTargetId: "local:codex", draftPrompt: "Review this issue", provider: "codex" }, type: agentGuiWorkbenchPrefillPromptActivationType }, dockEntryId: "agent-gui:unified", provider: "codex", reusePolicy: { kind: "none" }, targetAgentSessionId: null }); }); it("launches draft prompts into new windows when requested", () => { const descriptor = createAgentGuiWorkbenchLaunchDescriptor( createAgentGuiWorkbenchDraftLaunchRequest({ agentTargetId: "local:codex", draftPrompt: "Review this issue", openInNewWindow: true, provider: "codex" }) ); expect(descriptor).toMatchObject({ activation: { payload: { agentTargetId: "local:codex", draftPrompt: "Review this issue", provider: "codex" }, type: agentGuiWorkbenchPrefillPromptActivationType }, dockEntryId: "agent-gui:unified", openInNewWindow: true, provider: "codex", reusePolicy: { kind: "none" }, targetAgentSessionId: null }); expect(descriptor.instanceId).toMatch(/^agent-gui:instance:/); }); it("creates session launch requests for the unified dock entry", () => { expect( createAgentGuiWorkbenchSessionLaunchRequest({ agentSessionId: "session-2", provider: "claude-code" }) ).toMatchObject({ dockEntryId: "agent-gui:unified", payload: { agentSessionId: "session-2", provider: "claude-code" } }); }); it("does not reuse a shared unified aggregate dock node for provider-specific draft prompts", () => { expect( createAgentGuiWorkbenchLaunchDescriptor({ dockEntryId: agentGuiWorkbenchUnifiedDockEntryId(), payload: { draftPrompt: "Review this issue", provider: "codex" }, typeId: "agent-gui" }) ).toMatchObject({ dockEntryId: "agent-gui:unified", provider: "codex", reusePolicy: { kind: "none" }, targetAgentSessionId: null }); expect( createAgentGuiWorkbenchLaunchDescriptor({ dockEntryId: agentGuiWorkbenchUnifiedDockEntryId(), payload: { draftPrompt: "Review this issue", provider: "claude-code" }, typeId: "agent-gui" }) ).toMatchObject({ dockEntryId: "agent-gui:unified", provider: "claude-code", reusePolicy: { kind: "none" }, targetAgentSessionId: null }); }); });