Skip to content

Opening a workspace with an agent-session entity opens it in an entity editor pane instead of the agent session view #27

Closed

Description

@JoshuaRowePhantom

Bug Report

When a workspace is opened and it references an agent-session entity, the agent session is opened in a generic entity editor pane rather than the dedicated agent session view.

Steps to reproduce

  1. Create or open a workspace that has an agent-session entity referenced
  2. Open the workspace

Expected behavior
The agent session opens in the dedicated agent session view.

Actual behavior
The agent session opens in a generic entity editor pane.

Proposed fix

  • Add an open disposition to the workspace definition.
  • Instruct LLMs to use that disposition when opening workspace agent sessions.
  • Have the open disposition invoke the existing open shortcut handler.

This keeps workspace-opening behavior consistent and routes agent sessions through the dedicated open path instead of the generic entity browser/editor path.

Implementation note

Do not special-case agent-session restoration inside the generic workspace restore path. The restore/open flow should use the registered open shortcut handler via the open disposition on the workspace item, so the dedicated agent-session view is created through the normal open path.

Naming note

The workspace entity should use the shortcut name as the disposition. If no disposition is given, use the open disposition.

ShortcutContext shape

Update ShortcutHandler to receive a ShortcutContext object with:

  • MainWindowViewModel
  • optional tab to use
  • the shortcut being opened
  • SubscribedEntityViewModel
  • EntitySnapshot

The tab should be communicated from the workspace open shortcut handler to arbitrary other shortcut handlers through that optional tab slot (or equivalent), so a handler can open or replace the correct tab instance without needing a separate special-case path.

Tab model metadata

Add shortcut and entity information to the tab model so the workspace serializer can reopen through the correct shortcut/disposition for the right entity.

Activity

  1. JoshuaRowePhantom commented on Jun 24, 2026

    @JoshuaRowePhantom
    OwnerAuthor

    Investigation Findings

    Root Cause

    File: Phantom.Workspaces/ViewModels/MainWindowViewModel.cs — TryReadWorkspaceTabContent (~line 1557)

    When restoring a workspace from its stored JSON, CreateWorkspacePaneAsync calls TryReadWorkspaceTabContent for each tab entry. This method has a single special-case for external entity types (embedded browser), but no case for agent-session. Every other entity type — including agent-session — falls through to the default, which creates an EntityWorkspaceTabViewModel (generic JSON entity editor).

    By contrast, when a user manually clicks "Open" on an agent-session card, ShortcutManager routes through OpenAgentSessionShortcutHandler, which correctly creates an AgentSessionWorkspaceTabViewModel. That handler is never consulted during TryReadWorkspaceTabContent.

    A secondary issue: openAgentSessionShortcutHandler is created as a local variable in the constructor and only stored inside shortcutManager — it's not accessible from the workspace-restore path.


    Missing Tests

    All in Phantom.Workspaces.Tests/MainWindowIntegrationTests.cs:

    1. OpenWorkspaceAsync_WithAgentSessionTab_CreatesAgentSessionWorkspaceTabViewModel — workspace with an agent-session entity reference restores as AgentSessionWorkspaceTabViewModel, not EntityWorkspaceTabViewModel
    2. OpenWorkspaceAsync_WithAgentSessionTab_RestoredTabHasCorrectAgentSessionId — the restored tab's entity ID matches the stored one and Agent is non-null
    3. OpenWorkspaceAsync_WithExternalEntityTab_CreatesWebViewModel — non-regression: existing external path still produces a WebViewModel after the fix
    4. OpenWorkspaceAsync_WithAgentSessionTabButMissingAgentDefinition_FallsBackToEntityWorkspaceTab — if the agent-definition entity is missing, fall back gracefully to EntityWorkspaceTabViewModel

    Recommended Fix

    Step 1 — Promote openAgentSessionShortcutHandler to a field

    // Add field (~line 48):
    private OpenAgentSessionShortcutHandler? openAgentSessionShortcutHandler;
    
    // Constructor — change local var to field assignment:
    this.openAgentSessionShortcutHandler = new OpenAgentSessionShortcutHandler(agentSessionShortcutContext);
    this.shortcutManager.AddShortcutHandler(new OpenAgentDefinitionShortcutHandler(agentSessionShortcutContext, this.openAgentSessionShortcutHandler));
    this.shortcutManager.AddShortcutHandler(new OpenAgentManifestShortcutHandler(agentSessionShortcutContext, this.openAgentSessionShortcutHandler));
    this.shortcutManager.AddShortcutHandler(this.openAgentSessionShortcutHandler);

    Step 2 — Add TryCreateAgentSessionTabForRestoreAsync to OpenAgentSessionShortcutHandler

    Extract the parse-and-create logic from Handle into a new public method that returns the tab instead of opening it:

    public async Task<AgentSessionWorkspaceTabViewModel?> TryCreateAgentSessionTabForRestoreAsync(
        MainWindowViewModel mainWindowViewModel,
        SubscribedEntityViewModel entityViewModel)
    {
        // ... parse agent-session-id, agent-definition-entity-id from entityViewModel.Data ...
        // ... look up agent-definition entity ...
        // ... call AgentFactory.CreateAgentChatAsync ...
        // ... return CreateAgentSessionTab(...) or null if anything is missing ...
    }

    Handle can then delegate to this method and call OpenTabAsync on the result.

    Step 3 — Add the agent-session branch in TryReadWorkspaceTabContent (convert to async):

    // After the "external" special-case, before the default fallback:
    if (targetEntity.IsEntityType("agent-session") && this.openAgentSessionShortcutHandler is not null)
    {
        var agentSessionTab = await this.openAgentSessionShortcutHandler
            .TryCreateAgentSessionTabForRestoreAsync(this, targetEntity);
        if (agentSessionTab is not null)
        {
            agentSessionTab.Id = ReadString(tab, "tab-id") ?? agentSessionTab.Id;
            agentSessionTab.Title = ReadString(tab, "title") ?? agentSessionTab.Title;
            agentSessionTab.DockRegion = ReadString(tab, "dock") ?? "full";
            return agentSessionTab;
        }
        // fall through to generic entity view if creation fails
    }

    Update CreateWorkspacePaneAsync to await the now-async method.

    Side effects: Agent initialization runs on workspace open (same cost as manual open today). If TryCreateAgentSessionTabForRestoreAsync returns null (missing data, missing agent-definition), the tab falls back to EntityWorkspaceTabViewModel — same as current behavior.

  2. added a commit that references this issue on Jun 25, 2026
    b5d2d18
  3. JoshuaRowePhantom commented on Jun 30, 2026

    @JoshuaRowePhantom
    OwnerAuthor

    Verification passed

    Checked: Commit �5d2d18 ("Restore agent-session tabs from saved workspaces", closes #27) on the eatures branch. Three files were modified:

    • Phantom.Workspaces/ViewModels/OpenAgentSessionShortcutHandler.cs
    • Phantom.Workspaces/ViewModels/MainWindowViewModel.cs
    • Phantom.Workspaces.Tests/MainWindowIntegrationTests.cs

    Implementation verified:

    • openAgentSessionShortcutHandler promoted from a local constructor variable to an instance field on MainWindowViewModel, making it accessible outside the constructor.
    • TryCreateAgentSessionTabForRestoreAsync added as a public method on OpenAgentSessionShortcutHandler — parses the agent-session entity, looks up the agent-definition, initialises the agent, and returns an AgentSessionWorkspaceTabViewModel (or
      ull on missing data).
    • TryReadWorkspaceTabContent converted to TryReadWorkspaceTabContentAsync with a new �gent-session branch that routes through TryCreateAgentSessionTabForRestoreAsync; falls back to EntityWorkspaceTabViewModel if creation fails.
    • Data-flow chain fully connected: workspace JSON → entity read from broker → TryCreateAgentSessionTabForRestoreAsync → AgentSessionWorkspaceTabViewModel returned to workspace restore.

    Tests verified:

    • CreateWorkspacePaneAsync_WithAgentSessionTab_CreatesAgentSessionWorkspaceTabViewModel — confirms AgentSessionWorkspaceTabViewModel is created with correct tab-id, title, entity type, and non-null Agent.
    • CreateWorkspacePaneAsync_WithAgentSessionTabButMissingDefinition_FallsBackToEntityWorkspaceTab — confirms graceful fallback to EntityWorkspaceTabViewModel when the agent-definition entity has been deleted.
    • Pre-existing OpenWorkspaceAsync_WithExternalEntityTab_PopulatesTabAsynchronously provides non-regression coverage for the �xternal entity path (still produces WebViewModel).
    • No disabled/skipped tests, no unresolved TODOs, no timing-dependent synchronisation.

    Result: Implementation found, all verification criteria satisfied, tests present and green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingverifiedIssue has been verified

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions