mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-16 17:46:20 +00:00
* fix(agents): scope loop detection state per run * fix(agents): harden loop scope fallback * docs: move loop lifecycle detail out of inherited guidance --------- Co-authored-by: PeaceMaker-best <221849497+PeaceMaker-best@users.noreply.github.com> Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
74 lines
2.6 KiB
Python
74 lines
2.6 KiB
Python
"""Configuration for loop detection middleware."""
|
|
|
|
from pydantic import BaseModel, Field, model_validator
|
|
|
|
|
|
class ToolFreqOverride(BaseModel):
|
|
"""Per-tool frequency threshold override.
|
|
|
|
Can be higher or lower than the global defaults. Commonly used to raise
|
|
thresholds for high-frequency tools like bash in batch workflows (e.g.
|
|
RNA-seq pipelines) without weakening protection on every other tool.
|
|
"""
|
|
|
|
warn: int = Field(ge=1)
|
|
hard_limit: int = Field(ge=1)
|
|
|
|
@model_validator(mode="after")
|
|
def _validate(self) -> "ToolFreqOverride":
|
|
if self.hard_limit < self.warn:
|
|
raise ValueError("hard_limit must be >= warn")
|
|
return self
|
|
|
|
|
|
class LoopDetectionConfig(BaseModel):
|
|
"""Configuration for repetitive tool-call loop detection."""
|
|
|
|
enabled: bool = Field(
|
|
default=True,
|
|
description="Whether to enable repetitive tool-call loop detection",
|
|
)
|
|
warn_threshold: int = Field(
|
|
default=3,
|
|
ge=1,
|
|
description="Number of identical tool-call sets before injecting a warning",
|
|
)
|
|
hard_limit: int = Field(
|
|
default=5,
|
|
ge=1,
|
|
description="Number of identical tool-call sets before forcing a stop",
|
|
)
|
|
window_size: int = Field(
|
|
default=20,
|
|
ge=1,
|
|
description="Number of recent tool-call sets to track per thread",
|
|
)
|
|
max_tracked_threads: int = Field(
|
|
default=100,
|
|
ge=1,
|
|
description="Maximum number of thread/run histories to keep in memory (legacy field name)",
|
|
)
|
|
tool_freq_warn: int = Field(
|
|
default=30,
|
|
ge=1,
|
|
description="Number of calls to the same tool type before injecting a frequency warning",
|
|
)
|
|
tool_freq_hard_limit: int = Field(
|
|
default=50,
|
|
ge=1,
|
|
description="Number of calls to the same tool type before forcing a stop",
|
|
)
|
|
tool_freq_overrides: dict[str, ToolFreqOverride] = Field(
|
|
default_factory=dict,
|
|
description=("Per-tool overrides for tool_freq_warn / tool_freq_hard_limit, keyed by tool name. Values can be higher or lower than the global defaults. Commonly used to raise thresholds for high-frequency tools like bash."),
|
|
)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_thresholds(self) -> "LoopDetectionConfig":
|
|
"""Ensure hard stop cannot happen before the warning threshold."""
|
|
if self.hard_limit < self.warn_threshold:
|
|
raise ValueError("hard_limit must be greater than or equal to warn_threshold")
|
|
if self.tool_freq_hard_limit < self.tool_freq_warn:
|
|
raise ValueError("tool_freq_hard_limit must be greater than or equal to tool_freq_warn")
|
|
return self
|