fix: fork subagents recursed forever in the Claude Code export
A fork subagent's transcript opens with a copy of the parent turn that spawned it, its own Agent call included; folding that call re-entered the same fork until RecursionError, failing every daily sync since 2026-09-24. Skip a spawn call while its own subagent is being expanded, and strip the <fork-boilerplate> preamble. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LbnmGHnFqDjyhPcCg1SEfF
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b6ce636891
commit
64068bb19b
@@ -370,6 +370,59 @@ class TestSubagentFold:
|
||||
]
|
||||
assert "stray sidechain" not in top_text
|
||||
|
||||
def test_fork_containing_its_own_spawn_call(self, tmp_path):
|
||||
# The shape Claude Code writes for a `fork` subagent: a context-ref
|
||||
# record, a copy of the parent turn holding the fork's own spawn call,
|
||||
# then the directive behind <fork-boilerplate>. Folding that copied
|
||||
# call recursed until RecursionError.
|
||||
fork_records = [
|
||||
{"type": "fork-context-ref", "agentId": "a1", "parentLastUuid": "u0"},
|
||||
{
|
||||
"type": "assistant", "isSidechain": True,
|
||||
"message": {"role": "assistant", "content": [
|
||||
{"type": "tool_use", "id": "toolu_sub1", "name": "Agent",
|
||||
"input": {"description": "research"}},
|
||||
]},
|
||||
},
|
||||
{
|
||||
"type": "user", "isSidechain": True,
|
||||
"timestamp": "2026-05-01T10:00:06.000Z",
|
||||
"message": {"role": "user", "content": [
|
||||
{"type": "tool_result", "tool_use_id": "toolu_sub1",
|
||||
"content": [{"type": "text", "text": "Fork started"}]},
|
||||
{"type": "text", "text":
|
||||
"<fork-boilerplate>\nYou are a worker fork.\n"
|
||||
"</fork-boilerplate>\n\nYour directive: research X"},
|
||||
]},
|
||||
},
|
||||
{
|
||||
"type": "assistant", "isSidechain": True,
|
||||
"timestamp": "2026-05-01T10:00:07.000Z",
|
||||
"message": {"role": "assistant", "content": [
|
||||
{"type": "text", "text": "Fork result."},
|
||||
]},
|
||||
},
|
||||
]
|
||||
f = _write_session(tmp_path, _parent_with_task(), name="parent-3")
|
||||
_write_subagent(
|
||||
f, "toolu_sub1", fork_records,
|
||||
agent_type="fork", description="research X",
|
||||
)
|
||||
p = self._provider(tmp_path)
|
||||
p.fetch_all_conversations()
|
||||
conv = p.normalize_conversation(p.get_conversation("parent-3"))
|
||||
|
||||
subs = [
|
||||
b for m in conv["messages"] for b in m["blocks"] if b["type"] == "subagent"
|
||||
]
|
||||
assert len(subs) == 1
|
||||
inner = [bb for m in subs[0]["messages"] for bb in m["blocks"]]
|
||||
assert not any(b["type"] == "subagent" for b in inner)
|
||||
inner_text = [b.get("text") for b in inner]
|
||||
assert "Your directive: research X" in inner_text
|
||||
assert "Fork result." in inner_text
|
||||
assert not any("worker fork" in (t or "") for t in inner_text)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Repo tags in title (Part C)
|
||||
|
||||
Reference in New Issue
Block a user