mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-26 21:26:39 +00:00
* fix(config): reject boolean integer settings in app_config Follows the loop-detection and circuit-breaker guards: YAML booleans next to integer knobs load cleanly, and Pydantic coerces booleans to 1/0. - recursion_limit coerced from `true` to 1, so every Gateway run that does not supply its own limit hit the LangGraph recursion ceiling at the first super-step (max_recursion_limit likewise clamped the ceiling to 1). - The five llm_call integers coerced similarly: retry_max_attempts as `true` disabled retries, max_concurrent_calls as `true` serialized the pipeline. All seven integer fields now fail configuration loading with a field-specific error, while valid integers and numeric strings keep their existing behavior. Mirrors the loop-detection helper (#6017) and the in-file circuit-breaker validator. Signed-off-by: yetuge <2219677952@qq.com> * docs(changelog): record the app-config boolean rejection Changelog entries for #6171, mirroring the #6017 entry format in both languages. Signed-off-by: yetuge <2219677952@qq.com> * test(config): pin the False-side coercion regression in the boolean guards Per review: the tests only exercised `True`. On the `ge=1` fields `false` already failed the constraint pre-fix, but on the `ge=0` fields (`max_concurrent_calls`, the two delay fields) `false` coerced silently to the harmless-looking `0`, disabling the concurrency cap with no error. Parametrize both boolean tests over `[True, False]` to lock that regression in as well. Signed-off-by: yetuge <2219677952@qq.com> --------- Signed-off-by: yetuge <2219677952@qq.com>
52 lines
1.9 KiB
Python
52 lines
1.9 KiB
Python
"""YAML booleans must not coerce into the integer thresholds in app_config.
|
|
|
|
`config.yaml` legitimately mixes booleans (`enabled: true`) with integer knobs on
|
|
neighbouring lines, so a typo like `recursion_limit: true` loads cleanly — and
|
|
Pydantic coerces it to `1`, which for the recursion limit means every Gateway run
|
|
dies at the first LangGraph super-step. Mirrors the loop-detection and circuit
|
|
breaker guards already in the repo.
|
|
"""
|
|
|
|
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
from deerflow.config.app_config import AppConfig, LlmCallConfig
|
|
from deerflow.config.sandbox_config import SandboxConfig
|
|
|
|
LLM_CALL_INT_FIELDS = (
|
|
"max_concurrent_calls",
|
|
"retry_max_attempts",
|
|
"retry_base_delay_ms",
|
|
"retry_cap_delay_ms",
|
|
"burst_retry_base_delay_ms",
|
|
)
|
|
|
|
|
|
def _app_config(**overrides: object) -> AppConfig:
|
|
return AppConfig(sandbox=SandboxConfig(use="local"), **overrides)
|
|
|
|
|
|
@pytest.mark.parametrize("value", [True, False])
|
|
@pytest.mark.parametrize("field", LLM_CALL_INT_FIELDS)
|
|
def test_llm_call_config_rejects_boolean_integers(field: str, value: bool) -> None:
|
|
with pytest.raises(ValidationError, match="must be an integer, not a boolean"):
|
|
LlmCallConfig(**{field: value})
|
|
|
|
|
|
def test_llm_call_config_keeps_numeric_inputs() -> None:
|
|
config = LlmCallConfig(max_concurrent_calls="4", retry_max_attempts=3)
|
|
assert config.max_concurrent_calls == 4
|
|
assert config.retry_max_attempts == 3
|
|
|
|
|
|
@pytest.mark.parametrize("value", [True, False])
|
|
@pytest.mark.parametrize("field", ["recursion_limit", "max_recursion_limit"])
|
|
def test_recursion_limits_reject_booleans(field: str, value: bool) -> None:
|
|
with pytest.raises(ValidationError, match="must be an integer, not a boolean"):
|
|
_app_config(**{field: value})
|
|
|
|
|
|
def test_recursion_limits_keep_numeric_inputs() -> None:
|
|
config = _app_config(recursion_limit="25")
|
|
assert config.recursion_limit == 25
|