"""Pure rendering of agent events to HTML, plus the session run-cap check.""" import html as _html import json from agent import config TIMELINE_CSS = """ :root { --bg:#0b0f14; --card:#121821; --line:#1e2733; --fg:#cfd8e3; --muted:#7d8a99; --cyan:#39d3ee; --green:#37e0a6; --amber:#f0b35e; } .gradio-container { background: var(--bg) !important; } #oa-timeline { font-family: ui-monospace, "JetBrains Mono", Menlo, Consolas, monospace; display:flex; flex-direction:column; gap:10px; } .oa-card { background:var(--card); border:1px solid var(--line); border-left:3px solid var(--line); border-radius:8px; padding:10px 14px; color:var(--fg); } .oa-card .oa-head { font-size:12px; letter-spacing:.04em; color:var(--muted); margin-bottom:4px; } .oa-thought { border-left-color: var(--cyan); } .oa-revision { border-left-color: var(--amber); background:#1a1710; } .oa-tool_call { border-left-color: var(--green); } .oa-observation { border-left-color:#2b3a4a; } .oa-observation.oa-weak { border-left-color: var(--amber); opacity:.92; } .oa-final { border-left-color: var(--green); background:#0f1a16; font-size:15px; } .oa-status { color:var(--muted); font-style:italic; } .oa-args, .oa-obs { white-space:pre-wrap; word-break:break-word; margin-top:4px; } #oa-stats { color:var(--muted); font-family: ui-monospace, monospace; margin-top:6px; } """ _ICON = {"thought": "๐ง ", "tool_call": "๐ง", "observation": "๐", "final": "โ ", "limit": "โ"} def _esc(text) -> str: return _html.escape(str(text)) def render_event(event) -> str: kind = event["kind"] step = event.get("step", "") if kind == "thought": revision = event.get("revision", False) icon = "โป" if revision else _ICON["thought"] label = "revision" if revision else "thought" cls = "oa-thought oa-revision" if revision else "oa-thought" return (f'