Skip to content

Commit 2885e0c

Browse files
kapaleshreyasclaude
andcommitted
feat(sandboxes): reject harness=deepagents at the warm-sandbox door
The cross-harness suite proved deepagents has an engine-level conversation persistence gap: its LangGraph checkpointer is in-memory only, not bridged to the SessionStore protocol the way claude-agent-sdk and gitagent are. Verified scenarios (sessionStore:mongo + sessionId pinned through restore): claude-agent-sdk: AURORA-42 recalled after restore ✓ gitagent: AURORA-42 recalled after restore ✓ deepagents: "This appears to be the start of our conversation" ✗ Rather than ship a sandbox surface that's half-broken for one of three harnesses, gate at the door: POST /sandboxes with harness=deepagents → 400 { code: HARNESS_NOT_SUPPORTED, message: "...use /run or /tasks..." } Also gate POST /sandboxes/restore on snapshot.config.harness=deepagents (blocks any pre-existing deepagents snapshots from being revived). Multi-turn warmth WITHIN a single live deepagents sandbox works fine — the gap only surfaces across snapshot/restore. But the warm-pool feature contract IS persistence-friendly (autoSave on dispose, etc.), so partial support would be a footgun. Refuse cleanly with a helpful redirect to the right surface (/run + /tasks both work for deepagents one-shot work). Closing the gap is a future wedge: bridge engine-deepagents' MemorySaver checkpointer to SessionStore the way engine-claude-agent-sdk already does. Mechanical work; substantial scope. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 5e2816c commit 2885e0c

1 file changed

Lines changed: 29 additions & 0 deletions

File tree

examples/computeragent-server.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,18 @@ export class ComputerAgentServer {
13901390
const snap = await store.load(body.snapshotId);
13911391
if (!snap) return c.json({ error: { code: "NOT_FOUND", snapshotId: body.snapshotId } }, 404);
13921392

1393+
// Same gate as POST /sandboxes — if the snapshot was taken with
1394+
// harness=deepagents (only possible from before the gate was added),
1395+
// refuse to restore. The conversation wouldn't survive anyway.
1396+
if ((snap.config as { harness?: string } | undefined)?.harness === "deepagents") {
1397+
return c.json({
1398+
error: {
1399+
code: "HARNESS_NOT_SUPPORTED",
1400+
message: "Restore refused: snapshot's harness is deepagents, which the warm-sandbox surface does not support. The captured workdir survives but the conversation does not. Use POST /run with attachments if you need the workdir bytes only.",
1401+
},
1402+
}, 400);
1403+
}
1404+
13931405
try {
13941406
if (!body.target || body.target === "new") {
13951407
// Fresh slot. Reconstruct a SandboxBody from the snapshot's config
@@ -1962,6 +1974,23 @@ function validateSandboxBody(body: unknown): { code: string; message: string } |
19621974
if (!b.harness || typeof b.harness !== "string") {
19631975
return { code: "MISSING_HARNESS", message: "harness is required (e.g. 'claude-agent-sdk')" };
19641976
}
1977+
// ── Warm-sandbox gate (Wedge 1.13 follow-up) ───────────────────────────
1978+
// Deepagents' LangGraph checkpointer is fully in-memory and isn't bridged
1979+
// to the SessionStore protocol the way claude-agent-sdk + gitagent are.
1980+
// That means:
1981+
// - multi-turn within ONE warm sandbox WORKS (verified, in-memory state
1982+
// persists across chat() calls)
1983+
// - BUT snapshot → restore loses the conversation
1984+
// Cross-harness suite verified this end-to-end. Until engine-deepagents
1985+
// bridges its checkpointer (a substantial follow-up wedge), the warm
1986+
// sandbox surface refuses deepagents at the door. Users get /run + /tasks
1987+
// for one-shot work, which doesn't depend on the missing bridge.
1988+
if (b.harness === "deepagents") {
1989+
return {
1990+
code: "HARNESS_NOT_SUPPORTED",
1991+
message: "Warm sandboxes are not yet supported for harness=deepagents. The LangGraph checkpointer state isn't bridged to SessionStore, so conversation is lost on snapshot/restore. Use POST /run or POST /tasks for deepagents one-shot work.",
1992+
};
1993+
}
19651994
return undefined;
19661995
}
19671996

0 commit comments

Comments
 (0)