Skip to content

Render copilot skill invocations as a tool call#312557

Merged
roblourens merged 2 commits intomainfrom
roblou/agents/copilot-skill-tool-display
Apr 26, 2026
Merged

Render copilot skill invocations as a tool call#312557
roblourens merged 2 commits intomainfrom
roblou/agents/copilot-skill-tool-display

Conversation

@roblourens
Copy link
Copy Markdown
Member

The Copilot SDK now exposes a skill tool that the model uses to load SKILL.md files. Until now this surfaced in the agent host as the default tool UI, which doesn't fit. This PR replaces it with a proper "Reading skill" entry that links to the skill file.

(Written by Copilot)

Agent host (src/vs/platform/agentHost)

  • Hide the raw skill tool call by adding Skill to HIDDEN_TOOL_NAMES.
  • Synthesize a tool_start / tool_complete pair from the SDK's skill.invoked lifecycle event. The synth helper lives in copilotToolDisplay.ts and is called from both:
    • the live event path in copilotAgentSession.ts (_subscribeToEvents), and
    • the history-replay path in mapSessionEvents.ts,
      so reconnect/replay renders identically. The synthetic toolCallId is synth-skill-<eventId | path | name> for stability across replay.
  • Filter the synthetic user.message events the SDK sometimes injects with skill content. New isSyntheticUserMessage predicate keys off data.source (skill-injected messages have source: "skill-<name>"; real user messages either lack source or set it to "user").

Client side (stateToProgressAdapter.ts)

  • The link rewriter previously collapsed every rewritten markdown link to the canonical empty-text form [](newHref). It now preserves the original link text, so a skill named plan shows up as Reading [plan] instead of Reading [SKILL.md].
  • New isSkillFileUri check: when a rewritten link points at a SKILL.md basename, append ?vscodeLinkType=skill so the chat renderer's inline anchor widget shows the rich skill pill rather than a plain markdown anchor. Doing this client-side (rather than at the agent host) keeps the host VS-Code-agnostic and automatically upgrades older sessions and other providers that emit SKILL.md links.

Tests

  • New skill events suites in copilotToolDisplay.test.ts and mapSessionEvents.test.ts covering hidden tool, synth output (with-path and no-path), synthetic user message filtering, and stable toolCallId.
  • Updated stateToProgressAdapter.test.ts snapshots to expect preserved link text and the vscodeLinkType=skill tagging.

All 118 affected tests green; type-check clean.

The Copilot SDK now exposes a skill tool that the model uses to load
SKILL.md files. Until now this surfaced in the agent host as the default
tool UI, which doesn't fit. This change does three things:

- Hide the raw `skill` tool call (added to HIDDEN_TOOL_NAMES).
- Synthesize a `tool_start`/`tool_complete` pair from the SDK's
  `skill.invoked` lifecycle event so we can show 'Reading [name]'
  with a link to the skill file. Wired in both the live event path
  and the history-replay path so reconnect renders identically.
- Filter out the synthetic `user.message` events the SDK sometimes
  injects with skill content (data.source !== 'user').

Client side, the chat adapter now tags markdown links pointing at a
SKILL.md file with `?vscodeLinkType=skill` so they render as the
inline skill pill instead of a plain markdown anchor. Doing this on
the client (rather than at the agent host) keeps the agent host
host-agnostic and also upgrades older sessions and other providers
that emit SKILL.md links.

The link rewriter also now preserves the original link text rather
than always collapsing to `[](newHref)`, so a skill named 'plan'
shows up as 'Reading [plan]' rather than 'Reading [SKILL.md]'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 25, 2026 20:56
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 updates the Copilot agent-host and client rendering pipeline to treat Copilot SDK “skill” usage as a first-class tool-style progress entry (“Reading skill …”), including clickable links to SKILL.md, and improves markdown link rewriting so original link text is preserved and skill links are tagged for richer rendering.

Changes:

  • Hide raw skill tool calls and synthesize tool_start/tool_complete events from skill.invoked (live + replay).
  • Filter SDK-injected user.message events (e.g. skill content injection) using a new source predicate.
  • Preserve markdown link text during rewrite and append vscodeLinkType=skill for SKILL.md links; update tests accordingly.
Show a summary per file
File Description
src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/stateToProgressAdapter.ts Preserves rewritten link labels and tags SKILL.md links with vscodeLinkType=skill.
src/vs/workbench/contrib/chat/test/browser/agentSessions/stateToProgressAdapter.test.ts Updates expectations for preserved link text in rewritten markdown.
src/vs/platform/agentHost/node/copilot/copilotToolDisplay.ts Adds hidden skill tool and synthesizes tool events for skill.invoked.
src/vs/platform/agentHost/node/copilot/mapSessionEvents.ts Filters synthetic user messages and maps skill.invoked into synthesized tool events during replay.
src/vs/platform/agentHost/node/copilot/copilotAgentSession.ts Emits synthesized skill tool events on the live event stream.
src/vs/platform/agentHost/test/node/copilotToolDisplay.test.ts Adds unit coverage for hidden tool + synthesized skill tool event output.
src/vs/platform/agentHost/test/node/mapSessionEvents.test.ts Adds replay-path coverage for skill synthesis and synthetic user message filtering.

Copilot's findings

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

Comment thread src/vs/platform/agentHost/node/copilot/copilotToolDisplay.ts Outdated
Comment thread src/vs/platform/agentHost/node/copilot/copilotToolDisplay.ts
- Add escapeMarkdownLinkLabel helper in htmlContent.ts: only escapes
  '\' and ']' so link labels rendered without re-parsing markdown
  (e.g. the chat skill pill) don't show literal backslashes for safe
  characters like '-' or '.'.
- Use it in synthesizeSkillToolEvents and stateToProgressAdapter's
  rewriteLinkTokenRaw instead of the over-eager escapeMarkdownSyntaxTokens.
- Hash the path/name fallback in getSkillSyntheticToolCallId so the
  synthesized toolCallId never contains '/' (which breaks
  ChatResponseResource.createUri paths).
- Update copilotToolDisplay/mapSessionEvents test snapshots to match
  the actual emitted strings ('Reading skill [plan](...)' /
  'Read skill [plan](...)') and the new hash-based fallback id.
- Add htmlContent unit tests for escapeMarkdownLinkLabel.

(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@roblourens roblourens marked this pull request as ready for review April 25, 2026 21:39
@roblourens roblourens enabled auto-merge (squash) April 25, 2026 21:39
@roblourens roblourens merged commit 7ac607f into main Apr 26, 2026
26 checks passed
@roblourens roblourens deleted the roblou/agents/copilot-skill-tool-display branch April 26, 2026 01:46
@vs-code-engineering vs-code-engineering Bot added this to the 1.118.0 milestone Apr 26, 2026
roblourens added a commit that referenced this pull request Apr 26, 2026
* Restore empty link text for non-skill agent-host links

PR #312557 changed all agent-host link rewriting to preserve the
original markdown label, which made every read-tool link render as a
plain blue markdown link instead of the rich inline anchor / file
widget. Only skill links need a non-empty label (so the skill pill can
show the skill name); restore the empty-label behavior for everything
else.

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

* Address Copilot review: preserve image alt text, add skill/image tests

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

---------

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.

3 participants