Skip to content

Integrate Resolution Search and UI Improvements#478

Open
ngoiyaeric wants to merge 46 commits intomainfrom
integrate-resolution-search-and-ui-fixes-545125209238302071
Open

Integrate Resolution Search and UI Improvements#478
ngoiyaeric wants to merge 46 commits intomainfrom
integrate-resolution-search-and-ui-fixes-545125209238302071

Conversation

@ngoiyaeric
Copy link
Collaborator

@ngoiyaeric ngoiyaeric commented Feb 2, 2026

User description

Integrated targeted improvements for resolution search (drawnFeatures context, streaming stability) and mobile UI (padding, layout, text wrapping) while maintaining existing codebase structure.


PR created automatically by Jules for task 545125209238302071 started by @ngoiyaeric


PR Type

Enhancement, Bug fix


Description

  • Improved resolution search with vision-capable model selection and streaming stability

  • Fixed mobile UI responsiveness with optimized padding and text wrapping

  • Enhanced model selection logic to support SPECIFIC_API_MODEL environment variable

  • Replaced react-toastify with sonner for toast notifications

  • Updated LICENSE copyright and improved UI component layout robustness


Diagram Walkthrough

flowchart LR
  A["Model Selection Logic"] -->|"Support SPECIFIC_API_MODEL"| B["getModel Function"]
  B -->|"Vision-capable models"| C["Grok/Gemini/OpenAI"]
  D["Resolution Search"] -->|"Include drawnFeatures"| E["FormData"]
  E -->|"Improved streaming"| F["BotMessage Component"]
  G["Mobile UI"] -->|"Reduce padding"| H["Chat Panel"]
  H -->|"Text wrapping fixes"| I["Better Layout"]
  J["Toast Notifications"] -->|"Replace react-toastify"| K["Sonner Library"]
Loading

File Walkthrough

Relevant files
Enhancement
9 files
index.ts
Enhanced model selection with vision capability support   
+27/-6   
chat-panel.tsx
Optimized mobile input styling and text wrapping                 
+8/-9     
empty-screen.tsx
Added text wrapping and improved icon alignment                   
+3/-3     
header-search-button.tsx
Added drawnFeatures support and improved map validation   
+11/-7   
message.tsx
Added text wrapping for better content display                     
+1/-1     
mobile-icons-bar.tsx
Replaced search button with portal target                               
+1/-3     
search-related.tsx
Added break-words for text wrapping support                           
+1/-1     
suggestions-dropdown.tsx
Improved text wrapping and icon alignment                               
+3/-3     
resolution-search.tsx
Added clarification for JSON response format                         
+2/-0     
Formatting
1 files
globals.css
Reduced mobile padding and removed redundant styles           
+1/-57   
Documentation
1 files
LICENSE
Updated copyright year and author information                       
+1/-1     
Bug fix
1 files
actions.tsx
Improved streaming and partial update handling                     
+15/-22 
Miscellaneous
1 files
usage-view.tsx
Updated usage data and credit refresh information               
+6/-6     

CJWTRUST and others added 30 commits January 20, 2026 01:20
Restored the branch to the expected head at commit 488b47c.
This recovers several missing features and architectural improvements:
- Integrated HistoryToggleProvider and HistorySidebar.
- Integrated UsageToggleProvider and the new UsageView component.
- Removed legacy usage-sidebar.tsx.
- Restored pricing and feature updates in PurchaseCreditsPopup.
- Fixed layout structure in app/layout.tsx to support these new global state providers.

Resolved previous merge conflicts and incorrect force-push state.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Reset branch HEAD to historical recovery point 488b47c.
- Applied latest code fixes from orphan commit 166aee9, including Mapbox rendering optimizations and GeoJSON streaming.
- Improved type safety in app/actions.tsx by removing 'as any' casts and properly typing message arrays.
- Refined getModel utility to support vision-aware model fallback.
- Documented non-blocking background task pattern in server actions.
- Updated feature/billing-integration branch with the restored state.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Reset branch HEAD to historical recovery point 488b47c.
- Applied latest code fixes from orphan commit 166aee9.
- Resolved TypeScript build error in app/actions.tsx by casting GeoJSON data to FeatureCollection.
- Improved type safety for AIState message filtering and content handling.
- Implemented background processing for resolution search with immediate UI streaming.
- Optimized chat history fetching to trigger only when the sidebar is open.
- Ensured Mapbox style loading is robust against re-renders.
- Cleaned up dead code and improved documentation in server actions.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Reset branch HEAD to historical recovery point 488b47c.
- Applied latest code fixes from orphan commit 166aee9.
- Resolved TypeScript build error in app/actions.tsx by casting GeoJSON data to FeatureCollection.
- Improved type safety for AIState message filtering and content handling.
- Implemented background processing for resolution search with immediate UI streaming.
- Re-enabled auto-opening of the pricing popup in components/header.tsx.
- Optimized chat history fetching to trigger only when the sidebar is open.
- Ensured Mapbox style loading is robust against re-renders.
- Cleaned up dead code and improved documentation in server actions.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Restored historical state from 488b47c and merged latest changes.
- Implemented streaming for resolution search in lib/agents/resolution-search.tsx and app/actions.tsx to improve response time.
- Re-enabled auto-opening pricing popup in components/header.tsx.
- Resolved all TypeScript build errors in app/actions.tsx.
- Restored Grok model support for vision tasks in lib/utils/index.ts.
- Optimized chat history loading in components/sidebar/chat-history-client.tsx.
- Improved Mapbox style loading robustness in components/map/mapbox-map.tsx.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Synchronized branch with origin/main, prioritizing main's code structure and latest features.
- Bridged the history with historical recovery point 488b47c.
- Implemented streaming for resolution search in lib/agents/resolution-search.tsx and app/actions.tsx to resolve performance issues.
- Restored the auto-opening Pricing Popup and Usage View in the Header component.
- Integrated the Timezone Clock and time context into the restored resolution search logic.
- Resolved TypeScript build errors with proper type casting and fixed a missing 'use client' directive in components/history.tsx.
- Ensured all required providers (History, Usage, etc.) are correctly wrapped in the root layout.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Synchronized branch with origin/main, prioritizing main's code structure and latest features.
- Bridged the history with historical recovery point 488b47c.
- Integrated UsageView and billing UI into the Chat component, toggled by the tent tree icon.
- Implemented streaming for resolution search in lib/agents/resolution-search.tsx and app/actions.tsx for better performance.
- Restored the auto-opening Pricing Popup in the Header component.
- Improved type safety across server actions and Mapbox components.
- Ensured mutual exclusion between Settings, Usage, and Map views.
- Fixed a missing 'use client' directive in components/history.tsx.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Integrated UsageView into the main Chat component for both mobile and desktop.
- Ensured mutual exclusion between Settings, Usage, and Map views in the UI panel.
- Updated ConditionalLottie to hide the loading animation when the Usage View is open.
- Synchronized with origin/main while prioritizing its code structure.
- Maintained historical recovery and performance optimizations for resolution search.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Synchronized with origin/main, prioritizing main branch code and features.
- Fully restored historical context and missing changes from commit 488b47c.
- Integrated Usage and Billing UI (UsageView) into the Chat component.
- Implemented streaming for resolution search analysis to improve perceived performance.
- Re-enabled auto-opening pricing popup in components/header.tsx.
- Refined ConditionalLottie visibility to avoid overlaps with the Usage UI.
- Ensured mutual exclusion between Settings, Usage, and Map views in the side panel.
- Improved type safety across server actions and Mapbox components.
- Resolved build failures related to missing client directives and type mismatches.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…ability

- Recovered historical state from commit 488b47c and synchronized with main.
- Optimized resolution search by refactoring to stream partial summaries.
- Fixed Mapbox memory leaks by ensuring all event listeners are removed on cleanup.
- Improved StreamableValue stability by initializing with default values.
- Integrated Usage View with mutual exclusion logic and Lottie player visibility fixes.
- Refined model selection for Grok vision and Gemini 1.5 Pro.
- Integrated timezone-aware analysis using tz-lookup.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Fixed Type error in `app/actions.tsx` by casting `content` to `string` in `createStreamableValue`.
- Addressed ESLint warnings in `components/map/mapbox-map.tsx` and `components/chat-panel.tsx` by adding missing dependencies to `useEffect` and `useCallback` hooks.
- Ensured `relatedQueries` streamable value is initialized with an empty state for stability.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Reduced vertical padding in `.mobile-chat-input-area` in `globals.css`.
- Removed redundant `.mobile-chat-input` class and associated styles from `globals.css`.
- Adjusted `ChatPanel` to use more compact padding and a smaller minimum height on mobile.
- Removed excessive left padding (`pl-14`) on the mobile chat input since the attachment button is moved to the icons bar.
- Cleaned up unused mobile-specific CSS classes in `globals.css`.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…8048805505961867280

Reduce padding in mobile chat input area
Replaced all occurrences of the old Stripe checkout link with the new URL:
https://buy.stripe.com/14A3cv7K72TR3go14Nasg02

Updated files:
- components/mobile-icons-bar.tsx
- components/header.tsx

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
- Updated `EmptyScreen` example buttons to use `whitespace-normal`, `text-left`, and `items-start` for better multi-line support.
- Added `break-words` to `BotMessage` container to prevent horizontal overflow from long strings.
- Improved `SuggestionsDropdown` and `SearchRelated` buttons with wrapping and top-alignment.
- Replaced filename truncation with `break-all` wrapping in `ChatPanel` file attachments.
- Ensured consistent icon alignment for multi-line buttons.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…911856121500176

Ensure text wrapping for long sentences across UI components
- Optimized resolution search with streaming.
- Improved timezone handling and AI context.
- Fixed UI mutual exclusion and loading state logic.
- Stabilized Mapbox cleanup and event listeners.
- Resolved build errors and ESLint warnings.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…head features

- Reverted branch to commit 6acfbe5.
- Merged changes from main (e95a25b).
- Preserved Tentree Icon (UsageView logic), History layout (HistoryContainer), and PurchaseCreditsPopup from 6acfbe5 as requested.
- Updated Stripe checkout URL in PurchaseCreditsPopup to the official one (14A3cv7K72TR3go14Nasg02).
- Re-applied bug fixes from 6acfbe5 (type casting in app/actions.tsx, ESLint dependencies in components/map/mapbox-map.tsx and components/chat-panel.tsx, and relatedQueries initialization).
- Verified build and synchronization with main branch features (e.g., resolution search enhancements).

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…ranch head features

- Reverted branch to commit 6acfbe5 and merged with main (e95a25b).
- Preserved Tentree Icon (Usage View), history layout, and PurchaseCreditsPopup from 6acfbe5.
- Restored branch-specific UI components: Header, History button, Profile toggle, and Usage integration in Chat.
- Synchronized all other logic with main, including resolution search enhancements.
- Fixed an infinite re-render loop in Mapbox map by optimizing useEffect dependencies (removed cameraState from initialization effect).
- Re-applied critical bug fixes from 6acfbe5:
  - Type casting in app/actions.tsx (getUIStateFromAIState).
  - Streamable value initialization for stability.
  - setSuggestions dependency in ChatPanel.
- Updated Stripe checkout URL in PurchaseCreditsPopup to the official link.
- Verified successful build with 'bun run build'.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
google-labs-jules bot and others added 5 commits February 2, 2026 12:22
- Updated 'Daily refresh credits' to 'Yearly refresh credits'
- Updated refresh credit value from 300 to 500
- Updated subtext to 'Refresh to 500 every year.'
- Replaced task list with 'QCX-TERRA Crop yield Analysis', 'QCX-TERRA Flood predictions', and 'Green OS climate synchronization'
- Set task dates to 'upcoming' and credit changes to single digits (-7, -5, -3)

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
…resh-14763946411330416327

Update Usage View to Yearly Refresh
@ngoiyaeric
Copy link
Collaborator Author

@coderabbitai the resolution search is not responsive

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Examine the header-search-button component to understand resolution search implementation
cat components/header-search-button.tsx

Length of output: 4583


🏁 Script executed:

#!/bin/bash
# Search for resolution search related components and styles
rg -n "resolution" --type=tsx --type=ts --type=css -C 2

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Look for mobile-specific styles and responsive design patterns
rg -n "@media|mobile|responsive|sm:|md:|lg:" components/header-search-button.tsx -C 2

Length of output: 880


🏁 Script executed:

#!/bin/bash
# Check if there are any dialog or popup components related to search
rg -n "Dialog|Modal|Popover" components/header-search-button.tsx -C 3

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Find where the portal divs are defined
rg -n "header-search-portal|mobile-header-search-portal" -C 3

Length of output: 1059


🏁 Script executed:

#!/bin/bash
# Look at header component files
fd "header" --type f -e tsx -e ts | head -20

Length of output: 78


🏁 Script executed:

#!/bin/bash
# Check the main header component
cat components/header.tsx 2>/dev/null || cat components/Header.tsx 2>/dev/null || echo "Header component not found in components/"

Length of output: 3294


🏁 Script executed:

#!/bin/bash
# Search in app directory for layout or header files
fd -e tsx -e ts . app | rg "layout|header" | head -10

Length of output: 14


🏁 Script executed:

#!/bin/bash
# Check mobile-icons-bar and other mobile components
cat components/mobile-icons-bar.tsx

Length of output: 2457


🏁 Script executed:

#!/bin/bash
# Search for any other files that might have the mobile portal
rg -l "mobile.*portal|portal.*mobile" components/

Length of output: 35


🏁 Script executed:

#!/bin/bash
# List all components to see if there's another mobile menu component
fd -e tsx . components | grep -i mobile

Length of output: 31


@ngoiyaeric I've identified the issue! The resolution search is not responsive because the mobile portal container is missing from the DOM.

Root Cause

In components/header-search-button.tsx, the component creates a mobileButton that attempts to render into a div with id="mobile-header-search-portal", but this div doesn't exist anywhere in the codebase:

  • header-search-portal exists in header.tsx (line 79) but only in the desktop section with hidden md:flex classes
  • mobile-header-search-portal is missing entirely

This means the resolution search button cannot render on mobile devices, making the feature completely unavailable on smaller screens.

Recommended Fix

You have two options:

Option 1: Add to Header Mobile Section

Add the portal div to the mobile menu in components/header.tsx:

{/* Mobile menu buttons */}
<div className="flex md:hidden gap-2">
  <div id="mobile-header-search-portal" />
  
  <Button variant="ghost" size="icon" onClick={handleUsageToggle}>
    <TentTree className="h-[1.2rem] w-[1.2rem]" />
  </Button>
  <ProfileToggle/>
</div>

Option 2: Replace Static Button in Mobile Icons Bar

In components/mobile-icons-bar.tsx (line 48-50), replace the static Search button with the portal:

<div id="mobile-header-search-portal" />

This would be better since the existing Search button is non-functional anyway.

Would you like me to create a plan to implement one of these fixes?

@google-labs-jules
Copy link
Contributor

@coderabbitai the resolution search is not responsive

I have fixed the responsiveness of the resolution search. The mobile search button was missing its portal target, and the 'disabled' logic was incorrectly requiring a Mapbox instance even when Google Maps was active. I've also aligned the mobile button style with other icons and switched to 'sonner' for toast notifications.

google-labs-jules bot and others added 2 commits February 2, 2026 12:49
…responsiveness

This commit integrates key features and fixes from recent PRs:
- Improved Resolution Search: included `drawnFeatures` in requests and fixed AI streaming stability.
- Fixed Resolution Search Responsiveness: added missing portal target for mobile and corrected 'disabled' logic.
- Optimized mobile UI: reduced vertical padding and improved chat panel layout.
- Enhanced layout robustness: text wrapping fixes across multiple components.
- Updated Stripe checkout links to the latest URL.
- Updated LICENSE copyright.
- Switched to 'sonner' for toast notifications in HeaderSearchButton.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
This commit addresses the "no response" issue in resolution search by:
- Updating `getModel` to correctly return vision-capable models when needed.
- Improving `streamObject` partial update handling in `app/actions.tsx`.
- Adding a spinner and improving UI streaming for resolution search.
- Increasing static map quality with `scale=2`.

It also fixes mobile responsiveness:
- Added missing portal target for the mobile search button.
- Corrected button disabled logic to support Google Maps.
- Aligned mobile icon button styles.
- Optimized mobile padding and fixed text wrapping across the UI.
- Updated Stripe checkout links and LICENSE metadata.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
This commit integrates several key features and fixes from the requested PRs:
- Resolution Search: Added drawnFeatures support, fixed streaming logic, and improved vision model selection.
- Mobile UI: Optimized chat input padding, fixed filename wrapping, and added mobile search portal.
- Text Wrapping: Applied whitespace-normal and break-words to various components for better responsiveness.
- Metadata: Updated LICENSE and Stripe checkout links.
- Consistency: Maintained existing usage and history components as requested.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
This commit refactors the desktop header icon container in `components/header.tsx` to ensure all icons are equidistant.

Key changes:
- Changed the icon container from `justify-between w-1/2` to `justify-center flex-1` with a fixed `gap-10`.
- Removed the unused `<div id="timezone-clock-portal" />` which was causing irregular spacing between the TentTree and ModeToggle icons.
- Applied `className="contents"` to the `<div id="header-search-portal" />` so that it doesn't affect the flex layout when empty.
- These changes ensure that icons are always perfectly centered and equidistant regardless of the number of active icons.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/mobile-icons-bar.tsx (1)

7-16: 🧹 Nitpick | 🔵 Trivial

Unused Search import.

The Search icon import is no longer used after replacing the mobile search button with the portal div.

♻️ Remove unused import
 import {
-  Search,
   CircleUserRound,
   Map,
   CalendarDays,
   TentTree,
   Paperclip,
   ArrowRight,
   Plus
 } from 'lucide-react'
🤖 Fix all issues with AI agents
In `@components/header-search-button.tsx`:
- Line 114: Extract the repeated disable expression into a single computed
boolean (e.g., const isDisabled = isAnalyzing || !actions || (mapProvider ===
'mapbox' && !map) || (mapProvider === 'google' && !mapData.cameraState)) and
replace the duplicated uses in both the desktop button and the mobileButton with
this variable; update any JSX props that currently use the long expression to
use isDisabled to improve maintainability and avoid divergence between
HeaderSearchButton and mobileButton render paths.
- Line 12: Update remaining uses of react-toastify (notably in
components/map/mapbox-map.tsx) to import and call sonner's toast API: replace
any imports from 'react-toastify' and calls to toast.success/toast.error etc.
with "import { toast } from 'sonner'" and use toast.success/toast.error (or
toast) accordingly; remove any <ToastContainer /> usage since <Toaster /> is
mounted in app/layout.tsx. Search the repo for other 'react-toastify'
imports/usages and convert them to sonner likewise, then remove the
'react-toastify' entry from package.json and run install to update dependencies.

In `@lib/utils/index.ts`:
- Around line 44-47: The local const named `openai` is shadowing the imported
`openai` from `@ai-sdk/openai`; rename the local variable returned by
createOpenAI (e.g., to `openaiClient` or `openaiInstance`) and return that
instead (update the return statement from `openai(specificModel)` to use the new
name) so that the imported symbol and the created client are distinct; update
any callers in this file that expect the created client variable name
accordingly.
- Around line 30-48: The code currently returns a client for SPECIFIC_API_MODEL
without checking requireVision; update the block that handles specificModel to
validate vision/structured-capability when requireVision is true: inspect the
specificModel string (the existing specificModel variable) against known
vision-capable model identifiers (or a small helper list you add) and if
requireVision is true and the chosen specificModel is not recognized as
vision-capable, emit a clear warning or throw an error; keep the existing client
creation calls (createXai, createGoogleGenerativeAI, createOpenAI) but add this
validation/logging before returning the client so callers requiring vision get
an immediate, descriptive message instead of failing at runtime.
- Line 61: The current getModel selection uses the requireVision flag to choose
between 'grok-vision-beta' and 'grok-4-fast-non-reasoning', which mixes vision
capability with structured-output capability and causes JSON Schema rejections
for consumers of streamObject/generateObject; update the model selection logic
in the getModel function(s) so that any callsite that requires structured output
(e.g., streamObject, generateObject, and callers getModel() used by
task-manager.tsx, query-suggestor.tsx, inquire.tsx, suggest.ts,
resolution-search.tsx) never gets 'grok-4-fast-non-reasoning'—instead route
those cases to 'gpt-4o'; keep vision-only requests able to choose
'grok-vision-beta' but add a separate boolean or enum (e.g.,
requiresStructuredOutput) or inspect the caller flag (hasImage vs
structuredOutput) so selection checks structured-output first and returns
'gpt-4o' when true, otherwise fall back to vision or non-reasoning Grok as
appropriate.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9377934 and df52ed9.

📒 Files selected for processing (5)
  • app/actions.tsx
  • components/header-search-button.tsx
  • components/mobile-icons-bar.tsx
  • lib/agents/resolution-search.tsx
  • lib/utils/index.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-01-13T13:26:30.086Z
Learnt from: ngoiyaeric
Repo: QueueLab/QCX PR: 0
File: :0-0
Timestamp: 2026-01-13T13:26:30.086Z
Learning: Workers that rely on ai.generateObject (geojsonParser, map-command-generator, feedback-analyzer) must not use the X.AI 'grok-4-fast-non-reasoning' model because X.AI’s chat/completions rejects JSON Schema structured-output arguments; prefer OpenAI gpt-4o for structured outputs.

Applied to files:

  • lib/utils/index.ts
📚 Learning: 2026-01-17T06:14:51.070Z
Learnt from: ngoiyaeric
Repo: QueueLab/QCX PR: 0
File: :0-0
Timestamp: 2026-01-17T06:14:51.070Z
Learning: For structured output tasks using ai.generateObject (resolution-search, geojsonParser, map-command-generator, feedback-analyzer), prefer OpenAI gpt-4o. While xAI's grok-4-1-fast-reasoning technically supports structured outputs and vision, OpenAI has proven more reliable integration with the AI SDK's generateObject function and Zod schemas in production.

Applied to files:

  • lib/utils/index.ts
🧬 Code graph analysis (2)
lib/utils/index.ts (1)
lib/actions/users.ts (1)
  • getSelectedModel (126-139)
components/header-search-button.tsx (4)
components/map/google-map.tsx (2)
  • GoogleMapComponent (12-86)
  • apiKey (20-29)
components/map/mapbox-map.tsx (4)
  • prevData (166-166)
  • map (66-167)
  • map (320-341)
  • isMapTypeChanged (460-512)
components/map/google-geojson-layer.tsx (2)
  • feature (27-44)
  • map (14-57)
components/map/map-query-handler.tsx (1)
  • toolOutput (33-73)
🪛 Biome (2.3.13)
app/actions.tsx

[error] 672-672: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 685-685: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🔇 Additional comments (7)
components/mobile-icons-bar.tsx (1)

48-48: Good fix for the missing mobile portal target.

This correctly resolves the issue where the mobile resolution search button couldn't render because the portal container was missing from the DOM. The HeaderSearchButton component now has a target element to portal the mobile search button into.

lib/agents/resolution-search.tsx (1)

62-63: LGTM!

The additional instruction reinforces JSON schema compliance, which helps ensure the LLM produces well-structured output matching the resolutionSearchSchema. This is good defensive prompt engineering for structured output generation.

components/header-search-button.tsx (3)

38-46: Good addition of state validation with early returns.

The early returns with toast notifications provide clear user feedback when the map providers aren't ready. This prevents confusing errors during the resolution search process.


80-80: Static map quality improvement with scale=2.

Using scale=2 doubles the pixel density of the static map image, which is beneficial for image analysis by the vision model. Good enhancement.


97-97: drawnFeatures correctly appended to form data.

This enables the resolution search to analyze user-drawn areas/lines on the map. The JSON serialization with fallback to empty array is appropriate.

app/actions.tsx (2)

112-112: Good fallback chain for summary resolution.

The fallback analysisResult.summary || fullSummary || 'Analysis complete.' ensures the stream always completes with meaningful content, even if the structured output is partial.


724-725: Consistent streamable initialization pattern.

The pattern of creating empty streamables and calling done() with the value is now consistent across the codebase. This aligns with the PR objective of improving AI streaming stability.

Also applies to: 738-739

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

import { nanoid } from 'nanoid'
import { UserMessage } from './user-message'
import { toast } from 'react-toastify'
import { toast } from 'sonner'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify Toaster component is mounted in the app
rg -n "Toaster" --type=tsx --type=ts -g '!node_modules'

Repository: QueueLab/QCX

Length of output: 83


🏁 Script executed:

# Check for any remaining react-toastify imports
rg -n "react-toastify" --type=tsx --type=ts -g '!node_modules'

Repository: QueueLab/QCX

Length of output: 83


🏁 Script executed:

# Verify the migration in the file
rg -n "from 'sonner'" --type=tsx --type=ts -g '!node_modules'

Repository: QueueLab/QCX

Length of output: 83


🏁 Script executed:

#!/bin/bash
# Search for Toaster component in TypeScript/React files
rg -n "Toaster" --type-add 'web:*.{ts,tsx,js,jsx}' -t web -g '!node_modules'

Repository: QueueLab/QCX

Length of output: 970


🏁 Script executed:

# Search for react-toastify to ensure it was fully removed
rg "react-toastify" -g '!node_modules'

Repository: QueueLab/QCX

Length of output: 558


🏁 Script executed:

# Search for sonner imports
rg "from ['\"]sonner['\"]" -g '!node_modules'

Repository: QueueLab/QCX

Length of output: 382


🏁 Script executed:

# List the app entry/layout files to check for Toaster
fd -e tsx -e ts . -path '*/app*' -o -path '*/layout*' -o -path '*/main*' -o -path '*/index*' | head -20

Repository: QueueLab/QCX

Length of output: 224


Complete the sonner migration across the codebase.

The migration from react-toastify to sonner in this file is correct. The <Toaster /> component is properly mounted in app/layout.tsx. However, components/map/mapbox-map.tsx still imports and uses react-toastify. Complete the migration by updating this file and any other remaining references to use sonner instead, then remove the react-toastify dependency from package.json.

🤖 Prompt for AI Agents
In `@components/header-search-button.tsx` at line 12, Update remaining uses of
react-toastify (notably in components/map/mapbox-map.tsx) to import and call
sonner's toast API: replace any imports from 'react-toastify' and calls to
toast.success/toast.error etc. with "import { toast } from 'sonner'" and use
toast.success/toast.error (or toast) accordingly; remove any <ToastContainer />
usage since <Toaster /> is mounted in app/layout.tsx. Search the repo for other
'react-toastify' imports/usages and convert them to sonner likewise, then remove
the 'react-toastify' entry from package.json and run install to update
dependencies.

size="icon"
onClick={handleResolutionSearch}
disabled={isAnalyzing || !map || !actions}
disabled={isAnalyzing || !actions || (mapProvider === 'mapbox' && !map) || (mapProvider === 'google' && !mapData.cameraState)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Disable logic consistency is good but verbose.

The disable condition is duplicated between desktop and mobile buttons. Consider extracting to a computed variable for maintainability.

♻️ Extract shared disable condition
+  const isDisabled = isAnalyzing || !actions || (mapProvider === 'mapbox' && !map) || (mapProvider === 'google' && !mapData.cameraState)
+
   const desktopButton = (
     <Button
       variant="ghost"
       size="icon"
       onClick={handleResolutionSearch}
-      disabled={isAnalyzing || !actions || (mapProvider === 'mapbox' && !map) || (mapProvider === 'google' && !mapData.cameraState)}
+      disabled={isDisabled}
       title="Analyze current map view"
     >

And similarly for mobileButton.

Also applies to: 126-126

🤖 Prompt for AI Agents
In `@components/header-search-button.tsx` at line 114, Extract the repeated
disable expression into a single computed boolean (e.g., const isDisabled =
isAnalyzing || !actions || (mapProvider === 'mapbox' && !map) || (mapProvider
=== 'google' && !mapData.cameraState)) and replace the duplicated uses in both
the desktop button and the mobileButton with this variable; update any JSX props
that currently use the long expression to use isDisabled to improve
maintainability and avoid divergence between HeaderSearchButton and mobileButton
render paths.

Comment on lines +30 to +48
if (specificModel) {
if (specificModel.includes('grok')) {
const xai = createXai({
apiKey: xaiApiKey,
baseURL: 'https://api.x.ai/v1',
});
return xai(specificModel);
}
if (specificModel.includes('gemini')) {
const google = createGoogleGenerativeAI({
apiKey: gemini3ProApiKey,
});
return google(specificModel);
}
const openai = createOpenAI({
apiKey: openaiApiKey,
});
return openai(specificModel);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

SPECIFIC_API_MODEL path doesn't validate vision capability.

When SPECIFIC_API_MODEL is set, the model is used directly regardless of the requireVision parameter. If someone sets SPECIFIC_API_MODEL=grok-4-fast-non-reasoning but calls a function requiring vision or structured output, it will fail silently at runtime.

Consider logging a warning when requireVision is true but the specified model may not support vision.

🤖 Prompt for AI Agents
In `@lib/utils/index.ts` around lines 30 - 48, The code currently returns a client
for SPECIFIC_API_MODEL without checking requireVision; update the block that
handles specificModel to validate vision/structured-capability when
requireVision is true: inspect the specificModel string (the existing
specificModel variable) against known vision-capable model identifiers (or a
small helper list you add) and if requireVision is true and the chosen
specificModel is not recognized as vision-capable, emit a clear warning or throw
an error; keep the existing client creation calls (createXai,
createGoogleGenerativeAI, createOpenAI) but add this validation/logging before
returning the client so callers requiring vision get an immediate, descriptive
message instead of failing at runtime.

Comment on lines +44 to +47
const openai = createOpenAI({
apiKey: openaiApiKey,
});
return openai(specificModel);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Variable shadowing: openai redeclared.

The variable openai is imported at line 4 from @ai-sdk/openai and then redeclared here with createOpenAI. This shadows the import and could cause confusion.

♻️ Use a different variable name
-    const openai = createOpenAI({
+    const openaiClient = createOpenAI({
       apiKey: openaiApiKey,
     });
-    return openai(specificModel);
+    return openaiClient(specificModel);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const openai = createOpenAI({
apiKey: openaiApiKey,
});
return openai(specificModel);
const openaiClient = createOpenAI({
apiKey: openaiApiKey,
});
return openaiClient(specificModel);
🤖 Prompt for AI Agents
In `@lib/utils/index.ts` around lines 44 - 47, The local const named `openai` is
shadowing the imported `openai` from `@ai-sdk/openai`; rename the local variable
returned by createOpenAI (e.g., to `openaiClient` or `openaiInstance`) and
return that instead (update the return statement from `openai(specificModel)` to
use the new name) so that the imported symbol and the created client are
distinct; update any callers in this file that expect the created client
variable name accordingly.

});
try {
return xai('grok-4-fast-non-reasoning');
return xai(requireVision ? 'grok-vision-beta' : 'grok-4-fast-non-reasoning');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Check all callers of getModel to understand structured output usage
rg -n "getModel\(" --type=ts -A 3 -B 2 | head -100

Repository: QueueLab/QCX

Length of output: 4121


🏁 Script executed:

# Find resolution-search implementation
fd "resolution-search" --type=ts

Repository: QueueLab/QCX

Length of output: 225


🏁 Script executed:

# Check what uses streamObject or generateObject
rg -n "streamObject|generateObject" --type=ts -B 2 -A 1

Repository: QueueLab/QCX

Length of output: 2594


🏁 Script executed:

# Examine the actual getModel function in lib/utils/index.ts
cat lib/utils/index.ts

Repository: QueueLab/QCX

Length of output: 4707


Structured output incompatibility with grok-4-fast-non-reasoning requires immediate fix.

Multiple workers use streamObject or generateObject (both requiring JSON Schema support) but are routed to grok-4-fast-non-reasoning when requireVision=false:

  • task-manager.tsx (line 19): generateObject + getModel()
  • query-suggestor.tsx (line 21): streamObject + getModel()
  • inquire.tsx (line 26): streamObject + getModel()
  • suggest.ts (line 31): streamObject + getModel()
  • resolution-search.tsx (line 76): streamObject + getModel(hasImage)

The xAI model grok-4-fast-non-reasoning rejects JSON Schema structured-output arguments per learnings. The fundamental issue: the requireVision parameter conflates vision capability (image analysis) with structured output capability—these are orthogonal concerns. Workers needing structured outputs regardless of image presence will fail at runtime with JSON Schema rejection errors.

For Grok fallback at line 61, 105, and 116: ensure structured output workers never receive grok-4-fast-non-reasoning. Route them to gpt-4o instead.

🤖 Prompt for AI Agents
In `@lib/utils/index.ts` at line 61, The current getModel selection uses the
requireVision flag to choose between 'grok-vision-beta' and
'grok-4-fast-non-reasoning', which mixes vision capability with
structured-output capability and causes JSON Schema rejections for consumers of
streamObject/generateObject; update the model selection logic in the getModel
function(s) so that any callsite that requires structured output (e.g.,
streamObject, generateObject, and callers getModel() used by task-manager.tsx,
query-suggestor.tsx, inquire.tsx, suggest.ts, resolution-search.tsx) never gets
'grok-4-fast-non-reasoning'—instead route those cases to 'gpt-4o'; keep
vision-only requests able to choose 'grok-vision-beta' but add a separate
boolean or enum (e.g., requiresStructuredOutput) or inspect the caller flag
(hasImage vs structuredOutput) so selection checks structured-output first and
returns 'gpt-4o' when true, otherwise fall back to vision or non-reasoning Grok
as appropriate.

This commit provides a final consolidated update of the features requested from PRs #466, #469, #470, #471, and #473:
- Resolution Search: Finalized streaming logic and spatial context integration.
- UI: Consolidated Tailwind-based layout fixes for mobile responsiveness and text wrapping.
- Stability: Removed initial values from StreamableValue instances in app/actions.tsx to ensure hydration consistency.
- Metadata: Verified license and copyright information.
- Compliance: Ensured Usage and History components remain intact as requested.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/actions.tsx (1)

116-173: ⚠️ Potential issue | 🟠 Major

Persisted summary can diverge from streamed summary.

summaryStream.done uses analysisResult.summary || fullSummary || 'Analysis complete.', but the persisted messages use analysisResult.summary || 'Analysis complete.'. If the final object omits summary but the partial stream produced it, the UI shows the full summary while the saved history shows only “Analysis complete.”. Use a single finalSummary for all three writes.

✅ Proposed fix
-        // Mark the summary stream as done with the result.
-        summaryStream.done(analysisResult.summary || fullSummary || 'Analysis complete.');
-
-        messages.push({ role: 'assistant', content: analysisResult.summary || 'Analysis complete.' });
+        const finalSummary =
+          analysisResult.summary || fullSummary || 'Analysis complete.';
+        summaryStream.done(finalSummary);
+
+        messages.push({ role: 'assistant', content: finalSummary });
...
-              content: analysisResult.summary || 'Analysis complete.',
+              content: finalSummary,
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df52ed9 and a9bf40d.

📒 Files selected for processing (3)
  • app/actions.tsx
  • app/globals.css
  • components/empty-screen.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
components/empty-screen.tsx (1)
components/ui/button.tsx (2)
  • props (43-52)
  • ButtonProps (36-40)
app/actions.tsx (3)
components/section.tsx (1)
  • Section (24-75)
components/message.tsx (1)
  • BotMessage (11-31)
lib/agents/researcher.tsx (1)
  • researcher (77-161)
🪛 Biome (2.3.13)
app/actions.tsx

[error] 669-669: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 682-682: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🔇 Additional comments (2)
components/empty-screen.tsx (1)

44-51: LGTM! Well-implemented mobile text wrapping improvements.

The styling changes correctly address multi-line text scenarios:

  • items-start + mt-1 on the icon ensures proper vertical alignment with the first line of wrapped text
  • shrink-0 prevents icon compression on narrow viewports
  • whitespace-normal text-left with flex-1 span enables natural text wrapping while maintaining left alignment

This is consistent with the related wrapping improvements in search-related.tsx and suggestions-dropdown.tsx noted in the PR.

app/globals.css (1)

190-200: LGTM!

The padding reduction from 10px to 4px 10px in .mobile-chat-input-area is a sensible UI refinement that reduces vertical space while maintaining horizontal padding. This aligns with the PR objective of improving mobile layout compactness. The media query breakpoint (max-width: 1024px) is consistent with the mobile detection logic in components/chat.tsx.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@qodo-code-review
Copy link
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Model override data egress

Description: Allowing process.env.SPECIFIC_API_MODEL to override provider/model selection can route
sensitive prompts/images to an unintended third-party model/provider (data egress risk) if
the environment is misconfigured or attacker-controlled in any deployment path.
index.ts [21-48]

Referred Code
const specificModel = process.env.SPECIFIC_API_MODEL;
const xaiApiKey = process.env.XAI_API_KEY;
const gemini3ProApiKey = process.env.GEMINI_3_PRO_API_KEY;
const awsAccessKeyId = process.env.AWS_ACCESS_KEY_ID;
const awsSecretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
const awsRegion = process.env.AWS_REGION;
const bedrockModelId = process.env.BEDROCK_MODEL_ID || 'anthropic.claude-3-5-sonnet-20241022-v2:0';
const openaiApiKey = process.env.OPENAI_API_KEY;

if (specificModel) {
  if (specificModel.includes('grok')) {
    const xai = createXai({
      apiKey: xaiApiKey,
      baseURL: 'https://api.x.ai/v1',
    });
    return xai(specificModel);
  }
  if (specificModel.includes('gemini')) {
    const google = createGoogleGenerativeAI({
      apiKey: gemini3ProApiKey,
    });


 ... (clipped 7 lines)
Reverse tabnabbing risk

Description: External links are configured to open with target: '_blank' via rehypeExternalLinks
without an explicit rel="noopener noreferrer", which can enable reverse-tabnabbing if the
plugin does not automatically add safe rel attributes.
message.tsx [22-25]

Referred Code
<MemoizedReactMarkdown
  rehypePlugins={[[rehypeExternalLinks, { target: '_blank' }], rehypeKatex]}
  remarkPlugins={[remarkGfm, remarkMath]}
  className="prose-sm prose-neutral prose-a:text-accent-foreground/50"
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Unguarded JSON parse: New code calls JSON.parse(content as string) for relatedQueries without a try/catch, which
can throw on malformed content and crash UI-state reconstruction instead of degrading
gracefully.

Referred Code
const relatedQueries = createStreamableValue<RelatedQueries>()
relatedQueries.done(JSON.parse(content as string))
return {

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Error may leak: The new summaryStream.error(error) may propagate raw error details to the client depending
on the StreamableValue implementation, potentially exposing internal information to end
users.

Referred Code
} catch (error) {
  console.error('Error in resolution search:', error);
  summaryStream.error(error);

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Unstructured error logs: Added/expanded logging via console.error(..., error) may emit unstructured logs and could
include provider/client error payloads that contain sensitive request context depending on
upstream SDK behavior.

Referred Code
try {
  return xai(requireVision ? 'grok-vision-beta' : 'grok-4-fast-non-reasoning');
} catch (error) {
  console.error('Selected model "Grok 4.2" is configured but failed to initialize.', error);
  throw new Error('Failed to initialize selected model.');
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Unvalidated model override: The new SPECIFIC_API_MODEL override is used directly to select providers/models without
allowlisting/validation, which may enable unintended model routing or unsafe
configurations depending on deployment controls.

Referred Code
const specificModel = process.env.SPECIFIC_API_MODEL;
const xaiApiKey = process.env.XAI_API_KEY;
const gemini3ProApiKey = process.env.GEMINI_3_PRO_API_KEY;
const awsAccessKeyId = process.env.AWS_ACCESS_KEY_ID;
const awsSecretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
const awsRegion = process.env.AWS_REGION;
const bedrockModelId = process.env.BEDROCK_MODEL_ID || 'anthropic.claude-3-5-sonnet-20241022-v2:0';
const openaiApiKey = process.env.OPENAI_API_KEY;

if (specificModel) {
  if (specificModel.includes('grok')) {
    const xai = createXai({
      apiKey: xaiApiKey,
      baseURL: 'https://api.x.ai/v1',
    });
    return xai(specificModel);
  }
  if (specificModel.includes('gemini')) {
    const google = createGoogleGenerativeAI({
      apiKey: gemini3ProApiKey,
    });


 ... (clipped 7 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Incorporate drawn features into the prompt

The resolutionSearch agent should be updated to include the drawnFeatures data
within the system prompt sent to the AI model. Currently, this data is received
but not utilized in the analysis.

Examples:

lib/agents/resolution-search.tsx [33-81]
export async function resolutionSearch(messages: CoreMessage[], timezone: string = 'UTC', drawnFeatures?: DrawnFeature[]) {
  const localTime = new Date().toLocaleString('en-US', {
    timeZone: timezone,
    hour: '2-digit',
    minute: '2-digit',
    hour12: true,
    weekday: 'long',
    year: 'numeric',
    month: 'long',
    day: 'numeric'

 ... (clipped 39 lines)

Solution Walkthrough:

Before:

// file: lib/agents/resolution-search.tsx

export async function resolutionSearch(messages: CoreMessage[], timezone: string = 'UTC', drawnFeatures?: DrawnFeature[]) {
  // ...
  const systemPrompt = `You are an expert geospatial analyst.
  ...
  Analyze the user's prompt and the image to provide a holistic understanding of the location.
  ...
  `; // drawnFeatures is ignored

  const result = await streamObject({
    model: await getModel(true),
    system: systemPrompt,
    messages: filteredMessages,
    schema: resolutionSearchSchema
  });
  return result;
}

After:

// file: lib/agents/resolution-search.tsx

export async function resolutionSearch(messages: CoreMessage[], timezone: string = 'UTC', drawnFeatures?: DrawnFeature[]) {
  let drawnFeaturesContext = '';
  if (drawnFeatures && drawnFeatures.length > 0) {
    const featureDescriptions = drawnFeatures.map(f => `- A ${f.type} with measurement: ${f.measurement}`).join('\n');
    drawnFeaturesContext = `The user has highlighted specific areas on the map:\n${featureDescriptions}\nPay special attention to these areas in your analysis.`;
  }

  const systemPrompt = `You are an expert geospatial analyst.
  ...
  ${drawnFeaturesContext}
  Analyze the user's prompt and the image to provide a holistic understanding of the location.
  `;

  const result = await streamObject({
    model: await getModel(true),
    system: systemPrompt,
    // ...
  });
  return result;
}
Suggestion importance[1-10]: 9

__

Why: This suggestion correctly identifies a critical flaw where the drawnFeatures data is passed to the resolutionSearch agent but is never used, rendering a key part of the new functionality non-operational.

High
Possible issue
Prevent invalid map zoom calculation

In the zoom calculation, use Math.abs(range || 1) to prevent Math.log2 from
receiving a non-positive number, which would result in a NaN value and a failed
API call.

components/header-search-button.tsx [78-80]

-const zoom = Math.round(Math.log2(40000000 / (range || 1)));
+const zoom = Math.round(Math.log2(40000000 / Math.abs(range || 1)));
 
 let staticMapUrl = `https://maps.googleapis.com/maps/api/staticmap?center=${center.lat},${center.lng}&zoom=${zoom}&size=640x480&scale=2&maptype=satellite&key=${apiKey}`;
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential edge case where range could be non-positive, leading to a NaN zoom value and a failed API request. Applying Math.abs() makes the calculation more robust.

Medium
Add missing API key validation

Add checks to ensure API keys (xaiApiKey, gemini3ProApiKey, openaiApiKey) are
present before creating AI clients, and throw an error if a key is missing.

lib/utils/index.ts [30-48]

 if (specificModel) {
   if (specificModel.includes('grok')) {
+    if (!xaiApiKey) throw new Error('XAI_API_KEY is not set for Grok model.');
     const xai = createXai({
       apiKey: xaiApiKey,
       baseURL: 'https://api.x.ai/v1',
     });
     return xai(specificModel);
   }
   if (specificModel.includes('gemini')) {
+    if (!gemini3ProApiKey) throw new Error('GEMINI_3_PRO_API_KEY is not set for Gemini model.');
     const google = createGoogleGenerativeAI({
       apiKey: gemini3ProApiKey,
     });
     return google(specificModel);
   }
+  if (!openaiApiKey) throw new Error('OPENAI_API_KEY is not set for OpenAI model.');
   const openai = createOpenAI({
     apiKey: openaiApiKey,
   });
-  return openai(specificmodel);
+  return openai(specificModel);
 }
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: This is a good error handling practice that makes the application fail fast with a clear error message if an API key is missing, improving robustness and maintainability.

Low
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants