Skip to content

feat(magic-rewrite): port V1 to refactor#1260

Merged
cha1latte merged 5 commits into
Pasta-Devs:refactorfrom
cha1latte:prep/pr-1238-magic-rewrite-refactor-v2
May 26, 2026
Merged

feat(magic-rewrite): port V1 to refactor#1260
cha1latte merged 5 commits into
Pasta-Devs:refactorfrom
cha1latte:prep/pr-1238-magic-rewrite-refactor-v2

Conversation

@cha1latte
Copy link
Copy Markdown
Collaborator

@cha1latte cha1latte commented May 26, 2026

Linked issue

Refs #1183
Refs #1238

Why this change

PR #1238 contains the Magic Rewrite V1 feature, but its branch was not based on the active refactor branch.

This PR ports the Magic Rewrite V1 surface directly onto refactor and adapts the implementation to the refactor architecture, where editor UI calls the shared LLM gateway instead of adding the old package/server route path.

What changed

  • Added a shared Magic Rewrite hook that resolves the default text connection and calls llmApi.complete.
  • Added the shared MagicRewritePanel with instructions, Generate Rewrite, Before/After preview, and word-level diff highlighting.
  • Added Magic Rewrite access to the shared expanded textarea used by character/persona editor fields.
  • Added Magic Rewrite access to the lorebook entry expanded content editor.
  • Preserved V1 scope: no chat-context selectors, no history inclusion, and no extra provider controls.

Refactor impact

Primary owner:

  • Shared API / shared UI, with catalog editor entry points.

Impact areas reviewed:

  • Shared API boundary: UI uses src/shared/api/llm-api.ts and storageApi; no old package/server route was restored.
  • Feature boundary: character/persona expanded textareas and lorebook entry expanded content editor.
  • Remote runtime boundary: Magic Rewrite was smoke checked through llm_complete via the Rust remote runtime.

Boundary notes:

  • src/shared/hooks/use-magic-rewrite.ts stays in shared code and imports only shared API wrappers.
  • Feature editors import the shared panel/component instead of duplicating provider logic.
  • Engine code remains independent of shared API wrappers.

Pressure points touched:

  • Shared expanded textarea behavior.
  • Lorebook form expanded content modal.
  • No src-tauri/src/lib.rs command registration, mode surface, or import-module changes.

Validation

  • pnpm check passes locally
  • pnpm typecheck passes locally
  • pnpm build passes locally
  • pnpm check:architecture passes locally
  • pnpm check:docs passes locally
  • cargo check --manifest-path src-tauri/Cargo.toml --workspace passes locally
  • Rust clippy/tests were run for Rust behavior changes
  • Browser or Tauri app manual verification completed
  • Playwright, screenshot, or recording evidence added for UI changes
  • Remote runtime smoke checked when relevant

Manual verification notes

  • Codex ran pnpm check:architecture successfully in C:\tmp\marinara-pr-1238.
  • Codex ran pnpm check:frontend successfully.
  • Codex ran full pnpm check successfully after refreshing onto current upstream/refactor.
  • Codex ran git diff --check upstream/refactor...HEAD successfully.
  • Codex ran node scratch\verify-pr-1260-magic-rewrite.mjs successfully. The harness starts a disposable Rust remote runtime, seeds a default text connection and character, points the app at a fake OpenAI-compatible provider, opens the real character Description expanded editor, runs Magic Rewrite, receives the provider rewrite through llm_complete, applies it, and captures proof.
  • The provider request evidence shows the original source text and rewrite instruction were sent to the fake provider.
  • Bunny review pass completed after the refactor-base refresh and evidence commit.
  • GitHub CI passed on the refreshed head after the refactor-base update.
  • CodeRabbit reviewed the PR after the rate-limit retry and left three focused comments. Codex addressed them in commit 8f08fcd5 and reran local validation.

Docs and release impact

  • No docs changes needed
  • Updated README.md
  • Updated CONTRIBUTING.md
  • Updated docs/developer/
  • Updated repo skills or AGENTS.md
  • Confirmed this PR does not restore old staging/package-workspace/release claims

Added scoped PR evidence under docs/evidence/pr-1260-magic-rewrite/; no user-facing docs or release metadata changed.

UI evidence

Runtime proof screenshot:

Magic Rewrite applied in the refactor character Description editor

Provider request proof:

https://github.com/cha1latte/Marinara-Engine/blob/8f08fcd5de42cd273d4a9abf85a6bc81d83c2cd7/docs/evidence/pr-1260-magic-rewrite/provider-request.json

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Warning

Review limit reached

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

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

Your organization has run out of usage credits. Purchase more in the billing tab.

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

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ce1cc18-8d3e-443a-936a-047d0353fdd4

📥 Commits

Reviewing files that changed from the base of the PR and between 2f6f5d2 and 8f08fcd.

⛔ Files ignored due to path filters (1)
  • docs/evidence/pr-1260-magic-rewrite/after.png is excluded by !**/*.png
📒 Files selected for processing (3)
  • src/features/catalog/lorebooks/components/LorebookFormFields.tsx
  • src/shared/components/ui/MagicRewritePanel.tsx
  • src/shared/hooks/use-magic-rewrite.ts
📝 Walkthrough

Walkthrough

Ah, a most elegant specimen indeed! This pull request introduces a sophisticated text-rewriting apparatus powered by linguistic artifice. A new useMagicRewrite hook composes API calls, a MagicRewritePanel renders before-and-after word diffs with visual flourish, and the text editor UI integrates preview modes with apply controls throughout the modal layers.

Changes

Magic Rewrite Integration Framework

Layer / File(s) Summary
Magic Rewrite Hook and API Composition
src/shared/hooks/use-magic-rewrite.ts
useMagicRewrite(value) hook persists rewrite instructions to localStorage, resolves the default LLM connection, constructs system/user messages, and exposes generate(), result, loading, error, instruction, and setInstruction for downstream consumers. Includes error handling for missing defaults and image-generation connections.
Magic Rewrite Panel with Word-Diffing
src/shared/components/ui/MagicRewritePanel.tsx
MagicRewritePanel component wires useMagicRewrite, computes per-word diffs using a tokenization and matching algorithm, and renders instruction editing plus "Before"/"After" panes with inline red-struck-through deleted words and green added words. Fallback to raw text when diffing is skipped for large inputs.
ExpandedTextarea Magic Rewrite Mode
src/shared/components/ui/ExpandedTextarea.tsx
ExpandedTextarea now manages internal local text state and magicRewriteMode/magicRewriteResult flags. Header becomes mode-aware (title, character count, Open/Back/Apply buttons). Body conditionally renders textarea or MagicRewritePanel. Escape handling disabled in rewrite mode. Apply commits result to local and propagates via onChange.
LorebookFormFields Modal Integration
src/features/catalog/lorebooks/components/LorebookFormFields.tsx
ExpandedContentModal extended with magic rewrite state (magicRewriteMode, magicRewriteResult). Escape behavior conditional on mode. Modal footer and header text/controls change: "Back" returns to editor, "Apply" commits rewritten text and refocuses textarea. MagicRewritePanel rendered in place of textarea when magic mode active. Import of MagicRewritePanel added.
API Request Evidence
docs/evidence/pr-1260-magic-rewrite/provider-request.json
Static JSON payload documenting the LLM provider request: 4000 token limit, proof-model target, temperature 0.7, streaming disabled, system role defining rewrite assistant behavior, and user role instructing text enhancement.

Ah, you wish to observe the apparatus in action? Behold:

sequenceDiagram
  participant User as User
  participant ExpandedTextarea as ExpandedTextarea
  participant MagicRewritePanel as MagicRewritePanel
  participant useMagicRewrite as useMagicRewrite
  participant LLMApi as LLMApi
  
  User->>ExpandedTextarea: Click "Magic Rewrite"
  activate ExpandedTextarea
  ExpandedTextarea->>ExpandedTextarea: Set magicRewriteMode=true
  ExpandedTextarea->>MagicRewritePanel: Render with current text
  deactivate ExpandedTextarea
  
  User->>MagicRewritePanel: Edit instruction & Click Generate
  activate MagicRewritePanel
  MagicRewritePanel->>useMagicRewrite: Call generate()
  activate useMagicRewrite
  useMagicRewrite->>LLMApi: POST messages with instruction
  activate LLMApi
  LLMApi-->>useMagicRewrite: Rewritten text
  deactivate LLMApi
  useMagicRewrite->>useMagicRewrite: Compute word-level diff
  useMagicRewrite-->>MagicRewritePanel: result updated
  deactivate useMagicRewrite
  MagicRewritePanel->>MagicRewritePanel: Render Before/After with highlights
  MagicRewritePanel-->>User: Show diff preview
  deactivate MagicRewritePanel
  
  User->>ExpandedTextarea: Click "Apply"
  activate ExpandedTextarea
  ExpandedTextarea->>ExpandedTextarea: Update local=result
  ExpandedTextarea->>ExpandedTextarea: Set magicRewriteMode=false
  ExpandedTextarea->>ExpandedTextarea: Fire onChange(local)
  ExpandedTextarea-->>User: Return to editor with new text
  deactivate ExpandedTextarea
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The implementation spans multiple new files and non-trivial integration points. The useMagicRewrite hook requires understanding API composition and localStorage persistence patterns. The MagicRewritePanel contains a word-diffing algorithm with performance optimization logic. The textarea and modal integrations introduce state management complexity and mode-conditional rendering. However, the changes follow coherent architectural patterns and the feature remains self-contained within the UI layer.


Possibly Related PRs

  • Pasta-Devs/Marinara-Engine#364: Introduces the foundational ExpandableTextarea and ExpandedContentModal components that this PR extends with Magic Rewrite mode and controls.

Poem

🪄 Ah, what delightful apparatus we construct—
Words refracted through the lens of intellect,
Before and after dance in emerald and crimson hue,
The user's intent made manifest through scholarly review,
A rewrite most elegant, a function most true.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% 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
Title check ✅ Passed The title 'feat(magic-rewrite): port V1 to refactor' clearly and concisely summarizes the main change: porting the Magic Rewrite feature to the refactor branch architecture.
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.
Description check ✅ Passed The PR description comprehensively covers all required sections: linked issues, rationale, detailed change summary, refactor architecture impact, validation steps with evidence, and UI proof artifacts.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions github-actions Bot added the feature New feature or enhancement label May 26, 2026
@github-actions github-actions Bot added the docs label May 26, 2026
@cha1latte cha1latte marked this pull request as ready for review May 26, 2026 17:23
@cha1latte
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cha1latte
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

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

🧹 Nitpick comments (1)
src/features/catalog/lorebooks/components/LorebookFormFields.tsx (1)

320-325: ⚡ Quick win

Add type="button" to ExpandedContentModal controls in the lorebook editor

The modal buttons (close/back/apply/rewrite/done) in src/features/catalog/lorebooks/components/LorebookFormFields.tsx omit type; button defaults to submit only when nested in a <form>. In this repo, <form> elements only appear in AppDialogRenderer and SettingsPanel, so the lorebook editor/modal isn’t currently at risk of accidental submit—but adding type="button" is a cheap guard against future layout changes. Ah, a prudent little preventative experiment.

🧪 Proposed fix
           <div className="flex items-center gap-2">
             <button
+              type="button"
               onClick={handleClose}
               className="rounded-lg p-1.5 hover:bg-[var(--accent)]"
             >
               <X size="1rem" />
             </button>
@@
             <div className="flex items-center gap-2">
               <button
+                type="button"
                 onClick={handleMagicRewriteBack}
                 className="rounded-xl border border-[var(--border)] px-4 py-1.5 text-xs font-medium text-[var(--foreground)] hover:bg-[var(--accent)] active:scale-[0.98]"
               >
                 Back
               </button>
               <button
+                type="button"
                 onClick={handleMagicRewriteApply}
                 disabled={!magicRewriteResult}
                 className="rounded-xl bg-gradient-to-r from-violet-500 to-fuchsia-500 px-4 py-1.5 text-xs font-medium text-white shadow-md hover:shadow-lg active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-40"
               >
                 Apply
@@
             <div className="flex items-center gap-2">
               <button
+                type="button"
                 onClick={() => setMagicRewriteMode(true)}
                 className="inline-flex items-center gap-1.5 rounded-lg border border-violet-400/30 bg-violet-500/10 px-3 py-1.5 text-xs font-medium text-violet-200 hover:bg-violet-500/20"
                 title="Open Magic Rewrite"
               >
                 <Sparkles size="0.875rem" />
                 Rewrite
               </button>
               <button
+                type="button"
                 onClick={handleClose}
                 className="rounded-xl bg-gradient-to-r from-amber-400 to-orange-500 px-4 py-1.5 text-xs font-medium text-white shadow-md hover:shadow-lg active:scale-[0.98]"
               >
                 Done
               </button>
🤖 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 `@src/features/catalog/lorebooks/components/LorebookFormFields.tsx` around
lines 320 - 325, The modal control buttons in LorebookFormFields.tsx (e.g., the
close button using onClick={handleClose} and other modal controls: back, apply,
rewrite, done) are missing explicit types and should be declared as
non-submitting controls; update each <button> element used in the
ExpandedContentModal controls to include type="button" to prevent accidental
form submission (specifically add type="button" to the button rendering the X
icon tied to handleClose and to the other modal control buttons referenced in
this component).
🤖 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 `@src/shared/components/ui/MagicRewritePanel.tsx`:
- Around line 96-107: The button in MagicRewritePanel (the element with
onClick={generate} and disabled={loading}) lacks an explicit type and can
implicitly act as a form submitter; update that button element to include
type="button" to prevent accidental form submissions when this component is
rendered inside a <form>, keeping the onClick handler (generate) and other props
unchanged.

In `@src/shared/hooks/use-magic-rewrite.ts`:
- Around line 90-103: The generate() function leaves a prior successful result
visible if the new llmApi.complete(...) call fails; call setResult("") at the
start of generate (e.g., immediately after setLoading(true)/setError("")) to
clear any previous rewrite before attempting the new request so the UI cannot
show stale text under a new error; ensure generate and the state setters
setResult, setLoading, setError are the places you change.
- Around line 59-71: The current selection picks the default connection even if
it's an image_generation provider and throws before checking other text
connections; update the selection logic used around
storageApi.list<ConnectionRecord>("connections") so it first looks for a default
connection whose provider !== "image_generation" (e.g., connections.find(c =>
(boolish(c.isDefault) || boolish(c.default)) && c.provider !==
"image_generation")), then if none found fall back to the first connection with
provider !== "image_generation" (then finally to connections[0] only if no text
providers exist), and keep computing connectionId from the chosen selected;
ensure you only throw "No default agent connection configured" if no text
connection was found at all and remove the premature image_generation throw that
ignores later text connections.

---

Nitpick comments:
In `@src/features/catalog/lorebooks/components/LorebookFormFields.tsx`:
- Around line 320-325: The modal control buttons in LorebookFormFields.tsx
(e.g., the close button using onClick={handleClose} and other modal controls:
back, apply, rewrite, done) are missing explicit types and should be declared as
non-submitting controls; update each <button> element used in the
ExpandedContentModal controls to include type="button" to prevent accidental
form submission (specifically add type="button" to the button rendering the X
icon tied to handleClose and to the other modal control buttons referenced in
this component).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1a832110-5911-416a-9d60-a60e1b0ba327

📥 Commits

Reviewing files that changed from the base of the PR and between 13a8230 and 2f6f5d2.

⛔ Files ignored due to path filters (1)
  • docs/evidence/pr-1260-magic-rewrite/after.png is excluded by !**/*.png
📒 Files selected for processing (5)
  • docs/evidence/pr-1260-magic-rewrite/provider-request.json
  • src/features/catalog/lorebooks/components/LorebookFormFields.tsx
  • src/shared/components/ui/ExpandedTextarea.tsx
  • src/shared/components/ui/MagicRewritePanel.tsx
  • src/shared/hooks/use-magic-rewrite.ts

Comment thread src/shared/components/ui/MagicRewritePanel.tsx
Comment thread src/shared/hooks/use-magic-rewrite.ts Outdated
Comment thread src/shared/hooks/use-magic-rewrite.ts
@cha1latte
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cha1latte cha1latte merged commit cdc9781 into Pasta-Devs:refactor May 26, 2026
8 checks passed
@cha1latte cha1latte deleted the prep/pr-1238-magic-rewrite-refactor-v2 branch May 26, 2026 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs feature New feature or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant