mirror of
https://github.com/aljazceru/opencode.git
synced 2026-01-08 18:34:59 +01:00
fix: add doom loop detection (#3445)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
This commit is contained in:
@@ -56,6 +56,7 @@ export namespace SessionPrompt {
|
||||
const log = Log.create({ service: "session.prompt" })
|
||||
export const OUTPUT_TOKEN_MAX = 32_000
|
||||
const MAX_RETRIES = 10
|
||||
const DOOM_LOOP_THRESHOLD = 3
|
||||
|
||||
export const Event = {
|
||||
Idle: Bus.event(
|
||||
@@ -1068,6 +1069,32 @@ export namespace SessionPrompt {
|
||||
metadata: value.providerMetadata,
|
||||
})
|
||||
toolcalls[value.toolCallId] = part as MessageV2.ToolPart
|
||||
|
||||
const parts = await Session.getParts(assistantMsg.id)
|
||||
const lastThree = parts.slice(-DOOM_LOOP_THRESHOLD)
|
||||
if (
|
||||
lastThree.length === DOOM_LOOP_THRESHOLD &&
|
||||
lastThree.every(
|
||||
(p) =>
|
||||
p.type === "tool" &&
|
||||
p.tool === value.toolName &&
|
||||
p.state.status !== "pending" &&
|
||||
JSON.stringify(p.state.input) === JSON.stringify(value.input),
|
||||
)
|
||||
) {
|
||||
await Permission.ask({
|
||||
type: "doom-loop",
|
||||
pattern: value.toolName,
|
||||
sessionID: assistantMsg.sessionID,
|
||||
messageID: assistantMsg.id,
|
||||
callID: value.toolCallId,
|
||||
title: `Possible doom loop: "${value.toolName}" called ${DOOM_LOOP_THRESHOLD} times with identical arguments`,
|
||||
metadata: {
|
||||
tool: value.toolName,
|
||||
input: value.input,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
@@ -504,7 +504,11 @@ func renderToolDetails(
|
||||
base := styles.NewStyle().Background(backgroundColor)
|
||||
text := base.Foreground(t.Text()).Bold(true).Render
|
||||
muted := base.Foreground(t.TextMuted()).Render
|
||||
permissionContent = "Permission required to run this tool:\n\n"
|
||||
if permission.Type == "doom-loop" {
|
||||
permissionContent = permission.Title + "\n\n"
|
||||
} else {
|
||||
permissionContent = "Permission required to run this tool:\n\n"
|
||||
}
|
||||
permissionContent += text(
|
||||
"enter ",
|
||||
) + muted(
|
||||
@@ -642,9 +646,9 @@ func renderToolDetails(
|
||||
for _, item := range todos.([]any) {
|
||||
todo := item.(map[string]any)
|
||||
content := todo["content"]
|
||||
if content == nil {
|
||||
continue
|
||||
}
|
||||
if content == nil {
|
||||
continue
|
||||
}
|
||||
switch todo["status"] {
|
||||
case "completed":
|
||||
body += fmt.Sprintf("- [x] %s\n", content)
|
||||
|
||||
Reference in New Issue
Block a user