diff --git a/gui/src/pages/config/components/ToolPolicyItem.tsx b/gui/src/pages/config/components/ToolPolicyItem.tsx
index 5d81c5908f2..2971e015d4f 100644
--- a/gui/src/pages/config/components/ToolPolicyItem.tsx
+++ b/gui/src/pages/config/components/ToolPolicyItem.tsx
@@ -19,6 +19,7 @@ import {
import { useFontSize } from "../../../components/ui/font";
import { useAppSelector } from "../../../redux/hooks";
import { addTool, setToolPolicy } from "../../../redux/slices/uiSlice";
+import { isEditTool } from "../../../util/toolCallState";
interface ToolPolicyItemProps {
tool: Tool;
@@ -28,12 +29,22 @@ interface ToolPolicyItemProps {
export function ToolPolicyItem(props: ToolPolicyItemProps) {
const dispatch = useDispatch();
- const policy = useAppSelector(
+ const toolPolicy = useAppSelector(
(state) => state.ui.toolSettings[props.tool.function.name],
);
const [isExpanded, setIsExpanded] = useState(false);
const mode = useAppSelector((state) => state.session.mode);
+ const autoAcceptEditToolDiffs = useAppSelector(
+ (state) => state.config.config.ui?.autoAcceptEditToolDiffs,
+ );
+ const isAutoAcceptedToolCall =
+ isEditTool(props.tool.function.name) && autoAcceptEditToolDiffs;
+
+ const policy = isAutoAcceptedToolCall
+ ? "allowedWithoutPermission"
+ : toolPolicy;
+
useEffect(() => {
if (!policy) {
dispatch(addTool(props.tool));
@@ -53,6 +64,7 @@ export function ToolPolicyItem(props: ToolPolicyItemProps) {
const fontSize = useFontSize(-2);
const disabled =
+ isAutoAcceptedToolCall ||
!props.isGroupEnabled ||
(mode === "plan" &&
props.tool.group === BUILT_IN_GROUP_NAME &&
@@ -100,6 +112,19 @@ export function ToolPolicyItem(props: ToolPolicyItemProps) {
) : null}
+ {isAutoAcceptedToolCall ? (
+
+ Auto-Accept Agent Edits setting is on
+
+ }
+ >
+
+
+ ) : null}
{props.tool.faviconUrl && (
- {disabled || policy === "disabled"
- ? "Excluded"
- : policy === "allowedWithoutPermission"
- ? "Automatic"
- : "Ask First"}
+ {isAutoAcceptedToolCall
+ ? "Automatic"
+ : disabled || policy === "disabled"
+ ? "Excluded"
+ : policy === "allowedWithoutPermission"
+ ? "Automatic"
+ : "Ask First"}
diff --git a/gui/src/redux/slices/sessionSlice.ts b/gui/src/redux/slices/sessionSlice.ts
index 541787888a3..dee39f8565d 100644
--- a/gui/src/redux/slices/sessionSlice.ts
+++ b/gui/src/redux/slices/sessionSlice.ts
@@ -25,7 +25,6 @@ import {
ToolCallState,
} from "core";
import type { RemoteSessionMetadata } from "core/control-plane/client";
-import { BuiltInToolNames } from "core/tools/builtIn";
import { NEW_SESSION_TITLE } from "core/util/constants";
import {
renderChatMessage,
@@ -36,7 +35,7 @@ import { findLastIndex } from "lodash";
import { v4 as uuidv4 } from "uuid";
import { type InlineErrorMessageType } from "../../components/mainInput/InlineErrorMessage";
import { toolCallCtxItemToCtxItemWithId } from "../../pages/gui/ToolCallDiv/utils";
-import { addToolCallDeltaToState } from "../../util/toolCallState";
+import { addToolCallDeltaToState, isEditTool } from "../../util/toolCallState";
import { RootState } from "../store";
import { streamResponseThunk } from "../thunks/streamResponse";
import { findChatHistoryItemByToolCallId, findToolCallById } from "../util";
@@ -51,17 +50,10 @@ import { findChatHistoryItemByToolCallId, findToolCallById } from "../util";
function filterMultipleEditToolCalls(
toolCalls: ToolCallDelta[],
): ToolCallDelta[] {
- const editToolNames = [
- BuiltInToolNames.EditExistingFile,
- BuiltInToolNames.SingleFindAndReplace,
- BuiltInToolNames.MultiEdit,
- ];
let hasSeenEditTool = false;
return toolCalls.filter((toolCall) => {
- const isEditTool = editToolNames.includes(toolCall.function?.name as any);
-
- if (isEditTool) {
+ if (toolCall.function?.name && isEditTool(toolCall.function?.name)) {
if (hasSeenEditTool) {
return false; // Skip this duplicate edit tool
}
diff --git a/gui/src/redux/thunks/evaluateToolPolicies.ts b/gui/src/redux/thunks/evaluateToolPolicies.ts
index 990aef4c89e..37c009210a2 100644
--- a/gui/src/redux/thunks/evaluateToolPolicies.ts
+++ b/gui/src/redux/thunks/evaluateToolPolicies.ts
@@ -1,6 +1,7 @@
import { ToolPolicy } from "@continuedev/terminal-security";
import { Tool, ToolCallState } from "core";
import { IIdeMessenger } from "../../context/IdeMessenger";
+import { isEditTool } from "../../util/toolCallState";
import { errorToolCall, updateToolCallOutput } from "../slices/sessionSlice";
import { DEFAULT_TOOL_SETTING, ToolPolicies } from "../slices/uiSlice";
import { AppThunkDispatch } from "../store";
@@ -20,7 +21,16 @@ async function evaluateToolPolicy(
activeTools: Tool[],
toolCallState: ToolCallState,
toolPolicies: ToolPolicies,
+ autoAcceptEditToolDiffs: boolean | undefined,
): Promise {
+ // allow edit tool calls without permission if auto-accept is enabled
+ if (
+ isEditTool(toolCallState.toolCall.function.name) &&
+ autoAcceptEditToolDiffs
+ ) {
+ return { policy: "allowedWithoutPermission", toolCallState };
+ }
+
const basePolicy =
toolPolicies[toolCallState.toolCall.function.name] ??
activeTools.find(
@@ -73,6 +83,7 @@ export async function evaluateToolPolicies(
activeTools: Tool[],
generatedToolCalls: ToolCallState[],
toolPolicies: ToolPolicies,
+ autoAcceptEditToolDiffs: boolean | undefined,
): Promise {
// Check if ALL tool calls are auto-approved using dynamic evaluation
const policyResults = await Promise.all(
@@ -82,6 +93,7 @@ export async function evaluateToolPolicies(
activeTools,
toolCallState,
toolPolicies,
+ autoAcceptEditToolDiffs,
),
),
);
diff --git a/gui/src/redux/thunks/streamNormalInput.ts b/gui/src/redux/thunks/streamNormalInput.ts
index b1f5d10ff2b..bf4939c38cd 100644
--- a/gui/src/redux/thunks/streamNormalInput.ts
+++ b/gui/src/redux/thunks/streamNormalInput.ts
@@ -268,6 +268,7 @@ export const streamNormalInput = createAsyncThunk<
activeTools,
generatedCalls3,
toolPolicies,
+ state3.config.config.ui?.autoAcceptEditToolDiffs,
);
const anyRequireApproval = policies.find(
({ policy }) => policy === "allowedWithPermission",
diff --git a/gui/src/util/toolCallState.ts b/gui/src/util/toolCallState.ts
index 92df3acd3eb..c7b9bcbd7df 100644
--- a/gui/src/util/toolCallState.ts
+++ b/gui/src/util/toolCallState.ts
@@ -1,4 +1,5 @@
import { ToolCallDelta, ToolCallState } from "core";
+import { BuiltInToolNames } from "core/tools/builtIn";
import { incrementalParseJson } from "core/util/incrementalParseJson";
// Merge streamed tool calls
@@ -67,3 +68,12 @@ export function addToolCallDeltaToState(
parsedArgs,
};
}
+
+const editToolNames: string[] = [
+ BuiltInToolNames.EditExistingFile,
+ BuiltInToolNames.SingleFindAndReplace,
+ BuiltInToolNames.MultiEdit,
+];
+export function isEditTool(toolName: string) {
+ return editToolNames.includes(toolName);
+}