Skip to content

Conversation

@zachdive
Copy link
Contributor

No description provided.

- Add SuggestionPills component showing clickable follow-up suggestions
- Update ChatSection to display suggestions above text input
- Add suggestions field to Content and ParametricArtifact types
- Update chat function to generate 3 short suggestions after creating artifact
- Uses Claude Haiku for fast, cheap suggestion generation
- Add suggestion-generator Supabase function
- ChatSection calls suggestion-generator after model is created
- Base suggestions on what user asked for, not assistant response
- Remove backend suggestion generation from chat function
@vercel
Copy link

vercel bot commented Dec 15, 2025

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

Project Deployment Review Updated (UTC)
cadam Ready Ready Preview, Comment Dec 15, 2025 1:59am

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Dec 15, 2025

Greptile Overview

Greptile Summary

This PR adds AI-powered suggestion pills that appear after the assistant generates a 3D model, offering users contextual follow-up prompts like "Add handle" or "Add mounting holes".

Key Changes:

  • New suggestion-generator Edge Function calls OpenRouter API (claude-3.5-haiku) to generate 2 contextual suggestions based on user prompt and generated code
  • Authentication properly implemented with JWT verification in both config.toml and function code
  • Frontend effect triggers suggestion generation when assistant completes with an artifact, displays pills in a horizontal scrollable layout
  • Uses cancellation flag to prevent stale state updates from race conditions (though doesn't abort HTTP request)

Observations:

  • Previous thread comments about authentication, race conditions, and effect optimization have been addressed through JWT verification in config and cancellation flag implementation
  • The suggestion prompt emphasizes "new features" over parameter adjustments, aligning with commit message 21eb29f
  • Code truncated to 1500 chars before sending to API (reasonable for context while managing token costs)

Confidence Score: 4/5

  • This PR is safe to merge with minor issues already flagged in previous review threads
  • The implementation is solid with proper authentication, error handling, and user experience considerations. Previous review comments identified valid style improvements (effect optimization, retry logic, key prop usage) but none are blocking issues. The cancellation flag prevents stale state updates adequately for this use case. Code quality is good overall.
  • No files require special attention - previous review comments cover the minor style improvements

Important Files Changed

File Analysis

Filename Score Overview
supabase/functions/suggestion-generator/index.ts 4/5 New Edge Function that generates 2 follow-up suggestions using OpenRouter API, includes proper authentication and error handling
src/components/chat/SuggestionPills.tsx 5/5 New component displaying suggestion pills as clickable buttons in a horizontal scrollable layout
src/components/chat/ChatSection.tsx 4/5 Added suggestion generation logic that calls Edge Function after assistant responds with artifact, displays pills via new component

Sequence Diagram

sequenceDiagram
    participant User
    participant ChatSection
    participant SuggestionPills
    participant EdgeFunction as suggestion-generator
    participant OpenRouter

    User->>ChatSection: Send message (e.g., "create a box")
    ChatSection->>EdgeFunction: POST /chat (via useSendContentMutation)
    Note over ChatSection: isLoading = true, suggestions cleared
    EdgeFunction-->>ChatSection: Assistant message with artifact (code)
    Note over ChatSection: isLoading = false
    
    ChatSection->>ChatSection: useEffect triggered (loading done + artifact exists)
    ChatSection->>EdgeFunction: POST /suggestion-generator<br/>{userPrompt, generatedCode}
    EdgeFunction->>EdgeFunction: Authenticate user via JWT
    EdgeFunction->>OpenRouter: Generate 2 suggestions<br/>(claude-3.5-haiku)
    OpenRouter-->>EdgeFunction: Suggestions in XML tags
    EdgeFunction->>EdgeFunction: Parse <suggestion> tags
    EdgeFunction-->>ChatSection: {suggestions: ["Add handle", "Add lid"]}
    
    ChatSection->>SuggestionPills: Render pills (suggestions)
    SuggestionPills-->>User: Display suggestion buttons
    
    User->>SuggestionPills: Click "Add handle"
    SuggestionPills->>ChatSection: onSelect("Add handle")
    ChatSection->>EdgeFunction: POST /chat with "Add handle"
    Note over ChatSection: Process repeats
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 7 to 23
Deno.serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders });
}

if (req.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}

try {
const { userPrompt } = await req.json();

if (!userPrompt) {
return new Response(JSON.stringify({ suggestions: [] }), {
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: no authentication check - unlike title-generator/index.ts which validates the user. anyone with the function URL can call this and consume API credits

Prompt To Fix With AI
This is a comment left during a code review.
Path: supabase/functions/suggestion-generator/index.ts
Line: 7:23

Comment:
**logic:** no authentication check - unlike `title-generator/index.ts` which validates the user. anyone with the function URL can call this and consume API credits

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 81 to 123
useEffect(() => {
// Don't generate while loading
if (isLoading) {
setSuggestions([]);
return;
}

// Need a user message to base suggestions on
const userPrompt = lastUserMessage?.content?.text;
if (!userPrompt) {
setSuggestions([]);
return;
}

// Check if the last message is an assistant message with an artifact (model was generated)
const lastMsg = messages[messages.length - 1];
if (lastMsg?.role !== 'assistant' || !lastMsg?.content?.artifact) {
setSuggestions([]);
return;
}

// Generate suggestions
const generateSuggestions = async () => {
try {
const { data, error } = await supabase.functions.invoke(
'suggestion-generator',
{
body: { userPrompt },
},
);

if (error) throw error;
if (data?.suggestions) {
setSuggestions(data.suggestions);
}
} catch (err) {
console.error('Failed to generate suggestions:', err);
setSuggestions([]);
}
};

generateSuggestions();
}, [isLoading, lastUserMessage, messages]);
Copy link
Contributor

Choose a reason for hiding this comment

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

style: effect triggers on every messages change, but only generates suggestions when specific conditions are met. this causes unnecessary re-evaluation

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/chat/ChatSection.tsx
Line: 81:123

Comment:
**style:** effect triggers on every `messages` change, but only generates suggestions when specific conditions are met. this causes unnecessary re-evaluation

How can I resolve this? If you propose a fix, please make it concise.

return (
<div className="scrollbar-hide flex gap-2 overflow-x-auto pb-2 [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
{suggestions.map((suggestion, index) => (
<Button
Copy link
Contributor

Choose a reason for hiding this comment

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

style: using array index as key can cause rendering issues if suggestions change. use the suggestion text itself as the key since suggestions are unique

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/chat/SuggestionPills.tsx
Line: 20:20

Comment:
**style:** using array index as `key` can cause rendering issues if suggestions change. use the suggestion text itself as the key since suggestions are unique

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 107 to 128
const generateSuggestions = async () => {
try {
const { data, error } = await supabase.functions.invoke(
'suggestion-generator',
{
body: {
userPrompt,
generatedCode,
parameters,
},
},
);

if (error) throw error;
if (data?.suggestions) {
setSuggestions(data.suggestions);
}
} catch (err) {
console.error('Failed to generate suggestions:', err);
setSuggestions([]);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

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

style: no retry logic if suggestion generation fails - users won't see suggestions after a transient network error. consider persisting failure state to avoid repeated failed calls

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/chat/ChatSection.tsx
Line: 107:128

Comment:
**style:** no retry logic if suggestion generation fails - users won't see suggestions after a transient network error. consider persisting failure state to avoid repeated failed calls

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 26 to 31
const paramSummary = parameters
?.map(
(p: { name: string; value: string | number | boolean }) =>
`${p.name}=${p.value}`,
)
.join(', ');
Copy link
Contributor

Choose a reason for hiding this comment

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

style: parameters is typed inline - consider using the Parameter type from @shared/types.ts for consistency with the rest of the codebase

Prompt To Fix With AI
This is a comment left during a code review.
Path: supabase/functions/suggestion-generator/index.ts
Line: 26:31

Comment:
**style:** `parameters` is typed inline - consider using the `Parameter` type from `@shared/types.ts` for consistency with the rest of the codebase

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +7 to +14
Deno.serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders });
}

if (req.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}
Copy link
Contributor

Choose a reason for hiding this comment

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

style: add function registration to config.toml with verify_jwt = true per backend architecture guidelines

Prompt To Fix With AI
This is a comment left during a code review.
Path: supabase/functions/suggestion-generator/index.ts
Line: 7:14

Comment:
**style:** add function registration to `config.toml` with `verify_jwt = true` per backend architecture guidelines

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 106 to 128
const generateSuggestions = async () => {
try {
const { data, error } = await supabase.functions.invoke(
'suggestion-generator',
{
body: {
userPrompt,
generatedCode,
},
},
);

if (error) throw error;
if (data?.suggestions) {
setSuggestions(data.suggestions);
}
} catch (err) {
console.error('Failed to generate suggestions:', err);
setSuggestions([]);
}
};

generateSuggestions();
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: generateSuggestions doesn't cancel ongoing requests - if messages change rapidly while a suggestion request is pending, multiple requests fire and the last to complete wins. race conditions may show stale suggestions

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/chat/ChatSection.tsx
Line: 106:128

Comment:
**logic:** `generateSuggestions` doesn't cancel ongoing requests - if messages change rapidly while a suggestion request is pending, multiple requests fire and the last to complete wins. race conditions may show stale suggestions

How can I resolve this? If you propose a fix, please make it concise.

- Add authentication to suggestion-generator (prevents unauthorized API usage)
- Register suggestion-generator in config.toml with verify_jwt=true
- Use suggestion text as key instead of array index in SuggestionPills
- Add cancellation flag to prevent race conditions in suggestion generation
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

6 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

6 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants