Add mobile responsiveness and state diagram to Scenarios tab
Browse filesMobile fixes:
- Add CSS media queries (@media 900px, 600px) for padding, font sizes,
stat grid (6-col -> 3 -> 2), unique-grid (auto -> 1-col), metrics-bar
(4-col -> 2-col), table horizontal scroll
- Add class='hero-section', 'stat-grid-resp', 'unique-grid-resp' to
inline-styled divs so media queries can override with !important
- Benchmark table and arch code block wrapped in overflow-x:auto containers
- .table-wrap changed to overflow-x:auto for scenario tables on mobile
State diagram:
- New _state_diagram_html() function: 5-node flow diagram
(reset -> Phase1 -> Phase2 -> Phase3 -> done) with per-node reward
badges, state-after annotations, and transition labels
- Embedded <style> block makes diagram stack vertically on <=640px
- Added to top of Scenarios tab via _scenarios_html()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- app.py +137 -6
- server/app.py +137 -6
|
@@ -316,7 +316,7 @@ CSS = """
|
|
| 316 |
.gradio-container .wrap { border: none !important; }
|
| 317 |
.gradio-container .output-html { padding: 0 !important; }
|
| 318 |
|
| 319 |
-
/* β
|
| 320 |
.gradio-container .tab-nav {
|
| 321 |
background: #0d0d0d !important;
|
| 322 |
border-bottom: 1px solid #1f1f1f !important;
|
|
@@ -698,6 +698,32 @@ button.secondary:hover { border-color: #444 !important; color: #e8e8e8 !importan
|
|
| 698 |
}
|
| 699 |
.footer a { color: #555; text-decoration: none; }
|
| 700 |
.footer a:hover { color: #00d084; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 701 |
"""
|
| 702 |
|
| 703 |
# ---------------------------------------------------------------------------
|
|
@@ -739,12 +765,12 @@ def _hero_html() -> str:
|
|
| 739 |
_stat_card("Reward", "[0.002, 0.998]", small=True)
|
| 740 |
)
|
| 741 |
return (
|
| 742 |
-
f"<div style='background:#141414;border-bottom:1px solid #1f1f1f;"
|
| 743 |
f"padding:32px 32px 28px;font-family:Inter,sans-serif'>"
|
| 744 |
f"<div style='font-size:26px;font-weight:700;color:#f0f0f0;line-height:1.2;"
|
| 745 |
f"margin-bottom:10px;letter-spacing:-.3px'>Customer Support Agent</div>"
|
| 746 |
f"<div style='font-size:13px;color:#666;line-height:1.75;max-width:860px'>{desc}</div>"
|
| 747 |
-
f"<div style='display:grid;grid-template-columns:repeat(6,1fr);gap:10px;margin-top:24px'>"
|
| 748 |
f"{stats}"
|
| 749 |
f"</div></div>"
|
| 750 |
)
|
|
@@ -797,7 +823,7 @@ def _overview_html() -> str:
|
|
| 797 |
"contaminating the reward signal across runs."),
|
| 798 |
]
|
| 799 |
grid = (
|
| 800 |
-
f"<div style='display:grid;grid-template-columns:repeat(auto-fill,minmax(
|
| 801 |
f"gap:14px;margin-top:4px'>"
|
| 802 |
+ "".join(_unique_card(icon, title, body) for icon, title, body in cards)
|
| 803 |
+ "</div>"
|
|
@@ -863,7 +889,7 @@ def _overview_html() -> str:
|
|
| 863 |
"border-bottom:2px solid #1f1f1f;font-family:Inter,sans-serif'"
|
| 864 |
)
|
| 865 |
bench_table = (
|
| 866 |
-
f"<div style='background:#141414;border:1px solid #1f1f1f;border-radius:8px;overflow:hidden;
|
| 867 |
f"<table style='width:100%;border-collapse:collapse;font-size:12px;font-family:\"JetBrains Mono\",monospace'>"
|
| 868 |
f"<thead><tr>"
|
| 869 |
f"<th {th}>Model</th>"
|
|
@@ -875,7 +901,7 @@ def _overview_html() -> str:
|
|
| 875 |
f"<th {thc}>Overall</th>"
|
| 876 |
f"</tr></thead>"
|
| 877 |
f"<tbody>{bench_html_rows}</tbody>"
|
| 878 |
-
f"</table></div>"
|
| 879 |
)
|
| 880 |
|
| 881 |
return (
|
|
@@ -900,6 +926,110 @@ def _overview_html() -> str:
|
|
| 900 |
|
| 901 |
|
| 902 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 903 |
def _scenarios_html() -> str:
|
| 904 |
out = ""
|
| 905 |
tier_meta = {
|
|
@@ -961,6 +1091,7 @@ def _scenarios_html() -> str:
|
|
| 961 |
</div>
|
| 962 |
</div>"""
|
| 963 |
return f"""
|
|
|
|
| 964 |
<h2 class='section-h'>30 support tickets Β· 3 difficulty tiers</h2>
|
| 965 |
<p class='section-sub'>
|
| 966 |
Each scenario runs the full 3-phase MDP. Hover over a message cell to read the full text.
|
|
|
|
| 316 |
.gradio-container .wrap { border: none !important; }
|
| 317 |
.gradio-container .output-html { padding: 0 !important; }
|
| 318 |
|
| 319 |
+
/* οΏ½οΏ½οΏ½β Tab bar ββββββββββββββοΏ½οΏ½οΏ½ββββββββοΏ½οΏ½ββββββββββββββββοΏ½οΏ½οΏ½βββββββββββββββ */
|
| 320 |
.gradio-container .tab-nav {
|
| 321 |
background: #0d0d0d !important;
|
| 322 |
border-bottom: 1px solid #1f1f1f !important;
|
|
|
|
| 698 |
}
|
| 699 |
.footer a { color: #555; text-decoration: none; }
|
| 700 |
.footer a:hover { color: #00d084; }
|
| 701 |
+
|
| 702 |
+
/* ββ Table scrolling (all viewports) βββββββββββββββββββββββββββββββ */
|
| 703 |
+
.table-wrap { overflow-x: auto !important; }
|
| 704 |
+
|
| 705 |
+
/* ββ Mobile / tablet breakpoints βββββββββββββββββββββββββββββββββββ */
|
| 706 |
+
@media (max-width: 900px) {
|
| 707 |
+
.gradio-container > .main { padding: 0 16px 32px !important; }
|
| 708 |
+
.gradio-container .tab-nav { padding: 0 16px !important; }
|
| 709 |
+
.hero-section { padding: 24px 16px 20px !important; }
|
| 710 |
+
.stat-grid-resp { grid-template-columns: repeat(3, 1fr) !important; }
|
| 711 |
+
.unique-grid-resp { grid-template-columns: 1fr !important; }
|
| 712 |
+
.metrics-bar { grid-template-columns: repeat(2, 1fr) !important; }
|
| 713 |
+
.msg-cell { max-width: 180px !important; }
|
| 714 |
+
}
|
| 715 |
+
|
| 716 |
+
@media (max-width: 600px) {
|
| 717 |
+
.gradio-container > .main { padding: 0 10px 20px !important; }
|
| 718 |
+
.gradio-container .tab-nav { padding: 0 4px !important; }
|
| 719 |
+
.gradio-container .tab-nav button { padding: 10px 10px !important; font-size: 11px !important; }
|
| 720 |
+
.hero-section { padding: 16px 12px 14px !important; }
|
| 721 |
+
.stat-grid-resp { grid-template-columns: repeat(2, 1fr) !important; }
|
| 722 |
+
.metrics-bar { grid-template-columns: 1fr 1fr !important; }
|
| 723 |
+
.msg-cell { max-width: 120px !important; }
|
| 724 |
+
.kw-cell { display: none !important; }
|
| 725 |
+
.hide-mobile { display: none !important; }
|
| 726 |
+
}
|
| 727 |
"""
|
| 728 |
|
| 729 |
# ---------------------------------------------------------------------------
|
|
|
|
| 765 |
_stat_card("Reward", "[0.002, 0.998]", small=True)
|
| 766 |
)
|
| 767 |
return (
|
| 768 |
+
f"<div class='hero-section' style='background:#141414;border-bottom:1px solid #1f1f1f;"
|
| 769 |
f"padding:32px 32px 28px;font-family:Inter,sans-serif'>"
|
| 770 |
f"<div style='font-size:26px;font-weight:700;color:#f0f0f0;line-height:1.2;"
|
| 771 |
f"margin-bottom:10px;letter-spacing:-.3px'>Customer Support Agent</div>"
|
| 772 |
f"<div style='font-size:13px;color:#666;line-height:1.75;max-width:860px'>{desc}</div>"
|
| 773 |
+
f"<div class='stat-grid-resp' style='display:grid;grid-template-columns:repeat(6,1fr);gap:10px;margin-top:24px'>"
|
| 774 |
f"{stats}"
|
| 775 |
f"</div></div>"
|
| 776 |
)
|
|
|
|
| 823 |
"contaminating the reward signal across runs."),
|
| 824 |
]
|
| 825 |
grid = (
|
| 826 |
+
f"<div class='unique-grid-resp' style='display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));"
|
| 827 |
f"gap:14px;margin-top:4px'>"
|
| 828 |
+ "".join(_unique_card(icon, title, body) for icon, title, body in cards)
|
| 829 |
+ "</div>"
|
|
|
|
| 889 |
"border-bottom:2px solid #1f1f1f;font-family:Inter,sans-serif'"
|
| 890 |
)
|
| 891 |
bench_table = (
|
| 892 |
+
f"<div style='overflow-x:auto;margin-top:4px'><div style='background:#141414;border:1px solid #1f1f1f;border-radius:8px;overflow:hidden;min-width:520px'>"
|
| 893 |
f"<table style='width:100%;border-collapse:collapse;font-size:12px;font-family:\"JetBrains Mono\",monospace'>"
|
| 894 |
f"<thead><tr>"
|
| 895 |
f"<th {th}>Model</th>"
|
|
|
|
| 901 |
f"<th {thc}>Overall</th>"
|
| 902 |
f"</tr></thead>"
|
| 903 |
f"<tbody>{bench_html_rows}</tbody>"
|
| 904 |
+
f"</table></div></div>"
|
| 905 |
)
|
| 906 |
|
| 907 |
return (
|
|
|
|
| 926 |
|
| 927 |
|
| 928 |
|
| 929 |
+
def _state_diagram_html() -> str:
|
| 930 |
+
def node(phase_num: int, color: str, label: str, action: str, state_after: str, rewards: list) -> str:
|
| 931 |
+
reward_pills = "".join(
|
| 932 |
+
f"<span style='background:{c}11;color:{c};border:1px solid {c}33;"
|
| 933 |
+
f"border-radius:3px;padding:1px 6px;font-size:9px;"
|
| 934 |
+
f"font-family:\"JetBrains Mono\",monospace;font-weight:700'>{r}</span> "
|
| 935 |
+
for r, c in rewards
|
| 936 |
+
)
|
| 937 |
+
return (
|
| 938 |
+
f"<div class='sd-node' style='flex:1;min-width:150px'>"
|
| 939 |
+
f"<div style='background:#141414;border:2px solid {color}44;border-radius:10px;"
|
| 940 |
+
f"padding:14px 12px;height:100%;box-sizing:border-box'>"
|
| 941 |
+
f"<div style='font-size:9px;font-weight:700;color:{color};letter-spacing:1.5px;"
|
| 942 |
+
f"text-transform:uppercase;margin-bottom:6px'>Phase {phase_num}</div>"
|
| 943 |
+
f"<div style='font-size:14px;font-weight:700;color:#f0f0f0;margin-bottom:10px'>{label}</div>"
|
| 944 |
+
f"<div style='background:{color}0d;border:1px solid {color}22;border-radius:5px;"
|
| 945 |
+
f"padding:6px 8px;margin-bottom:10px;font-family:\"JetBrains Mono\",monospace;"
|
| 946 |
+
f"font-size:10px;color:#aaa'>{action}</div>"
|
| 947 |
+
f"<div style='font-size:9px;color:#444;text-transform:uppercase;letter-spacing:.8px;margin-bottom:5px'>State after</div>"
|
| 948 |
+
f"<div style='font-size:10px;font-family:\"JetBrains Mono\",monospace;color:#555;"
|
| 949 |
+
f"line-height:1.8;margin-bottom:10px'>{state_after}</div>"
|
| 950 |
+
f"<div style='display:flex;gap:3px;flex-wrap:wrap'>{reward_pills}</div>"
|
| 951 |
+
f"</div></div>"
|
| 952 |
+
)
|
| 953 |
+
|
| 954 |
+
def arrow(label: str) -> str:
|
| 955 |
+
return (
|
| 956 |
+
f"<div class='sd-arrow' style='display:flex;flex-direction:column;align-items:center;"
|
| 957 |
+
f"justify-content:center;width:52px;flex-shrink:0;padding-top:36px'>"
|
| 958 |
+
f"<div style='font-size:9px;color:#333;text-align:center;margin-bottom:5px;"
|
| 959 |
+
f"font-family:\"JetBrains Mono\",monospace;line-height:1.5;white-space:nowrap'>{label}</div>"
|
| 960 |
+
f"<div style='display:flex;align-items:center;width:100%'>"
|
| 961 |
+
f"<div style='flex:1;height:1px;background:linear-gradient(to right,#222,#333)'></div>"
|
| 962 |
+
f"<div style='color:#444;font-size:12px;line-height:1'>▶</div>"
|
| 963 |
+
f"</div></div>"
|
| 964 |
+
)
|
| 965 |
+
|
| 966 |
+
reset_node = (
|
| 967 |
+
f"<div class='sd-node' style='flex:0 0 auto;min-width:110px;max-width:130px'>"
|
| 968 |
+
f"<div style='background:#111;border:1px solid #222;border-radius:10px;"
|
| 969 |
+
f"padding:14px 12px;height:100%;box-sizing:border-box'>"
|
| 970 |
+
f"<div style='font-size:9px;color:#333;letter-spacing:1.5px;text-transform:uppercase;margin-bottom:6px'>Start</div>"
|
| 971 |
+
f"<div style='font-size:13px;font-weight:600;color:#555;margin-bottom:12px;font-family:\"JetBrains Mono\",monospace'>reset()</div>"
|
| 972 |
+
f"<div style='font-size:10px;font-family:\"JetBrains Mono\",monospace;color:#3a3a3a;line-height:1.8'>"
|
| 973 |
+
f"issue_type:<br><span style='color:#444'>unknown</span><br>history: []<br>phase: 1"
|
| 974 |
+
f"</div></div></div>"
|
| 975 |
+
)
|
| 976 |
+
|
| 977 |
+
done_node = (
|
| 978 |
+
f"<div class='sd-node' style='flex:0 0 auto;min-width:110px;max-width:130px'>"
|
| 979 |
+
f"<div style='background:#111;border:1px solid #00d08433;border-radius:10px;"
|
| 980 |
+
f"padding:14px 12px;height:100%;box-sizing:border-box'>"
|
| 981 |
+
f"<div style='font-size:9px;color:#00d084;letter-spacing:1.5px;text-transform:uppercase;margin-bottom:6px'>End</div>"
|
| 982 |
+
f"<div style='font-size:13px;font-weight:600;color:#00d084;margin-bottom:12px;font-family:\"JetBrains Mono\",monospace'>done=True</div>"
|
| 983 |
+
f"<div style='font-size:10px;font-family:\"JetBrains Mono\",monospace;color:#3a3a3a;line-height:1.8'>"
|
| 984 |
+
f"score =<br>mean(r1,r2,r3)"
|
| 985 |
+
f"</div></div></div>"
|
| 986 |
+
)
|
| 987 |
+
|
| 988 |
+
p1 = node(1, "#60a5fa", "Triage",
|
| 989 |
+
"classify + issue_type",
|
| 990 |
+
"issue_type: <span style='color:#60a5fa'>revealed</span><br>history: +1 msg",
|
| 991 |
+
[("0.998","#00d084"),("0.55","#ffa94d"),("0.002","#ff6b6b")])
|
| 992 |
+
p2 = node(2, "#ffa94d", "Route",
|
| 993 |
+
"assign + team",
|
| 994 |
+
"team: <span style='color:#ffa94d'>in history</span><br>phase: 3",
|
| 995 |
+
[("0.998","#00d084"),("0.400","#ffa94d"),("0.002","#ff6b6b")])
|
| 996 |
+
p3 = node(3, "#00d084", "Resolve",
|
| 997 |
+
"respond / refund / escalate",
|
| 998 |
+
"done: <span style='color:#00d084'>True</span><br>or retry if r<0.5",
|
| 999 |
+
[("0.002β0.998","#00d084")])
|
| 1000 |
+
|
| 1001 |
+
a01 = arrow("")
|
| 1002 |
+
a12 = arrow("issue_type<br>revealed")
|
| 1003 |
+
a23 = arrow("team added<br>to history")
|
| 1004 |
+
a3d = arrow("episode<br>ends")
|
| 1005 |
+
|
| 1006 |
+
return (
|
| 1007 |
+
f"<style>"
|
| 1008 |
+
f"@media(max-width:640px){{"
|
| 1009 |
+
f".sd-flow{{flex-direction:column!important;}}"
|
| 1010 |
+
f".sd-arrow{{flex-direction:row!important;width:100%!important;padding-top:0!important;"
|
| 1011 |
+
f"padding-left:36px!important;height:36px!important;}}"
|
| 1012 |
+
f".sd-arrow>div:last-child{{flex-direction:row!important;}}"
|
| 1013 |
+
f"}}"
|
| 1014 |
+
f"</style>"
|
| 1015 |
+
f"<div style='font-family:Inter,sans-serif;margin-bottom:36px'>"
|
| 1016 |
+
f"<div style='font-size:18px;font-weight:600;color:#f0f0f0;margin-bottom:6px'>Episode State Diagram</div>"
|
| 1017 |
+
f"<div style='font-size:13px;color:#666;margin-bottom:20px;line-height:1.6'>"
|
| 1018 |
+
f"State evolves at each phase transition. The agent sees richer context at every step β "
|
| 1019 |
+
f"decisions in early phases directly constrain options in later ones.</div>"
|
| 1020 |
+
f"<div style='overflow-x:auto;padding-bottom:4px'>"
|
| 1021 |
+
f"<div class='sd-flow' style='display:flex;align-items:stretch;gap:0;min-width:620px'>"
|
| 1022 |
+
f"{reset_node}{a01}{p1}{a12}{p2}{a23}{p3}{a3d}{done_node}"
|
| 1023 |
+
f"</div></div>"
|
| 1024 |
+
f"<div style='display:flex;gap:20px;margin-top:12px;flex-wrap:wrap'>"
|
| 1025 |
+
f"<span style='font-size:11px;color:#444;font-family:\"JetBrains Mono\",monospace'>"
|
| 1026 |
+
f"<span style='color:#00d084'>■</span> correct "
|
| 1027 |
+
f"<span style='color:#ffa94d'>■</span> partial/wrong-team "
|
| 1028 |
+
f"<span style='color:#ff6b6b'>■</span> wrong action</span>"
|
| 1029 |
+
f"</div></div>"
|
| 1030 |
+
)
|
| 1031 |
+
|
| 1032 |
+
|
| 1033 |
def _scenarios_html() -> str:
|
| 1034 |
out = ""
|
| 1035 |
tier_meta = {
|
|
|
|
| 1091 |
</div>
|
| 1092 |
</div>"""
|
| 1093 |
return f"""
|
| 1094 |
+
{_state_diagram_html()}
|
| 1095 |
<h2 class='section-h'>30 support tickets Β· 3 difficulty tiers</h2>
|
| 1096 |
<p class='section-sub'>
|
| 1097 |
Each scenario runs the full 3-phase MDP. Hover over a message cell to read the full text.
|
|
@@ -316,7 +316,7 @@ CSS = """
|
|
| 316 |
.gradio-container .wrap { border: none !important; }
|
| 317 |
.gradio-container .output-html { padding: 0 !important; }
|
| 318 |
|
| 319 |
-
/* β
|
| 320 |
.gradio-container .tab-nav {
|
| 321 |
background: #0d0d0d !important;
|
| 322 |
border-bottom: 1px solid #1f1f1f !important;
|
|
@@ -698,6 +698,32 @@ button.secondary:hover { border-color: #444 !important; color: #e8e8e8 !importan
|
|
| 698 |
}
|
| 699 |
.footer a { color: #555; text-decoration: none; }
|
| 700 |
.footer a:hover { color: #00d084; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 701 |
"""
|
| 702 |
|
| 703 |
# ---------------------------------------------------------------------------
|
|
@@ -739,12 +765,12 @@ def _hero_html() -> str:
|
|
| 739 |
_stat_card("Reward", "[0.002, 0.998]", small=True)
|
| 740 |
)
|
| 741 |
return (
|
| 742 |
-
f"<div style='background:#141414;border-bottom:1px solid #1f1f1f;"
|
| 743 |
f"padding:32px 32px 28px;font-family:Inter,sans-serif'>"
|
| 744 |
f"<div style='font-size:26px;font-weight:700;color:#f0f0f0;line-height:1.2;"
|
| 745 |
f"margin-bottom:10px;letter-spacing:-.3px'>Customer Support Agent</div>"
|
| 746 |
f"<div style='font-size:13px;color:#666;line-height:1.75;max-width:860px'>{desc}</div>"
|
| 747 |
-
f"<div style='display:grid;grid-template-columns:repeat(6,1fr);gap:10px;margin-top:24px'>"
|
| 748 |
f"{stats}"
|
| 749 |
f"</div></div>"
|
| 750 |
)
|
|
@@ -797,7 +823,7 @@ def _overview_html() -> str:
|
|
| 797 |
"contaminating the reward signal across runs."),
|
| 798 |
]
|
| 799 |
grid = (
|
| 800 |
-
f"<div style='display:grid;grid-template-columns:repeat(auto-fill,minmax(
|
| 801 |
f"gap:14px;margin-top:4px'>"
|
| 802 |
+ "".join(_unique_card(icon, title, body) for icon, title, body in cards)
|
| 803 |
+ "</div>"
|
|
@@ -863,7 +889,7 @@ def _overview_html() -> str:
|
|
| 863 |
"border-bottom:2px solid #1f1f1f;font-family:Inter,sans-serif'"
|
| 864 |
)
|
| 865 |
bench_table = (
|
| 866 |
-
f"<div style='background:#141414;border:1px solid #1f1f1f;border-radius:8px;overflow:hidden;
|
| 867 |
f"<table style='width:100%;border-collapse:collapse;font-size:12px;font-family:\"JetBrains Mono\",monospace'>"
|
| 868 |
f"<thead><tr>"
|
| 869 |
f"<th {th}>Model</th>"
|
|
@@ -875,7 +901,7 @@ def _overview_html() -> str:
|
|
| 875 |
f"<th {thc}>Overall</th>"
|
| 876 |
f"</tr></thead>"
|
| 877 |
f"<tbody>{bench_html_rows}</tbody>"
|
| 878 |
-
f"</table></div>"
|
| 879 |
)
|
| 880 |
|
| 881 |
return (
|
|
@@ -900,6 +926,110 @@ def _overview_html() -> str:
|
|
| 900 |
|
| 901 |
|
| 902 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 903 |
def _scenarios_html() -> str:
|
| 904 |
out = ""
|
| 905 |
tier_meta = {
|
|
@@ -961,6 +1091,7 @@ def _scenarios_html() -> str:
|
|
| 961 |
</div>
|
| 962 |
</div>"""
|
| 963 |
return f"""
|
|
|
|
| 964 |
<h2 class='section-h'>30 support tickets Β· 3 difficulty tiers</h2>
|
| 965 |
<p class='section-sub'>
|
| 966 |
Each scenario runs the full 3-phase MDP. Hover over a message cell to read the full text.
|
|
|
|
| 316 |
.gradio-container .wrap { border: none !important; }
|
| 317 |
.gradio-container .output-html { padding: 0 !important; }
|
| 318 |
|
| 319 |
+
/* οΏ½οΏ½οΏ½β Tab bar ββββββββββββββοΏ½οΏ½οΏ½ββββββββοΏ½οΏ½ββββββββββββββββοΏ½οΏ½οΏ½βββββββββββββββ */
|
| 320 |
.gradio-container .tab-nav {
|
| 321 |
background: #0d0d0d !important;
|
| 322 |
border-bottom: 1px solid #1f1f1f !important;
|
|
|
|
| 698 |
}
|
| 699 |
.footer a { color: #555; text-decoration: none; }
|
| 700 |
.footer a:hover { color: #00d084; }
|
| 701 |
+
|
| 702 |
+
/* ββ Table scrolling (all viewports) βββββββββββββββββββββββββββββββ */
|
| 703 |
+
.table-wrap { overflow-x: auto !important; }
|
| 704 |
+
|
| 705 |
+
/* ββ Mobile / tablet breakpoints βββββββββββββββββββββββββββββββββββ */
|
| 706 |
+
@media (max-width: 900px) {
|
| 707 |
+
.gradio-container > .main { padding: 0 16px 32px !important; }
|
| 708 |
+
.gradio-container .tab-nav { padding: 0 16px !important; }
|
| 709 |
+
.hero-section { padding: 24px 16px 20px !important; }
|
| 710 |
+
.stat-grid-resp { grid-template-columns: repeat(3, 1fr) !important; }
|
| 711 |
+
.unique-grid-resp { grid-template-columns: 1fr !important; }
|
| 712 |
+
.metrics-bar { grid-template-columns: repeat(2, 1fr) !important; }
|
| 713 |
+
.msg-cell { max-width: 180px !important; }
|
| 714 |
+
}
|
| 715 |
+
|
| 716 |
+
@media (max-width: 600px) {
|
| 717 |
+
.gradio-container > .main { padding: 0 10px 20px !important; }
|
| 718 |
+
.gradio-container .tab-nav { padding: 0 4px !important; }
|
| 719 |
+
.gradio-container .tab-nav button { padding: 10px 10px !important; font-size: 11px !important; }
|
| 720 |
+
.hero-section { padding: 16px 12px 14px !important; }
|
| 721 |
+
.stat-grid-resp { grid-template-columns: repeat(2, 1fr) !important; }
|
| 722 |
+
.metrics-bar { grid-template-columns: 1fr 1fr !important; }
|
| 723 |
+
.msg-cell { max-width: 120px !important; }
|
| 724 |
+
.kw-cell { display: none !important; }
|
| 725 |
+
.hide-mobile { display: none !important; }
|
| 726 |
+
}
|
| 727 |
"""
|
| 728 |
|
| 729 |
# ---------------------------------------------------------------------------
|
|
|
|
| 765 |
_stat_card("Reward", "[0.002, 0.998]", small=True)
|
| 766 |
)
|
| 767 |
return (
|
| 768 |
+
f"<div class='hero-section' style='background:#141414;border-bottom:1px solid #1f1f1f;"
|
| 769 |
f"padding:32px 32px 28px;font-family:Inter,sans-serif'>"
|
| 770 |
f"<div style='font-size:26px;font-weight:700;color:#f0f0f0;line-height:1.2;"
|
| 771 |
f"margin-bottom:10px;letter-spacing:-.3px'>Customer Support Agent</div>"
|
| 772 |
f"<div style='font-size:13px;color:#666;line-height:1.75;max-width:860px'>{desc}</div>"
|
| 773 |
+
f"<div class='stat-grid-resp' style='display:grid;grid-template-columns:repeat(6,1fr);gap:10px;margin-top:24px'>"
|
| 774 |
f"{stats}"
|
| 775 |
f"</div></div>"
|
| 776 |
)
|
|
|
|
| 823 |
"contaminating the reward signal across runs."),
|
| 824 |
]
|
| 825 |
grid = (
|
| 826 |
+
f"<div class='unique-grid-resp' style='display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));"
|
| 827 |
f"gap:14px;margin-top:4px'>"
|
| 828 |
+ "".join(_unique_card(icon, title, body) for icon, title, body in cards)
|
| 829 |
+ "</div>"
|
|
|
|
| 889 |
"border-bottom:2px solid #1f1f1f;font-family:Inter,sans-serif'"
|
| 890 |
)
|
| 891 |
bench_table = (
|
| 892 |
+
f"<div style='overflow-x:auto;margin-top:4px'><div style='background:#141414;border:1px solid #1f1f1f;border-radius:8px;overflow:hidden;min-width:520px'>"
|
| 893 |
f"<table style='width:100%;border-collapse:collapse;font-size:12px;font-family:\"JetBrains Mono\",monospace'>"
|
| 894 |
f"<thead><tr>"
|
| 895 |
f"<th {th}>Model</th>"
|
|
|
|
| 901 |
f"<th {thc}>Overall</th>"
|
| 902 |
f"</tr></thead>"
|
| 903 |
f"<tbody>{bench_html_rows}</tbody>"
|
| 904 |
+
f"</table></div></div>"
|
| 905 |
)
|
| 906 |
|
| 907 |
return (
|
|
|
|
| 926 |
|
| 927 |
|
| 928 |
|
| 929 |
+
def _state_diagram_html() -> str:
|
| 930 |
+
def node(phase_num: int, color: str, label: str, action: str, state_after: str, rewards: list) -> str:
|
| 931 |
+
reward_pills = "".join(
|
| 932 |
+
f"<span style='background:{c}11;color:{c};border:1px solid {c}33;"
|
| 933 |
+
f"border-radius:3px;padding:1px 6px;font-size:9px;"
|
| 934 |
+
f"font-family:\"JetBrains Mono\",monospace;font-weight:700'>{r}</span> "
|
| 935 |
+
for r, c in rewards
|
| 936 |
+
)
|
| 937 |
+
return (
|
| 938 |
+
f"<div class='sd-node' style='flex:1;min-width:150px'>"
|
| 939 |
+
f"<div style='background:#141414;border:2px solid {color}44;border-radius:10px;"
|
| 940 |
+
f"padding:14px 12px;height:100%;box-sizing:border-box'>"
|
| 941 |
+
f"<div style='font-size:9px;font-weight:700;color:{color};letter-spacing:1.5px;"
|
| 942 |
+
f"text-transform:uppercase;margin-bottom:6px'>Phase {phase_num}</div>"
|
| 943 |
+
f"<div style='font-size:14px;font-weight:700;color:#f0f0f0;margin-bottom:10px'>{label}</div>"
|
| 944 |
+
f"<div style='background:{color}0d;border:1px solid {color}22;border-radius:5px;"
|
| 945 |
+
f"padding:6px 8px;margin-bottom:10px;font-family:\"JetBrains Mono\",monospace;"
|
| 946 |
+
f"font-size:10px;color:#aaa'>{action}</div>"
|
| 947 |
+
f"<div style='font-size:9px;color:#444;text-transform:uppercase;letter-spacing:.8px;margin-bottom:5px'>State after</div>"
|
| 948 |
+
f"<div style='font-size:10px;font-family:\"JetBrains Mono\",monospace;color:#555;"
|
| 949 |
+
f"line-height:1.8;margin-bottom:10px'>{state_after}</div>"
|
| 950 |
+
f"<div style='display:flex;gap:3px;flex-wrap:wrap'>{reward_pills}</div>"
|
| 951 |
+
f"</div></div>"
|
| 952 |
+
)
|
| 953 |
+
|
| 954 |
+
def arrow(label: str) -> str:
|
| 955 |
+
return (
|
| 956 |
+
f"<div class='sd-arrow' style='display:flex;flex-direction:column;align-items:center;"
|
| 957 |
+
f"justify-content:center;width:52px;flex-shrink:0;padding-top:36px'>"
|
| 958 |
+
f"<div style='font-size:9px;color:#333;text-align:center;margin-bottom:5px;"
|
| 959 |
+
f"font-family:\"JetBrains Mono\",monospace;line-height:1.5;white-space:nowrap'>{label}</div>"
|
| 960 |
+
f"<div style='display:flex;align-items:center;width:100%'>"
|
| 961 |
+
f"<div style='flex:1;height:1px;background:linear-gradient(to right,#222,#333)'></div>"
|
| 962 |
+
f"<div style='color:#444;font-size:12px;line-height:1'>▶</div>"
|
| 963 |
+
f"</div></div>"
|
| 964 |
+
)
|
| 965 |
+
|
| 966 |
+
reset_node = (
|
| 967 |
+
f"<div class='sd-node' style='flex:0 0 auto;min-width:110px;max-width:130px'>"
|
| 968 |
+
f"<div style='background:#111;border:1px solid #222;border-radius:10px;"
|
| 969 |
+
f"padding:14px 12px;height:100%;box-sizing:border-box'>"
|
| 970 |
+
f"<div style='font-size:9px;color:#333;letter-spacing:1.5px;text-transform:uppercase;margin-bottom:6px'>Start</div>"
|
| 971 |
+
f"<div style='font-size:13px;font-weight:600;color:#555;margin-bottom:12px;font-family:\"JetBrains Mono\",monospace'>reset()</div>"
|
| 972 |
+
f"<div style='font-size:10px;font-family:\"JetBrains Mono\",monospace;color:#3a3a3a;line-height:1.8'>"
|
| 973 |
+
f"issue_type:<br><span style='color:#444'>unknown</span><br>history: []<br>phase: 1"
|
| 974 |
+
f"</div></div></div>"
|
| 975 |
+
)
|
| 976 |
+
|
| 977 |
+
done_node = (
|
| 978 |
+
f"<div class='sd-node' style='flex:0 0 auto;min-width:110px;max-width:130px'>"
|
| 979 |
+
f"<div style='background:#111;border:1px solid #00d08433;border-radius:10px;"
|
| 980 |
+
f"padding:14px 12px;height:100%;box-sizing:border-box'>"
|
| 981 |
+
f"<div style='font-size:9px;color:#00d084;letter-spacing:1.5px;text-transform:uppercase;margin-bottom:6px'>End</div>"
|
| 982 |
+
f"<div style='font-size:13px;font-weight:600;color:#00d084;margin-bottom:12px;font-family:\"JetBrains Mono\",monospace'>done=True</div>"
|
| 983 |
+
f"<div style='font-size:10px;font-family:\"JetBrains Mono\",monospace;color:#3a3a3a;line-height:1.8'>"
|
| 984 |
+
f"score =<br>mean(r1,r2,r3)"
|
| 985 |
+
f"</div></div></div>"
|
| 986 |
+
)
|
| 987 |
+
|
| 988 |
+
p1 = node(1, "#60a5fa", "Triage",
|
| 989 |
+
"classify + issue_type",
|
| 990 |
+
"issue_type: <span style='color:#60a5fa'>revealed</span><br>history: +1 msg",
|
| 991 |
+
[("0.998","#00d084"),("0.55","#ffa94d"),("0.002","#ff6b6b")])
|
| 992 |
+
p2 = node(2, "#ffa94d", "Route",
|
| 993 |
+
"assign + team",
|
| 994 |
+
"team: <span style='color:#ffa94d'>in history</span><br>phase: 3",
|
| 995 |
+
[("0.998","#00d084"),("0.400","#ffa94d"),("0.002","#ff6b6b")])
|
| 996 |
+
p3 = node(3, "#00d084", "Resolve",
|
| 997 |
+
"respond / refund / escalate",
|
| 998 |
+
"done: <span style='color:#00d084'>True</span><br>or retry if r<0.5",
|
| 999 |
+
[("0.002β0.998","#00d084")])
|
| 1000 |
+
|
| 1001 |
+
a01 = arrow("")
|
| 1002 |
+
a12 = arrow("issue_type<br>revealed")
|
| 1003 |
+
a23 = arrow("team added<br>to history")
|
| 1004 |
+
a3d = arrow("episode<br>ends")
|
| 1005 |
+
|
| 1006 |
+
return (
|
| 1007 |
+
f"<style>"
|
| 1008 |
+
f"@media(max-width:640px){{"
|
| 1009 |
+
f".sd-flow{{flex-direction:column!important;}}"
|
| 1010 |
+
f".sd-arrow{{flex-direction:row!important;width:100%!important;padding-top:0!important;"
|
| 1011 |
+
f"padding-left:36px!important;height:36px!important;}}"
|
| 1012 |
+
f".sd-arrow>div:last-child{{flex-direction:row!important;}}"
|
| 1013 |
+
f"}}"
|
| 1014 |
+
f"</style>"
|
| 1015 |
+
f"<div style='font-family:Inter,sans-serif;margin-bottom:36px'>"
|
| 1016 |
+
f"<div style='font-size:18px;font-weight:600;color:#f0f0f0;margin-bottom:6px'>Episode State Diagram</div>"
|
| 1017 |
+
f"<div style='font-size:13px;color:#666;margin-bottom:20px;line-height:1.6'>"
|
| 1018 |
+
f"State evolves at each phase transition. The agent sees richer context at every step β "
|
| 1019 |
+
f"decisions in early phases directly constrain options in later ones.</div>"
|
| 1020 |
+
f"<div style='overflow-x:auto;padding-bottom:4px'>"
|
| 1021 |
+
f"<div class='sd-flow' style='display:flex;align-items:stretch;gap:0;min-width:620px'>"
|
| 1022 |
+
f"{reset_node}{a01}{p1}{a12}{p2}{a23}{p3}{a3d}{done_node}"
|
| 1023 |
+
f"</div></div>"
|
| 1024 |
+
f"<div style='display:flex;gap:20px;margin-top:12px;flex-wrap:wrap'>"
|
| 1025 |
+
f"<span style='font-size:11px;color:#444;font-family:\"JetBrains Mono\",monospace'>"
|
| 1026 |
+
f"<span style='color:#00d084'>■</span> correct "
|
| 1027 |
+
f"<span style='color:#ffa94d'>■</span> partial/wrong-team "
|
| 1028 |
+
f"<span style='color:#ff6b6b'>■</span> wrong action</span>"
|
| 1029 |
+
f"</div></div>"
|
| 1030 |
+
)
|
| 1031 |
+
|
| 1032 |
+
|
| 1033 |
def _scenarios_html() -> str:
|
| 1034 |
out = ""
|
| 1035 |
tier_meta = {
|
|
|
|
| 1091 |
</div>
|
| 1092 |
</div>"""
|
| 1093 |
return f"""
|
| 1094 |
+
{_state_diagram_html()}
|
| 1095 |
<h2 class='section-h'>30 support tickets Β· 3 difficulty tiers</h2>
|
| 1096 |
<p class='section-sub'>
|
| 1097 |
Each scenario runs the full 3-phase MDP. Hover over a message cell to read the full text.
|