feat(tools): add WeatherTool with wttr.in integration (#4104)
Implements the Weather integration as a native Rust Tool trait
implementation, consistent with the existing first-party tool
architecture (no WASM/plugin layer required).
- Add src/tools/weather_tool.rs with full WeatherTool impl
- Fetches from wttr.in ?format=j1 (no API key, global coverage)
- Supports city names (any language/script), IATA airport codes,
GPS coordinates, postal/zip codes, domain-based geolocation
- Metric (°C, km/h, mm) and imperial (°F, mph, in) units
- Current conditions + 0-3 day forecast with hourly breakdown
- Graceful error messages for unknown/invalid locations
- Respects runtime proxy config via apply_runtime_proxy_to_builder
- 36 unit tests: schema, URL building, param validation, formatting
- Register WeatherTool unconditionally in all_tools_with_runtime
(no API key needed, no config gate — same pattern as CalculatorTool)
- Flip integrations registry Weather entry from ComingSoon to Available
Closes #<issue>
This commit is contained in:
committed by
Roman Tataurov
parent
94d5cea577
commit
e2e1278efb
@@ -155,6 +155,13 @@ fn show_integration_info(config: &Config, name: &str) -> Result<()> {
|
||||
println!(" Schedule tasks in ~/.zeroclaw/workspace/cron/");
|
||||
println!(" Run: zeroclaw cron list");
|
||||
}
|
||||
"Weather" => {
|
||||
println!(" Built-in:");
|
||||
println!(" Fetches live conditions from wttr.in — no API key required.");
|
||||
println!(" Supports city names, IATA airport codes, GPS coordinates,");
|
||||
println!(" postal/zip codes, and Unicode location names.");
|
||||
println!(" Ask the agent: \"What's the weather in Tulsa?\"");
|
||||
}
|
||||
"Webhooks" => {
|
||||
println!(" Built-in:");
|
||||
println!(" HTTP endpoint for external triggers.");
|
||||
|
||||
@@ -672,7 +672,7 @@ pub fn all_integrations() -> Vec<IntegrationEntry> {
|
||||
name: "Weather",
|
||||
description: "Forecasts & conditions",
|
||||
category: IntegrationCategory::ToolsAutomation,
|
||||
status_fn: |_| IntegrationStatus::ComingSoon,
|
||||
status_fn: |_| IntegrationStatus::Active,
|
||||
},
|
||||
IntegrationEntry {
|
||||
name: "Canvas",
|
||||
@@ -995,7 +995,7 @@ mod tests {
|
||||
fn shell_and_filesystem_always_active() {
|
||||
let config = Config::default();
|
||||
let entries = all_integrations();
|
||||
for name in ["Shell", "File System"] {
|
||||
for name in ["Shell", "File System", "Weather"] {
|
||||
let entry = entries.iter().find(|e| e.name == name).unwrap();
|
||||
assert!(
|
||||
matches!((entry.status_fn)(&config), IntegrationStatus::Active),
|
||||
|
||||
Reference in New Issue
Block a user