Pleuron commited on
Commit
f1ab84b
·
verified ·
1 Parent(s): ba100bb

EvoTool interactive replay (static)

Browse files
Files changed (3) hide show
  1. README.md +16 -4
  2. index.html +396 -18
  3. static/replay_data.js +0 -0
README.md CHANGED
@@ -1,10 +1,22 @@
1
  ---
2
- title: Evotool Replay
3
- emoji: 🏃
4
- colorFrom: indigo
5
  colorTo: indigo
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: EvoTool Interactive Replay
3
+ emoji: 🔁
4
+ colorFrom: purple
5
  colorTo: indigo
6
  sdk: static
7
  pinned: false
8
+ license: mit
9
+ short_description: Generation-by-generation replay of EvoTool's evolution loop
10
  ---
11
 
12
+ # EvoTool Interactive Replay
13
+
14
+ Generation-by-generation replay of the EvoTool self-evolving loop (blame → targeted
15
+ mutation → diversity-aware selection) on a reference run: every one of the 90
16
+ generations with the Blamer's diagnosis, the prompt diff, and the population state.
17
+
18
+ - Paper: **EvoTool: Self-Evolving Tool-Use Policy Optimization in LLM Agents via
19
+ Blame-Aware Mutation and Diversity-Aware Selection** (ACL 2026) —
20
+ https://aclanthology.org/2026.acl-long.2016/ · arXiv: https://arxiv.org/abs/2603.04900
21
+ - Code: https://github.com/SYang2000/ACL_2026_EvoTool
22
+ - Project page: https://syang2000.github.io/ACL_2026_EvoTool/
index.html CHANGED
@@ -1,19 +1,397 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>EvoTool Generation-by-Generation Replay</title>
7
+ <style>
8
+ :root {
9
+ --ink: #1c2430;
10
+ --muted: #5b6a7c;
11
+ --line: #dde4ec;
12
+ --bg: #f6f8fa;
13
+ --card: #ffffff;
14
+ --accent: #1f5fbf;
15
+ --planner: #1f5fbf;
16
+ --selector: #7b3fbf;
17
+ --caller: #c96a11;
18
+ --synthesizer: #1e8a4c;
19
+ --ok: #1e8a4c;
20
+ --bad: #b3402f;
21
+ }
22
+ * { box-sizing: border-box; }
23
+ body {
24
+ margin: 0;
25
+ background: var(--bg);
26
+ color: var(--ink);
27
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
28
+ font-size: 15px;
29
+ line-height: 1.5;
30
+ }
31
+ a { color: var(--accent); text-decoration: none; }
32
+ a:hover { text-decoration: underline; }
33
+ .wrap { max-width: 980px; margin: 0 auto; padding: 20px 18px 60px; }
34
+ header h1 { font-size: 1.45rem; margin: 8px 0 4px; }
35
+ header .sub { color: var(--muted); font-size: .92rem; }
36
+ .navlinks { font-size: .9rem; margin-top: 6px; }
37
+ .navlinks a + a { margin-left: 14px; }
38
+ .banner {
39
+ margin: 14px 0 18px;
40
+ padding: 10px 14px;
41
+ background: #fff7e8;
42
+ border: 1px solid #ecd9ac;
43
+ border-radius: 8px;
44
+ font-size: .88rem;
45
+ color: #6a5320;
46
+ }
47
+ .card {
48
+ background: var(--card);
49
+ border: 1px solid var(--line);
50
+ border-radius: 10px;
51
+ padding: 16px 18px;
52
+ margin-bottom: 16px;
53
+ }
54
+ /* controls */
55
+ .controls { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
56
+ .controls button {
57
+ font: inherit;
58
+ padding: 5px 14px;
59
+ border: 1px solid var(--line);
60
+ border-radius: 7px;
61
+ background: #fff;
62
+ color: var(--ink);
63
+ cursor: pointer;
64
+ }
65
+ .controls button:hover { border-color: var(--accent); color: var(--accent); }
66
+ .controls input[type=range] { flex: 1; min-width: 180px; accent-color: var(--accent); }
67
+ .controls .genlabel { font-variant-numeric: tabular-nums; font-weight: 600; min-width: 120px; }
68
+ .hint { color: var(--muted); font-size: .8rem; margin-top: 6px; }
69
+ /* generation panel */
70
+ .genhead { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
71
+ .genhead .gid { font-weight: 700; font-size: 1.05rem; }
72
+ .chip {
73
+ display: inline-block;
74
+ padding: 1px 10px;
75
+ border-radius: 999px;
76
+ font-size: .78rem;
77
+ font-weight: 600;
78
+ color: #fff;
79
+ }
80
+ .chip.planner { background: var(--planner); }
81
+ .chip.selector { background: var(--selector); }
82
+ .chip.caller { background: var(--caller); }
83
+ .chip.synthesizer { background: var(--synthesizer); }
84
+ .badge {
85
+ display: inline-block;
86
+ padding: 1px 10px;
87
+ border-radius: 6px;
88
+ font-size: .78rem;
89
+ font-weight: 700;
90
+ letter-spacing: .03em;
91
+ }
92
+ .badge.accepted { background: #e2f3e8; color: var(--ok); border: 1px solid #bcdfc9; }
93
+ .badge.rejected { background: #f7e8e5; color: var(--bad); border: 1px solid #e6c5be; }
94
+ .stats { display: flex; gap: 22px; flex-wrap: wrap; font-size: .9rem; margin: 6px 0 10px; }
95
+ .stats .k { color: var(--muted); }
96
+ .stats .v { font-weight: 600; font-variant-numeric: tabular-nums; }
97
+ .up { color: var(--ok); } .down { color: var(--bad); }
98
+ .diag {
99
+ border-left: 3px solid var(--accent);
100
+ background: #f2f6fc;
101
+ margin: 10px 0;
102
+ padding: 8px 12px;
103
+ font-size: .9rem;
104
+ border-radius: 0 6px 6px 0;
105
+ }
106
+ .diag .who { font-weight: 700; font-size: .8rem; color: var(--accent); display: block; margin-bottom: 2px; }
107
+ pre.diff {
108
+ background: #0f1720;
109
+ color: #cfd8e3;
110
+ border-radius: 8px;
111
+ padding: 12px 14px;
112
+ overflow-x: auto;
113
+ font-size: .8rem;
114
+ line-height: 1.45;
115
+ white-space: pre-wrap;
116
+ word-break: break-word;
117
+ }
118
+ pre.diff .add { color: #7fd08a; }
119
+ pre.diff .del { color: #f08f80; }
120
+ pre.diff .hunk { color: #8fa6c0; font-weight: 600; }
121
+ pre.diff .filehdr { color: #8fa6c0; }
122
+ canvas { width: 100%; height: 190px; display: block; }
123
+ .charthead { font-size: .85rem; color: var(--muted); margin-bottom: 6px; }
124
+ .infonote {
125
+ margin: -4px 0 16px;
126
+ padding: 6px 14px;
127
+ border-left: 3px solid var(--line);
128
+ color: var(--muted);
129
+ font-size: .84rem;
130
+ }
131
+ #error {
132
+ display: none;
133
+ background: #f7e8e5;
134
+ border: 1px solid #e6c5be;
135
+ color: var(--bad);
136
+ padding: 14px 16px;
137
+ border-radius: 8px;
138
+ margin-top: 14px;
139
+ }
140
+ footer { color: var(--muted); font-size: .8rem; margin-top: 26px; }
141
+ </style>
142
+ </head>
143
+ <body>
144
+ <div class="wrap">
145
+ <header>
146
+ <h1>EvoTool — Generation-by-Generation Replay</h1>
147
+ <div class="sub">Every mutation the self-evolving loop proposed on BFCL: what the Blamer diagnosed,
148
+ what the Mutator changed, and whether the child beat its parent.</div>
149
+ <div class="navlinks">
150
+ <a href="index.html">&larr; Project page</a>
151
+ <a href="https://github.com/SYang2000/ACL_2026_EvoTool" target="_blank" rel="noopener">GitHub repo</a>
152
+ <a href="https://aclanthology.org/2026.acl-long.2016/" target="_blank" rel="noopener">Paper (ACL 2026)</a>
153
+ </div>
154
+ <div class="banner" id="banner">
155
+ <b>Provenance:</b> reference testbed run — Qwen3-4B backbone on the 150-instance curated BFCL demo
156
+ subset (90 train / 30 sel / 30 test, seed 42, 3 epochs = 90 generations). The paper's reported
157
+ numbers use Qwen3-8B on the full benchmarks; this replay illustrates the mechanism, not the paper's scores.
158
+ </div>
159
+ </header>
160
+
161
+ <div id="error">
162
+ Replay data failed to load. This page needs <code>static/replay_data.js</code> next to it
163
+ (shipped in the repo under <code>docs/static/</code>). If you are viewing a copy of this file alone,
164
+ grab the full <code>docs/</code> directory from the
165
+ <a href="https://github.com/SYang2000/ACL_2026_EvoTool" target="_blank" rel="noopener">GitHub repo</a>.
166
+ </div>
167
+
168
+ <noscript><p style="max-width:720px;margin:24px auto;padding:12px 16px;background:#fef3c7;border:1px solid #d97706;border-radius:8px;font-size:14px">This interactive replay requires JavaScript. The same run is documented statically in <a href="https://github.com/SYang2000/ACL_2026_EvoTool/blob/main/CASE_STUDY.md">CASE_STUDY.md</a>.</p></noscript>
169
+ <div id="app" style="display:none">
170
+ <div class="card">
171
+ <div class="controls">
172
+ <button id="btnPrev" title="previous generation (&larr;)">&#9664; Prev</button>
173
+ <button id="btnPlay" title="auto-advance">&#9654; Play</button>
174
+ <button id="btnNext" title="next generation (&rarr;)">Next &#9654;</button>
175
+ <input type="range" id="slider" min="0" max="89" value="0" step="1">
176
+ <span class="genlabel" id="genLabel">gen 0 / 89</span>
177
+ </div>
178
+ <div class="hint">Keyboard: &larr; / &rarr; step through generations, space toggles play.</div>
179
+ </div>
180
+
181
+ <div class="card">
182
+ <div class="charthead">Best validation score on S<sub>sel</sub> across generations
183
+ (dots: held-out test mean reward at epoch ends; dotted lines: epoch boundaries)</div>
184
+ <canvas id="chart" width="940" height="190"></canvas>
185
+ </div>
186
+
187
+ <div class="infonote">
188
+ <b>Why is the parent so often <code>init</code>?</b> Diversity-aware selection retains every policy
189
+ that wins at least one selection instance — including the initial policy — and parents are sampled
190
+ proportional to instance wins, so <code>init</code> keeps being re-selected as long as it still wins
191
+ instances. Deep chains form when an evolved policy overtakes it (e.g. the deployed
192
+ <code>g48-planner</code> lineage).
193
+ </div>
194
+
195
+ <div class="card" id="genPanel">
196
+ <div class="genhead">
197
+ <span class="gid" id="gid"></span>
198
+ <span class="chip" id="moduleChip"></span>
199
+ <span class="badge" id="acceptBadge"></span>
200
+ </div>
201
+ <div class="stats">
202
+ <span><span class="k">lineage&nbsp;</span><span class="v" id="lineage"></span></span>
203
+ <span><span class="k">batch reward&nbsp;</span><span class="v" id="rewards"></span></span>
204
+ <span><span class="k">best val (S<sub>sel</sub>)&nbsp;</span><span class="v" id="valScore"></span></span>
205
+ <span id="testWrap" style="display:none"><span class="k">held-out test&nbsp;</span><span class="v" id="testScore"></span></span>
206
+ <span><span class="k">population&nbsp;</span><span class="v" id="popSize"></span></span>
207
+ </div>
208
+ <div class="diag"><span class="who">BLAMER DIAGNOSIS</span><span id="diag"></span></div>
209
+ <pre class="diff" id="diff"></pre>
210
+ </div>
211
+
212
+ <footer>
213
+ Data source: <code>static/replay_data.js</code>, trimmed from the raw run log of the reference
214
+ testbed run (one JSONL record per generation, including rejected mutations).
215
+ </footer>
216
+ </div>
217
+ </div>
218
+
219
+ <script src="static/replay_data.js"></script>
220
+ <script>
221
+ (function () {
222
+ "use strict";
223
+
224
+ var D = window.REPLAY_DATA;
225
+ if (!D || !D.gens || !D.gens.length) {
226
+ document.getElementById("error").style.display = "block";
227
+ return;
228
+ }
229
+ document.getElementById("app").style.display = "block";
230
+
231
+ var gens = D.gens;
232
+ var N = gens.length;
233
+ var idx = 0;
234
+ var playing = false;
235
+ var timer = null;
236
+
237
+ var slider = document.getElementById("slider");
238
+ slider.max = N - 1;
239
+
240
+ function esc(s) {
241
+ return String(s == null ? "" : s)
242
+ .replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
243
+ }
244
+ function fmt(x) { return (x == null) ? "–" : Number(x).toFixed(4); }
245
+
246
+ function renderDiff(text) {
247
+ if (!text) return "<span class='filehdr'>(no prompt change recorded)</span>";
248
+ return text.split("\n").map(function (line) {
249
+ var e = esc(line);
250
+ if (line.indexOf("---") === 0 || line.indexOf("+++") === 0) return "<span class='filehdr'>" + e + "</span>";
251
+ if (line.indexOf("@@") === 0) return "<span class='hunk'>" + e + "</span>";
252
+ if (line.charAt(0) === "+") return "<span class='add'>" + e + "</span>";
253
+ if (line.charAt(0) === "-") return "<span class='del'>" + e + "</span>";
254
+ return e;
255
+ }).join("\n");
256
+ }
257
+
258
+ // ---------- chart ----------
259
+ var canvas = document.getElementById("chart");
260
+ var ctx = canvas.getContext("2d");
261
+ var PAD = { l: 44, r: 12, t: 10, b: 24 };
262
+
263
+ function fitCanvas() {
264
+ var cssW = canvas.clientWidth || 940;
265
+ var scale = window.devicePixelRatio || 1;
266
+ canvas.width = Math.round(cssW * scale);
267
+ canvas.height = Math.round(190 * scale);
268
+ ctx.setTransform(scale, 0, 0, scale, 0, 0);
269
+ return { w: cssW, h: 190 };
270
+ }
271
+
272
+ function drawChart() {
273
+ var dim = fitCanvas();
274
+ var w = dim.w, h = dim.h;
275
+ var vals = gens.map(function (g) { return g.val; });
276
+ var lo = 0, hi = Math.max.apply(null, vals.concat(gens.filter(function (g) { return g.test != null; })
277
+ .map(function (g) { return g.test; }))) * 1.15 || 1;
278
+ function X(g) { return PAD.l + (w - PAD.l - PAD.r) * (g / (N - 1)); }
279
+ function Y(v) { return h - PAD.b - (h - PAD.b - PAD.t) * ((v - lo) / (hi - lo)); }
280
+
281
+ ctx.clearRect(0, 0, w, h);
282
+ // gridlines + y labels
283
+ ctx.font = "10px sans-serif";
284
+ ctx.fillStyle = "#5b6a7c";
285
+ ctx.strokeStyle = "#e4e9f0";
286
+ ctx.lineWidth = 1;
287
+ [0, 0.2, 0.4, 0.6].forEach(function (v) {
288
+ if (v > hi) return;
289
+ ctx.beginPath(); ctx.moveTo(PAD.l, Y(v)); ctx.lineTo(w - PAD.r, Y(v)); ctx.stroke();
290
+ ctx.fillText(v.toFixed(1), 14, Y(v) + 3);
291
+ });
292
+ // epoch boundaries (start of epochs 1 and 2)
293
+ ctx.strokeStyle = "#9aa7b6";
294
+ ctx.setLineDash([2, 3]);
295
+ for (var i = 1; i < N; i++) {
296
+ if (gens[i].epoch !== gens[i - 1].epoch) {
297
+ ctx.beginPath(); ctx.moveTo(X(gens[i].gen), PAD.t); ctx.lineTo(X(gens[i].gen), h - PAD.b); ctx.stroke();
298
+ }
299
+ }
300
+ ctx.setLineDash([]);
301
+ // x labels
302
+ [0, 30, 60, 89].forEach(function (g) {
303
+ ctx.fillText(String(g), X(g) - 6, h - 8);
304
+ });
305
+ // val line
306
+ ctx.strokeStyle = "#1f5fbf";
307
+ ctx.lineWidth = 2;
308
+ ctx.beginPath();
309
+ gens.forEach(function (g, i) {
310
+ var x = X(g.gen), y = Y(g.val);
311
+ if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
312
+ });
313
+ ctx.stroke();
314
+ // test points
315
+ ctx.fillStyle = "#c62828";
316
+ gens.forEach(function (g) {
317
+ if (g.test == null) return;
318
+ ctx.beginPath(); ctx.arc(X(g.gen), Y(g.test), 4.5, 0, 2 * Math.PI); ctx.fill();
319
+ });
320
+ // cursor
321
+ var cg = gens[idx];
322
+ ctx.strokeStyle = "#c96a11";
323
+ ctx.lineWidth = 1.5;
324
+ ctx.beginPath(); ctx.moveTo(X(cg.gen), PAD.t); ctx.lineTo(X(cg.gen), h - PAD.b); ctx.stroke();
325
+ ctx.fillStyle = "#c96a11";
326
+ ctx.beginPath(); ctx.arc(X(cg.gen), Y(cg.val), 5, 0, 2 * Math.PI); ctx.fill();
327
+ }
328
+
329
+ // ---------- panel ----------
330
+ function render() {
331
+ var g = gens[idx];
332
+ slider.value = idx;
333
+ document.getElementById("genLabel").textContent = "gen " + g.gen + " / " + (N - 1);
334
+ document.getElementById("gid").textContent = "Generation " + g.gen + " (epoch " + g.epoch + ")";
335
+
336
+ var chip = document.getElementById("moduleChip");
337
+ chip.textContent = "blamed: " + g.blamed;
338
+ chip.className = "chip " + g.blamed;
339
+
340
+ var badge = document.getElementById("acceptBadge");
341
+ badge.textContent = g.accepted ? "ACCEPTED" : "rejected";
342
+ badge.className = "badge " + (g.accepted ? "accepted" : "rejected");
343
+
344
+ document.getElementById("lineage").textContent = g.parent_id + " → " + g.child_id;
345
+ var delta = g.c - g.p;
346
+ var cls = delta > 0 ? "up" : (delta < 0 ? "down" : "");
347
+ document.getElementById("rewards").innerHTML =
348
+ fmt(g.p) + " → <span class='" + cls + "'>" + fmt(g.c) + "</span>";
349
+ document.getElementById("valScore").textContent = fmt(g.val);
350
+ var tw = document.getElementById("testWrap");
351
+ if (g.test != null) {
352
+ tw.style.display = "";
353
+ document.getElementById("testScore").textContent = fmt(g.test) + " (epoch end)";
354
+ } else {
355
+ tw.style.display = "none";
356
+ }
357
+ document.getElementById("popSize").textContent = g.pop;
358
+ document.getElementById("diag").textContent = g.diag || "(no diagnosis recorded)";
359
+ document.getElementById("diff").innerHTML = renderDiff(g.diff);
360
+ drawChart();
361
+ }
362
+
363
+ function goto(i) {
364
+ idx = Math.max(0, Math.min(N - 1, i));
365
+ render();
366
+ }
367
+ function stop() {
368
+ playing = false;
369
+ if (timer) { clearInterval(timer); timer = null; }
370
+ document.getElementById("btnPlay").innerHTML = "&#9654; Play";
371
+ }
372
+ function togglePlay() {
373
+ if (playing) { stop(); return; }
374
+ playing = true;
375
+ document.getElementById("btnPlay").innerHTML = "&#10074;&#10074; Pause";
376
+ timer = setInterval(function () {
377
+ if (idx >= N - 1) { stop(); return; }
378
+ goto(idx + 1);
379
+ }, 1200);
380
+ }
381
+
382
+ document.getElementById("btnPrev").addEventListener("click", function () { stop(); goto(idx - 1); });
383
+ document.getElementById("btnNext").addEventListener("click", function () { stop(); goto(idx + 1); });
384
+ document.getElementById("btnPlay").addEventListener("click", togglePlay);
385
+ slider.addEventListener("input", function () { stop(); goto(parseInt(slider.value, 10)); });
386
+ document.addEventListener("keydown", function (e) {
387
+ if (e.key === "ArrowLeft") { stop(); goto(idx - 1); e.preventDefault(); }
388
+ else if (e.key === "ArrowRight") { stop(); goto(idx + 1); e.preventDefault(); }
389
+ else if (e.key === " ") { togglePlay(); e.preventDefault(); }
390
+ });
391
+ window.addEventListener("resize", drawChart);
392
+
393
+ render();
394
+ })();
395
+ </script>
396
+ </body>
397
  </html>
static/replay_data.js ADDED
The diff for this file is too large to render. See raw diff