mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
test: cover project instruction configuration branches
This commit is contained in:
@@ -128,6 +128,16 @@ describe('dsh-agent-core bundle', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('supports direct apply with project instructions disabled and no forwarded agents', async () => {
|
||||
const ctx = new Context()
|
||||
agentCore.apply(ctx, { projectInstructions: false })
|
||||
await new Promise(resolve => setTimeout(resolve, 50))
|
||||
|
||||
expect(ctx.get('agents')?.list()).toEqual([])
|
||||
expect(ctx.get('systemPrompt')).toBeDefined()
|
||||
await ctx.fiber.dispose()
|
||||
})
|
||||
|
||||
it('re-exports the loop config schema as its own', () => {
|
||||
expect(agentCore.Config).toBeDefined()
|
||||
expect(agentCore.name).toBe('agent-core')
|
||||
|
||||
@@ -150,6 +150,7 @@ function ancestorChain(root: string, cwd: string): string[] {
|
||||
while (current !== resolvedRoot) {
|
||||
chain.push(current)
|
||||
const parent = dirname(current)
|
||||
/* v8 ignore next -- defensive guard for direct helper misuse; discovery always passes cwd or an ancestor root. */
|
||||
if (parent === current) break
|
||||
current = parent
|
||||
}
|
||||
|
||||
@@ -195,6 +195,24 @@ describe('project instruction discovery', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('labels the default DSH home as ~/.dsh when HOME points at the configured default', async () => {
|
||||
const root = await tempRepo()
|
||||
const home = await tempRepo()
|
||||
const previousHome = process.env.HOME
|
||||
try {
|
||||
process.env.HOME = home
|
||||
await write(join(home, '.dsh/AGENTS.md'), 'global default rule')
|
||||
|
||||
const files = await discoverBaselineInstructionFiles({ cwd: root })
|
||||
|
||||
expect(files.map(file => file.displayPath)).toEqual(['~/.dsh/AGENTS.md'])
|
||||
} finally {
|
||||
process.env.HOME = previousHome
|
||||
await rm(root, { recursive: true, force: true })
|
||||
await rm(home, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('ignores instruction candidates that are directories', async () => {
|
||||
const root = await tempRepo()
|
||||
const home = await tempRepo()
|
||||
@@ -280,6 +298,38 @@ describe('project instruction rendering', () => {
|
||||
expect(rendered.truncated[0]!.includedBytes).toBeGreaterThan(0)
|
||||
expect(Buffer.byteLength(rendered.text, 'utf8')).toBeLessThanOrEqual(700)
|
||||
})
|
||||
|
||||
it('omits all text when the render budget is disabled', () => {
|
||||
const rendered = renderProjectInstructions([
|
||||
{ absolutePath: '/repo/AGENTS.md', displayPath: 'AGENTS.md', content: 'root rules' },
|
||||
], { maxBytes: 0 })
|
||||
|
||||
expect(rendered).toEqual({
|
||||
text: '',
|
||||
omitted: [{ absolutePath: '/repo/AGENTS.md', displayPath: 'AGENTS.md', content: 'root rules' }],
|
||||
truncated: [],
|
||||
})
|
||||
})
|
||||
|
||||
it('falls back to a compact truncation notice when even the empty heading cannot fit', () => {
|
||||
const rendered = renderProjectInstructions([
|
||||
{ absolutePath: '/repo/pkg/AGENTS.md', displayPath: 'pkg/AGENTS.md', content: 'x'.repeat(1000) },
|
||||
], { maxBytes: 100 })
|
||||
|
||||
expect(rendered.text).toBe('<!-- Project instruction budget 100 bytes: truncated pkg/AGENTS.md from 1000 to 0 bytes -->')
|
||||
expect(rendered.truncated).toEqual([{ displayPath: 'pkg/AGENTS.md', originalBytes: 1000, includedBytes: 0 }])
|
||||
expect(Buffer.byteLength(rendered.text, 'utf8')).toBeLessThanOrEqual(100)
|
||||
})
|
||||
|
||||
it('truncates the compact notice itself when the render budget is smaller than the notice', () => {
|
||||
const rendered = renderProjectInstructions([
|
||||
{ absolutePath: '/repo/pkg/AGENTS.md', displayPath: 'pkg/AGENTS.md', content: 'x'.repeat(1000) },
|
||||
], { maxBytes: 20 })
|
||||
|
||||
expect(rendered.text).toBe('<!-- Project instruc')
|
||||
expect(rendered.truncated).toEqual([{ displayPath: 'pkg/AGENTS.md', originalBytes: 1000, includedBytes: 0 }])
|
||||
expect(Buffer.byteLength(rendered.text, 'utf8')).toBe(20)
|
||||
})
|
||||
})
|
||||
|
||||
describe('project instruction request injection', () => {
|
||||
|
||||
@@ -46,6 +46,18 @@ describe('dsh-acp-agent composition', () => {
|
||||
await ctx.fiber.dispose()
|
||||
})
|
||||
|
||||
it('forwards explicit project-instruction controls to the bundled spine', async () => {
|
||||
const ctx = await mount({
|
||||
model: 'mock',
|
||||
systemPrompt: 'hi',
|
||||
persistenceRoot: '/tmp/dsh-acp-agent-project-instructions',
|
||||
projectInstructions: false,
|
||||
})
|
||||
expect(ctx.get('agents')).toBeDefined()
|
||||
expect(ctx.get('agentLoop')).toBeDefined()
|
||||
await ctx.fiber.dispose()
|
||||
})
|
||||
|
||||
it('exposes its plugin shape', () => {
|
||||
expect(acpAgent.name).toBe('acp-agent')
|
||||
expect(acpAgent.Config).toBeDefined()
|
||||
|
||||
@@ -51,6 +51,17 @@ describe('dsh-stdio-agent app', () => {
|
||||
await ctx.fiber.dispose()
|
||||
})
|
||||
|
||||
it('forwards explicit project-instruction controls to the bundled spine', async () => {
|
||||
const ctx = await mount({
|
||||
model: 'mock',
|
||||
systemPrompt: 'hi',
|
||||
persistenceRoot: '/tmp/dsh-stdio-agent-spec-project-instructions',
|
||||
projectInstructions: false,
|
||||
})
|
||||
expect(ctx.get('agents')?.get(AgentId('main'))).toBeDefined()
|
||||
await ctx.fiber.dispose()
|
||||
})
|
||||
|
||||
it('forwards resumeSessionId onto the pre-created agent when set', async () => {
|
||||
// A resume id defers agent creation until persistence loads; with no backing
|
||||
// session the resume is contained + logged, so no `main` agent registers —
|
||||
|
||||
Reference in New Issue
Block a user