Merge remote-tracking branch 'origin/worktree/agent-execution-context-rfc' into codex/simplify-agent-identity-plumbing

# Conflicts:
#	docs/rfc/implemented/architecture/2026-07-15-agent-initiator-scope.i18n.yaml
#	docs/rfc/implemented/architecture/2026-07-15-agent-initiator-scope.md
#	docs/rfc/implemented/architecture/2026-07-15-agent-initiator-scope.zh.md
This commit is contained in:
Tianyi Cui
2026-07-19 14:18:58 +08:00
5 changed files with 9 additions and 9 deletions

View File

@@ -142,7 +142,7 @@ describe('AgentLoop initiator scope', () => {
await ctx.fiber.dispose()
})
it('keeps child setup under the parent boundary, switches for the child driver, then restores the parent', async () => {
it('keeps child setup under the parent boundary and restores the parent while the child driver remains active', async () => {
const adapter = new MockAdapter([
toolCallResponse('spawn', 'spawn-child', {}),
toolCallResponse('observe', 'observe-child', {}),
@@ -153,7 +153,7 @@ describe('AgentLoop initiator scope', () => {
let parentDuringSetup: Agent | undefined
let explicitChild: Agent | undefined
let childDuringDriver: Agent | undefined
let parentAfterChild: Agent | undefined
let parentWhileChildDriverActive: Agent | undefined
let child: Agent | undefined
ctx.tools.register(defineTool({
@@ -181,9 +181,9 @@ describe('AgentLoop initiator scope', () => {
},
})
child = handle.agent
parentWhileChildDriverActive = ctx.agents.requireInitiator()
send(handle.agent, 'run child')
await handle.agent.whenIdle()
parentAfterChild = ctx.agents.requireInitiator()
await handle.dispose()
return [{ type: 'text', text: 'child completed' }]
},
@@ -200,7 +200,7 @@ describe('AgentLoop initiator scope', () => {
expect(parentDuringSetup).toBe(parentHandle.agent)
expect(explicitChild).toBe(child)
expect(childDuringDriver).toBe(child)
expect(parentAfterChild).toBe(parentHandle.agent)
expect(parentWhileChildDriverActive).toBe(parentHandle.agent)
expect(ctx.agents.currentInitiator()).toBeUndefined()
await parentHandle.dispose()
await ctx.fiber.dispose()

View File

@@ -19,7 +19,7 @@ The scoped-registration surface: `Agent.ctx` is the agent's scope context (`dsh-
#### Initiating Agent scope
`AgentLoop` runs each concrete driver's complete lifetime inside an initiator boundary. Concurrent drivers remain isolated, a child driver shadows its parent, and the parent returns after the child settles. Creation, persistence load, and unpublished setup remain outside the child's boundary, so setup initiated by a parent inherits the parent while `agentCtx.agent` identifies the child explicitly.
`AgentLoop` runs each concrete driver's complete lifetime inside an initiator boundary. Concurrent drivers remain isolated: a child driver's continuations carry the child, while the parent continuation regains the parent as soon as `withInitiator()` returns; drain tracking continues until the child driver's Promise settles. Creation, persistence load, and unpublished setup remain outside the child's boundary, so setup initiated by a parent inherits the parent while `agentCtx.agent` identifies the child explicitly.
- `ctx.agents.currentInitiator(): Agent | undefined` — read the inherited initiator without requiring one.
- `ctx.agents.requireInitiator(): Agent` — read it or throw `no initiating agent is active`.