Skip to content

fix(community): reject bool and fractional web-search max_results like image search does - #5852

Merged
WillemJiang merged 1 commit into
bytedance:mainfrom
Lesereingrape:fix/ddg-web-max-results-guard
Sep 25, 2026
Merged

WillemJiang merged 1 commit into
bytedance:mainfrom
Lesereingrape:fix/ddg-web-max-results-guard

Conversation

@Lesereingrape

Copy link
Copy Markdown
Contributor

Why

README.md (the DDG search section) already documents the contract for both DDG tools:

For DDG web search and DDG image search, max_results in config.yaml can be a positive integer or an environment-variable reference such as max_results: $DDG_MAX_RESULTS … Invalid values (for example, abc, an empty string, or 3.5), zero, and negative counts produce a warning and fall back to the default of 5 results.

The image-search copy honours it: #5807 added a bool/fractional guard to _coerce_max_results in community/image_search/tools.py:19-21. The web-search copy, introduced by #5792, never got it — on origin/main (174c6f7f) it is still:

try:
    count = int(value)
except (TypeError, ValueError, OverflowError):
    count = 0

int() accepts both of the YAML-native shapes the README promises to reject, so web_search silently narrows the result set instead of warning and falling back:

max_results in config.yaml web_search on main image_search on main documented
3.5 3 results, no warning 5 + warning 5 + warning
true 1 result, no warning 5 + warning 5 + warning
"3.5", abc, "", 0, -2, [] 5 + warning 5 + warning 5 + warning

(Verified with yaml.safe_load: max_results: 3.5 is a float and max_results: true is a bool, so both reach the helper uncoerced — this is not a string-only path.)

What changed

  • backend/packages/harness/deerflow/community/ddg_search/tools.py — port the two-line guard from the image-search sibling into _coerce_max_results, so a bool or a non-integral float falls into the existing "invalid → warn + default" branch instead of being truncated by int().
  • backend/tests/test_ddg_search_tools.py — add the fractional-config and boolean-config rows to the existing parametrize table, mirroring the ids already used by tests/test_image_search.py:91-92.

Surface area

One private helper, one call site: web_search_tool reads config.model_extra.get("max_results", …) (tools.py:193) and passes it through _coerce_max_results before _search_text (tools.py:200). Integral floats such as 4.0 and numeric strings keep their current behaviour, so nothing that is valid today changes.

Bug fix verification

The two new rows are red on unmodified origin/main (174c6f7f):

$ python -m pytest tests/test_ddg_search_tools.py -k "fractional-config or boolean-config"
E  AssertionError: assert 3 == 5   # fractional-config
E  AssertionError: assert 1 == 5   # boolean-config
2 failed, 29 deselected

and green with the guard applied: 31 passed.

Validation

  • pytest tests/test_ddg_search_tools.py → 31 passed
  • pytest tests/test_ddg_search_tools.py tests/test_image_search.py tests/test_web_search_time_range.py tests/test_remote_search.py → 75 passed, 10 skipped
  • ruff check and ruff format --check on both changed files → clean
  • I did not run the full make test suite locally; the search-related files above are what I exercised.

AI assistance

This change was drafted and verified by an AI coding agent (Qoder CLI agent) on my machine: the reproduction, the RED/GREEN runs and the port of the sibling guard were all executed locally, and the diff was reviewed by the agent rather than by a second human.

  • I confirm that a human reviewer independently reviewed every line of this diff before submission.

@github-actions github-actions Bot added risk:medium Medium risk: regular code changes size/XS PR changes < 20 lines labels Sep 25, 2026
@WillemJiang WillemJiang added this to the 2.2.0 milestone Sep 25, 2026
@WillemJiang
WillemJiang merged commit 63401d7 into bytedance:main Sep 25, 2026
16 checks passed
hawkli-1994 pushed a commit to rongxinzy/deer-flow that referenced this pull request Sep 27, 2026
Winoren added a commit to Winoren/deer-flow that referenced this pull request Oct 15, 2026
Serper keeps a private _coerce_max_results in the pre-bytedance#5852 shape: a bare
int() silently turns max_results: true into 1 and 3.5 into 3, and an invalid
value falls back without a warning (bytedance#5865).

Delegate to deerflow.community.search_max_results.coerce_max_results, which
owns what invalid means for the folded providers, and keep Serper's
10-result cap at the call site the way You.com does, because clamping policy
is deliberately per-provider.

Invalid configured counts now warn under the Serper label and fall back to
the default instead of being silently coerced.
WillemJiang pushed a commit that referenced this pull request Oct 16, 2026
…6966)

Serper keeps a private _coerce_max_results in the pre-#5852 shape: a bare
int() silently turns max_results: true into 1 and 3.5 into 3, and an invalid
value falls back without a warning (#5865).

Delegate to deerflow.community.search_max_results.coerce_max_results, which
owns what invalid means for the folded providers, and keep Serper's
10-result cap at the call site the way You.com does, because clamping policy
is deliberately per-provider.

Invalid configured counts now warn under the Serper label and fall back to
the default instead of being silently coerced.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:medium Medium risk: regular code changes size/XS PR changes < 20 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants