You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
AgentSessionShortcutContext (features/Phantom.Workspaces/ViewModels/AgentSessionShortcutContext.cs) is a GUI ViewModels-layer class, but it performs a large amount of composition and infrastructure heavy-lifting that belongs in lower layers:
AgentServices composition — hand-assembles the toolset-factory chain, the MCP tool-resource factory (machine/user/defaults mcp-servers search prefixes), the account-upsert service, the current-session context, and forwards SecretProvider.
Agent-persistence-store construction — a ~95-line switch over RepositorySource that builds Web / DevTunnel (reconnecting) / MongoDB / in-memory stores, including GitHub-auth-token resolution and chat-history-provider wiring.
Agent-session entity authoring — builds the agent-session entity JSON document, names, display name, parameter-values, host-profile id, and name sanitization.
Because each launch path re-assembles AgentServices by hand, the assemblies drift and silently drop services. This is not hypothetical — it is the direct root cause of two filed bugs:
Both are symptoms of the same architectural problem: service composition is duplicated across App.axaml.cs and AgentSessionShortcutContext (and other launch sites) instead of living in one shared composition root. The goal of this bug is to strip AgentSessionShortcutContext down to a thin GUI adapter and move the heavy lifting (especially all MCP-server work) into the appropriate layers, so every launch path gets one complete, identical AgentServices bundle and the whole class of "forgot to thread service X" bugs is eliminated.
Root Cause
AgentSessionShortcutContext mixes four unrelated responsibilities in the GUI layer.
(a) AgentServices composition (37-86) — including the MCP tool-resource factory (101-129):
The returned AgentServices (74-85) sets SecretProvider but notMcpOAuthOptions (#1402), and the app-level composition in App.axaml.cs:313-316 builds a differentAgentServices that does have McpOAuthOptions. Two hand-written bundles, guaranteed to drift.
(b) Persistence-store construction (197-292) — a RepositorySource switch that belongs in a persistence-store factory:
AgentPersistenceStoreFactory already exists (used at 222/276/291) — this switch and its three helpers should live there (or in an IAgentPersistenceStoreFactory keyed on RepositorySource), not in a GUI ViewModel.
(d) The only genuinely GUI-specific inputs are MainWindowViewModel, ShortcutManager, and WorkspaceGuiContextProvider. Everything else is host/infrastructure composition.
Existing lower-layer factories the extracted logic should move into or be driven by.
Design / Fix
Reduce AgentSessionShortcutContext to a thin GUI adapter; move each responsibility to its proper layer. Prefer extracting into existing factories over inventing new abstractions.
Move MCP-server tool-resource composition out of the GUI.CreateToolResourceFactory / CreateFixedToolMapping (the ComposingToolResourceFactory + McpServerEntityToolResourceFactory + machine/user/defaults prefixes) belong in an Llm.Core factory (e.g. extend ToolResourceFactory), parameterized by the data-access layer and execution context. The GUI should not know MCP search-prefix precedence.
Move persistence-store construction into AgentPersistenceStoreFactory. Relocate CreateAgentPersistenceStoreAsync and its Web/DevTunnel/MongoDB helpers into AgentPersistenceStoreFactory (or a new IAgentPersistenceStoreFactory keyed on RepositorySource). AgentSessionShortcutContext should call one factory method, not own the switch.
Move agent-session entity authoring into the data layer. Extract CreateAgentSessionEntityData, CreateSessionObjectSimpleName, SanitizeNameComponent into a data-layer AgentSessionEntityFactory (or similar). The shortcut context orchestrates the UpdateAsync call; it does not build the document.
Result.AgentSessionShortcutContext shrinks to: resolve GUI context → call the shared AgentServices composition → call the persistence-store factory → call the entity factory → issue the entity UpdateAsync. No MCP wiring, no persistence switch, no JSON authoring.
This bug is the umbrella refactor; #1401 and #1402 are its symptoms. Landing this eliminates the root cause (per-site hand-assembly of AgentServices). #1401/#1402 may be fixed first as tactical patches, or folded into this refactor — either way their fixes should converge on the single composition root.
The single composition root returns AgentServices with SecretProvider, McpOAuthOptions, toolset factory, MCP tool-resource factory, account-upsert service, and current-session context all set.
The session-launch path returns the bundle from the shared composition root (same McpOAuthOptions/SecretProvider instances as the app-level path), not a hand-assembled one.
Summary
AgentSessionShortcutContext(features/Phantom.Workspaces/ViewModels/AgentSessionShortcutContext.cs) is a GUI ViewModels-layer class, but it performs a large amount of composition and infrastructure heavy-lifting that belongs in lower layers:AgentServicescomposition — hand-assembles the toolset-factory chain, the MCP tool-resource factory (machine/user/defaultsmcp-serverssearch prefixes), the account-upsert service, the current-session context, and forwardsSecretProvider.switchoverRepositorySourcethat builds Web / DevTunnel (reconnecting) / MongoDB / in-memory stores, including GitHub-auth-token resolution and chat-history-provider wiring.Because each launch path re-assembles
AgentServicesby hand, the assemblies drift and silently drop services. This is not hypothetical — it is the direct root cause of two filed bugs:AgentServicesomitsMcpOAuthOptions, so interactive MCP OAuth falls back to the failing "not configured" stub on session launch.SecretProvidermaterialization.Both are symptoms of the same architectural problem: service composition is duplicated across
App.axaml.csandAgentSessionShortcutContext(and other launch sites) instead of living in one shared composition root. The goal of this bug is to stripAgentSessionShortcutContextdown to a thin GUI adapter and move the heavy lifting (especially all MCP-server work) into the appropriate layers, so every launch path gets one complete, identicalAgentServicesbundle and the whole class of "forgot to thread service X" bugs is eliminated.Root Cause
AgentSessionShortcutContextmixes four unrelated responsibilities in the GUI layer.(a)
AgentServicescomposition (37-86) — including the MCP tool-resource factory (101-129):The returned
AgentServices(74-85) setsSecretProviderbut notMcpOAuthOptions(#1402), and the app-level composition inApp.axaml.cs:313-316builds a differentAgentServicesthat does haveMcpOAuthOptions. Two hand-written bundles, guaranteed to drift.(b) Persistence-store construction (197-292) — a
RepositorySourceswitch that belongs in a persistence-store factory:AgentPersistenceStoreFactoryalready exists (used at 222/276/291) — this switch and its three helpers should live there (or in anIAgentPersistenceStoreFactorykeyed onRepositorySource), not in a GUI ViewModel.(c) Agent-session entity authoring (138-195, 294-369) —
CreateAgentSessionEntityData,CreateSessionObjectSimpleName,SanitizeNameComponentare data-layer concerns.(d) The only genuinely GUI-specific inputs are
MainWindowViewModel,ShortcutManager, andWorkspaceGuiContextProvider. Everything else is host/infrastructure composition.Affected Files
features/Phantom.Workspaces/ViewModels/AgentSessionShortcutContext.csAgentServicescomposition (37-86), MCP tool-resource factory (101-129), persistence-store switch (197-292), entity authoring (138-195, 294-369).features/Phantom.Workspaces/App.axaml.csAgentServices(313-316) withMcpOAuthOptions; target caller of the shared composition root.features/Phantom.Workspaces/Services/ApplicationServices.csSecretProvider); natural home for (or reference to) the sharedAgentServicescomposition +McpOAuthOptions.features/Phantom.Workspaces.Llm.Interfaces/AgentServices.csfeatures/Phantom.Workspaces/Services/Mcp/McpOAuthComposition.csfeatures/Phantom.Workspaces.Llm.Core/*(AgentPersistenceStoreFactory,ToolResourceFactory,McpServerEntityToolResourceFactory)Design / Fix
Reduce
AgentSessionShortcutContextto a thin GUI adapter; move each responsibility to its proper layer. Prefer extracting into existing factories over inventing new abstractions.Single
AgentServicescomposition root. Introduce one host-level composer (e.g.Services/AgentServicesComposition.cs, or a method onApplicationServices) that produces the completeAgentServicesbundle: toolset-factory chain, MCP tool-resource factory,SecretProvider,McpOAuthOptions, account-upsert service, current-session context. BothApp.axaml.csandAgentSessionShortcutContext(and any other session-launch site) call this one method, passing only the small GUI-specific context (MainWindowViewModel/ShortcutManager/WorkspaceGuiContextProvider). This structurally prevents Secret materialization is gated on the manifest; agent-session launches never resolve ${SECRET:...} (only sessions/definitions should materialize secrets) #1401/Interactive MCP OAuth not wired on session-launch path: AgentServices omits McpOAuthOptions #1402-class drift — there is exactly one place that can forget a service, and it forgets it for everyone (caught by one test) rather than silently for one path.Move MCP-server tool-resource composition out of the GUI.
CreateToolResourceFactory/CreateFixedToolMapping(theComposingToolResourceFactory+McpServerEntityToolResourceFactory+ machine/user/defaults prefixes) belong in an Llm.Core factory (e.g. extendToolResourceFactory), parameterized by the data-access layer and execution context. The GUI should not know MCP search-prefix precedence.Move persistence-store construction into
AgentPersistenceStoreFactory. RelocateCreateAgentPersistenceStoreAsyncand its Web/DevTunnel/MongoDB helpers intoAgentPersistenceStoreFactory(or a newIAgentPersistenceStoreFactorykeyed onRepositorySource).AgentSessionShortcutContextshould call one factory method, not own the switch.Move agent-session entity authoring into the data layer. Extract
CreateAgentSessionEntityData,CreateSessionObjectSimpleName,SanitizeNameComponentinto a data-layerAgentSessionEntityFactory(or similar). The shortcut context orchestrates theUpdateAsynccall; it does not build the document.Result.
AgentSessionShortcutContextshrinks to: resolve GUI context → call the sharedAgentServicescomposition → call the persistence-store factory → call the entity factory → issue the entityUpdateAsync. No MCP wiring, no persistence switch, no JSON authoring.Considered / Background
McpOAuthOptions, keep everything else in place). That is Interactive MCP OAuth not wired on session-launch path: AgentServices omits McpOAuthOptions #1402's scope and resolves the current failure, but leaves the duplication that will keep producing drift bugs. This bug exists specifically to remove that duplication.Expected Tests
AgentServicesComposition_Compose_ProducesCompleteBundleAgentServicesCompositionTestsAgentServiceswithSecretProvider,McpOAuthOptions, toolset factory, MCP tool-resource factory, account-upsert service, and current-session context all set.AgentSessionShortcutContext_CreateAgentServices_DelegatesToCompositionRootAgentSessionShortcutContextTestsMcpOAuthOptions/SecretProviderinstances as the app-level path), not a hand-assembled one.AgentSessionShortcutContext_DoesNotConstructPersistenceStoreOrToolResourceFactoryAgentSessionShortcutContextTestsRepositorySourceswitch or MCP tool-resource composition (delegates to the factories).AgentPersistenceStoreFactory_CreateForRepositorySource_WebAgentPersistenceStoreFactoryTestsAgentPersistenceStoreFactory_CreateForRepositorySource_MongoDbAndDevTunnelAndInMemoryAgentPersistenceStoreFactoryTestsToolResourceFactory_CreateMcpServerResolution_UsesMachineUserDefaultsPrecedenceToolResourceFactoryTests${USER}/mcp-servers>defaults/mcp-serversprecedence (issue #1399).AgentSessionEntityFactory_CreateEntityData_EscapesFreeTextAndSetsOptionalFieldsAgentSessionEntityFactoryTests