* Create and run a durable linked child Session without changing the * parent-facing agent_spawn compatibility path. * * Cross-session provenance lives on the child header. The first AgentRun * intentionally carries no parentRunId, so it is an ordinary session-inline * run and every l
(
parentSessionId: string,
input: SpawnChildSessionInput,
)
| 2369 | * run and every later child turn can reuse only the child's own history. |
| 2370 | */ |
| 2371 | async spawnChildSession( |
| 2372 | parentSessionId: string, |
| 2373 | input: SpawnChildSessionInput, |
| 2374 | ): Promise<SpawnChildSessionResult> { |
| 2375 | const resolvedInput = await this.resolveChildSessionSelector(input); |
| 2376 | const spawnKey = childSessionSpawnKey(parentSessionId, resolvedInput); |
| 2377 | const requestFingerprint = childSessionRequestFingerprint(parentSessionId, resolvedInput); |
| 2378 | const inFlight = this.childSessionSpawns.get(spawnKey); |
| 2379 | if (inFlight) { |
| 2380 | if (inFlight.requestFingerprint !== requestFingerprint) { |
| 2381 | throw new Error('Child-session spawn identity was reused for different work'); |
| 2382 | } |
| 2383 | return await inFlight.promise; |
| 2384 | } |
| 2385 | const runtimeOwner = { |
| 2386 | execution: this.runtimeKernel.claimExecution(parentSessionId), |
| 2387 | }; |
| 2388 | const promise = this.spawnChildSessionOnce( |
| 2389 | parentSessionId, |
| 2390 | resolvedInput, |
| 2391 | requestFingerprint, |
| 2392 | runtimeOwner, |
| 2393 | ).finally(() => runtimeOwner.execution.release()); |
| 2394 | this.childSessionSpawns.set(spawnKey, { requestFingerprint, promise }); |
| 2395 | try { |
| 2396 | return await promise; |
| 2397 | } finally { |
| 2398 | if (this.childSessionSpawns.get(spawnKey)?.promise === promise) { |
| 2399 | this.childSessionSpawns.delete(spawnKey); |
| 2400 | } |
| 2401 | } |
| 2402 | } |
| 2403 | |
| 2404 | private async resolveChildSessionSelector( |
| 2405 | input: SpawnChildSessionInput, |
no test coverage detected