fix(web): compose a forked session, and give the shell realm its provider

Two consequences of moving the agent plane behind presets, both invisible
until the host plane stopped carrying model-facing rows.

`sessions.fork` built its child with a bare `installTarget` and a `meta`
without `agentPreset`. That was harmless while every tool sat in the host
plane — the child inherited them for free. It now comes up with an EMPTY
tool set. The child composes the parent's preset instead, for the same
reason a resumed session keeps its own: the seeded history was produced
under those tools.

`bashEnv` lives in its own `dsh-bash-env` row rather than inside
`tool-bash`, so a preset that isolates the realm must compose the provider
beside its consumer; the host row is disabled here like every other
model-facing one. Nothing outside the agent plane injects `bashEnv`, so it
stays per-session.
This commit is contained in:
Yichen Jiang
2026-08-05 15:40:32 +08:00
parent 3d68185480
commit 25b6381c84
5 changed files with 53 additions and 1 deletions

View File

@@ -1898,6 +1898,12 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
})
}
const childId = `session-${randomUUID()}` as SessionId
// The child inherits the parent's composition for the same reason a
// resumed session keeps its own: the seeded history was produced under
// those tools, and composing anything else would strand the tool calls
// it already carries. Now that no model-facing row sits in the host
// plane, composing nothing would leave the child with no tools at all.
const forkComposition = await composeAgent(source.header.agentPreset)
try {
await ctx.agents.create({
sessionId: childId,
@@ -1906,9 +1912,12 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
...source.header.cwd === undefined ? {} : { cwd: source.header.cwd },
parentSession: source.id,
seedLength: cut,
...forkComposition.agentPreset === undefined
? {}
: { agentPreset: forkComposition.agentPreset },
},
agentOptions,
setup: installTarget,
setup: forkComposition.setup,
})
} catch (error: unknown) {
return err(request, {