feat: Display eval prompt in dashboard task detail (#526) - #543
feat: Display eval prompt in dashboard task detail (#526)#543Shayne Boyer (spboyer) wants to merge 2 commits into
Conversation
- Add optional prompt field to internal TaskResult model - Capture prompt in orchestration runner context - Expose prompt through webapi store and REST endpoints - Extend TypeScript API client with prompt field in TaskResult interface This implementation focuses on the data model and API layer changes needed to support displaying eval prompts in the dashboard. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Adds a note to the README dashboard views and the site dashboard guide explaining that the eval prompt is now visible in expanded task rows, with a copy-to-clipboard button and collapsible follow-ups. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds first-class support for capturing and surfacing the resolved eval prompt (plus prompt source path and follow-up prompts) in run results and the dashboard, addressing issue #526 by letting the UI display what instruction(s) the agent actually received.
Changes:
- Extend the Go results model (
TestOutcome) and runner to recordprompt,prompt_file, andfollow_upsper task. - Expose these new fields through the web API layer and validate mapping via a new unit test.
- Update the web dashboard (and TS API types) to render a prompt panel with copy-to-clipboard and follow-up prompt display.
Show a summary per file
| File | Description |
|---|---|
internal/models/outcome.go |
Adds prompt/prompt_file/follow_ups fields to the persisted task outcome model. |
internal/orchestration/runner.go |
Attempts to populate the new prompt-related fields when producing TestOutcome. |
internal/webapi/types.go |
Extends API TaskResult response shape to include prompt data. |
internal/webapi/store.go |
Maps the new model fields into the API response payload. |
internal/webapi/additional_test.go |
Adds a unit test to ensure prompt fields are mapped into API output. |
web/src/api/client.ts |
Updates the TypeScript TaskResult interface with prompt fields. |
web/src/components/RunDetail.tsx |
Adds a new prompt panel UI within expanded task rows (copy + follow-ups). |
web/dist/index.html |
Updates hashed bundle references in the tracked index.html. |
Review details
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Files reviewed: 9/10 changed files
- Comments generated: 1
- Review effort level: Lite
| Prompt: tc.Stimulus.Message, | ||
| PromptFile: tc.Stimulus.MessageFile, | ||
| FollowUps: tc.Stimulus.FollowUps, |
There was a problem hiding this comment.
Review details
Suppressed comments (6)
Previously missed (1) — in code that hasn't changed since the last review.
web/src/components/RunDetail.tsx:183
- This table contains expanded grader rows with 6 cells (GraderRow), so the table effectively has 6 columns. Using colSpan={5} here leaves an extra blank column and can cause the prompt panel background/borders to misalign with the grader detail rows.
This issue also appears in the following locations of the same file:
- line 192
- line 202
<td colSpan={5} className="px-12 py-3 text-xs italic text-zinc-500">
internal/orchestration/runner.go:845
- PromptFile is being populated from tc.Stimulus.MessageFile, but TaskStimulus.resolvePromptFile clears MessageFile after loading the file (internal/models/testcase.go:566). As a result, tasks that used prompt_file will always end up with an empty PromptFile in results.json, so the dashboard can’t show the source path.
outcomes = append(outcomes, models.TestOutcome{
TestID: tc.TestID,
DisplayName: tc.DisplayName,
Golden: tc.Golden,
Status: models.StatusFailed,
Prompt: tc.Stimulus.Message,
PromptFile: tc.Stimulus.MessageFile,
FollowUps: tc.Stimulus.FollowUps,
internal/orchestration/runner.go:936
- PromptFile is being populated from test.Stimulus.MessageFile, but TaskStimulus.resolvePromptFile clears MessageFile after loading the file (internal/models/testcase.go:566). This means PromptFile will be empty for prompt_file tasks, so the API/UI won’t be able to display the source path.
resultChan <- result{index: idx, outcome: models.TestOutcome{
TestID: test.TestID,
DisplayName: test.DisplayName,
Golden: test.Golden,
Status: models.StatusFailed,
Prompt: test.Stimulus.Message,
PromptFile: test.Stimulus.MessageFile,
FollowUps: test.Stimulus.FollowUps,
internal/orchestration/runner.go:1121
- PromptFile is being populated from tc.Stimulus.MessageFile, but prompt_file resolution clears MessageFile (internal/models/testcase.go:566). That makes PromptFile always empty for prompt_file tasks, so this won’t actually persist the source path into results.json.
Group: r.resolveGroup(),
Golden: tc.Golden,
Status: status,
Prompt: tc.Stimulus.Message,
PromptFile: tc.Stimulus.MessageFile,
FollowUps: tc.Stimulus.FollowUps,
web/src/components/RunDetail.tsx:196
- navigator.clipboard.writeText can throw or reject (e.g., insecure context, permissions denied). Right now this would create an unhandled rejection and leave the UI in an inconsistent state. Please guard for clipboard availability and add a .catch handler.
const handleCopy = () => {
if (!copyable) return;
void navigator.clipboard.writeText(copyable).then(() => {
setCopied(true);
window.setTimeout(() => setCopied(false), 1500);
web/src/components/RunDetail.tsx:202
- This prompt panel should span the full width of the expanded detail area. Because GraderRow renders 6 cells, the effective column count is 6; colSpan={5} can leave a trailing blank column and misaligned borders.
<td colSpan={5} className="px-12 py-3">
- Files reviewed: 9/10 changed files
- Comments generated: 0 new
- Review effort level: Lite
Closes #526
Summary
Adds the eval prompt used to run each task into the dashboard, alongside graders and outcome details.
Approach (Claude Opus 4.7)
End-to-end: persist the prompt in results JSON, expose it through the webapi, render an inline panel in the expanded task row on the dashboard.
Backend
internal/models/outcome.go—TestOutcomenow has optionalPrompt,PromptFile,FollowUpsfields (allomitempty, backward compatible with legacyresults.jsonfiles).internal/orchestration/runner.go— populates the new fields fromTestCase.Stimulusat the threeTestOutcomeconstruction sites: the mainrunTestUncachedreturn path, and both the sequential and concurrentbefore_taskhook-failure branches.internal/webapi/types.go+internal/webapi/store.go—TaskResultgainsprompt/promptFile/followUpsfields, andoutcomeToDetailforwards them.internal/webapi/additional_test.go— newTestOutcomeToDetailMapsPromptasserts prompt round-trips through the API and that legacy tasks without a prompt still work.Frontend
web/src/api/client.ts—TaskResultinterface extended with the optional prompt fields.web/src/components/RunDetail.tsx— newPromptPanelcomponent rendered above graders in the expanded task row:<pre>with wrapped/scrollable content, dark theme.navigator.clipboard, flips to aCheckicon for ~1.5s).prompt_filesource path when the prompt was loaded from a file.Docs
README.md— added the prompt panel to the dashboard views bullet list.site/src/content/docs/guides/dashboard.mdx— expanded the "Run Details" list with a description of the prompt panel.Verification
go fmt ./... && go test ./...— all packages pass.golangci-lint run— clean on our code (twoflatted/golang/pkggovet warnings live inweb/node_modules/, unrelated to this change).cd web && npm run build— TypeScript compiles, Vite build succeeds.cd web && npm run lint— clean.Design choices
<pre>, no syntax highlighting. YAML and Markdown prompts stay readable without adding a highlighter dependency; a future PR can layer highlighting on top.omitempty+ optional TS field. Olderresults.jsonfiles just render without the panel — no schema-version bump needed.Parallel approaches
This is one of two agent-generated implementations for #526. See the sibling GPT-5.5 PR for an alternative before merging.