Skip to content

Add agent-host skill buttons to changes view#311815

Draft
roblourens wants to merge 28 commits intomainfrom
roblou/agents/agent-app-pull-request-skills-issue
Draft

Add agent-host skill buttons to changes view#311815
roblourens wants to merge 28 commits intomainfrom
roblou/agents/agent-app-pull-request-skills-issue

Conversation

@roblourens
Copy link
Copy Markdown
Member

@roblourens roblourens commented Apr 22, 2026

Adds skill buttons (Merge Changes, Create Pull Request, Create Draft Pull Request, Update Pull Request) for agent-host sessions in the Agents app changes view.

What this does

  • Contributes the skill buttons to ChatEditingSessionApplySubmenu so they appear in the same dropdown as the existing apply-to-parent-repo actions, gated on context keys (HasGitRepository, HasGitHubRemote, etc.)
  • Suppresses the Copilot extension's own commit/merge/PR buttons for agent-host sessions (via !sessions.isAgentHostSession when clause) to avoid duplicates
  • Adds ISessionGitState as a typed accessor over the protocol-level _meta bag, so clients can read git state (branch name, ahead/behind counts, PR-related affordances) without parsing raw unknown data

Protocol changes

  • Moves session git state from SessionSummary._meta to SessionState._meta (lazy, only computed when a session is opened) via the new SessionMetaChanged AHP action
  • Syncs vendored agent-host-protocol files to 84e5779: SessionMeta interface removed in favour of Record<string, unknown> directly; action field renamed from meta_meta; new SessionActivityChangedAction added (not yet consumed on the VS Code side)

Known issues / follow-up needed

  • Button gating: the when clauses depend on context keys derived from IAgentSession.metadata, but the agent-host list controller doesn't yet bridge state._meta.git into that metadata pipeline — so the buttons may not appear until that wiring is added
  • listSessions() overlay doesn't propagate _meta, which can cause git affordances to flicker off after a turn completes

(Written by Copilot)

roblourens and others added 2 commits April 21, 2026 18:21
Mirrors the Copilot CLI extension's commit/merge/PR buttons for
agent-host sessions in the Agents app. Buttons are contributed to the
ChatEditingSessionApplySubmenu so they render as a dropdown alongside
the existing apply-to-parent-repo actions.

Also adds a typed ISessionGitState accessor under the protocol-level
ISessionMeta bag so clients can read git state (branch, ahead/behind,
PR-related affordances) without parsing raw _meta.

(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…pp-pull-request-skills-issue

# Conflicts:
#	src/vs/sessions/contrib/agentHost/browser/localAgentHostSessionsProvider.ts
#	src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHostSessionsProvider.ts
Copilot AI review requested due to automatic review settings April 22, 2026 01:23
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 Agents-app (“sessions window”) equivalents of the Copilot CLI extension’s commit/merge/PR actions for agent-host sessions, and plumbs a typed git-state payload through the agent-host session metadata so the UI can drive correct affordances (branch, ahead/behind, PR gating).

Changes:

  • Introduces agent-host skill buttons contributed to ChatEditingSessionApplySubmenu, and styles them appropriately in the Changes view.
  • Adds protocol-level _meta (ISessionMeta) and a typed _meta.git (ISessionGitState) accessor path; overlays git state into session summaries on the agent-host side.
  • Updates workspace/session list metadata propagation and adds unit tests for customization resolution, git parsing/state, and menu/context-key wiring.
Show a summary per file
File Description
src/vs/workbench/contrib/chat/test/browser/agentSessions/resolveCustomizationRefs.test.ts New unit tests for resolving customization refs (plugin vs bundled files, built-ins).
src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostChatContribution.test.ts Stubs IPromptsService and tests propagation of git state into session item metadata.
src/vs/workbench/contrib/chat/browser/chatSessions/chatSessions.contribution.ts Exports resolvePromptSlashCommand for reuse by Sessions-window skill buttons.
src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostSessionListController.ts Carries _meta through and maps _meta.git into IChatSessionItem.metadata keys used by Changes view.
src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostChatContribution.ts Collects built-in skills via IPromptsService.findAgentSkills and factors resolveCustomizationRefs for testing.
src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHostSessionsProvider.ts Extends workspace builder signature to accept ISessionGitState.
src/vs/sessions/contrib/changes/browser/changesView.ts Applies button styling/badge behavior to agent-host skill actions.
src/vs/sessions/contrib/agentHost/test/browser/agentHostSkillButtons.test.ts New tests for context key binding and menu registrations for skill buttons.
src/vs/sessions/contrib/agentHost/browser/localAgentHostSessionsProvider.ts Extends workspace builder signature to accept ISessionGitState.
src/vs/sessions/contrib/agentHost/browser/localAgentHost.contribution.ts Ensures agent-host skill buttons are registered in Sessions window.
src/vs/sessions/contrib/agentHost/browser/baseAgentHostSessionsProvider.ts Threads readSessionGitState(metadata._meta) into workspace construction and adapter options.
src/vs/sessions/contrib/agentHost/browser/agentHostSkillButtons.ts New action/menu contributions that run built-in skills by sending /<skill> prompts via IChatService.
src/vs/sessions/common/agentHostSessionWorkspace.ts Includes base-branch info in workspace identity and stores base-branch fields on repository entries.
src/vs/platform/agentHost/test/node/copilotGitProject.test.ts Updates test git-service stub to satisfy new getSessionGitState API.
src/vs/platform/agentHost/test/node/copilotAgent.test.ts Updates test git-service stub to satisfy new getSessionGitState API.
src/vs/platform/agentHost/test/node/agentService.test.ts Adds tests verifying git state overlay into _meta.git during listSessions.
src/vs/platform/agentHost/test/node/agentHostGitService.test.ts Adds unit tests for git parsing helpers and on-disk tests for getSessionGitState (skipped if git missing).
src/vs/platform/agentHost/node/agentService.ts Overlays computed git state into _meta during listSessions; propagates _meta when restoring sessions.
src/vs/platform/agentHost/node/agentHostMain.ts Wires a single AgentHostGitService instance into AgentService and DI.
src/vs/platform/agentHost/node/agentHostGitService.ts Adds getSessionGitState with short TTL caching plus parsing helpers for status/remotes/default branch.
src/vs/platform/agentHost/common/state/sessionState.ts Adds _meta.git well-known key + ISessionGitState interface and read/write helpers.
src/vs/platform/agentHost/common/state/protocol/state.ts Introduces ISessionMeta and optional ISessionSummary._meta.
src/vs/platform/agentHost/common/agentService.ts Mirrors _meta?: ISessionMeta onto IAgentSessionMetadata.
src/vs/platform/agentHost/browser/remoteAgentHostProtocolClient.ts Propagates _meta from protocol session summaries into metadata objects.
extensions/copilot/package.json Suppresses Copilot CLI extension’s session buttons when sessions.isAgentHostSession is true.

Copilot's findings

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

Comment thread src/vs/platform/agentHost/common/state/sessionState.ts Outdated
Comment thread src/vs/platform/agentHost/node/agentHostGitService.ts Outdated
Comment thread src/vs/platform/agentHost/node/agentService.ts Outdated
Going through IChatService.sendRequest directly bypassed widget-owned
view  most importantly the tool confirmation rendering wired upstate
in IChatWidget._acceptInput. It also let us pass the wrong agentIdSilent
(the shared logical sessionType 'copilotcli' instead of the per-host
chat-session contribution type 'agent-host-copilotcli'), which routed
clicks to the EH copilotcli extension rather than the active local/remote
agent-host session.

Look up the chat widget by session resource and call acceptInput, which
handles slash-command parsing, locked-agent resolution, instructions, and
tool confirmation UI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 22, 2026

Base: 8f547df8 Current: 94c948a0

No screenshot changes.

roblourens and others added 6 commits April 21, 2026 19:08
…agent id

Removes the standalone Commit  it has no equivalent in the EHbutton
copilotcli extension's contributions to the apply submenu (which only
exposes commitAndSync, gated to workspace-isolation), so its presence
made Commit appear as the dropdown's primary action for agent-host
sessions where Merge wasn't applicable.

Reverts the dispatch back to IChatService.sendRequest with agentIdSilent
(matching the pattern in chatSessions.contribution.ts's
openSessionWithPrompt action). Going through the chat widget required a
mounted IChatWidget for the session, which isn't available when only the
Changes view is  clicks were silently bailing on the no-widgetopen
guard. The agent id correctness fix from the previous attempt is
preserved: pass session.resource.scheme (e.g. agent-host-copilotcli),
not the shared logical sessionType (copilotcli).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
From #311751

Co-authored-by: Copilot <copilot@github.com>
…request-skills-issue

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Without this capability, the chat input's slash command completion
provider returns null when an agent is locked (which agent-host sessions
always have), suppressing all '/' slash commands including bundled
built-in skills like /create-pr.

(Written by Copilot)

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: 24/24 changed files
  • Comments generated: 3

Comment thread src/vs/sessions/contrib/agentHost/browser/agentHostSkillButtons.ts
Comment thread src/vs/platform/agentHost/test/node/agentHostGitService.test.ts Outdated
roblourens and others added 10 commits April 22, 2026 10:45
Use the store returned by ensureNoDisposablesAreLeakedInTestSuite()
instead of a separate DisposableStore to avoid the afterEach leak check
flagging the store itself.

(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
These two registerWorkbenchContribution2 calls landed on origin/main in
f3d5d14 (#311954, 'agentHost: settings followups') after our last
merge from origin/main. Without them the Agents app never instantiates
AgentHostContribution, so authentication never runs and the local agent
host stays in the loading state forever.

(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mirrors the capability set on the chat session contribution in
1ce51eb. The chat input uses the contribution's capability for
slash-command completions, but the chat request parser
(ChatRequestParser.tryToParseSlashCommand) reads it off the agent
itself when an agent is forced via agentIdSilent. Without it, the
parser sees a usedAgent with no matching subcommand and bails before
producing a ChatRequestSlashPromptPart, so /merge / /create-pr render
as plain text instead of a styled slash-command  both for skillchip
buttons and for users typing the command directly.

(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…pp-pull-request-skills-issue

Conflicts were caused by upstream renaming protocol types to drop the I-
prefix (#311983). Resolutions:

- Adopt the new (no-I) names everywhere protocol types are referenced.
- Rename our newly-added 'ISessionMeta' -> 'SessionMeta' to match the
  same convention; preserve '_meta' / 'SessionMeta' / 'ISessionGitState'
  / 'readSessionGitState' / 'withSessionGitState' additions, plus the
  'resolveCustomizationRefs' helper extraction.
- In the local/remote agent host providers, merge upstream's 'description'
  computation into our 'buildWorkspace' callbacks (which still need to
  thread 'gitState' through to support the skill buttons).

Type-check passes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pure parser tests (parseGitStatusV2, parseHasGitHubRemote,
parseDefaultBranchRef, getBranchCompletions) stay in agentHostGitService.test.ts
and remain hermetic. The cases that initialise temp git repos and spawn real
git move into agentHostGitService.integrationTest.ts and are picked up by
scripts/test-integration.sh via the **/*.integrationTest.js glob.

Mirrors the git extension's split between unit-style parser tests in
git.test.ts and on-disk smoke tests in smoke.test.ts.

Also includes a leftover ICustomizationRef -> CustomizationRef rename in
resolveCustomizationRefs.test.ts that should have landed with the
origin/main merge.

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

MockAgent.listSessions() does not infer workingDirectory from
resolvedWorkingDirectory (that field is only consumed by
resolveSessionConfig). Without an explicit override the session metadata
has no workingDirectory, so AgentService.listSessions skips the git
overlay and the test asserted undefined !== { git: ... }.

Set agent.sessionMetadataOverrides = { workingDirectory } so the
listSessions code path actually receives a working directory and invokes
the mock git service.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the agent-host server-side git state probe from `listSessions`
(which ran for every session on every refresh) into `createSession` /
`restoreSession` (runs once when a session is opened).

The result is merged into `summary._meta.git` via a new
`AgentHostStateManager.setSessionMeta` method which marks the
summary dirty and lets the existing `SessionSummaryChanged`
notification fan it out to clients. `_flushSummaryNotifications` now
also propagates `_meta` deltas.

On the client, `AgentHostSessionAdapter` retains the project /
working-directory it was constructed with, exposes a `setMeta` method
that rebuilds the `workspace` observable when `_meta` changes, and
`_handleSessionSummaryChanged` invokes it. List rendering is
otherwise unchanged.

Tests: rewrote the two `agentService.test.ts` tests that previously
asserted overlay-in-listSessions behaviour to instead drive
`createSession` and assert that `_meta.git` lands on the summary.

(Written by Copilot)

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

SessionSummary is returned for every session in listSessions and is
meant to be cheap to compute. Git state (branch, ahead/behind, etc.) is
only consumed by the changesViewModel and the skill buttons, both of
which only run for opened sessions, so it belongs on the lazy per-URI
SessionState subscription rather than the eager summary.

Protocol additions (vendored, will be upstreamed separately):
- Add SessionMetaChanged action (server-only, full-replacement
  semantics matching SessionDiffsChanged) to the action enum,
  StateAction union, IS_CLIENT_DISPATCHABLE map, and version registry.
- Add _meta?: SessionMeta to SessionState.
- Remove _meta?: SessionMeta from SessionSummary.

Server side:
- AgentHostStateManager.setSessionMeta now dispatches a
  SessionMetaChanged action via dispatchServerAction so the change
  flows through the action envelope (and thus to all live subscribers)
  rather than mutating the summary.
- Drop _meta change-detection from _flushSummaryNotifications.
- AgentService._attachGitState reads state._meta instead of
  state.summary._meta.
- AgentService.listSessions drops the summary._meta overlay.
- AgentService.restoreSession dispatches SessionMetaChanged after
  restoreSession instead of seeding _meta on the summary literal.
- remoteAgentHostProtocolClient.listSessions stops forwarding s._meta.

Client side:
- BaseAgentHostSessionsProvider's state subscription handler now also
  syncs cached.setMeta(state._meta), so opening a session causes its
  git state to flow to the adapter via the action envelope.
- BaseAgentHostSessionsProvider.getSessionByResource triggers
  _ensureSessionStateSubscription so the wire subscription is open
  when the chat editor mounts. The subscription is reference-counted
  with the chat session handler's, so this is essentially free.
- BaseAgentHostSessionsProvider._handleSessionSummaryChanged drops the
  changes._meta branch (no longer flows through summary).
- AgentHostSessionListController._buildMetadata drops the git fields
  and the meta parameter; the list never read them anyway. The repo
  tag falls back to workingDirectoryPath.

Tests:
- agentService.test.ts: assert on state._meta (via stateManager) instead
  of summary._meta.
- agentHostChatContribution.test.ts: rewrite the list-controller git
  metadata test to assert that git fields are no longer surfaced in
  list metadata (now per-session state, not summary).
…pp-pull-request-skills-issue

# Conflicts:
#	extensions/copilot/package.json
#	src/vs/platform/agentHost/common/state/protocol/action-origin.generated.ts
#	src/vs/sessions/contrib/changes/browser/changesView.ts
Pulls in upstream changes:
- SessionMeta interface removed; `_meta` now typed as `Record<string, unknown>` directly
- SessionMetaChangedAction `meta` field renamed to `_meta`
- New SessionActivityChangedAction (not yet consumed)

Adapt VS Code side:
- Define a local `SessionMeta` type alias in sessionState.ts (kept for ergonomics in our git-state helpers)
- Update agentHostStateManager.setSessionMeta to dispatch with the renamed `_meta` field

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: 6

Comment thread src/vs/platform/agentHost/common/state/sessionState.ts
Comment thread src/vs/platform/agentHost/node/agentHostGitService.ts Outdated
Comment thread src/vs/sessions/contrib/agentHost/browser/agentHostSkillButtons.ts Outdated
Comment thread src/vs/sessions/contrib/agentHost/browser/baseAgentHostSessionsProvider.ts Outdated
Comment thread src/vs/sessions/common/agentHostSessionWorkspace.ts Outdated
roblourens and others added 9 commits April 24, 2026 10:15
…pp-pull-request-skills-issue

# Conflicts:
#	src/vs/platform/agentHost/node/agentHostStateManager.ts
…den validation, bound cache

- Add git state fields to ISessionRepository (hasGitHubRemote, upstreamBranchName,
  incomingChanges, outgoingChanges, uncommittedChanges)
- buildAgentHostSessionWorkspace: populate all ISessionGitState fields into the
  repository; update agentHostSessionWorkspaceKey to include them so downstream
  observables react when git state changes
- changesViewModel: fix activeSessionHasGitRepositoryObs to check workspace.repositories
  for agent-host sessions (which don't set metadata.repositoryPath); fall back to
  workspaceRepository for hasGitHubRemote, incomingChanges, outgoingChanges,
   this wires the buttons to actually appearuncommittedChanges
- agentHostSkillButtons: use localize2 / ILocalizedString so Action2.title.original
  is always the stable English string, not the locale-translated value
- readSessionGitState: reject arrays, validate each field's type individually so
  partial state still propagates; never trust raw cast
- agentHostGitService: add _pruneGitStateCache (TTL eviction + LRU cap at 256)
  called before every new insertion so the map stays bounded

  SessionMetaChanged / _applySessionMetaFromState / setMeta)
- agentHostSessionWorkspace: import ISessionGitState as import type

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the TTL cache from AgentHostGitService.getSessionGitState
_computeSessionGitState now runs unconditionally each time it's called,
keeping the implementation simple.

Add IAgentSideEffectsOptions.onTurnComplete callback, invoked from the
idle-event handler in _handleAgentProgress. This fires only for
top-level sessions (subagent events are short-circuited earlier), so we
get exactly one git probe per real turn.

AgentService wires onTurnComplete to _attachGitState using the session's
stored workingDirectory, so the toolbar buttons reflect post-turn
branch/remote/change state without a session reload.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Drop `baseBranchProtected` from `ISessionGitState` (it was never
populated by the agent host's git  it's a VS Code policy concept,probe
not git data). Instead, the agent-host providers now read VS Code's
`git.branchProtection` setting, match the base branch against those
glob patterns, and write the result into `ISessionRepository` when
building the workspace.

The view model continues to read `baseBranchProtected` from the
session metadata (Copilot Chat) or the workspace repository (agent
 uniform across providers, no policy logic in the view.host)

(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The git-state cache was removed; `getSessionGitState` no longer
returns the same promise reference across calls.

(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The provider constructors now require IConfigurationService for branch
protection pattern reads. Test instantiation services need to provide it.

(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…pp-pull-request-skills-issue

# Conflicts:
#	src/vs/sessions/contrib/remoteAgentHost/browser/remoteAgentHostSessionsProvider.ts
Agent-host worktree branches are typically created without an upstream
tracking ref, so 'git status -b --porcelain=v2' doesn't emit ahead/behind
counts. That meant outgoingChanges came back undefined for committed-but-
unpushed work, hiding the 'Create PR' button.

Fall back to 'git rev-list --count <baseBranch>..HEAD' to count commits
relative to the base branch, which matches what the user actually cares
about for PR-creation. Adds an integration test covering the no-upstream
case.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The local agent-host harness collects every built-in skill bundled under
'vs/sessions/skills/' and ships them as part of the active client's
customizations, so the toolbar buttons (/create-pr, /merge, /update-pr,
...) just work for any agent-host session. The remote harness was only
syncing the user's manually selected entries, so on a remote agent host
those buttons would invoke skills the agent doesn't know about.

Extract the built-in collector into a shared 'collectBuiltinSkillFiles'
helper and reuse the existing 'resolveCustomizationRefs' pipeline from
the remote contribution. Both harnesses now produce the same single
synthetic plugin ref containing the bundled skills (plus whatever the
user has selected).

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

2 participants