diff --git a/CONTEXT.md b/CONTEXT.md
new file mode 100644
index 00000000..78e6cee3
--- /dev/null
+++ b/CONTEXT.md
@@ -0,0 +1,29 @@
+# Context & Glossary
+
+This file is a glossary of the ubiquitous language used in this codebase. It is
+intentionally free of implementation detail — it defines *what words mean*, not
+*how things are built*.
+
+## Terms
+
+### Sub-agent
+A delegated agent that the main agent spawns to carry out a scoped sub-task on
+its behalf. The main agent invokes it through the `run_subagent` tool and
+receives the sub-agent's result back as part of its own turn.
+
+### Sub-agent policy
+Organization-level governance that decides whether sub-agents are permitted for
+a user. It is authoritative and is **enforced by the language server**, not by
+the editor client: when the policy forbids sub-agents, the server refuses to
+offer the `run_subagent` tool regardless of what the client advertises.
+
+### Capability
+A feature the editor client declares support for when it initializes its
+connection to the language server. A capability is an *offer of support*, not a
+*grant of permission* — the server may still withhold the corresponding feature
+(for example, because the sub-agent policy forbids it).
+
+### Client preview feature
+A gate that exposes in-development features to a subset of users. It is distinct
+from the sub-agent policy: after this change, the availability of sub-agents no
+longer depends on the client preview feature.
diff --git a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/Constants.java b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/Constants.java
index 176bc245..101fa319 100644
--- a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/Constants.java
+++ b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/Constants.java
@@ -26,7 +26,6 @@ private Constants() {
public static final String PROXY_KERBEROS_SP = "proxyKerberosSp";
public static final String GITHUB_ENTERPRISE = "githubEnterprise";
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";
diff --git a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/FeatureFlags.java b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/FeatureFlags.java
index f54e0bfa..e3414736 100644
--- a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/FeatureFlags.java
+++ b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/FeatureFlags.java
@@ -5,7 +5,6 @@
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
-import org.osgi.service.prefs.BackingStoreException;
/**
* Class to manage feature flags for the Copilot plugin. This class allows enabling or disabling features.
@@ -21,8 +20,6 @@ public class FeatureFlags {
private boolean mcpContributionPointEnabled = false;
- private boolean subAgentPolicyEnabled = true;
-
private boolean customAgentPolicyEnabled = true;
private boolean autoApprovalTokenEnabled = true;
@@ -61,25 +58,6 @@ public void setMcpContributionPointEnabled(boolean mcpContributionPointEnabled)
this.mcpContributionPointEnabled = mcpContributionPointEnabled;
}
- public boolean isSubAgentPolicyEnabled() {
- return subAgentPolicyEnabled;
- }
-
- /**
- * Sets whether the sub-agent policy is enabled.
- * When the policy is disabled, it also disables the user preference for sub-agent.
- *
- * @param subAgentPolicyEnabled true to enable the sub-agent policy, false to disable it
- */
- public void setSubAgentPolicyEnabled(boolean subAgentPolicyEnabled) {
- this.subAgentPolicyEnabled = subAgentPolicyEnabled;
-
- // When policy disables subagent, also disable the user preference
- if (!subAgentPolicyEnabled) {
- disableSubAgentPreference();
- }
- }
-
public boolean isCustomAgentPolicyEnabled() {
return customAgentPolicyEnabled;
}
@@ -113,17 +91,11 @@ public boolean isClientPreviewFeatureEnabled() {
/**
* Sets whether the client preview feature is enabled.
- * When the feature is disabled, it also disables the user preference for sub-agent.
*
* @param clientPreviewFeatureEnabled true to enable the client preview feature, false to disable it
*/
public void setClientPreviewFeatureEnabled(boolean clientPreviewFeatureEnabled) {
this.clientPreviewFeatureEnabled = clientPreviewFeatureEnabled;
-
- // When client preview feature is disabled, also disable the user preference for subagent
- if (!clientPreviewFeatureEnabled) {
- disableSubAgentPreference();
- }
}
/**
@@ -143,46 +115,6 @@ public static boolean isWorkspaceContextEnabled() {
return false;
}
- /**
- * Disables the user preference for sub-agent.
- * This method accesses the UI plugin's preference store to set the sub-agent preference to false.
- *
- *
Note: The sub-agent preference is used to initialize capabilities which happens before policies
- * are sent to us. Therefore, we need to flush the preference immediately when policy changes occur
- * to ensure the next capability initialization reflects the updated policy state.
- */
- private void disableSubAgentPreference() {
- // The preference is stored in the UI plugin's preference store, which uses InstanceScope internally
- IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode("com.microsoft.copilot.eclipse.ui");
- if (prefs != null) {
- // Only update and flush if the current setting is true
- boolean currentValue = prefs.getBoolean(Constants.SUB_AGENT_ENABLED, false);
- if (currentValue) {
- prefs.putBoolean(Constants.SUB_AGENT_ENABLED, false);
- try {
- prefs.flush();
- } catch (BackingStoreException e) {
- CopilotCore.LOGGER.error("Failed to save subagent preference when disabled by policy", e);
- }
- }
- }
- }
-
- /**
- * Checks if the sub-agent is enabled.
- * Sub-agent is enabled only if both the user preference is enabled AND the organization policy allows it.
- *
- * @return true if the sub-agent is enabled, false otherwise.
- */
- public static boolean isSubAgentEnabled() {
- IEclipsePreferences uiPrefs = InstanceScope.INSTANCE.getNode("com.microsoft.copilot.eclipse.ui");
- if (uiPrefs != null) {
- return uiPrefs.getBoolean(Constants.SUB_AGENT_ENABLED, false);
- }
-
- return false;
- }
-
/**
* Checks if the custom agent is enabled.
* Custom agent is enabled only if the organization policy allows it.
diff --git a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/events/CopilotEventConstants.java b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/events/CopilotEventConstants.java
index 1a2d3c9e..8b5b6fa3 100644
--- a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/events/CopilotEventConstants.java
+++ b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/events/CopilotEventConstants.java
@@ -86,11 +86,6 @@ public class CopilotEventConstants {
public static final String TOPIC_DID_CHANGE_MCP_CONTRIBUTION_POINT_POLICY = TOPIC_POLICY
+ "MCP_CONTRIBUTION_POINT_ENABLED";
- /**
- * Event when the sub-agent policy flag is updated.
- */
- public static final String TOPIC_DID_CHANGE_SUB_AGENT_POLICY = TOPIC_POLICY + "SUB_AGENT_ENABLED";
-
/**
* Event when the custom agent policy flag is updated.
*/
diff --git a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/CopilotLanguageClient.java b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/CopilotLanguageClient.java
index cf0e81ad..e7008691 100644
--- a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/CopilotLanguageClient.java
+++ b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/CopilotLanguageClient.java
@@ -351,10 +351,6 @@ public void onDidChangePolicy(DidChangePolicyParams params) {
eventBroker.post(CopilotEventConstants.TOPIC_DID_CHANGE_MCP_CONTRIBUTION_POINT_POLICY,
params.isMcpContributionPointEnabled());
}
- if (flags.isSubAgentPolicyEnabled() != params.isSubAgentEnabled()) {
- flags.setSubAgentPolicyEnabled(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());
diff --git a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/LsStreamConnectionProvider.java b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/LsStreamConnectionProvider.java
index 6f637137..4c775f84 100644
--- a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/LsStreamConnectionProvider.java
+++ b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/LsStreamConnectionProvider.java
@@ -55,7 +55,7 @@ public Object getInitializationOptions(@Nullable URI rootUri) {
NameAndVersion editorPluginInfo = new NameAndVersion(EDITOR_PLUGIN_NAME, bundleVersion);
List supportedUriSchemes = PlatformUtils.getSupportedUriSchemes();
CopilotCapabilities capabilities = new CopilotCapabilities(false, FeatureFlags.isWorkspaceContextEnabled(),
- FeatureFlags.isSubAgentEnabled(), supportedUriSchemes);
+ true /*isSubAgentEnabled*/, supportedUriSchemes);
return new InitializationOptions(editorInfo, editorPluginInfo, capabilities);
}
diff --git a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/policy/DidChangePolicyParams.java b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/policy/DidChangePolicyParams.java
index 3d21772a..1f194a50 100644
--- a/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/policy/DidChangePolicyParams.java
+++ b/com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/policy/DidChangePolicyParams.java
@@ -16,9 +16,6 @@ public class DidChangePolicyParams {
@SerializedName("mcp.contributionPoint.enabled")
private boolean mcpContributionPointEnabled;
- @SerializedName("subAgent.enabled")
- private boolean subAgentEnabled = true;
-
@SerializedName("customAgent.enabled")
private boolean customAgentEnabled = true;
@@ -33,14 +30,6 @@ public void setMcpContributionPointEnabled(boolean mcpContributionPointEnabled)
this.mcpContributionPointEnabled = mcpContributionPointEnabled;
}
- public boolean isSubAgentEnabled() {
- return subAgentEnabled;
- }
-
- public void setSubAgentEnabled(boolean subAgentEnabled) {
- this.subAgentEnabled = subAgentEnabled;
- }
-
public boolean isCustomAgentEnabled() {
return customAgentEnabled;
}
@@ -59,7 +48,7 @@ public void setAutoApprovalPolicyEnabled(boolean autoApprovalPolicyEnabled) {
@Override
public int hashCode() {
- return Objects.hash(mcpContributionPointEnabled, subAgentEnabled, customAgentEnabled,
+ return Objects.hash(mcpContributionPointEnabled, customAgentEnabled,
autoApprovalPolicyEnabled);
}
@@ -76,7 +65,6 @@ public boolean equals(Object obj) {
}
DidChangePolicyParams other = (DidChangePolicyParams) obj;
return mcpContributionPointEnabled == other.mcpContributionPointEnabled
- && subAgentEnabled == other.subAgentEnabled
&& customAgentEnabled == other.customAgentEnabled
&& autoApprovalPolicyEnabled == other.autoApprovalPolicyEnabled;
}
@@ -85,7 +73,6 @@ public boolean equals(Object obj) {
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("mcpContributionPointEnabled", mcpContributionPointEnabled);
- builder.append("subAgentEnabled", subAgentEnabled);
builder.append("customAgentEnabled", customAgentEnabled);
builder.append("autoApprovalPolicyEnabled", autoApprovalPolicyEnabled);
return builder.toString();
diff --git a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/preferences/ChatPreferencesPage.java b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/preferences/ChatPreferencesPage.java
index 11a791ef..0b0ce6ff 100644
--- a/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/preferences/ChatPreferencesPage.java
+++ b/com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/preferences/ChatPreferencesPage.java
@@ -3,12 +3,6 @@
package com.microsoft.copilot.eclipse.ui.preferences;
-import java.lang.reflect.Type;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
@@ -60,29 +54,6 @@ public void createFieldEditors() {
addNote(parent, Messages.preferences_page_watched_files_note_content);
addSeparator(parent);
- // Add sub-agent toggle
- Composite subAgentComposite = createSectionComposite(parent, gdf);
- boolean policyAllowsSubAgent = isPolicyAllowsSubAgent();
- if (!policyAllowsSubAgent) {
- Composite disabledComposite = new Composite(subAgentComposite, SWT.NONE);
- GridLayout disabledCompositeLayout = new GridLayout(1, false);
- disabledCompositeLayout.marginWidth = 0;
- disabledCompositeLayout.marginHeight = 0;
- disabledComposite.setLayout(disabledCompositeLayout);
- disabledComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
- WrappableIconLink.createWithCustomizedImage(disabledComposite, "/icons/information.png",
- Messages.setting_managed_by_organization);
- }
-
- BooleanFieldEditor subAgentField = new BooleanFieldEditor(Constants.SUB_AGENT_ENABLED,
- Messages.preferences_page_sub_agent, SWT.WRAP, subAgentComposite);
- subAgentField.setEnabled(policyAllowsSubAgent, subAgentComposite);
- applyFieldWidthHint(subAgentField, subAgentComposite);
- addField(subAgentField);
-
- addNote(parent, Messages.preferences_page_sub_agent_note_content);
- addSeparator(parent);
-
if (isClientPreviewFeatureEnabled()) {
// Add Enable Skills toggle
Composite skillsComposite = createSectionComposite(parent, gdf);
@@ -111,41 +82,15 @@ public void createFieldEditors() {
@Override
public void init(IWorkbench workbench) {
setPreferenceStore(CopilotUi.getPlugin().getPreferenceStore());
-
- // Ensure run_subagent tool configuration is consistent with sub-agent preference
- // Only check if sub-agent is policy-enabled
- if (isPolicyAllowsSubAgent()) {
- boolean subAgentEnabled = getPreferenceStore().getBoolean(Constants.SUB_AGENT_ENABLED);
- updateSubAgentToolConfiguration(subAgentEnabled);
- }
}
@Override
public boolean performOk() {
final boolean oldWorkspaceContextValue = getPreferenceStore().getBoolean(Constants.WORKSPACE_CONTEXT_ENABLED);
- // Check if sub-agent is policy-enabled before handling sub-agent preferences
- boolean policyAllowsSubAgent = isPolicyAllowsSubAgent();
-
- boolean oldSubAgentValue = false;
- if (policyAllowsSubAgent) {
- oldSubAgentValue = getPreferenceStore().getBoolean(Constants.SUB_AGENT_ENABLED);
- }
-
final boolean result = super.performOk();
boolean newWorkspaceContextValue = getPreferenceStore().getBoolean(Constants.WORKSPACE_CONTEXT_ENABLED);
- boolean newSubAgentValue = false;
- if (policyAllowsSubAgent) {
- newSubAgentValue = getPreferenceStore().getBoolean(Constants.SUB_AGENT_ENABLED);
- }
-
- // Handle sub-agent preference change
- boolean isSubAgentChanged = policyAllowsSubAgent && (oldSubAgentValue ^ newSubAgentValue);
- if (isSubAgentChanged) {
- updateSubAgentToolConfiguration(newSubAgentValue);
- }
-
boolean isWorkspaceContextChanged = oldWorkspaceContextValue ^ newWorkspaceContextValue;
if (isWorkspaceContextChanged) {
try {
@@ -153,9 +98,7 @@ public boolean performOk() {
} catch (BackingStoreException e) {
CopilotCore.LOGGER.error("Failed to save preference 'Enable workspace context'", e);
}
- }
- if (isSubAgentChanged || isWorkspaceContextChanged) {
boolean restart = MessageDialog.openQuestion(getShell(), Messages.preferences_page_restart_required,
Messages.preferences_page_restart_question);
@@ -196,63 +139,8 @@ private void addSeparator(Composite parent) {
separator.setLayoutData(gridData);
}
- private boolean isPolicyAllowsSubAgent() {
- FeatureFlags flags = CopilotCore.getPlugin().getFeatureFlags();
- return isClientPreviewFeatureEnabled() && flags != null && flags.isSubAgentPolicyEnabled();
- }
-
private boolean isClientPreviewFeatureEnabled() {
FeatureFlags flags = CopilotCore.getPlugin().getFeatureFlags();
return flags != null && flags.isClientPreviewFeatureEnabled();
}
-
- /**
- * Updates the MCP tool configuration to include or exclude the run_subagent tool for agent mode based on the
- * sub-agent preference setting.
- *
- * @param subAgentEnabled true if sub-agent is enabled, false otherwise
- */
- private void updateSubAgentToolConfiguration(boolean subAgentEnabled) {
- try {
- // Load existing MCP tools mode status
- String existingJson = getPreferenceStore().getString(Constants.MCP_TOOLS_MODE_STATUS);
-
- // Parse existing configuration or create new one
- Map>> modeToolStatus;
- if (existingJson != null && !existingJson.trim().isEmpty()) {
- Type type = new TypeToken