Skip to content

feat(ui): collapse pasted text in chat history#407

Open
pascalandr wants to merge 9 commits into
NeuralNomadsAI:devfrom
Pagecran:feat/hidden-prompt-sections
Open

feat(ui): collapse pasted text in chat history#407
pascalandr wants to merge 9 commits into
NeuralNomadsAI:devfrom
Pagecran:feat/hidden-prompt-sections

Conversation

@pascalandr
Copy link
Copy Markdown
Contributor

@pascalandr pascalandr commented May 8, 2026

Summary

  • Collapse intact placeholder-backed long pasted text blocks by default in user message history for readability.
  • Keep pasted content fully visible to the model; this is a display-only history treatment.
  • Persist pasted-text collapse metadata across optimistic message replacement and app reloads.
  • Fall back to normal plain-text history rendering when the placeholder-backed pasted structure has been edited or is no longer intact before send.

Fixes #266

Behavior

When a user submits a prompt containing an intact long pasted block from the existing pasted-text placeholder flow, the full pasted text is still sent to the model unchanged, but the chat history renders that pasted section as a collapsed expandable block.

This applies to the existing placeholder-backed long-paste flow only. If the pasted placeholder structure is broken before submission, the message renders in history as normal plain text with no collapse metadata.

Verification

  • npx tsx --test "packages/ui/src/components/prompt-input/submitPrompt.test.ts" "packages/ui/src/lib/prompt-display-metadata.test.ts" "packages/ui/src/stores/message-prompt-display.test.ts"
  • npm run typecheck --workspace @codenomad/ui
  • npm run build --workspace @codenomad/ui
  • npm run build --workspace @codenomad/tauri-app

Local desktop verification

  • Built executable: packages/tauri-app/target/release/codenomad-tauri.exe
  • Built installer: packages/tauri-app/target/release/bundle/nsis/CodeNomad_0.15.0_x64-setup.exe
  • Launched the built Tauri executable locally and confirmed startup succeeded.
image

pascalandr added 2 commits May 8, 2026 19:02
Add a CodeNomad-specific hidden prompt syntax for user messages so long planning and instruction blocks can stay out of the main chat flow without changing the text sent to the model.

User messages now strip `<codenomad:hide>` markers before prompt submission, render hidden sections inside collapsed details blocks in the message history, and persist that display-only structure across optimistic message replacement and full app reloads.

Validation:
- npx tsx --test "packages/ui/src/lib/hidden-prompt-sections.test.ts" "packages/ui/src/stores/message-prompt-display.test.ts"
- npm run typecheck --workspace @codenomad/ui
- npm run build --workspace @codenomad/ui
@pascalandr
Copy link
Copy Markdown
Contributor Author

@CodeNomadBot

I want you to perform the gatekeeper checks for latest PR state

check for regressions
check for better possible implementations
Be the PR gatekeeper
Be ruthless about code quality

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/25568593846

Artifacts expire in 7 days.
Artifacts: (none found on this run)

@codenomadbot
Copy link
Copy Markdown
Contributor

codenomadbot Bot commented May 8, 2026

Understood request: perform gatekeeper checks for the latest PR state, looking for regressions and better implementations. Assumption: this is a review-only pass, not a request to patch the branch.

Gatekeeper result: changes requested.

Findings:

  • Medium: packages/ui/src/stores/message-v2/instance-store.ts:1052 removes messages in pruneMessagesAfterRevert, but it never clears the corresponding hidden-prompt display overrides. This PR introduces localStorage persistence for display text, and most deletion paths were updated (removeMessage, clearSession, clearInstance), but the revert/prune path leaves deleted hidden prompt content behind. That is both stale metadata and a privacy/storage leak. Fix by clearing each removed message override inside pruneMessagesAfterRevert, or by introducing a shared helper for “remove these message IDs” so all deletion paths clean the new side store consistently.

  • Medium: packages/ui/src/stores/message-prompt-display.ts:1 persists the full original prompt text in localStorage, not just display metadata. The PR summary says “Persist the display-only folding metadata,” but the implementation duplicates the entire prompt, including hidden sections, in a browser store with no size bound or TTL. This is fragile for large prompts and creates another long-lived copy of potentially sensitive prompt content. A better implementation is to persist marker/range metadata keyed by message ID and render against the current message text from the message store, rather than storing a second full prompt body.

Additional quality notes:

  • packages/ui/src/components/message-item.tsx:600 has JSX indentation drift in the changed block. Not behavioral, but it is a code-quality smell in a touched file.

  • packages/ui/src/lib/hidden-prompt-sections.ts:27 strips marker tokens even when the hide section is malformed/unbalanced, while display splitting falls back to showing the marker text. That mismatch is probably acceptable if malformed markers are unsupported, but it should be an explicit choice and ideally covered by a test for preparePromptDisplayText.

Verification performed:

  • Passed: npx tsx --test "packages/ui/src/lib/hidden-prompt-sections.test.ts" "packages/ui/src/stores/message-prompt-display.test.ts"

  • Could not validate in this checkout: npm run typecheck --workspace @codenomad/ui fails broadly because dependencies/types are missing (solid-js, node:test, SDK packages, etc.). This does not look isolated to this PR’s code.

  • Could not validate in this checkout: npm run build --workspace @codenomad/ui fails because vite is missing.

Oversized touched files to keep on the refactor radar:

  • packages/ui/src/stores/message-v2/instance-store.ts is about 1,281 lines.

  • packages/ui/src/components/message-item.tsx is about 702 lines.

Recommendation: do not merge until the stale override cleanup is fixed and the persistence strategy is either narrowed to metadata/ranges or explicitly accepted as storing full prompt bodies in localStorage.

--
Yours,
CodeNomadBot

Use segment-length metadata instead of persisting the full original prompt body in localStorage so hidden prompt sections keep their collapsed display state without creating an extra long-lived copy of the prompt text.

This also clears the persisted metadata when revert pruning removes user messages, keeping the side store aligned with message deletion paths and avoiding stale hidden-section leftovers.

Validation:
- npx tsx --test "packages/ui/src/lib/hidden-prompt-sections.test.ts" "packages/ui/src/stores/message-prompt-display.test.ts"
- npm run typecheck --workspace @codenomad/ui
- npm run build --workspace @codenomad/ui
@pascalandr
Copy link
Copy Markdown
Contributor Author

@CodeNomadBot

Same review again please

@codenomadbot
Copy link
Copy Markdown
Contributor

codenomadbot Bot commented May 8, 2026

Understood request: repeat the gatekeeper review for the latest PR state. Assumption: review-only pass, no branch changes requested.

Gatekeeper result: no blocking findings found in the latest state.

What changed since the prior review:

  • The stale override cleanup issue is addressed: pruneMessagesAfterRevert now clears prompt display overrides for pruned message IDs.

  • The full-prompt localStorage concern is addressed: persistence now stores segment metadata (hidden + length) instead of duplicating the original prompt body.

Review notes:

  • The metadata approach is a much better implementation for privacy and storage footprint. splitHiddenPromptSections also fails closed by returning null if persisted metadata no longer matches the message text length, which avoids rendering incorrect folds.

  • Malformed markers now stay as plain text for both send and display paths, and that behavior is covered by a test.

  • The JSX indentation drift from the previous pass was fixed.

Residual risks / suggestions, non-blocking:

  • resolveClientPromptDisplayText in packages/ui/src/stores/message-v2/instance-store.ts now resolves metadata, not text. Renaming it to resolveClientPromptDisplayMetadata would avoid future confusion, but this is not a merge blocker.

  • The metadata persistence is intentionally keyed by message ID in localStorage. That is acceptable for this feature, but if message IDs ever become reusable across imported/restored sessions, the text-length mismatch guard is the main protection.

Verification performed:

  • Passed: npx tsx --test "packages/ui/src/lib/hidden-prompt-sections.test.ts" "packages/ui/src/stores/message-prompt-display.test.ts"

  • Passed: git diff --check origin/dev...HEAD

  • Could not validate in this checkout: npm run typecheck --workspace @codenomad/ui still fails broadly because dependencies/types are missing (solid-js, node:test, SDK packages, etc.). This does not appear isolated to this PR.

  • Could not validate in this checkout: npm run build --workspace @codenomad/ui fails because vite is missing.

Oversized touched files to keep on the refactor radar:

  • packages/ui/src/stores/message-v2/instance-store.ts is about 1,283 lines.

  • packages/ui/src/components/message-item.tsx is about 707 lines.

Recommendation: acceptable to merge once CI confirms typecheck/build in a dependency-complete environment.

--
Yours,
CodeNomadBot

@shantur
Copy link
Copy Markdown
Collaborator

shantur commented May 8, 2026

@pascalandr Thanks for working on this, but not sure we should do it. It might confuse users.

@pascalandr
Copy link
Copy Markdown
Contributor Author

@pascalandr Thanks for working on this, but not sure we should do it. It might confuse users.

I'm not sure how it can confuse users, what do you mean ?

@shantur
Copy link
Copy Markdown
Collaborator

shantur commented May 9, 2026

@pascalandr Thanks for working on this, but not sure we should do it. It might confuse users.

I'm not sure how it can confuse users, what do you mean ?

I see that your are using codenomad:hide which is very explicit. My take is

  1. I don't see this feature being used by more than 1 user.
  2. Sending Intro<codenomad:hide>Secret</codenomad:hide>Outro will surely confuse models about what is sent
  3. If the user is sending secrets to model, its already in plain text everywhere.

@pascalandr
Copy link
Copy Markdown
Contributor Author

Oh I see but this is not the use case here : #266 (comment)
My wording was bad, I should have used codenomad:collapse instead , this is not about secrets but about convenience. This could be very useful when pasting something in your prompt but you want it to stay collapsed for the user for convenience but still not hidden to the model.
but I realize indeed this is exactly how I would like pasted text in my prompt to appear in the message window collapsed by default (like collapsed tool for example) so my implementation is bad at the moment, What if pasted text instead of converted to raw text in bulk could keep its form and be collapsed by defaut (and uncollapsed if needed) if it's possible, does it make sens ?

@shantur
Copy link
Copy Markdown
Collaborator

shantur commented May 9, 2026

If we can do something without sending additional stuff to LLM then it could used.
For paste maybe, we can surround with with codeblocks with language paste and detect it automatically and collapse it. Models do understand markdown syntax and could work.

Maybe if needed, a codeblock with language hidden would be a better way, that way model would understand the codeblock and we can treat this codeblock specially and hide it.

TBH, I see this as low value vs high effort and maintenance and not very keen on it. It all adds up in the markdown rendering logic which is a heavy computation part already.

@pascalandr
Copy link
Copy Markdown
Contributor Author

If we can do something without sending additional stuff to LLM then it could used. For paste maybe, we can surround with with codeblocks with language paste and detect it automatically and collapse it. Models do understand markdown syntax and could work.

Maybe if needed, a codeblock with language hidden would be a better way, that way model would understand the codeblock and we can treat this codeblock specially and hide it.

TBH, I see this as low value vs high effort and maintenance and not very keen on it. It all adds up in the markdown rendering logic which is a heavy computation part already.

ok I'll keep this in mind and will go on only if the trade-off is worthwhile enough

@pascalandr pascalandr added the needs-work PR needs more work label May 16, 2026
Rescope the hidden prompt section work to the pasted-text history use case so long placeholder-backed pastes stay fully visible to the model while rendering as collapsed disclosures in user message history.

This replaces the hidden-marker-specific metadata helper with prompt display metadata that resolves pasted placeholders at send time, preserves optimistic and persisted display metadata, and keeps the existing prompt attachment flow intact when users edit or remove placeholders before submission. The history renderer and localized disclosure label now reflect pasted text rather than hidden prompt syntax.

Add focused regression coverage for prompt preparation, metadata persistence, and casing-edited pasted placeholders, and validate the change with targeted tests, UI typecheck, and UI production build.
@github-actions
Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/26212242172

Artifacts expire in 7 days.
Artifacts:

  • pr-407-55d14f81447387b52539ebd65a222e702153009f-electron-macos
  • pr-407-55d14f81447387b52539ebd65a222e702153009f-tauri-macos
  • pr-407-55d14f81447387b52539ebd65a222e702153009f-tauri-windows
  • pr-407-55d14f81447387b52539ebd65a222e702153009f-tauri-linux
  • pr-407-55d14f81447387b52539ebd65a222e702153009f-tauri-macos-arm64
  • pr-407-55d14f81447387b52539ebd65a222e702153009f-electron-windows
  • pr-407-55d14f81447387b52539ebd65a222e702153009f-electron-linux

@github-actions
Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/26218379417

Artifacts expire in 7 days.
Artifacts:

  • pr-407-6933695eafc6d659b8fb5bf97e4ab0f987a20ca0-tauri-macos
  • pr-407-6933695eafc6d659b8fb5bf97e4ab0f987a20ca0-tauri-macos-arm64
  • pr-407-6933695eafc6d659b8fb5bf97e4ab0f987a20ca0-tauri-linux
  • pr-407-6933695eafc6d659b8fb5bf97e4ab0f987a20ca0-tauri-windows
  • pr-407-6933695eafc6d659b8fb5bf97e4ab0f987a20ca0-electron-macos
  • pr-407-6933695eafc6d659b8fb5bf97e4ab0f987a20ca0-electron-windows
  • pr-407-6933695eafc6d659b8fb5bf97e4ab0f987a20ca0-electron-linux

@pascalandr pascalandr removed the needs-work PR needs more work label May 21, 2026
Keep placeholder-backed pasted text intact for message submission so the send path can generate collapsed history metadata instead of flattening the prompt too early in the composer.

This introduces a prompt submission helper that separates the history entry from the actual submitted message, normalizes pasted text line endings for display metadata generation, and adds focused regression coverage for Windows CRLF hydration and message-mode placeholder handling.

Validated with focused prompt submission tests plus UI typecheck and production build to reduce the risk of regressions while resuming the rescoped PR 407 behavior.
@pascalandr pascalandr changed the title feat(ui): fold hidden prompt sections in chat history feat(ui): collapse pasted text in chat history May 21, 2026
@pascalandr
Copy link
Copy Markdown
Contributor Author

@CodeNomadBot
this a new implementation
Check if it adds maintenance or computation.
I want you to perform the gatekeeper checks for latest PR state

check for regressions
check for better possible implementations
Be the PR gatekeeper
Be ruthless about code quality

@codenomadbot
Copy link
Copy Markdown
Contributor

codenomadbot Bot commented May 21, 2026

Understood request: gatekeeper review of the latest pasted-text-collapse implementation, specifically checking regressions, maintenance burden, computation cost, and better alternatives. Assumption: review-only pass, no branch changes requested.

Gatekeeper result: changes requested.

Findings:

  • Medium: packages/ui/src/components/message-part.tsx:171 still renders the full pasted block through <Markdown> while the <details> is closed. Native <details> collapses visibility, but Solid still mounts the children, so the heavy markdown/render/highlight path runs for the entire pasted payload on initial history render. This directly misses the stated goal of avoiding extra computation in an already-heavy markdown rendering path; in fact it can be worse than before because the message is split into multiple Markdown components. Fix by lazily mounting the pasted segment body only after the details is opened, or by rendering a cheap escaped/plain preview until expansion. If keeping Markdown inside the expanded body, gate it behind an onToggle/signal so collapsed pasted content does not pay markdown cost.

Maintenance / implementation assessment:

  • The new placeholder-backed approach is significantly better than the old explicit marker implementation: it does not send extra control syntax to the model, it uses existing paste metadata, and it persists only segment metadata rather than full prompt text.

  • The added surface area is still non-trivial: new parser/metadata module, submission helper, message-store side persistence, and segmented rendering. That is acceptable only if the render path is made lazy; otherwise we are taking on maintenance without the main performance/readability payoff.

Non-blocking notes:

  • preparePromptSubmission now returns unresolved placeholders for normal message submission and relies on the downstream sendMessage path to resolve them. Current consumers do call sendMessage, so this is okay, but it is a subtle coupling worth documenting or naming clearly.

  • resolveClientPromptDisplayText in packages/ui/src/stores/message-v2/instance-store.ts resolves metadata, not text. Rename to resolveClientPromptDisplayMetadata to reduce future confusion.

Verification performed:

  • Passed: npx tsx --test "packages/ui/src/components/prompt-input/submitPrompt.test.ts" "packages/ui/src/lib/prompt-display-metadata.test.ts" "packages/ui/src/stores/message-prompt-display.test.ts"

  • Passed: git diff --check origin/dev...HEAD

  • Passed after the Tauri prebuild repaired local optional dependencies: npm run typecheck --workspace @codenomad/ui

  • Passed after dependency repair: npm run build --workspace @codenomad/ui

  • Inconclusive: npm run build --workspace @codenomad/tauri-app progressed through UI/server packaging and Rust compilation but exceeded the 120s local timeout before completion.

Oversized touched files to keep on the refactor radar:

  • packages/ui/src/stores/message-v2/instance-store.ts is about 1,300 lines.

  • packages/ui/src/components/message-item.tsx is about 740 lines.

Recommendation: do not merge until collapsed pasted blocks avoid initial Markdown rendering cost. After that, the implementation trade-off looks reasonable for this feature.

--
Yours,
CodeNomadBot

@github-actions
Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/26223556146

Artifacts expire in 7 days.
Artifacts:

  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-macos
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-linux
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-windows
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-electron-macos
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-macos-arm64
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-electron-windows
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-electron-linux

3 similar comments
@github-actions
Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/26223556146

Artifacts expire in 7 days.
Artifacts:

  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-macos
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-linux
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-windows
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-electron-macos
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-macos-arm64
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-electron-windows
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-electron-linux

@github-actions
Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/26223556146

Artifacts expire in 7 days.
Artifacts:

  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-macos
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-linux
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-windows
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-electron-macos
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-macos-arm64
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-electron-windows
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-electron-linux

@github-actions
Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/26223556146

Artifacts expire in 7 days.
Artifacts:

  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-macos
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-linux
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-windows
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-electron-macos
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-tauri-macos-arm64
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-electron-windows
  • pr-407-080ee6c16fa03e6569fd8a422fe3db15f378b1d8-electron-linux

Preserve collapsed pasted prompt sections after reopening sessions by storing prompt display metadata under stable session and message keys instead of ephemeral workspace instance ids.

This also migrates legacy instance-scoped storage entries forward, adds focused persistence coverage for reopen and storage-key migration, and lazy-mounts pasted disclosure markdown so closed blocks avoid the expensive initial markdown and highlight render path.

Validated with focused pasted-text tests plus UI typecheck and production build so the resumed PR 407 scope keeps the fixed placeholder-backed submission flow while improving reopen behavior and rendering cost.
@pascalandr
Copy link
Copy Markdown
Contributor Author

@CodeNomadBot
Same review

@codenomadbot
Copy link
Copy Markdown
Contributor

codenomadbot Bot commented May 21, 2026

Understood request: repeat the CodeNomadBot gatekeeper review for the latest PR #407 state, focusing on regressions, maintenance burden, computation/render cost, and better implementation options. Assumption: review-only pass, no branch changes requested.

Gatekeeper result: changes requested.

Findings:

  • Medium: packages/ui/src/stores/message-prompt-display.ts:141 and packages/ui/src/stores/message-prompt-display.ts:155 no longer clear the keys created by the current v3 key scheme. makeKey now ignores instanceId and stores entries as ${sessionId}:${messageId} (packages/ui/src/stores/message-prompt-display.ts:8), but clearPromptDisplayOverridesForSession still looks for ${instanceId}:${sessionId}: and clearPromptDisplayOverridesForInstance still looks for ${instanceId}:. That means single-message deletes work, but session/instance cleanup leaves persisted pasted-display metadata behind. This is a regression from the new stable-key migration and should be covered by tests that seed v3 keys, call the session/instance cleanup helpers, and assert storage is actually emptied or narrowed correctly.

Resolved from prior review:

  • The previous blocker about collapsed pasted sections still paying initial Markdown render cost appears fixed. The current rendering path lazy-mounts the expanded pasted content behind disclosure state instead of rendering the full Markdown body while collapsed.

Maintenance / implementation assessment:

  • The placeholder-backed implementation remains the right direction compared with explicit hidden markers: it avoids sending display-control syntax to the model and keeps the collapse behavior as UI metadata.

  • The v3 stable-key change is reasonable for preserving collapse metadata across message-store instance changes, but it needs cleanup semantics updated to match the new key ownership model. If instance-wide cleanup can no longer be expressed precisely after removing instanceId from the key, the helper should either be redesigned around available session IDs or removed from callers that expect instance scoping.

Verification performed:

  • Passed: npx tsx --test "packages/ui/src/components/prompt-input/submitPrompt.test.ts" "packages/ui/src/lib/prompt-display-metadata.test.ts" "packages/ui/src/stores/message-prompt-display.test.ts"

  • Passed: git diff --check origin/dev...HEAD

  • Passed: npm run typecheck --workspace @codenomad/ui

  • Passed: npm run build --workspace @codenomad/ui with the existing Vite/esbuild warning from virtua about JSX import source / automatic transform.

  • Not claimed: I do not have a verified successful local result for npm run build --workspace @codenomad/tauri-app from this review pass.

Non-blocking notes:

  • resolveClientPromptDisplayText in packages/ui/src/stores/message-v2/instance-store.ts still reads like it resolves text, but it resolves metadata. resolveClientPromptDisplayMetadata would reduce future confusion.

Oversized touched files to keep on the refactor radar:

  • packages/ui/src/stores/message-v2/instance-store.ts is about 1,300 lines.

  • packages/ui/src/components/message-item.tsx is about 740 lines.

Recommendation: do not merge until the v3 prompt-display cleanup paths are corrected and covered by tests.

--
Yours,
CodeNomadBot

@github-actions
Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/26225545956

Artifacts expire in 7 days.
Artifacts:

  • pr-407-acff400d9189c3936d8eeedc17c0f1ad7636abb8-tauri-macos
  • pr-407-acff400d9189c3936d8eeedc17c0f1ad7636abb8-tauri-linux
  • pr-407-acff400d9189c3936d8eeedc17c0f1ad7636abb8-electron-macos
  • pr-407-acff400d9189c3936d8eeedc17c0f1ad7636abb8-tauri-windows
  • pr-407-acff400d9189c3936d8eeedc17c0f1ad7636abb8-tauri-macos-arm64
  • pr-407-acff400d9189c3936d8eeedc17c0f1ad7636abb8-electron-windows
  • pr-407-acff400d9189c3936d8eeedc17c0f1ad7636abb8-electron-linux

Update prompt display metadata cleanup to match the stable v3 session/message storage key model so clearing a session or instance removes the correct persisted pasted-collapse entries instead of relying on obsolete instance-scoped prefixes.

This adds focused regression coverage for session-level and instance-level v3 cleanup behavior, keeps legacy key cleanup support in place, and passes the instance store's known session ids into broader cleanup so reopen persistence does not regress while stale metadata is removed correctly.

Validated with focused pasted-text tests plus UI typecheck and production build to keep the rescoped PR 407 history-collapse behavior stable across reopen and cleanup paths.
@pascalandr
Copy link
Copy Markdown
Contributor Author

@CodeNomadBot
Same review

@codenomadbot
Copy link
Copy Markdown
Contributor

codenomadbot Bot commented May 21, 2026

Understood request: repeat the CodeNomadBot gatekeeper review for the latest PR #407 state after the cleanup-semantics fix. Assumption: review-only pass, no branch changes requested.

Gatekeeper result: no blocking findings.

Findings:

  • None blocking. The previous v3 prompt-display cleanup issue is addressed: session cleanup now matches stable ${sessionId}: keys, instance cleanup receives the known session IDs from state.sessions, and focused tests cover stable session and instance cleanup behavior.

Resolved from prior reviews:

  • Collapsed pasted sections no longer pay the full initial Markdown render cost while closed; the expanded pasted Markdown body is lazy-mounted after disclosure expansion.

  • Stable v3 prompt-display metadata survives instance reopen while cleanup paths no longer leave stale stable-key metadata behind for known sessions.

Maintenance / implementation assessment:

  • The placeholder-backed approach remains the right implementation direction. It avoids sending display-control syntax to the model, keeps pasted content fully visible in the request text, and scopes collapse behavior to client display metadata.

  • The stable-key storage model is acceptable now that cleanup semantics are explicit. The tradeoff is that instance-wide cleanup depends on the caller supplying known session IDs, which the current clearInstance path now does.

Non-blocking notes:

  • resolveClientPromptDisplayText in packages/ui/src/stores/message-v2/instance-store.ts still returns metadata, not text. A future rename to resolveClientPromptDisplayMetadata would reduce confusion, but this is not merge-blocking.

Verification performed:

  • Passed: npx tsx --test "packages/ui/src/components/prompt-input/submitPrompt.test.ts" "packages/ui/src/lib/prompt-display-metadata.test.ts" "packages/ui/src/stores/message-prompt-display.test.ts"

  • Passed: git diff --check origin/dev...HEAD

  • Passed: npm run typecheck --workspace @codenomad/ui

  • Passed: npm run build --workspace @codenomad/ui with the existing Vite/esbuild warning from virtua about JSX import source / automatic transform, plus existing chunk-size warnings.

  • Passed: npm run build --workspace @codenomad/tauri-app on local macOS arm64, producing packages/tauri-app/target/release/bundle/macos/CodeNomad.app.

Oversized touched files to keep on the refactor radar:

  • packages/ui/src/stores/message-v2/instance-store.ts is about 1,300 lines.

  • packages/ui/src/components/message-item.tsx is about 740 lines.

Recommendation: acceptable to merge from this gatekeeper pass.

--
Yours,
CodeNomadBot

@github-actions
Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/26227365750

Artifacts expire in 7 days.
Artifacts:

  • pr-407-2e0f6860e6064b6bbe683c07321dc935fc5163fc-tauri-macos
  • pr-407-2e0f6860e6064b6bbe683c07321dc935fc5163fc-tauri-linux
  • pr-407-2e0f6860e6064b6bbe683c07321dc935fc5163fc-tauri-windows
  • pr-407-2e0f6860e6064b6bbe683c07321dc935fc5163fc-electron-macos
  • pr-407-2e0f6860e6064b6bbe683c07321dc935fc5163fc-tauri-macos-arm64
  • pr-407-2e0f6860e6064b6bbe683c07321dc935fc5163fc-electron-windows
  • pr-407-2e0f6860e6064b6bbe683c07321dc935fc5163fc-electron-linux

@pascalandr
Copy link
Copy Markdown
Contributor Author

@CodeNomadBot
can you confirm the implementation trade-off is worthwhile for this feature

@codenomadbot
Copy link
Copy Markdown
Contributor

codenomadbot Bot commented May 21, 2026

Understood request: confirm whether the implementation trade-off is worthwhile for this feature. Assumption: this is an architecture/merge-readiness judgment only, not a request for new code changes.

Yes, the trade-off is worthwhile for this feature in its current form.

Why it is justified:

  • The user-visible problem is real: long pasted blocks make chat history hard to scan, and this feature improves readability without changing what the model receives.

  • The implementation uses the existing placeholder-backed paste flow instead of inventing hidden prompt markers. That is the right boundary: collapse state is client display metadata, not prompt syntax.

  • The model-facing text remains unchanged after placeholder resolution. That keeps behavior safer than approaches that add/remove sentinel markup around pasted content.

  • The performance concern that would have made the trade-off questionable has been addressed: collapsed pasted bodies are not Markdown-rendered until expansion.

  • The persistence cost is now acceptable: metadata is compact segment length/kind data, stable across reopen, and cleanup semantics are covered for known sessions.

Costs accepted:

  • There is more surface area than a pure render-only heuristic: metadata preparation, store persistence, optimistic-message handoff, and segmented rendering.

  • The store now carries a subtle client-only metadata path. That is acceptable because the feature needs to survive optimistic replacement and reloads; a render-only local heuristic would either be brittle or lose the collapsed state.

  • Instance-wide cleanup depends on known session IDs after moving to stable keys. That is a reasonable compromise because clearInstance now supplies those IDs, and stale metadata risk is bounded by the cleanup tests added.

Why I would not push for a simpler alternative now:

  • Re-detecting pasted sections from final plain text alone would be unreliable once placeholders are resolved, especially if the user edits surrounding content.

  • Persisting full pasted text would be heavier and riskier than persisting segment metadata.

  • Embedding markers in the prompt text would leak UI concerns into the model path and was the worse design direction.

Recommendation: keep this implementation. The added complexity is proportionate to the feature requirements now that lazy rendering and cleanup semantics are fixed. The only follow-up I would still suggest is a small naming cleanup later: rename resolveClientPromptDisplayText to resolveClientPromptDisplayMetadata to better match what it returns.

--
Yours,
CodeNomadBot

@pascalandr
Copy link
Copy Markdown
Contributor Author

pascalandr commented May 21, 2026

@shantur I think this is ready to merge. I didn’t realize I needed this feature at first, but after using it, I really really like it.

@pascalandr pascalandr requested a review from shantur May 25, 2026 21: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.

[Feature] A way to hide portions of a prompt in codenomad display

2 participants