d1eefe6acc
When the chosen/keyed backend fails a web_search or web_extract call (bad key, upstream outage, 5xx, raised exception), that single call retries on the keyless free-tier ring instead of erroring. The next call attempts the chosen backend again — no sticky failover, no state. Resolves the keyed half of #78984/#32159 (keyless half landed in the ring PR). - tools/web_tools.py: _rescue_eligible (keyed ring vendors + non-ring backends eligible; keyless-mode calls excluded — they already walked the ring), _rescue_search/_rescue_extract (search annotates rescued_from + backend_error naming the original failure and the retry-next-call semantics; extract rescues only whole-batch failures, partial failures pass through untouched; rescue failure preserves the ORIGINAL backend error with the rescue note appended) - both dispatchers wrap the provider call: failure-results AND raised exceptions rescue; ineligible paths re-raise unchanged - web.keyless_rescue config key (default true; implicitly off when keyless_fallback is off); docs updated Live E2E: keyed Tavily with an invalid key 401'd and the call was served by the real ring with the rescue annotation; a second call re-attempted Tavily first (statelessness proven); whole-batch extract rescue returned real page content. 13 new tests; 67 green across the keyless suites.