feat(ui): collapse pasted text in chat history#11
Conversation
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
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
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.
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.
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.
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.
Preserve the approved pasted-text history shell by keeping the compact header, right-aligned action cluster, and contour-free icon treatment while leaving the expanded markdown body on the normal rendering path. The disclosure now shows line-count context, uses the ChevronsUpDown/ChevronsDownUp affordance, and keeps copy available without moving the duration placement back into the rejected layout. Add a tiny pasted-text display helper with focused coverage and localize the new line-count and copy accessibility strings across the supported UI locales so the shell remains discoverable without hardcoded English. Validation in this worktree: npx tsx --test packages/ui/src/lib/pasted-text-display.test.ts, npm run typecheck --workspace @codenomad/ui, and npm run build --workspace @codenomad/ui. nomadworks_validate was also run and still fails because of pre-existing repository-wide codemap defects outside TASK-059 scope.
Fix the current upstream/dev baseline type mismatches exposed during the integrated PR batch validation. Align the session SDK imports with the v2 surface and narrow the git status workspace payload typing so the merged batch typechecks cleanly without changing feature behavior.
|
| Filename | Overview |
|---|---|
| packages/ui/src/lib/prompt-display-metadata.ts | New module: parses placeholder-backed prompts into display segments with byte-length metadata; correctly resets shared PASTED_PLACEHOLDER_REGEX.lastIndex before every use and normalizes CRLF so stored lengths stay consistent with persisted text. |
| packages/ui/src/components/message-part.tsx | Adds PastedTextDisclosure (native details, lazy Markdown, copy button) and a For loop over display segments; expanded/collapsed state lives in local signals that are reset on unmount — a known outstanding issue with the virtual-list overscan already flagged in the previous review round. |
| packages/ui/src/stores/message-prompt-display.ts | New localStorage-backed store for segment metadata; v2→v3 key migration is applied once and the v2 key is removed on successful persist; no-op guards prevent unnecessary writes; clearPromptDisplayOverridesForSession correctly removes both stable and legacy-prefixed keys. |
| packages/ui/src/stores/message-v2/instance-store.ts | Integrates prompt-display metadata into every MessageRecord upsert path; movePromptDisplayOverride is called on ID replacement; clearPromptDisplayOverride is called on truncation and session/instance clear — lifecycle coverage appears complete. |
| packages/ui/src/components/prompt-input/submitPrompt.ts | New module separating submission modes; message mode intentionally keeps raw placeholder text as submitPrompt so sendMessage can call preparePromptDisplayText with attachments intact. |
| packages/ui/src/stores/session-actions.ts | sendMessage now calls preparePromptDisplayText (instead of the old resolvePastedPlaceholders) and attaches displayMetadata to the optimistic MessageRecord; the resolved text sent to the model is unchanged. |
| packages/ui/src/types/permission.ts | Replaces PermissionRequestLike with a PermissionV2Request |
| packages/ui/src/lib/sse-manager.ts | Adds typed handlers for permission.v2.asked/replied and question.v2.asked/replied/rejected SSE events alongside existing legacy event types. |
| packages/ui/src/stores/session-api.ts | Large refactor; switches from getChildSessions to getDescendantSessions and adds V2SessionsResponse handling — changes are structural and appear consistent with the new SDK types. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User submits prompt with pasted placeholder] --> B[preparePromptSubmission\nmode=message\nsubmitPrompt = raw text with placeholders]
B --> C[onSend called with raw text + attachments]
C --> D[sendMessage in session-actions.ts]
D --> E[preparePromptDisplayText\nresolve path mentions\nresolve pasted placeholders]
E --> F{Intact placeholder\nbacked structure?}
F -->|Yes| G[Build PromptDisplaySegment array\ninline + pasted sections\nwith byte-length metadata]
F -->|No| H[Fall back: plain resolved text\nno displayMetadata]
G --> I[promptToSend = joined segment texts\ndisplayMetadata = segment kind+length pairs]
H --> I2[promptToSend = fully resolved text]
I --> J[Optimistic MessageRecord upserted\nwith clientPromptDisplayMetadata]
I2 --> J2[Optimistic MessageRecord upserted\nno metadata]
J --> K[setPromptDisplayOverride\npersist to localStorage v3]
J2 --> K
K --> L[Model receives promptToSend\nfull resolved text]
J --> M[replaceMessageId on server confirmation]
M --> N[movePromptDisplayOverride\nold ID to new ID]
N --> O[splitPromptDisplaySections at render\nrebuilds inline + pasted segments]
O --> P{segment.kind}
P -->|inline| Q[Markdown renderer]
P -->|pasted| R[PastedTextDisclosure\nnative details element\nlazy Markdown + copy button]
Reviews (8): Last reviewed commit: "merge: task-086 refresh PR407 onto upstr..." | Re-trigger Greptile
|
PR builds are available as GitHub Actions artifacts: https://github.com/Pagecran/CodeNomad/actions/runs/27044301615 Artifacts expire in 7 days.
|
1 similar comment
|
PR builds are available as GitHub Actions artifacts: https://github.com/Pagecran/CodeNomad/actions/runs/27044301615 Artifacts expire in 7 days.
|
|
PR builds are available as GitHub Actions artifacts: https://github.com/Pagecran/CodeNomad/actions/runs/27046216283 Artifacts expire in 7 days.
|
Keep the Greptile-requested prompt display fixes while removing accidental internal task and evidence artifacts from branch history. This squashes the previous fix and cleanup commits into a single public commit containing only the prompt display store, tests, and prompt input integration changes.
2818eba to
224b6bd
Compare
|
PR builds are available as GitHub Actions artifacts: https://github.com/Pagecran/CodeNomad/actions/runs/27057558608 Artifacts expire in 7 days. |
|
PR builds are available as GitHub Actions artifacts: https://github.com/Pagecran/CodeNomad/actions/runs/27057615857 Artifacts expire in 7 days.
|
|
PR builds are available as GitHub Actions artifacts: https://github.com/Pagecran/CodeNomad/actions/runs/27073348912 Artifacts expire in 7 days.
|
|
PR builds are available as GitHub Actions artifacts: https://github.com/Pagecran/CodeNomad/actions/runs/27073589759 Artifacts expire in 7 days.
|
## Summary - upgrade the UI OpenCode SDK usage for the 1.16 v2 session list/response shapes - migrate session list/search handling to v2 while preserving unsupported legacy session actions - support mixed legacy/v2 permission and question queues, events, hydration, and reply routing during the 1.16 transition ## Validation - npm run typecheck --workspace packages/ui - npx tsx --test "packages/ui/src/types/permission.test.ts" "packages/ui/src/stores/message-v2/instance-store.test.ts"
Fixes NeuralNomadsAI#299 ## Summary - show the active session title in the instance header, just after the menu switch. - keep the title visible whenever the left session drawer is not pinned, using a quiet two-line header treatment without active-item highlighting. - when the unpinned drawer is open as a floating overlay, keep the title in the same left header slot so the drawer covers it instead of pushing toolbar controls around. - disable the feature in mobile view ## Validation - `git diff --check` - `npm run typecheck --workspace @codenomad/ui` - `npm run build --workspace @codenomad/ui` - visually validated in the rebuilt desktop app raw executable
Refreshes origin/feat/hidden-prompt-sections against upstream/dev in a clean isolated worktree without touching the stale issue-266 worktree. The merge keeps the existing pasted-text collapse implementation intact while reconciling the message-v2 permission typing with the newer upstream session and request model. Validation in the isolated worktree included the targeted pasted-text tests, @codenomad/ui typecheck, UI build, and git diff --check. A local npm ci was required inside the worktree so validation used the 1.16.0 SDK versions pinned by the merged lockfile rather than the ancestor worktree's older shared install.
|
PR builds are available as GitHub Actions artifacts: https://github.com/Pagecran/CodeNomad/actions/runs/27092110903 Artifacts expire in 7 days.
|
Summary
Fixes NeuralNomadsAI#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/uinpm run build --workspace @codenomad/uinpm run build --workspace @codenomad/tauri-appLocal desktop verification
packages/tauri-app/target/release/codenomad-tauri.exepackages/tauri-app/target/release/bundle/nsis/CodeNomad_0.15.0_x64-setup.exeFork-local note
This PR is opened in the Pagecran fork to test Greptile review on the existing upstream PR NeuralNomadsAI#407 changes.
Source upstream PR: NeuralNomadsAI#407