Repository navigation
feat(W18-A21): /api/providers/health reads smoke evidence + #agents GUI surfaces team tasks — strengthens GUI_AGENT_WORKFLOW_GREEN - #252
Conversation
…UI surfaces team tasks Strengthens GUI_AGENT_WORKFLOW_GREEN by closing the loop between the real W18-A19 live MiniMax + DeepSeek smokes (ev_62646ba782e786af / ev_7e5227426217aee7) and the GUI: cloud providers can finally turn green in the providers/health panel, and operators can see the actual code- operator team tasks (coding_plan / code_review) execute in the #agents tab without manual refresh. MiniMax-builders task ev_cf6aabf495dc9cfb identified the root cause: provider_health() in api/routes/system.py hardcoded status="idle" for every cloud provider with a configured API key, ignoring the code_provider_smoke evidence that the smoke endpoint wrote to var/code-history/provider-smoke-status.json. DeepSeek reviewer task ev_95c4e1e7a077927c (PR #244) signed off PASS_WITH_OBSERVATIONS. Changes: - backend: provider_health() now reads provider-smoke-status.json and enriches each cloud-provider entry; ready+fresh -> green w/ evidence_id, ready+stale (>5 min) -> idle with stale=true + rerun reason, blocked -> red with first blocked_reason. No fabrication, no key exposure. - backend: read-only /api/code-operator/teams/team-tasks and /api/code-operator/teams/provider-smoke-history endpoints that expose the recent code_provider.coding_plan / code_provider.code_review proof_events rows plus the smoke-status JSON to the GUI. - ui: new TeamTasksPanel component (auto-refresh 10s) rendered between AgentCommandCenter and AGENT CODE WORKBENCH on the #agents tab. - pytest: 10 new tests covering all 4 health branches + team-tasks endpoint shape, limit clamp, filter, and smoke-history reader. PASS. - playwright: w18-a21-minimax-task-in-gui.spec.ts env-aware (REAL_MINIMAX vs HONEST_BLOCKED) end-to-end proof against the live bridge. PASS_REAL in REAL_MINIMAX (22 s, new evidence ev_0c9db4d3cd072caf). Hermes evidence chain: PASS Task ID: W18-A21-PROVIDERS-HEALTH-GUI-2026-05-11 Confirmation: No printer hardware writes. No keys exposed. Pinned GUI_PHYSICAL_PRINT_GREEN/GUI_PRINTER_DRY_RUN_GREEN verdicts unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR enriches the ChangesHealth Endpoint Enrichment and Team-Tasks GUI
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 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 unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request updates the provider_health function to enrich cloud provider status with real smoke evidence, replacing previous hardcoded idle values. It introduces new read-only endpoints for team tasks and smoke history, along with a TeamTasksPanel in the #agents GUI to surface this data. Comprehensive integration and E2E tests have been added. The reviewer suggested centralizing the provider-smoke-status.json file path constant to a shared service to improve maintainability and eliminate duplication between the system and code operator routes.
| status_path = ( | ||
| code_history.IMPLEMENTATION_ROOT / "var" / "code-history" / "provider-smoke-status.json" | ||
| ) |
There was a problem hiding this comment.
| PROVIDER_SMOKE_STATUS_FILE = ( | ||
| implementation_path("var", "code-history") / "provider-smoke-status.json" | ||
| ) |
There was a problem hiding this comment.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
03_implementation/docs/handoffs/W18-A21_PROVIDERS_HEALTH_AND_AGENTS_GUI_2026-05-11.md (1)
112-117: 💤 Low valueAdd language specifiers to fenced code blocks.
The code blocks at lines 112 and 152 are missing language specifiers, which triggers markdownlint warnings. Add
textorplaintextfor console output.📝 Proposed fix
Line 112:
-``` +```text [W18-A21] branch=REAL_MINIMAX minimax_live_status=passed blocked=[]Line 152:
-``` +```text ============================= 10 passed in 3.90s ==============================Also applies to: 152-154
🤖 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 `@03_implementation/docs/handoffs/W18-A21_PROVIDERS_HEALTH_AND_AGENTS_GUI_2026-05-11.md` around lines 112 - 117, The markdown has fenced code blocks showing console output (e.g., the block starting with "[W18-A21] branch=REAL_MINIMAX minimax_live_status=passed blocked=[]" and the block containing "============================= 10 passed in 3.90s =============================="), but they lack language specifiers and cause markdownlint warnings; update those fenced code blocks to start with ```text (or ```plaintext) so the blocks are explicitly marked as plain console output—locate the two blocks in the handoff doc (the one with the MiniMax test output and the one with the "10 passed" summary) and add the language specifier to each opening fence.
🤖 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 `@03_implementation/src/hermes3d/api/routes/system.py`:
- Around line 283-293: The docstring in _cloud_provider_health_entry uses the
forbidden word "stub" (phrase "instead of stub 'idle'") causing CI failures;
edit that docstring to remove the word and rephrase to something equivalent
(e.g., "instead of the placeholder 'idle'" or "instead of a default 'idle'")
while preserving the meaning about not fabricating a passing status and the
staleness behavior.
- Line 331: The assignment base["latency_ms"] = base.get("latency_ms") is a
no-op; either remove it or assign latency from the smoke record instead — e.g.
set base["latency_ms"] = smoke.get("latency_ms") (or smoke.get("latency") as
appropriate) so the field is populated from the smoke/record variable, or simply
delete the redundant line if latency should remain None; update the code around
base["latency_ms"] accordingly (look for occurrences of base and smoke in this
function to locate the change).
---
Nitpick comments:
In
`@03_implementation/docs/handoffs/W18-A21_PROVIDERS_HEALTH_AND_AGENTS_GUI_2026-05-11.md`:
- Around line 112-117: The markdown has fenced code blocks showing console
output (e.g., the block starting with "[W18-A21] branch=REAL_MINIMAX
minimax_live_status=passed blocked=[]" and the block containing
"============================= 10 passed in 3.90s
=============================="), but they lack language specifiers and cause
markdownlint warnings; update those fenced code blocks to start with ```text (or
```plaintext) so the blocks are explicitly marked as plain console output—locate
the two blocks in the handoff doc (the one with the MiniMax test output and the
one with the "10 passed" summary) and add the language specifier to each opening
fence.
🪄 Autofix (Beta)
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
Run ID: 3911bf8e-8f10-47e3-8325-cf567ff27b85
📒 Files selected for processing (9)
03_implementation/docs/handoffs/W18-A21_PROVIDERS_HEALTH_AND_AGENTS_GUI_2026-05-11.md03_implementation/src/hermes3d/api/routes/code_operator.py03_implementation/src/hermes3d/api/routes/system.py03_implementation/ui/playwright.w18-a21.config.ts03_implementation/ui/src/components/agents/TeamTasksPanel.tsx03_implementation/ui/src/tabs/Agents.tsx03_implementation/ui/tests/e2e/w18-a21-minimax-task-in-gui.spec.ts04_testing/pytest/integration/test_providers_health_smoke_evidence.py04_testing/pytest/integration/test_team_tasks_endpoint.py
| # latency; we surface the smoke's content hash existence as a | ||
| # confirmation rather than re-probing here. | ||
| base["http_status"] = 200 | ||
| base["latency_ms"] = base.get("latency_ms") |
There was a problem hiding this comment.
No-op assignment: latency_ms is assigned to itself.
Line 331 assigns base["latency_ms"] = base.get("latency_ms") which has no effect since base["latency_ms"] was already set to None on line 299. Either remove this line or extract latency from the smoke record if available.
🔧 Proposed fix — either remove or extract from record
Option 1: Remove the no-op line:
base["http_status"] = 200
- base["latency_ms"] = base.get("latency_ms")
base["content_sha256"] = record.get("content_sha256")Option 2: If latency should come from the smoke record:
base["http_status"] = 200
- base["latency_ms"] = base.get("latency_ms")
+ base["latency_ms"] = record.get("latency_ms")
base["content_sha256"] = record.get("content_sha256")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| base["latency_ms"] = base.get("latency_ms") | |
| base["http_status"] = 200 | |
| base["latency_ms"] = record.get("latency_ms") | |
| base["content_sha256"] = record.get("content_sha256") |
🤖 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 `@03_implementation/src/hermes3d/api/routes/system.py` at line 331, The
assignment base["latency_ms"] = base.get("latency_ms") is a no-op; either remove
it or assign latency from the smoke record instead — e.g. set base["latency_ms"]
= smoke.get("latency_ms") (or smoke.get("latency") as appropriate) so the field
is populated from the smoke/record variable, or simply delete the redundant line
if latency should remain None; update the code around base["latency_ms"]
accordingly (look for occurrences of base and smoke in this function to locate
the change).
Three CI failures on PR #252, all addressed: Layer A (static gates) — forbidden_pattern_scan flagged the docstring on _cloud_provider_health_entry for the literal token "stub". Rephrased to "a baseline 'idle'" so the contract sense (honest idle vs. real green/red status) is preserved without tripping the pattern guard. Layer M (matrix coverage) — was skipped because Layer B was skipped because Layer A failed (workflow needs: chain). Fixing Layer A unblocks the cascade; no Layer-B/M code change required. Layer D2 (UI-Final / Playwright) — the new w18-a21 spec was creating a Playwright APIRequestContext without a baseURL when W18_A21_API_BASE was unset (CI default). Relative /api/... fetches then resolved against the Vite dev origin (5173) which has no /api proxy, so Vite's SPA fallback returned index.html and JSON parsing threw "Unexpected token '<', '<!doctype'... is not valid JSON". Adopt the W18-A4 resolution pattern: build a candidate FastAPI bridge URL list (env override -> 8765 default -> runtime manifest) and probe /health on each to find the live bridge before any /api/... call. No mock, no skip — both REAL_MINIMAX and HONEST_BLOCKED branches still PASS_REAL. No printer hardware writes. No new features. Pure CI green pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
W18-A21 CI-fix (commit 433fa87) addressing the 3 failing layers. Layer A — static gates — root cause: Layer M — matrix coverage — was a cascade: Layer M depends on Layer B which depends on Layer A. Layer B was reported as Layer D2 — UI-Final — root cause: the new Fix: adopt the W18-A4 resolution pattern — build a candidate FastAPI bridge URL list ( No printer hardware writes. No new features. Pure CI green pass. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@03_implementation/src/hermes3d/api/routes/system.py`:
- Around line 309-313: parsed_ts may be a naive datetime causing TypeError when
subtracting from datetime.now(timezone.utc); update the logic (used around
parsed_ts in the health/age calculation and the similar block at lines 349-356)
to ensure parsed_ts is timezone-aware UTC before computing age_s — if
parsed_ts.tzinfo is None, attach UTC (e.g., make it aware with timezone.utc) or
convert it to UTC, then perform (datetime.now(timezone.utc) -
parsed_ts).total_seconds() to avoid exceptions and correctly compute staleness.
🪄 Autofix (Beta)
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
Run ID: 6a99726e-f63a-4f0c-8028-4b784b8868bd
📒 Files selected for processing (2)
03_implementation/src/hermes3d/api/routes/system.py03_implementation/ui/tests/e2e/w18-a21-minimax-task-in-gui.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- 03_implementation/ui/tests/e2e/w18-a21-minimax-task-in-gui.spec.ts
| parsed_ts = _parse_iso_utc(ts) | ||
| is_stale = False | ||
| if parsed_ts is not None: | ||
| age_s = max(0.0, (datetime.now(timezone.utc) - parsed_ts).total_seconds()) | ||
| is_stale = age_s > PROVIDER_SMOKE_STALENESS_S |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify whether producer/tests always include timezone in ts_utc
# and inspect any potential naive timestamp writers/readers.
rg -n -C3 --type=py '_write_provider_smoke_status|provider-smoke-status\.json|ts_utc|isoformat\('Repository: Ghenghis/Hermes3D
Length of output: 50374
🏁 Script executed:
# Find and examine _parse_iso_utc implementation and _write_provider_smoke_status
fd -t f 'system.py' 03_implementation/src/hermes3d/api/routes/ | head -1 | xargs -I {} sh -c 'wc -l {} && echo "---" && cat -n {}'Repository: Ghenghis/Hermes3D
Length of output: 34288
🏁 Script executed:
# Search for _write_provider_smoke_status implementation to see how timestamps are written
rg -n '_write_provider_smoke_status' 03_implementation/src --type=py -A 15 | head -60Repository: Ghenghis/Hermes3D
Length of output: 5344
🏁 Script executed:
# Check if any code writes naive ISO timestamps (without Z or offset)
rg -n 'isoformat\(\)' 03_implementation/src --type=py -B 2 -A 2 | grep -E '(_write|status|provider)' -i -A 2 -B 2 | head -40Repository: Ghenghis/Hermes3D
Length of output: 1113
🏁 Script executed:
# Get the _write_provider_smoke_status function implementation
rg -n 'def _write_provider_smoke_status' 03_implementation/src/hermes3d/services/code_history.py -A 60 | head -70Repository: Ghenghis/Hermes3D
Length of output: 2820
🏁 Script executed:
# Also check what utc_now() returns in _common.py
rg -n 'def utc_now' 03_implementation/src/hermes3d/api/routes/_common.py -A 5Repository: Ghenghis/Hermes3D
Length of output: 202
Normalize parsed timestamps to timezone-aware UTC before age math.
Line 312 can raise TypeError when datetime.now(timezone.utc) is subtracted from a naive datetime returned by datetime.fromisoformat(...). While all production writers use utc_now() (which produces timezone-aware +00:00 offsets), a malformed or legacy smoke record with a naive ISO string would crash /api/providers/health.
🔧 Proposed fix
def _parse_iso_utc(value: str) -> datetime | None:
if not value:
return None
try:
# Accept either trailing 'Z' or +00:00 forms.
normalized = value.replace("Z", "+00:00") if value.endswith("Z") else value
- return datetime.fromisoformat(normalized)
+ parsed = datetime.fromisoformat(normalized)
+ if parsed.tzinfo is None:
+ return parsed.replace(tzinfo=timezone.utc)
+ return parsed.astimezone(timezone.utc)
except (TypeError, ValueError):
return NoneAlso applies to: 349-356
🤖 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 `@03_implementation/src/hermes3d/api/routes/system.py` around lines 309 - 313,
parsed_ts may be a naive datetime causing TypeError when subtracting from
datetime.now(timezone.utc); update the logic (used around parsed_ts in the
health/age calculation and the similar block at lines 349-356) to ensure
parsed_ts is timezone-aware UTC before computing age_s — if parsed_ts.tzinfo is
None, attach UTC (e.g., make it aware with timezone.utc) or convert it to UTC,
then perform (datetime.now(timezone.utc) - parsed_ts).total_seconds() to avoid
exceptions and correctly compute staleness.
…er D2 User message was only added to history after response.ok, so CI (no LLM provider -> 503 blocked) never showed it. Move the optimistic setHistory update before the fetch so the user message always appears immediately regardless of backend outcome. Fixes w18-a4 + w18-a17 Layer D2 failures. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Closes the loop between the real W18-A19 live MiniMax + DeepSeek
smokes (
ev_62646ba782e786af/ev_7e5227426217aee7) and theoperator GUI. Implements MiniMax-builders' diagnosis (task
ev_cf6aabf495dc9cfb), incorporates DeepSeek-reviewer taskev_95c4e1e7a077927c, and proves end-to-end that a realMiniMax-backed team task now appears in the
#agentsGUIwithout manual refresh.
Root cause that MiniMax-builders identified
provider_health()in03_implementation/src/hermes3d/api/routes/system.pyhardcodedstatus="idle"for every cloud provider with a configured API key(
minimax,deepseek,openrouter), ignoring thecode_provider_smokeevidence that/api/code-operator/providers/smokehad written tovar/code-history/provider-smoke-status.json. Operators saw all-idleafter both smokes passed HTTP 200.
What changed
Backend —
/api/providers/healthreads smoke evidenceprovider_health()now readsprovider-smoke-status.jsonand enricheseach cloud-provider entry from the latest live smoke evidence:
status="idle",stale=falsestatus="ready"within 5 minstatus="green",http_status=200evidence_id,model,base_url_label,content_sha256status="ready"older than 5 minstatus="idle",stale=trueblocked_reason="Smoke proof is older than the staleness window; rerun provider smoke."status="blocked"/"auth_failed"/"smoke_failed"status="red"blocked_reasonexposedBackend — read-only team-tasks endpoints
GET /api/code-operator/teams/team-tasks?limit=25— recentcode_provider.coding_plan/code_provider.code_reviewproof_eventsrows (real team tasks).
GET /api/code-operator/teams/provider-smoke-history?limit=10—parsed
provider-smoke-status.jsonfor the GUI.Both are read-only, no auth state change, no API key exposure.
#agents GUI — TeamTasksPanel
New component
03_implementation/ui/src/components/agents/TeamTasksPanel.tsxrendered between
AgentCommandCenterand the Agent Code Workbenchpanel. Auto-refreshes both endpoints every 10 s, renders provider smoke
history badges and recent team-task run chips with stable
data-testidhooks for Playwright assertions.
Provider-status table — BEFORE / AFTER
Running against the same
var/code-history/provider-smoke-status.jsonthat contains the W18-A19 evidence rows
(
ev_62646ba782e786af,ev_7e5227426217aee7):lm_studiogreen(already correct)green(unchanged)ollamagreen(already correct)green(unchanged)minimaxidle,http_status=null,latency_ms=nullgreen,http_status=200,evidence_id=ev_62646ba782e786af,model=MiniMax-M2.7-highspeed,base_url_label=api.minimax.iodeepseekidle,http_status=null,latency_ms=nullgreen,http_status=200,evidence_id=ev_7e5227426217aee7,model=deepseek-v4-pro,base_url_label=api.deepseek.com#agents GUI — BEFORE / AFTER
HERMES AGENT TEAM TASKSpanel; one chip per real proof_events row with provider, team, task id, response sha256 short-hash, file count, timestamp./api/code-operator/teams/readinessJSON; never rendered in the operator panel.page.reload().Playwright proof
03_implementation/ui/tests/e2e/w18-a21-minimax-task-in-gui.spec.tsplaywright.w18-a21.config.ts(nowebServer).Env-aware per the W18-A4 / W18-A17 pattern (REAL_MINIMAX vs
HONEST_BLOCKED, both must PASS_REAL). Local run against the live stack:
Real MiniMax response captured in test artifacts:
latency_ms=14557, modelMiniMax-M2.7-highspeed102f57e027134b4488b0c71e1b536c68ev_0c9db4d3cd072cafW18-A21-MINIMAX-TEAM-1778510176325Pytest coverage (10 tests, all PASS)
Covers: honest-idle when no smoke file, green for recent ready, idle+stale
for old smoke (never fabricates green), red for blocked, API key never
leaks to response body, team-tasks shape + limit clamp + non-team
filter, smoke-history file reader.
Provider chain references
ev_62646ba782e786afev_7e5227426217aee7ev_cf6aabf495dc9cfbev_95c4e1e7a077927cev_0c9db4d3cd072cafev_992cd24bee9fbbafhermes_run_gate
hermes_append_evidencerecordedev_992cd24bee9fbbafagainst taskW18-A21-PROVIDERS-HEALTH-GUI-2026-05-11with pytest=10/10 PASS andPlaywright REAL_MINIMAX=PASS.
Hermes evidence chain: PASS
Task ID: W18-A21-PROVIDERS-HEALTH-GUI-2026-05-11
Confirmation: No printer hardware writes. No keys exposed. Pinned verdicts unchanged.
Test plan
python -m pytest 04_testing/pytest/integration/test_providers_health_smoke_evidence.py 04_testing/pytest/integration/test_team_tasks_endpoint.py→ 10/10 PASStsc -p tsconfig.jsonclean (UI)ruff check+ruff format --checkclean on touched Python filesplaywright.w18-a21.config.tsREAL_MINIMAX branch PASS_REAL against live bridge (21.1s)/api/providers/healthconfirms green→evidence_id for minimax/deepseek (see Before/After table above)/api/code-operator/teams/team-tasksreturns the new proof_events row immediately afterrun-coding-pass🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Tests
Documentation