Chat Sessions

Purpose and Scope

A chat session is the durable conversation record behind VS Code AI workflows: the user prompts, AI responses, and contextual state that let a task continue after the UI changes or after the user switches between the Chat view and the Agents window. The official VS Code documentation describes sessions as shared across chat experiences, with each session carrying its own context window and agent type. In this repository slice, the most concrete implementation evidence is the Claude Code session path, which adapts the Anthropic Claude Agent SDK into VS Code services for listing, loading, naming, forking, and inspecting sessions.

The code separates three concerns that are easy to confuse when debugging session behavior. The SDK wrapper is the narrow dependency-injection boundary over @anthropic-ai/claude-agent-sdk. The session parser service turns SDK metadata and messages into VS Code session objects for workspace-aware UI consumption. The agent manager is the runtime side that starts Claude Code interactions, manages the language model server lifecycle, and coordinates tool, MCP, permission, telemetry, authentication, and workspace services while a session is active. Sources: extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeSdkService.ts, extensions/copilot/src/extension/chatSessions/claude/node/sessionParser/claudeCodeSessionService.ts, extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeAgent.ts

Relevant Source Files

  • extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeAgent.ts - Defines ClaudeAgentManager, the runtime manager for Claude Code agent interactions, session objects, and language model server startup.
  • extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeFolderMru.ts - Builds the recently used folder list for agent-session selection from Claude sessions, recent Git repositories, and current workspace folders.
  • extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeModels.ts - Provides the Claude model service used to resolve Claude endpoints, reasoning effort, and VS Code language model picker integration.
  • extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeSdkService.ts - Wraps the Claude Agent SDK session APIs behind IClaudeCodeSdkService so callers can query, list, inspect, rename, fork, and read subagent messages.
  • extensions/copilot/src/extension/chatSessions/claude/node/sessionParser/claudeCodeSessionService.ts - Implements IClaudeCodeSessionService, converting SDK session metadata and message histories into repository session models.
  • extensions/copilot/src/extension/chatSessions/claude/vscode-node/mcpServers/index.ts - Imports MCP server contributors for VS Code-specific Claude session integration registration.

System-to-Code Mapping

The public session-management shape begins with IClaudeCodeSdkService. It exposes query, listSessions, getSessionInfo, getSessionMessages, renameSession, forkSession, listSubagents, and getSubagentMessages. The implementation lazy-loads the Claude Agent SDK through IClaudeAgentSdkLoaderService, which keeps the rest of the extension insulated from direct module loading and makes tests or alternate loaders easier to provide. This is the lowest-level contract on this page: it deals in SDK types such as SDKSessionInfo, SessionMessage, ForkSessionOptions, and GetSubagentMessagesOptions. Sources: extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeSdkService.ts

ClaudeCodeSessionService is the workspace-facing layer. Its interface intentionally has only two methods: getAllSessions for lightweight metadata and getSession for full session content. The implementation delegates to SDK calls, converts raw SDK shapes through adapter helpers such as sdkSessionInfoToSessionInfo, buildClaudeCodeSession, and sdkSubagentMessagesToSubagentSession, and accounts for whether VS Code is currently operating in an agent-sessions workspace. That division lets the UI populate session lists quickly, then load full transcripts and subagent material only when the user opens a specific session. Sources: extensions/copilot/src/extension/chatSessions/claude/node/sessionParser/claudeCodeSessionService.ts

Folder selection and recency are derived from session and repository activity rather than from one storage file. ClaudeCodeFolderMruService asks the session service for all sessions, applies a five-second timeout to avoid delaying MRU population, filters Claude worktree paths such as .claude/worktrees/ and .worktrees/copilot-, and combines the result with IGitService.getRecentRepositories() plus current workspace folders. The resulting entries are sorted by lastAccessed, using session timestamps such as request start, request end, or creation time when available. Sources: extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeFolderMru.ts

Execution Flow

A typical session-listing flow starts when the UI needs available sessions or candidate project folders. The session service checks whether the current workspace is an agent-sessions workspace. In that mode it can call listSessions() without a directory and map every returned SDK session into lightweight session metadata. Otherwise, it discovers project folders, calls SDK session listing for each project location, and builds a combined view that represents sessions in the current working context. Cancellation is respected through the CancellationToken, which matters because session discovery can touch multiple projects and should not block the workbench after the user moves on. Sources: extensions/copilot/src/extension/chatSessions/claude/node/sessionParser/claudeCodeSessionService.ts

Loading a single session is a deeper operation than rendering the list. The service contract says getSession(resource, token) loads complete message history and subagents. The SDK wrapper provides the required primitives: getSessionInfo to retrieve metadata, getSessionMessages to retrieve the conversation body, listSubagents to enumerate child agents, and getSubagentMessages to read messages for a particular subagent. This matches the product concept that an agent session can contain the primary thread plus related autonomous work, while keeping list rendering fast and detailed parsing on demand. Sources: extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeSdkService.ts, extensions/copilot/src/extension/chatSessions/claude/node/sessionParser/claudeCodeSessionService.ts

Starting or continuing an interactive Claude Code run moves into ClaudeAgentManager. The manager owns a DisposableMap<string, ClaudeCodeSession> for active sessions and lazily starts a ClaudeLanguageModelServer the first time it is needed. Its imports show the runtime dependencies that shape a session: authentication, Git and workspace services, MCP configuration, OpenTelemetry tracing, request logging, prompt resolution, external edit tracking, tool permission handling, settings-change tracking, and Claude session URI handling. In practice, this means persistence is not just transcript storage; it is coordinated with model selection, tools, edits, telemetry, and workspace identity. Sources: extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeAgent.ts

API Components

The compact reference below lists the source-level contracts most relevant when extending or debugging session persistence.

ComponentContractBehavior
IClaudeCodeSdkService.query(options)prompt: AsyncIterable<SDKUserMessage>, options: OptionsCreates a Claude Code Query for response streaming or generation.
IClaudeCodeSdkService.listSessions(dir?)Optional project directoryReturns SDKSessionInfo[]; the SDK resolves the storage location internally.
IClaudeCodeSdkService.getSessionInfo(sessionId, dir?)Session ID and optional directoryReturns one SDKSessionInfo or undefined.
IClaudeCodeSdkService.getSessionMessages(sessionId, dir?)Session ID and optional directoryReturns SessionMessage[] for the main conversation.
IClaudeCodeSdkService.renameSession(sessionId, title)Session ID and titleSets a custom title for an existing session.
IClaudeCodeSdkService.forkSession(sessionId, options?)ForkSessionOptionsCreates a new session from an existing session, optionally using a subset of messages.
IClaudeCodeSdkService.listSubagents(sessionId, options?)ListSubagentsOptionsReturns subagent IDs associated with a session.
IClaudeCodeSdkService.getSubagentMessages(sessionId, agentId, options?)Parent session, subagent ID, optional paging or directory optionsReturns messages for one subagent.
IClaudeCodeSessionService.getAllSessions(token)VS Code CancellationTokenReturns lightweight IClaudeCodeSessionInfo entries for the current workspace context.
IClaudeCodeSessionService.getSession(resource, token)Session resource URI and cancellationReturns a complete IClaudeCodeSession with message and subagent content when available.

ClaudeCodeModels is adjacent to persistence because sessions can run with different model choices. Its service resolves a Claude endpoint for a requested model, falls back to an explicit fallback model or to available Claude endpoints, resolves reasoning effort through the CLAUDE_REASONING_EFFORT_PROPERTY, and registers a LanguageModelChatProvider under claude-code. The provider advertises Claude models in VS Code's model picker, emits model-change events when endpoints refresh, and deliberately leaves chat response generation to chat participants rather than implementing it inside the picker provider. Sources: extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeModels.ts

Sync, Remote, and MCP Considerations

The official session-sync documentation says VS Code syncs chat sessions to the user's GitHub account by default, including local agent sessions, while enterprise policy and settings can keep session data local. The source evidence here does not contain the cloud sync implementation, but it does show the local session surface that sync-related features must read from or coordinate with: SDK session metadata, full message history, subagent messages, workspace folders, and repository identity. When investigating sync problems, first determine whether the problem is local session discovery, full transcript loading, repository exclusion or policy, or cloud transport outside this Claude service layer.

Remote sessions add another boundary. The official remote-agent documentation describes using the Agents window to start or inspect sessions on SSH hosts or dev tunnels through the Agent Host Protocol. In the supplied implementation files, workspace and folder identity remain central: the session service discovers project folders, the folder MRU service combines sessions with recent Git repositories, and the agent manager imports native environment and workspace services. That means remote behavior should be validated by checking which directory the SDK is asked to use, whether the workspace is treated as an agent-sessions workspace, and whether repository MRU entries point to the expected remote folder. Sources: extensions/copilot/src/extension/chatSessions/claude/node/sessionParser/claudeCodeSessionService.ts, extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeFolderMru.ts, extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeAgent.ts

MCP servers are registered through import side effects. The VS Code node entrypoint imports the node MCP server index first, with comments explaining the contributor chain from common to node to VS Code-specific modules. ClaudeAgentManager imports MCP types and services, including McpServerConfig, IMcpService, LanguageModelToolMCPSource, and buildMcpServersFromRegistry, which places MCP configuration in the runtime path rather than in the session parser. For maintainers, this is the key distinction: persisted sessions can contain the evidence of tool use, but MCP server contribution and permission wiring belongs to the agent execution layer. Sources: extensions/copilot/src/extension/chatSessions/claude/vscode-node/mcpServers/index.ts, extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeAgent.ts

Implementation and Troubleshooting Notes

When a session does not appear in the list, start at getAllSessions and the folder MRU flow rather than at the transcript parser. The service may be operating in global agent-sessions mode, or it may be enumerating project folders and asking the SDK for sessions per directory. The MRU layer can also suppress paths that look like generated worktrees and can hide folders after deleteRecentlyUsedFolder records them in an in-memory ResourceSet. A stale-looking picker can also come from cached MRU entries, although the service updates the cache when a new retrieval completes. Sources: extensions/copilot/src/extension/chatSessions/claude/node/sessionParser/claudeCodeSessionService.ts, extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeFolderMru.ts

When a session appears but content is incomplete, inspect the boundary between SDK calls and adapters. The expected full-load sequence uses metadata, main messages, subagent IDs, and subagent messages. Failures in any one of those calls can produce an object that is present in the list but missing expected detail. The implementation imports logging and converts caught errors to readable messages, so debug logs from ClaudeCodeSessionService and SDK loader failures are more actionable than UI symptoms alone. For runtime failures during active chats, switch to ClaudeAgentManager and check model resolution, MCP setup, permission handling, and telemetry spans. Sources: extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeSdkService.ts, extensions/copilot/src/extension/chatSessions/claude/node/sessionParser/claudeCodeSessionService.ts, extensions/copilot/src/extension/chatSessions/claude/node/claudeCodeAgent.ts

Next Steps

Read the Chat View and Agents Window pages to understand the user-facing surfaces that open and switch sessions. Read MCP Servers and Chat Tools and Approvals when a session's behavior depends on external tools. For implementation work, use IClaudeCodeSdkService as the stable boundary for SDK operations, IClaudeCodeSessionService as the workspace and parsing layer, and ClaudeAgentManager as the active execution layer. Keeping those layers separate makes it easier to decide whether a bug belongs to persistence, model selection, tool execution, workspace discovery, or sync policy.