Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/sessions/MOBILE.md
13383 views

Mobile Agent Sessions — Architecture

Core Principle

Every feature accessible in the desktop window must be accessible on mobile — same functionality, different presentation. Mobile is NOT "desktop minus stuff." It is a parallel UI layer where the same services, views, and actions are rendered through mobile-native interaction patterns.

Architecture

Mobile Part Subclasses

Desktop Parts (ChatBarPart, SidebarPart, PanelPart, AuxiliaryBarPart) remain unchanged. Each has a mobile subclass that extends it and overrides only layout() and/or updateStyles(). AgenticPaneCompositePartService conditionally instantiates the mobile or desktop variant at startup based on viewport width (< 640px → phone).

Each mobile Part checks the current layout class (via isPhoneLayout(layoutService)) at every call. When the viewport is phone it applies mobile behavior (full-cell layout, no card chrome, no session-bar subtraction). When the viewport is tablet/desktop — which happens when a real phone rotates past the 640px breakpoint — it delegates to the desktop super implementation. This means a Mobile*Part instance is safe to keep through a viewport-class transition without producing wrong layout math.

This means:

  • Desktop code has zero phone-layout checks — all mobile logic lives in mobile subclasses, MobileTitlebarPart, and CSS.

  • Phone-instantiated parts adapt correctly to rotation across the 640px breakpoint by delegating to super.

After a viewport-class transition the workbench calls updateStyles() on each pane composite part so card-chrome inline styles get re-applied (desktop) or cleared (phone) for the new class.

View & Action Gating

Views, menu items, and actions use when clauses with the sessionsIsPhoneLayout context key to control visibility in phone layout. This follows a default-deny approach for phone:

  • Desktop-only features add when: IsPhoneLayoutContext.negate() to their view descriptors and menu registrations. They simply don't appear on phone.

  • Phone-compatible features (chat, sessions list) have no phone gate — they render on all viewports.

  • Phone-specific replacements (when ready) register with when: IsPhoneLayoutContext and live in separate files under parts/mobile/contributions/.

Tablet and larger viewports currently fall back to the desktop layout; no separate tablet design exists yet.

Two registrations can target the same slot with opposite when clauses, pointing to different view classes in different files — giving full file separation with no internal branching.

Current Gating Status

FeaturePhone StatusMechanism
Sessions list (sidebar)✅ CompatibleNo gate
Chat views (ChatBar)✅ CompatibleNo gate
Changes view (AuxiliaryBar)❌ Gatedwhen: !sessionsIsPhoneLayout on view descriptor
Files view (AuxiliaryBar)❌ Gatedwhen: !sessionsIsPhoneLayout on view descriptor
Logs view (Panel)❌ Gatedwhen: !sessionsIsPhoneLayout on view descriptor
Terminal actions❌ Gatedwhen: !sessionsIsPhoneLayout on menu item
"Open in VS Code" action❌ Gatedwhen: !sessionsIsPhoneLayout on menu item
Code review toolbar❌ Gatedwhen: !sessionsIsPhoneLayout on menu item
Customizations toolbar❌ HiddenCSS display: none on phone
Titlebar❌ HiddenGrid visible: false + CSS + MobileTitlebarPart replacement

Phone Layout

On phone-sized viewports (< 640px width):

┌──────────────────────────────────┐ │ [☰] Session Title [+|👤] │ ← MobileTitlebarPart (prepended before grid) ├──────────────────────────────────┤ │ │ │ Chat (edge-to-edge) │ ← Grid: ChatBarPart fills 100% │ │ │ │ │ │ │ ┌──────────────────────────┐ │ │ │ Chat input │ │ ← Pinned to bottom │ └──────────────────────────┘ │ └──────────────────────────────────┘
  • MobileTitlebarPart is a DOM element prepended above the grid. It has a hamburger (☰), session title, and a contextual right slot that swaps between the new session (+) button (when in a chat) and the account indicator 👤 (on the welcome / new session screen).

  • Sidebar is hidden by default and opens as an 85% width drawer overlay with a backdrop when the hamburger is tapped. CSS makes its split-view-view absolutely positioned with z-index: 250. The workbench manually calls sidebarPart.layout() with drawer dimensions after opening. Closing the drawer clears the navigation stack.

  • Titlebar is hidden in the grid (visible: false) and via CSS — replaced by MobileTitlebarPart.

  • SessionCompositeBar (chat tabs) is hidden via CSS.

  • The grid uses display: flex; flex-direction: column and all split-view-view:has(> .part) containers are positioned absolutely at 100% width/height.

Viewport Classification

SessionsLayoutPolicy classifies the viewport:

  • phone: width < 640px

  • tablet: 640px ≤ width < 1024px (treated as desktop; no phone-specific chrome)

  • desktop: width ≥ 1024px

The workbench toggles the phone-layout CSS class on layout() and creates/destroys mobile components when the viewport class changes at runtime (e.g., DevTools device emulation, or a real phone rotating across the 640px breakpoint). MobileTitlebarPart lifecycle is managed via a DisposableStore that is cleared on viewport transitions to prevent leaks.

Context Keys

KeyTypePurpose
sessionsIsPhoneLayoutbooleantrue when the viewport is phone (< 640px)
sessionsKeyboardVisiblebooleantrue when the virtual keyboard is visible

Desktop → Mobile Component Mapping

Desktop ComponentMobile EquivalentHow Accessed
Titlebar (3-section toolbar)MobileTitlebarPart (☰ / title / +👤)
Sidebar (sessions list)Drawer overlay (85% width)Hamburger button (☰)
ChatBar (chat widget)Same Part, edge-to-edge, no card chromeDefault view (always visible)
AuxiliaryBar (files, changes)Gated — not shown on mobilePlanned: mobile-specific view
Panel (terminal, output)Gated — not shown on mobilePlanned: mobile-specific view
SessionCompositeBar (chat tabs)Hidden on phone
New Session (sidebar button)+ button in MobileTitlebarPartVisible in top bar when in a chat
Account indicator (titlebar)Account button in MobileTitlebarPartVisible in top bar on welcome/new session

File Map

Mobile Part Subclasses

FilePurpose
browser/parts/mobile/mobileChatBarPart.tsExtends ChatBarPart. Overrides layout() (no card margins) and updateStyles() (no inline card styles).
browser/parts/mobile/mobileSidebarPart.tsExtends SidebarPart. Overrides updateStyles() (no inline card/title styles).
browser/parts/mobile/mobileAuxiliaryBarPart.tsExtends AuxiliaryBarPart. Overrides layout() and updateStyles() (no card margins or inline styles).
browser/parts/mobile/mobilePanelPart.tsExtends PanelPart. Overrides layout() and updateStyles() (no card margins or inline styles).

Mobile Chrome Components

FilePurpose
browser/parts/mobile/mobileTitlebarPart.tsPhone top bar: hamburger (☰), session title, contextual right slot (+ for in-chat, account indicator for welcome). Emits onDidClickHamburger, onDidClickNewSession, onDidClickTitle. Includes account state tracking, avatar loading, and account panel with copilot dashboard.
browser/parts/mobile/mobileChatShell.cssSingle source of truth for all phone-layout CSS: flex column layout, split-view-view absolute positioning, card chrome removal, part/content width overrides, sidebar title hiding, composite bar hiding, welcome page layout, sash hiding, button focus overrides, mobile pickers.

Layout & Navigation

FilePurpose
browser/layoutPolicy.tsSessionsLayoutPolicy: observable viewport classification (phone/tablet/desktop), platform flags (isIOS, isAndroid, isTouchDevice), part visibility and size defaults.
browser/mobileNavigationStack.tsMobileNavigationStack: Android back button integration via history.pushState / popstate. Supports push(), pop(), and clear().
common/contextkeys.tsPhone context keys: IsPhoneLayoutContext, KeyboardVisibleContext.

Part Instantiation

FilePurpose
browser/paneCompositePartService.tsAgenticPaneCompositePartService: checks viewport width at construction time and instantiates Mobile*Part vs desktop *Part classes accordingly.

Workbench Integration

FileKey Changes
browser/workbench.tsLayout policy integration, MobileTitlebarPart creation/destruction (via DisposableStore), sidebar drawer open/close with backdrop, viewport-class-change detection, window resize listener, grid height calculation (subtracts MobileTitlebarPart height), titlebar grid visibility toggle, ISessionsManagementService for new session button.
browser/parts/chatBarPart.ts_lastLayout changed from private to protected for mobile subclass access.

Styling

FilePurpose
browser/parts/mobile/mobileChatShell.cssAll phone-layout CSS (see above).
browser/parts/media/sidebarPart.cssSidebar drawer overlay CSS: 85% width, z-index 250, slide-in animation, backdrop.
browser/media/style.cssMobile overscroll containment, 44px touch targets, quick pick bottom sheets, context menu action sheets, dialog sizing, notification positioning, hover card suppression, editor modal full-screen.

Remaining Work

  • Files & Terminal access: Should become phone-specific views gated with when: IsPhoneLayoutContext.

  • iOS keyboard handling: Adjust layout when virtual keyboard appears (context key exists, but no layout response yet).

  • Session list inline actions: Make always-visible on touch devices (no hover-to-reveal).

  • Customizations on mobile: Currently hidden — needs a mobile-friendly alternative.