Skip to content

Port resource preview UX improvements to PromptsScreen (#1328)#1331

Open
cliffhall wants to merge 8 commits into
v2/mainfrom
v2/issue-1328-prompts-screen-parity
Open

Port resource preview UX improvements to PromptsScreen (#1328)#1331
cliffhall wants to merge 8 commits into
v2/mainfrom
v2/issue-1328-prompts-screen-parity

Conversation

@cliffhall
Copy link
Copy Markdown
Member

@cliffhall cliffhall commented May 20, 2026

Summary

Brings the prompts-side flow up to parity with the resource preview work from #1326:

  • Argument-form width cap: maw=40% on the form pane.
  • Auto-hide form after Get Prompt: handleSelectPrompt decides between auto-fetch (no-arg prompts) vs. form-render (arg-bearing prompts); submittedFor flips off the form once the user submits.
  • Auto-fetch on sidebar selection for no-argument prompts.
  • Sized-to-content preview with viewport cap: PreviewCard variant=\"preview\" + PreviewPane mah=SCROLL_MAX_HEIGHT. PromptMessagesDisplay pins its header (flex: 0 0 auto) and the inner ScrollArea (flex: 0 1 auto, mih: 0) absorbs overflow.
  • Markdown in prompt messages: MessageBubble routes each content block through ContentViewer with mimeType=\"text/markdown\" for text blocks; image/audio/resource flow through the existing ContentViewer branches. Non-renderable block types (tool_use, tool_result) are filtered out.
  • Stale-result guard: App.tsx tags getPromptState with promptName so the screen can ignore a stale result whose name no longer matches the sidebar selection.
  • Live completion/complete on argument inputs: PromptArgumentsForm accepts onCompleteArgument + completionsSupported, swaps TextInput → Mantine Autocomplete, mirrors the per-arg AbortController + per-arg timer / 300ms debounce pattern from ResourceTemplatePanel. PromptsScreen re-injects the active prompt name as a ref/prompt envelope. App.tsx already had the callback; just threaded it through.

Closes #1328.

Test plan

  • npm run validate (format, lint, build, unit + coverage gate)
  • npm run test:integration (379 passed)
  • npm run test:storybook (300 passed)
  • New / updated tests cover: auto-fetch on no-arg selection (and no re-fire on prop change), form auto-hide after submit, stale-name guard, ref/prompt envelope on completion, markdown rendering in MessageBubble, multi-block messages.
  • Manual: connect to the everything server, select a no-arg prompt (should auto-fetch + show messages); select a prompt with required args (should show form ≤40% width); fill + Get Prompt → form disappears, messages render as markdown; verify autocomplete fires per keystroke against completion/complete.

🤖 Generated with Claude Code

Brings the prompt-fetching flow up to parity with the resource preview
work from #1326:

- Cap the argument-form pane at maw=40% so a bare input + button doesn't
  stretch across wide displays.
- Auto-fetch no-argument prompts the moment they're picked from the
  sidebar (handleSelectPrompt routes them straight to onGetPrompt({})),
  and hide the form once the user clicks Get Prompt — the result panel
  takes the same fixed-height column the resource preview uses.
- Apply the PreviewCard variant=preview pattern: card sizes to content
  but caps at viewport, PromptMessagesDisplay pins its header (flex 0 0
  auto) and lets the inner ScrollArea (flex 0 1 auto, mih 0) absorb
  overflow.
- Tag getPromptState with the prompt name in App.tsx so the screen can
  ignore a stale result whose name no longer matches the selection.
- MessageBubble now routes each content block through ContentViewer
  (markdown for text via mimeType="text/markdown", image/audio/resource
  via existing ContentViewer branches). Non-renderable block types
  (tool_use, tool_result) are filtered out; the role-label header keeps
  the bubble visible regardless.
- PromptArgumentsForm gains onCompleteArgument + completionsSupported;
  when both are set, each input becomes Mantine Autocomplete with the
  same per-arg AbortController + per-arg debounce timer pattern as
  ResourceTemplatePanel. PromptsScreen + InspectorView + App.tsx wire
  the callback to inspectorClient.getCompletions with a
  ref/prompt envelope.

Closes #1328.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cliffhall cliffhall added the v2 Issues and PRs for v2 label May 20, 2026
cliffhall and others added 6 commits May 20, 2026 14:22
A top-left CloseButton dismisses the preview panel. The host screen
decides what to fall back to:

- ResourcesScreen remembers the originating template URI when the user
  reads from a template form (originatingTemplateUri); closing the
  preview restores the template form. Plain-resource reads (sidebar
  selection) just empty the selection and return to the empty state.
  Picking a different template / resource from the sidebar clears the
  back-trail.
- PromptsScreen flips submittedFor back to undefined when the closed
  prompt has arguments — the argument form re-renders with the
  user's values preserved so they can edit and re-submit. No-arg
  prompts have nothing to fall back to, so the selection is dropped
  and the empty state appears.

The X button is hidden when the host omits onClose, so callers that
don't want a dismiss control keep their existing rendering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The OK-state preview already had its X button (inside the panel
component itself). Pending and error states were inline cards in
renderReadState / renderPreview with no way to dismiss them, so a
user who submitted bad input to a resource template or prompt was
stuck staring at the error until they picked a different sidebar
item. Adds a top-left CloseButton row to both states on both screens,
wired to the same handleClosePreview handler — so the template form
or argument form re-appears on close just like it does from the OK
state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two fixes to the PromptArgumentsForm autocomplete:

- Focusing an argument input now fires completion/complete immediately
  (handleFocus) — the dropdown is populated as soon as the user clicks
  in, not only after they start typing. Any in-flight debounce timer
  for the same arg is cancelled so a stale keystroke request can't
  overwrite the fresh focus response.
- The completion context now includes every declared prompt argument
  (with "" for ones the user hasn't typed into yet), minus the one
  being completed. Previously the context only carried args the user
  had touched, so servers that disambiguate based on co-arguments
  couldn't see the full picture on the first keystroke.

Tests cover both: a focus-only path that fires before any keystroke,
and a typing path that asserts the empty sibling is sent through.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the prompt-side change: focusing a template variable input
now fires completion/complete immediately so the dropdown populates
the moment the user clicks in, rather than waiting for the first
keystroke + 300ms debounce. Any pending debounce timer for the same
variable is cancelled first so a stale keystroke response can't
overwrite the focus response.

The sibling-context coverage was already correct here — `variables`
is seeded with empty strings for every declared template variable at
mount and on template switch, so the context payload always carries
the full variable set minus the one being completed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two fixes so the completion dropdowns on prompt-argument and
resource-template inputs look like every other dropdown in the app:

- App.css: the dark-mode dropdown / option-hover rules used to target
  .mantine-Select-* only, so the Autocomplete dropdowns shipped with
  Mantine's default surface color and a different hover background.
  Re-scoped to .mantine-Combobox-* so every Combobox-built input
  (Select, Autocomplete, MultiSelect, …) inherits the same styling.
- theme/Autocomplete.ts: new theme module setting `radius: "md"` so
  Autocomplete matches the default Select / TextInput corner radius.
  Wired through theme/index.ts and theme/theme.ts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous commit re-scoped the dark-mode dropdown rules from
`.mantine-Select-*` to `.mantine-Combobox-*` on the assumption that
both Select and Autocomplete share a Combobox class on the dropdown
root. They don't — Mantine's Combobox factory takes
`__staticSelector` from the parent component, so Select emits
`mantine-Select-dropdown` and Autocomplete emits
`mantine-Autocomplete-dropdown` with no shared `Combobox` class on
that element. The `.mantine-Combobox-*` selector matched nothing,
so the TaskControls filter (and every other Select) lost its gray
surface and reverted to Mantine's default brown-ish dark background.

List both selectors so Select dropdowns keep their styling and
Autocomplete dropdowns pick it up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cliffhall
Copy link
Copy Markdown
Member Author

Follow-up commits since this PR was opened

The initial commit (c61e15f1) covered the original #1328 scope: 40%-width form pane, auto-fetch / auto-hide, sized-to-content preview with viewport cap, markdown in messages, stale-name guard, and live completion/complete on prompt arguments. Six follow-up commits refined the surface based on visual review:

1. Close (X) buttons on result panels — b1b541b9

Added a top-left Mantine CloseButton on ResourcePreviewPanel and PromptMessagesDisplay (new optional onClose prop on each). The host screens decide what to fall back to:

  • ResourcesScreen tracks an originatingTemplateUri so that closing a preview that came from a template form restores the form (with values intact). Plain-resource reads close back to the empty state. Picking a different template / resource from the sidebar clears the back-trail.
  • PromptsScreen flips submittedFor back to undefined on close for arg-bearing prompts — the form re-renders with the user's values preserved so they can edit and re-submit. No-arg prompts drop the selection entirely.

The X button is hidden when the host omits onClose, so consumers that don't want a dismiss control are unaffected.

2. Close button on pending / error states — 6d758749

The OK-state preview already had its X button inside the panel component itself, but the pending and error states were inline cards rendered by renderReadState / renderPreview with no dismiss control. A user who submitted bad input to a resource template URI was stuck on the error until they picked a different sidebar item. Added a top-left CloseButton row to both pending and error states on both screens, wired to the same handleClosePreview handler.

3. Fire prompt completions on focus + full sibling context — 5408e164

Two fixes to PromptArgumentsForm's autocomplete:

  • handleFocus fires completion/complete immediately on focus (no debounce) so the dropdown is populated when the user first clicks in, not only after they start typing. Any in-flight debounce timer for the same arg is cancelled first so a stale keystroke request can't overwrite the fresh focus response.
  • buildContext now seeds every declared prompt argument with "" for unset ones, minus the one being completed. Previously the context only carried args the user had typed something into, so servers that disambiguate based on co-arguments couldn't see the full picture on the first keystroke.

4. Same focus-fire treatment for resource templates — fd1c7313

Mirrored the focus-fire change to ResourceTemplatePanel. The sibling-context coverage was already correct on that side — variables is seeded with empty strings for every declared template variable at mount and on template switch — so only the focus handler was new. Same debounce-cancel rule on focus.

5. Autocomplete dropdown styling — 1561b46e (broken) → 719e7bec (fixed)

The completion dropdowns were rendering with Mantine's default dark surface color, which didn't match the gray surface every other dropdown in the app uses.

First attempt (broken) scoped the dark-mode dropdown / option-hover CSS to .mantine-Combobox-* on the assumption that Select and Autocomplete share a Combobox class on the dropdown root. They don't — Mantine's Combobox factory inherits __staticSelector from the parent component, so Select emits mantine-Select-dropdown and Autocomplete emits mantine-Autocomplete-dropdown with no shared Combobox class on the dropdown element. The .mantine-Combobox-* selector matched nothing, breaking the TaskControls filter and every other Select dropdown in dark mode.

Fix lists both .mantine-Select-dropdown, .mantine-Autocomplete-dropdown (and matching *-option:hover) explicitly. Also added theme/Autocomplete.ts with radius: "md" so the input chrome matches the default Select / TextInput corner radius at rest.


All four pipelines (validate, unit + coverage, integration, storybook) are green at every commit. Resource-side tests were untouched apart from the close-button additions; prompt-side tests cover the new auto-fetch, hide-after-submit, stale-guard, ref/prompt envelope, focus-fire completion, and empty-sibling-context paths.

@cliffhall
Copy link
Copy Markdown
Member Author

@claude review

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 20, 2026

Claude finished @cliffhall's task in 2m 55s —— View job


Code Review

Read the full diff against origin/v2/main. The PR brings PromptsScreen into parity with the resource preview work cleanly — the two screens now share the same layout primitives (PreviewCard variant="preview" + PreviewPane + inner ScrollArea), the same back-trail-style close behavior, and the same debounced + focus-fire completion pipeline. Tests cover the novel paths well.

A few observations below, mostly minor / forward-looking. Nothing blocking — ship as-is if the manual test item at the end of the PR body passes.


1. Prompt text blocks are always rendered as markdown — intentional but irreversible for consumers

MessageBubble.tsx:42-45 hard-codes text/markdown for every text block, while ResourcePreviewPanel is careful to fall back to markdown only when the server supplies text/markdown or the URI ends in .md (see ResourcePreviewPanel.tsx:145-165 and the test at ResourcePreviewPanel.test.tsx:257-272 that explicitly guards # not a heading in text/plain from being promoted to H1).

Prompts don't carry a mimeType on text blocks, so the SDK leaves no signal to branch on — but the consequence is that prompt prose containing #, >, backticks, or underscores will get transformed. For the "everything" server this is the intent; for a server returning a shell snippet or a raw log line in a prompt message, it's a regression vs. the resource side. Worth documenting as a known caveat in the comment at MessageBubble.tsx:37-45 or considering whether prompts should gain an opt-out later. Not a blocker.

2. PromptArgumentsForm has no canSubmit guard, unlike ResourceTemplatePanel

ResourceTemplatePanel.tsx:205,262 disables "Read Resource" until every variable is non-empty. PromptArgumentsForm.tsx:200-204 always enables "Get Prompt" — even when required args are blank. The server will reject, the error state shows, and the user can close back into the form — so it's functional, just asymmetric with the resource side. A small prompt.arguments?.filter(a => a.required).every(a => argumentValues[a.name]?.length) check would restore symmetry.

3. Focus fires a completion on every focus event, unbatched

PromptArgumentsForm.tsx:144-156 and ResourceTemplatePanel.tsx:187-203 both call runCompletion synchronously on every onFocus. Autocomplete can refocus the input when the user clicks a dropdown option or tabs back in from another field, so rapid focus-toggling will hammer the server with N independent completion/complete calls (each of which correctly aborts the previous via the per-arg controller, but still issues the HTTP request — the SDK's getCompletions doesn't accept an AbortSignal, see core/mcp/inspectorClient.ts:1799-1807). Worth gating focus-fire on "we don't already have a fresh response for this value/context" — or at minimum documenting that the abort is client-state-only, not a wire-level cancel.

4. Sibling context captured at keystroke time, not fire time

PromptArgumentsForm.tsx:134 computes const context = buildContext(argName) before scheduling the 300ms debounce. If the user types into arg A, then within 300ms types into arg B, A's fire will ship context that misses B's new value. ResourceTemplatePanel.tsx:166-185 avoids this by computing context inside the setVariables updater from next. Not a correctness bug (the values were "current" at keystroke time), but the two forms differ in subtle disambiguation semantics. Easy to align by capturing context in the debounce callback instead of in handleChange.

5. Closing a pending preview leaves the request in flight

PromptsScreen.tsx:150-161 and the analogous path in ResourcesScreen.tsx:172-178 flip the "submitted" marker off so the eventual result is filtered out client-side (the submittedFor !== selectedPrompt.name guard on previewActive), but the parent onGetPrompt / onReadResource promise keeps running and will set getPromptState / readState. If the user then re-submits the same prompt, two calls race to populate the same slot. Since both tag the state with the name, the result matches and renders either way — functionally fine, just wasted work. Probably OK to leave for now.

6. handleSelectPrompt clears argumentValues even when re-clicking the same prompt

PromptsScreen.tsx:129-142: clicking a sidebar entry for the prompt that's already selected (e.g. to dismiss a stuck preview) will wipe the form values. Users who close the preview via the ✕ keep their values (handleClosePreview doesn't clear them), but a sidebar re-click is a different reset path. If that's intended, fine — but if the intent is "sidebar = navigate, ✕ = dismiss", then a if (name === selectedPromptName) return; early-return would make the two paths consistent.

7. Tiny nit — ThemeAutocomplete is minimal

theme/Autocomplete.ts only sets radius: "md", which already matches theme.defaultRadius = "md" at theme/theme.ts:43. The file is defensive (in case the default changes), but it's effectively a no-op right now. Keep it or inline the default — either is fine.


Tests

Coverage is good. Call-outs:

  • PromptsScreen.test.tsx:67-90 — nice assertion that props-change doesn't re-fire auto-fetch. This was the main risk of the new effect-free design.
  • PromptArgumentsForm.test.tsx:176-205 — focus-fire behavior verified with an empty sibling context. Matches the new buildContext seeding.
  • MessageBubble.test.tsx:20-30 — markdown rendering via content-viewer confirmed.
  • Gap: no test for the AbortController.abort() path — i.e., a fast second keystroke while the first response is in-flight, asserting only the second response's values land in completions. The production code is correct by inspection, but a regression test would be cheap.

All four pipelines are green per the PR body. The code follows the project's Mantine conventions (no inline styles, .withProps() for sub-components, theme variant for preview Card, var(--inspector-*) tokens, CSS classes reserved for pseudo-selectors / dark-mode overrides).

  • Read PR diff against origin/v2/main
  • Reviewed PromptsScreen + stale-name guard in App.tsx
  • Reviewed PromptArgumentsForm (autocomplete, debounce, focus-fire, sibling context)
  • Reviewed PromptMessagesDisplay (scroll layout, close button)
  • Reviewed MessageBubble markdown routing
  • Reviewed ResourcesScreen originatingTemplateUri back-trail
  • Reviewed App.css dropdown selector fix + theme/Autocomplete.ts
  • Reviewed test coverage
  • Posted review feedback
    • Branch: v2/issue-1328-prompts-screen-parity

- PromptArgumentsForm: add a canSubmit guard that disables Get Prompt
  until every required argument has a value, matching the resource
  template form's symmetry. Optional args may stay blank.
- Both forms: capture sibling context inside the debounce callback,
  not at schedule time. Hold the latest argumentValues / variables
  in a ref + sync via useEffect, and call buildContext() at fire
  time. Without this, typing in arg A then arg B within the 300ms
  window would ship A's request with B's pre-keystroke value.
- PromptsScreen.handleSelectPrompt: early-return when the user
  re-clicks the already-selected prompt — sidebar is for navigation,
  ✕ is for dismiss. Previously a re-click wiped form values and
  re-fired the auto-fetch for no-arg prompts.
- MessageBubble: expand the comment on effectiveMimeForBlock to flag
  the unconditional markdown promotion as a known asymmetry with
  the resource side (which only promotes when the server signals it),
  pending a per-block mimeType in the spec.
- New tests: canSubmit disabled / enabled transitions, fire-time
  context capture across siblings, abort-path verification (a stale
  in-flight response must not overwrite the fresh one), and the
  no-op re-click guard on PromptsScreen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cliffhall
Copy link
Copy Markdown
Member Author

Thanks for the review! Walking through each item:

1. Prompt text always rendered as markdown — kept current behavior, expanded the comment on effectiveMimeForBlock in 622270d7 to flag the asymmetry and the "if the spec ever adds a per-block mimeType" exit path. Per the reviewer's read this is intentional for now.

2. canSubmit guard — fixed. PromptArgumentsForm now disables Get Prompt until every required: true argument has a value; optional args may stay blank. Test cases lock the disabled / enabled transitions.

3. Focus fires unbatched — leaving as-is. The per-arg AbortController keeps client state correct, and a focus event fires once per actual focus (Mantine doesn't re-emit on dropdown option click — that goes through onChange). Tab-away + back will refire, which is the trade-off for "immediate dropdown on click in" — worth it for now. I've added a note to consider gating once we see real wire pressure.

4. Sibling context captured at keystroke time — fixed for both forms. Both PromptArgumentsForm and ResourceTemplatePanel now hold the latest values in a ref + sync via useEffect, and call buildContext() inside the debounce callback. New captures sibling values at fire time, not at schedule time test covers the cross-arg keystroke timing.

5. Closing a pending preview leaves the request in flight — leaving as-is per the reviewer's "probably OK to leave" — the submittedFor / promptName guards prevent the late response from leaking into the wrong pane, and the duplicate-fetch-on-resubmit race is wasted work, not a correctness bug.

6. Re-click clears argumentValues — fixed. handleSelectPrompt early-returns when name === selectedPromptName so sidebar re-clicks no longer wipe form values or re-fire the auto-fetch. New test asserts the no-op.

7. ThemeAutocomplete is minimal — keeping as-is. The defensive radius: "md" matches the theme default but pins the value at the component level so future defaultRadius shuffles don't silently shift the Autocomplete chrome (which would re-introduce the mismatch with Select/TextInput).

Test gap (abort path) — added. New aborts an in-flight request when a faster keystroke arrives test holds two promises open simultaneously, resolves the stale one first, then the fresh one, and asserts only the fresh values land in the dropdown.

validate, test:integration, and test:storybook still green.

@cliffhall
Copy link
Copy Markdown
Member Author

@claude review

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 20, 2026

Claude finished @cliffhall's task in 2m 5s —— View job


Follow-up Code Review

Read the latest diff against origin/v2/main, focused on the commits since my previous review (622270d7 and earlier follow-ups). All six review-response items landed as described, with test coverage to match. No blockers — the residual observations below are either intentional trade-offs or low-value nits.


Response to prior review items — all verified ✅

# Item Status
1 Markdown-always caveat documented MessageBubble.tsx:41-55 comment now flags the asymmetry with ResourcePreviewPanel and the "if the spec adds per-block mimeType" exit path.
2 canSubmit guard on PromptArgumentsForm PromptArgumentsForm.tsx:175-179 gates on every required: true arg; PromptArgumentsForm.test.tsx:163-188 covers both the disabled→enabled transition and the "optional-arg-blank is still submittable" path.
3 Focus fires unbatched Left as-is per author call (Mantine doesn't re-emit focus on option click). Reasonable.
4 Fire-time sibling context ✅ Both forms now use a ref + buildContext() inside the debounce callback. PromptArgumentsForm.tsx:115-125, ResourceTemplatePanel.tsx:166-180. Regression test at PromptArgumentsForm.test.tsx:289-329 is exactly the cross-arg keystroke race case I had in mind.
5 Pending-preview in-flight request Left as-is. Author called out wasted-work vs. correctness split; agreed.
6 Re-click clears argumentValues PromptsScreen.tsx:130-134 has if (name === selectedPromptName) return;. Covered by PromptsScreen.test.tsx:222-240.
7 ThemeAutocomplete minimal Left as-is (defensive pin). Fine either way.
Abort-path test PromptArgumentsForm.test.tsx:360-405 — nicely constructed: holds both promises open, resolves the stale one first, then the fresh one, asserts only the fresh values land.

New observations this pass

Minor: asymmetric buildContext shapes between the two forms

ResourceTemplatePanel.tsx:176-180's buildContext clones variablesRef.current and deletes the current var. That relies on variables already carrying every declared template variable (which it does — seeded with "" at mount, line 101). PromptArgumentsForm.tsx:126-138's buildContext instead iterates promptArguments and reads from argumentValuesRef with ?? "" because argumentValues is not pre-seeded. Both produce the same shape, but the asymmetry is load-bearing — if someone later changes how argumentValues is initialized to include seeded empties (mirroring the resource side), the ?? "" fallback becomes dead code. Not worth fixing; just worth a mental note that the two forms are converging in API but diverging in internal invariants.

Minor: dead clause in previewActive

PromptsScreen.tsx:164-167:

const previewActive =
  !!selectedPrompt &&
  submittedFor === selectedPrompt.name &&
  (!getPromptState?.promptName ||
    getPromptState.promptName === selectedPrompt.name);

App.tsx:455-475 always sets promptName on every state transition, so the !getPromptState?.promptName branch is unreachable in production. Defensive for the unit test where callers might omit the tag, but the tests in this PR all set it. Simplifying to getPromptState.promptName === selectedPrompt.name (inside a !!getPromptState && guard) would line up the runtime invariant with the code.

Nit: stale dropdown options between keystroke and response

filter={({ options }) => options} shows whatever the server last returned until the next response lands. So a user who types "a" (gets [alpha, alphabet]), then quickly types "z", sees alpha/alphabet for up to 300ms + network latency before the new list arrives. Not a bug — this is the intentional "server filters, client passes through" design — but if someone later files a "ghost suggestions" UX complaint, this is the spot. Cheap fix if it ever becomes a real issue: clear completions[argName] at the top of handleChange.

Nit: MessageBubble blob-resource label changed from [resource: ...] to [blob: ...]

Not regressive — the ContentViewer label is arguably clearer. Just calling it out as a user-visible copy change (the test at MessageBubble.test.tsx:91 confirms the new label). If UX wants to keep the old wording, the fix lives in ContentViewer, not here.

Micro-nit: RENDERABLE_TYPES / isRenderableBlock

MessageBubble.tsx:20-34 filters to text | image | audio | resource | resource_link. Prompts-side content is actually typed narrower than this in the SDK (ContentBlock union), so in practice every incoming block should pass — the filter is a future-proofing guard for agent messages that could theoretically carry tool_use / tool_result. That's what the comment says, so this is working as designed. No action needed.


Tests

Coverage on the follow-up commits is strong:

  • PromptArgumentsForm.test.tsx:202-231 — focus-fire before any keystroke.
  • PromptArgumentsForm.test.tsx:289-329 — sibling values at fire time, not schedule time. This is the hard one and the test exercises it well.
  • PromptArgumentsForm.test.tsx:360-405 — abort path, correctly resolves stale-then-fresh.
  • PromptsScreen.test.tsx:222-240 — re-click-is-a-noop.
  • PromptsScreen.test.tsx:256-330 — close-button flows for OK / error / no-arg states.
  • ResourceTemplatePanel.test.tsx:142-169 — focus-fire parity on the resource side.
  • ResourcesScreen.test.tsx:168-262 — originatingTemplateUri back-trail for OK and error close paths.

Only gap I'd flag is not having a direct assertion that completions[argName] gets wiped when name changes (the useEffect at PromptArgumentsForm.tsx:65-67). Not worth a new test — the existing resets argument values when switching prompts test at PromptsScreen.test.tsx:242-254 exercises the re-render path that triggers it.


Pipelines

validate, test:integration, test:storybook all green per PR body — consistent with what I'd expect from this diff.


Summary

The follow-up round cleanly addresses every prior review item with tests. The two forms (PromptArgumentsForm / ResourceTemplatePanel) are now structurally parallel for focus-fire + fire-time context + abort handling, which makes future maintenance easier. None of the residual observations above are worth holding the PR for — ship it.

  • Read PR diff against origin/v2/main
  • Review follow-up changes since last review (622270d and earlier)
  • Verify each review response from author landed as described
  • Look for any new issues introduced by the fixes
  • Post consolidated review feedback
    • Branch: v2/issue-1328-prompts-screen-parity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Issues and PRs for v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant