Skip to content

fix(pearl): display responses as text instead of raw JSON blocks#251

Open
srivtx wants to merge 1 commit intobubblelabai:mainfrom
srivtx:fix/238-pearl-json-formatting
Open

fix(pearl): display responses as text instead of raw JSON blocks#251
srivtx wants to merge 1 commit intobubblelabai:mainfrom
srivtx:fix/238-pearl-json-formatting

Conversation

@srivtx
Copy link

@srivtx srivtx commented Dec 28, 2025

Fixes #238

Summary

When the AI model wraps its JSON response in markdown code blocks, JSON.parse() fails and the raw response (including markdown) was displayed to users as a "JSON Response" block.

This fix uses the existing parseJsonWithFallbacks() utility which properly strips markdown formatting before parsing, allowing the clean message text to be displayed.

Related Issues

Fixes #238

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactor
  • Other (please describe):

Checklist

  • My code follows the code style of this project
  • I have added appropriate tests for my changes
  • I have run pnpm check and all tests pass
  • I have tested my changes locally
  • I have linked relevant issues
  • I have added screenshots for UI changes (if applicable)

Screenshots (if applicable)

N/A - Backend fix, no UI changes.

Additional Context

The parseJsonWithFallbacks() function is already used elsewhere in the codebase and has 60 passing tests covering markdown-wrapped JSON scenarios.

Summary by CodeRabbit

  • Bug Fixes
    • Improved JSON parsing robustness to handle responses wrapped in markdown formatting.
    • Enhanced error messages to be more user-friendly and less technical when processing fails.
    • Refined error handling to prevent exposure of raw AI responses to end-users.

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

Use parseJsonWithFallbacks instead of raw JSON.parse to handle AI
responses wrapped in markdown code blocks (```json ... ```).

Also updated error messages to be user-friendly instead of including
raw response text with markdown formatting.

Fixes bubblelabai#238
@coderabbitai
Copy link

coderabbitai bot commented Dec 28, 2025

📝 Walkthrough

Walkthrough

Updates JSON parsing in two AI service files from direct JSON.parse() to parseJsonWithFallbacks() utility to handle markdown-wrapped responses. Error messages are changed to user-friendly text instead of exposing raw response details.

Changes

Cohort / File(s) Summary
AI Service JSON Parsing
apps/bubblelab-api/src/services/ai/milktea.ts, apps/bubblelab-api/src/services/ai/pearl.ts
Replaced direct JSON.parse() with parseJsonWithFallbacks() to robustly handle JSON wrapped in markdown code blocks. Updated error messages to be user-facing and generic instead of exposing raw response details. Pearl also handles both object and array result types.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

A rabbit fixed JSON so tight,
Wrapped in markdown, oh what a sight!
With fallbacks and parsing so keen,
Error messages now calm and clean,
Users smile—no more markdown blight! 🐰

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(pearl): display responses as text instead of raw JSON blocks' directly describes the main change—replacing JSON parsing logic to display clean text instead of raw markdown-wrapped JSON responses.
Linked Issues check ✅ Passed The pull request implements the requirements from issue #238: it replaces direct JSON.parse with parseJsonWithFallbacks to handle markdown-wrapped JSON, and updates error messages to be user-friendly instead of exposing raw responses.
Out of Scope Changes check ✅ Passed All changes are scoped to the objective of fixing JSON parsing for markdown-wrapped responses in pearl.ts and milktea.ts, with no unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

@bubblelab-pearl
Copy link
Contributor

Suggested PR title from Pearl

Title: fix(ai): improve JSON parsing and error messages in AI agents

Body:

Changes

Improves JSON response parsing and error handling in MilkTea and Pearl AI agents.

What Changed

  • Replaced direct JSON.parse() calls with parseJsonWithFallbacks() to handle AI responses wrapped in markdown code blocks (e.g., ```json ... ```)
  • Added proper error checking for parse results before proceeding
  • Updated error messages to be more user-friendly and actionable

Error Message Improvements

Before:

  • "Failed to parse agent response"
  • "Error parsing agent response, original response: ..." (exposing raw technical output)

After:

  • "Failed to process your request. Please try rephrasing your question."
  • "Unable to understand your request. Please try rephrasing your question."

Why

AI models sometimes wrap JSON responses in markdown code blocks, which causes standard JSON parsing to fail. The new parseJsonWithFallbacks() function handles these cases gracefully. Additionally, raw technical error messages were being shown to users, which is not helpful and may expose internal implementation details.

Files Modified

  • apps/bubblelab-api/src/services/ai/milktea.ts
  • apps/bubblelab-api/src/services/ai/pearl.ts

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

🧹 Nitpick comments (2)
apps/bubblelab-api/src/services/ai/milktea.ts (1)

517-522: LGTM! Proper use of parseJsonWithFallbacks to handle markdown-wrapped JSON.

The implementation correctly replaces direct JSON.parse with parseJsonWithFallbacks, which handles AI responses wrapped in markdown code blocks (e.g., ````json ... ```). The validation of both parseResult.success and `parseResult.parsed` before proceeding, followed by Zod schema validation, ensures robust error handling.

Optional: Consider explicit undefined check

The condition !parseResult.parsed uses falsy evaluation, which could theoretically be problematic if parsed is a valid but falsy value like 0, false, or "". While this is unlikely given the expected object type, you could make it more explicit:

-if (!parseResult.success || !parseResult.parsed) {
+if (!parseResult.success || parseResult.parsed === undefined) {

However, this is a minor pedantic concern and not necessary for this use case.

apps/bubblelab-api/src/services/ai/pearl.ts (1)

598-600: Add a brief comment explaining the array handling logic.

The parseJsonWithFallbacks function can return either an object or an array at the top level. This code handles the case where it returns an array by extracting the first element. While this pattern appears elsewhere in the codebase (e.g., slack-formatter-agent.ts, coffee.ts), similar implementations in other files document why arrays are handled. A comment here would improve clarity:

// Handle case where AI returns an array of responses instead of a single object
if (Array.isArray(parsedResponse) && parsedResponse.length > 0) {
  parsedResponse = parsedResponse[0];
}
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1b008c and 97daa58.

📒 Files selected for processing (2)
  • apps/bubblelab-api/src/services/ai/milktea.ts
  • apps/bubblelab-api/src/services/ai/pearl.ts
🧰 Additional context used
🧬 Code graph analysis (1)
apps/bubblelab-api/src/services/ai/milktea.ts (2)
packages/bubble-core/src/index.ts (1)
  • parseJsonWithFallbacks (139-139)
packages/bubble-shared-schemas/src/milk-tea.ts (1)
  • MilkTeaAgentOutputSchema (93-97)
🔇 Additional comments (3)
apps/bubblelab-api/src/services/ai/milktea.ts (1)

527-528: LGTM! User-friendly error message improves UX.

The updated error message provides a clear, actionable message to users without exposing potentially confusing raw AI responses or markdown formatting. The detailed error information is still preserved in the error field (line 530) for debugging purposes, which maintains a good balance between user experience and developer observability.

apps/bubblelab-api/src/services/ai/pearl.ts (2)

591-597: LGTM! Well-documented parsing logic handles markdown-wrapped JSON.

The implementation correctly uses parseJsonWithFallbacks to handle AI responses wrapped in markdown code blocks. The explanatory comments (lines 591-592) add valuable context about why this utility is used instead of direct JSON.parse, making the code more maintainable. The validation checks and error handling are robust.


615-615: LGTM! User-friendly error messages with clear documentation.

The error messages are now generic and actionable, avoiding exposure of potentially confusing raw AI responses with markdown formatting. The explanatory comments (lines 675-676) clearly document why raw responseText is excluded from user-facing messages, which aids future maintainers. The detailed error information is still preserved in the error field for debugging, maintaining good observability.

Also applies to: 675-680

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.

Legitment Pearl response formatted in json blocks

2 participants