feat(babysitter): resume the previous wake's agent session on a reused box (F4)

Merged
KH
17d ago
+602-25

Rebased on main after #635 and #636 merged; the diff is the Babysitter part only: examples/babysitter/{fix,fixer}.ts, the tests, FIXER.md, the rebuilt fixer artifact and the evidence.

This is the last piece of Khaliq's ask: on a wake for new PR feedback, the same sandbox, the same checkout and dependencies, and now the same agent session, so the agent keeps the earlier wake's reading of the code on top of the original intent.

Behaviour

  • Recording: stashCheckout writes the agent's sessionId beside the PR checkout cache, or removes it when the agent reported none, so a stale session is never kept.
  • Restoring: restoreCheckout returns that session only when it restored the checkout on this box.
  • Resuming: the fixer resumes the session when it belongs to the origin's CLI, and never resumes another CLI's session.
  • Fallback: a session the CLI no longer has fails that step (Claude: "No conversation found"). The run then continues with a fresh babysitter-fix-fresh agent, which carries the origin context in its task either way. A stale session can't fail a run.
  • Audit: the cli/model pairs stay literal. resume is a plain property, because f.agent treats undefined as absent, so the unmodified shipped-source audit resolves every call.
    • My first attempt used a conditional spread, which the audit refused as unprovable. That capture is evidence/f4-fixer-resume/05a.

Evidence (examples/babysitter/evidence/f4-fixer-resume/)

Red, before the adoption:

✖ a restored PR checkout brings back its session, and a stash records the new one (1.970079ms)
✖ a session the CLI no longer has falls back to a fresh agent with the origin context (0.599917ms)
✖ a wake on a reused box resumes the previous agent session and records the new one (0.856034ms)
✖ failing tests:
ℹ fail 3
ℹ pass 26
  • 02: 145 tests, 138 pass, 0 fail, 7 todo.
  • 03: digests reproduce. Standalone is unchanged at 580bab1d…; fixer is 23ad283edac047a601f40f62da3f82baf6466ccd834dae7806e5b002da8b5e5b.
  • 04: flows check passes, run with #636's SDK build because this worktree's build predates the option.
  • 05: shipped-source audit 2/2, file unmodified.
  • 06: filtered-count=0.

Rollout notes

  • The fixer runs on the sandbox's installed SDK. An SDK without #636 drops resume (it builds the step spec from an explicit list), so that wake simply starts fresh. Resume takes effect once a release with #636 is in the sandbox image.
  • cloud#4348 (merged) already pins this fixer digest, 23ad283edac047a601f40f62da3f82baf6466ccd834dae7806e5b002da8b5e5b; node examples/babysitter/build-standalone.mjs --check reproduces it at this head.

🤖 Generated with Claude Code


Summary by cubic

Makes the Babysitter fixer resume the previous wake's agent session when it restores the PR checkout in a reused sandbox, so a later step continues the CLI session an earlier step recorded instead of starting cold.

Babysitter fixer adoption

  • stashCheckout records the run's sessionId beside the PR checkout cache and removes it when the agent reported none; restoreCheckout returns it only when it restored the checkout on that box.
  • The fixer resumes the session only when it belongs to the origin's CLI; a session the CLI no longer has falls back to a fresh agent that still carries the origin context, so a stale session can't fail a run.
  • On a sandbox whose SDK lacks resume, that wake simply starts fresh.

Agent Relay sessions

  • claude session 497569fc · opened via gh pr create · last active 2026-10-09

[!NOTE]
Medium Risk
Changes cross-run agent dispatch and persists session IDs on the sandbox filesystem; behavior depends on SDK resume support (#636) but falls back to a fresh agent when resume fails or the CLI mismatches.

Overview
On a reused sandbox, the Babysitter fixer now continues the previous wake’s agent session alongside the cached PR checkout, so follow-up fixes keep the earlier code context plus the original task intent.

Checkout cache: stashCheckout writes checkout.session.json with { cli, sessionId } (or deletes it when the agent reports no session). restoreCheckout returns that session only when it successfully restores the cached checkout. restore / stash wrappers pass session data through the journaled f.run steps.

Fixer flow: After restore, the fixer calls f.agent('babysitter-fix', …, resume) when the cached CLI matches the origin source; otherwise it starts cold. If resume throws, it logs and retries with babysitter-fix-fresh (same task/origin context, no resume). The run’s new sessionId is stashed in finally for the next wake.

Docs, tests, artifact: FIXER.md documents session resume; fixer.test.ts adds restore/stash/resume/fallback cases; the bundled fixer artifact and manifest digest are updated; evidence/f4-fixer-resume/ captures red→green test output.

Reviewed by Cursor Bugbot for commit 5b5f5a02830e94d8e41521c72d0f768e1611e702. Bugbot is set up for automated code reviews on this repo. Configure here.