Merge pull request #2590 from MoerAI/fix/subagent-circuit-breaker
fix(background-agent): add circuit breaker to prevent subagent infinite loops (fixes #2571)
This commit is contained in:
@@ -11,6 +11,8 @@ export const BackgroundTaskConfigSchema = z.object({
|
|||||||
/** Timeout for tasks that never received any progress update, falling back to startedAt (default: 1800000 = 30 minutes, minimum: 60000 = 1 minute) */
|
/** Timeout for tasks that never received any progress update, falling back to startedAt (default: 1800000 = 30 minutes, minimum: 60000 = 1 minute) */
|
||||||
messageStalenessTimeoutMs: z.number().min(60000).optional(),
|
messageStalenessTimeoutMs: z.number().min(60000).optional(),
|
||||||
syncPollTimeoutMs: z.number().min(60000).optional(),
|
syncPollTimeoutMs: z.number().min(60000).optional(),
|
||||||
|
/** Maximum tool calls per subagent task before circuit breaker triggers (default: 200, minimum: 10). Prevents runaway loops from burning unlimited tokens. */
|
||||||
|
maxToolCalls: z.number().int().min(10).optional(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export type BackgroundTaskConfig = z.infer<typeof BackgroundTaskConfigSchema>
|
export type BackgroundTaskConfig = z.infer<typeof BackgroundTaskConfigSchema>
|
||||||
|
|||||||
@@ -878,6 +878,21 @@ export class BackgroundManager {
|
|||||||
if (partInfo?.type === "tool" || partInfo?.tool) {
|
if (partInfo?.type === "tool" || partInfo?.tool) {
|
||||||
task.progress.toolCalls += 1
|
task.progress.toolCalls += 1
|
||||||
task.progress.lastTool = partInfo.tool
|
task.progress.lastTool = partInfo.tool
|
||||||
|
|
||||||
|
const maxToolCalls = this.config?.maxToolCalls ?? 200
|
||||||
|
if (task.progress.toolCalls >= maxToolCalls) {
|
||||||
|
log("[background-agent] Circuit breaker: tool call limit reached", {
|
||||||
|
taskId: task.id,
|
||||||
|
toolCalls: task.progress.toolCalls,
|
||||||
|
maxToolCalls,
|
||||||
|
agent: task.agent,
|
||||||
|
sessionID,
|
||||||
|
})
|
||||||
|
void this.cancelTask(task.id, {
|
||||||
|
source: "circuit-breaker",
|
||||||
|
reason: `Subagent exceeded maximum tool call limit (${maxToolCalls}). This usually indicates an infinite loop. The task was automatically cancelled to prevent excessive token usage.`,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user