Feat/dashboard collab and UI upgrades - #113
Conversation
…for every run, UI polish Three production fixes plus a feature upgrade for the Playwright Dashboard and the QA Office chat panel: - **Multi-agent collaboration** in /api/qa-agent: primary → critic → primary refine → Edi M synthesis. Auto-triggered when 2+ agents are tagged or the manager is mentioned. New SSE turn_start/turn_done/turn_verdict events produce a threaded conversation in chat, with colour-coded role pills. - **Run logs persisted** alongside each archived run; clicking an old run re-hydrates the dashboard log panel. archiveRun() now logs success/failure to the server console so silent archive failures are visible. - **Edi M summary now streams to chat for every Run Tests**, not just agent-generated dynamic runs. Phase 2 streamSummary() helper shared by /api/playwright/run and /api/run-dynamic-test. - **Dashboard UI/UX polish**: KPI hero with progress ring + verdict, pill subtitle row, history-chart hover tooltip + moving-average trend line, sticky suite headers with smooth chevron rotation, copy-error button, cropped QA Office canvas (no more "blue void" above the office). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- server: drop unnecessary \- escape in runId sanitiser regex - tests/sv-login: remove unused BASE_URL import - PlaywrightDashboard: replace ternary-as-statement with explicit if/else in the multi-spec picker onChange (no-unused-expressions) - OfficePage + PlaywrightDashboard: remove orphaned `eslint-disable-next-line react-hooks/exhaustive-deps` directives — the rule isn't registered in this project's ESLint config so the directive itself was reported as an error - PlaywrightDashboard: drop two unused `// eslint-disable-line` trailing comments flagged by no-unused-disable - README: mention multi-agent collab + persistent run history features so the docs-check script sees a docs update alongside the code change Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-format 115 files with Prettier to fix the failing format:check workflow step. Also removes the temporary PR_BODY.md file. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…, summary snapshot, types) - CHANGELOG: remove duplicate bullets (two entries appeared under both the unreleased ### Changed block and an orphaned second block) - runCollabTurn: accept and forward history + imageAttachments into startChat/sendMessageStream so collaborative turns preserve context and vision - capturedLog: switch from oldest-first cap to a sliding window (push + shift) so archiveRun and AI summaries always see the newest 5 000 lines - streamSummary: accept runId in SummaryCreds; reads the per-run immutable archive instead of the shared RESULTS_PATH to prevent concurrent-run clobbering - Both route close-handlers now capture archiveRun return value and pass runId to streamSummary - PlaywrightDashboard: define RunRequest and SummaryEvent types; runWithSSE typed as (body: RunRequest); evt typed as SummaryEvent | Record<string,unknown>; fetchResults always calls setRunLog (clears to [] when not an archived run) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-and-ui-upgrades # Conflicts: # CHANGELOG.md # server/index.ts # ui/src/pages/PlaywrightDashboard.tsx
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR adds per-run result isolation for Playwright/dynamic runs, forwards Gemini multi-agent chat history and images across specialist turns, introduces RunRequest/SummaryEvent typings, and revises docs/README/CHANGELOG content. ChangesPer-Run Archiving and Gemini Collaboration
Sequence DiagramsequenceDiagram
participant Client
participant PlayEndpoint as /api/playwright/run
participant ArchiveRun
participant StreamSummary
Client->>PlayEndpoint: POST run request (RunRequest)
PlayEndpoint->>ArchiveRun: archiveRun(logs, results)
ArchiveRun-->>PlayEndpoint: runId
PlayEndpoint->>StreamSummary: streamSummary(creds with runId)
StreamSummary->>StreamSummary: read RUNS_DIR/runId.json (if exists)
StreamSummary-->>Client: summary_start/summary_chunk/summary_done SSE
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Satisfies the docs-validation CI check that requires README.md to be updated alongside any server/ or ui/src/ changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@server/index.ts`:
- Around line 1267-1275: The archive path races because archiveRun() snapshots
the shared RESULTS_PATH (pw-results.json) rather than the per-run output used by
streamSummary; modify archiveRun, and any callers, to accept and archive a
per-run reporter output path derived from runId (e.g., pw-results-{runId}.json)
instead of reading the global RESULTS_PATH, and update streamSummary invocation
sites (where runId is passed) to also pass the same reporter path; ensure
functions/methods named archiveRun, streamSummary and any uses of RESULTS_PATH
are updated to use the per-run path so each run archives its own file
atomically.
- Around line 455-468: playTurn is only passing turnHistory and turnImages into
the initial runCollabTurn call, leaving the critic/refinement/synthesis steps
without chat or image context; update the calls to the downstream functions
(e.g., runCriticTurn, runRefinementTurn, runSynthesisTurn or whatever functions
invoke follow-up turns from playTurn) to accept and forward the same turnHistory
and turnImages parameters so every collaboration turn receives the original chat
history and image attachments; locate the follow-up calls inside playTurn and
add the turnHistory and turnImages arguments (and corresponding parameters on
those functions if needed) so image-based reviews and final synthesis run with
full context.
- Around line 489-490: Guard use of message before calling message.trim(): where
you construct userBlock from message.trim() (the collaboration flow and the
single-agent Ollama/Gemini paths that also call message.trim()), first check
that message is defined and contains non-whitespace (e.g., if (message &&
message.trim().length) ...) and only then build or append userBlock; otherwise
treat it as empty/omit user text so imageAttachments-only requests proceed
without throwing. Update the userBlock construction sites (references:
userBlock, message.trim(), imageAttachments, Ollama, Gemini) to use this guard
and ensure downstream code handles an empty userBlock gracefully.
🪄 Autofix (Beta)
❌ Autofix failed (check again to retry)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 5bd80155-dd57-4608-8750-c627d2297673
📒 Files selected for processing (4)
CHANGELOG.mdREADME.mdserver/index.tsui/src/pages/PlaywrightDashboard.tsx
💤 Files with no reviewable changes (1)
- CHANGELOG.md
| turnHistory?: HistoryItem[], | ||
| turnImages?: ImageAttachment[], | ||
| ): Promise<string> => { | ||
| send({ evt: 'turn_start', agentId: agent.id, agentName: agent.name, role, round, label }); | ||
| let full = ''; | ||
| try { | ||
| full = await runCollabTurn(apiKey!, model, systemPrompt, userPrompt, (txt) => | ||
| send({ chunk: txt }), | ||
| full = await runCollabTurn( | ||
| apiKey!, | ||
| model, | ||
| systemPrompt, | ||
| userPrompt, | ||
| (txt) => send({ chunk: txt }), | ||
| turnHistory, | ||
| turnImages, |
There was a problem hiding this comment.
Forward the original chat context to every collaboration turn.
playTurn can now carry turnHistory and turnImages, but only the initial primary call uses them. The critic, refinement, and synthesis turns still run without the user's prior chat or screenshots, so image-based reviews and the final synthesis are working from incomplete context.
Suggested fix
const critiqueText = await playTurn(
critic,
'critic',
round,
`Critique (round ${round})`,
critic.systemPrompt +
"\n\nYou are reviewing a peer's draft. Be specific, constructive, and decisive — your goal is to make the final answer the best it can be.",
- critiquePrompt,
+ critiquePrompt,
+ history,
+ imageAttachments,
);
@@
primaryAnswer = await playTurn(
primary,
'primary',
round + 1,
`Refined response (round ${round + 1})`,
primary.systemPrompt +
"\n\nYou are refining your previous draft based on peer feedback. Be focused — incorporate the feedback that's right, push back briefly on anything that's wrong, and produce a stronger answer.",
- refinePrompt,
+ refinePrompt,
+ history,
+ imageAttachments,
);
@@
await playTurn(
manager,
'synthesis',
rounds + 1,
'Final synthesis',
manager.systemPrompt +
"\n\nYou are delivering the team's final answer to the user. Be clear, decisive, and useful.",
- synthPrompt,
+ synthPrompt,
+ history,
+ imageAttachments,
);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@server/index.ts` around lines 455 - 468, playTurn is only passing turnHistory
and turnImages into the initial runCollabTurn call, leaving the
critic/refinement/synthesis steps without chat or image context; update the
calls to the downstream functions (e.g., runCriticTurn, runRefinementTurn,
runSynthesisTurn or whatever functions invoke follow-up turns from playTurn) to
accept and forward the same turnHistory and turnImages parameters so every
collaboration turn receives the original chat history and image attachments;
locate the follow-up calls inside playTurn and add the turnHistory and
turnImages arguments (and corresponding parameters on those functions if needed)
so image-based reviews and final synthesis run with full context.
| history, // forward chat history so prior context is preserved | ||
| imageAttachments, // forward image attachments so vision prompts work |
There was a problem hiding this comment.
Guard message before trimming in the new image-only flow.
The handler now accepts requests with only imageAttachments, but collaboration still builds userBlock from message.trim() on Line 479, and the single-agent Ollama/Gemini paths do the same on Lines 581 and 664. A screenshot-only prompt will throw before the vision request is sent.
Suggested fix
const {
message,
@@
collaborate = false,
maxRounds = 2,
} = req.body as QaAgentBody;
+ const promptText = message?.trim() ?? '';
@@
- if (!message?.trim() && imageAttachments.length === 0) {
+ if (!promptText && imageAttachments.length === 0) {
send({ error: 'Body field "message" is required.' });
res.end();
return;
}
@@
- const userBlock = `# User request\n${message.trim()}\n`;
+ const userBlock = `# User request\n${promptText}\n`;
@@
content:
- message.trim() ||
+ promptText ||
'(image attached — vision not supported by Ollama in this integration)',
@@
- if (message.trim()) parts.push({ text: message });
+ if (promptText) parts.push({ text: promptText });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@server/index.ts` around lines 489 - 490, Guard use of message before calling
message.trim(): where you construct userBlock from message.trim() (the
collaboration flow and the single-agent Ollama/Gemini paths that also call
message.trim()), first check that message is defined and contains non-whitespace
(e.g., if (message && message.trim().length) ...) and only then build or append
userBlock; otherwise treat it as empty/omit user text so imageAttachments-only
requests proceed without throwing. Update the userBlock construction sites
(references: userBlock, message.trim(), imageAttachments, Ollama, Gemini) to use
this guard and ensure downstream code handles an empty userBlock gracefully.
| await streamSummary(res, { | ||
| agentName, | ||
| apiKey, | ||
| model, | ||
| provider, | ||
| ollamaBaseUrl, | ||
| ollamaModel, | ||
| runId: runId ?? undefined, | ||
| }); |
There was a problem hiding this comment.
runId fixes the read side, but the archive still races on the shared results file.
Both endpoints now pass runId into streamSummary, but archiveRun() still snapshots the single RESULTS_PATH after the child exits. Two overlapping runs can therefore still archive whichever pw-results.json was written last, and the “immutable” summary/history will belong to the wrong run.
Use a per-run reporter output path (or serialize runs) and archive that file directly instead of reading the shared RESULTS_PATH.
Also applies to: 1348-1350, 1604-1612
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@server/index.ts` around lines 1267 - 1275, The archive path races because
archiveRun() snapshots the shared RESULTS_PATH (pw-results.json) rather than the
per-run output used by streamSummary; modify archiveRun, and any callers, to
accept and archive a per-run reporter output path derived from runId (e.g.,
pw-results-{runId}.json) instead of reading the global RESULTS_PATH, and update
streamSummary invocation sites (where runId is passed) to also pass the same
reporter path; ensure functions/methods named archiveRun, streamSummary and any
uses of RESULTS_PATH are updated to use the per-run path so each run archives
its own file atomically.
|
Note Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it. The branch was updated while autofix was in progress. Please try again. |
Rewrote all nine documentation sections in DocsPage to reflect the current project state. Replaced every Anthropic/Claude reference with Gemini/Ollama, updated the directory tree, rewrote the env-var section with dual-provider setup instructions, corrected the tech stack table, added FAQ entries for provider switching and multi-agent collaboration, and updated the roadmap to mark completed features as done. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Description
Fixes # (issue number)
Type of change
Checklist:
Summary by CodeRabbit
New Features
Bug Fixes
Documentation