Merge remote-tracking branch 'origin/master' into worktree/custom-deepseek-models
# Conflicts: # apps/web/tests/snapshots/message-actions/ui.expected.md # apps/web/tests/snapshots/seeded-history/command-row.expected.md # apps/web/tests/snapshots/seeded-history/ui.expected.md # packages/client/ui-model/README.i18n.yaml # packages/client/ui-model/README.md # packages/client/ui-model/README.zh.md # packages/client/ui-model/tests/model-select.spec.tsx # packages/host/apiproxy/README.i18n.yaml
This commit is contained in:
@@ -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 })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -55,6 +55,7 @@ describe('ModelSelect reasoning effort', () => {
|
||||
})
|
||||
render(<ModelSelect
|
||||
locked={false}
|
||||
available
|
||||
directory={directory}
|
||||
load={vi.fn()}
|
||||
select={select}
|
||||
@@ -95,6 +96,7 @@ describe('ModelSelect reasoning effort', () => {
|
||||
}))
|
||||
render(<ModelSelect
|
||||
locked={false}
|
||||
available
|
||||
directory={directory}
|
||||
load={vi.fn()}
|
||||
select={vi.fn().mockResolvedValue(true)}
|
||||
@@ -116,6 +118,7 @@ describe('ModelSelect reasoning effort', () => {
|
||||
const select = vi.fn().mockResolvedValue(true)
|
||||
render(<ModelSelect
|
||||
locked={false}
|
||||
available
|
||||
directory={directory}
|
||||
load={vi.fn()}
|
||||
select={select}
|
||||
@@ -130,4 +133,19 @@ describe('ModelSelect reasoning effort', () => {
|
||||
expect(screen.queryByText('removed-model')).toBeNull()
|
||||
expect(screen.getByRole('menuitemradio', { name: 'DeepSeek-V4-Flash' })).toBeTruthy()
|
||||
})
|
||||
|
||||
it('renders no Agent-bound control for an addressed subagent session', () => {
|
||||
const load = vi.fn()
|
||||
render(<ModelSelect
|
||||
locked={false}
|
||||
available={false}
|
||||
directory={createSnapshotStore(state())}
|
||||
load={load}
|
||||
select={vi.fn().mockResolvedValue(false)}
|
||||
t={t}
|
||||
/>)
|
||||
|
||||
expect(screen.queryByRole('button')).toBeNull()
|
||||
expect(load).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user