Skip to content

Fix resolution search and UI consistency#491

Open
ngoiyaeric wants to merge 2 commits intomainfrom
fix/resolution-search-and-ui-consistency-7491228516552462755
Open

Fix resolution search and UI consistency#491
ngoiyaeric wants to merge 2 commits intomainfrom
fix/resolution-search-and-ui-consistency-7491228516552462755

Conversation

@ngoiyaeric
Copy link
Collaborator

@ngoiyaeric ngoiyaeric commented Feb 4, 2026

User description

This PR fixes multiple issues with the resolution search feature and general UI consistency:

  • Fixed lib/utils/index.ts to use correct model IDs and respect the requireVision flag.
  • Updated resolution search in app/actions.tsx to initialize with a loading message.
  • Replaced react-toastify with sonner in components/header-search-button.tsx.
  • Included the captured image in the UserMessage for resolution search for immediate feedback.
  • Synchronized isMobile breakpoints to 768px across components.
  • Fixed a bug in components/chat-panel.tsx where the input form was hidden on desktop when messages were present.
  • Adjusted mobile padding and filename wrapping in ChatPanel.

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


PR Type

Bug fix, Enhancement


Description

  • Fixed model ID mappings in getModel() to use correct model names and respect requireVision flag

  • Synchronized mobile breakpoint from 1024px to 768px across components

  • Replaced react-toastify with sonner for consistent toast notifications

  • Fixed chat panel layout bug where input form was hidden on desktop with messages

  • Improved resolution search UX with loading message and captured image in UserMessage

  • Enhanced file attachment UI with better text wrapping and error handling


Diagram Walkthrough

flowchart LR
  A["Model Configuration"] -->|"Use correct model IDs"| B["getModel function"]
  B -->|"Respect requireVision flag"| C["Vision-aware model selection"]
  D["Mobile Breakpoint"] -->|"Standardize to 768px"| E["ChatPanel & Components"]
  F["Toast Notifications"] -->|"Replace react-toastify"| G["Use sonner"]
  H["Resolution Search"] -->|"Add loading state & image"| I["Improved UX"]
  J["Chat Panel Layout"] -->|"Fix desktop visibility"| K["Input form always visible"]
Loading

File Walkthrough

Relevant files
Bug fix
index.ts
Correct model IDs and add vision support                                 

lib/utils/index.ts

  • Fixed Grok model ID from grok-4-fast-non-reasoning to grok-beta with
    vision variant support
  • Fixed Gemini model ID from gemini-3-pro-preview to gemini-1.5-pro
  • Updated both explicit model selection and fallback chain to use
    correct model names
  • Added conditional logic to use grok-vision-beta when requireVision is
    true
+4/-4     
chat-panel.tsx
Fix layout bug and standardize mobile breakpoint                 

components/chat-panel.tsx

  • Changed mobile breakpoint from 1024px to 768px for consistency
  • Replaced alert() with toast.error() for file size validation
  • Fixed chat panel layout bug by moving "New chat" button inside main
    container to prevent hiding input form on desktop
  • Adjusted input field padding: added px-4 for mobile, kept pl-14 for
    desktop
  • Added break-all class to filename display for better text wrapping
  • Removed unused import of SuggestionsDropdown, added import for sonner
    toast
+29/-32 
Enhancement
actions.tsx
Add loading message to resolution search                                 

app/actions.tsx

  • Initialize resolution search stream with loading message "Analyzing
    map view..."
  • Provides immediate user feedback while processing resolution search
+1/-1     
header-search-button.tsx
Include image in UserMessage and use sonner                           

components/header-search-button.tsx

  • Replaced react-toastify import with sonner for consistent toast
    notifications
  • Moved UserMessage creation to after image blob is captured and
    converted to URL
  • Included captured map image in UserMessage content alongside text for
    immediate visual feedback
  • Improved resolution search flow by ensuring image is available before
    displaying message
+18/-9   

Summary by CodeRabbit

  • New Features

    • Map images now displayed alongside analysis requests for better context.
  • Bug Fixes

    • Improved error feedback for oversized file uploads.
    • Enhanced mobile layout responsiveness.
  • Chores

    • Updated AI model integrations for improved performance.
    • Refined initial feedback messaging during map analysis.

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

vercel bot commented Feb 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
qcx Ready Ready Preview, Comment Feb 4, 2026 0:14am

@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@charliecreates charliecreates bot requested a review from CharlieHelps February 4, 2026 11:57
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 4, 2026

Warning

Rate limit exceeded

@ngoiyaeric has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 11 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 6b24889 and ee18cc3.

📒 Files selected for processing (3)
  • app/actions.tsx
  • components/chat.tsx
  • lib/agents/resolution-search.tsx

Walkthrough

The PR updates the map analysis streaming text, migrates toast notifications from react-toastify to sonner, includes map images within chat messages, adjusts mobile layout breakpoints, and updates AI model identifiers for Grok and Gemini providers.

Changes

Cohort / File(s) Summary
Toast Notification Migration
components/chat-panel.tsx, components/header-search-button.tsx
Replaced toast imports from react-toastify with sonner; updated file-size alert and error handling to use toast.error().
Chat Panel Layout & Input Refinements
components/chat-panel.tsx
Changed mobile breakpoint from ≤ 1024 to < 768; repositioned new chat button inside main render with conditional desktop display; adjusted input/attachment padding (added mobile px-4, modified desktop pl-14); updated selected filename styling to use break-all for text wrapping.
AI Model Provider Selection
lib/utils/index.ts
Updated Grok model selection to dynamic variants (grok-vision-beta or grok-beta based on vision requirement); changed Gemini fallback from gemini-3-pro-preview to gemini-1.5-pro.
Map Analysis Stream & Image Integration
app/actions.tsx, components/header-search-button.tsx
Changed initial summaryStream value to 'Analyzing map view...'; modified header-search-button to create image URLs from map blobs and append UserMessages containing both text ("Analyze this map view.") and the captured map image.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

Review effort 3/5

Poem

🐰 With sonner's toast and gleaming cheer,
Maps now join the chat right here!
Grok and Gemini stride anew,
Layout tighter, messages bright too! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix resolution search and UI consistency' directly reflects the main changes: fixing resolution search initialization with a loading message, correcting model IDs, replacing toast libraries, and synchronizing mobile layout breakpoints for UI consistency.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/resolution-search-and-ui-consistency-7491228516552462755

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Feb 4, 2026

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
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: Security-First Input Validation and Data Handling

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

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:
Unclear identifier: The newly added variable groupeId appears to be a misspelling/unclear name, reducing
self-documentation and intent clarity.

Referred Code
const groupeId = nanoid();

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:
Missing cleanup: The new URL.createObjectURL(blob) usage does not revoke the generated object URL, risking
memory leaks during repeated searches.

Referred Code
const imageUrl = URL.createObjectURL(blob);

setMessages(currentMessages => [
  ...currentMessages,
  {
    id: nanoid(),
    component: (
      <UserMessage
        content={[
          { type: 'text', text: 'Analyze this map view.' },
          { type: 'image', image: imageUrl }
        ]}
      />
    )
  }
])

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 exposure risk: New/modified paths log raw caught error objects via console.error/console.warn, which may
expose sensitive provider or environment details depending on runtime logging
configuration.

Referred Code
      return xai(requireVision ? 'grok-vision-beta' : 'grok-beta');
    } catch (error) {
      console.error('Selected model "Grok 4.2" is configured but failed to initialize.', error);
      throw new Error('Failed to initialize selected model.');
    }
  } else {
      console.error('User selected "Grok 4.2" but XAI_API_KEY is not set.');
      throw new Error('Selected model is not configured.');
  }
case 'Gemini 3':
  if (gemini3ProApiKey) {
    const google = createGoogleGenerativeAI({
      apiKey: gemini3ProApiKey,
    });
    try {
      return google('gemini-1.5-pro');
    } catch (error) {
      console.error('Selected model "Gemini 3" is configured but failed to initialize.', error);
      throw new Error('Failed to initialize selected model.');
    }
  } else {


 ... (clipped 38 lines)

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 logs: The updated code continues to emit unstructured console logs and includes raw error
objects, which may contain sensitive request/provider context in some environments.

Referred Code
      return xai(requireVision ? 'grok-vision-beta' : 'grok-beta');
    } catch (error) {
      console.error('Selected model "Grok 4.2" is configured but failed to initialize.', error);
      throw new Error('Failed to initialize selected model.');
    }
  } else {
      console.error('User selected "Grok 4.2" but XAI_API_KEY is not set.');
      throw new Error('Selected model is not configured.');
  }
case 'Gemini 3':
  if (gemini3ProApiKey) {
    const google = createGoogleGenerativeAI({
      apiKey: gemini3ProApiKey,
    });
    try {
      return google('gemini-1.5-pro');
    } catch (error) {
      console.error('Selected model "Gemini 3" is configured but failed to initialize.', error);
      throw new Error('Failed to initialize selected model.');
    }
  } else {


 ... (clipped 38 lines)

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

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

Copy link

@charliecreates charliecreates bot left a comment

Choose a reason for hiding this comment

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

  • URL.createObjectURL(blob) in HeaderSearchButton is not revoked, causing a likely memory leak during repeated resolution searches.
  • getModel(requireVision) is only partially honoring requireVision (xAI does; Gemini doesn’t), which can lead to inconsistent behavior when images are attached.
  • The breakpoint comparison changed to < 768; confirm this matches the CSS breakpoint semantics to avoid edge-case layout mismatches at exactly 768px.
Additional notes (4)
  • Maintainability | lib/utils/index.ts:52-52
    getModel(requireVision) now respects requireVision for xAI, but the Gemini path ignores it and always returns gemini-1.5-pro. If resolution search attaches images (as this PR now does), the Gemini fallback should likely choose a vision-capable model when requireVision === true, otherwise the behavior differs across providers.

  • Maintainability | lib/utils/index.ts:37-43
    The model ID changes for xAI switch to grok-beta / grok-vision-beta. These look like beta identifiers; if this is deliberate, consider how you’ll handle stability and future upgrades. Also, the selected label “Grok 4.2” no longer maps to a “4.x” model name, which can be confusing for users and makes incident debugging harder (UI label and backend model diverge).

  • Readability | components/chat-panel.tsx:56-62
    The new mobile breakpoint uses < 768. Most responsive logic uses <= comparisons to avoid a 1px “dead zone” at the exact breakpoint. At exactly 768, this code will treat the layout as desktop, which may contradict the rest of the app’s CSS breakpoints depending on how md: is defined.

  • Readability | components/chat-panel.tsx:292-297
    The attachment filename span now combines truncate with break-all. truncate relies on overflow-hidden/text-ellipsis/whitespace-nowrap, while break-all encourages wrapping; together they can produce inconsistent results across browsers and can defeat the goal (either it never wraps, or it wraps but still ellipsizes oddly).

Summary of changes

What changed

  • Resolution search UX

    • Initialized the resolution-search summary stream with a loading message ("Analyzing map view...") in app/actions.tsx.
  • Chat panel UI + behavior (components/chat-panel.tsx)

    • Standardized the mobile breakpoint to < 768.
    • Replaced the attachment oversize alert() with sonner toast.error().
    • Fixed desktop behavior where the input form could disappear by moving the “New chat” button into the main render instead of returning early.
    • Adjusted padding/left-right spacing for mobile vs desktop input.
    • Improved filename wrapping by adding break-all.
  • Header resolution search (components/header-search-button.tsx)

    • Migrated toast provider to sonner.
    • Added immediate visual feedback by rendering the captured map image in the UserMessage (via URL.createObjectURL(blob)) before submitting the action.
  • Model selection logic (lib/utils/index.ts)

    • Updated xAI model IDs to respect requireVision (grok-vision-beta vs grok-beta).
    • Switched Gemini model ID from gemini-3-pro-preview to gemini-1.5-pro in both selected and fallback paths.

Comment on lines +81 to +97
const imageUrl = URL.createObjectURL(blob);

setMessages(currentMessages => [
...currentMessages,
{
id: nanoid(),
component: (
<UserMessage
content={[
{ type: 'text', text: 'Analyze this map view.' },
{ type: 'image', image: imageUrl }
]}
/>
)
}
])

Copy link

Choose a reason for hiding this comment

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

Creating an object URL for the captured image without revoking it can leak memory over time (each search allocates a blob URL that persists until URL.revokeObjectURL). This is especially risky if users perform multiple searches in a session.

Suggestion

Revoke the object URL after it’s no longer needed. If UserMessage only needs the URL for rendering, you can revoke it after the image loads (best), or at least after the request completes.

One pragmatic approach is to track the URL and revoke it in a finally block (may revoke too early if the image is still rendering), or better, pass a callback to revoke on image onLoad.

Example (safer: revoke on image load inside UserMessage):

  • Extend UserMessage image rendering to accept an onLoad handler and call URL.revokeObjectURL(imageUrl).

Minimal stopgap (revoke after submission finishes):

const imageUrl = URL.createObjectURL(blob);
try {
  setMessages(/* ... */)
  // submit
} finally {
  URL.revokeObjectURL(imageUrl);
}

Reply with "@CharlieHelps yes please" if you'd like me to add a commit implementing URL revocation in the most appropriate place (preferably on image load).

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Feb 4, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
Revoke object URL to prevent memory leaks

Revoke the imageUrl created with URL.createObjectURL() using
URL.revokeObjectURL() after it is no longer needed to prevent memory leaks.

components/header-search-button.tsx [81-96]

 const imageUrl = URL.createObjectURL(blob);
 
 setMessages(currentMessages => [
   ...currentMessages,
   {
     id: nanoid(),
     component: (
       <UserMessage
         content={[
           { type: 'text', text: 'Analyze this map view.' },
           { type: 'image', image: imageUrl }
         ]}
       />
     )
   }
-])
+]);
 
+formData.append('file', blob, 'map_capture.png');
+formData.append('action', 'resolution_search');
+// ... submit or send formData ...
+URL.revokeObjectURL(imageUrl);
+

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential memory leak from an unrevoked object URL and proposes a valid fix, which improves application stability.

Medium
  • Update

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: 3

🤖 Fix all issues with AI agents
In `@components/chat-panel.tsx`:
- Around line 173-193: The fixed "New chat" button wrapper lacks an explicit
z-index and can be rendered behind other stacking contexts; update the wrapper
div (the element rendered when messages.length > 0 && !isMobile) to include a
higher z-index in its className (e.g., add "z-11" or larger) so the Button (the
Button with onClick={() => handleClear()} and the Plus icon) reliably appears
above the sticky input container.

In `@components/header-search-button.tsx`:
- Around line 81-96: The blob URL created by URL.createObjectURL(blob) is never
revoked and can leak memory; update the message creation in the setMessages
callback to use a persistent data URL instead of a blob URL (use the same base64
data URL produced in app/actions.tsx for the AI message) or ensure you call
URL.revokeObjectURL(imageUrl) when the message is removed/cleared; locate the
code that builds the message component (setMessages / UserMessage) and replace
image: imageUrl with the base64 data URL or add cleanup logic tied to message
removal to revoke the blob URL.

In `@lib/utils/index.ts`:
- Line 84: The fallback return uses xai(requireVision ? 'grok-vision-beta' :
'grok-beta') but doesn't apply the same structured-output handling used for the
explicit Grok selection; update the fallback path so when returning via xai(...)
it wraps or configures the chosen model to enforce structured outputs (mirror
the structured-output wrapper/logic used elsewhere for explicit selection),
referencing the same requireVision flag and the model names ('grok-vision-beta'
and 'grok-beta') and the xai call so both paths produce consistent structured
output.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f89e3f7 and 6b24889.

📒 Files selected for processing (4)
  • app/actions.tsx
  • components/chat-panel.tsx
  • components/header-search-button.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 (3)
app/actions.tsx (1)
lib/agents/resolution-search.tsx (2)
  • resolutionSearch (33-79)
  • f (50-50)
components/header-search-button.tsx (2)
components/user-message.tsx (1)
  • UserMessage (15-53)
components/map/google-map.tsx (2)
  • GoogleMapComponent (12-86)
  • apiKey (20-29)
components/chat-panel.tsx (3)
lib/utils/index.ts (1)
  • cn (12-14)
components/ui/button.tsx (1)
  • Button (56-56)
components/chat.tsx (1)
  • Chat (29-229)
🔇 Additional comments (8)
app/actions.tsx (1)

87-87: LGTM!

Initializing summaryStream with 'Analyzing map view...' provides immediate visual feedback to the user while the resolution search streams its response. This aligns well with the PR objective of improving UI consistency.

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

12-12: LGTM on toast migration.

Replacing react-toastify with sonner aligns with the PR objective and maintains consistency with the same change in chat-panel.tsx.

components/chat-panel.tsx (4)

59-59: LGTM on breakpoint synchronization.

Changing the mobile breakpoint from <= 1024 to < 768 aligns with the isMobile detection in components/chat.tsx, ensuring consistent responsive behavior across the application. This matches the PR objective of synchronizing the isMobile breakpoint to 768px.


70-70: Good replacement of alert with toast.

Using toast.error() from sonner provides a non-blocking, more polished user experience compared to the native alert() dialog.


241-246: LGTM on input styling adjustments.

The padding changes (px-4 for mobile, pl-14 for desktop) appropriately accommodate the attachment button placement on desktop while maintaining clean mobile styling.


294-294: LGTM on filename wrapping.

Adding break-all ensures long filenames without natural word breaks (e.g., map_capture_2026020411570512345.png) wrap properly within the container.

lib/utils/index.ts (2)

55-55: Model identifier change requires clarification.

The code changed from gemini-3-pro-preview to gemini-1.5-pro. However, current Gemini API documentation (2025) lists gemini-3-pro-preview as an available model identifier, while gemini-1.5-pro does not appear in the current model catalog. This appears to be a regression to an older/obsolete model rather than a correction to a stable identifier. Clarify the reasoning behind this change—if compatibility with an older API version is required, that should be documented.

Likely an incorrect or invalid review comment.


40-40: ⚠️ Potential issue | 🟠 Major

Use grok-2-vision-1212 (or newer) instead of grok-vision-beta for resolution-search structured outputs.

resolution-search uses streamObject with a Zod schema for structured geospatial analysis output. When satellite images are provided (the primary use case), this calls getModel(true), which returns grok-vision-beta.

Per X.AI integration documentation, grok-vision-beta is treated as a legacy model and does not guarantee native JSON schema support for structured outputs—it falls back to a tool-calling workaround. Use grok-2-vision-1212 or newer for reliable JSON schema enforcement with vision capabilities.

Alternatively, use OpenAI gpt-4o (which supports both vision and structured outputs reliably) if X.AI model availability is a constraint.

⛔ Skipped due to learnings
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.
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.

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

Comment on lines +173 to +193
{/* New chat button (appears when there are messages on desktop) */}
{messages.length > 0 && !isMobile && (
<div
className={cn(
'fixed bottom-2 left-2 flex justify-start items-center pointer-events-none md:bottom-8'
)}
>
<Button
type="button"
variant={'secondary'}
className="rounded-full bg-secondary/80 group transition-all hover:scale-105 pointer-events-auto"
onClick={() => handleClear()}
data-testid="new-chat-button"
>
<span className="text-sm mr-2 group-hover:block hidden animate-in fade-in duration-300">
New
</span>
<Plus size={18} className="group-hover:rotate-90 transition-all" />
</Button>
</div>
)}
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:

cat -n components/chat-panel.tsx | sed -n '165,200p'

Repository: QueueLab/QCX

Length of output: 1559


🏁 Script executed:

#!/bin/bash
# Check for other fixed/sticky positioned elements that might overlap
rg -n "fixed|sticky" --type=tsx -C2 components/

Repository: QueueLab/QCX

Length of output: 83


🏁 Script executed:

#!/bin/bash
# Search for fixed/sticky positioning in component files
rg "fixed|sticky" components/ -C2

Repository: QueueLab/QCX

Length of output: 5523


🏁 Script executed:

# Also check specifically for z-index usage in chat-panel.tsx
rg "z-index|z-\d+" components/chat-panel.tsx -n

Repository: QueueLab/QCX

Length of output: 156


Add explicit z-index to the fixed button to prevent stacking order issues.

The fixed button uses bottom-2 left-2 positioning without an explicit z-index, while its parent sticky container has z-10. Since the fixed element is nested as a child in the DOM, it may be rendered behind the sticky parent depending on stacking context. Add z-11 or higher to the fixed wrapper's className to ensure the button appears on top of the sticky input container.

🤖 Prompt for AI Agents
In `@components/chat-panel.tsx` around lines 173 - 193, The fixed "New chat"
button wrapper lacks an explicit z-index and can be rendered behind other
stacking contexts; update the wrapper div (the element rendered when
messages.length > 0 && !isMobile) to include a higher z-index in its className
(e.g., add "z-11" or larger) so the Button (the Button with onClick={() =>
handleClear()} and the Plus icon) reliably appears above the sticky input
container.

});
try {
return xai('grok-4-fast-non-reasoning');
return xai(requireVision ? 'grok-vision-beta' : 'grok-beta');
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

Same structured output concern applies to the fallback path.

The default fallback path has the same potential issue with Grok models and structured outputs as noted for the explicit selection path above.

🤖 Prompt for AI Agents
In `@lib/utils/index.ts` at line 84, The fallback return uses xai(requireVision ?
'grok-vision-beta' : 'grok-beta') but doesn't apply the same structured-output
handling used for the explicit Grok selection; update the fallback path so when
returning via xai(...) it wraps or configures the chosen model to enforce
structured outputs (mirror the structured-output wrapper/logic used elsewhere
for explicit selection), referencing the same requireVision flag and the model
names ('grok-vision-beta' and 'grok-beta') and the xai call so both paths
produce consistent structured output.

- Fixed model mapping and vision support in getModel.
- Improved resolution search UX with loading states and immediate image feedback.
- Synchronized mobile breakpoints and layout padding across components.
- Fixed suggestion/example submission logic in Chat component.
- Implemented robust hydration refresh pattern in Chat component.
- Fixed app/actions.tsx type safety and researcher agent call signature.
- Enhanced resolution search agent to prioritize user-drawn features.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
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.

2 participants