Location params on best_local_bid / latest_prices (zip / GPS + radius)
CI / test (push) Successful in 17s
CI / build-push (push) Successful in 6s

Thread zip/lat/lng/radius_miles through the client and both tools; friendly
guard for the zip-XOR-gps rule. Formatters surface distance, the searched
center, and the nearest-source hint when nothing is in range.

- client: best()/latest() take zip/lat/lng/radius_miles
- server: location params + docstrings (note Ohio-concentrated coverage)
- format: distance column + center/nearest rendering
- README + CHANGELOG + advisor prompt library updated
- tests: location formatting cases

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 07:51:54 -04:00
parent ae15aa5c3c
commit fb50c103d3
7 changed files with 245 additions and 31 deletions
+48
View File
@@ -3,6 +3,54 @@
Notes for clients/agents that consume the ag-bids MCP tools and the underlying
`ag-monitor` `/api/data/*` HTTP API. Newest first.
## 2026-05-31 — Location-aware bid lookup (zip / GPS + radius)
`best_local_bid` and `latest_prices` can now be scoped to a farmer's location, so
"where should I haul today" means *near me*, not "across every elevator we
scrape." Filtering is offline (vendored US Census ZIP centroids — no geocoding
API).
### Changed MCP tools
- **`best_local_bid(commodity, zip?, lat?, lng?, radius_miles?)`** — pass a
**`zip`** OR **`lat`+`lng`** (not both) with optional **`radius_miles`**
(default **50**) to restrict to nearby elevators; the result shows the
**distance** to the winner. With no location it behaves as before (all
sources). If nothing is in range it returns no winner **and reports the
nearest elevator + its distance**, so a coverage gap reads as a gap, not an
error.
- **`latest_prices(..., zip?, lat?, lng?, radius_miles?)`** — same location
filter; rows are limited to the radius, annotated with **`distance_miles`**,
and sorted **nearest-first** (adds a Distance column).
GPS input is reverse-labeled to its nearest ZIP for display; only `zip → coord`
is used for the actual distance math.
> **Coverage note:** scraped **cash-bid** sources are currently concentrated in
> **Ohio**. A zip/GPS far from Ohio (e.g. Iowa) will correctly return "nothing in
> range" with the nearest-source hint until more regions are added. (Reference
> data — `price_trend`, `input_cost_trend` — is already national.)
### API
- `GET /api/data/best?commodity=&zip=&lat=&lng=&radius_miles=` — new location
params. Response adds `center` (`{lat,lng,zip,source}`), `radius_miles`, and
(when out of range) `nearest`. `best` now carries `distance_miles`, `city`,
`state`.
- `GET /api/data/latest?...&zip=&lat=&lng=&radius_miles=` — same params; rows
carry `distance_miles` and source `city`/`state`/`latitude`/`longitude`;
response adds `center` + `radius_miles` when a location is given.
- Errors (HTTP 400): zip *and* GPS together, partial GPS, `radius_miles` with no
location, or an unknown zip.
### Example questions → tool calls
| Ask | Call |
|---|---|
| Best corn bid within 40 mi of my zip | `best_local_bid(commodity="corn", zip="45810", radius_miles=40)` |
| Best soybean bid near my coordinates | `best_local_bid(commodity="soy", lat=40.79, lng=-83.81)` |
| Elevators near me, nearest first | `latest_prices(commodity="corn", zip="45810", radius_miles=60)` |
## 2026-05-30 — Regional fertilizer input costs (real $/ton + change)
Real U.S. **regional retail fertilizer prices** now feed the input-cost tools,