Skip to content
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

### New Features

- **`render_map_tool`: results carousel at the bottom of the map instead of the side list (#292).** Search results and id-bearing markers now show as a row of swipeable cards along the bottom, like the place results in ChatGPT, instead of the 280 px list on the right, which covered much of an inline map or started collapsed below 560 px wide. Each card has the place's name, category, distance and popularity, its photo once loaded, and a second line with today's hours (from Place Details `opening_hours`) and phone number.
- **Place pins instead of orange numbers:** places are white pins with a [Maki](https://github.com/mapbox/maki) icon for their category (the Maki name Search Box gives each result, or one matched from the category, falling back to a plain marker), like ChatGPT's place results. About 20 common icons are inlined (about 12 KB). A caller's color tints the icon. Numbered badges stay for markers whose number means something: a caller's `style: "numbered"` with a `label` (a visit order), optimized trip stops, and route start/end.
- **Card and pin stay in sync:** the selected card gets a border, and its pin turns black (a numbered badge turns white), comes to the front and shows the place's name under it. The first card starts selected. Swiping selects whichever card ends up in the middle, clicking a card selects it, and clicking a pin scrolls to its card. Picking a card or a pin moves the map only when the pin or its name label is off screen or behind the cards, and then only far enough to show them.
- **No popups on carousel pins:** a pin with a card no longer opens a popup, so the phone number moved from the popup to the card. Pins without an id (route ends, waypoints) keep their popups.
- **Hours:** parsed from the OSM-style `opening_hours` string for simple rules (`Mo-Fr 07:00-19:00; Sa,Su 08:00-17:00`, `Su off`, `24/7`, several ranges a day). Anything more complex (holidays, months) shows no hours rather than wrong ones. "Today" is the viewer's day, which can differ from the place's near midnight across time zones.
- **Layout:** the cards sit 36 px up so the Mapbox logo and attribution stay visible, the legend moves up above them, and the map fits its data above both. The collapse toggle and the right-hand fit padding are gone. The zoom buttons move down below the summary chip ("6 results for …") while it shows, instead of sitting under it (same fix as #278).
- **OpenAI's [UI guidelines](https://developers.openai.com/plugins/concepts/ui-guidelines):** every card has a picture (the place's icon on a muted tile until a photo loads, or when there is none), labeled with the place's name for screen readers. Numbered badges pick dark or white numbers by contrast with the badge color (WCAG). The tool description asks the model not to list the places again after rendering, since the cards already show them.
- **Light and dark:** the cards, summary chip, legend and messages follow the host's theme (MCP Apps `hostContext.theme`, at start and on `host-context-changed`), or the system's `prefers-color-scheme` when the host sends none. Colors come from the host's style variables (`--color-background-primary`, `--color-text-primary` and so on) when it sends them, so the cards match the chat around them. The map, its pins and their name labels look the same in both.
- Tool and resource descriptions now say "carousel" instead of "panel". Dedupe across merged payloads, the batched Place Details lookup and photo loading are unchanged.

- **`feedback_tool`: report wrong map, place or routing data to Mapbox (#291).** When someone says a place has closed, a road is closed, or a route took an illegal turn, the agent can send it to the [Feedback API](https://docs.mapbox.com/api/feedback/) (`POST /user-feedback/v1/feedback`, Public Preview) with the text, a category and the location, usually taken from an earlier search or directions result. It returns the report's id and status (`received`).
- **Confirm first:** the report goes to Mapbox under the user's account, so the description tells the model to show the user what it will send and get a yes. Clients that support elicitation also get a confirmation prompt from the tool itself. Declining sends nothing, and so does a failed prompt.
- **Categories:** an enum of the Feedback Agent's default categories that make sense from chat (`poi_closed`, `poi_details`, `road_closure_issue`, `illegal_turn` and so on), leaving out the navigation-app ones such as voice guidance and rerouting.
Expand Down
4 changes: 2 additions & 2 deletions src/resources/place-photo/PlacePhotoResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const lookupAll: LookupHost = async (hostname) =>

/**
* A POI's first Place Details photo, proxied through the server for the map
* app's results panel.
* app's results carousel.
*
* Place Details photos are hosted wherever the business's own site hosts
* them (Yext, Webflow and so on), so the map app's CSP can't list their
Expand All @@ -67,7 +67,7 @@ export class PlacePhotoResource extends MapboxApiBasedResource {
readonly uri = `${URI_PREFIX}{id}`;
readonly name = 'Mapbox Place Photo';
readonly description =
"The first photo of a POI from Place Details, as an image, for the map app's results panel. " +
"The first photo of a POI from Place Details, as an image, for the map app's results carousel. " +
'Read with mapbox://place-photo/{mapbox_id}.';
readonly mimeType = 'image/jpeg';

Expand Down
2 changes: 1 addition & 1 deletion src/resources/resourceRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const ALL_RESOURCES = [
new ToolResponseResource({ httpRequest }),
// Single shared map renderer, targeted exclusively by render_map_tool.
new MapAppUIResource({ httpRequest }),
// Photos for the map app's results panel, which its CSP can't load directly.
// Photos for the map app's results carousel, which its CSP can't load directly.
new PlacePhotoResource({ httpRequest }),
new VersionResource()
] as const;
Expand Down
Loading
Loading