Skip to content

Improvements for the AI Assistant#403

Merged
craquet merged 7 commits into
devfrom
ai-improvements
Jun 18, 2026
Merged

Improvements for the AI Assistant#403
craquet merged 7 commits into
devfrom
ai-improvements

Conversation

@craquet

@craquet craquet commented Jun 17, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • In-place editing of AI chat messages (confirm/cancel) and quick copy-to-clipboard.
  • Improvements
    • Refreshed AI chat rendering for text, tool outputs, and expandable reasoning, with improved markdown formatting.
    • Expanded AI entity editing to accept JSON inputs and perform patch-style updates.
    • More reliable AI chat persistence per project.
  • Bug Fixes
    • Prevent unsafe removal of @id/@type properties during edits.

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@craquet, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 51 minutes and 7 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c69eb041-85ef-4ecc-b8a8-841e830caa9f

📥 Commits

Reviewing files that changed from the base of the PR and between 1ddf763 and 30e4035.

📒 Files selected for processing (1)
  • components/editor/type-field.tsx

Walkthrough

The PR refactors the AI assistant chat by extracting the large inline onToolCall switch into a dedicated useFrontendToolHandler hook, reworks editEntity to use patch-style operations ($set/$push/$delete) with a JSON preprocessor, adds a persisted Zustand chat store, decomposes message rendering into Message and UserMessage components, strengthens editor state constraints on property removal, and wires chat history persistence keyed by crateId.

Changes

AI Assistant Chat Refactor

Layer / File(s) Summary
Shared schemas and NC_UIMessage type
lib/utils.ts, lib/ai/types.ts
Extracts EntityPropertySchema from the inline EntitySchema union so tools can reference property value shapes directly, and defines NC_UIMessage as a UIMessage alias parameterized with InferUITools<typeof tools>.
editEntity patch schema and JSON preprocessor
lib/ai/tools.ts
Adds parseJsonPreprocessor to allow Zod to accept JSON-encoded strings, reworks editEntity to accept entityId plus optional $set/$push/$delete patch fields (wrapping the schema with the preprocessor), and wraps createEntity's content field with the same preprocessor.
Editor state property removal constraints
lib/state/editor-state.ts
Adds removeProperty method that prevents removal of mandatory @id/@type properties, and tightens removePropertyEntry to ignore @id deletion and block attempts to fully remove @type in both array-valued and scalar-valued property cases.
Type field remove entry UI constraint
components/editor/single-property-editor.tsx, components/editor/type-field.tsx
Extends TypeField with entityId prop to look up the current entity via editor state and disable the "Remove Entry" option when @type (after normalization to array) contains exactly one entry, preventing invalid entity states.
useFrontendToolHandler hook
lib/ai/use-frontend-tool-handler.ts
Introduces the useFrontendToolHandler hook with an in-memory readEntities cache. Routes handleToolCall across entity CRUD, patch-style edits with stale-cache detection, file reads, metadata summary, validation, delete/move (with cache cleanup), and ORCID/ROR imports—all emitting structured addToolOutput success or error payloads.
AI assistant chat persistence store
lib/state/ai-assistant-chats.ts
Adds useAIAssistantChats, a persisted SSR-safe Zustand store keyed by crateId that provides updateChat (upsert by crateId) and getChat (lookup), using Immer for mutable-style updates.
Message and UserMessage rendering components
components/ai/message.tsx, components/ai/user-message.tsx, components/ai/model-selection.tsx
Adds UserMessage (in-place editing and copy-to-clipboard for user-role messages), Message (role-dispatching renderer with markdown, all ToolCall variants, collapsible reasoning, and step-start/fallback handling), and wraps ModelSelection with memo.
chat.tsx wiring and refactor
components/ai/chat.tsx
Replaces the large inline onToolCall switch and per-message rendering loop with useFrontendToolHandler, useAIAssistantChats, and the Message component. Wires crateId-based chat persistence, adds editMessage (patches text parts and triggers regenerate()), and extracts the header into a memoized element.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant AIAssistantChat as chat.tsx
  participant useChat
  participant useFrontendToolHandler
  participant useAIAssistantChats
  participant EditorState

  User->>AIAssistantChat: open chat panel
  AIAssistantChat->>useAIAssistantChats: getChat(crateId)
  useAIAssistantChats-->>AIAssistantChat: persisted messages
  AIAssistantChat->>useChat: initialize with messages
  User->>AIAssistantChat: submit message
  useChat->>useFrontendToolHandler: onToolCall → handleToolCall(toolCall, addToolOutput)
  useFrontendToolHandler->>EditorState: read/edit/create/delete entity
  EditorState-->>useFrontendToolHandler: result
  useFrontendToolHandler-->>useChat: addToolOutput (success or output-error)
  useChat-->>AIAssistantChat: status = ready, updated messages
  AIAssistantChat->>useAIAssistantChats: updateChat(crateId, messages)
  User->>AIAssistantChat: edit user message
  AIAssistantChat->>useChat: setMessages + regenerate()
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • kit-data-manager/NovaCrate#279: The editor-state changes (adding removeProperty and further tightening removePropertyEntry's @id/@type deletion behavior) are directly related to this PR's tightening of mandatory property protections.
  • kit-data-manager/NovaCrate#393: Both PRs touch the AI assistant chat/tool flow—components/ai/chat.tsx (tool-call dispatch/UI) and lib/ai/tools.ts (tool contracts)—so this PR's refactor/update of tool handling and schemas builds on the initial LLM integration.

Suggested labels

enhancement

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 is vague and generic, using non-descriptive terms that don't convey specific meaningful information about the substantial refactoring and new features introduced. Consider a more specific title that highlights the main change, such as 'Refactor AI Assistant chat UI and tool handling' or 'Extract AI message rendering and implement tool handler hook'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ai-improvements

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.

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

Actionable comments posted: 6

🧹 Nitpick comments (2)
components/ai/message.tsx (1)

1-4: ⚡ Quick win

Declare this component as client-side explicitly.

Add "use client" at the top to keep client boundary explicit and consistent with repo rules for TSX components.

Suggested change
+"use client"
+
 import Markdown from "react-markdown"

As per coding guidelines, **/*.{tsx,jsx} should “Mark client components with "use client" directive at the top of the file”.

🤖 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 `@components/ai/message.tsx` around lines 1 - 4, The TSX file
components/ai/message.tsx is missing the "use client" directive at the top. Add
"use client" as the very first line in the file, before all imports including
Markdown, remarkGfm, memo, and PropsWithChildren. This explicitly marks the
component as client-side and keeps it consistent with the repository's coding
guidelines for TSX components.

Source: Coding guidelines

components/ai/user-message.tsx (1)

1-7: ⚡ Quick win

Add an explicit client boundary for this hook-based component.

This component uses client-only hooks and event handlers; add "use client" at file top for consistent boundary declaration.

Suggested change
+"use client"
+
 import { CheckIcon, CopyIcon, PencilIcon, XIcon } from "lucide-react"

As per coding guidelines, **/*.{tsx,jsx} should “Mark client components with "use client" directive at the top of the file”.

🤖 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 `@components/ai/user-message.tsx` around lines 1 - 7, The user-message.tsx
component uses client-only React hooks (useCallback, useState) and the
useCopyToClipboard hook, but is missing the "use client" directive required for
client components in Next.js. Add "use client" as the very first line at the top
of the file before any import statements to properly mark this as a client
component and comply with the coding guidelines.

Source: Coding guidelines

🤖 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.

Inline comments:
In `@components/ai/message.tsx`:
- Around line 90-93: The anchor element in the markdown link renderer (the `a`
component with `target={"_blank"}`) is missing the `rel` attribute which is
needed to prevent opener attacks when opening links in new tabs. Add
`rel="noopener noreferrer"` to the anchor tag alongside the existing `target`,
`href`, and `className` attributes to harden the link against security
vulnerabilities.

In `@components/ai/user-message.tsx`:
- Around line 67-75: The icon-only buttons in the user message component lack
accessible names for screen readers. Add aria-label attributes to both Button
components: one containing the PencilIcon with onClick={startEditing} should
have an aria-label like "Edit message", and the button containing the
CopyIcon/CheckIcon with onClick={copyMessage} should have an aria-label like
"Copy message". These labels will be announced by screen readers to provide
context for visually impaired users.

In `@lib/ai/tools.ts`:
- Around line 33-42: The `$set` field in the inputSchema currently allows `@id`
to be set, which causes silent failures downstream when `editEntity({...initial,
...$set})` is called because changing `@id` gets rejected by
`editorState.editEntity`. Add validation to the `$set` record schema using Zod's
`.refine()` method to disallow the `@id` key and reject it with a clear error
message stating that `@id` changes must be handled through `moveEntity` instead
of `$set`.

In `@lib/ai/use-frontend-tool-handler.ts`:
- Line 11: The module-level readEntities map persists across all hook instances
and crate switches, causing stale data and unbounded memory growth. Refactor the
caching mechanism to be scoped per crateId by accepting crateId as a parameter
to the hook and implementing a caching function (such as getReadEntitiesCache)
that returns or manages a cache specific to each crateId. Replace all direct
references to the readEntities map with calls to this new crate-aware caching
function to ensure each crate maintains its own isolated cache that is properly
cleaned up when switching between crates.
- Around line 225-253: The promises array contains nested arrays instead of flat
promises, preventing proper settlement. The Array.from(entities.values()).map()
call returns an array of promises that should be spread into the outer promises
array, and similarly the Object.keys(entity).map() result containing property
validation promises should be flattened before passing to the inner
Promise.allSettled call. Use the spread operator to flatten both the entity
validation promises (after the map call) and the property validation promises
(after the Object.keys map call) so that Promise.allSettled receives a
single-level array of promises to await.

In `@lib/state/editor-state.ts`:
- Around line 452-460: The removeProperty method allows deletion of reserved
entity properties like `@id` and `@type`, which can break entity invariants and
identity-dependent flows. Add validation at the start of the removeProperty
method to check if the propertyName being deleted is a reserved key (`@id` or
`@type`) and prevent deletion of these critical properties by returning early or
throwing an error before the setState call.

---

Nitpick comments:
In `@components/ai/message.tsx`:
- Around line 1-4: The TSX file components/ai/message.tsx is missing the "use
client" directive at the top. Add "use client" as the very first line in the
file, before all imports including Markdown, remarkGfm, memo, and
PropsWithChildren. This explicitly marks the component as client-side and keeps
it consistent with the repository's coding guidelines for TSX components.

In `@components/ai/user-message.tsx`:
- Around line 1-7: The user-message.tsx component uses client-only React hooks
(useCallback, useState) and the useCopyToClipboard hook, but is missing the "use
client" directive required for client components in Next.js. Add "use client" as
the very first line at the top of the file before any import statements to
properly mark this as a client component and comply with the coding guidelines.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7425c099-54f9-4e79-aeca-4a7c2cb2b3ef

📥 Commits

Reviewing files that changed from the base of the PR and between 4ce8a8b and 1d33425.

📒 Files selected for processing (10)
  • components/ai/chat.tsx
  • components/ai/message.tsx
  • components/ai/model-selection.tsx
  • components/ai/user-message.tsx
  • lib/ai/tools.ts
  • lib/ai/types.ts
  • lib/ai/use-frontend-tool-handler.ts
  • lib/state/ai-assistant-chats.ts
  • lib/state/editor-state.ts
  • lib/utils.ts

Comment thread components/ai/message.tsx
Comment thread components/ai/user-message.tsx Outdated
Comment thread lib/ai/tools.ts
Comment thread lib/ai/use-frontend-tool-handler.ts Outdated
Comment thread lib/ai/use-frontend-tool-handler.ts
Comment thread lib/state/editor-state.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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@components/editor/type-field.tsx`:
- Around line 67-71: The onClick handler onRemoveEntry is attached to
DropdownMenuContent instead of DropdownMenuItem, which causes the remove handler
to execute even when the menu item is disabled on line 70. Remove the onClick
prop from DropdownMenuContent and move it to the DropdownMenuItem component so
that the disabled state properly prevents the click handler from executing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f661b3d5-fc3f-49f2-b68a-180a3b2f80ce

📥 Commits

Reviewing files that changed from the base of the PR and between 1d33425 and 1ddf763.

📒 Files selected for processing (6)
  • components/ai/message.tsx
  • components/ai/user-message.tsx
  • components/editor/single-property-editor.tsx
  • components/editor/type-field.tsx
  • lib/ai/use-frontend-tool-handler.ts
  • lib/state/editor-state.ts
✅ Files skipped from review due to trivial changes (1)
  • components/editor/single-property-editor.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • components/ai/message.tsx
  • components/ai/user-message.tsx
  • lib/state/editor-state.ts
  • lib/ai/use-frontend-tool-handler.ts

Comment thread components/editor/type-field.tsx Outdated
@craquet craquet merged commit 6edffc7 into dev Jun 18, 2026
8 checks passed
@craquet craquet deleted the ai-improvements branch June 18, 2026 12:59
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.

1 participant