Skip to content

sessions: Add mobile-compatible layout for agent sessions#309344

Merged
osortega merged 16 commits intomainfrom
agents/fixed-magpie
Apr 23, 2026
Merged

sessions: Add mobile-compatible layout for agent sessions#309344
osortega merged 16 commits intomainfrom
agents/fixed-magpie

Conversation

@osortega
Copy link
Copy Markdown
Contributor

@osortega osortega commented Apr 13, 2026

Revert: #310552
Revert: #310849

Summary

Introduces a responsive mobile layout for the agent sessions window, enabling a native app-like experience when accessed via mobile browsers or installed as a PWA. The implementation uses mobile Part subclasses, a MobileTopBar chrome component, CSS overrides, and when-clause gating to progressively enhance the desktop sessions workbench for phone viewports (<640px).

Architecture

The approach avoids forking the workbench — instead it layers mobile behavior on top:

  • SessionsLayoutPolicy — Observable viewport classification (phone/tablet/desktop) using width breakpoints + platform flags
  • Mobile Part subclasses (MobileChatBarPart, MobileSidebarPart, MobileAuxiliaryBarPart, MobilePanelPart) — Override only layout() and updateStyles(), keeping desktop Parts untouched
  • AgenticPaneCompositePartService — Conditionally instantiates mobile vs desktop Part classes at construction
  • MobileTopBar — Phone top bar chrome: hamburger (☰) + session title + new session (+)
  • MobileNavigationStackhistory.pushState integration for Android back button support
  • when clause gating — Desktop-only views (Changes, Files, Logs, Terminal, Code Review, "Open in VS Code") hidden on mobile via IsMobileLayoutContext.negate()
  • mobileChatShell.css — Single source of truth for all phone-layout CSS

Key Changes

Area What Changed
Layout policy SessionsLayoutPolicy with observable viewport class, 3 context keys
Mobile chrome MobileTopBar with hamburger/title/+ buttons
Navigation MobileNavigationStack with history.pushState/popstate
Part subclasses 4 mobile Part classes overriding layout/styling only
Sidebar drawer Full-screen overlay (85% width) with backdrop dismiss
Chat Edge-to-edge on phone (no card chrome, no max-width)
View gating 6 desktop-only contributions hidden on mobile
PWA Manifest, viewport-fit=cover, dynamic theme-color meta
CSS Safe area insets, 44px touch targets, overscroll containment

Context Keys Added

  • ViewportClassContext'phone' / 'tablet' / 'desktop'
  • IsMobileLayoutContexttrue when phone or tablet
  • KeyboardVisibleContexttrue when virtual keyboard is open

Testing

Tested via npm run serve from src/vs/sessions/test/e2e with Chrome DevTools device emulation (iPhone 14 Pro, Pixel 7). Verified:

  • Edge-to-edge chat rendering
  • Sidebar drawer open/close with backdrop
  • New session button (+) in top bar
  • Desktop-only views properly hidden
  • Android back button dismisses sidebar

Known Limitations

  • Session title in MobileTopBar shows hardcoded "New Session" — not yet wired to sessionsManagementService.activeSession
  • Part classes chosen once at construction, no runtime swapping on resize
  • Customizations panel hidden on mobile — needs mobile-specific alternative
  • iOS keyboard handling context key exists but layout response not yet implemented

Documentation

See src/vs/sessions/MOBILE.md for full architecture docs, file map, and remaining work items.

Copilot AI review requested due to automatic review settings April 13, 2026 02:21
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a mobile/PWA-friendly layout to the Agents Sessions standalone window (vs/sessions) and extends the web sessions entrypoint to discover/connect remote agent hosts in browser contexts.

Changes:

  • Introduces a mobile layout policy + mobile chrome (top bar, drawer sidebar, viewport/keyboard context keys) and a phone-first CSS layer.
  • Gates several desktop-only views/actions on mobile via IsMobileLayoutContext.negate().
  • Adds browser implementations for remote agent host connectivity (WebSocket transport + service) and web host discovery wiring in sessions.web.main.ts.
Show a summary per file
File Description
src/vs/sessions/sessions.web.main.ts Registers browser remote-agent-host services and sessions web contributions.
src/vs/sessions/MOBILE.md Documents the mobile architecture, parts, gating, and remaining work.
src/vs/sessions/contrib/welcome/browser/welcome.contribution.ts Skips welcome overlay when an existing GitHub session is detected.
src/vs/sessions/contrib/welcome/browser/sessionsWalkthrough.ts Adds fallback device-code sign-in flow and remote host connection bootstrap.
src/vs/sessions/contrib/webHostDiscovery/browser/webHostDiscovery.contribution.ts New workbench contribution to discover hosts from registry on web.
src/vs/sessions/contrib/terminal/browser/sessionsTerminalContribution.ts Hides “Open session in terminal” action on mobile layout.
src/vs/sessions/contrib/sessions/browser/media/sessionsList.css Makes list inline actions always visible + touch feedback on mobile.
src/vs/sessions/contrib/logs/browser/logs.contribution.ts Gating logs view container off on mobile.
src/vs/sessions/contrib/files/browser/files.contribution.ts Gating files view off on mobile.
src/vs/sessions/contrib/codeReview/browser/codeReview.contributions.ts Gating code-review toolbar actions off on mobile.
src/vs/sessions/contrib/chat/browser/chat.contribution.ts Gating “Open in VS Code” action off on mobile.
src/vs/sessions/contrib/changes/browser/changesView.contribution.ts Gating changes view off on mobile.
src/vs/sessions/common/contextkeys.ts Adds viewport/mobile/keyboard context keys for mobile layout.
src/vs/sessions/browser/workbench.ts Core mobile layout integration: classes, top bar, drawer behavior, theme-color updates.
src/vs/sessions/browser/parts/mobile/mobileTopBar.ts New mobile top bar component.
src/vs/sessions/browser/parts/mobile/mobileSidebarPart.ts Mobile sidebar part variant with reduced inline styling.
src/vs/sessions/browser/parts/mobile/mobilePanelPart.ts Mobile panel part variant with full-bleed layout behavior.
src/vs/sessions/browser/parts/mobile/mobileChatShell.css New phone-layout CSS source-of-truth.
src/vs/sessions/browser/parts/mobile/mobileChatBarPart.ts Mobile chat bar part variant with full-bleed layout behavior.
src/vs/sessions/browser/parts/mobile/mobileAuxiliaryBarPart.ts Mobile auxiliary bar part variant with full-bleed layout behavior.
src/vs/sessions/browser/parts/media/titlebarpart.css Phone overrides for titlebar structure (even though hidden on phone).
src/vs/sessions/browser/parts/media/sidebarPart.css Implements phone sidebar drawer overlay + backdrop styling.
src/vs/sessions/browser/parts/chatBarPart.ts Makes _lastLayout protected for mobile subclass access.
src/vs/sessions/browser/paneCompositePartService.ts Chooses mobile vs desktop part classes at construction for phone widths.
src/vs/sessions/browser/mobileNavigationStack.ts New history-backed overlay stack for Android back button behavior.
src/vs/sessions/browser/media/style.css Mobile quick pick/context menu/dialog/toast/editor-modal styling.
src/vs/sessions/browser/layoutPolicy.ts New SessionsLayoutPolicy for viewport classification and defaults.
src/vs/platform/agentHost/common/state/sessionTransport.ts Extends transport send typing to include JSON-RPC notifications.
src/vs/platform/agentHost/browser/webSocketClientTransport.ts New browser WebSocket transport for agent-host protocol messages.
src/vs/platform/agentHost/browser/remoteAgentHostServiceImpl.ts New browser remote agent host service implementation.
src/vs/platform/agentHost/browser/remoteAgentHostProtocolClient.ts New protocol client wrapping transport + JSON-RPC request/notify handling.
src/vs/platform/agentHost/browser/nullSshRemoteAgentHostService.ts Browser null service for SSH remote agent host support.
src/vs/code/browser/workbench/workbench.html Adds viewport-fit=cover and an Apple startup image link.
resources/server/manifest.json Adds PWA theme/background/orientation metadata.
extensions/copilot/package-lock.json Lockfile updates (dev flags added on some deps).

Copilot's findings

Files not reviewed (1)
  • extensions/copilot/package-lock.json: Language not supported
Comments suppressed due to low confidence (5)

src/vs/sessions/browser/parts/mobile/mobileTopBar.ts:52

  • The default session title string 'New Session' is user-facing and should be localized (and ideally wired to the active session title when available).
		this.sessionTitleElement = append(this.element, $('div.mobile-session-title'));
		this.sessionTitleElement.textContent = 'New Session';
		this.sessionTitleElement.addEventListener('click', () => this._onDidClickTitle.fire());

src/vs/sessions/browser/parts/mobile/mobileTopBar.ts:57

  • The new session button’s aria-label is user-facing text but is not localized. Please externalize it via localize(...).
		const newSession = append(this.element, $('button.mobile-top-bar-button'));
		newSession.setAttribute('aria-label', 'New session');
		const newSessionIcon = append(newSession, $('span'));

src/vs/sessions/contrib/welcome/browser/welcome.contribution.ts:107

  • Same floating-promise issue here: _hasExistingGitHubSession().then(...) is not awaited and has no .catch(...). Consider void ... and a rejection handler to avoid unhandled rejections.
    src/vs/sessions/contrib/welcome/browser/sessionsWalkthrough.ts:344
  • The access token is included in the WebSocket proxy URL as a query parameter (token=...). Tokens in URLs can leak via logs, intermediaries, and referrers. Prefer passing tokens via headers during the WebSocket upgrade (if supported) or using a short-lived one-time code instead of the raw token in the URL.
    src/vs/sessions/contrib/webHostDiscovery/browser/webHostDiscovery.contribution.ts:118
  • _waitForToken() polls localStorage for a token. Since this token is security-sensitive, prefer reading from ISecretStorageService (encrypted) or another protected channel rather than relying on plain localStorage.
  • Files reviewed: 34/35 changed files
  • Comments generated: 10

Comment thread src/vs/sessions/browser/workbench.ts Outdated
Comment thread src/vs/sessions/browser/workbench.ts Outdated
Comment thread src/vs/sessions/browser/workbench.ts
Comment thread src/vs/sessions/browser/parts/mobile/mobileTopBar.ts
Comment thread src/vs/sessions/browser/parts/mobile/mobileChatShell.css
Comment thread src/vs/sessions/contrib/welcome/browser/welcome.contribution.ts Outdated
Comment thread src/vs/sessions/contrib/welcome/browser/sessionsWalkthrough.ts Outdated
Comment thread src/vs/sessions/contrib/webHostDiscovery/browser/webHostDiscovery.contribution.ts Outdated
Comment thread src/vs/platform/agentHost/browser/remoteAgentHostServiceImpl.ts Outdated
Comment thread src/vs/platform/agentHost/browser/webSocketClientTransport.ts Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 22, 2026

Screenshot Changes

Base: 9932ad01 Current: 1e1a438d

Changed (1)

chat/aiCustomizations/aiCustomizationManagementEditor/McpBrowseMode/Light
Before After
before after

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

Comments suppressed due to low confidence (1)

src/vs/sessions/browser/parts/mobile/mobileTopBar.ts:52

  • The mobile top bar title is always initialized to "New Session" and never updated, so it will be incorrect once a real session becomes active. Since ISessionsManagementService.activeSession already exists, consider wiring MobileTopBar.setTitle(...) to the active session (and/or active chat) so the top bar reflects the current session.
		// Session title
		this.sessionTitleElement = append(this.element, $('div.mobile-session-title'));
		this.sessionTitleElement.textContent = 'New Session';
		this.sessionTitleElement.addEventListener('click', () => this._onDidClickTitle.fire());
  • Files reviewed: 25/25 changed files
  • Comments generated: 5

Comment thread src/vs/sessions/sessions.web.main.ts Outdated
Comment thread src/vs/sessions/browser/workbench.ts
Comment thread src/vs/sessions/browser/workbench.ts
Comment thread src/vs/sessions/browser/paneCompositePartService.ts
Comment thread src/vs/sessions/browser/parts/mobile/mobileTopBar.ts
@osortega
Copy link
Copy Markdown
Contributor Author

Images

Before:
image

Now:
Screenshot 2026-04-22 at 12 49 43 PM

Comment thread src/vs/sessions/browser/media/style.css Outdated
Comment thread src/vs/sessions/browser/parts/mobile/mobileAuxiliaryBarPart.ts
osortega and others added 9 commits April 22, 2026 21:06
Introduce a responsive mobile layout for the agent sessions window,
enabling a native app-like experience when accessed via mobile browsers
or installed as a PWA. The implementation uses mobile Part subclasses,
a MobileTopBar chrome component, CSS overrides, and when-clause gating
to progressively enhance the desktop sessions workbench for phone
viewports.

Key changes:

Layout policy & viewport detection:
- SessionsLayoutPolicy with observable viewport classification
  (phone <640px, tablet 640-1024, desktop >1024)
- Context keys: ViewportClassContext, IsMobileLayoutContext,
  KeyboardVisibleContext
- Runtime viewport class change detection in layout()

Mobile chrome components:
- MobileTopBar: hamburger + session title + new session (+)
- MobileNavigationStack: history.pushState integration for Android
  back button
- Sidebar drawer overlay with backdrop dismiss

Mobile Part subclasses:
- MobileChatBarPart, MobileSidebarPart, MobileAuxiliaryBarPart,
  MobilePanelPart override layout()/updateStyles() only
- AgenticPaneCompositePartService conditionally instantiates
  mobile vs desktop Parts

View gating:
- Desktop-only views hidden on mobile via IsMobileLayoutContext:
  Changes, Files, Logs, Terminal, Code Review, Open in VS Code
- Customization toolbar hidden via CSS on phone

CSS & PWA:
- Edge-to-edge chat (no card chrome on phone)
- Safe area insets, touch targets (44px min), overscroll containment
- PWA manifest with standalone display mode
- viewport-fit=cover meta tag
- Dynamic theme-color meta created programmatically

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove agentHost WebSocket implementation, webHostDiscovery contribution,
welcome/walkthrough OAuth flow changes, PWA manifest updates, and lock
file noise — none of these are related to mobile layout components for
the agents workbench.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
These files exist in main and were not introduced by this PR.
They were mistakenly removed during out-of-scope cleanup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Revert copilot package-lock.json to main (unrelated npm artifact)
- Revert agentHost remoteAgentHostProtocolClient.ts (diffs field not mobile-related)
- Revert agentHost sessionTransport.ts (protocol cleanup not mobile-related)
- Remove theme-color meta element creation and dynamic updates (PWA)
- Remove apple-touch-startup-image link injection (PWA)
- Remove PWA & Viewport section from MOBILE.md
- Keep viewport-fit=cover as it is needed for safe-area-inset CSS on mobile

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The mobile phone-layout CSS targeted non-existent class names
(chat-full-welcome*) instead of the actual DOM classes used by
newChatViewPane.ts and newChatInput.ts. This caused the welcome
page to render without the Copilot logo, centering, or
bottom-pinned input on phone viewports.

Also fixes the logo SVG path and adds dark/light theme support.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix isVisible(TITLEBAR_PART) to return false on phone layout where the
  grid titlebar is hidden and replaced by MobileTopBar
- Fix computeContainerOffset() to use MobileTopBar height on phone layout
  so overlays (quick picks, hovers) are positioned correctly
- Add CSS comment block documenting the .mobile-layout vs .phone-layout
  class hierarchy and when to use each
- Add code comment in MobileAuxiliaryBarPart explaining why inline style
  clearing is needed (parent sets them via JS, CSS can't override)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sal hygiene

- Mobile Parts now dispatch at runtime (isPhoneLayout): phone uses mobile
  layout math, tablet/desktop delegates to super. Fixes 35px chat overlap
  after phone→landscape rotation across the 640px breakpoint.
- Workbench calls updateStyles() on pane composite parts after viewport
  class transitions so card-chrome inline styles re-apply/clear correctly.
- MobileNavigationStack: replace _suppressNextPop boolean with pending
  counter to handle concurrent popSilently calls and rapid back taps.
- Drop redundant Part.prototype.layout.call in mobile Part overrides
  (AbstractPaneCompositePart.layout already cascades to Part.layout).
- Virtual keyboard detection: use mainWindow.innerHeight as baseline
  instead of captured initialViewportHeight; threshold 150→100.
- Sidebar drawer backdrop: managed via DisposableStore with
  addDisposableListener for its click handler.
- MobileTopBar: switch raw addEventListener to addDisposableListener;
  register element removal before parent.prepend so exceptions still
  clean up.
- Remove redundant matchMedia orientation listener; the window resize
  listener already handles orientation changes.
@osortega osortega force-pushed the agents/fixed-magpie branch from f96a8eb to 06f0285 Compare April 23, 2026 04:08
@osortega osortega marked this pull request as ready for review April 23, 2026 04:14
joshspicer
joshspicer previously approved these changes Apr 23, 2026
joshspicer
joshspicer previously approved these changes Apr 23, 2026
@osortega osortega force-pushed the agents/fixed-magpie branch from 3177f04 to 6e0dbc9 Compare April 23, 2026 04:21
@osortega osortega enabled auto-merge (squash) April 23, 2026 04:23
joshspicer
joshspicer previously approved these changes Apr 23, 2026
Comment thread src/vs/sessions/browser/layoutPolicy.ts Outdated
* only applied on actual mobile devices so that resizing a desktop window
* below 640px does not switch the agents workbench into phone mode.
*/
const isMobilePlatform = isIOS || isAndroid;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we may want to use platform.isMobile.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in commit 41760a28: SessionsLayoutPolicy now uses platform.isMobile for mobile layout gating instead of the local iOS/Android check.

Screenshot: https://github.com/user-attachments/assets/538e657c-c808-429c-9c64-a6b8f0eae021

Comment thread src/vs/sessions/browser/parts/media/sidebarPart.css
Comment thread src/vs/sessions/browser/media/style.css Outdated
@osortega osortega changed the title sessions: Add mobile-compatible PWA layout for agent sessions sessions: Add mobile-compatible layout for agent sessions Apr 23, 2026
@rebornix
Copy link
Copy Markdown
Member

@copilot review all the !important usage. remove the unnecessary ones, especially when we have more strict css selectors.

Comment thread src/vs/sessions/MOBILE.md
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 23, 2026

@copilot review all the !important usage. remove the unnecessary ones, especially when we have more strict css selectors.

Completed in commit 41760a28: I reviewed the sessions mobile CSS !important usage and removed the unnecessary ones where selector specificity is already sufficient, keeping only overrides that must win against inline layout styles.

Screenshot: https://github.com/user-attachments/assets/538e657c-c808-429c-9c64-a6b8f0eae021

Copilot AI requested a review from rebornix April 23, 2026 05:02
@rebornix
Copy link
Copy Markdown
Member

@copilot are !important for the css rules beginning with .agent-sessions-workbench.phone-layout selector required?

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 23, 2026

@copilot are !important for the css rules beginning with .agent-sessions-workbench.phone-layout selector required?

Not all of them are required, and I already removed the unnecessary ones in 41760a28. The remaining !important under .agent-sessions-workbench.phone-layout are primarily the rules that must override inline positioning/sizing written by workbench layout/context-view code (for quick input, context menus, overlays, and split-view containers).

Screenshot: https://github.com/user-attachments/assets/9bbef325-dc41-4f1e-8c98-57e1beb3e5f1

# Conflicts:
#	src/vs/sessions/contrib/changes/browser/changes.contribution.ts
#	src/vs/sessions/contrib/files/browser/files.contribution.ts
#	src/vs/sessions/contrib/logs/browser/logs.contribution.ts
# Conflicts:
#	src/vs/sessions/browser/workbench.ts
@osortega osortega merged commit 6aaf3c6 into main Apr 23, 2026
40 of 41 checks passed
@osortega osortega deleted the agents/fixed-magpie branch April 23, 2026 16:34
@vs-code-engineering vs-code-engineering Bot added this to the 1.118.0 milestone Apr 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants