Repository navigation
Opening an agent session should show a loading tab immediately, then transition to the loaded view #59
Description
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…" messageReady→ existingAgentChatEditorControlFailed→ 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:
- Open a placeholder loading tab with a temporary id.
- Await
CreateAgentSessionEntityAsync(fast — just a data write). - Re-key the tab to the new entity id.
- Await
AgentFactory.CreateAgentChatAsyncin the background. - 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.csPhantom.Workspaces/ViewModels/OpenAgentSessionShortcutHandler.csPhantom.Workspaces/ViewModels/OpenAgentDefinitionShortcutHandler.csPhantom.Workspaces/Templates/(or wherever the agent tab data template lives) — add
loading / failed state views
Activity
Fix #59: agent session tabs open immediately with loading state, init…
JoshuaRowePhantom commentedon Jun 30, 2026
Verification failed
Checked: Commit e51ec14 (Fix #59) and the
featuresbranch tip. Files inspected:Phantom.Workspaces/ViewModels/AgentSessionWorkspaceTabViewModel.csPhantom.Workspaces/ViewModels/OpenAgentSessionShortcutHandler.csPhantom.Workspaces/ViewModels/OpenAgentDefinitionShortcutHandler.csPhantom.Workspaces/Templates/WorkspaceDataTemplates.axamlPhantom.Workspaces.Tests/MainWindowIntegrationTests.csFound: The core loading-state machine is correctly implemented.
AgentTabState(Loading/Ready/Failed) is present onAgentSessionWorkspaceTabViewModel;OpenAgentSessionShortcutHandler.Handleopens the loading tab immediately and initialises the agent in a backgroundTask.Run;WorkspaceDataTemplates.axamlrenders 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
Failedstate UI exposes a Retry command that re-triggers the background load sequence from step 2 above, clearingLoadErrorand resetting toLoadingfirst." Neither aRetryCommand(or equivalent) onAgentSessionWorkspaceTabViewModelnor a Retry button in the Failed-state template exists on thefeaturesbranch. No test exercises the retry flow.