git:20260926.17f4722 to git:20261011.d5e0a0a

19 added, 0 removed. Audit A to A.

# Tavily tools
The client helper selects credentials by tool name: search defaults to
`web_search`, fetch passes `web_fetch`, and an omitted key uses the SDK's
`TAVILY_API_KEY` fallback. Keep credential regressions in `backend/tests/test_tavily_tools.py`
on the real helper and SDK constructor, mocking only search/extract calls.
Each tool owns its per-call async client and awaits `close()` in `finally`,
including request failures and cancellation. Lifecycle regressions exercise
the real SDK connection pool without network requests.
Search forwards `include_domains` and `exclude_domains` only when present in
the `web_search` tool config's `model_extra`, alongside `max_results` and optional
`time_range`. Preserve explicit empty lists (no restriction of that kind) and
omit absent keys. These are deployment-only search-source settings; keep the
model-visible signature limited to `query` and `time_range`. Offline regressions
in `backend/tests/test_tavily_tools.py` pin SDK arguments and the tool schema.
For non-empty `include_domains`, explicitly send `include_domains_mode="filter"`
through the SDK's keyword arguments; inclusion must restrict sources rather than
boost them. Omit the mode when the include list is absent or empty.
+ Validate the HTTP-success payload before normalizing it. A top-level that is not an
+ object, a `results`/`failed_results` container that is not a list, or a non-empty
+ list whose entries hold no objects is a format error, not a legitimate empty result:
+ search returns the structured `{"error": ..., "query": ...}` response and fetch
+ returns the `Error: ...` string. Non-object entries are skipped while valid objects
+ are preserved in order, and missing or null search leaf fields (`title`, `url`,
+ `content`) normalize to empty text. A missing, null, or empty `results` keeps
+ search's `[]` and fetch's "Error: No results found"; a failed extraction whose object has no `error`
+ message reports "Error: Extraction failed". `web_fetch` coerces non-string
+ `raw_content` to text before truncating to 4096 characters. Log the malformed
+ container's name and type, or that no usable result objects remain, before
+ returning — never the query, URL, credentials, or payload values.
+
+ `backend/tests/test_tavily_response_shapes.py` drives the real tools and the real
+ AsyncTavilyClient through an offline HTTPX MockTransport; non-object top-level
+ payloads stub the client because the SDK's public wrappers reject that shape before
+ the tools see it. Cover null search fields individually and together, and mixed
+ fetch lists so the first retained object supplies the result or extraction error.
+