Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a35c2d3
feat: add support for skills in agent settings and UI preferences
ethanyhou Apr 27, 2026
a727518
test: enhance skill support with new actions and UI preferences test
ethanyhou Apr 28, 2026
68c427b
refactor: streamline ChatPreferencesPage layout
ethanyhou Apr 29, 2026
cf9e81c
Adjusted menu context.
ethanyhou Apr 29, 2026
99f62bb
Adjusted menu context.
ethanyhou Apr 29, 2026
00c187c
Merge branch 'ethan/support-skill' of https://github.com/microsoft/co…
ethanyhou Apr 29, 2026
92a9af8
Address comments.
ethanyhou Apr 29, 2026
028b0b3
refactor: optimize initialization of command, template, and agent lists
ethanyhou Apr 29, 2026
7ba48f2
Address comments.
ethanyhou May 6, 2026
6cdb44e
Removed probe tests.
ethanyhou May 6, 2026
eb60cc2
Updated readme file to include skill capability.
ethanyhou May 6, 2026
30f5b41
fix: reorder import statements for consistency
ethanyhou May 6, 2026
7311115
Address comments.
ethanyhou May 6, 2026
43a20ab
Add TODO comments.
ethanyhou May 6, 2026
ae95231
fix: format REFRESH_JOB_FAMILY string and update TODO comment for cla…
ethanyhou May 6, 2026
0c1088f
Address comments.
ethanyhou May 6, 2026
2950c2a
refactor: move isSkillsEnabled logic to PreferencesUtils and update u…
ethanyhou May 6, 2026
4cf5c68
Fixed tests.
ethanyhou May 7, 2026
888c939
Fixed tests.
ethanyhou May 7, 2026
469c77d
Address comments.
ethanyhou May 7, 2026
802ef3a
refactor: remove event handling for ENABLE_SKILLS property and rely o…
ethanyhou May 8, 2026
28b2fd2
Merge branch 'main' into ethan/support-skill
ethanyhou May 11, 2026
f9b1f1b
cls: bump cls version to 1.484.0
ethanyhou May 11, 2026
065f185
Merge branch 'main' into ethan/support-skill
ethanyhou May 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/skills/ui-action/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,4 +296,4 @@ action is usable from every probe.
### Keep one probe focused

Each JSON script represents one test case. Split unrelated behaviours into
separate probes so a single `FAILED-step…` screenshot tells you what broke.
separate probes so a single `FAILED-step…` screenshot tells you what broke.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ MCP support enables integrating external tools and services into Copilot workflo
- **Custom Agents** allow users to create personalized agents with specific instructions and behaviors.
- **Isolated Subagents** can be spawned by the main agent to handle specific tasks or contexts independently.
- **Plan Agent** can generate multi-step plans to accomplish complex tasks, breaking them down into manageable actions.
- **Skills** are reusable, specialized AI assistant templates that enrich chat context in Agent Mode. Skills are defined as `SKILL.md` files and can be scoped to a workspace or shared globally.

- Creating Skills

Place a `SKILL.md` file in any of these directories:

- **Project-scoped:** `.github/skills/<skill-name>/`, `.claude/skills/<skill-name>/`, `.agents/skills/<skill-name>/`
- **User-scoped (global):** `~/.copilot/skills/<skill-name>/`, `~/.claude/skills/<skill-name>/`, `~/.agents/skills/<skill-name>/`

Each `SKILL.md` file can include YAML front matter with metadata (name, description) followed by Markdown content that provides domain knowledge, workflows, or instructions for the AI assistant.

Skills are automatically discovered and available in Agent Mode. You can enable or disable skills in **Window → Preferences → Copilot → Chat → Enable Skills**.

For other available features in Eclipse, see the [Copilot feature matrix](https://docs.github.com/en/copilot/reference/copilot-feature-matrix?tool=eclipse).

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions com.microsoft.copilot.eclipse.core/copilot-agent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
"postinstall": "node copy-binaries.js"
},
"dependencies": {
"@github/copilot-language-server": "1.482.0",
"@github/copilot-language-server-win32-x64": "1.482.0",
"@github/copilot-language-server-darwin-x64": "1.482.0",
"@github/copilot-language-server-darwin-arm64": "1.482.0",
"@github/copilot-language-server-linux-x64": "1.482.0",
"@github/copilot-language-server-linux-arm64": "1.482.0"
"@github/copilot-language-server": "1.484.0",
"@github/copilot-language-server-win32-x64": "1.484.0",
"@github/copilot-language-server-darwin-x64": "1.484.0",
"@github/copilot-language-server-darwin-arm64": "1.484.0",
"@github/copilot-language-server-linux-x64": "1.484.0",
"@github/copilot-language-server-linux-arm64": "1.484.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ private Constants() {
public static final String WORKSPACE_CONTEXT_ENABLED = "workspaceContextEnabled";
public static final String SUB_AGENT_ENABLED = "subAgentEnabled";
public static final String AGENT_MAX_REQUESTS = "agentMaxRequests";
public static final String ENABLE_SKILLS = "enableSkills";
public static final String TRANSCRIPT_SUBDIR = ".copilot/eclipse";
public static final String MCP = "mcp";
public static final String MCP_REGISTRY_URL = "mcpRegistryUrl";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,10 @@ public class CopilotEventConstants {
* Event when a rate limit warning is received from the language server.
*/
public static final String TOPIC_RATE_LIMIT_WARNING = TOPIC_CHAT + "RATE_LIMIT_WARNING";

/**
* Event when custom prompts, skills, agents, or instructions change on the language server. Clients should re-fetch
* conversation templates on receipt.
*/
public static final String TOPIC_CHAT_DID_CHANGE_CUSTOMIZATION_FILES = TOPIC_CHAT + "DID_CHANGE_CUSTOMIZATION_FILES";
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,11 @@ public CompletableFuture<Object[]> getConversationContext(ConversationContextPar
public CompletableFuture<Object> invokeClientTool(InvokeClientToolParams params) {
return CompletableFuture.supplyAsync(() -> {
try {
CompletableFuture<LanguageModelToolResult[]> toolFuture =
CopilotCore.getPlugin().getChatEventsManager().invokeAgentTool(params);
CompletableFuture<LanguageModelToolResult[]> toolFuture = CopilotCore.getPlugin().getChatEventsManager()
.invokeAgentTool(params);
if (toolFuture == null) {
CopilotCore.LOGGER.error(
new IllegalStateException("invokeAgentTool returned null for tool: " + params.getName()));
CopilotCore.LOGGER
.error(new IllegalStateException("invokeAgentTool returned null for tool: " + params.getName()));
LanguageModelToolResult errorResult = new LanguageModelToolResult();
errorResult.addContent("Failed to invoke the tool: tool invocation returned null");
errorResult.setStatus(ToolInvocationStatus.error);
Expand Down Expand Up @@ -182,6 +182,8 @@ public CompletableFuture<Object[]> confirmClientTool(InvokeClientToolConfirmatio
});
}

// TODO: Should remove workspace-root folder as the projects are not directly under it in Eclipse, and can cause
// confusion in CLS.
@Override
public CompletableFuture<List<WorkspaceFolder>> workspaceFolders() {
// Ideally, we should return each IProject as a workspace folder, but given that when
Expand Down Expand Up @@ -259,9 +261,30 @@ public void onRateLimitWarning(RateLimitWarningParams params) {
}

/**
* Handles the Dynamic OAuth request for MCP.
* Shows a dialog with multiple input fields and returns the user's input values.
* Returns null if the user cancels the request.
* Notify when custom skills change (global or workspace). Signal-only; clients re-fetch templates.
*/
@JsonNotification("copilot/customSkill/didChange")
public void onDidChangeCustomSkill(Object params) {
notifyCustomizationFilesChanged();
}

/**
* Notify when custom prompts change (global or workspace). Signal-only; clients re-fetch templates.
*/
@JsonNotification("copilot/customPrompt/didChange")
public void onDidChangeCustomPrompt(Object params) {
notifyCustomizationFilesChanged();
}

private void notifyCustomizationFilesChanged() {
if (eventBroker != null) {
eventBroker.post(CopilotEventConstants.TOPIC_CHAT_DID_CHANGE_CUSTOMIZATION_FILES, null);
}
}

/**
* Handles the Dynamic OAuth request for MCP. Shows a dialog with multiple input fields and returns the user's input
* values. Returns null if the user cancels the request.
*/
@JsonRequest("copilot/dynamicOAuth")
public CompletableFuture<Map<String, String>> mcpOauth(McpOauthRequest request) {
Expand Down Expand Up @@ -307,13 +330,11 @@ public void onDidChangePolicy(DidChangePolicyParams params) {
}
if (flags.isSubAgentPolicyEnabled() != params.isSubAgentEnabled()) {
flags.setSubAgentPolicyEnabled(params.isSubAgentEnabled());
eventBroker.post(CopilotEventConstants.TOPIC_DID_CHANGE_SUB_AGENT_POLICY,
params.isSubAgentEnabled());
eventBroker.post(CopilotEventConstants.TOPIC_DID_CHANGE_SUB_AGENT_POLICY, params.isSubAgentEnabled());
}
if (flags.isCustomAgentPolicyEnabled() != params.isCustomAgentEnabled()) {
flags.setCustomAgentPolicyEnabled(params.isCustomAgentEnabled());
eventBroker.post(CopilotEventConstants.TOPIC_DID_CHANGE_CUSTOM_AGENT_POLICY,
params.isCustomAgentEnabled());
eventBroker.post(CopilotEventConstants.TOPIC_DID_CHANGE_CUSTOM_AGENT_POLICY, params.isCustomAgentEnabled());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationMode;
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationModesParams;
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationTemplate;
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationTemplatesParams;
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationTurnParams;
import com.microsoft.copilot.eclipse.core.lsp.protocol.CopilotModel;
import com.microsoft.copilot.eclipse.core.lsp.protocol.CopilotStatusResult;
Expand Down Expand Up @@ -140,9 +141,11 @@ public interface CopilotLanguageServer extends LanguageServer {

/**
* List conversation templates.
*
* @param params includes workspace folders for discovering workspace-specific prompt files and skills
*/
@JsonRequest("conversation/templates")
CompletableFuture<ConversationTemplate[]> listTemplates(NullParams param);
CompletableFuture<ConversationTemplate[]> listTemplates(ConversationTemplatesParams params);

/**
* List conversation modes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.lsp4j.ProgressParams;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.WorkspaceFolder;
import org.eclipse.lsp4j.jsonrpc.Endpoint;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.eclipse.lsp4j.services.LanguageServer;
Expand All @@ -46,6 +47,7 @@
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationMode;
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationModesParams;
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationTemplate;
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationTemplatesParams;
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationTurnParams;
import com.microsoft.copilot.eclipse.core.lsp.protocol.CopilotModel;
import com.microsoft.copilot.eclipse.core.lsp.protocol.CopilotStatusResult;
Expand Down Expand Up @@ -391,10 +393,12 @@ public CompletableFuture<ChatTurnResult> addConversationTurn(String workDoneToke

/**
* List the conversation templates.
*
* @param workspaceFolders workspace folders for discovering workspace-specific prompt files and skills
*/
public CompletableFuture<ConversationTemplate[]> listConversationTemplates() {
public CompletableFuture<ConversationTemplate[]> listConversationTemplates(List<WorkspaceFolder> workspaceFolders) {
Function<LanguageServer, CompletableFuture<ConversationTemplate[]>> fn = server -> {
return ((CopilotLanguageServer) server).listTemplates(new NullParams());
Comment thread
ethanyhou marked this conversation as resolved.
return ((CopilotLanguageServer) server).listTemplates(new ConversationTemplatesParams(workspaceFolders));
};
return this.languageServerWrapper.execute(fn);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,78 +4,14 @@
package com.microsoft.copilot.eclipse.core.lsp.protocol;

import java.util.List;
import java.util.Objects;

import org.apache.commons.lang3.builder.ToStringBuilder;

/**
* Get the templates.
* Represents a conversation template returned by the language server.
*/
public class ConversationTemplate {


private String id;
private String description;
private String shortDescription;
private List<String> scopes;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public String getShortDescription() {
return shortDescription;
}

public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}

public List<String> getScopes() {
return scopes;
}

public void setScopes(List<String> scopes) {
this.scopes = scopes;
}

@Override
public int hashCode() {
return Objects.hash(id, description, shortDescription, scopes);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
ConversationTemplate that = (ConversationTemplate) obj;
return Objects.equals(id, that.id) && Objects.equals(description, that.description)
&& Objects.equals(shortDescription, that.shortDescription) && Objects.equals(scopes, that.scopes);
}

@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("id", id);
builder.append("description", description);
builder.append("shortDescription", shortDescription);
builder.append("scopes", scopes);
return builder.toString();
}
public record ConversationTemplate(
String id,
String description,
String shortDescription,
List<String> scopes,
TemplateSource source) {
}
Loading
Loading