Skip to content

fix(community): initialize InfoQuest TLS clients off the event loop - #7899

Merged
WillemJiang merged 5 commits into
bytedance:mainfrom
BlueX888:fix/infoquest-tls-offloop
Nov 6, 2026
Merged

WillemJiang merged 5 commits into
bytedance:mainfrom
BlueX888:fix/infoquest-tls-offloop

Conversation

@BlueX888

@BlueX888 BlueX888 commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Why

InfoQuest's fetch, web_search_raw_results and image_search_raw_results constructed httpx.AsyncClient inline in their coroutines. httpx builds the default transport in AsyncClient.__init__, and that synchronously loads the TLS trust store (~125 ms per call in a local probe) on the agent event loop. Requests were already asynchronous; only setup was blocking.

RAGFlow and LightRAG (#7738) and You.com, GroundRoute and Webz (#7889) already construct their clients with asyncio.to_thread. The #7738 review explicitly named infoquest/infoquest_client.py:82 among the remaining clients and suggested a follow-up; #7889 was limited to its three adapters. InfoQuest migrated to httpx.AsyncClient in #5782, before both sweeps.

What changed

  • All three InfoQuest client-construction sites now use async with await asyncio.to_thread(httpx.AsyncClient, follow_redirects=True) as client:, matching the merged siblings. Endpoints, headers, payloads, timeouts, redirects, error paths and response handling are unchanged; requests and async with cleanup stay on the event loop.
  • backend/tests/blocking_io/test_search_client_ssl.py gains a parametrized regression for all three methods: it asserts TLS context creation runs off the loop thread, send runs on it, and the client is closed exactly once.
  • backend/AGENTS.md:139 and README.md:253 now list InfoQuest among the providers that initialize HTTPX clients off-loop.

Surface area

Backend harness runtime (community search provider); no API shape, response, or valid-call behavior change. It adds one executor dispatch per request, the same trade-off the merged siblings carry.

Verification

From backend/:

  • pytest tests/blocking_io/test_search_client_ssl.py -q → 8 passed.
  • Parent a46d9221 with the new test → 3 failed, 5 passed; each fails with AssertionError: TLS trust loading blocks the event loop (for fetch, the provider catches the exception and returns Error: fetch API failed: TLS trust loading blocks the event loop...).
  • pytest tests/blocking_io/test_search_client_ssl.py tests/test_infoquest_client.py tests/test_infoquest_http_timeout.py -q → 75 passed.
  • Thread probe against the real methods: ssl.create_default_context on a worker thread (on_loop=False); send and transport __aexit__ on the loop (on_loop=True).
  • ruff check / ruff format --check clean; scripts/check_agent_guidance.py --base-ref a46d9221 --head-ref 0116d6cd exits 0 (only pre-existing soft-chain warnings).
  • Independent review reran red/green and the probe in a separate worktree; 5 repeat runs of the new test were stable.

AI assistance

Tool(s) used: Claude Code

How you used it: AI reproduced the event-loop TLS load, wrote the regression test (red on parent) and the to_thread change, and ran the verification above. An independent review reran the red/green and thread probe in a separate worktree.

  • I've read and understand every line of this change and take responsibility for it — it's not unreviewed AI output.

🤖 Generated with Claude Code

InfoQuest's fetch, web search and image search constructed
httpx.AsyncClient inline in their coroutines, so the default transport
loaded the TLS trust store synchronously on the agent event loop
(~125 ms per call in a local probe). RAGFlow, LightRAG, You.com,
GroundRoute and Webz already construct their clients with
asyncio.to_thread; InfoQuest was the missed sibling.

Move the three constructions to asyncio.to_thread and cover all three
methods in the blocking-I/O TLS test. Requests, cleanup, timeouts and
responses stay on the event loop.

Co-Authored-By: Claude Code <[email protected]>
@github-actions github-actions Bot added area:docs Documentation and Markdown only risk:medium Medium risk: regular code changes size/S PR changes 20-100 lines labels Nov 4, 2026

@willem-bd willem-bd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extends (does not duplicate) the merged #7889 sweep to the remaining InfoQuest sites: all three client constructions (fetch, web_search_raw_results, image_search_raw_results) now build httpx.AsyncClient via asyncio.to_thread, offloading the synchronous TLS trust-store load while keeping requests and async with cleanup on the loop — the same semantics as #7889 and #7738, with no endpoint/header/timeout changes. The regression test is well designed: it asserts TLS context creation happens off the loop thread, send runs on it, exactly one client is used, and it is closed, and assert contexts would also catch a hypothetical lazy-context regression since send is fully replaced. One non-blocking note on the doc line below.

Comment thread backend/AGENTS.md Outdated
Read-only knowledge: [contract](docs/KNOWLEDGE.md) covers independent retrieval
tools, scope intersection and extension-owned providers.
HTTPX clients for RAGFlow, LightRAG, You.com, GroundRoute and Webz use
HTTPX clients for RAGFlow, LightRAG, You.com, GroundRoute, Webz and InfoQuest use

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit/suggestion (pre-existing, out of scope for this PR): the enumerated list reads as exhaustive, but at this head several other community providers still construct httpx.AsyncClient inline on the event loop — crawl4ai/crawl4ai_client.py:35, jsonify/tools.py:116, searxng/searxng_client.py:144, browserless/browserless_client.py:145 and :235, jina_ai/jina_client.py:129 and :192. Since this PR is itself a straggler recovered from the #7738/#7889 sweeps, a follow-up sweep (or a qualifying phrase like "among others") would stop the list from implying completion. No change required here.

The list is not exhaustive; several community clients still construct
their client inline. Use non-exhaustive wording until the follow-up
sweep lands.

Co-Authored-By: Claude Code <[email protected]>
@BlueX888

BlueX888 commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

Good point — qualified the list in e4378292 ("several community providers, including ...") so it no longer reads as exhaustive. The remaining clients you named are verified and prepared as a separate follow-up sweep; I'll open it once this lands.

@BlueX888

BlueX888 commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

CI note: the backend-unit-tests (1) failure is a main-branch regression, not this patch. test_repository_guidance_chains_fit_hard_budget reports AG002 for backend/packages/harness/deerflow/agents/memory/AGENTS.md: the effective AGENTS chain is 98,313 bytes vs the 98,304-byte hard limit. #7906 (merged 2026-11-05T06:24Z) added 4 lines to backend/AGENTS.md; this PR does not touch AGENTS docs. Re-running after the chain is trimmed should clear it.

@BlueX888

BlueX888 commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Fixed a docs slip from the last main merge in 044983f: the conflict resolution re-listed Browserless as not yet migrated and dropped Crawl4AI from the migrated list, plus left a broken sentence boundary. backend/AGENTS.md now reads: Crawl4AI, Browserless and InfoQuest use asyncio.to_thread; jsonify, SearXNG and Jina are the remaining list. Docs-only, no code change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:docs Documentation and Markdown only risk:medium Medium risk: regular code changes size/S PR changes 20-100 lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants