fix(agent/tools): surface serpapi error responses in google search (#17062)

### Summary

`agent/tools/google.py` indexes `search["organic_results"]` directly
after `GoogleSearch(params).get_dict()`. serpapi returns `{"error":
...}` **without** an `organic_results` key on realistic conditions — an
invalid API key, an exhausted plan/quota, or a query that matched
nothing. that raised `KeyError('organic_results')`, which the tool's
retry loop then surfaced to the model as the opaque `"Google error:
'organic_results'"` instead of the real reason.

this guards the missing key and raises serpapi's actual `error` message
(with a clear fallback) into the existing retry/`_ERROR` path, so the
model sees e.g. `"Google error: Invalid API key."`. valid responses are
unchanged.

adds `test/unit_test/agent/tools/test_google_unit.py` covering the
error-response path (asserts the real message is surfaced, no
`KeyError`) and the normal result path, mirroring the existing
`test_googlescholar.py` pattern (skips when the `serpapi` SDK is
absent).

---------

Co-authored-by: Yaroslav98214 <diakovichyaroslav30@gmail.com>
This commit is contained in:
Yurii214
2026-07-21 04:58:14 +02:00
committed by GitHub
parent 1c828daea1
commit 4f1820bcaa
2 changed files with 113 additions and 5 deletions
+15 -5
View File
@@ -498,13 +498,23 @@ class Google(ToolBase, ABC):
if self.check_if_canceled("Google processing"):
return
# serpapi reports an invalid key, exhausted quota or an empty result
# set through an "error" field and omits "organic_results"; surface that
# message instead of raising a cryptic KeyError on the missing key.
if "organic_results" not in search:
raise RuntimeError(search.get("error", "SerpApi returned no organic_results."))
organic_results = search["organic_results"]
# a result may omit any of these; note the fallback of the "description"
# lookup is evaluated eagerly, so it has to be a .get() too or a result
# carrying a description but no snippet raises KeyError.
self._retrieve_chunks(
search["organic_results"],
get_title=lambda r: r["title"],
get_url=lambda r: r["link"],
get_content=lambda r: r.get("about_this_result", {}).get("source", {}).get("description", r["snippet"]),
organic_results,
get_title=lambda r: r.get("title", ""),
get_url=lambda r: r.get("link", ""),
get_content=lambda r: r.get("about_this_result", {}).get("source", {}).get("description", r.get("snippet", "")),
)
self.set_output("json", search["organic_results"])
self.set_output("json", organic_results)
return self.output("formalized_content")
except Exception as e:
if self.check_if_canceled("Google processing"):