feat(web): playground composer for typed messages + Save flow (Plan C)#13
Merged
Conversation
…ages Adds the structured Message[] field alongside the legacy single-string template so the composer (next task) can read messages directly. The page mapper falls back to wrapping the legacy template as a single human message when template_messages is absent (defensive - Plan B's api always sends both, but old api versions during a deploy gap may not). No behavior change yet; the composer still reads template until Task 4 rewrites it. Signed-off-by: gaurav0107 <gauravdubey0107@gmail.com>
Sister to extractVariables(template). Used by the composer (next task) to keep the Inputs panel in sync as the user edits System and Human bodies. Preserves first-seen order so the Inputs panel doesn't reshuffle while the user is mid-edit. Test file deferred until a JS test runner is configured for the web workspace. Signed-off-by: gaurav0107 <gauravdubey0107@gmail.com>
Self-contained, callback-driven. Renders the role pill (system/human dropdown), content textarea (auto-grows on newlines), and the reorder + delete affordances. Uses the design system tokens (--surface, --border, --r-3, .btn .btn-ghost .btn-sm) per DESIGN.md - no hardcoded hex values or one-off radii. Used by the composer rewrite in the next task. canDelete prop lets the caller block the last delete so the composer can never end up with zero messages. Signed-off-by: gaurav0107 <gauravdubey0107@gmail.com>
Replaces the rawMode/rawTemplate dichotomy with a single messages: Message[] state. The prompt panel renders one MessageEditor per turn (reorder, delete, role pill, content textarea) plus an + Add message button. Variable detection runs across all messages and dedupes the union into the Inputs panel. The Run payload sends raw_messages when no version is loaded, or prompt_version_id when a saved version is loaded - Plan B's api accepts both shapes during the back-compat window. Loading a saved version replaces the editable messages and pins loadedVersionId so the run goes through the catalog path; an Unload button detaches without resetting the composer. Save is wired in the next task. Typecheck + lint clean. Signed-off-by: gaurav0107 <gauravdubey0107@gmail.com>
Two paths:
- Loaded version: POST /v1/prompts/{id}/versions with the current
messages. Plan B's api short-circuits identical messages and returns
the existing row (HTTP 200) - re-saving an unchanged composer is a
cheap no-op. The composer pins loadedVersionId to the response id so
subsequent saves land as v2/v3/...
- No version loaded: open the inline name+slug form (slug auto-derived
from name with override). On submit: create the prompt, post v1, and
switch the composer to the loaded state.
The Save button sits in the prompt panel header next to Load/Version
pickers. Errors render inline above the +Add message button. The
canSave gate requires non-empty messages and no in-flight save or run.
The proxy routes /api/prompts and /api/prompts/{id}/versions already
exist - no new server code needed.
Signed-off-by: gaurav0107 <gauravdubey0107@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Plan C, the user-visible half of the playground messages redesign.
The composer now edits a list of typed messages (system + human),
detects `{{ var }}` substitutions across all messages and dedupes
them into the Inputs panel, and saves the result as a versioned
prompt.
Companion to PRs #11 (Plan A — schema) and #12 (Plan B — api).
What changed
PromptOptiontype carriestemplate_messages: Message[]alongside the legacytemplatestring. The page mapper falls back to wrapping legacy template as a single human message during a deploy gap.extractVariablesFromMessagesdedupes{{ var }}matches across the union, preserves first-seen order.<MessageEditor>— per-message card with role pill + dropdown, content textarea (auto-grows on newlines), reorder ↑/↓, delete ×. Uses design tokens (no hardcoded hex / radii).messages: Message[]state replacesrawMode/rawTemplate. The prompt panel renders one editor per turn plus an "+ Add message" button. Run sendsraw_messages(orprompt_version_idwhen a saved version is loaded).<SavePromptForm>(inline name+slug, slug auto-derived). Two paths: existing prompt → POST/v1/prompts/{id}/versions(api short-circuits identical bodies at HTTP 200); new prompt → POST/v1/promptsthen v1, switch to loaded state. An Unload button detaches a loaded version without resetting the composer.Files
web/src/components/playground/MessageEditor.tsx— per-message cardweb/src/components/playground/SavePromptForm.tsx— inline name+slugweb/src/components/PlaygroundClient.tsx— composer rewrite + save wiringweb/src/app/playground/page.tsx—PromptOptionmapper carriestemplate_messagesTest plan
Out of scope
Compare mode (two prompt panels) — deferred per spec decision 4. Single prompt only. The existing `mode` toggle and `modelB` machinery is left in place for that follow-up.
Companion docs
🤖 Generated with Claude Code