feat(config): add background task circuit breaker settings

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-03-17 16:31:04 +09:00
parent 4d74d888e4
commit e271b4a1b0
3 changed files with 92 additions and 0 deletions

View File

@@ -3699,6 +3699,32 @@
"syncPollTimeoutMs": {
"type": "number",
"minimum": 60000
},
"maxToolCalls": {
"type": "integer",
"minimum": 10,
"maximum": 9007199254740991
},
"circuitBreaker": {
"type": "object",
"properties": {
"maxToolCalls": {
"type": "integer",
"minimum": 10,
"maximum": 9007199254740991
},
"windowSize": {
"type": "integer",
"minimum": 5,
"maximum": 9007199254740991
},
"repetitionThresholdPercent": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 100
}
},
"additionalProperties": false
}
},
"additionalProperties": false

View File

@@ -0,0 +1,59 @@
import { describe, expect, test } from "bun:test"
import { ZodError } from "zod/v4"
import { BackgroundTaskConfigSchema } from "./background-task"
describe("BackgroundTaskConfigSchema.circuitBreaker", () => {
describe("#given valid circuit breaker settings", () => {
test("#when parsed #then returns nested config", () => {
const result = BackgroundTaskConfigSchema.parse({
circuitBreaker: {
maxToolCalls: 150,
windowSize: 10,
repetitionThresholdPercent: 70,
},
})
expect(result.circuitBreaker).toEqual({
maxToolCalls: 150,
windowSize: 10,
repetitionThresholdPercent: 70,
})
})
})
describe("#given windowSize below minimum", () => {
test("#when parsed #then throws ZodError", () => {
let thrownError: unknown
try {
BackgroundTaskConfigSchema.parse({
circuitBreaker: {
windowSize: 4,
},
})
} catch (error) {
thrownError = error
}
expect(thrownError).toBeInstanceOf(ZodError)
})
})
describe("#given repetitionThresholdPercent is zero", () => {
test("#when parsed #then throws ZodError", () => {
let thrownError: unknown
try {
BackgroundTaskConfigSchema.parse({
circuitBreaker: {
repetitionThresholdPercent: 0,
},
})
} catch (error) {
thrownError = error
}
expect(thrownError).toBeInstanceOf(ZodError)
})
})
})

View File

@@ -1,5 +1,11 @@
import { z } from "zod"
const CircuitBreakerConfigSchema = z.object({
maxToolCalls: z.number().int().min(10).optional(),
windowSize: z.number().int().min(5).optional(),
repetitionThresholdPercent: z.number().gt(0).max(100).optional(),
})
export const BackgroundTaskConfigSchema = z.object({
defaultConcurrency: z.number().min(1).optional(),
providerConcurrency: z.record(z.string(), z.number().min(0)).optional(),
@@ -13,6 +19,7 @@ export const BackgroundTaskConfigSchema = z.object({
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(),
circuitBreaker: CircuitBreakerConfigSchema.optional(),
})
export type BackgroundTaskConfig = z.infer<typeof BackgroundTaskConfigSchema>