Skip to content

fix(agent): port QWeather to ToolBase so it works as an Agent tool - #16692

Merged
yuzhichang merged 1 commit into
infiniflow:mainfrom
boskodev790:fix/qweather-agent-tool-port
Jul 13, 2026
Merged

fix(agent): port QWeather to ToolBase so it works as an Agent tool#16692
yuzhichang merged 1 commit into
infiniflow:mainfrom
boskodev790:fix/qweather-agent-tool-port

Conversation

@boskodev790

Copy link
Copy Markdown
Contributor

Summary

Port the QWeather agent tool to the modern ToolBase / _invoke interface. It was still written against the removed legacy ComponentBase / _run / be_output API, so it was non-functional as an Agent tool — adding it to an Agent raised AttributeError because it had no get_meta(). This is the same defect that was fixed for the AkShare tool in #16417.

Changes

  • QWeatherParam now extends ToolParamBase with a meta exposing a query (location) parameter, and adds get_input_form(). Existing config (web_apikey, lang, type, user_type, time_period) is preserved.
  • QWeather now extends ToolBase and implements _invoke(**kwargs) with the standard retry loop, cancellation checks, set_output("formalized_content", ...), and thoughts(). The weather / indices / air-quality branches and the API error-code messages are kept.
  • Added test/unit_test/agent/component/test_qweather.py covering the restored meta, param validation, the weather-now and multi-day and indices branches, the empty-query short-circuit, and the location-lookup error message.

Testing

  • ruff check agent/tools/qweather.py test/unit_test/agent/component/test_qweather.py — clean
  • ruff format --check — clean
  • pytest test/unit_test/agent/component/test_qweather.py

QWeather still extended the legacy ComponentBase/_run/be_output API that was
removed in the agent redesign, so adding it to an Agent raised AttributeError
(it had no get_meta()) and it was non-functional as a tool -- the same defect
fixed for AkShare in infiniflow#16417.

- QWeatherParam now extends ToolParamBase with a meta exposing a `query`
  (location) parameter and a get_input_form().
- QWeather now extends ToolBase and implements _invoke(**kwargs) with the
  standard retry loop, cancellation checks, set_output("formalized_content"),
  and thoughts(); config (api key, lang, type, time_period) is preserved.
- Add test/unit_test/agent/component/test_qweather.py covering the restored
  meta, param validation, the weather/indices branches, empty-query
  short-circuit, and API-error messaging.
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jul 7, 2026
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The QWeather tool component is refactored from ComponentBase to ToolBase architecture, changing _run to _invoke with a retry loop, cancellation checks, and centralized error handling via _error_message/_finish. String-based output replaces the prior pandas DataFrame approach. Unit tests are added covering param validation, meta schema, and invoke scenarios.

Changes

QWeather ToolBase Migration

Layer / File(s) Summary
Tool param schema and validation
agent/tools/qweather.py
QWeatherParam now extends ToolParamBase with meta-based query schema; API key validation error message updated to reference "QWeather API key".
Invoke execution and error handling
agent/tools/qweather.py
_run replaced by _invoke with timeout decoration, retry loop, cancellation checks, city lookup, weather/indices/airquality branching, and _error_message/_finish helpers; DataFrame output replaced with string formatting.
Unit tests for param and invoke
test/unit_test/agent/component/test_qweather.py
New tests cover param instantiation/validation, meta schema exposure, and _invoke scenarios for successful weather lookup, empty query, and location lookup errors, using stubbed tool construction and mocked HTTP responses.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant QWeather
  participant GeoAPI
  participant WeatherAPI

  Caller->>QWeather: _invoke(query)
  QWeather->>GeoAPI: lookup location
  GeoAPI-->>QWeather: location result
  alt lookup failed
    QWeather->>QWeather: _error_message(code)
    QWeather->>QWeather: _finish(error content)
  else lookup succeeded
    QWeather->>WeatherAPI: fetch weather/indices/airquality
    WeatherAPI-->>QWeather: data
    QWeather->>QWeather: _finish(formatted content)
  end
  QWeather-->>Caller: content
Loading

Suggested labels: 🐞 bug

Poem

A rabbit hopped through code so bright,
Swapped old clouds for a ToolBase light 🌤️
Retry loops spin, errors caught with care,
No more DataFrames floating in the air,
Tests all green, my whiskers twitch with glee! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main change: porting QWeather to ToolBase for Agent use.
Description check ✅ Passed The description includes the required Summary plus useful context, changes, and testing details.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (2)
agent/tools/qweather.py (2)

130-133: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Pass location via params= instead of string concatenation to avoid query-parameter injection.

location is model/user-supplied and is concatenated directly into the query string. While requests percent-encodes spaces/non-ASCII, it does not encode reserved characters like &/=, so a value such as Beijing&key=... could inject or override query parameters. Passing structured params lets requests encode each value safely (applies to the weather/indices/air URLs at Lines 145, 156, 166 as well).

♻️ Example fix for the geo lookup
-                lookup = requests.get(
-                    url="https://geoapi.qweather.com/v2/city/lookup?location=" + location + "&key=" + self._param.web_apikey,
-                    timeout=DEFAULT_TIMEOUT,
-                ).json()
+                lookup = requests.get(
+                    url="https://geoapi.qweather.com/v2/city/lookup",
+                    params={"location": location, "key": self._param.web_apikey},
+                    timeout=DEFAULT_TIMEOUT,
+                ).json()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent/tools/qweather.py` around lines 130 - 133, The QWeather request URLs
are building query strings by concatenating the user-supplied location directly,
which can allow query-parameter injection. Update the request construction in
the lookup flow and the other QWeather helpers that build weather, indices, and
air URLs to use requests.get(..., params=...) instead of string concatenation,
passing location and the API key as structured parameters so requests handles
encoding safely.

184-184: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Avoid assert False; raise or return explicitly.

Under python -O this assertion is stripped, so the function silently returns None on the fall-through path (reachable if max_retries is negative). Prefer an explicit return of the current output or an AssertionError.

♻️ Proposed change
-        assert False, self.output()
+        raise AssertionError(self.output())
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agent/tools/qweather.py` at line 184, The fall-through path in the retry
logic uses an assert to signal an impossible state, but that can be stripped
under optimized Python and silently return None. Update the relevant fallback in
qweather.py (the retry/response handling around self.output()) to use an
explicit raise AssertionError or return the current output directly, and ensure
the behavior is defined even when max_retries is negative.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@agent/tools/qweather.py`:
- Around line 130-133: The QWeather request URLs are building query strings by
concatenating the user-supplied location directly, which can allow
query-parameter injection. Update the request construction in the lookup flow
and the other QWeather helpers that build weather, indices, and air URLs to use
requests.get(..., params=...) instead of string concatenation, passing location
and the API key as structured parameters so requests handles encoding safely.
- Line 184: The fall-through path in the retry logic uses an assert to signal an
impossible state, but that can be stripped under optimized Python and silently
return None. Update the relevant fallback in qweather.py (the retry/response
handling around self.output()) to use an explicit raise AssertionError or return
the current output directly, and ensure the behavior is defined even when
max_retries is negative.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f5f798d0-534a-4d99-a41d-fec4818c217b

📥 Commits

Reviewing files that changed from the base of the PR and between 9eba452 and 46f960a.

📒 Files selected for processing (2)
  • agent/tools/qweather.py
  • test/unit_test/agent/component/test_qweather.py

@yuzhichang
yuzhichang self-requested a review July 12, 2026 12:23

@yuzhichang yuzhichang left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jul 13, 2026
@yuzhichang yuzhichang added the ci Continue Integration label Jul 13, 2026
@yuzhichang
yuzhichang merged commit 80a7a87 into infiniflow:main Jul 13, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci Continue Integration lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants