Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ private Constants() {
// Auto-Approve settings
public static final String AUTO_APPROVE_TERMINAL_RULES = "autoApproveTerminalRules";
public static final String AUTO_APPROVE_UNMATCHED_TERMINAL = "autoApproveUnmatchedTerminal";
public static final String AUTO_APPROVE_FILE_OP_RULES = "autoApproveEditRules";
public static final String AUTO_APPROVE_UNMATCHED_FILE_OP = "autoApproveUnmatchedFileOp";

// Base excluded file types shared by both
// Copied from InelliJ, excluded file extension list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,44 @@
public class ConfirmationResult {

/** Auto-approved, no user confirmation needed. */
public static final ConfirmationResult AUTO_APPROVED = new ConfirmationResult(true, null);
public static final ConfirmationResult AUTO_APPROVED = new ConfirmationResult(true, false, null);

/** Dismissed — malformed or unhandleable request; CLS should be told to skip the tool. */
public static final ConfirmationResult DISMISSED = new ConfirmationResult(false, true, null);

private final boolean autoApproved;
private final boolean dismissed;
private final ConfirmationContent content;

private ConfirmationResult(boolean autoApproved, ConfirmationContent content) {
private ConfirmationResult(boolean autoApproved, boolean dismissed, ConfirmationContent content) {
this.autoApproved = autoApproved;
this.dismissed = dismissed;
this.content = content;
}

/** Creates a result that requires user confirmation with the given content. */
public static ConfirmationResult needsConfirmation(
ConfirmationContent content) {
return new ConfirmationResult(false, content);
return new ConfirmationResult(false, false, content);
}

public boolean isAutoApproved() {
return autoApproved;
}

/** Returns true if the request should be dismissed without showing UI. */
public boolean isDismissed() {
return dismissed;
}

/** Returns the confirmation content, or null if auto-approved or using defaults. */
public ConfirmationContent getContent() {
return content;
}

@Override
public int hashCode() {
return Objects.hash(autoApproved, content);
return Objects.hash(autoApproved, dismissed, content);
}

@Override
Expand All @@ -57,13 +67,15 @@ public boolean equals(Object obj) {
}
ConfirmationResult other = (ConfirmationResult) obj;
return autoApproved == other.autoApproved
&& dismissed == other.dismissed
&& Objects.equals(content, other.content);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.append("autoApproved", autoApproved)
.append("dismissed", dismissed)
.append("content", content)
.toString();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

package com.microsoft.copilot.eclipse.core.chat;

import java.util.Objects;

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

/**
* A single file-operation auto-approve rule mapping a glob pattern to an allow/deny decision.
*/
public class FileOperationAutoApproveRule {
private String pattern;
private String description;
private boolean autoApprove;
private transient boolean isDefault;

/**
* Creates a new rule.
*
* @param pattern the glob pattern (e.g., "**\/.github/instructions/*")
* @param description human-readable description of what this pattern matches
* @param autoApprove true to auto-approve, false to always require confirmation
*/
public FileOperationAutoApproveRule(String pattern, String description, boolean autoApprove) {
this(pattern, description, autoApprove, false);
}

/**
* Creates a new rule.
*
* @param pattern the glob pattern
* @param description human-readable description
* @param autoApprove true to auto-approve, false to always require confirmation
* @param isDefault true if this is a CLS default rule (non-removable)
*/
public FileOperationAutoApproveRule(String pattern, String description,
boolean autoApprove, boolean isDefault) {
this.pattern = pattern;
this.description = description;
this.autoApprove = autoApprove;
this.isDefault = isDefault;
}

/** Default constructor for Gson deserialization. */
public FileOperationAutoApproveRule() {
}

public String getPattern() {
return pattern;
}

public void setPattern(String pattern) {
this.pattern = pattern;
}

public String getDescription() {
return description;
}

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

public boolean isAutoApprove() {
return autoApprove;
}

public void setAutoApprove(boolean autoApprove) {
this.autoApprove = autoApprove;
}

public boolean isDefault() {
return isDefault;
}

public void setDefault(boolean isDefault) {
this.isDefault = isDefault;
}

@Override
public int hashCode() {
return Objects.hash(pattern, description, autoApprove);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
FileOperationAutoApproveRule other = (FileOperationAutoApproveRule) obj;
return Objects.equals(pattern, other.pattern)
&& Objects.equals(description, other.description)
&& autoApprove == other.autoApprove;
}

@Override
public String toString() {
return new ToStringBuilder(this)
.append("pattern", pattern)
.append("description", description)
.append("autoApprove", autoApprove)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.microsoft.copilot.eclipse.core.lsp.protocol.DidShowInlineEditParams;
import com.microsoft.copilot.eclipse.core.lsp.protocol.GenerateThinkingTitleParams;
import com.microsoft.copilot.eclipse.core.lsp.protocol.GenerateThinkingTitleResponse;
import com.microsoft.copilot.eclipse.core.lsp.protocol.GetDefaultFileSafetyRulesResult;
import com.microsoft.copilot.eclipse.core.lsp.protocol.LanguageModelToolInformation;
import com.microsoft.copilot.eclipse.core.lsp.protocol.NextEditSuggestionsParams;
import com.microsoft.copilot.eclipse.core.lsp.protocol.NextEditSuggestionsResult;
Expand Down Expand Up @@ -285,6 +286,13 @@ public interface CopilotLanguageServer extends LanguageServer {
@JsonRequest("githubApi/searchPR")
CompletableFuture<SearchPrResponse> searchPr(SearchPrParams params);

/**
* Get the default file safety rules from CLS.
*/
@JsonRequest("getDefaultFileSafetyRules")
CompletableFuture<GetDefaultFileSafetyRulesResult> getDefaultFileSafetyRules(
NullParams params);

/**
* Notify that an inline edit was shown.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import com.microsoft.copilot.eclipse.core.lsp.protocol.DidShowInlineEditParams;
import com.microsoft.copilot.eclipse.core.lsp.protocol.GenerateThinkingTitleParams;
import com.microsoft.copilot.eclipse.core.lsp.protocol.GenerateThinkingTitleResponse;
import com.microsoft.copilot.eclipse.core.lsp.protocol.GetDefaultFileSafetyRulesResult;
import com.microsoft.copilot.eclipse.core.lsp.protocol.LanguageModelToolInformation;
import com.microsoft.copilot.eclipse.core.lsp.protocol.NextEditSuggestionsParams;
import com.microsoft.copilot.eclipse.core.lsp.protocol.NextEditSuggestionsResult;
Expand Down Expand Up @@ -153,6 +154,16 @@ public CompletableFuture<CheckQuotaResult> checkQuota() {
return this.languageServerWrapper.execute(fn);
}

/**
* Get the default file safety rules from CLS.
*/
public CompletableFuture<GetDefaultFileSafetyRulesResult> getDefaultFileSafetyRules() {
Function<LanguageServer, CompletableFuture<GetDefaultFileSafetyRulesResult>> fn =
server -> ((CopilotLanguageServer) server)
.getDefaultFileSafetyRules(new NullParams());
return this.languageServerWrapper.execute(fn);
}

/**
* Get single completion for the given parameters.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public class CopilotAgentSettings {
@SerializedName("autoApproveUnmatchedTerminal")
private boolean autoApproveUnmatchedTerminal;

@SerializedName("autoApproveUnmatchedFileOp")
private boolean autoApproveUnmatchedFileOp;

// Tells CLS to always send confirmation requests to the editor
@SerializedName("editorHandlesAllConfirmation")
private boolean editorHandlesAllConfirmation = true;
Expand All @@ -32,6 +35,7 @@ public class CopilotAgentSettings {
/** Nested tools settings matching CLS agent.tools structure. */
public static class ToolsSettings {
private TerminalSettings terminal;
private EditSettings edit;

/** Gets terminal settings, creating if needed. */
public TerminalSettings getTerminal() {
Expand All @@ -40,6 +44,39 @@ public TerminalSettings getTerminal() {
}
return terminal;
}

/** Gets edit settings, creating if needed. */
public EditSettings getEdit() {
if (edit == null) {
edit = new EditSettings();
}
return edit;
}

@Override
public int hashCode() {
return Objects.hash(terminal, edit);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
ToolsSettings other = (ToolsSettings) obj;
return Objects.equals(terminal, other.terminal) && Objects.equals(edit, other.edit);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.append("terminal", terminal)
.append("edit", edit)
.toString();
}
}

/** Terminal auto-approve rules: command/pattern -> allow(true)/deny(false). */
Expand All @@ -53,6 +90,65 @@ public Map<String, Boolean> getAutoApprove() {
public void setAutoApprove(Map<String, Boolean> autoApprove) {
this.autoApprove = autoApprove;
}

@Override
public int hashCode() {
return Objects.hash(autoApprove);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return Objects.equals(autoApprove, ((TerminalSettings) obj).autoApprove);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.append("autoApprove", autoApprove)
.toString();
}
}

/** Edit (file operation) auto-approve rules: pattern → allow(true)/deny(false). */
public static class EditSettings {
private Map<String, Boolean> autoApprove;

public Map<String, Boolean> getAutoApprove() {
return autoApprove;
}

public void setAutoApprove(Map<String, Boolean> autoApprove) {
this.autoApprove = autoApprove;
}

@Override
public int hashCode() {
return Objects.hash(autoApprove);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return Objects.equals(autoApprove, ((EditSettings) obj).autoApprove);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.append("autoApprove", autoApprove)
.toString();
}
}

public int getAgentMaxRequests() {
Expand Down Expand Up @@ -98,6 +194,14 @@ public void setAutoApproveUnmatchedTerminal(boolean autoApproveUnmatchedTerminal
this.autoApproveUnmatchedTerminal = autoApproveUnmatchedTerminal;
}

public boolean isAutoApproveUnmatchedFileOp() {
return autoApproveUnmatchedFileOp;
}

public void setAutoApproveUnmatchedFileOp(boolean autoApproveUnmatchedFileOp) {
this.autoApproveUnmatchedFileOp = autoApproveUnmatchedFileOp;
}

/** Gets tools settings, creating if needed. */
public ToolsSettings getTools() {
if (tools == null) {
Expand All @@ -109,7 +213,7 @@ public ToolsSettings getTools() {
@Override
public int hashCode() {
return Objects.hash(agentMaxRequests, enableSkills, transcriptDirectory,
editorHandlesAllConfirmation, autoApproveUnmatchedTerminal, tools);
editorHandlesAllConfirmation, autoApproveUnmatchedTerminal, autoApproveUnmatchedFileOp, tools);
}

@Override
Expand All @@ -128,6 +232,7 @@ public boolean equals(Object obj) {
&& Objects.equals(transcriptDirectory, other.transcriptDirectory)
&& editorHandlesAllConfirmation == other.editorHandlesAllConfirmation
&& autoApproveUnmatchedTerminal == other.autoApproveUnmatchedTerminal
&& autoApproveUnmatchedFileOp == other.autoApproveUnmatchedFileOp
&& Objects.equals(tools, other.tools);
}

Expand All @@ -139,6 +244,7 @@ public String toString() {
builder.append("transcriptDirectory", transcriptDirectory);
builder.append("editorHandlesAllConfirmation", editorHandlesAllConfirmation);
builder.append("autoApproveUnmatchedTerminal", autoApproveUnmatchedTerminal);
builder.append("autoApproveUnmatchedFileOp", autoApproveUnmatchedFileOp);
builder.append("tools", tools);
return builder.toString();
}
Expand Down
Loading