You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix the desktop trigger button in components/header-search-button.tsx so it enables in Google provider mode, matching the mobile button's provider-aware disabled condition.
Document NEXT_PUBLIC_GOOGLE_MAPS_API_KEY in .env.local.example, because the compare slider needs the Google Static Maps image.
Replace the silent Google Static Map failure with user-facing toasts, and continue with a single-image fallback instead of aborting.
Add onError image fallbacks in components/compare-slider.tsx to avoid blank/broken images.
File-Level Changes and Follow-Up Notes
components/header-search-button.tsx: Fix the desktop button disabled condition to guard map with mapProvider === 'mapbox'. In handleResolutionSearch, add toasts for a missing NEXT_PUBLIC_GOOGLE_MAPS_API_KEY and for a failed Google Static Map fetch, and keep the flow running with the available images.
.env.local.example: Add and document NEXT_PUBLIC_GOOGLE_MAPS_API_KEY.
components/compare-slider.tsx: Add onError fallbacks to both <img> elements using the existing placeholder image.
Follow-up instruction for the implementing agent:
First verify the fix by testing both provider modes on desktop: set mapProvider to 'mapbox' and to 'google', then confirm the search button is enabled and handleResolutionSearch fires in both.
Confirm that with a valid NEXT_PUBLIC_GOOGLE_MAPS_API_KEY, both mapboxImage and googleImage reach components/resolution-carousel.tsx and the CompareSlider slide renders.
Do not modify the resolution_search server action logic in app/actions.tsx or lib/agents/resolution-search.tsx; the exploration confirmed that branch is intact.
Ignore the stale root-level .patch files (chat-panel.patch, app_actions_diff.patch, layout.patch); they are already-applied or superseded and are not the cause of this regression.
Design ChoicesDesign Choice 1: Primary root cause of the regression
Options Considered:
The desktop trigger button is permanently disabled when the Google map provider is active, because its disabled condition requires the Mapbox map instance unconditionally.
The NEXT_PUBLIC_GOOGLE_MAPS_API_KEY is unset and undocumented, so the Google Static Map fetch is skipped silently, and the compare slider never gets its second image.
Chosen Option: 1
Rationale: Fix both defects: the desktop button condition and the missing key documentation. The compare slider needs both a working trigger and both images to render. Both defects fail silently today.
💡 User Tips
Regenerate the plan with different choices with @coderabbitai <feedback>.
Implementation Steps
Phase 1: Restore the trigger and its prerequisites
This phase restores the user's ability to start a resolution search and documents the configuration the compare slider needs. The goal is to make the trigger fire in all supported provider modes and to make the Google Static Maps requirement explicit.
Task 1: Fix the desktop search button disabled condition
The desktop trigger button is disabled whenever the Mapbox map instance is absent. When mapProvider === 'google', the Mapbox map is never mounted, so map stays null and the button never enables. This blocks the whole resolution-search flow on desktop in Google mode.
Update components/header-search-button.tsx.
Change the desktop button disabled condition to match the mobile button.
Require map only when mapProvider === 'mapbox' (for example, disabled={isAnalyzing || !actions || (mapProvider === 'mapbox' && !map)}).
Keep the mobile button condition unchanged, because it already has the provider-aware guard.
Task 2: Document the Google Static Maps API key requirement
The compare slider needs a Google image. components/header-search-button.tsx fetches it from the Google Static Maps API using NEXT_PUBLIC_GOOGLE_MAPS_API_KEY. This variable is not documented in any example env file, so it is likely unset in most environments, and the fetch is skipped silently.
Add NEXT_PUBLIC_GOOGLE_MAPS_API_KEY to .env.local.example.
State in a comment that this key is required for the Google Static Maps fetch and the compare slider, and that it is also used by components/map/google-map.tsx and lib/agents/tools/geospatial.tsx.
Do not add secrets. Add the variable name and an explanatory comment only.
🤖 Prompt for AI agents
Implement Phase 1: restore the resolution-search trigger and document its
required configuration.
1. In `components/header-search-button.tsx`, locate the desktop search button
and its `disabled` condition. Change the condition so it requires the Mapbox
`map` instance only when `mapProvider === 'mapbox'`. Use a condition such as
`disabled={isAnalyzing || !actions || (mapProvider === 'mapbox' && !map)}`.
Match this to the logic already used by the mobile button. Do not change the
mobile button condition.
2. In `.env.local.example`, add the `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY` variable
name with a comment. The comment must state that this key is required for the
Google Static Maps fetch used by the compare slider, and that it is also used by
`components/map/google-map.tsx` and `lib/agents/tools/geospatial.tsx`. Do not
add an actual secret value, only the variable name and comment.
Phase 2: Make image-capture failures visible and add resilience
This phase removes the silent failure modes that hide the compare slider. The goal is that a missing key or a failed image fetch produces a clear message and, where possible, a graceful fallback, instead of a quietly dropped slide.
Task 1: Surface Google Static Map fetch failures
In components/header-search-button.tsx, the Google Static Map fetch is wrapped in logic that only writes to console.error or skips when the key is missing. When this happens, googleBlob stays null, the compare slide is dropped, and the user sees no reason.
When NEXT_PUBLIC_GOOGLE_MAPS_API_KEY is missing, show a user-facing toast that explains the Google image is unavailable and the compare view will not appear.
When the Google Static Map fetch throws or returns a non-OK response, show a toast with a short error message.
Continue the resolution search with the available images (single-image fallback) rather than aborting the whole flow.
Task 2: Add image error fallback in the compare slider
components/compare-slider.tsx renders two <img> elements with no onError handling. A broken or expired image URL shows a blank area with no indication of failure. Other image components in the repo already use a placeholder fallback.
Update components/compare-slider.tsx.
Add onError handling to both <img> elements to fall back to the existing placeholder image (/images/placeholder-image.png), consistent with components/search-results-image.tsx.
Do not change the drag/slider behavior or the layout logic.
🤖 Prompt for AI agents
Implement Phase 2: remove silent failure modes around the resolution-search
image capture and add fallback handling for broken images.
1. In `components/header-search-button.tsx`, inside `handleResolutionSearch`,
add user-facing toasts:
- If `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY` is missing, show a toast that explains
the Google image is unavailable and the compare view will not appear.
- If the Google Static Map fetch throws an error or returns a non-OK response,
show a toast with a short error message.
- In both cases, continue the resolution search using the available images as a
single-image fallback. Do not abort the whole flow.
2. In `components/compare-slider.tsx`, add an `onError` handler to both `<img>`
elements. On error, fall back to the existing placeholder image at
`/images/placeholder-image.png`, consistent with the pattern in
`components/search-results-image.tsx`. Do not change the drag/slider behavior or
the layout logic.
Research
The app uses the Vercel AI SDK RSC streaming pattern. A submit server action in app/actions.tsx streams React components into a uiStream. The compare slider path is a dedicated action === 'resolution_search' branch, not an LLM tool. components/header-search-button.tsx is the client trigger. It captures the Mapbox canvas and fetches a Google Static Map image, then submits both as a FormData to the resolution_search action. app/actions.tsx renders components/resolution-carousel.tsx, which renders components/compare-slider.tsx only when both a Mapbox image and a Google image exist. The provider state lives in lib/store/settings.ts (mapProvider, default 'mapbox').
🚀 Next Steps
🤖 All AI agent prompts combined
Task: 1
Implement Phase 1: restore the resolution-search trigger and document its
required configuration.
1. In `components/header-search-button.tsx`, locate the desktop search button
and its `disabled` condition. Change the condition so it requires the Mapbox
`map` instance only when `mapProvider === 'mapbox'`. Use a condition such as
`disabled={isAnalyzing || !actions || (mapProvider === 'mapbox' && !map)}`.
Match this to the logic already used by the mobile button. Do not change the
mobile button condition.
2. In `.env.local.example`, add the `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY` variable
name with a comment. The comment must state that this key is required for the
Google Static Maps fetch used by the compare slider, and that it is also used by
`components/map/google-map.tsx` and `lib/agents/tools/geospatial.tsx`. Do not
add an actual secret value, only the variable name and comment.
===============================================================================
Task: 2
Implement Phase 2: remove silent failure modes around the resolution-search
image capture and add fallback handling for broken images.
1. In `components/header-search-button.tsx`, inside `handleResolutionSearch`,
add user-facing toasts:
- If `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY` is missing, show a toast that explains
the Google image is unavailable and the compare view will not appear.
- If the Google Static Map fetch throws an error or returns a non-OK response,
show a toast with a short error message.
- In both cases, continue the resolution search using the available images as a
single-image fallback. Do not abort the whole flow.
2. In `components/compare-slider.tsx`, add an `onError` handler to both `<img>`
elements. On error, fall back to the existing placeholder image at
`/images/placeholder-image.png`, consistent with the pattern in
`components/search-results-image.tsx`. Do not change the drag/slider behavior or
the layout logic.
💡 Iterate on the plan with:
`@coderabbitai` <feedback>
Example Feedback
- `@coderabbitai` You can skip phase 3. Add a simple unit test case for phase 2.
- `@coderabbitai` For design choice 1 go ahead with option 3 and replan.
Activity
ngoiyaeric commentedon Sep 5, 2026
@coderabbitai plan
coderabbitai commentedon Sep 5, 2026
Coding Plan
Summary
components/header-search-button.tsxso it enables in Google provider mode, matching the mobile button's provider-awaredisabledcondition.NEXT_PUBLIC_GOOGLE_MAPS_API_KEYin.env.local.example, because the compare slider needs the Google Static Maps image.onErrorimage fallbacks incomponents/compare-slider.tsxto avoid blank/broken images.File-Level Changes and Follow-Up Notes
components/header-search-button.tsx: Fix the desktop buttondisabledcondition to guardmapwithmapProvider === 'mapbox'. InhandleResolutionSearch, add toasts for a missingNEXT_PUBLIC_GOOGLE_MAPS_API_KEYand for a failed Google Static Map fetch, and keep the flow running with the available images..env.local.example: Add and documentNEXT_PUBLIC_GOOGLE_MAPS_API_KEY.components/compare-slider.tsx: AddonErrorfallbacks to both<img>elements using the existing placeholder image.Follow-up instruction for the implementing agent:
mapProviderto'mapbox'and to'google', then confirm the search button is enabled andhandleResolutionSearchfires in both.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY, bothmapboxImageandgoogleImagereachcomponents/resolution-carousel.tsxand theCompareSliderslide renders.resolution_searchserver action logic inapp/actions.tsxorlib/agents/resolution-search.tsx; the exploration confirmed that branch is intact..patchfiles (chat-panel.patch,app_actions_diff.patch,layout.patch); they are already-applied or superseded and are not the cause of this regression.Design Choices
Design Choice 1: Primary root cause of the regression
Options Considered:
disabledcondition requires the Mapboxmapinstance unconditionally.NEXT_PUBLIC_GOOGLE_MAPS_API_KEYis unset and undocumented, so the Google Static Map fetch is skipped silently, and the compare slider never gets its second image.Chosen Option: 1
Rationale: Fix both defects: the desktop button condition and the missing key documentation. The compare slider needs both a working trigger and both images to render. Both defects fail silently today.
💡 User Tips
Regenerate the plan with different choices with
@coderabbitai <feedback>.Implementation Steps
Phase 1: Restore the trigger and its prerequisites
This phase restores the user's ability to start a resolution search and documents the configuration the compare slider needs. The goal is to make the trigger fire in all supported provider modes and to make the Google Static Maps requirement explicit.
Task 1: Fix the desktop search button disabled condition
The desktop trigger button is disabled whenever the Mapbox
mapinstance is absent. WhenmapProvider === 'google', the Mapbox map is never mounted, somapstaysnulland the button never enables. This blocks the whole resolution-search flow on desktop in Google mode.components/header-search-button.tsx.disabledcondition to match the mobile button.maponly whenmapProvider === 'mapbox'(for example,disabled={isAnalyzing || !actions || (mapProvider === 'mapbox' && !map)}).Task 2: Document the Google Static Maps API key requirement
The compare slider needs a Google image.
components/header-search-button.tsxfetches it from the Google Static Maps API usingNEXT_PUBLIC_GOOGLE_MAPS_API_KEY. This variable is not documented in any example env file, so it is likely unset in most environments, and the fetch is skipped silently.NEXT_PUBLIC_GOOGLE_MAPS_API_KEYto.env.local.example.components/map/google-map.tsxandlib/agents/tools/geospatial.tsx.🤖 Prompt for AI agents
Phase 2: Make image-capture failures visible and add resilience
This phase removes the silent failure modes that hide the compare slider. The goal is that a missing key or a failed image fetch produces a clear message and, where possible, a graceful fallback, instead of a quietly dropped slide.
Task 1: Surface Google Static Map fetch failures
In
components/header-search-button.tsx, the Google Static Map fetch is wrapped in logic that only writes toconsole.erroror skips when the key is missing. When this happens,googleBlobstaysnull, the compare slide is dropped, and the user sees no reason.components/header-search-button.tsxhandleResolutionSearch.NEXT_PUBLIC_GOOGLE_MAPS_API_KEYis missing, show a user-facing toast that explains the Google image is unavailable and the compare view will not appear.Task 2: Add image error fallback in the compare slider
components/compare-slider.tsxrenders two<img>elements with noonErrorhandling. A broken or expired image URL shows a blank area with no indication of failure. Other image components in the repo already use a placeholder fallback.components/compare-slider.tsx.onErrorhandling to both<img>elements to fall back to the existing placeholder image (/images/placeholder-image.png), consistent withcomponents/search-results-image.tsx.🤖 Prompt for AI agents
Research
The app uses the Vercel AI SDK RSC streaming pattern. A
submitserver action inapp/actions.tsxstreams React components into auiStream. The compare slider path is a dedicatedaction === 'resolution_search'branch, not an LLM tool.components/header-search-button.tsxis the client trigger. It captures the Mapbox canvas and fetches a Google Static Map image, then submits both as aFormDatato theresolution_searchaction.app/actions.tsxrenderscomponents/resolution-carousel.tsx, which renderscomponents/compare-slider.tsxonly when both a Mapbox image and a Google image exist. The provider state lives inlib/store/settings.ts(mapProvider, default'mapbox').🚀 Next Steps
🤖 All AI agent prompts combined
💡 Iterate on the plan with:
`@coderabbitai` <feedback>