Skip to content

Main pr jan20#86

Merged
urjitc merged 36 commits into
mainfrom
main_pr_jan20
Jan 21, 2026
Merged

Main pr jan20#86
urjitc merged 36 commits into
mainfrom
main_pr_jan20

Conversation

@1shCha

@1shCha 1shCha commented Jan 21, 2026

Copy link
Copy Markdown
Contributor

Quizzes and deep research along with other minor fixes


Important

This PR adds full support for quizzes, including creation, updating, and playing, with new tools, workers, UI components, and style enhancements.

  • Behavior:
    • Adds createQuizTool and updateQuizTool in quiz-tools.ts for creating and updating quizzes.
    • Introduces quizWorker in quiz-worker.ts for generating quiz questions based on context or topic.
    • Updates workspace-worker.ts to handle quiz creation and updates.
  • UI:
    • Implements CreateQuizToolUI and UpdateQuizToolUI in assistant-ui for quiz interactions.
    • Adds QuizContent component in workspace-canvas for rendering quizzes.
  • Models:
    • Adds QuizData, QuizQuestion, and QuizSessionData types in types.ts.
  • Misc:
    • Refactors workers.ts into separate worker files for better organization.
    • Updates grid-layout-helpers.ts to include quiz in default card dimensions.
    • Adds animated gradient border styles in globals.css.

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


Summary by CodeRabbit

  • New Features

    • Quiz functionality: Create quizzes with adaptive difficulty levels, update existing quizzes with new questions, and play interactive quizzes with progress tracking and results.
    • Enhanced editor paste handling for markdown content, mathematical expressions, and images with intelligent block replacement logic.
  • Style

    • Added animated gradient border effects for visual enhancement.
    • Improved markdown typography with refined spacing and heading styles in content cards.

✏️ Tip: You can customize this high-level summary in your review settings.

1shCha and others added 30 commits January 17, 2026 23:24
Pass questionsToAdd as a top-level parameter to workspaceWorker instead of nesting it in quizData, and remove unused variable.
Simplify workspace context by removing emoji icons and the internal PDF_CONTENT_URL marker.
Update logic to correctly handle adding new questions to a completed quiz and simplify memoization comparisons.
Prevent stripping valid punctuation after inline math and ensure mixed-content paragraphs (with links/mentions) are not incorrectly converted to block math.
Update regex patterns to support literal/escaped dollar signs within math delimiters.
…er mismatch; consolidate state loading logic
@greptile-apps

greptile-apps Bot commented Jan 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds comprehensive quiz functionality to ThinkEx, enabling users to create interactive multiple-choice and true/false quizzes either from selected workspace content or general topics. The implementation includes adaptive difficulty adjustment based on user performance, LaTeX math support for STEM subjects, and session persistence for resuming quizzes.

Major Changes:

  • New quiz tools (createQuizTool, updateQuizTool) for AI-assisted quiz generation with context extraction from selected cards
  • Quiz worker with adaptive difficulty engine that adjusts question complexity based on user performance telemetry
  • Interactive QuizContent component with state management, navigation, progress tracking, and results visualization
  • Extended workspace worker to handle quiz CRUD operations with proper event sourcing
  • Refactored math conversion logic into dedicated math-helpers.ts module for reusability
  • Type definitions for QuizData, QuizQuestion, and QuizSessionData with comprehensive documentation

Key Features:

  • Context-based quiz generation: analyzes selected cards to generate questions exclusively from that content
  • Three-mode quiz updates: context update (new cards), topic pivot (new subject), or continuation (more of same)
  • Performance tracking: identifies weak areas and generates targeted scaffolding questions
  • Math support: LaTeX rendering in questions, options, and explanations using KaTeX

Architecture Notes:

  • Quiz creation follows existing workspace patterns with event sourcing for state management
  • Session state persisted in quiz data for resume functionality
  • UI components use proper React patterns with hooks and memoization

Confidence Score: 4/5

  • This PR is safe to merge with one logic issue that should be addressed
  • The implementation is well-structured and follows existing patterns, but there's a critical LaTeX sanitization bug in quiz-worker.ts (line 200) that will break math rendering by incorrectly double-escaping valid LaTeX commands. The regex pattern needs correction before merge. Otherwise, the code demonstrates good practices: proper error handling, type safety, comprehensive documentation, and thoughtful UX considerations like adaptive difficulty and session persistence.
  • src/lib/ai/workers/quiz-worker.ts requires attention for LaTeX escape sequence handling

Important Files Changed

Filename Overview
src/lib/ai/workers/quiz-worker.ts New quiz generation worker with adaptive difficulty and LaTeX sanitization - implementation looks solid with proper error handling
src/lib/ai/tools/quiz-tools.ts Quiz creation/update tools with context extraction logic - comprehensive implementation with good error handling and multi-mode support
src/components/workspace-canvas/QuizContent.tsx Interactive quiz UI component with session state management, navigation, and dynamic question handling - complex but well-structured
src/lib/ai/workers/workspace-worker.ts Extended workspace worker with quiz create/update operations - consistent with existing patterns
src/lib/editor/math-helpers.ts Refactored math conversion utilities into dedicated module - good separation of concerns

Sequence Diagram

sequenceDiagram
    participant User
    participant Assistant
    participant QuizTool as createQuiz/updateQuiz Tool
    participant QuizWorker
    participant WorkspaceWorker
    participant Database
    participant UI as QuizContent Component

    User->>Assistant: "Create a quiz on [topic]" or select cards + "create quiz"
    Assistant->>QuizTool: Call createQuiz tool
    QuizTool->>QuizTool: Extract context from selected cards
    QuizTool->>QuizWorker: Generate quiz questions
    QuizWorker->>QuizWorker: Build adaptive prompt with difficulty
    QuizWorker->>QuizWorker: Sanitize LaTeX in JSON response
    QuizWorker-->>QuizTool: Return quiz questions + title
    QuizTool->>WorkspaceWorker: Create quiz item
    WorkspaceWorker->>Database: Append ITEM_CREATED event
    Database-->>WorkspaceWorker: Success
    WorkspaceWorker-->>QuizTool: Return itemId
    QuizTool-->>Assistant: Success result
    Assistant->>UI: Display CreateQuizToolUI
    UI->>User: Show quiz card in workspace

    User->>UI: Start quiz (click on quiz card)
    UI->>UI: Load QuizContent component
    UI->>UI: Render first question
    User->>UI: Select answer + Submit
    UI->>UI: Update session state
    UI->>Database: Persist session via onUpdateData
    UI->>User: Show explanation + Next button

    User->>Assistant: "Add more questions"
    Assistant->>QuizTool: Call updateQuiz tool
    QuizTool->>Database: Load workspace state
    QuizTool->>QuizTool: Analyze user performance telemetry
    QuizTool->>QuizWorker: Generate adaptive questions
    QuizWorker-->>QuizTool: Return new questions
    QuizTool->>WorkspaceWorker: Update quiz (append questions)
    WorkspaceWorker->>Database: Append ITEM_UPDATED event
    Database-->>WorkspaceWorker: Success
    WorkspaceWorker-->>QuizTool: Success
    QuizTool-->>Assistant: Success result
    Assistant->>UI: Display UpdateQuizToolUI
    UI->>UI: Detect new questions added
    UI->>User: Toast notification + navigate to new questions
Loading

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

27 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment thread src/lib/ai/workers/quiz-worker.ts Outdated

// Sanitize LaTeX escape sequences before parsing
// We need to double-escape backslashes that aren't valid JSON escapes
jsonText = jsonText.replace(/\\(?!["\\/bfnrtu])/g, '\\\\');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

logic: incomplete regex pattern for LaTeX escape sequences

the negative lookahead (?!["\\/bfnrtu]) only checks for valid JSON escape sequences, but LaTeX uses many more backslash patterns (e.g. \alpha, \beta, \frac, \sqrt). this will double-escape valid LaTeX, breaking math rendering

Suggested change
jsonText = jsonText.replace(/\\(?!["\\/bfnrtu])/g, '\\\\');
// Sanitize LaTeX: preserve backslashes in JSON strings
jsonText = jsonText.replace(/\\(?=["\\\/bfnrtu])/g, '\\\\');

alternatively, handle LaTeX preservation more carefully by parsing string content separately

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/lib/ai/workers/quiz-worker.ts
Line: 200:200

Comment:
**logic:** incomplete regex pattern for LaTeX escape sequences

the negative lookahead `(?!["\\/bfnrtu])` only checks for valid JSON escape sequences, but LaTeX uses many more backslash patterns (e.g. `\alpha`, `\beta`, `\frac`, `\sqrt`). this will double-escape valid LaTeX, breaking math rendering

```suggestion
            // Sanitize LaTeX: preserve backslashes in JSON strings
            jsonText = jsonText.replace(/\\(?=["\\\/bfnrtu])/g, '\\\\');
```

alternatively, handle LaTeX preservation more carefully by parsing string content separately

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

@urjitc

urjitc commented Jan 21, 2026

Copy link
Copy Markdown
Member

@greptile how did deep research change in this pr

@urjitc

urjitc commented Jan 21, 2026

Copy link
Copy Markdown
Member

@greptile explain cleanedMessages

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looking at the code in the chat route, cleanedMessages refers to a processed version of the conversation messages that have been sanitized and normalized before being passed to the AI tools.

Here's what happens:

Message Cleaning Process

The cleanedMessages are created by processing the raw messages from the chat request to:

  1. Remove or sanitize problematic content that could interfere with AI processing
  2. Normalize message formats to ensure consistent structure
  3. Preserve essential context while removing noise

Usage in Quiz Tools

In the quiz tools (src/lib/ai/tools/quiz-tools.ts), the cleanedMessages are used to:

// Extract user's intent from their latest message
function extractUserMessage(messages: any[]): string | undefined {
    // Find the last user message (most recent request)
    for (let i = messages.length - 1; i >= 0; i--) {
        const msg = messages[i];
        if (msg.role === 'user') {
            if (typeof msg.content === 'string') {
                return cleanMessageForTopic(msg.content);
            }
            // Handle multi-part messages...
        }
    }
}

Key Functions

  1. Topic Extraction: Extract what the user actually wants the quiz to be about
  2. Context Detection: Find selected cards context using extractSelectedCardsContext()
  3. Intent Understanding: Determine if user wants to create new quiz vs update existing

Message Structure

The messages typically contain:

  • User messages: What the user typed
  • Assistant responses: Previous AI responses
  • System context: Selected cards data marked with [[SELECTED_CARDS_MARKER]]
  • Tool results: Results from previous tool executions

Why "Cleaned"?

The messages are "cleaned" because they may contain:

  • Raw markdown that needs normalization
  • System markers that should be filtered out for topic extraction
  • File URLs and metadata that aren't relevant to understanding user intent
  • Special formatting that could confuse the AI models

The cleaning ensures the AI tools get the most relevant information for generating appropriate quiz content based on either the user's specified topic or selected card content.

The regex pattern was incorrectly double-escaping LaTeX sequences like \alpha,
\beta, \frac, breaking math rendering. Removed the problematic sanitization
as JSON parser handles properly escaped JSON correctly.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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/globals.css`:
- Around line 1243-1263: The file contains duplicate declarations for the
`@keyframes` gradient-rotate and the .gradient-border-animated class; remove this
later duplicate block so only the original definitions remain (keep the earlier
definitions already declared around gradient-rotate and
.gradient-border-animated and delete the repeated declarations in this later
section), and verify no other styles rely on a different variant name so
references to gradient-rotate and .gradient-border-animated remain unchanged.

Comment thread src/app/globals.css
Comment on lines +1243 to +1263
/* Animated gradient border - rotates colors around the border in a circle */
@keyframes gradient-rotate {
0% { background-position: 0% 0%; }
25% { background-position: 100% 0%; }
50% { background-position: 100% 100%; }
75% { background-position: 0% 100%; }
100% { background-position: 0% 0%; }
}
.gradient-border-animated {
background: linear-gradient(
90deg,
#ef444480,
#eab30880,
#22c55e80,
#3b82f680,
#a855f780,
#ef444480
);
background-size: 200% 200%;
animation: gradient-rotate 10s ease-in-out infinite;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate gradient border definitions.

The @keyframes gradient-rotate and .gradient-border-animated are already defined earlier in this file (lines 586–616). These identical declarations should be removed to avoid maintenance confusion.

🧹 Suggested fix: remove duplicate definitions
-/* Animated gradient border - rotates colors around the border in a circle */
-@keyframes gradient-rotate {
-  0% { background-position: 0% 0%; }
-  25% { background-position: 100% 0%; }
-  50% { background-position: 100% 100%; }
-  75% { background-position: 0% 100%; }
-  100% { background-position: 0% 0%; }
-}
-.gradient-border-animated {
-  background: linear-gradient(
-    90deg,
-    `#ef444480`,
-    `#eab30880`,
-    `#22c55e80`,
-    `#3b82f680`,
-    `#a855f780`,
-    `#ef444480`
-  );
-  background-size: 200% 200%;
-  animation: gradient-rotate 10s ease-in-out infinite;
-}
📝 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
/* Animated gradient border - rotates colors around the border in a circle */
@keyframes gradient-rotate {
0% { background-position: 0% 0%; }
25% { background-position: 100% 0%; }
50% { background-position: 100% 100%; }
75% { background-position: 0% 100%; }
100% { background-position: 0% 0%; }
}
.gradient-border-animated {
background: linear-gradient(
90deg,
#ef444480,
#eab30880,
#22c55e80,
#3b82f680,
#a855f780,
#ef444480
);
background-size: 200% 200%;
animation: gradient-rotate 10s ease-in-out infinite;
}
🤖 Prompt for AI Agents
In `@src/app/globals.css` around lines 1243 - 1263, The file contains duplicate
declarations for the `@keyframes` gradient-rotate and the
.gradient-border-animated class; remove this later duplicate block so only the
original definitions remain (keep the earlier definitions already declared
around gradient-rotate and .gradient-border-animated and delete the repeated
declarations in this later section), and verify no other styles rely on a
different variant name so references to gradient-rotate and
.gradient-border-animated remain unchanged.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
4 Security Hotspots
3.9% Duplication on New Code (required ≤ 3%)
B Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@ellipsis-dev ellipsis-dev Bot left a comment

Copy link
Copy Markdown
Contributor

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 4cb7b7e in 56 seconds. Click for details.
  • Reviewed 20 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 2 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.
1. package.json:92
  • Draft comment:
    Removed 'canvas-confetti' dependency. The release notes mentioned adding it; please confirm its removal is intentional and not needed in the code (e.g., for confetti animations).
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the PR author to confirm the intention behind removing a dependency. This is not allowed according to the rules, as it falls under asking the author to confirm their intention.
2. package.json:139
  • Draft comment:
    Removed '@types/canvas-confetti'. Ensure that this removal is aligned with the dependency removal and that no code references require these types.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the author to ensure that the removal of @types/canvas-confetti is aligned with the dependency removal and that no code references require these types. This is a request for confirmation and verification, which violates the rules.

Workflow ID: wflow_rd08gUlOuVEfr18E

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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/lib/ai/workers/quiz-worker.ts`:
- Around line 199-201: The catch block that handles JSON parsing in
quiz-worker.ts currently logs the full AI response via result.text (see the
parseError catch and logger.error calls); remove or stop logging result.text
directly to avoid PII leakage and instead log only safe metadata and a
controlled/truncated sample behind an environment guard. Update the parseError
handler to log parseError and contextual metadata (e.g., requestId, modelName)
and, if process.env.NODE_ENV !== "production", include a short
sanitized/truncated snippet of result.text (e.g., first 100 chars) or a
redaction marker; reference the parseError catch block, the logger.error calls,
and result.text when making the change.
♻️ Duplicate comments (1)
src/lib/ai/workers/quiz-worker.ts (1)

205-215: Validate quiz payload before mapping.

parsed.questions.map(...) will throw if questions is missing, and invalid options/correctIndex can produce broken quizzes. Add array and bounds validation and fail fast with a clear error.

🔧 Suggested change
-        const questions: QuizQuestion[] = parsed.questions.map((q) => ({
-            id: generateItemId(), // Always use unique ID
-            type: q.type as QuestionType,
-            questionText: q.questionText || q.question_text || q.text || "",
-            options: q.options || [],
-            correctIndex: q.correctIndex ?? q.correct_index ?? 0,
-            hint: q.hint,
-            explanation: q.explanation || "No explanation provided.",
-        }));
+        if (!Array.isArray(parsed.questions) || parsed.questions.length === 0) {
+            throw new Error("Quiz generation returned no questions");
+        }
+        const questions: QuizQuestion[] = parsed.questions.map((q) => {
+            const options = Array.isArray(q.options) ? q.options : [];
+            const correctIndex = q.correctIndex ?? q.correct_index ?? 0;
+            if (options.length === 0 || correctIndex < 0 || correctIndex >= options.length) {
+                throw new Error("Quiz generation returned invalid options/correctIndex");
+            }
+            return {
+                id: generateItemId(), // Always use unique ID
+                type: q.type as QuestionType,
+                questionText: q.questionText || q.question_text || q.text || "",
+                options,
+                correctIndex,
+                hint: q.hint,
+                explanation: q.explanation || "No explanation provided.",
+            };
+        });

Comment on lines +199 to +201
} catch (parseError) {
logger.error("🎯 [QUIZ-WORKER] Failed to parse JSON:", parseError);
logger.error("🎯 [QUIZ-WORKER] Raw response:", result.text);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid logging raw AI response content in errors.

result.text can include user workspace content; logging it at error level risks PII leakage. Log only metadata or a truncated sample behind a non‑prod guard.

🔧 Suggested change
-            logger.error("🎯 [QUIZ-WORKER] Raw response:", result.text);
+            logger.error("🎯 [QUIZ-WORKER] Raw response length:", result.text.length);
+            if (process.env.NODE_ENV !== "production") {
+                logger.debug("🎯 [QUIZ-WORKER] Raw response (truncated):", result.text.slice(0, 1000));
+            }
🤖 Prompt for AI Agents
In `@src/lib/ai/workers/quiz-worker.ts` around lines 199 - 201, The catch block
that handles JSON parsing in quiz-worker.ts currently logs the full AI response
via result.text (see the parseError catch and logger.error calls); remove or
stop logging result.text directly to avoid PII leakage and instead log only safe
metadata and a controlled/truncated sample behind an environment guard. Update
the parseError handler to log parseError and contextual metadata (e.g.,
requestId, modelName) and, if process.env.NODE_ENV !== "production", include a
short sanitized/truncated snippet of result.text (e.g., first 100 chars) or a
redaction marker; reference the parseError catch block, the logger.error calls,
and result.text when making the change.

@urjitc
urjitc merged commit 593a681 into main Jan 21, 2026
7 of 8 checks passed
@urjitc
urjitc deleted the main_pr_jan20 branch January 21, 2026 05:22
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Dev Board Jan 21, 2026
This was referenced Feb 21, 2026
This was referenced Mar 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants