mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
test: cover the agent-preset wire routes and both restore edges
master moved the RPC surface onto the fetch transport, so the two agentPreset methods arrived there with nothing driving them. Adds the round trip, plus the two `recompose` edges that had none: an agent that never composed a preset, so there is nothing to restore, and a restore that fails because the composition it reaches for is gone — the roster is a live directory. Marks the deliberate non-Error rejections in the store specs, which is the branch they exist to cover.
This commit is contained in:
@@ -169,6 +169,7 @@ describe('the agent-preset settings controller', () => {
|
||||
describe: () => Promise.resolve({
|
||||
rpcId: 'r', result: { ok: true as const, value: { writable: true, hasDocument: true, namespaces: [] } },
|
||||
}),
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors -- the non-Error branch is what this covers
|
||||
update: () => Promise.reject(value),
|
||||
},
|
||||
} as unknown as IApiClient)
|
||||
@@ -181,6 +182,7 @@ describe('the agent-preset settings controller', () => {
|
||||
expect(controller.store.getSnapshot().error).toBe('socket closed')
|
||||
|
||||
const failing = new AgentPresetSettingsController({
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors -- the non-Error branch is what this covers
|
||||
agentPresets: { list: () => Promise.reject('offline') },
|
||||
settings: {
|
||||
describe: () => Promise.resolve({
|
||||
@@ -368,7 +370,9 @@ describe('the composer seat controller', () => {
|
||||
it('reads a rejection that is not an Error', async () => {
|
||||
const api = {
|
||||
agentPresets: {
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors -- the non-Error branch is what this covers
|
||||
list: () => Promise.reject('offline'),
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors -- the non-Error branch is what this covers
|
||||
select: () => Promise.reject('socket closed'),
|
||||
},
|
||||
} as unknown as IApiClient
|
||||
|
||||
@@ -226,6 +226,18 @@ describe('unary round trip', () => {
|
||||
expect(appended.result.ok).toBe(true)
|
||||
})
|
||||
|
||||
it('routes the agent-preset roster and switch through the wire', async () => {
|
||||
const c = client(scriptedApi())
|
||||
|
||||
const listed = await c.agentPresets.list({})
|
||||
expect(listed.result).toEqual({ ok: true, value: { presets: [] } })
|
||||
|
||||
// The switch carries the session it is about: the host refuses one whose
|
||||
// conversation has started, and it can only know which by id.
|
||||
const selected = await c.agentPresets.select({ sessionId: sid('s1'), agentPreset: 'standard' })
|
||||
expect(selected.result).toEqual({ ok: true, value: { agentPreset: 'standard' } })
|
||||
})
|
||||
|
||||
it('passes business errors through as 200 + err result, not a throw', async () => {
|
||||
const api = scriptedApi({
|
||||
sessions: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mkdir, mkdtemp, readFile, writeFile } from 'node:fs/promises'
|
||||
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url'
|
||||
@@ -331,6 +331,53 @@ describe('replacing a composition', () => {
|
||||
expect(toolNames(ctx, handle.agent)).toEqual(['alpha'])
|
||||
})
|
||||
|
||||
it('leaves an agent that never composed one with nothing to restore', async () => {
|
||||
const handle = await ctx.agents.create({ sessionId: SessionId('sess-bare') })
|
||||
|
||||
await expect(ctx.agentPresets.recompose(handle.agent.ctx, 'broken'))
|
||||
.rejects.toThrow(/failed to mount/)
|
||||
|
||||
// There was no previous composition to put back, so the failure is the
|
||||
// whole outcome — not a restore that silently invents one.
|
||||
expect(toolNames(ctx, handle.agent)).toEqual([])
|
||||
})
|
||||
|
||||
it('reports the switch failure when the restore fails too', async () => {
|
||||
// A preset root this test owns, so removing the composition mid-flight
|
||||
// cannot disturb the shipped fixtures.
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-preset-restore-'))
|
||||
const seeded: [string, string][] = [['first', `- id: only\n name: ${join(FIXTURES, 'plugins', 'contribute.js')}\n config:\n tool: only\n`], ['broken', '- id: nope\n name: ./does-not-exist.js\n']]
|
||||
for (const [id, body] of seeded) {
|
||||
await mkdir(join(root, id))
|
||||
await writeFile(join(root, id, COMPOSITION_FILE), body)
|
||||
}
|
||||
const scoped = new Context()
|
||||
scoped.baseUrl = pathToFileURL(FIXTURES).href + '/'
|
||||
await scoped.plugin(Loader)
|
||||
scoped.loader.builtins.include = Include
|
||||
await scoped.plugin(LlmService)
|
||||
await scoped.plugin(SessionStore)
|
||||
await scoped.plugin(SystemPrompt, { persona: '' })
|
||||
await scoped.plugin(ToolRegistry)
|
||||
await scoped.plugin(AgentRegistry)
|
||||
await scoped.plugin(AgentLoop, { agents: [] })
|
||||
await scoped.plugin(AgentPresets, { default: 'first', roots: [{ path: root, trust: 'user' as const }] })
|
||||
const handle = await scoped.agents.create({
|
||||
sessionId: SessionId('sess-restore-gone'),
|
||||
setup: async (agentCtx: Context) => void await scoped.agentPresets.mount(agentCtx, 'first'),
|
||||
})
|
||||
|
||||
// The roster is a live directory: the composition the agent came from can
|
||||
// be gone by the time the restore reaches for it.
|
||||
await rm(join(root, 'first'), { recursive: true })
|
||||
|
||||
await expect(scoped.agentPresets.recompose(handle.agent.ctx, 'broken'))
|
||||
.rejects.toThrow(/failed to mount/)
|
||||
|
||||
// The switch failure is the actionable one; the restore's is swallowed.
|
||||
expect(toolNames(scoped, handle.agent)).toEqual([])
|
||||
})
|
||||
|
||||
it('refuses an unscoped context', async () => {
|
||||
await expect(ctx.agentPresets.recompose(ctx, 'minimal'))
|
||||
.rejects.toThrow(/unscoped context/)
|
||||
|
||||
Reference in New Issue
Block a user