Turning IP Geolocation on changed nothing: every lookup failed, and the
tool output still said "no Location is set in preferences", which is a
different problem and sent the user looking in the wrong place.
ipapi.co no longer serves an unauthenticated caller. Verified directly:
no User-Agent -> HTTP 429 {"reason":"RateLimited",
"message":"Please sign up for a paid plan"}
browser UA -> HTTP 403, a Cloudflare "Just a moment..." challenge
So the provider is now ipwho.is, which answers 200 without a key. It
signals refusal with success: false on an HTTP 200, so the body is checked
as well as the status, and it nests the timezone under an object, which the
parser now accepts alongside a bare string. A named User-Agent is sent:
node's default is bare, and "who is asking" is the one thing a geolocation
provider has a fair interest in.
The failure branch is also fixed. A failed lookup and an unset preference
are different problems, and the wording no longer conflates them. The note
tells the model to pass the failure on, because the model is the only
channel that reaches the user and it had been paraphrasing the failure away.
Accuracy is documented honestly rather than as "city-level". An IP locates
the ISP's egress, not the person: measured from one machine, an IPv4 query
resolved to Cebu City and an IPv6 query moments later to Talisay in
Calabarzon, about 500km apart. That is now in the README, the preference
description and the tool output, and it is the argument for setting
Location instead.
Verified live with the exact request and field access the extension uses:
HTTP 200, "Talisay, Calabarzon (Region IV-A), Philippines", Asia/Manila.
344 tests, tsc, eslint, prettier, and vici build.
Adds the one thing the extension could not answer before: roughly where
the user actually is, rather than which zone their clock is set to.
- `lib/geo.ts` resolves a place from ipapi.co. Chosen because it is HTTPS
and needs no API key; ip-api.com, the other obvious free option, is
HTTP-only on its free tier, which is not a place to send an IP address.
- Off by default, and skipped entirely when the user has set Location: the
better answer is already there, so spending their privacy on a worse one
would be indefensible. `ipPlace` is only wired into ToolContext when the
preference is on, so an off setting cannot reach the network at all.
- Cached for 6 hours. A city does not change between questions, and every
lookup hands the provider another copy of the address. Set Up Lam Agent
clears it on re-test, alongside the vision cache.
- Failures are returned, not swallowed: a rate limit or an offline machine
says so in the tool output while the region answer stays available. The
provider signals some failures with error: true and HTTP 200, so the body
is checked as well as the status.
- The tool output always names the provider and calls the result city-level
rather than exact. It also flags an IP timezone that disagrees with the
device clock, which usually means a VPN.
- The README claimed no geolocation service ever saw the user's address.
That is now conditional, so the section was rewritten rather than left to
quietly become untrue.
Deliberately not done: GPS. CoreLocation has no CLI on macOS and GeoClue's
usual provider resolves nearby Wi-Fi through a Mozilla service anyway.
Verified: 341 tests (25 new), tsc, eslint, prettier, and vici build. I did
not make a live API call, because doing so would send this machine's IP to
the provider as the exact flow being opted into.