Skip to content

Opening an agent session should show a loading tab immediately, then transition to the loaded view #59

Closed

Description

@JoshuaRowePhantom

Summary

When the user opens an agent session or agent definition, the UI stays frozen on the
entity card until AgentFactory.CreateAgentChatAsync completes. This includes connecting
to MCP servers, starting the Copilot CLI process, and restoring chat history — all of
which can take several seconds. The tab should open immediately with a loading indicator
and transition in-place to the live agent view once initialization is complete.

Current behaviour

Both OpenAgentSessionShortcutHandler.Handle and OpenAgentDefinitionShortcutHandler.Handle
follow this sequence:

1. await AgentFactory.CreateAgentChatAsync(...)  ← can take 2–10 s; UI unresponsive
2. await mainWindowViewModel.OpenTabAsync(tab)   ← tab appears only after load

No loading feedback is shown during step 1.

Desired behaviour

1. OpenTabAsync(loadingTab)   ← tab appears instantly with "Loading agent…" placeholder
2. await CreateAgentChatAsync (background)
3. Replace loading tab content in-place with the live AgentViewModel
   (or swap to full AgentSessionWorkspaceTabViewModel if necessary)

The tab title should be visible immediately (using the entity display name). On failure,
the loading tab should show an inline error with the exception message and a retry button.

Design

AgentSessionWorkspaceTabViewModel loading state

Add a LoadingState discriminated union (or a IsLoading / LoadError pair) to
AgentSessionWorkspaceTabViewModel:

public enum AgentTabState { Loading, Ready, Failed }

public sealed class AgentSessionWorkspaceTabViewModel : WorkspaceTabViewModel, IAsyncDisposable
{
    private AgentTabState state = AgentTabState.Loading;
    private string? loadError;

    public AgentTabState State
    {
        get => this.state;
        private set => this.SetProperty(ref this.state, value);
    }

    public string? LoadError
    {
        get => this.loadError;
        private set => this.SetProperty(ref this.loadError, value);
    }

    // Agent is null until State == Ready
    public AgentViewModel? Agent { get; private set; }

    public void SetReady(AgentViewModel agent, ObservableLoggerFactory loggerFactory) { … }
    public void SetFailed(string error) { … }
}

The view (AgentSessionWorkspaceTabView / the WorkspaceDocument data template) switches
on State:

  • Loading → spinner + "Loading agent…" message
  • Ready → existing AgentChatEditorControl
  • Failed → error text + Retry button

OpenAgentSessionShortcutHandler changes

// 1. Create a loading tab immediately and open it
var loadingTab = new AgentSessionWorkspaceTabViewModel
{
    Id = entityViewModel.EntityId.ToString(),
    Title = entityViewModel.DisplayName,
    Entity = entityViewModel,
};
await mainWindowViewModel.OpenTabAsync(loadingTab);   // returns immediately

// 2. Load in the background (fire-and-forget, errors caught and reflected in tab)
_ = Task.Run(async () =>
{
    try
    {
        var loggerFactory = new ObservableLoggerFactory();
        var agentServices = await this.agentSessionShortcutContext
            .CreateAgentServicesAsync(mainWindowViewModel, loggerFactory);
        var agentChat = await AgentFactory.CreateAgentChatAsync(createAgentChatRequest);
        var agentViewModel = new AgentViewModel(agentChat, entityViewModel.DisplayName, loggerFactory);
        await Dispatcher.UIThread.InvokeAsync(() => loadingTab.SetReady(agentViewModel, loggerFactory));
    }
    catch (Exception ex)
    {
        await Dispatcher.UIThread.InvokeAsync(() => loadingTab.SetFailed(ex.Message));
    }
});
return true;

OpenAgentDefinitionShortcutHandler changes

Same pattern: open the loading tab first (keyed on the session entity id once created, or
on a temporary id before the entity is written), then complete initialization in the
background.

Because OpenAgentDefinitionShortcutHandler also creates the agent-session entity, the
sequence becomes:

  1. Open a placeholder loading tab with a temporary id.
  2. Await CreateAgentSessionEntityAsync (fast — just a data write).
  3. Re-key the tab to the new entity id.
  4. Await AgentFactory.CreateAgentChatAsync in the background.
  5. Call SetReady.

Retry button

The Failed state UI exposes a Retry command that re-triggers the background load
sequence from step 2 above, clearing LoadError and resetting to Loading first.

Affected files

  • Phantom.Workspaces/ViewModels/AgentSessionWorkspaceTabViewModel.cs
  • Phantom.Workspaces/ViewModels/OpenAgentSessionShortcutHandler.cs
  • Phantom.Workspaces/ViewModels/OpenAgentDefinitionShortcutHandler.cs
  • Phantom.Workspaces/Templates/ (or wherever the agent tab data template lives) — add
    loading / failed state views

Activity

  1. added a commit that references this issue on Jun 26, 2026
    e51ec14
  2. JoshuaRowePhantom commented on Jun 30, 2026

    @JoshuaRowePhantom
    OwnerAuthor

    Verification failed

    Checked: Commit e51ec14 (Fix #59) and the features branch tip. Files inspected:

    • Phantom.Workspaces/ViewModels/AgentSessionWorkspaceTabViewModel.cs
    • Phantom.Workspaces/ViewModels/OpenAgentSessionShortcutHandler.cs
    • Phantom.Workspaces/ViewModels/OpenAgentDefinitionShortcutHandler.cs
    • Phantom.Workspaces/Templates/WorkspaceDataTemplates.axaml
    • Phantom.Workspaces.Tests/MainWindowIntegrationTests.cs

    Found: The core loading-state machine is correctly implemented. AgentTabState (Loading/Ready/Failed) is present on AgentSessionWorkspaceTabViewModel; OpenAgentSessionShortcutHandler.Handle opens the loading tab immediately and initialises the agent in a background Task.Run; WorkspaceDataTemplates.axaml renders the Loading spinner, the Ready agent view, and the Failed error message. Integration tests cover the Loading -> Ready and Loading -> Failed transitions.

    Missing: The issue's Design section specifies a Retry button in the Failed state: "The Failed state UI exposes a Retry command that re-triggers the background load sequence from step 2 above, clearing LoadError and resetting to Loading first." Neither a RetryCommand (or equivalent) on AgentSessionWorkspaceTabViewModel nor a Retry button in the Failed-state template exists on the features branch. No test exercises the retry flow.

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions