feat(web): rewrite subagent conversations for FIFO activation

This commit is contained in:
Dudu-0223
2026-07-30 23:33:07 +08:00
committed by Tianyi Cui
parent f0ab04273d
commit 8a518e353b
52 changed files with 829 additions and 420 deletions
@@ -93,7 +93,13 @@ async function bench() {
ctx.provide('conversation', {})
ctx.provide('locale', new LocaleService(ctx))
const scopes = new Map<SessionId, Context>()
ctx.provide('sessions', { scope: (id: SessionId) => scopes.get(id) })
const addressed = new Set<SessionId>()
ctx.provide('sessions', {
scope: (id: SessionId) => scopes.get(id),
subagentAddress: (id: SessionId) => addressed.has(id)
? { parentSessionId: sid('parent'), childSessionId: id, mode: 'continuable' as const }
: undefined,
})
const fiber = ctx.plugin({ inject: [...inject], apply })
await fiber.await()
await ctx.plugin(function probe() {}).await()
@@ -108,6 +114,7 @@ async function bench() {
seat: () => seats.get('conversation.input.model')!,
hostCurrent: () => current,
setHostCurrent: (target: ModelTarget) => { current = target },
address: (id: SessionId) => { addressed.add(id) },
}
}
@@ -214,4 +221,30 @@ describe('ui-model dual entry', () => {
const b = await bench()
expect(() => b.seat().inject!(sid('ghost'))).toThrow(/resolved no scope/)
})
it('withholds both model entries from addressed subagent sessions without Agent-bound RPCs', async () => {
const b = await bench()
b.mint('child')
b.address(sid('child'))
expect(b.contribution().available(projection('child'))).toBe(false)
await expect(b.contribution().ui.options(
projection('child'),
new AbortController().signal,
)).rejects.toThrow(/unavailable for addressed subagent/)
const face = b.seat().inject!(sid('child'))
expect(face.available).toBe(false)
face.load()
await expect(face.select({ provider: 'deepseek', model: 'deepseek-v4-pro' })).resolves.toBe(false)
await expect(b.ctx.models.directoryFor(sid('child')).load())
.rejects.toThrow(/unavailable for addressed subagent/)
await expect(b.ctx.models.directoryFor(sid('child')).select({
provider: 'deepseek',
model: 'deepseek-v4-pro',
})).rejects.toThrow(/unavailable for addressed subagent/)
b.ctx.emit('connection/reset')
await Promise.resolve()
expect(b.calls).toEqual({ models: 0, select: 0 })
})
})