feat(skills): consolidate find-nearby into maps as a single location skill
find-nearby and the (new) maps optional skill both used OpenStreetMap's Overpass + Nominatim to answer the same question — 'what's near this location?' — so shipping both would be duplicate code for overlapping capability. Consolidate into one active-by-default skill at skills/productivity/maps/ that is a strict superset of find-nearby. Moves + deletions: - optional-skills/productivity/maps/ → skills/productivity/maps/ (active, no install step needed) - skills/leisure/find-nearby/ → DELETED (fully superseded) Upgrades to maps_client.py so it covers everything find-nearby did: - Overpass server failover — tries overpass-api.de then overpass.kumi.systems so a single-mirror outage doesn't break the skill (new overpass_query helper, used by both nearby and bbox) - nearby now accepts --near "<address>" as a shortcut that auto-geocodes, so one command replaces the old 'search → copy coords → nearby' chain - nearby now accepts --category (repeatable) for multi-type queries in one call (e.g. --category restaurant --category bar), results merged and deduped by (osm_type, osm_id), sorted by distance, capped at --limit - Each nearby result now includes maps_url (clickable Google Maps search link) and directions_url (Google Maps directions from the search point — only when a ref point is known) - Promoted commonly-useful OSM tags to top-level fields on each result: cuisine, hours (opening_hours), phone, website — instead of forcing callers to dig into the raw tags dict SKILL.md: - Version bumped 1.1.0 → 1.2.0, description rewritten to lead with capability surface - New 'Working With Telegram Location Pins' section replacing find-nearby's equivalent workflow - metadata.hermes.supersedes: [find-nearby] so tooling can flag any lingering references to the old skill External references updated: - optional-skills/productivity/telephony/SKILL.md — related_skills find-nearby → maps - website/docs/reference/skills-catalog.md — removed the (now-empty) 'leisure' section, added 'maps' row under productivity - website/docs/user-guide/features/cron.md — find-nearby example usages swapped to maps - tests/tools/test_cronjob_tools.py, tests/hermes_cli/test_cron.py, tests/cron/test_scheduler.py — fixture string values swapped - cli.py:5290 — /cron help-hint example swapped Not touched: - RELEASE_v0.2.0.md — historical record, left intact E2E-verified live (Nominatim + Overpass, one query each): - nearby --near "Times Square" --category restaurant --category bar → 3 results, sorted by distance, all with maps_url, directions_url, cuisine, phone, website where OSM had the tags All 111 targeted tests pass across tests/cron/, tests/tools/, tests/hermes_cli/.
This commit is contained in:
@@ -1024,7 +1024,7 @@ class TestRunJobSkillBacked:
|
||||
"id": "multi-skill-job",
|
||||
"name": "multi skill test",
|
||||
"prompt": "Combine the results.",
|
||||
"skills": ["blogwatcher", "find-nearby"],
|
||||
"skills": ["blogwatcher", "maps"],
|
||||
}
|
||||
|
||||
fake_db = MagicMock()
|
||||
@@ -1057,12 +1057,12 @@ class TestRunJobSkillBacked:
|
||||
assert error is None
|
||||
assert final_response == "ok"
|
||||
assert skill_view_mock.call_count == 2
|
||||
assert [call.args[0] for call in skill_view_mock.call_args_list] == ["blogwatcher", "find-nearby"]
|
||||
assert [call.args[0] for call in skill_view_mock.call_args_list] == ["blogwatcher", "maps"]
|
||||
|
||||
prompt_arg = mock_agent.run_conversation.call_args.args[0]
|
||||
assert prompt_arg.index("blogwatcher") < prompt_arg.index("find-nearby")
|
||||
assert prompt_arg.index("blogwatcher") < prompt_arg.index("maps")
|
||||
assert "Instructions for blogwatcher." in prompt_arg
|
||||
assert "Instructions for find-nearby." in prompt_arg
|
||||
assert "Instructions for maps." in prompt_arg
|
||||
assert "Combine the results." in prompt_arg
|
||||
|
||||
|
||||
|
||||
@@ -54,12 +54,12 @@ class TestCronCommandLifecycle:
|
||||
deliver=None,
|
||||
repeat=None,
|
||||
skill=None,
|
||||
skills=["find-nearby", "blogwatcher"],
|
||||
skills=["maps", "blogwatcher"],
|
||||
clear_skills=False,
|
||||
)
|
||||
)
|
||||
updated = get_job(job["id"])
|
||||
assert updated["skills"] == ["find-nearby", "blogwatcher"]
|
||||
assert updated["skills"] == ["maps", "blogwatcher"]
|
||||
assert updated["name"] == "Edited Job"
|
||||
assert updated["prompt"] == "Revised prompt"
|
||||
assert updated["schedule_display"] == "every 120m"
|
||||
@@ -95,7 +95,7 @@ class TestCronCommandLifecycle:
|
||||
deliver=None,
|
||||
repeat=None,
|
||||
skill=None,
|
||||
skills=["blogwatcher", "find-nearby"],
|
||||
skills=["blogwatcher", "maps"],
|
||||
)
|
||||
)
|
||||
out = capsys.readouterr().out
|
||||
@@ -103,5 +103,5 @@ class TestCronCommandLifecycle:
|
||||
|
||||
jobs = list_jobs()
|
||||
assert len(jobs) == 1
|
||||
assert jobs[0]["skills"] == ["blogwatcher", "find-nearby"]
|
||||
assert jobs[0]["skills"] == ["blogwatcher", "maps"]
|
||||
assert jobs[0]["name"] == "Skill combo"
|
||||
|
||||
@@ -192,23 +192,23 @@ class TestUnifiedCronjobTool:
|
||||
result = json.loads(
|
||||
cronjob(
|
||||
action="create",
|
||||
skills=["blogwatcher", "find-nearby"],
|
||||
skills=["blogwatcher", "maps"],
|
||||
prompt="Use both skills and combine the result.",
|
||||
schedule="every 1h",
|
||||
name="Combo job",
|
||||
)
|
||||
)
|
||||
assert result["success"] is True
|
||||
assert result["skills"] == ["blogwatcher", "find-nearby"]
|
||||
assert result["skills"] == ["blogwatcher", "maps"]
|
||||
|
||||
listing = json.loads(cronjob(action="list"))
|
||||
assert listing["jobs"][0]["skills"] == ["blogwatcher", "find-nearby"]
|
||||
assert listing["jobs"][0]["skills"] == ["blogwatcher", "maps"]
|
||||
|
||||
def test_multi_skill_default_name_prefers_prompt_when_present(self):
|
||||
result = json.loads(
|
||||
cronjob(
|
||||
action="create",
|
||||
skills=["blogwatcher", "find-nearby"],
|
||||
skills=["blogwatcher", "maps"],
|
||||
prompt="Use both skills and combine the result.",
|
||||
schedule="every 1h",
|
||||
)
|
||||
@@ -220,7 +220,7 @@ class TestUnifiedCronjobTool:
|
||||
created = json.loads(
|
||||
cronjob(
|
||||
action="create",
|
||||
skills=["blogwatcher", "find-nearby"],
|
||||
skills=["blogwatcher", "maps"],
|
||||
prompt="Use both skills and combine the result.",
|
||||
schedule="every 1h",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user