fix: allow user to configure doom loop & external dir perms (#4095)

This commit is contained in:
Aiden Cline
2025-11-09 18:21:38 -08:00
committed by GitHub
parent 7be8e16c33
commit 4e549b1c05
8 changed files with 95 additions and 62 deletions

View File

@@ -20,6 +20,8 @@ export namespace Agent {
edit: Config.Permission,
bash: z.record(z.string(), Config.Permission),
webfetch: Config.Permission.optional(),
doom_loop: Config.Permission.optional(),
external_directory: Config.Permission.optional(),
}),
model: z
.object({
@@ -45,6 +47,8 @@ export namespace Agent {
"*": "allow",
},
webfetch: "allow",
doom_loop: "ask",
external_directory: "ask",
}
const agentPermission = mergeAgentPermissions(defaultPermission, cfg.permission ?? {})
@@ -244,6 +248,8 @@ function mergeAgentPermissions(basePermission: any, overridePermission: any): Ag
edit: merged.edit ?? "allow",
webfetch: merged.webfetch ?? "allow",
bash: mergedBash ?? { "*": "allow" },
doom_loop: merged.doom_loop,
external_directory: merged.external_directory,
}
return result

View File

@@ -360,6 +360,8 @@ export namespace Config {
edit: Permission.optional(),
bash: z.union([Permission, z.record(z.string(), Permission)]).optional(),
webfetch: Permission.optional(),
doom_loop: Permission.optional(),
external_directory: Permission.optional(),
})
.optional(),
})
@@ -574,6 +576,8 @@ export namespace Config {
edit: Permission.optional(),
bash: z.union([Permission, z.record(z.string(), Permission)]).optional(),
webfetch: Permission.optional(),
doom_loop: Permission.optional(),
external_directory: Permission.optional(),
})
.optional(),
tools: z.record(z.string(), z.boolean()).optional(),

View File

@@ -1115,8 +1115,10 @@ export namespace SessionPrompt {
JSON.stringify(p.state.input) === JSON.stringify(value.input),
)
) {
const permission = await Agent.get(input.agent).then((x) => x.permission)
if (permission.doom_loop === "ask") {
await Permission.ask({
type: "doom-loop",
type: "doom_loop",
pattern: value.toolName,
sessionID: assistantMsg.sessionID,
messageID: assistantMsg.id,
@@ -1129,6 +1131,7 @@ export namespace SessionPrompt {
})
}
}
}
break
}
case "tool-result": {

View File

@@ -35,11 +35,14 @@ export const EditTool = Tool.define("edit", {
throw new Error("oldString and newString must be different")
}
const agent = await Agent.get(ctx.agent)
const filePath = path.isAbsolute(params.filePath) ? params.filePath : path.join(Instance.directory, params.filePath)
if (!Filesystem.contains(Instance.directory, filePath)) {
const parentDir = path.dirname(filePath)
if (agent.permission.external_directory === "ask") {
await Permission.ask({
type: "external-directory",
type: "external_directory",
pattern: parentDir,
sessionID: ctx.sessionID,
messageID: ctx.messageID,
@@ -51,8 +54,8 @@ export const EditTool = Tool.define("edit", {
},
})
}
}
const agent = await Agent.get(ctx.agent)
let diff = ""
let contentOld = ""
let contentNew = ""

View File

@@ -55,8 +55,9 @@ export const PatchTool = Tool.define("patch", {
if (!Filesystem.contains(Instance.directory, filePath)) {
const parentDir = path.dirname(filePath)
if (agent.permission.external_directory === "ask") {
await Permission.ask({
type: "external-directory",
type: "external_directory",
pattern: parentDir,
sessionID: ctx.sessionID,
messageID: ctx.messageID,
@@ -68,6 +69,7 @@ export const PatchTool = Tool.define("patch", {
},
})
}
}
switch (hunk.type) {
case "add":

View File

@@ -10,6 +10,7 @@ import { Instance } from "../project/instance"
import { Provider } from "../provider/provider"
import { Identifier } from "../id/id"
import { Permission } from "../permission"
import { Agent } from "@/agent/agent"
const DEFAULT_READ_LIMIT = 2000
const MAX_LINE_LENGTH = 2000
@@ -27,11 +28,13 @@ export const ReadTool = Tool.define("read", {
filepath = path.join(process.cwd(), filepath)
}
const title = path.relative(Instance.worktree, filepath)
const agent = await Agent.get(ctx.agent)
if (!ctx.extra?.["bypassCwdCheck"] && !Filesystem.contains(Instance.directory, filepath)) {
const parentDir = path.dirname(filepath)
if (agent.permission.external_directory === "ask") {
await Permission.ask({
type: "external-directory",
type: "external_directory",
pattern: parentDir,
sessionID: ctx.sessionID,
messageID: ctx.messageID,
@@ -43,6 +46,7 @@ export const ReadTool = Tool.define("read", {
},
})
}
}
const file = Bun.file(filepath)
if (!(await file.exists())) {

View File

@@ -18,11 +18,14 @@ export const WriteTool = Tool.define("write", {
filePath: z.string().describe("The absolute path to the file to write (must be absolute, not relative)"),
}),
async execute(params, ctx) {
const agent = await Agent.get(ctx.agent)
const filepath = path.isAbsolute(params.filePath) ? params.filePath : path.join(Instance.directory, params.filePath)
if (!Filesystem.contains(Instance.directory, filepath)) {
const parentDir = path.dirname(filepath)
if (agent.permission.external_directory === "ask") {
await Permission.ask({
type: "external-directory",
type: "external_directory",
pattern: parentDir,
sessionID: ctx.sessionID,
messageID: ctx.messageID,
@@ -34,12 +37,12 @@ export const WriteTool = Tool.define("write", {
},
})
}
}
const file = Bun.file(filepath)
const exists = await file.exists()
if (exists) await FileTime.assert(ctx.sessionID, filepath)
const agent = await Agent.get(ctx.agent)
if (agent.permission.edit === "ask")
await Permission.ask({
type: "write",

View File

@@ -198,6 +198,8 @@ export type AgentConfig = {
[key: string]: "ask" | "allow" | "deny"
}
webfetch?: "ask" | "allow" | "deny"
doom_loop?: "ask" | "allow" | "deny"
external_directory?: "ask" | "allow" | "deny"
}
[key: string]:
| unknown
@@ -216,6 +218,8 @@ export type AgentConfig = {
[key: string]: "ask" | "allow" | "deny"
}
webfetch?: "ask" | "allow" | "deny"
doom_loop?: "ask" | "allow" | "deny"
external_directory?: "ask" | "allow" | "deny"
}
| undefined
}
@@ -463,6 +467,8 @@ export type Config = {
[key: string]: "ask" | "allow" | "deny"
}
webfetch?: "ask" | "allow" | "deny"
doom_loop?: "ask" | "allow" | "deny"
external_directory?: "ask" | "allow" | "deny"
}
tools?: {
[key: string]: boolean
@@ -1043,6 +1049,8 @@ export type Agent = {
[key: string]: "ask" | "allow" | "deny"
}
webfetch?: "ask" | "allow" | "deny"
doom_loop?: "ask" | "allow" | "deny"
external_directory?: "ask" | "allow" | "deny"
}
model?: {
modelID: string