Skip to content

feat: support rich text generation via AI - #810

Merged
dmitriy-kostianetskiy merged 7 commits into
mainfrom
feat/text-block-tools
Jul 15, 2026
Merged

dmitriy-kostianetskiy merged 7 commits into
mainfrom
feat/text-block-tools

Conversation

@dmitriy-kostianetskiy

@dmitriy-kostianetskiy dmitriy-kostianetskiy commented Jul 14, 2026 •

Copy link
Copy Markdown
Collaborator
image

Summary by CodeRabbit

  • New Features
    • Block documents now support rich text for headings, paragraphs, lists, and to-do items (bold/italic/code, plus links/strike), with rich text preserved in list items.
    • AI text-block creation now accepts formatted rich-text input.
  • Improvements
    • Block titles are derived from formatted content for more consistent display.
    • Empty rich-text content is handled cleanly during conversion.
    • Block-scoped AI sessions and worksheet AI editing availability were updated to align with the current session/content and enabled block-type rules.
  • Tests
    • Updated expectations and added coverage for rich-text roundtrips across conversions.
  • Chores / Style
    • Minor formatting cleanups in UI rendering and imports.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9e5c1186c6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

...BlockDocumentTextBlockBase,
type: z.literal('paragraph'),
text: z.string(),
text: z.array(BlockDocumentNode),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restore plain-text block DTO compatibility

For callers that still use the previously supported block DTO shape, such as appendBlocks(..., [{type: 'paragraph', text: 'Hello'}]), this schema now rejects the block before blockDocumentBlockToNode can convert it because BlockDocumentBlock.parse only accepts arrays. Supporting rich text does not require breaking existing plain-text command/API payloads; keep a string union/transform to preserve current JS callers and serialized command inputs while accepting rich text nodes.

Useful? React with 👍 / 👎.

Comment thread packages/documents/__tests__/BlockDocumentRichText.test.ts Outdated
@coderabbitai

coderabbitai Bot commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 49dc8267-c815-4f74-a29d-ced234eb093b

📥 Commits

Reviewing files that changed from the base of the PR and between 07aa646 and e4036f5.

📒 Files selected for processing (5)
  • apps/sqlrooms-cli-ui/src/components/useAssistantContextItems.ts
  • apps/sqlrooms-cli-ui/src/statefulBlockArtifactConfigs.ts
  • apps/sqlrooms-cli-ui/src/workspace/WorksheetArtifact.tsx
  • packages/ai-core/src/components/MessageContainer.tsx
  • packages/vega/src/VegaChartToolResult.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/sqlrooms-cli-ui/src/statefulBlockArtifactConfigs.ts
  • apps/sqlrooms-cli-ui/src/components/useAssistantContextItems.ts
  • apps/sqlrooms-cli-ui/src/workspace/WorksheetArtifact.tsx

📝 Walkthrough

Walkthrough

Block document text and list items now use rich-text node arrays throughout schemas, conversions, creation/listing tools, and tests. CLI and worksheet AI block eligibility is computed from runtime-enabled types. Block-scoped chat actions now return sessions with content.

Changes

Rich-text block documents

Layer / File(s) Summary
Rich-text contracts and conversions
packages/documents/src/BlockDocumentSliceConfig.ts
Block schemas and TipTap conversion functions preserve structured text nodes, list-item content, marks, and empty content.
Text block creation and listing
packages/documents/src/createAddBlockDocumentTextBlockTool.ts, packages/documents/src/createListBlockDocumentBlocksTool.ts
Text-block inputs accept rich-text arrays, while block titles are derived through recursive plain-text extraction.
Rich-text behavior and integration coverage
packages/documents/__tests__/BlockDocument*.test.ts, packages/documents/__tests__/documentsCrdt.test.ts, apps/sqlrooms-cli-ui/src/__tests__/createCliBlockDocumentAiAdapter.test.ts
Tests cover formatting marks, conversions, mutations, AI tool payloads, slice round trips, and CRDT mirroring.

Runtime AI block eligibility

Layer / File(s) Summary
CLI context block eligibility
apps/sqlrooms-cli-ui/src/components/useAssistantContextItems.ts, apps/sqlrooms-cli-ui/src/statefulBlockArtifactConfigs.ts
CLI context mapping and selected-ID validation use runtime-enabled block types and retain chart support.
Worksheet AI editing eligibility
apps/sqlrooms-cli-ui/src/workspace/WorksheetArtifact.tsx
Worksheet AI editing computes enabled block types from the experimental flag and updates header actions when they change.

Block-scoped chat session types

Layer / File(s) Summary
Chat session return type
packages/documents/src/startBlockScopedChat.ts
getAiSessions now returns ArtifactAiSessionWithContent[].

Presentation formatting

Layer / File(s) Summary
Component formatting updates
packages/ai-core/src/components/MessageContainer.tsx, packages/vega/src/VegaChartToolResult.tsx
Import, utility-class, and JSX formatting are adjusted without changing component behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: ilyabo

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding rich-text generation support via AI.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/text-block-tools

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.

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (3)
packages/documents/src/BlockDocumentSliceConfig.ts (2)

82-129: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Generic BlockDocumentNode doesn't constrain inline node types.

text/items fields now accept any BlockDocumentNode (arbitrary type: string), the same schema used for block-level nodes. Nothing stops a caller (especially the AI tool) from nesting a block-level node type (e.g., heading) inside an inline text array, producing a structurally invalid TipTap document that could break rendering downstream.

Consider a narrower inline-node schema (e.g., restrict type to 'text'/'hardBreak') for text/items fields, separate from the generic node type used for document-level content.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/documents/src/BlockDocumentSliceConfig.ts` around lines 82 - 129,
Introduce a dedicated inline-node schema restricted to supported inline types
such as text and hardBreak, then update BlockDocumentHeadingBlock,
BlockDocumentParagraphBlock, BlockDocumentTodoBlock, and BlockDocumentListBlock
items to use it instead of the generic BlockDocumentNode. Keep BlockDocumentNode
for document-level content while ensuring inline text and list item arrays
reject block types like heading.

214-221: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consolidate duplicate text-extraction helpers. textFromNode in BlockDocumentSliceConfig.ts is no longer called by the block↔node converters after this migration, while createListBlockDocumentBlocksTool.ts reimplements the same recursive text-flattening logic locally as extractTextFromNodes. One shared, exported helper avoids the duplication and dead code.

  • packages/documents/src/BlockDocumentSliceConfig.ts#L214-L221: export a single plain-text extraction helper (rename/reuse textFromNode, accepting either a node or node array) and drop textContent if confirmed unused.
  • packages/documents/src/createListBlockDocumentBlocksTool.ts#L10-L24: remove the local extractTextFromNodes and import the shared helper from BlockDocumentSliceConfig.ts instead.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/documents/src/BlockDocumentSliceConfig.ts` around lines 214 - 221,
Consolidate recursive text extraction into one exported helper: in
packages/documents/src/BlockDocumentSliceConfig.ts lines 214-221, update
textFromNode to accept a node or node array, export it, and remove textContent
if unused; in packages/documents/src/createListBlockDocumentBlocksTool.ts lines
10-24, delete extractTextFromNodes and import/use the shared helper instead.
packages/documents/src/createAddBlockDocumentTextBlockTool.ts (1)

17-33: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

AI-facing text/items accept arbitrary node type values.

Since BlockDocumentNode.type is an unconstrained string, the LLM tool caller could pass non-inline node types (e.g., a nested heading or list type) inside text/items, which are meant to represent inline text runs. This is the primary entry point where malformed rich-text payloads would originate. Tightening the schema here (or in the shared BlockDocumentNode, see BlockDocumentSliceConfig.ts) to restrict inline content to text/mark-carrying nodes would prevent invalid documents from being persisted via the AI tool.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/documents/src/createAddBlockDocumentTextBlockTool.ts` around lines
17 - 33, Restrict the AI-facing text and items schemas in
createAddBlockDocumentTextBlockTool to inline text/mark-carrying node types
instead of the unconstrained BlockDocumentNode type. Apply the constraint
consistently to both the text array and each nested items array, while
preserving supported marks and existing heading-level behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/documents/src/BlockDocumentSliceConfig.ts`:
- Around line 82-129: Introduce a dedicated inline-node schema restricted to
supported inline types such as text and hardBreak, then update
BlockDocumentHeadingBlock, BlockDocumentParagraphBlock, BlockDocumentTodoBlock,
and BlockDocumentListBlock items to use it instead of the generic
BlockDocumentNode. Keep BlockDocumentNode for document-level content while
ensuring inline text and list item arrays reject block types like heading.
- Around line 214-221: Consolidate recursive text extraction into one exported
helper: in packages/documents/src/BlockDocumentSliceConfig.ts lines 214-221,
update textFromNode to accept a node or node array, export it, and remove
textContent if unused; in
packages/documents/src/createListBlockDocumentBlocksTool.ts lines 10-24, delete
extractTextFromNodes and import/use the shared helper instead.

In `@packages/documents/src/createAddBlockDocumentTextBlockTool.ts`:
- Around line 17-33: Restrict the AI-facing text and items schemas in
createAddBlockDocumentTextBlockTool to inline text/mark-carrying node types
instead of the unconstrained BlockDocumentNode type. Apply the constraint
consistently to both the text array and each nested items array, while
preserving supported marks and existing heading-level behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 855c513b-0601-40d0-ab02-88993b04cd65

📥 Commits

Reviewing files that changed from the base of the PR and between 10eaa68 and 8747a00.

📒 Files selected for processing (9)
  • packages/documents/__tests__/BlockDocumentAi.test.ts
  • packages/documents/__tests__/BlockDocumentCommands.test.ts
  • packages/documents/__tests__/BlockDocumentRichText.test.ts
  • packages/documents/__tests__/BlockDocumentsSlice.test.ts
  • packages/documents/__tests__/documentsCrdt.test.ts
  • packages/documents/src/BlockDocumentSliceConfig.ts
  • packages/documents/src/createAddBlockDocumentTextBlockTool.ts
  • packages/documents/src/createListBlockDocumentBlocksTool.ts
  • packages/documents/src/startBlockScopedChat.ts

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 07aa64659b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/documents/src/BlockDocumentSliceConfig.ts

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
apps/sqlrooms-cli-ui/src/components/useAssistantContextItems.ts (1)

34-42: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Cache the enabled block types to avoid repeated computations.

isEnabledCliBlockType is invoked repeatedly per node during React render cycles (inside hooks like useValidatedSelectedIds and useContextSelectorItems). Since getEnabledStatefulBlockArtifactTypes traverses and filters the artifact configurations, computing it on every call adds unnecessary overhead.

Consider lazily caching the result to optimize performance for worksheets with many blocks.

♻️ Proposed refactor
+let enabledCliBlockTypesCache: Set<string> | null = null;
+
 function isEnabledCliBlockType(blockType: string): boolean {
   if (blockType === 'chart') return true;
   if (!isStatefulBlockArtifactType(blockType)) return false;
-  return (
-    getEnabledStatefulBlockArtifactTypes(experimentalEnabled).includes(
-      blockType,
-    ) && CLI_BLOCK_CONTEXT_TYPES.has(blockType)
-  );
+  
+  if (!enabledCliBlockTypesCache) {
+    enabledCliBlockTypesCache = new Set(
+      getEnabledStatefulBlockArtifactTypes(experimentalEnabled)
+    );
+  }
+  
+  return enabledCliBlockTypesCache.has(blockType) && CLI_BLOCK_CONTEXT_TYPES.has(blockType);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/sqlrooms-cli-ui/src/components/useAssistantContextItems.ts` around lines
34 - 42, Cache the result of
getEnabledStatefulBlockArtifactTypes(experimentalEnabled) within the surrounding
assistant-context logic, reusing the cached enabled-type collection across
repeated isEnabledCliBlockType calls during a render. Ensure the cache is
invalidated or recreated when experimentalEnabled changes, while preserving the
existing chart, stateful-type, and CLI_BLOCK_CONTEXT_TYPES checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@apps/sqlrooms-cli-ui/src/components/useAssistantContextItems.ts`:
- Around line 34-42: Cache the result of
getEnabledStatefulBlockArtifactTypes(experimentalEnabled) within the surrounding
assistant-context logic, reusing the cached enabled-type collection across
repeated isEnabledCliBlockType calls during a render. Ensure the cache is
invalidated or recreated when experimentalEnabled changes, while preserving the
existing chart, stateful-type, and CLI_BLOCK_CONTEXT_TYPES checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 322efc47-c1ba-44f9-92ef-3086e37b113f

📥 Commits

Reviewing files that changed from the base of the PR and between 8747a00 and 07aa646.

📒 Files selected for processing (6)
  • apps/sqlrooms-cli-ui/src/__tests__/createCliBlockDocumentAiAdapter.test.ts
  • apps/sqlrooms-cli-ui/src/components/useAssistantContextItems.ts
  • apps/sqlrooms-cli-ui/src/statefulBlockArtifactConfigs.ts
  • apps/sqlrooms-cli-ui/src/workspace/WorksheetArtifact.tsx
  • packages/documents/src/BlockDocumentSliceConfig.ts
  • packages/documents/src/createAddBlockDocumentTextBlockTool.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/documents/src/createAddBlockDocumentTextBlockTool.ts
  • packages/documents/src/BlockDocumentSliceConfig.ts

@dmitriy-kostianetskiy
dmitriy-kostianetskiy merged commit a573fa0 into main Jul 15, 2026
6 checks passed
@dmitriy-kostianetskiy
dmitriy-kostianetskiy deleted the feat/text-block-tools branch July 15, 2026 08:17
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