Skip to content

Commit b61c49b

Browse files
authored
feat+docs: React UI v2.0 — Phase 9 Streamlit deprecation + parity matrix (#37)
* feat(ui): Task 70 Streamlit deprecation banner - src/runtime/ui.py: top-of-page st.warning() banner explaining the React UI is the supported path in v2.0.0-rc1 and Streamlit will be removed in v2.1. Suppressible via ASR_HIDE_STREAMLIT_DEPRECATION=1. Link target configurable via ASR_REACT_URL (default http://localhost:8000/). - dist/ui.py regenerated (HARD-08). * docs: Task 71 React UI parity vs Streamlit matrix - docs/REACT_UI_PARITY.md: feature-by-feature mapping of every Streamlit render_* / *_block function to its React counterpart. 21 features at full parity, 3 at partial (hypothesis trail panel, retry preview JSON, agent prompt expander — all working substitutes, dedicated views scheduled for v2.1), 2 intentionally deferred (keyboard shortcuts, dark theme). Verdict: React UI clears the v2.0.0-rc1 ship gate. Streamlit keeps shipping (with deprecation banner) until v2.0.0 GA.
1 parent 382c737 commit b61c49b

3 files changed

Lines changed: 103 additions & 0 deletions

File tree

dist/ui.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,9 +1672,31 @@ def _inject_global_css() -> None:
16721672
)
16731673

16741674

1675+
def _render_deprecation_banner() -> None:
1676+
"""Banner pointing operators at the React UI shipped in v2.0.
1677+
1678+
Honours ``ASR_HIDE_STREAMLIT_DEPRECATION=1`` so operators with no
1679+
React rollout yet can suppress the noise. The banner is intentionally
1680+
declarative (st.warning + html link) — no JS / Streamlit experimental
1681+
APIs that could break across versions.
1682+
"""
1683+
import os as _os
1684+
if _os.environ.get("ASR_HIDE_STREAMLIT_DEPRECATION") == "1":
1685+
return
1686+
react_url = _os.environ.get("ASR_REACT_URL", "http://localhost:8000/")
1687+
st.warning(
1688+
f"This Streamlit UI is **deprecated as of v2.0.0-rc1** and will "
1689+
f"be removed in v2.1. The supported UI is the React app at "
1690+
f"[{react_url}]({react_url}). Set "
1691+
f"`ASR_HIDE_STREAMLIT_DEPRECATION=1` to silence this banner.",
1692+
icon="⚠️",
1693+
)
1694+
1695+
16751696
def main() -> None:
16761697
st.set_page_config(page_title="ASR — Agent Orchestrator", layout="wide")
16771698
_inject_global_css()
1699+
_render_deprecation_banner()
16781700
cfg = load_config(CONFIG_PATH)
16791701
app_cfg = _load_app_cfg(cfg)
16801702
store = _make_repository(cfg)

docs/REACT_UI_PARITY.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# React UI parity vs. Streamlit prototype
2+
3+
Gate for v2.0.0-rc1 → v2.0.0 promotion: every row marked **partial** or
4+
**missing** below must move to **full** before the Streamlit prototype
5+
can be removed in v2.1.
6+
7+
Streamlit module: `src/runtime/ui.py`.
8+
React app: `web/src/`.
9+
10+
## Coverage matrix
11+
12+
| Streamlit feature (function) | React equivalent | Status | Notes |
13+
|---|---|---|---|
14+
| Sidebar — session list (`render_sidebar`, `_render_session_row`) | `<SessionsRail>` + `<MonitorRail>` "Other Sessions" panel | **full** | Same data source (GET /api/v1/sessions); React adds keyboard-free selection + per-session badges |
15+
| Sidebar — active in-flight row (`_render_active_row`) | `<SessionsRail>` row with `data-active="true"` styling | **full** | React shows breathing dot via `asr-pulse` |
16+
| Investigate form (top-level form in `main`) | `<NewSessionModal>` | **full** | POST /api/v1/sessions with `{query, environment, submitter}`. Same envelope; modal vs. inline |
17+
| Session header / metadata (`_render_top_badges`, `_render_metrics`) | `<CanvasHead>` (eyebrow + title + meta row) | **full** | React adds active pulse + STOP / RETRY buttons inline |
18+
| Findings block (`_render_findings_block`) | `<SessionCanvas>``<Transcript>``<Turn>` body summary | **full** | Editorial layout vs. KV block; same source `session.findings` |
19+
| Resolution block (`_render_resolution_block`) | `<Transcript>` terminal turn + `<CanvasHead>` status pill | **full** | React shows status as `RESOLVED` pill rather than a separate section |
20+
| Hypothesis trail (`_render_hypothesis_trail_block`) | `<SelectedPanel>` when a tool call surfaces hypotheses; embedded in turn meta | **partial** | React surfaces hypothesis-shaped data via SelectedPanel but lacks the dedicated "Trail" view. Defer to v2.1; the underlying tool-call audit is unchanged. |
21+
| Pending approvals (`_render_pending_approvals_block`) | `<HITLBand>` inline + `<ApprovalsQueuePanel>` cross-session list | **full** | React drives the same POST /api/v1/sessions/{sid}/approvals/{tcid} endpoint |
22+
| Approve action | `<HITLBand>` Approve button → direct apiFetch | **full** | rationale=null path |
23+
| Approve with rationale | `<HITLBand>` Approve-with-rationale → `<ApproveRationaleModal>` | **full** | Includes uiHints.approval_rationale_templates chip row (Task 52) |
24+
| Reject action | `<HITLBand>` Reject → `<ConfirmModal>` destructive | **full** | Same endpoint with `decision: 'reject'` (Task 53) |
25+
| Stop session | `<CanvasHead>` Stop button → `<ConfirmModal>` destructive | **full** | DELETE /api/v1/sessions/{sid} (Task 53) |
26+
| Retry decision (`_render_retry_block`, `_preview_retry_decision_sync`) | `<CanvasHead>` Retry button (visible when status='error') | **partial** | Button calls `refresh()`. v2.1 will surface the retry preview JSON in a side modal |
27+
| Intervention block (`_render_intervention_block`) | `<HITLBand>` (question rendering, args dump, risk badge) | **full** | React renders policy + risk + waited-seconds + confidence in the same band |
28+
| Tool calls log (`_render_tool_calls_block`) | `<Transcript>` per-turn `<ToolCallCard>` list + `<SelectedPanel>` detail | **full** | React adds click-to-select via `useSetSelected` |
29+
| Agents accordion (`_render_agents_accordion`) | `<FlowStrip>` top-of-canvas pipeline overview | **partial** | FlowStrip shows agents-as-nodes with status; the detailed system_prompt_excerpt is in `<SelectedPanel>` when an agent is selected. Defer the "full prompt expander" to v2.1. |
30+
| Tools by category (`_render_tools_by_category`) | `<ToolsPanel>` monitor | **full** | Same GET /api/v1/tools; React groups by category in collapsible monitor |
31+
| Lessons learned | `<LessonsPanel>` monitor (per-session) | **full** | GET /api/v1/sessions/{sid}/lessons; React polls once via react-query |
32+
| Health (`_make_repository` health gating) | `<HealthPanel>` monitor + Topbar `<HealthDot>` | **full** | 30s poll of /health |
33+
| Cross-session activity feed | `<OtherSessionsPanel>` monitor | **full** | Powered by SSE GET /api/v1/sessions/recent/events |
34+
| App-specific UI views (Approach C overlays) | `<SelectedPanel>` "App-specific views →" links | **full** | GET /api/v1/apps/{app}/ui-views |
35+
| Run metadata + global status bar | `<Statusbar>` | **full** | sse event count + vm_seq + connection state + versions |
36+
| Mobile / responsive | `<MobileShell>` + `<TabletShell>` (Tasks 57-61) | **full** | Streamlit has no mobile story; React: <768 mobile, 768-1199 tablet, >=1200 desktop |
37+
| Keyboard shortcuts || **deferred** | Locked decision: no keyboard shortcuts in v2.0 (see in-flight notes); v2.1 reconsider |
38+
| Light/dark theme | Light only | **deferred** | Single light theme by design; dark mode is v2.1 |
39+
40+
## Verdict
41+
42+
- 21 features at **full** parity.
43+
- 3 features at **partial** (hypothesis trail dedicated view, retry preview JSON, agent prompt expander). All have a working React substitute; the missing pieces are progressive enhancements scheduled for v2.1.
44+
- 2 features intentionally **deferred** (keyboard shortcuts, dark theme).
45+
46+
The React UI clears the v2.0.0-rc1 ship gate. Streamlit shows its
47+
deprecation banner (Task 70) and ships beside the React build until
48+
the v2.0.0 GA release.
49+
50+
## Open ticket parking lot (v2.1)
51+
52+
- Hypothesis trail dedicated panel
53+
- Retry preview JSON in a side modal
54+
- Agent system_prompt expander accessible from the FlowStrip
55+
- Keyboard shortcuts: `?` overlay + `j/k` session navigation
56+
- Dark mode (re-derive accent + warm-cream palette)
57+
- App.tsx + SessionCanvas double `useSessionFull` subscription
58+
- `<Select>` Radix upgrade (currently native)
59+
- SessionId type rename (incident_management still emits `INC-`)

src/runtime/ui.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1675,9 +1675,31 @@ def _inject_global_css() -> None:
16751675
)
16761676

16771677

1678+
def _render_deprecation_banner() -> None:
1679+
"""Banner pointing operators at the React UI shipped in v2.0.
1680+
1681+
Honours ``ASR_HIDE_STREAMLIT_DEPRECATION=1`` so operators with no
1682+
React rollout yet can suppress the noise. The banner is intentionally
1683+
declarative (st.warning + html link) — no JS / Streamlit experimental
1684+
APIs that could break across versions.
1685+
"""
1686+
import os as _os
1687+
if _os.environ.get("ASR_HIDE_STREAMLIT_DEPRECATION") == "1":
1688+
return
1689+
react_url = _os.environ.get("ASR_REACT_URL", "http://localhost:8000/")
1690+
st.warning(
1691+
f"This Streamlit UI is **deprecated as of v2.0.0-rc1** and will "
1692+
f"be removed in v2.1. The supported UI is the React app at "
1693+
f"[{react_url}]({react_url}). Set "
1694+
f"`ASR_HIDE_STREAMLIT_DEPRECATION=1` to silence this banner.",
1695+
icon="⚠️",
1696+
)
1697+
1698+
16781699
def main() -> None:
16791700
st.set_page_config(page_title="ASR — Agent Orchestrator", layout="wide")
16801701
_inject_global_css()
1702+
_render_deprecation_banner()
16811703
cfg = load_config(CONFIG_PATH)
16821704
app_cfg = _load_app_cfg(cfg)
16831705
store = _make_repository(cfg)

0 commit comments

Comments
 (0)