test(spine): fold workspace instructions into the first request

The react-loop simplification enters the workspace baseline with the first
request instead of queueing it for a second step, and the acp-agent sandbox
scenarios now replay the branch's inbox event flow. Update the agent-spine-demo
assertions to the single-request shape (workspace rule ahead of the skill
catalog, matching registration order) and refresh the two keyless sandbox
snapshots against the merged runtime.
This commit is contained in:
_Kerman
2026-08-05 16:02:58 +08:00
parent 289a23421d
commit 7e9fa76bf9
3 changed files with 89 additions and 84 deletions

View File

@@ -335,7 +335,7 @@ describe('dsh-agent-spine-demo bundle', () => {
try {
await mkdir(join(root, '.git'), { recursive: true })
await writeFile(join(root, 'AGENTS.md'), 'bundled project rule')
const adapter = new MockAdapter([textResponse('first'), textResponse('ok')])
const adapter = new MockAdapter([textResponse('first')])
const ctx = await mount({ workspaceContext: { maxBytes: 65536 } })
await ctx.plugin(LocalFileSystem, { cwd: '/' })
ctx.llm.registerAdapter(['mock'], adapter)
@@ -349,12 +349,10 @@ describe('dsh-agent-spine-demo bundle', () => {
agent.followup(createUserMessage({ content: [{ type: 'text', text: 'hi' }], source: { kind: 'user' } }))
await waitForIdle(ctx, agent)
expect(adapter.requests).toHaveLength(2)
expect(adapter.requests).toHaveLength(1)
const firstRequestText = adapter.requests[0]?.messages.map(messageText).join('\n')
const secondRequestText = adapter.requests[1]?.messages.map(messageText).join('\n')
expect(firstRequestText).toContain('hi')
expect(firstRequestText).not.toContain('bundled project rule')
expect(secondRequestText).toContain('bundled project rule')
expect(firstRequestText).toContain('bundled project rule')
expect(adapter.requests[0]?.system).toContain('You are an AI agent powered by the DeepSeek Harness SDK.')
expect(adapter.requests[0]?.system).not.toContain('bundled project rule')
await handle.dispose()
@@ -588,12 +586,12 @@ describe('dsh-agent-spine-demo bundle', () => {
}).toThrow('agent-spine-demo: dshHome and skills.local.dshHome must resolve to the same directory')
})
it('delivers workspace instructions after the first-step skill catalog', async () => {
it('delivers workspace instructions ahead of the first-step skill catalog', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-agent-spine-demo-prefix-order-'))
try {
await mkdir(join(root, '.git'), { recursive: true })
await writeFile(join(root, 'AGENTS.md'), 'workspace rule before skills')
const adapter = new MockAdapter([textResponse('first'), textResponse('ok')])
const adapter = new MockAdapter([textResponse('first')])
const ctx = await mount({ workspaceContext: { maxBytes: 65536 } })
await ctx.plugin(LocalFileSystem, { cwd: '/' })
ctx.llm.registerAdapter(['mock'], adapter)
@@ -612,15 +610,16 @@ describe('dsh-agent-spine-demo bundle', () => {
handle.agent.followup(createUserMessage({ content: [{ type: 'text', text: 'hi' }], source: { kind: 'user' } }))
await waitForIdle(ctx, handle.agent)
expect(adapter.requests).toHaveLength(2)
const firstCatalogIndex = adapter.requests[0]!.messages.findIndex(
message => messageText(message).includes('prefix-order-skill'),
)
const workspaceIndex = adapter.requests[1]!.messages.findIndex(
expect(adapter.requests).toHaveLength(1)
const workspaceIndex = adapter.requests[0]!.messages.findIndex(
message => messageText(message).includes('workspace rule before skills'),
)
expect(firstCatalogIndex).toBeGreaterThanOrEqual(0)
const catalogIndex = adapter.requests[0]!.messages.findIndex(
message => messageText(message).includes('prefix-order-skill'),
)
expect(workspaceIndex).toBeGreaterThanOrEqual(0)
expect(catalogIndex).toBeGreaterThanOrEqual(0)
expect(workspaceIndex).toBeLessThan(catalogIndex)
await handle.dispose()
await ctx.fiber.dispose()
} finally {