{"ok":true,"site":{"host":"glassmap.clyeh.xyz","url":"https://glassmap.clyeh.xyz/#v1.eyJjIjpbMTIxLjUxNzUsMjUuMDQ3OF0sInoiOjEyfQ","type":"live","desc":"An agent-native web map: WebMCP turns the map canvas into a semantic surface.","tools":[{"name":"get_map_state","kind":"answer","impl":"imperative","description":"Read the current map view: camera (center, zoom, bearing, pitch), the visible bounds, how many features are loaded, the selection, and everything drawn or noted on the map by either side. Every count is exact; the lists are capped (selection.ids at 20, drawings.items and annotations.items at the ten most recent each, annotation notes at 80 characters). features_loaded counts everything searchable, including any point-of-interest category fetched this session, which tier2.loaded names once there is one. Use this instead of a screenshot to know what the map shows. The page keeps its agent chrome hidden until an agent acts, and the human can also open or close that chrome by hand at any time - so bounds always describes the rectangle actually on screen right now: narrowed while the inspector lane is up, full-width while the chrome is closed, and the same rectangle list_features_in_view tests against either way.","annotations":{"readOnlyHint":true,"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"set_map_view","kind":"act","impl":"imperative","description":"Move the map camera. Give a place name or a feature id to jump to something by name, fit to frame something whole, or center/zoom/bearing/pitch to position the camera directly. place and feature_id fly to the thing at zoom 15, or keep the current zoom when it is already closer than that - going to a place never zooms you out; pass zoom to say otherwise. fit takes a drawing id or a feature id and frames that thing against what is currently on screen: an area (a district, a park, a circle or a route) is fitted so all of it is visible, which can zoom OUT when the thing is bigger than the view, while a target with no extent - a point of interest, a pinned note - behaves exactly like feature_id. fit needs the map to have rendered once; before that it answers \"map not ready\" rather than guessing how much you can see. Returns the new map state, so no follow-up read is needed.","annotations":{"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"center":{"type":"object","properties":{"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in degrees."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in degrees."}},"required":["lng","lat"],"additionalProperties":false,"description":"Exact camera centre. Cannot be combined with place or feature_id."},"zoom":{"type":"number","minimum":0,"maximum":22,"description":"Zoom level: 10 shows a city, 15 a neighbourhood, 18 a building. With place or feature_id it defaults to 15 without ever zooming out past the current view - the closer of the two wins - so pass zoom to override, including to pull back. Cannot be combined with fit, which decides its own zoom."},"bearing":{"type":"number","description":"Map rotation in degrees clockwise from north; 0 is north-up."},"pitch":{"type":"number","minimum":0,"maximum":85,"description":"Camera tilt in degrees; 0 looks straight down."},"place":{"type":"string","description":"Name of a place in the loaded data, e.g. \"Daan Station\". Station suffixes are optional. If several places match equally well the map does not move and the answer lists candidates to choose from. Like every place name, it needs the base data the page loads on open; before that it answers \"map data not ready\" rather than guessing, and asking again works."},"feature_id":{"type":"string","description":"Id of a loaded feature, e.g. \"osm:node:123\". Use this instead of place when you already have an id, or to resolve an ambiguous place."},"fit":{"type":"string","description":"Frame this whole thing: a drawing id as draw_shape returns and map state lists (\"drawing:1\", including a shape the human drew by hand), or the id of a loaded feature (\"district:daan\", \"osm:way:10\"). An area is fitted to what is on screen and may zoom out to get all of it in; a target with no extent behaves exactly like feature_id, at any starting zoom - the two paths share one rule. Cannot be combined with center, place or feature_id, and not with zoom either - the fit is what decides the zoom."}},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"list_features_in_view","kind":"answer","impl":"imperative","description":"List the loaded features whose bounding box overlaps the current view, nearest to the centre of the view first, each with its distance in metres and an 8-point compass direction from that centre, which comes back as origin. The test is a bounding-box overlap, so a large area counts as in view when any part of it is. This is how you describe what is on screen without taking a screenshot. Pass query to search the screen by text - the same match find_features makes, scoped to what is in view, and combining with categories rather than replacing it, so \"which of the cafes on screen is a Louisa?\" is one call. Called without categories it also returns category_counts - how many of each category the answer covers, which is the same set features and total describe, so with a query only the features that matched it are counted - and, when there are point-of-interest categories it has not fetched, unsearched_categories with their city-wide totals.","annotations":{"readOnlyHint":true,"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"query":{"type":"string","description":"Case-insensitive substring of the local or English name, brand, cuisine, or address. A result may have matched on a field the list does not echo; get_place_details shows all of a feature's tags. Only the features already in view are searched; omit to list every feature in view. Combines with categories instead of replacing it."},"categories":{"type":"array","minItems":1,"items":{"type":"string","enum":["mrt_station","park","school","supermarket","listing","district","restaurant","cafe","fast_food","bakery","bar","convenience","pharmacy","clinic","hospital","place_of_worship","bank","hotel","parking","bicycle_rental","library","museum","post_office","police"]},"description":"Which categories to search. Always in memory: mrt_station, park, school, supermarket, listing, district. Points of interest, fetched for the whole city the first time you name one and kept for the rest of the session: restaurant, cafe, fast_food, bakery, bar, convenience, pharmacy, clinic, hospital, place_of_worship, bank, hotel, parking, bicycle_rental, library, museum, post_office, police. Naming a category is how you search it - there is no way to search all of them at once. Omit this and the search covers the always-in-memory categories plus the points of interest fetched earlier in this session; the answer then lists what it did not search under unsearched_categories, with how many exist city-wide."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Maximum number of features to return (default 20, max 100). The \"total\" field reports how many matched in all."}},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"find_features","kind":"answer","impl":"imperative","description":"Search every loaded feature, not only the visible ones. Filter by text (name, brand, cuisine or address), category, distance from a place, a feature or a coordinate (up to 10000 m), and by whether a feature is inside a shape on the map - including one the human drew by hand. Results come back nearest first, each with its distance in metres and an 8-point compass direction from that origin, which is echoed as origin - together with radius_m when near or radius_m limited the search. Naming a point-of-interest category (restaurant, cafe, pharmacy and so on) fetches it for the whole city on first use and then searches all of it, wherever the map happens to be pointing; searching without categories answers from what is already loaded and lists the rest under unsearched_categories. With query, the answer also carries unloaded_matches when the same text matches in point-of-interest categories this session has not fetched: {category, count} for each, biggest first, at most 6 of them (unloaded_matches_omitted counts any further ones). This is how a search that returned nothing can still tell you where the matches are - the count is city-wide, matched on the same name, brand, cuisine and address fields this tool matches once a category is loaded, so call find_features again with that category in categories to load it and get the features. Nothing is fetched on your behalf: naming the category is still your call.","annotations":{"readOnlyHint":true,"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"query":{"type":"string","description":"Case-insensitive substring of the local or English name, brand, cuisine, or address. A result may have matched on a field the list does not echo; get_place_details shows all of a feature's tags. Omit to match every name."},"categories":{"type":"array","minItems":1,"items":{"type":"string","enum":["mrt_station","park","school","supermarket","listing","district","restaurant","cafe","fast_food","bakery","bar","convenience","pharmacy","clinic","hospital","place_of_worship","bank","hotel","parking","bicycle_rental","library","museum","post_office","police"]},"description":"Which categories to search. Always in memory: mrt_station, park, school, supermarket, listing, district. Points of interest, fetched for the whole city the first time you name one and kept for the rest of the session: restaurant, cafe, fast_food, bakery, bar, convenience, pharmacy, clinic, hospital, place_of_worship, bank, hotel, parking, bicycle_rental, library, museum, post_office, police. Naming a category is how you search it - there is no way to search all of them at once. Omit this and the search covers the always-in-memory categories plus the points of interest fetched earlier in this session; the answer then lists what it did not search under unsearched_categories, with how many exist city-wide."},"near":{"description":"Origin for distances and for the radius filter: a feature id returned by an earlier call (e.g. \"osm:node:123\"), a place name to look up in the loaded data (e.g. \"Daan Station\"), or an explicit coordinate. Omit to measure from the centre of the current view.","anyOf":[{"type":"string","description":"A feature id, or the name of a station, park or district. A name needs the base data the page loads on open; before that it answers \"map data not ready\" rather than guessing, and asking again works."},{"type":"object","properties":{"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in degrees."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in degrees."}},"required":["lng","lat"],"additionalProperties":false,"description":"Explicit coordinate."}]},"radius_m":{"type":"number","exclusiveMinimum":0,"maximum":10000,"description":"Keep only features within this many metres of \"near\" (default 800 when \"near\" is given, no radius filter otherwise, at most 10000). A larger radius is refused rather than quietly narrowed. Measured to a feature point, or to the centroid of an area."},"within":{"type":"string","description":"\"drawing:<n>\" - restrict results to features inside that drawing, as returned by draw_shape or listed in map state under drawings (the ten most recent; drawings.count is the true total). A circle or polygon works; a line has no inside. Combines with the other filters instead of replacing them."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Maximum number of features to return (default 20, max 100). The \"total\" field reports how many matched in all."}},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"select_features","kind":"act","impl":"imperative","description":"Highlight features on the map and in the sidebar so a sighted person can see what you are talking about. Pass explicit ids (from find_features, list_features_in_view or describe_surroundings), or the same query/near/radius_m (at most 10000 m)/categories/within filter as find_features — the filter resolves to the same set of features, but unlike find_features it does not stop at the limit: every match is selected, and state.selection.count reports the true number. Pass an empty ids array to clear the selection. Returns the resulting selection and the new map state; selected lists at most 20 of them. A filter that matches more than 500 point-of-interest features is refused rather than highlighting half a city: the answer gives the true count, and near + radius_m, within or query narrows it. On a page opened from a share link whose point-of-interest categories are still loading, the ids that belong to them stay selected and come back in pending_ids instead of selected: they are not lost, and state.tier2.loading names what is still arriving.","annotations":{"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string"},"maxItems":100,"description":"Feature ids to select, as returned by find_features or list_features_in_view (at most 100; use the filter instead for larger sets). An empty array clears the selection. Ids that are not loaded are reported in unknown_ids instead of failing the call - except while a share link's categories are still loading, where an id they may contain is kept, selected and reported in pending_ids."},"query":{"type":"string","description":"Case-insensitive substring of the local or English name, brand, cuisine, or address. A result may have matched on a field the list does not echo; get_place_details shows all of a feature's tags. Exactly as in find_features."},"near":{"description":"Origin for distances and for the radius filter: a feature id returned by an earlier call (e.g. \"osm:node:123\"), a place name to look up in the loaded data (e.g. \"Daan Station\"), or an explicit coordinate. Omit to measure from the centre of the current view.","anyOf":[{"type":"string","description":"A feature id, or the name of a station, park or district. A name needs the base data the page loads on open; before that it answers \"map data not ready\" rather than guessing, and asking again works."},{"type":"object","properties":{"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in degrees."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in degrees."}},"required":["lng","lat"],"additionalProperties":false,"description":"Explicit coordinate."}]},"radius_m":{"type":"number","exclusiveMinimum":0,"maximum":10000,"description":"Keep only features within this many metres of \"near\" (default 800 when \"near\" is given, no radius filter otherwise, at most 10000). A larger radius is refused rather than quietly narrowed. Measured to a feature point, or to the centroid of an area."},"within":{"type":"string","description":"\"drawing:<n>\" - restrict results to features inside that drawing, as returned by draw_shape or listed in map state under drawings (the ten most recent; drawings.count is the true total). A circle or polygon works; a line has no inside. Combines with the other filters instead of replacing them."},"categories":{"type":"array","minItems":1,"items":{"type":"string","enum":["mrt_station","park","school","supermarket","listing","district","restaurant","cafe","fast_food","bakery","bar","convenience","pharmacy","clinic","hospital","place_of_worship","bank","hotel","parking","bicycle_rental","library","museum","post_office","police"]},"description":"Which categories to search. Always in memory: mrt_station, park, school, supermarket, listing, district. Points of interest, fetched for the whole city the first time you name one and kept for the rest of the session: restaurant, cafe, fast_food, bakery, bar, convenience, pharmacy, clinic, hospital, place_of_worship, bank, hotel, parking, bicycle_rental, library, museum, post_office, police. Naming a category is how you search it - there is no way to search all of them at once. Omit this and the search covers the always-in-memory categories plus the points of interest fetched earlier in this session; the answer then lists what it did not search under unsearched_categories, with how many exist city-wide."},"replace":{"type":"boolean","description":"true (the default) replaces the current selection; false adds to it."}},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"draw_shape","kind":"act","impl":"imperative","description":"Draw a circle, a polygon or a line on the map, so the human can see the area you are talking about. A circle takes a centre (a coordinate, a feature id or a place name) and a radius in metres; a polygon and a line take a list of [lng, lat] points. Returns the drawing id plus its area in square metres (circle, polygon) or its length in metres (line), and the new map state. Pass the id to find_features({within}) or select_features({within}) to ask what is inside it. Shapes the human drew by hand appear in the same list with source \"user\" and can be queried the same way.","annotations":{"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"type":{"type":"string","enum":["circle","polygon","line"],"description":"circle: centre plus radius_m. polygon: a closed area from coordinates. line: a route or a measurement from coordinates."},"center":{"description":"Circle only: where the circle is centred. A coordinate, a feature id from an earlier call, or a place name such as \"Daan Station\". If a name matches several places the map is left alone and the answer lists the candidates.","anyOf":[{"type":"string","description":"A feature id, or the name of a station, park or district. A name needs the base data the page loads on open; before that it answers \"map data not ready\" rather than guessing, and asking again works."},{"type":"object","properties":{"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in degrees."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in degrees."}},"required":["lng","lat"],"additionalProperties":false,"description":"Explicit coordinate."}]},"radius_m":{"type":"number","exclusiveMinimum":0,"maximum":10000,"description":"Circle only: radius in metres (default 800, a comfortable walk; at most 10000). A larger radius is refused rather than shrunk, so what you draw is always what you asked for."},"coordinates":{"type":"array","minItems":2,"maxItems":500,"items":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"number"},"description":"One point as [lng, lat] in degrees."},"description":"Polygon or line only: the points, as [lng, lat] pairs. A polygon needs at least 3 distinct points and is closed for you if you do not repeat the first one; a line needs at least 2. At most 500 points."},"label":{"type":"string","maxLength":80,"description":"Short name shown on the map and in map state, e.g. \"10-minute walk\" (at most 80 characters)."}},"required":["type"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"plan_route","kind":"act","impl":"imperative","description":"Plan a walk between two places and draw it on the map as a line the human can see. Walking only: the route is on foot, and there is no driving, cycling or transit profile here. It comes from the OpenStreetMap-based routing service run by FOSSGIS (routing.openstreetmap.de), which is the one thing on this map fetched at the moment you ask: when it cannot answer, nothing is drawn, the map is unchanged and the answer says so plainly rather than guessing a line. Both ends take the same three forms as anywhere else - a coordinate, a feature id from an earlier call, or a place name. Returns the drawing id, the service's own distance in metres and duration in seconds, both ends as it resolved them, and the new map state. What it leaves behind is an ordinary drawing: measure gives its length and remove_from_map takes it off again. A line has no inside, so find_features({within}) and select_features({within}) cannot be asked what is inside a route - measure it for its length, or draw a circle somewhere along it to ask what is near it. A route with more points than the map can redraw is simplified, and simplified says so; distance_m is always the service's figure for the real walk, not the drawn line's.","annotations":{"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"from":{"description":"Where the walk starts: a coordinate, a feature id such as \"osm:node:123\", or a place name such as \"Daan Station\". If a name matches several places nothing is drawn and the answer lists the candidates.","anyOf":[{"type":"string","description":"A feature id, or the name of a station, park or district. A name needs the base data the page loads on open; before that it answers \"map data not ready\" rather than guessing, and asking again works."},{"type":"object","properties":{"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in degrees."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in degrees."}},"required":["lng","lat"],"additionalProperties":false,"description":"Explicit coordinate."}]},"to":{"description":"Where the walk ends, in any of the same three forms as from.","anyOf":[{"type":"string","description":"A feature id, or the name of a station, park or district. A name needs the base data the page loads on open; before that it answers \"map data not ready\" rather than guessing, and asking again works."},{"type":"object","properties":{"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in degrees."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in degrees."}},"required":["lng","lat"],"additionalProperties":false,"description":"Explicit coordinate."}]},"label":{"type":"string","maxLength":80,"description":"Short name shown on the map and in map state (at most 80 characters). Omit it and the walk is named after the two places, e.g. \"walk: 大安 → 台北車站\"."}},"required":["from","to"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"annotate","kind":"act","impl":"imperative","description":"Pin a short note to a place on the map, so the human sees what you found where you found it. The location can be a coordinate, a feature id from an earlier call, or a place name. Returns the annotation id and the new map state; map state lists notes with their first 80 characters and says whether the agent or the human wrote each one.","annotations":{"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"at":{"description":"Where to pin the note: a coordinate, a feature id such as \"osm:node:123\", or a place name such as \"Daan Station\". If a name matches several places nothing is pinned and the answer lists the candidates.","anyOf":[{"type":"string","description":"A feature id, or the name of a station, park or district. A name needs the base data the page loads on open; before that it answers \"map data not ready\" rather than guessing, and asking again works."},{"type":"object","properties":{"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in degrees."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in degrees."}},"required":["lng","lat"],"additionalProperties":false,"description":"Explicit coordinate."}]},"note":{"type":"string","minLength":1,"maxLength":500,"description":"The note itself, at most 500 characters. One or two sentences a human can read on the map, not a paragraph."},"icon":{"type":"string","maxLength":24,"description":"Optional short marker label or emoji, e.g. \"star\" (at most 24 characters)."}},"required":["at","note"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"remove_from_map","kind":"act","impl":"imperative","description":"Take something off the map: a shape or a note an agent put there, or a feature out of the highlighted selection. Ids come in three forms and can be mixed in one call - \"drawing:<n>\" and \"annotation:<n>\", as map state lists them under drawings and annotations, and the id of a currently selected feature such as \"osm:node:123\". This never deletes map data. Features and places cannot be removed; naming a selected feature only takes it out of the highlight. Taking a shape or a note off the map is permanent: there is no undo, and the only way back is to draw or pin it again. Shapes and notes the human made themselves - source \"user\" in map state - are not removed: they come back under refused, and the human takes their own mark off by tapping it on the map and pressing Remove. Everything else in the same call still happens. No per-id problem fails the batch: what could not be removed is accounted for by name under refused (with one refused_reason for all of them), not_selected (a loaded feature that was not highlighted, so there was nothing to take out), unknown_ids, and malformed_ids with one malformed_error saying which forms do work. Returns what was removed and the new map state, so no follow-up read is needed.","annotations":{"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"ids":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string"},"description":"What to take off the map, in any mix of the three forms: \"drawing:<n>\" for a shape, \"annotation:<n>\" for a note, or the id of a currently selected feature, which leaves the selection and stays on the map (at most 100; repeats count once). There is no \"remove everything\": an empty array is refused, and clearing the highlight is select_features({ids: []})."}},"required":["ids"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"describe_surroundings","kind":"answer","impl":"imperative","description":"Describe what is around a point the way a person would say it out loud: the district it is in, and the nearby features grouped by compass direction, nearest first, each with its feature id, name and distance in metres. Pass an id straight to select_features or set_map_view to act on something you just described. Use this to answer \"what is around me?\" or \"what is near this listing?\" without a screenshot. When from named an id or a place, name is the place it resolved to, so you can check it is the one you meant. total is how many features are inside radius_m, returned is how many are described (at most 30, the nearest ones): when total is larger, narrow radius_m or use find_features with a category filter - widening the radius will not reveal the ones that were left out.","annotations":{"readOnlyHint":true,"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"from":{"description":"Where to look from: a coordinate, a feature id from an earlier call, or a place name. Omit to describe the surroundings of the centre of the current view.","anyOf":[{"type":"string","description":"A feature id, or the name of a station, park or district. A name needs the base data the page loads on open; before that it answers \"map data not ready\" rather than guessing, and asking again works."},{"type":"object","properties":{"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in degrees."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in degrees."}},"required":["lng","lat"],"additionalProperties":false,"description":"Explicit coordinate."}]},"radius_m":{"type":"number","exclusiveMinimum":0,"maximum":10000,"description":"How far to look, in metres (default 500, roughly a five-minute walk; at most 10000)."},"categories":{"type":"array","minItems":1,"items":{"type":"string","enum":["mrt_station","park","school","supermarket","listing","district","restaurant","cafe","fast_food","bakery","bar","convenience","pharmacy","clinic","hospital","place_of_worship","bank","hotel","parking","bicycle_rental","library","museum","post_office","police"]},"description":"Which categories to describe. Always in memory: mrt_station, park, school, supermarket, listing, district. Points of interest, fetched for the whole city the first time you name one and kept for the rest of the session: restaurant, cafe, fast_food, bakery, bar, convenience, pharmacy, clinic, hospital, place_of_worship, bank, hotel, parking, bicycle_rental, library, museum, post_office, police. Naming a category is how you search it - there is no way to search all of them at once. Omit this and the answer describes mrt_station, park, school, supermarket, listing plus the points of interest fetched earlier in this session, and lists what it did not describe under unsearched_categories with how many exist city-wide; district is never described, because the district you are standing in is its own field."}},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"compare_areas","kind":"answer","impl":"imperative","description":"Compare two places in one call: how many features of each category are within radius_m of a, how many are within radius_m of b, and the nearest one of each category on each side. Both places are given the same way as anywhere else - a feature id, a place name such as \"Zhongshan Station\", or a coordinate - and both are counted with exactly the filter find_features uses, so the numbers match what a per-category search would return. Read \"summary\" out; use by_category to reason and its feature ids to act (select_features, set_map_view). A point of interest tagged as two categories - a bakery that also serves fast food - is counted under each of them, exactly as both of their find_features queries return it, so by_category can add up to slightly more than total, which counts places. This replaces one find_features call per category per place.","annotations":{"readOnlyHint":true,"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"a":{"description":"The first place: a feature id from an earlier call, a place name such as \"Daan Park Station\", or an explicit coordinate. If a name matches several places nothing is counted and the answer lists the candidates.","anyOf":[{"type":"string","description":"A feature id, or the name of a station, park or district. A name needs the base data the page loads on open; before that it answers \"map data not ready\" rather than guessing, and asking again works."},{"type":"object","properties":{"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in degrees."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in degrees."}},"required":["lng","lat"],"additionalProperties":false,"description":"Explicit coordinate."}]},"b":{"description":"The second place, in any of the same three forms as a.","anyOf":[{"type":"string","description":"A feature id, or the name of a station, park or district. A name needs the base data the page loads on open; before that it answers \"map data not ready\" rather than guessing, and asking again works."},{"type":"object","properties":{"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in degrees."},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in degrees."}},"required":["lng","lat"],"additionalProperties":false,"description":"Explicit coordinate."}]},"radius_m":{"type":"number","exclusiveMinimum":0,"maximum":10000,"description":"How far around each place to count, in metres (default 800, a comfortable walk; at most 10000). The same radius is used on both sides - that is what makes the two counts comparable. A larger radius is refused rather than quietly narrowed."},"categories":{"type":"array","minItems":1,"items":{"type":"string","enum":["mrt_station","park","school","supermarket","listing","district","restaurant","cafe","fast_food","bakery","bar","convenience","pharmacy","clinic","hospital","place_of_worship","bank","hotel","parking","bicycle_rental","library","museum","post_office","police"]},"description":"Which categories to count. Always in memory: mrt_station, park, school, supermarket, listing, district. Points of interest, fetched for the whole city the first time you name one and kept for the rest of the session: restaurant, cafe, fast_food, bakery, bar, convenience, pharmacy, clinic, hospital, place_of_worship, bank, hotel, parking, bicycle_rental, library, museum, post_office, police. Naming a category is how you search it - there is no way to search all of them at once. Omit this and the answer counts mrt_station, park, school, supermarket, listing plus the points of interest fetched earlier in this session, and lists what it did not count under unsearched_categories with how many exist city-wide; district is never counted, because it is a property of a place rather than something near it."}},"required":["a","b"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"measure","kind":"act","impl":"imperative","description":"Measure one thing on the map and get whole metres back: a shape drawn by you or by the human (\"drawing:1\", the ids map state lists under drawings), or a loaded feature (an id from find_features, list_features_in_view or describe_surroundings). A line answers with length_m; a circle or a polygon with area_m2 and perimeter_m. A point has a location but no extent, so measuring one is refused - ask find_features for distances instead.","annotations":{"readOnlyHint":true,"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"target":{"type":"string","description":"What to measure: a drawing id such as \"drawing:1\" (yours or the human's) or a feature id such as \"osm:way:123\". Names are not accepted; look the place up with find_features first and pass the id it returns."}},"required":["target"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"get_place_details","kind":"answer","impl":"imperative","description":"Everything this map holds about one place, for the questions a list answer is too lean to carry: opening hours, phone, address, website, wheelchair, and whatever its kind of place is tagged with - a hotel's star rating, a car park's fee and capacity, a pharmacy's dispensing, a place of worship's religion and denomination, a hospital's emergency department. Takes one feature id per call, as returned by find_features, list_features_in_view, describe_surroundings or select_features: those answer with a name, a category and a distance for many places, and this answers with one place in full, including its coordinate and every category it is tagged in. Every field comes from OpenStreetMap and exists only where a contributor entered it, so a field that is absent means nobody has recorded it - not that the place has none; say it that way round, and expect most places to carry only some of them. \"wheelchair\" is the OSM tag as tagged (yes, no or limited): report it as what OpenStreetMap says, never as a verified accessibility claim, and tell the human to ring ahead if it matters. Shapes and notes on the map are not places - use measure for a drawing's size and get_map_state for what is drawn or noted.","annotations":{"readOnlyHint":true,"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"id":{"type":"string","description":"The feature id to look up, e.g. \"osm:node:123\" - one per call, exactly as an earlier answer spelled it. A point-of-interest id only resolves once its category has been loaded, which is what naming that category in find_features or select_features does."}},"required":["id"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"get_share_link","kind":"answer","impl":"imperative","description":"Build a link that reproduces this map for whoever opens it: the camera, the selection, every shape and every note, plus the names of any point-of-interest categories loaded this session so the other side loads the same data and the selected places resolve there too, all encoded in the URL itself. Nothing is uploaded and no account is needed - the state travels inside the link, so the person who opens it sees the map you are looking at now, with the human's own drawings still marked as theirs. Give the URL to the human as a URL, so they can send it on. Returns the url and its size in bytes. A map carrying very large hand-drawn shapes can exceed the byte limit a URL has to stay under; then there is no url, only an error saying what to remove. If \"omitted\" comes back, that many shapes or notes could not be encoded and are not in the link - say so rather than promising a complete map.","annotations":{"readOnlyHint":true},"inputSchema":{"type":"object","properties":{},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"add_note","kind":"act","impl":"declarative","description":"Pin a note to the current map centre","inputSchema":{"type":"object","properties":{"note":{"type":"string","description":"e.g. quiet street, good light"}},"required":["note"]},"__source":"spec","__declarative":true}],"category":"Travel & Events","favicon":"/favicons/glassmap.clyeh.xyz.ico","apiSurface":"spec","toolCount":15}}