mekosotto Claude Sonnet 4.6 commited on
Commit
4fc125d
·
1 Parent(s): 55d9d32

feat(frontend): Agent tab with decision-trace expander

Browse files

Add 6th "🤖 Agent" tab to the Streamlit UI that calls POST /agent/run,
renders the response text + model/finish_reason caption, and shows an
expandable decision-trace panel listing each tool call's name, args,
and result (or error). Also makes _post() timeout configurable via a
keyword arg (default 120 s) for backwards compatibility.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. src/frontend/app.py +53 -3
src/frontend/app.py CHANGED
@@ -935,9 +935,9 @@ def _check_api_health() -> tuple[bool, str]:
935
  return False, type(e).__name__.lower()
936
 
937
 
938
- def _post(endpoint: str, payload: dict) -> dict:
939
  """POST to the FastAPI surface; let httpx raise on non-2xx."""
940
- resp = httpx.post(f"{_API_URL}{endpoint}", json=payload, timeout=120.0)
941
  resp.raise_for_status()
942
  return resp.json()
943
 
@@ -1752,12 +1752,13 @@ def main() -> None:
1752
  "Run `uvicorn src.api.main:app --port 8000` or `docker compose up`."
1753
  )
1754
 
1755
- bbb_tab, eeg_tab, mri_tab, assistant_tab, experiments_tab = st.tabs([
1756
  "Molecule",
1757
  "Signal",
1758
  "Image",
1759
  "AI Assistant",
1760
  "Experiments",
 
1761
  ])
1762
 
1763
  with bbb_tab:
@@ -1771,6 +1772,55 @@ def main() -> None:
1771
  with experiments_tab:
1772
  _render_experiments_tab()
1773
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1774
 
1775
  if __name__ == "__main__":
1776
  main()
 
935
  return False, type(e).__name__.lower()
936
 
937
 
938
+ def _post(endpoint: str, payload: dict, timeout: float = 120.0) -> dict:
939
  """POST to the FastAPI surface; let httpx raise on non-2xx."""
940
+ resp = httpx.post(f"{_API_URL}{endpoint}", json=payload, timeout=timeout)
941
  resp.raise_for_status()
942
  return resp.json()
943
 
 
1752
  "Run `uvicorn src.api.main:app --port 8000` or `docker compose up`."
1753
  )
1754
 
1755
+ bbb_tab, eeg_tab, mri_tab, assistant_tab, experiments_tab, agent_tab = st.tabs([
1756
  "Molecule",
1757
  "Signal",
1758
  "Image",
1759
  "AI Assistant",
1760
  "Experiments",
1761
+ "🤖 Agent",
1762
  ])
1763
 
1764
  with bbb_tab:
 
1772
  with experiments_tab:
1773
  _render_experiments_tab()
1774
 
1775
+ with agent_tab:
1776
+ st.markdown("### Orchestrator Agent")
1777
+ st.caption(
1778
+ "Pick the pipeline automatically, run it, then ground the response "
1779
+ "in curated reference docs (RAG)."
1780
+ )
1781
+
1782
+ with st.form("agent_form"):
1783
+ agent_input = st.text_input(
1784
+ "Input",
1785
+ value="CCO",
1786
+ help="SMILES (e.g., CCO), .fif/.edf path, or NIfTI directory path",
1787
+ )
1788
+ agent_question = st.text_input(
1789
+ "Question (optional)",
1790
+ value="",
1791
+ help="Ask in any language — the agent will mirror it in the response",
1792
+ )
1793
+ submitted = st.form_submit_button("Run agent")
1794
+
1795
+ if submitted and agent_input:
1796
+ with st.spinner("Agent is reasoning..."):
1797
+ try:
1798
+ payload: dict = {"user_input": agent_input}
1799
+ if agent_question:
1800
+ payload["user_question"] = agent_question
1801
+ response = _post("/agent/run", payload, timeout=120.0)
1802
+ except Exception as e:
1803
+ st.error(f"Agent run failed: {e}")
1804
+ else:
1805
+ st.markdown("#### Response")
1806
+ st.write(response.get("text", ""))
1807
+ st.caption(
1808
+ f"model: `{response.get('model', '?')}` · "
1809
+ f"finish: `{response.get('finish_reason', '?')}`"
1810
+ )
1811
+ trace = response.get("trace", [])
1812
+ expander_title = f"🧠 Decision trace ({len(trace)} step{'s' if len(trace) != 1 else ''})"
1813
+ with st.expander(expander_title, expanded=True):
1814
+ if not trace:
1815
+ st.write("_(no tool calls)_")
1816
+ for i, step in enumerate(trace, start=1):
1817
+ st.markdown(f"**{i}. `{step['name']}`**")
1818
+ if step.get("error"):
1819
+ st.error(step["error"])
1820
+ else:
1821
+ st.json(step.get("args", {}))
1822
+ st.json(step.get("result", {}))
1823
+
1824
 
1825
  if __name__ == "__main__":
1826
  main()