Skip to content

Instantly share code, notes, and snippets.

@arajkumar
Created August 5, 2026 06:20
Show Gist options
  • Select an option

  • Save arajkumar/04f5b06a2ac3cc8f736e9ab01235685b to your computer and use it in GitHub Desktop.

Select an option

Save arajkumar/04f5b06a2ac3cc8f736e9ab01235685b to your computer and use it in GitHub Desktop.
pi #7609 — interactive fix walkthrough: resume a failed turn from /tree
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>pi #7609 — the fix, step by step</title>
<style>
:root {
--bg: #0d1117; --panel: #161b22; --border: #30363d; --text: #e6edf3;
--dim: #8b949e; --blue: #58a6ff; --red: #f85149; --green: #3fb950;
--yellow: #d29922; --purple: #bc8cff; --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
* { box-sizing: border-box; }
body { background: var(--bg); color: var(--text); font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
margin: 0; line-height: 1.55; }
.wrap { max-width: 980px; margin: 0 auto; padding: 32px 24px 96px; }
h1 { font-size: 26px; margin: 0 0 4px; }
h2 { font-size: 20px; margin: 48px 0 12px; padding-top: 16px; border-top: 1px solid var(--border); }
h3 { font-size: 16px; margin: 24px 0 8px; color: var(--blue); }
a { color: var(--blue); }
code { font-family: var(--mono); font-size: 0.88em; background: #21262d; padding: 2px 5px; border-radius: 4px; }
pre { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 14px 16px;
overflow-x: auto; font-family: var(--mono); font-size: 12.5px; line-height: 1.5; }
pre code { background: none; padding: 0; }
.meta { color: var(--dim); font-size: 14px; margin-bottom: 8px; }
.pill { display: inline-block; font-family: var(--mono); font-size: 11.5px; padding: 2px 8px; border-radius: 10px;
border: 1px solid var(--border); background: var(--panel); color: var(--dim); margin-right: 6px; }
.file { color: var(--purple); font-family: var(--mono); font-size: 12.5px; }
/* --- interactive stepper --- */
.stage { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin: 16px 0; }
@media (max-width: 800px) { .stage { grid-template-columns: 1fr; } }
.pane { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 14px 16px; min-height: 220px; }
.pane h4 { margin: 0 0 10px; font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--dim); font-weight: 600; }
.tnode { font-family: var(--mono); font-size: 12.5px; border: 1px solid var(--border); border-radius: 6px;
padding: 5px 10px; margin: 4px 0; position: relative; background: #1c2128; transition: all .35s; width: fit-content; max-width: 100%; }
.tnode .role { color: var(--dim); margin-right: 6px; }
.tnode.user { border-color: var(--blue); }
.tnode.error { border-color: var(--red); color: #ffa198; }
.tnode.ok { border-color: var(--green); }
.tnode.abandoned { opacity: .45; border-style: dashed; }
.tnode.target { box-shadow: 0 0 0 2px var(--yellow); }
.tnode .leaf { position: absolute; right: -8px; top: 50%; transform: translate(100%, -50%);
font-size: 10.5px; background: var(--yellow); color: #111; border-radius: 4px; padding: 1px 6px; font-weight: 700; }
.tkids { margin-left: 22px; border-left: 1px solid var(--border); padding-left: 14px; }
.chat { font-family: var(--mono); font-size: 12.5px; }
.chat .u { color: var(--blue); margin: 6px 0; }
.chat .e { color: var(--red); margin: 6px 0; transition: opacity .35s; }
.chat .a { color: var(--green); margin: 6px 0; }
.chat .ghost { opacity: 0; }
.chat .cursor { color: var(--dim); }
.stepbar { display: flex; align-items: center; gap: 12px; margin: 14px 0 6px; position: sticky; top: 0;
background: var(--bg); padding: 10px 0; z-index: 5; }
.stepbar button { background: var(--panel); color: var(--text); border: 1px solid var(--border); border-radius: 6px;
padding: 6px 16px; font-size: 14px; cursor: pointer; }
.stepbar button:hover:not(:disabled) { border-color: var(--blue); }
.stepbar button:disabled { opacity: .35; cursor: default; }
.stepbar .dots { display: flex; gap: 6px; }
.stepbar .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--border); cursor: pointer; }
.stepbar .dot.on { background: var(--yellow); }
.stepdesc { background: #1c2128; border-left: 3px solid var(--yellow); border-radius: 0 6px 6px 0;
padding: 10px 14px; font-size: 14px; min-height: 66px; }
.stepdesc b { color: var(--yellow); }
table { border-collapse: collapse; width: 100%; font-size: 13.5px; margin: 10px 0; }
th, td { border: 1px solid var(--border); padding: 7px 10px; text-align: left; vertical-align: top; }
th { background: var(--panel); }
.anno { color: var(--dim); font-size: 13px; margin: 4px 0 0; }
.hl { background: rgba(210,153,34,.18); display: block; margin: 0 -16px; padding: 0 16px; }
.k { color: #ff7b72; } .s { color: #a5d6ff; } .c { color: var(--dim); } .f { color: #d2a8ff; }
ul { padding-left: 20px; } li { margin: 4px 0; }
body { padding: 24px; }
.wrap { max-width: 980px; margin: 0 auto; }
</style>
</head>
<body>
<div class="wrap">
<h2 style="border:none;margin-top:0;padding-top:0">Resume a failed turn from <code>/tree</code> — step by step</h2>
<p style="color:var(--dim);font-size:14px">Interactive walkthrough for <a href="https://github.com/earendil-works/pi/issues/7609">earendil-works/pi#7609</a>. Use ← → keys or the buttons.</p>
<div class="stepbar">
<button id="prev">← Prev</button>
<div class="dots" id="dots"></div>
<button id="next">Next →</button>
</div>
<div class="stepdesc" id="stepdesc"></div>
<div class="stage">
<div class="pane"><h4>Session tree</h4><div id="tree"></div></div>
<div class="pane"><h4>Chat (what you see)</h4><div class="chat" id="chat"></div></div>
</div>
</div>
<script>
const U1 = '<div class="tnode user"><span class="role">user</span>"Nice, what is the time?"{LEAF}</div>';
const E1 = '<div class="tnode error{AB}"><span class="role">assistant</span>✗ Connection error{LEAF}</div>';
const E2 = '<div class="tnode error{AB}"><span class="role">assistant</span>✗ Connection error{LEAF}</div>';
const A1 = '<div class="tnode ok"><span class="role">assistant</span>✓ "I can get the current time by running date…"{LEAF}</div>';
const LEAF = '<span class="leaf">LEAF</span>';
const fill = (t, o) => t.replace('{LEAF}', o.leaf ? LEAF : '').replace('{AB}', o.ab ? ' abandoned' : '') + (o.kids || '');
const wrap = k => '<div class="tkids">' + k + '</div>';
const steps = [
{
d: '<b>1 · Failure.</b> You ask the time; the network dies. Pi auto-retries in-session (attempt 1 → <i>error₁</i>, attempt 2 → <i>error₂</i>), each persisted as a child of the previous one. Retries exhausted → <code>Retry failed after 3 attempts</code>. Leaf = error₂.',
tree: () => fill(U1, {kids: wrap(fill(E1, {kids: wrap(fill(E2, {leaf:true}))}) )}),
chat: '<div class="u">› Nice, what is the time?</div><div class="e">✗ Error: Retry failed after 3 attempts: Connection error.</div>'
},
{
d: '<b>2 · You select error₂ in /tree</b> (double-Esc, Enter). <b>Before the fix:</b> leaf already there → <i>"Already at this point"</i>, or a dead-end error node with an empty editor. <b>After:</b> <code>beginFailedTurnRetry(error₂.id)</code> runs.',
tree: () => fill(U1, {kids: wrap(fill(E1, {kids: wrap(fill(E2, {leaf:true}))}) )}),
chat: '<div class="u">› Nice, what is the time?</div><div class="e">✗ Error: Retry failed after 3 attempts: Connection error.</div>'
},
{
d: '<b>3 · Walk past the chain.</b> error₂\'s parent is error₁ — also a failed attempt, keep walking. error₁\'s parent is the user message — the last good message. <b>Target = user.</b>',
tree: () => fill(U1, {kids: wrap(fill(E1, {kids: wrap(fill(E2, {leaf:true}))}) )}).replace('tnode user', 'tnode user target'),
chat: '<div class="u">› Nice, what is the time?</div><div class="e">✗ Error: Retry failed after 3 attempts: Connection error.</div>'
},
{
d: '<b>4 · <code>branch(user)</code> + rebuild.</b> The leaf jumps to your prompt; error₁/error₂ become an <b>abandoned branch</b> — off the leaf path, so excluded from model context. The UI now clears and re-renders the chat…',
tree: () => fill(U1, {leaf:true, kids: wrap(fill(E1, {ab:true, kids: wrap(fill(E2, {ab:true}))}) )}),
chat: '<div class="u">› Nice, what is the time?</div><div class="e ghost">✗ Error: Retry failed after 3 attempts: Connection error.</div>'
},
{
d: '<b>5 · …and the error is gone.</b> Nothing on the active branch renders it. Then <code>continueTurn()</code> calls <code>agent.continue()</code> — legal, since the leaf is a user message — with the normal post-run loop (retry, compaction).',
tree: () => fill(U1, {leaf:true, kids: wrap(fill(E1, {ab:true, kids: wrap(fill(E2, {ab:true}))}) )}),
chat: '<div class="u">› Nice, what is the time?</div><div class="cursor">▍ retrying…</div>'
},
{
d: '<b>6 · Done.</b> The retried response appends as a child of your prompt — a <b>sibling</b> of the abandoned errors, which stay visible in /tree as history. Final shape: <code>user → [error₁ → error₂ (abandoned), ✓ answer]</code>.',
tree: () => fill(U1, {kids: wrap(fill(E1, {ab:true, kids: wrap(fill(E2, {ab:true}))}) + fill(A1, {leaf:true}))}),
chat: '<div class="u">› Nice, what is the time?</div><div class="a">✓ I can get the current time by running the date command…</div>'
}
];
let cur = 0;
const dots = document.getElementById('dots');
steps.forEach((_, i) => {
const d = document.createElement('div');
d.className = 'dot'; d.onclick = () => go(i);
dots.appendChild(d);
});
function go(i) {
cur = Math.max(0, Math.min(steps.length - 1, i));
document.getElementById('stepdesc').innerHTML = steps[cur].d;
document.getElementById('tree').innerHTML = steps[cur].tree();
document.getElementById('chat').innerHTML = steps[cur].chat;
[...dots.children].forEach((d, j) => d.className = 'dot' + (j === cur ? ' on' : ''));
document.getElementById('prev').disabled = cur === 0;
document.getElementById('next').disabled = cur === steps.length - 1;
}
document.getElementById('prev').onclick = () => go(cur - 1);
document.getElementById('next').onclick = () => go(cur + 1);
document.addEventListener('keydown', e => {
if (e.key === 'ArrowRight') go(cur + 1);
if (e.key === 'ArrowLeft') go(cur - 1);
});
go(0);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment