fix(session): persist the delegation depth in the session header

A subagent child's recursion depth lived only in runtime AgentOptions,
so a persisted child came back from resume counted as top-level and
maxDepth stopped binding after every restart. Add
SessionHeader.delegationDepth, round-trip it through the JSONL and
SQLite backends (SQLite schema v5), restore it on agent-loop resume,
and write it when the in-process backends create a child. The seam now
owns the shared depth vocabulary (delegationDepthOf): the persisted
header is authoritative and monotone — runtime options may deepen it
but never lower it.
This commit is contained in:
Yichen Jiang
2026-07-19 17:20:36 +08:00
parent e05e7a0870
commit 0d00106fa8
29 changed files with 229 additions and 106 deletions

View File

@@ -8,7 +8,7 @@ This package is the shared run driver for the two in-process providers. Spawn pa
The driver follows this sequence:
1. Validate the parent depth and optional absolute `maxDepth`, then derive child depth as parent depth plus one.
1. Validate the parent depth and optional absolute `maxDepth`, then derive child depth as parent depth plus one and persist it in the child session header.
2. Call `parent.ctx.agents.create` directly, passing the required request signal into the factory's creation transaction.
3. During that transaction's unpublished setup window, install the requested persona, tool restriction, and structured-output runtime.
4. Publish the child, retain the returned `AgentHandle`, and drive one task with `child.send(prompt)` followed by `child.whenIdle()`.
@@ -26,7 +26,7 @@ After fulfillment, the caller owns the run. Provider-plugin unload does not revo
`InProcessRunOptions` is `{ seed?: SessionEvent[] }`. Spawn omits it. Fork supplies a balanced completed-turn prefix and records its length so the result reader never mistakes a seeded parent message for child output.
Depth enforcement is internal to `startInProcessRun`: it reads `AgentOptions.subagentDepth`, treats absence as top-level depth zero, rejects malformed stored values, and reports an attempted child depth above `maxDepth`. An unrepresentable depth above the safe-integer domain is a `RangeError`.
Depth enforcement is internal to `startInProcessRun`: it reads the parent depth via `delegationDepthOf` (the persisted `SessionHeader.delegationDepth` is authoritative; runtime `AgentOptions.subagentDepth` may deepen but never lower it, so a resumed child keeps its budget), treats absence as top-level depth zero, rejects malformed stored values, and reports an attempted child depth above `maxDepth`. An unrepresentable depth above the safe-integer domain is a `RangeError`. The child depth is written to the child header, so it survives persistence and resume.
## Structured output