Skip to content

agent-host: surface session git state via SessionState._meta#312543

Merged
roblourens merged 11 commits intomainfrom
roblou/agents/agent-host-git-metadata
Apr 26, 2026
Merged

agent-host: surface session git state via SessionState._meta#312543
roblourens merged 11 commits intomainfrom
roblou/agents/agent-host-git-metadata

Conversation

@roblourens
Copy link
Copy Markdown
Member

The agent host process now computes per-session git state (branch, GitHub remote, ahead/behind, uncommitted changes) for sessions that have a working directory and publishes it through the protocol's per-session _meta. The Agents app reads it from SessionState._meta (not SessionSummary) and surfaces it via ISessionWorkspace, lighting up existing UI in the Changes view (e.g. ahead/behind indicators, branch info).

This is a narrower successor to #311815: just the metadata pipe, without skill syncing or toolbar button contributions. Those will be revisited separately.

Highlights

  • New AgentHostGitService (server-side) computes git state by shelling out to git; refreshed on session open and after each turn.
  • New SessionMetaChanged action propagates _meta deltas without a full list refresh.
  • Client-side AgentHostSessionAdapter retains _project / _workingDirectory / _meta so the workspace observable can be rebuilt when only _meta changes.
  • baseBranchProtected is computed client-side from git.branchProtection config, so the workspace shape no longer carries it as a field on ISessionRepository.
  • update() only overwrites _meta when the source actually provides one (SessionSummary feeds have no _meta field), so the polling refresh path no longer clobbers good state pushed via SessionState.

(Written by Copilot)

The agent host process now computes per-session git state (branch, GitHub
remote, ahead/behind, uncommitted changes) for sessions that have a working
directory and publishes it through the protocol's per-session `_meta`.
The Agents app reads it from `SessionState._meta` (not `SessionSummary`)
and surfaces it via `ISessionWorkspace`, lighting up existing UI in the
Changes view (e.g. ahead/behind indicators, branch info).

Highlights:
- New `AgentHostGitService` (server-side) computes git state by shelling
  out to git; refreshed on session open and after each turn.
- New `SessionMetaChanged` action propagates `_meta` deltas without a full
  list refresh.
- Client-side `AgentHostSessionAdapter` retains `_project` /
  `_workingDirectory` / `_meta` so the workspace observable can be
  rebuilt when only `_meta` changes.
- `baseBranchProtected` is computed client-side from
  `git.branchProtection` config, so the workspace shape no longer carries
  it as a field on `ISessionRepository`.
- `update()` only overwrites `_meta` when the source actually provides
  one (SessionSummary feeds have no `_meta` field), so the polling
  refresh path no longer clobbers good state pushed via `SessionState`.

(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 25, 2026 17:50
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

This PR adds a per-session git-state “side channel” for agent-host sessions by computing git info in the agent-host process and publishing it via SessionState._meta, then adapting the Agents app/session providers to rebuild ISessionWorkspace when _meta changes so existing Changes UI can light up (branch/ahead-behind/uncommitted/GitHub remote).

Changes:

  • Introduces SessionState._meta + SessionMetaChanged action in the AHP protocol and reducers, plus typed helpers (readSessionGitState, withSessionGitState) for the reserved git meta slot.
  • Adds server-side git probing (AgentHostGitService.getSessionGitState) and hooks to refresh/publish git state on session open/restore and after each completed turn.
  • Updates agent-host session adapters/providers to retain project/workingDirectory/meta and rebuild the workspace on _meta updates; updates UI logic to read git state from workspace repositories (vs session summary metadata).
Show a summary per file
File Description
src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostChatContribution.test.ts Adds regression test ensuring list metadata only includes working directory (git state no longer on summary).
src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostSessionListController.ts Stops emitting empty metadata; only includes remote host + workingDirectoryPath when present.
src/vs/sessions/services/sessions/common/session.ts Extends ISessionRepository to carry git-related fields sourced from _meta.git.
src/vs/sessions/contrib/terminal/test/browser/sessionsTerminalContribution.test.ts Updates tests for ISessionRepository shape change (removes explicit baseBranchProtected: undefined).
src/vs/sessions/contrib/remoteAgentHost/test/browser/remoteAgentHostSessionsProvider.test.ts Stubs IConfigurationService required by provider changes.
src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHostSessionsProvider.ts Passes git state + branch protection patterns into workspace builder; injects configuration service.
src/vs/sessions/contrib/copilotChatSessions/browser/copilotChatSessionsProvider.ts Stops expecting baseBranchProtected in metadata-derived repository objects.
src/vs/sessions/contrib/chat/test/browser/sessionsConfigurationService.test.ts Updates test repository object to match optional baseBranchProtected.
src/vs/sessions/contrib/chat/test/browser/sessionWorkspacePicker.test.ts Updates mock provider repository object for new ISessionRepository optional fields.
src/vs/sessions/contrib/changes/browser/changesViewModel.ts Reads git state from workspace repositories for agent-host sessions; adjusts hasGitRepository derivation.
src/vs/sessions/contrib/agentHost/test/browser/localAgentHostSessionsProvider.test.ts Stubs IConfigurationService required by provider changes.
src/vs/sessions/contrib/agentHost/browser/localAgentHostSessionsProvider.ts Passes git state + branch protection patterns into workspace builder; injects configuration service.
src/vs/sessions/contrib/agentHost/browser/baseAgentHostSessionsProvider.ts Retains _meta and rebuilds workspace on SessionMetaChanged via session-state subscription.
src/vs/sessions/common/agentHostSessionWorkspace.ts Adds branch protection pattern helpers and maps _meta.git into ISessionRepository fields + workspace key.
src/vs/platform/agentHost/test/node/copilotGitProject.test.ts Updates test git service stub for new getSessionGitState API.
src/vs/platform/agentHost/test/node/copilotAgent.test.ts Updates test git service stub for new getSessionGitState API.
src/vs/platform/agentHost/test/node/agentSideEffects.test.ts Updates tests for new onTurnComplete callback requirement.
src/vs/platform/agentHost/test/node/agentService.test.ts Adds tests validating git state is attached to SessionState._meta.git when workingDirectory exists.
src/vs/platform/agentHost/test/node/agentHostGitService.test.ts Adds unit tests for git parsing helpers (status v2, remotes, default branch ref).
src/vs/platform/agentHost/test/node/agentHostGitService.integrationTest.ts Adds on-disk integration tests that spawn real git to validate computed session git state.
src/vs/platform/agentHost/node/agentSideEffects.ts Calls onTurnComplete after idle to trigger post-turn git refresh.
src/vs/platform/agentHost/node/agentService.ts Wires in git state refresh/publish on create/restore and post-turn; restores persisted _meta.
src/vs/platform/agentHost/node/agentHostStateManager.ts Adds setSessionMeta dispatching SessionMetaChanged to update SessionState._meta.
src/vs/platform/agentHost/node/agentHostGitService.ts Implements getSessionGitState by shelling out to git + adds parsing helpers.
src/vs/platform/agentHost/common/state/sessionState.ts Defines SessionMeta, ISessionGitState, reserved git key, and helper read/write functions.
src/vs/platform/agentHost/common/state/protocol/version/registry.ts Registers new actions as introduced in protocol v1.
src/vs/platform/agentHost/common/state/protocol/state.ts Adds SessionState._meta and SessionSummary.activity; updates some schema JSDoc.
src/vs/platform/agentHost/common/state/protocol/reducers.ts Handles SessionActivityChanged and SessionMetaChanged in reducer.
src/vs/platform/agentHost/common/state/protocol/actions.ts Adds SessionActivityChangedAction and SessionMetaChangedAction.
src/vs/platform/agentHost/common/state/protocol/action-origin.generated.ts Updates generated action unions and client-dispatchable map for new actions.
src/vs/platform/agentHost/common/state/protocol/.ahp-version Syncs vendored protocol version to 84e5779.
src/vs/platform/agentHost/common/agentService.ts Extends IAgentSessionMetadata with _meta?: SessionMeta.

Copilot's findings

Comments suppressed due to low confidence (2)

src/vs/platform/agentHost/node/agentService.ts:618

  • Same as above: this comment says git state attaches under summary._meta.git, but the implementation uses SessionState._meta via setSessionMeta. Please update to avoid misleading future readers.
		// Lazily compute git state for sessions with a working directory;
		// attaches under `summary._meta.git` once ready.
		this._attachGitState(session, meta.workingDirectory);

src/vs/platform/agentHost/node/agentService.ts:343

  • _attachGitState is fire-and-forget and can be triggered multiple times (session open + after each turn). Because results are applied asynchronously, a slower earlier probe can overwrite a newer git state snapshot and regress the UI. Consider tracking a per-session request counter / cancellation token and only applying the latest completed probe’s result.
	private _attachGitState(session: URI, workingDirectory: URI | undefined): void {
		if (!this._gitService || !workingDirectory) {
			return;
		}
		this._gitService.getSessionGitState(workingDirectory).then(
			gitState => {
				if (!gitState) {
					return;
				}
				const sessionKey = session.toString();
				const current = this._stateManager.getSessionState(sessionKey)?._meta;
				this._stateManager.setSessionMeta(sessionKey, withSessionGitState(current, gitState));
			},
			e => {
				this._logService.warn(`[AgentService] Failed to compute git state for ${session}`, e);
			},
		);
  • Files reviewed: 32/32 changed files
  • Comments generated: 4

Comment thread src/vs/platform/agentHost/common/agentService.ts
Comment thread src/vs/sessions/contrib/changes/browser/changesViewModel.ts Outdated
Comment thread src/vs/platform/agentHost/node/agentService.ts Outdated
- Doc updates: reference SessionState._meta (not SessionSummary._meta)
  in agent service interface and the setMeta delta path.
- changesViewModel.activeSessionHasGitRepositoryObs now derives the
  git-backed signal from surfaced git state on the workspace's first
  repository (uncommittedChanges/incomingChanges/outgoingChanges/
  upstreamBranchName) rather than from mere workspace presence, so we
  don't enable git-specific UI for non-git working directories.

(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
roblourens and others added 8 commits April 25, 2026 12:40
Plumb 'branchName' through:
- ISessionRepository (new optional field)
- buildAgentHostSessionWorkspace + agentHostSessionWorkspaceKey (gitFields)
- ChangesViewModel.activeSessionStateObs (fall back to workspace repo)
- ChangesViewPane.getTreeRootInfo: only render parens when branchName known

Also subscribe to activeSessionStateObs in the changes-tree autorun so the
root rebuilds once branchName arrives asynchronously.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously AgentService was constructed without a git service (the
optional _gitService parameter was never passed), so _attachGitState
always bailed with 'hasGitService=false' and no branch name was ever
computed. The fix creates AgentHostGitService before AgentService and
passes it as the fifth constructor argument.

Also removes debug logging added during investigation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The optional `_gitService?` parameter was the root cause of git
metadata never reaching the client: `agentHostMain.ts` and
`agentHostServerMain.ts` constructed AgentService without passing it,
and `_attachGitState` silently bailed at runtime. Making the dep
required forces all callers (now and in the future) to wire it
correctly at compile time.

Also adds a regression test for the `subscribe()` lazy-fire path,
which was the intended client-visible mechanism for surfacing branch
name on sessions that already exist in the state manager.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Branch name on non-worktree sessions wasn't a goal. Restores the
original guard so `(branch)` only appears when the session has a
worktree.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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

  • Files reviewed: 31/31 changed files
  • Comments generated: 3

Comment thread src/vs/sessions/contrib/changes/browser/changesViewModel.ts
Comment thread src/vs/sessions/contrib/changes/browser/changesView.ts
Comment thread src/vs/platform/agentHost/node/agentService.ts
- changesViewModel: fall back to workspaceRepository.baseBranchName so
  agent-host sessions get branch protection UI when only the workspace
  repo carries baseBranchName
- changesView: add comment explaining the intentional dependency read on
  activeSessionStateObs in the tree-update autorun
- agentService: dedupe _ skip setSessionMeta when theattachGitState
  newly computed git state equals the current _meta.git, avoiding action
  churn after every turn

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@roblourens roblourens marked this pull request as ready for review April 26, 2026 02:37
@roblourens roblourens enabled auto-merge (squash) April 26, 2026 02:37
@roblourens roblourens merged commit 1fa1b7a into main Apr 26, 2026
28 of 29 checks passed
@roblourens roblourens deleted the roblou/agents/agent-host-git-metadata branch April 26, 2026 04:19
@vs-code-engineering vs-code-engineering Bot added this to the 1.118.0 milestone Apr 26, 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.

3 participants