Skip to content

Enhancement/auto gen personalization#190

Open
ibraheemshaikh5 wants to merge 9 commits intomainfrom
enhancement/auto-gen-personalization
Open

Enhancement/auto gen personalization#190
ibraheemshaikh5 wants to merge 9 commits intomainfrom
enhancement/auto-gen-personalization

Conversation

@ibraheemshaikh5
Copy link
Collaborator

@ibraheemshaikh5 ibraheemshaikh5 commented Feb 9, 2026

Important

Enhances auto-generation of personalized content in workspaces with user-selectable content types and improved handling of URL parameters.

  • New Features:
    • Adds generation settings in HomePromptInput.tsx for users to select content types (notes, quizzes, flashcards, YouTube) with persistence.
    • Implements type-aware generation in route.ts and AssistantPanel.tsx, reflecting selected types in prompts and creation flows.
    • Handles URL parameters for generation types in WorkspaceRuntimeProvider.tsx and AssistantPanel.tsx, ensuring scoped output.
  • Bug Fixes:
    • Falls back to full set of types if selected types produce no recognizable steps in AssistantPanel.tsx.
  • Misc:
    • Updates CREATE_FROM_REGEX in route.ts to make YouTube suffix optional.
    • Adds Popover for generation settings in HomePromptInput.tsx.
    • Removes genTypes from URL after use in AssistantPanel.tsx and WorkspaceRuntimeProvider.tsx.

This description was created by Ellipsis for f1cc7e5. You can customize this summary. It will automatically update as commits are pushed.


Summary by CodeRabbit

  • New Features

    • Generation settings letting users pick content types (notes, quizzes, flashcards, YouTube) with persistence.
    • Type-aware generation end-to-end: placeholders, prompts, and creation flows reflect selected types.
    • URL parameters for generation types are respected and removed after use; generation types are included in transports to ensure scoped output.
  • Bug Fixes

    • If selected types produce no recognizable steps, generation falls back to full set.

@vercel
Copy link

vercel bot commented Feb 9, 2026

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

Project Deployment Actions Updated (UTC)
thinkex Ready Ready Preview, Comment Feb 9, 2026 11:15pm

@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

📝 Walkthrough

Walkthrough

Adds opt-in, type-scoped generation (genTypes) end-to-end: UI for selecting content types, persisted settings, URL propagation, transport payload inclusion, handler usage, and API system-prompt generation that tailors and enforces allowed output types (note, quiz, flashcard, youtube).

Changes

Cohort / File(s) Summary
System Prompt Generation
src/app/api/chat/route.ts
getCreateFromSystemPrompt(messages, genTypes) signature updated; builds type-specific update instructions, quality guidelines, optional YouTube guidance, and conditional enforcement of allowed types. API parses genTypes from request body and forwards it.
Chat Transport Layer
src/components/assistant-ui/WorkspaceRuntimeProvider.tsx
Reads genTypes from URL search params for auto-init flows; includes genTypes in AssistantChatTransport payload and memo deps so transport recreates when it changes.
Handler Logic (Assistant UI)
src/components/assistant-ui/AssistantPanel.tsx
CreateFrom and GenerateStudyMaterials handlers read genTypes from searchParams, build type-aware prompts/messages (selecting steps and YouTube inclusion), include genTypes when sending, and remove genTypes from URL after sending; dependency arrays updated.
Generation Settings UI & Control
src/components/home/HomePromptInput.tsx
Adds GenContentType/GenerationSettings, default settings, localStorage persistence, UI (Popover + SlidersHorizontal) to toggle types/auto; generates dynamic placeholders based on effective types and propagates genTypes into workspace creation/navigation when custom settings active.
Miscellaneous
package.json
Small manifest/metadata spacing change.

Sequence Diagram

sequenceDiagram
    actor User
    participant HomeUI as HomePromptInput
    participant Transport as WorkspaceRuntimeProvider
    participant Handlers as AssistantPanel
    participant API as Chat API

    User->>HomeUI: Select genTypes / toggle auto
    HomeUI->>HomeUI: Persist GenerationSettings (localStorage)
    HomeUI->>HomeUI: Navigate/init with genTypes in URL
    HomeUI->>Transport: Init/navigation contains genTypes

    Transport->>Transport: Read genTypes from searchParams
    Transport->>Transport: Include genTypes in transport payload
    Transport->>Handlers: Initialize transport (contains genTypes)

    Handlers->>Handlers: Read genTypes from searchParams
    Handlers->>Handlers: Build type-aware message/prompt
    Handlers->>API: POST messages + genTypes
    API->>API: Parse genTypes, call getCreateFromSystemPrompt(messages, genTypes)
    API-->>Handlers: Return generated content scoped to genTypes
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Possibly related PRs

Suggested reviewers

  • urjitc

"I nibble at settings, plant a seed,
GenTypes chosen — notes, quizzes, feed,
Through URL, transport, prompts I hop,
Tailored outputs sprout, I never stop,
A rabbit cheers as pipelines lead!" 🐇✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Enhancement/auto gen personalization' is vague and does not clearly describe the main changes; it uses non-descriptive terms that lack specific detail about the feature being added. Consider a more descriptive title that clearly conveys the feature, such as 'Add user-selectable content generation types' or 'Allow users to customize generated content types'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch enhancement/auto-gen-personalization

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.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed everything up to 75abd9c in 23 seconds. Click for details.
  • Reviewed 631 lines of code in 4 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_J3TUvQ9ZQ8Wo09I2

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 4 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/app/api/chat/route.ts">

<violation number="1" location="src/app/api/chat/route.ts:99">
P2: The non-greedy capture in the createFrom regex truncates topics that contain periods (e.g., "U.S. history" becomes "U"). Use a greedy capture with backtracking so the optional YouTube suffix still matches while preserving the full topic.</violation>

<violation number="2" location="src/app/api/chat/route.ts:247">
P2: `genTypes` splitting doesn’t trim whitespace, so values like "note, quiz" won’t match the expected type keys and the prompt may omit requested sections. Trim and filter the split values before building the Set.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link

@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

🤖 Fix all issues with AI agents
In `@src/app/api/chat/route.ts`:
- Around line 128-131: The push strings for updateInstructions are using single
quotes so the ${topic} placeholder is not interpolated; change those three
string literals (the ones pushed when types.has('note'), types.has('flashcard'),
and types.has('quiz') in route.ts) to template literals using backticks so
${topic} is expanded (i.e., update the push calls that reference
updateNote/updateFlashcards/updateQuiz to use backtick strings including
${topic}).
- Around line 159-162: The prompt template in route.ts creates a numbering gap
because the hardcoded "4." assumes a conditional "3." injected by the
`restriction` variable (used alongside `updateInstructions.join('\n')`), so when
`restriction` is empty the list skips 3; fix this by building the instruction
lines programmatically instead of hardcoding indices — e.g., assemble an array
of items (using `updateInstructions` entries and conditionally pushing
`restriction` if present) and then map them to numbered strings
(`items.map((it,i)=>\`\${i+1}. \${it}\`)`) or always include a neutral item 3
when `genTypes`/`restriction` is missing; update the code that constructs the
prompt string (the template using `updateInstructions` and `restriction`) to use
this dynamic numbering approach so the sequence stays continuous.

In `@src/components/assistant-ui/AssistantPanel.tsx`:
- Around line 206-215: The prompt can be malformed when genTypes is set but
contains no recognized values because types/steps end up empty; adjust the logic
in AssistantPanel.tsx around genTypes/types/steps so you detect an empty steps
array before constructing prompt and provide a sensible fallback (e.g., populate
steps with a default instruction set or treat types as null to include all
steps), then build the prompt using the possibly-updated steps array; look for
the genTypes split, the types Set, the steps array and the prompt template to
apply the fix.

In `@src/components/home/HomePromptInput.tsx`:
- Around line 264-308: Duplicate placeholder construction should be
consolidated: add a helper like buildPlaceholderItems(effectiveTypes, startY,
variant?) that returns the array of placeholders with consistent fields (id,
type, name, subtitle, color, layout, lastSource, data) and deterministic
per-type colors (e.g., map type->color for 'note','quiz','flashcard') and
correct heights/layout logic; use this helper to replace both the uploads and
no-uploads blocks in HomePromptInput.tsx so every placeholder includes
lastSource: 'user' and uses the same color assignment and layout rules (refer to
the existing placeholder creation objects and variables currentY/totalUploadY,
pdfItems, and allItems to integrate the returned placeholders).
- Around line 618-689: The toggle buttons for content types (rendered in the
ALL_CONTENT_TYPES.map using toggleGenType and reading genSettings.types) and the
Auto toggle (which calls setGenSettings and reads genSettings.auto) are missing
accessibility attributes; update each toggle button element to include
role="switch", aria-checked set to the boolean active state (for type toggles:
genSettings.types.includes(key); for Auto: genSettings.auto), and add an
appropriate aria-label (e.g., `${label} toggle` for type toggles and "Auto
toggle" for Auto) so screen readers announce the control and its state; keep the
existing onClick handlers (toggleGenType / setGenSettings) intact.
🧹 Nitpick comments (1)
src/app/api/chat/route.ts (1)

247-248: No server-side validation of genTypes values.

body.genTypes is split and passed directly without validating that each element is a recognized type. While not a security risk (values are only used in prompt construction), invalid types silently produce an incomplete prompt. Consider filtering to known types.

🛡️ Suggested validation
-    const genTypes: string[] | null = body.genTypes ? body.genTypes.split(',') : null;
+    const VALID_GEN_TYPES = new Set(['note', 'quiz', 'flashcard', 'youtube']);
+    const genTypes: string[] | null = body.genTypes
+      ? body.genTypes.split(',').filter((t: string) => VALID_GEN_TYPES.has(t))
+      : null;
+    // Treat empty filtered array as null (all types)
+    const effectiveGenTypes = genTypes && genTypes.length > 0 ? genTypes : null;

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

This PR adds user-selectable “generation types” (notes/quizzes/flashcards/YouTube) with persistence, threads the selected types via genTypes through auto-init URL params, scopes genTypes propagation to only auto-init chat requests, and updates server-side create-from prompt detection/instructions to be type-aware (including making the YouTube suffix optional).

The main integration points are:

  • HomePromptInput persists settings, creates placeholder workspace items based on selected types, and appends genTypes to the workspace URL.
  • AssistantPanel reads genTypes to build type-aware auto-init prompts and removes URL params after sending.
    WorkspaceRuntimeProvider forwards genTypes only during auto-init flows.
  • /api/chat parses/validates genTypes and injects a type-scoped create-from system prompt.

One blocking issue remains: YouTube is a selectable type but no YouTube placeholder item is created in the new placeholder builder, which can produce an initial workspace state that cannot satisfy the type-scoped instructions.

Confidence Score: 3/5

  • This PR is close to merge-ready but has a functional gap in the new type-selection flow.
  • The genTypes threading/scoping is implemented consistently across client and server, but the HomePromptInput placeholder builder omits YouTube despite it being a selectable type, which can create workspaces that lack the required item for auto-init updates.
  • src/components/home/HomePromptInput.tsx

Important Files Changed

Filename Overview
src/app/api/chat/route.ts Adds optional YouTube suffix matching for createFrom prompts and passes genTypes through to build type-scoped create-from system instructions (validated + trimmed on server).
src/components/assistant-ui/AssistantPanel.tsx Makes auto-init prompts type-aware using genTypes from URL and cleans URL params after auto-sending; builds dynamic numbered generation steps with fallback to defaults on empty selection.
src/components/assistant-ui/WorkspaceRuntimeProvider.tsx Scopes genTypes propagation to /api/chat to only auto-init flows (createFrom or generate_study_materials) to avoid leaking URL constraints into normal chat.
src/components/home/HomePromptInput.tsx Adds persistent generation settings UI and uses selected types to build initial placeholder items and pass genTypes via URL; currently no YouTube placeholder is created despite being a selectable type.

Sequence Diagram

sequenceDiagram
  participant User
  participant Home as HomePromptInput
  participant Router
  participant WS as WorkspacePage
  participant Panel as AssistantPanel
  participant Runtime as WorkspaceRuntimeProvider
  participant API as ChatRoute

  User->>Home: Submit prompt + select types
  Home->>Router: push /workspace/:slug with genTypes
  Router->>WS: Navigate to workspace
  WS->>Panel: Mount auto-init handlers
  Panel->>Panel: Build type-aware prompt from genTypes
  Panel->>Runtime: composer.send(prompt)
  Runtime->>API: POST /api/chat (body.genTypes when auto-init)
  API->>API: Parse/validate genTypes
  API->>API: Inject createFrom system prompt
  API-->>Runtime: Stream response
  Panel->>Router: replace() remove genTypes/createFrom/action
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.

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 129 to 132
if (types.has('note')) updateInstructions.push(' - Use `updateNote` with noteName "Update me" and a descriptive `title` (e.g. "${topic} Notes")');
if (types.has('flashcard')) updateInstructions.push(' - Use `updateFlashcards` with deckName "Update me" and a descriptive `title` (e.g. "${topic} Flashcards")');
if (types.has('quiz')) updateInstructions.push(' - Use `updateQuiz` with quizName "Update me" and a descriptive `title` (e.g. "${topic} Quiz")');

Copy link
Contributor

Choose a reason for hiding this comment

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

Template string not interpolated

The type-specific updateInstructions are built with single-quoted strings containing ${topic} (e.g. "${topic} Notes"), so ${topic} will be sent literally in the system prompt rather than being substituted. This breaks the intended “descriptive title” guidance for create-from initialization.

Suggested change
if (types.has('note')) updateInstructions.push(' - Use `updateNote` with noteName "Update me" and a descriptive `title` (e.g. "${topic} Notes")');
if (types.has('flashcard')) updateInstructions.push(' - Use `updateFlashcards` with deckName "Update me" and a descriptive `title` (e.g. "${topic} Flashcards")');
if (types.has('quiz')) updateInstructions.push(' - Use `updateQuiz` with quizName "Update me" and a descriptive `title` (e.g. "${topic} Quiz")');
if (types.has('note')) updateInstructions.push(` - Use \`updateNote\` with noteName "Update me" and a descriptive \`title\` (e.g. "${topic} Notes")`);
if (types.has('flashcard')) updateInstructions.push(` - Use \`updateFlashcards\` with deckName "Update me" and a descriptive \`title\` (e.g. "${topic} Flashcards")`);
if (types.has('quiz')) updateInstructions.push(` - Use \`updateQuiz\` with quizName "Update me" and a descriptive \`title\` (e.g. "${topic} Quiz")`);

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed 464ab35 in 18 seconds. Click for details.
  • Reviewed 279 lines of code in 3 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_FRCrkpEyIBMIy0hv

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/app/api/chat/route.ts">

<violation number="1" location="src/app/api/chat/route.ts:99">
P2: The greedy capture in the create-from regex causes the topic to include the optional YouTube sentence, so generated prompts will treat that suffix as part of the topic. Use a non-greedy capture to stop at the first period.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

// Regex to detect createFrom auto-generated prompts
const CREATE_FROM_REGEX = /^Update the preexisting contents of this workspace to be about (.+)\. Only add one quality YouTube video\.$/;
// Regex to detect createFrom auto-generated prompts (YouTube suffix is optional for custom type selections)
const CREATE_FROM_REGEX = /^Update the preexisting contents of this workspace to be about (.+)\.(?:\s*Only add one quality YouTube video\.)?$/;
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 9, 2026

Choose a reason for hiding this comment

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

P2: The greedy capture in the create-from regex causes the topic to include the optional YouTube sentence, so generated prompts will treat that suffix as part of the topic. Use a non-greedy capture to stop at the first period.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/app/api/chat/route.ts, line 99:

<comment>The greedy capture in the create-from regex causes the topic to include the optional YouTube sentence, so generated prompts will treat that suffix as part of the topic. Use a non-greedy capture to stop at the first period.</comment>

<file context>
@@ -96,7 +96,7 @@ function getSelectedCardsContext(body: any): string {
 
 // Regex to detect createFrom auto-generated prompts (YouTube suffix is optional for custom type selections)
-const CREATE_FROM_REGEX = /^Update the preexisting contents of this workspace to be about (.+?)\.(?:\s*Only add one quality YouTube video\.)?$/;
+const CREATE_FROM_REGEX = /^Update the preexisting contents of this workspace to be about (.+)\.(?:\s*Only add one quality YouTube video\.)?$/;
 
 /**
</file context>
Suggested change
const CREATE_FROM_REGEX = /^Update the preexisting contents of this workspace to be about (.+)\.(?:\s*Only add one quality YouTube video\.)?$/;
const CREATE_FROM_REGEX = /^Update the preexisting contents of this workspace to be about (.+?)\.(?:\s*Only add one quality YouTube video\.)?$/;
Fix with Cubic

@ibraheemshaikh5
Copy link
Collaborator Author

@greptile

Copy link

@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: 1

🤖 Fix all issues with AI agents
In `@src/app/api/chat/route.ts`:
- Around line 125-152: The "Update ONLY these workspace items" block is emitted
even when updateInstructions is empty (e.g., genTypes=['youtube']), producing an
empty/confusing instruction; update the logic in src/app/api/chat/route.ts
around the variables genTypes/types/updateInstructions and the instructions.push
call that uses instrNum to only add that numbered "Update ONLY..." entry when
updateInstructions.length > 0 (or alternatively add a YouTube-specific
updateInstructions entry when types.has('youtube')), so that the instructions
array never contains an empty update list.
🧹 Nitpick comments (4)
src/app/api/chat/route.ts (1)

249-250: Consider validating parsed genTypes before use.

If body.genTypes is a truthy but degenerate string (e.g. ",,") the pipeline produces an empty array, which passes the truthy check on line 125 and yields a prompt with no update instructions and the "Do NOT create other types" restriction — effectively telling the LLM to do nothing.

A simple guard normalises this to the default behaviour:

Suggested fix
- const genTypes: string[] | null = body.genTypes ? body.genTypes.split(',').map((t: string) => t.trim()).filter(Boolean) : null;
+ const genTypesParsed: string[] = body.genTypes ? body.genTypes.split(',').map((t: string) => t.trim()).filter(Boolean) : [];
+ const genTypes: string[] | null = genTypesParsed.length > 0 ? genTypesParsed : null;
src/components/home/HomePromptInput.tsx (3)

50-96: Good extraction of buildPlaceholderItems — addresses the prior duplication concern.

The shared helper consolidates the two code paths. Layout logic (side-by-side quiz + flashcard, full-width note) is sound.

One nit: the return type is any[]. If the workspace item shape is defined elsewhere (e.g., in types.ts), a concrete type would prevent silent shape drift.


98-111: loadGenSettings doesn't validate individual type values.

If localStorage contains stale or tampered values (e.g. types: ["note", "podcast"]), the invalid entries propagate through to effectiveTypes and ultimately to the genTypes URL param / API payload, where they'll be silently ignored by route.ts but still occupy prompt space.

A quick filter against ALL_CONTENT_TYPES keys would tighten this:

Suggested fix
+ const VALID_TYPES = new Set<string>(ALL_CONTENT_TYPES.map(t => t.key));
+
  function loadGenSettings(): GenerationSettings {
    if (typeof window === 'undefined') return DEFAULT_GEN_SETTINGS;
    try {
      const stored = localStorage.getItem('thinkex-gen-settings');
      if (stored) {
        const parsed = JSON.parse(stored);
        return {
          auto: typeof parsed.auto === 'boolean' ? parsed.auto : true,
-         types: Array.isArray(parsed.types) ? parsed.types : DEFAULT_GEN_SETTINGS.types,
+         types: Array.isArray(parsed.types)
+           ? parsed.types.filter((t: string) => VALID_TYPES.has(t))
+           : DEFAULT_GEN_SETTINGS.types,
        };
      }
    } catch {}
    return DEFAULT_GEN_SETTINGS;
  }

163-168: localStorage write on every settings change is fine, but the empty catch silently swallows quota errors.

If the user hits a storage quota limit, the settings will appear saved (state updates) but won't persist across sessions. A minimal console.warn inside the catch would help debug this in the field without affecting UX.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed eed1885 in 29 seconds. Click for details.
  • Reviewed 15 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_uBgHNNsom8Zpq2sQ

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

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.

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 50 to 93
function buildPlaceholderItems(
effectiveTypes: Set<GenContentType>,
startY: number,
heights: { note: number; flashcard: number },
): any[] {
const placeholders: any[] = [];
let currentY = startY;

if (effectiveTypes.has('note')) {
placeholders.push({
id: crypto.randomUUID(),
type: 'note',
name: 'Update me',
subtitle: '',
color: '#10B981',
layout: { x: 0, y: currentY, w: 4, h: heights.note },
data: { blockContent: [], field1: '' },
});
currentY += heights.note;
}

if (effectiveTypes.has('quiz')) {
placeholders.push({
id: crypto.randomUUID(),
type: 'quiz',
name: 'Update me',
subtitle: '',
color: '#F59E0B',
layout: { x: 0, y: currentY, w: 2, h: 13 },
data: { questions: [] },
});
}

if (effectiveTypes.has('flashcard')) {
placeholders.push({
id: crypto.randomUUID(),
type: 'flashcard',
name: 'Update me',
subtitle: '',
color: '#EC4899',
layout: { x: effectiveTypes.has('quiz') ? 2 : 0, y: currentY, w: 2, h: heights.flashcard },
data: { cards: [] },
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Invalid flashcard placeholder shape

buildPlaceholderItems() creates a flashcard item with data: { cards: [] }, but the workspace state expects flashcards to include additional fields like currentIndex and typically card entries with id/front/back/frontBlocks/backBlocks (see defaultDataFor("flashcard") in src/lib/workspace-state/item-helpers.ts:10-28). Creating placeholders with the wrong shape can break flashcard rendering/updating when the workspace loads. You should construct flashcard placeholder data using the same shape as defaultDataFor("flashcard") (or call that helper) so the created workspace state is valid.

@ibraheemshaikh5
Copy link
Collaborator Author

@greptile

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed 147a6c1 in 34 seconds. Click for details.
  • Reviewed 21 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_J26PCFo43ifSyYcv

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

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.

4 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 99 to 111
function loadGenSettings(): GenerationSettings {
if (typeof window === 'undefined') return DEFAULT_GEN_SETTINGS;
try {
const stored = localStorage.getItem('thinkex-gen-settings');
if (stored) {
const parsed = JSON.parse(stored);
return {
auto: typeof parsed.auto === 'boolean' ? parsed.auto : true,
types: Array.isArray(parsed.types) ? parsed.types : DEFAULT_GEN_SETTINGS.types,
};
}
} catch {}
return DEFAULT_GEN_SETTINGS;
Copy link
Contributor

Choose a reason for hiding this comment

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

Unvalidated localStorage shape

loadGenSettings() accepts any array for parsed.types and persists it back to localStorage. If types contains values outside GenContentType (e.g. from a previous version or manual editing), the UI can enter a state where auto is off but steps/system prompt end up empty (because nothing matches), which then forces the fallback-to-all behavior later and effectively ignores the user’s selection. Consider filtering parsed.types to the allowed keys (note|quiz|flashcard|youtube) when loading, so “custom” mode can’t be activated with an invalid/empty effective set.

Comment on lines 206 to 223
// Build type-aware prompt: only include steps for selected types
const types = genTypes ? new Set(genTypes.split(',')) : null;
const steps: string[] = [];
let n = 1;
if (!types || types.has('note')) steps.push(`${n++}. Update the note with a comprehensive summary`);
if (!types || types.has('quiz')) steps.push(`${n++}. Update the quiz with 5-10 relevant questions`);
if (!types || types.has('flashcard')) steps.push(`${n++}. Update the flashcards with key terms and concepts`);
if (!types || types.has('youtube')) steps.push(`${n++}. Search and add one relevant YouTube video if possible`);

// If genTypes was set but contained no recognized values, fall back to all types
if (steps.length === 0) {
steps.push('1. Update the note with a comprehensive summary');
steps.push('2. Update the quiz with 5-10 relevant questions');
steps.push('3. Update the flashcards with key terms and concepts');
steps.push('4. Search and add one relevant YouTube video if possible');
}

const prompt = `First, process any PDF files in this workspace.\n\nThen, using the content:\n${steps.join('\n')}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

genTypes parsing misses whitespace

genTypes.split(',') isn’t trimmed before being put into the Set. A query like ?genTypes=note, quiz will produce ' quiz' which won’t match types.has('quiz'), dropping steps unexpectedly and potentially triggering the “fallback to all” path. Trimming each entry (and filtering empties) when parsing would keep the handler consistent with the server-side parsing in route.ts.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

src/components/assistant-ui/WorkspaceRuntimeProvider.tsx
genTypes sent as null

searchParams.get("genTypes") returns string | null, and the value is passed through in the transport body. On the server, route.ts expects body.genTypes to be a string (it calls .split(',') if truthy). If the transport serializes null as null (not undefined), this will be truthy/falsey-dependent behavior that can change if the library’s JSON handling changes. Safer to omit the field entirely when it’s not present (or normalize to undefined/empty string) so the server-side parsing stays stable.

@ibraheemshaikh5
Copy link
Collaborator Author

@greptile

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed d208c3b in 32 seconds. Click for details.
  • Reviewed 44 lines of code in 2 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_iCpPOdJbynRmArbj

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

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.

4 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 40 to 44
const selectedActions = useUIStore((state) => state.selectedActions);
const replySelections = useUIStore(useShallow((state) => state.replySelections));
const searchParams = useSearchParams();
const genTypes = searchParams.get("genTypes");
const { data: session } = useSession();
Copy link
Contributor

Choose a reason for hiding this comment

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

Leaking URL genTypes

WorkspaceRuntimeProvider always reads genTypes from the URL and sends it in every /api/chat request body (body.genTypes), but AssistantPanel deletes genTypes from the URL only when it auto-sends createFrom/action prompts. If the user opens a workspace URL containing genTypes without those params (or after manual navigation), genTypes will persist and unintentionally constrain all future chats (server-side route.ts will restrict create-from instructions based on it). Consider scoping genTypes to only the auto-init flows (e.g., only attach it when createFrom/action=generate_study_materials is present, or remove it from the URL on load even when no auto-send triggers).

Comment on lines +86 to +96
if (effectiveTypes.has('flashcard')) {
placeholders.push({
id: crypto.randomUUID(),
type: 'flashcard',
name: 'Update me',
subtitle: '',
color: '#EC4899',
layout: { x: effectiveTypes.has('quiz') ? 2 : 0, y: currentY, w: 2, h: heights.flashcard },
data: defaultDataFor('flashcard'),
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing YouTube placeholder

The new generation settings include youtube, and effectiveTypes can contain it, but buildPlaceholderItems() never creates a placeholder item for YouTube. When users select only YouTube (or include YouTube alongside others), the initial workspace state will not contain any YouTube item for the assistant to update, so the type-aware prompts/instructions won’t be satisfiable. If YouTube is meant to be a workspace item type, add a corresponding placeholder here (using the same shape as the rest of the app expects for a YouTube card).

@ibraheemshaikh5
Copy link
Collaborator Author

@greptile

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed c7883af in 8 seconds. Click for details.
  • Reviewed 16 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_PAjebhX62HQM3v9R

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link

@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: 4

🤖 Fix all issues with AI agents
In `@src/app/api/chat/route.ts`:
- Around line 167-171: The prompt currently inserts the "QUALITY GUIDELINES FOR
CONTENT:" header even when qualityGuidelines is empty (e.g. genTypes ===
['youtube']); update the prompt assembly in route.ts so the header and joined
qualityGuidelines are only included when qualityGuidelines.length > 0 (or
truthy), otherwise omit that entire section; locate the variables
qualityGuidelines and youtubeSection and conditionally concatenate the header
plus qualityGuidelines.join(...) only when there are guidelines to show.
- Around line 251-252: Validate and sanitize body.genTypes before passing to
getCreateFromSystemPrompt by applying an allowlist of known generation types:
split and trim as you already do for genTypes, then filter each token against
the server-side allowed set (e.g., allowedGenTypes or the same set used inside
getCreateFromSystemPrompt, using a consistent normalization like toLowerCase()),
discard unknown values, and set genTypes to null if the resulting array is
empty; update the use-site where genTypes is declared and where
getCreateFromSystemPrompt(cleanedMessages, genTypes) is called so only
validated/allowed types reach getCreateFromSystemPrompt.

In `@src/components/home/HomePromptInput.tsx`:
- Around line 615-646: The content-type toggle buttons remain keyboard-focusable
when Auto mode is on because only the wrapper uses pointer-events-none; update
the button rendering inside the ALL_CONTENT_TYPES map (where toggleGenType is
used and active is computed from genSettings.types) to set
disabled={genSettings.auto} (or aria-disabled="true") and
tabIndex={genSettings.auto ? -1 : 0}, and move/adjust visual disabled styling to
rely on the :disabled pseudo-class (or keep pointer-events-none for pointer
visuals) so the toggles are both non-interactive and removed from keyboard focus
when genSettings.auto is true.
- Around line 333-353: The no-uploads custom-settings branch in
HomePromptInput.tsx builds placeholders via buildPlaceholderItems but doesn’t
set lastSource, causing inconsistency with the uploads path; update the branch
where placeholders are assigned (the isCustom block that sets initialState and
itemsCreated) to attach lastSource: 'user' to each placeholder (e.g., map over
placeholders before setting initialState) so initialState.items matches the
uploads path shape and downstream code relying on lastSource sees it.
🧹 Nitpick comments (2)
src/components/home/HomePromptInput.tsx (2)

286-293: Edge case: all types toggled off with auto disabled produces default-all behavior — by design?

When genSettings.auto is false and genSettings.types is empty, effectiveTypes falls back to all four types. The popover's onOpenChange (Line 588) snaps auto back to true on close if types are empty, but there's a window where submission could happen while the popover is still open with no types selected.

This is likely a rare edge case with a safe fallback (all types), just flagging for awareness.


166-171: Silent catch on localStorage write is fine, but consider a brief comment.

Empty catch {} blocks can look unintentional. A one-line comment like // localStorage may be unavailable (e.g. private browsing) would clarify intent for future readers. Very minor nit.

Comment on lines +251 to +252
const genTypes: string[] | null = body.genTypes ? body.genTypes.split(',').map((t: string) => t.trim()).filter(Boolean) : null;
const createFromPrompt = getCreateFromSystemPrompt(cleanedMessages, genTypes);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

genTypes values are not validated against the known set of types.

body.genTypes comes from the client and is split/trimmed but never validated. Arbitrary strings pass through to getCreateFromSystemPrompt, where they silently miss every types.has(...) check, producing a prompt with empty instructions and guidelines sections. Consider filtering against an allowlist server-side:

Proposed fix
-    const genTypes: string[] | null = body.genTypes ? body.genTypes.split(',').map((t: string) => t.trim()).filter(Boolean) : null;
+    const ALLOWED_GEN_TYPES = new Set(['note', 'quiz', 'flashcard', 'youtube']);
+    const genTypes: string[] | null = body.genTypes
+      ? body.genTypes.split(',').map((t: string) => t.trim()).filter((t: string) => ALLOWED_GEN_TYPES.has(t))
+      : null;
+    // Fall back to null if filtering removed all entries
+    const validGenTypes = genTypes && genTypes.length > 0 ? genTypes : null;
🤖 Prompt for AI Agents
In `@src/app/api/chat/route.ts` around lines 251 - 252, Validate and sanitize
body.genTypes before passing to getCreateFromSystemPrompt by applying an
allowlist of known generation types: split and trim as you already do for
genTypes, then filter each token against the server-side allowed set (e.g.,
allowedGenTypes or the same set used inside getCreateFromSystemPrompt, using a
consistent normalization like toLowerCase()), discard unknown values, and set
genTypes to null if the resulting array is empty; update the use-site where
genTypes is declared and where getCreateFromSystemPrompt(cleanedMessages,
genTypes) is called so only validated/allowed types reach
getCreateFromSystemPrompt.

Comment on lines +333 to +353
// For no-uploads path with custom settings, build a custom initial state
// instead of using the getting_started template
let template: "blank" | "getting_started";
if (hasUploads) {
template = "blank";
} else if (isCustom) {
template = "blank";
const placeholders = buildPlaceholderItems(effectiveTypes, 0, { note: 9, flashcard: 9 });

if (placeholders.length > 0) {
initialState = {
workspaceId: '',
globalTitle: '',
globalDescription: '',
items: placeholders,
itemsCreated: placeholders.length,
};
}
} else {
template = "getting_started";
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

No-uploads placeholders are missing lastSource: 'user'.

The uploads path (Line 320) adds lastSource: 'user' to each placeholder, but the no-uploads custom-settings path (Line 340) does not. If downstream code relies on lastSource, this inconsistency could cause issues.

Proposed fix
-      const placeholders = buildPlaceholderItems(effectiveTypes, 0, { note: 9, flashcard: 9 });
+      const placeholders = buildPlaceholderItems(effectiveTypes, 0, { note: 9, flashcard: 9 })
+        .map(item => ({ ...item, lastSource: 'user' as const }));
🤖 Prompt for AI Agents
In `@src/components/home/HomePromptInput.tsx` around lines 333 - 353, The
no-uploads custom-settings branch in HomePromptInput.tsx builds placeholders via
buildPlaceholderItems but doesn’t set lastSource, causing inconsistency with the
uploads path; update the branch where placeholders are assigned (the isCustom
block that sets initialState and itemsCreated) to attach lastSource: 'user' to
each placeholder (e.g., map over placeholders before setting initialState) so
initialState.items matches the uploads path shape and downstream code relying on
lastSource sees it.

Comment on lines +615 to +646
<div className={cn("space-y-2", genSettings.auto && "opacity-40 pointer-events-none")}>
{ALL_CONTENT_TYPES.map(({ key, label }) => {
const active = genSettings.types.includes(key);
return (
<button
key={key}
type="button"
role="switch"
aria-checked={active}
aria-label={`Toggle ${label}`}
className="flex items-center justify-between w-full"
onClick={() => toggleGenType(key)}
>
<span className="text-xs text-foreground">{label}</span>
<span
aria-hidden="true"
className={cn(
"relative inline-flex h-4 w-7 shrink-0 cursor-pointer rounded-full transition-colors",
active ? "bg-primary" : "bg-muted-foreground/25"
)}
>
<span
className={cn(
"pointer-events-none inline-block h-3 w-3 rounded-full bg-background shadow-sm ring-0 transition-transform mt-0.5",
active ? "translate-x-[14px]" : "translate-x-0.5"
)}
/>
</span>
</button>
);
})}
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Content-type toggles remain keyboard-focusable when disabled by Auto mode.

pointer-events-none only blocks pointer interactions. Users can still Tab into the toggles and activate them with Space/Enter while they appear disabled. Consider adding tabIndex={-1} and disabled (or aria-disabled="true") when auto mode is on.

Proposed fix
                   <button
                     key={key}
                     type="button"
                     role="switch"
                     aria-checked={active}
                     aria-label={`Toggle ${label}`}
+                    disabled={genSettings.auto}
                     className="flex items-center justify-between w-full"
                     onClick={() => toggleGenType(key)}
                   >

Then replace the wrapper pointer-events-none approach with styling via the :disabled pseudo-class or keep both for visual consistency.

📝 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
<div className={cn("space-y-2", genSettings.auto && "opacity-40 pointer-events-none")}>
{ALL_CONTENT_TYPES.map(({ key, label }) => {
const active = genSettings.types.includes(key);
return (
<button
key={key}
type="button"
role="switch"
aria-checked={active}
aria-label={`Toggle ${label}`}
className="flex items-center justify-between w-full"
onClick={() => toggleGenType(key)}
>
<span className="text-xs text-foreground">{label}</span>
<span
aria-hidden="true"
className={cn(
"relative inline-flex h-4 w-7 shrink-0 cursor-pointer rounded-full transition-colors",
active ? "bg-primary" : "bg-muted-foreground/25"
)}
>
<span
className={cn(
"pointer-events-none inline-block h-3 w-3 rounded-full bg-background shadow-sm ring-0 transition-transform mt-0.5",
active ? "translate-x-[14px]" : "translate-x-0.5"
)}
/>
</span>
</button>
);
})}
</div>
<div className={cn("space-y-2", genSettings.auto && "opacity-40 pointer-events-none")}>
{ALL_CONTENT_TYPES.map(({ key, label }) => {
const active = genSettings.types.includes(key);
return (
<button
key={key}
type="button"
role="switch"
aria-checked={active}
aria-label={`Toggle ${label}`}
disabled={genSettings.auto}
className="flex items-center justify-between w-full"
onClick={() => toggleGenType(key)}
>
<span className="text-xs text-foreground">{label}</span>
<span
aria-hidden="true"
className={cn(
"relative inline-flex h-4 w-7 shrink-0 cursor-pointer rounded-full transition-colors",
active ? "bg-primary" : "bg-muted-foreground/25"
)}
>
<span
className={cn(
"pointer-events-none inline-block h-3 w-3 rounded-full bg-background shadow-sm ring-0 transition-transform mt-0.5",
active ? "translate-x-[14px]" : "translate-x-0.5"
)}
/>
</span>
</button>
);
})}
</div>
🤖 Prompt for AI Agents
In `@src/components/home/HomePromptInput.tsx` around lines 615 - 646, The
content-type toggle buttons remain keyboard-focusable when Auto mode is on
because only the wrapper uses pointer-events-none; update the button rendering
inside the ALL_CONTENT_TYPES map (where toggleGenType is used and active is
computed from genSettings.types) to set disabled={genSettings.auto} (or
aria-disabled="true") and tabIndex={genSettings.auto ? -1 : 0}, and move/adjust
visual disabled styling to rely on the :disabled pseudo-class (or keep
pointer-events-none for pointer visuals) so the toggles are both non-interactive
and removed from keyboard focus when genSettings.auto is true.

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.

4 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 124 to 128
const topic = match[1];
const types = genTypes ? new Set(genTypes) : new Set(['note', 'quiz', 'flashcard', 'youtube']);

// Build type-specific update instructions — always include title param
const updateInstructions: string[] = [];
Copy link
Contributor

Choose a reason for hiding this comment

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

Invalid genTypes yields no-op

getCreateFromSystemPrompt() treats any non-null genTypes as authoritative (const types = genTypes ? new Set(genTypes) : ...). If body.genTypes is present but contains no recognized values (e.g. genTypes=foo,bar or an empty/filtered client value), updateInstructions becomes empty and the prompt still adds the “Do NOT create or update any other item types” restriction, which can leave the model with no valid update actions to take during create-from initialization. Consider validating/filtering genTypes to the allowed set and falling back to default types when the recognized set is empty.

Comment on lines +53 to +99
function buildPlaceholderItems(
effectiveTypes: Set<GenContentType>,
startY: number,
heights: { note: number; flashcard: number },
): any[] {
const placeholders: any[] = [];
let currentY = startY;

if (effectiveTypes.has('note')) {
placeholders.push({
id: crypto.randomUUID(),
type: 'note',
name: 'Update me',
subtitle: '',
color: '#10B981',
layout: { x: 0, y: currentY, w: 4, h: heights.note },
data: { blockContent: [], field1: '' },
});
currentY += heights.note;
}

if (effectiveTypes.has('quiz')) {
placeholders.push({
id: crypto.randomUUID(),
type: 'quiz',
name: 'Update me',
subtitle: '',
color: '#F59E0B',
layout: { x: 0, y: currentY, w: 2, h: 13 },
data: { questions: [] },
});
}

if (effectiveTypes.has('flashcard')) {
placeholders.push({
id: crypto.randomUUID(),
type: 'flashcard',
name: 'Update me',
subtitle: '',
color: '#EC4899',
layout: { x: effectiveTypes.has('quiz') ? 2 : 0, y: currentY, w: 2, h: heights.flashcard },
data: defaultDataFor('flashcard'),
});
}

return placeholders;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

YouTube selection creates empty workspace

buildPlaceholderItems() never creates a placeholder for youtube, but GenContentType/settings allow selecting it and effectiveTypes can be {'youtube'}. In the no-uploads + custom path, this makes placeholders.length === 0, so you create a template="blank" workspace with initialState unset, yet still append genTypes=youtube and trigger the auto-init prompt. That leaves the assistant with no workspace item to update for the requested type. This also affects the uploads path (no YouTube placeholder ever exists). Either add a YouTube placeholder item type (matching what the workspace state expects) or disallow youtube as a selectable type until it maps to a real workspace item.

Also appears in the no-uploads custom path at handleSubmit where initialState is only set when placeholders.length > 0 (src/components/home/HomePromptInput.tsx:333-353).

@ibraheemshaikh5
Copy link
Collaborator Author

@greptile

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed f1cc7e5 in 16 seconds. Click for details.
  • Reviewed 35 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_5bY7YnyFTtnBNiB2

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 9, 2026

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.

4 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +74 to +96
if (effectiveTypes.has('quiz')) {
placeholders.push({
id: crypto.randomUUID(),
type: 'quiz',
name: 'Update me',
subtitle: '',
color: '#F59E0B',
layout: { x: 0, y: currentY, w: 2, h: 13 },
data: { questions: [] },
});
}

if (effectiveTypes.has('flashcard')) {
placeholders.push({
id: crypto.randomUUID(),
type: 'flashcard',
name: 'Update me',
subtitle: '',
color: '#EC4899',
layout: { x: effectiveTypes.has('quiz') ? 2 : 0, y: currentY, w: 2, h: heights.flashcard },
data: defaultDataFor('flashcard'),
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing YouTube placeholder

GenContentType/settings allow selecting youtube, but buildPlaceholderItems() never creates a type: "youtube" item. If a user selects only YouTube (or any set that includes YouTube but excludes note/quiz/flashcard), the created workspace initialState.items can end up without any YouTube card to update, while AssistantPanel/route.ts prompts can still instruct adding/updating a YouTube video. This will make the auto-init flows unable to satisfy the requested type selection. Consider adding a YouTube placeholder using the existing defaultDataFor("youtube") shape.

Comment on lines +333 to +353
// For no-uploads path with custom settings, build a custom initial state
// instead of using the getting_started template
let template: "blank" | "getting_started";
if (hasUploads) {
template = "blank";
} else if (isCustom) {
template = "blank";
const placeholders = buildPlaceholderItems(effectiveTypes, 0, { note: 9, flashcard: 9 });

if (placeholders.length > 0) {
initialState = {
workspaceId: '',
globalTitle: '',
globalDescription: '',
items: placeholders,
itemsCreated: placeholders.length,
};
}
} else {
template = "getting_started";
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Blank template without state

In the no-uploads + custom-types path you set template = "blank" but only set initialState when placeholders.length > 0. If the user selects only youtube (or any selection that yields zero placeholders), this creates a blank workspace with no items, yet you still append genTypes and trigger the auto-init prompt. That leaves the assistant with nothing to update for the selected types. This should either create the corresponding placeholder item(s) for the selected types, or avoid using template="blank" when initialState would be empty.

Comment on lines +206 to +221
// Build type-aware prompt: only include steps for selected types
const types = genTypes ? new Set(genTypes.split(',').map(s => s.trim()).filter(Boolean)) : null;
const steps: string[] = [];
let n = 1;
if (!types || types.has('note')) steps.push(`${n++}. Update the note with a comprehensive summary`);
if (!types || types.has('quiz')) steps.push(`${n++}. Update the quiz with 5-10 relevant questions`);
if (!types || types.has('flashcard')) steps.push(`${n++}. Update the flashcards with key terms and concepts`);
if (!types || types.has('youtube')) steps.push(`${n++}. Search and add one relevant YouTube video if possible`);

// If genTypes was set but contained no recognized values, fall back to all types
if (steps.length === 0) {
steps.push('1. Update the note with a comprehensive summary');
steps.push('2. Update the quiz with 5-10 relevant questions');
steps.push('3. Update the flashcards with key terms and concepts');
steps.push('4. Search and add one relevant YouTube video if possible');
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Invalid genTypes not detected

GenerateStudyMaterialsHandler treats any non-empty genTypes entries as recognized and builds steps off types.has(...). For ?genTypes=foo,bar (or whitespace variants), types is non-null and steps becomes empty, which triggers the fallback-to-all path, but CreateFromPromptHandler does not have an equivalent fallback: it will omit the YouTube suffix because types is non-null and includes('youtube') is false. That makes the first user message not match CREATE_FROM_REGEX (server still expects a trailing period) and getCreateFromSystemPrompt won’t inject the initialization instructions. Net effect: createFrom auto-init can silently lose the server-side system prompt when genTypes contains only invalid values.

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

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant