Merge remote-tracking branch 'origin/master' into worktree/context-source-cards
# Conflicts: # .agents/notes/implemented/simplification/2026-07-31-web-ui-no-steer-entry-or-interjection-chrome.i18n.yaml # .agents/notes/implemented/simplification/2026-07-31-web-ui-no-steer-entry-or-interjection-chrome.md # .agents/notes/implemented/simplification/2026-07-31-web-ui-no-steer-entry-or-interjection-chrome.zh.md # apps/web/tests/seeded-history.e2e.ts # apps/web/tests/snapshots/queue-actions/layout.expected.md # docs/core-data-structures/core.i18n.yaml # examples/acp-agent/tests/snapshots/code-mode-workspace-context/session.jsonl # examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl # examples/acp-agent/tests/snapshots/skill-load/session.jsonl # examples/acp-agent/tests/snapshots/workspace-context/session.jsonl # examples/headless-agent/tests/snapshots/advanced-toolchain/session.1.jsonl # examples/headless-agent/tests/snapshots/advanced-toolchain/session.2.jsonl # examples/headless-agent/tests/snapshots/advanced-toolchain/session.jsonl # examples/headless-agent/tests/snapshots/pty-tools/session.jsonl # packages/client/runtime/README.i18n.yaml # packages/client/runtime/tests/history-fold.spec.ts # packages/client/ui-conversation/README.i18n.yaml # packages/client/ui-conversation/src/client/chat/MessageItem.tsx # packages/client/ui-conversation/tests/chat-branch-tails.spec.tsx # packages/context/workspace-context/src/index.ts # packages/context/workspace-context/tests/workspace-context.spec.ts # packages/skill/tool-skill/README.i18n.yaml # packages/skill/tool-skill/README.md # packages/skill/tool-skill/README.zh.md # packages/skill/tool-skill/src/index.ts # packages/skill/tool-skill/tests/tool-skill.spec.ts
This commit is contained in:
@@ -39,7 +39,16 @@ declare module '@deepseek-ai/dsh-tasks' {
|
||||
|
||||
async function composePrefix(ctx: Context, cwd: string): Promise<Message[]> {
|
||||
const agent = ctx.agentLoop.create(SessionId('agent-spine-prefix'), {}, { cwd })
|
||||
await agentEvents(ctx, agent).serial('agent/step', 1, 1, new AbortController().signal)
|
||||
const signal = new AbortController().signal
|
||||
const decision = await agentEvents(ctx, agent).waterfall(
|
||||
'agent/pre-step', [], { turn: 1, step: 1, signal },
|
||||
() => Promise.resolve({ kind: 'enter', messages: [] }),
|
||||
)
|
||||
if (decision.kind === 'enter') {
|
||||
for (const message of decision.messages) {
|
||||
agent.session.append('user/message', message, { surfaceOp: 'append' })
|
||||
}
|
||||
}
|
||||
return agent.session.deriveMessages()
|
||||
}
|
||||
|
||||
@@ -166,7 +175,6 @@ describe('dsh-agent-spine-demo bundle', () => {
|
||||
const session = ctx.sessions.create(SessionId('configured-title-limits'))
|
||||
session.append('turn/start', {
|
||||
turn: 1,
|
||||
trigger: { kind: 'message', source: { kind: 'user' } },
|
||||
})
|
||||
session.append('user/message', createUserMessage({
|
||||
content: [{ type: 'text', text: 'One two three four' }],
|
||||
@@ -209,8 +217,8 @@ describe('dsh-agent-spine-demo bundle', () => {
|
||||
it('mounts package companions and forwards invariant selection config', async () => {
|
||||
const nestedTurn = (ctx: Context): void => {
|
||||
const session = ctx.sessions.create()
|
||||
session.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
session.append('turn/start', { turn: 2, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
session.append('turn/start', { turn: 1 })
|
||||
session.append('turn/start', { turn: 2 })
|
||||
}
|
||||
|
||||
const enabled = await mount({ workspaceContext: false })
|
||||
@@ -327,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('ok')])
|
||||
const adapter = new MockAdapter([textResponse('first')])
|
||||
const ctx = await mount({ workspaceContext: { maxBytes: 65536 } })
|
||||
await ctx.plugin(LocalFileSystem, { cwd: '/' })
|
||||
ctx.llm.registerAdapter(['mock'], adapter)
|
||||
@@ -341,9 +349,10 @@ describe('dsh-agent-spine-demo bundle', () => {
|
||||
agent.followup(createUserMessage({ content: [{ type: 'text', text: 'hi' }], source: { kind: 'user' } }))
|
||||
await waitForIdle(ctx, agent)
|
||||
|
||||
const sentText = adapter.requests[0]?.messages.map(messageText).join('\n')
|
||||
expect(sentText).toContain('hi')
|
||||
expect(sentText).toContain('bundled project rule')
|
||||
expect(adapter.requests).toHaveLength(1)
|
||||
const firstRequestText = adapter.requests[0]?.messages.map(messageText).join('\n')
|
||||
expect(firstRequestText).toContain('hi')
|
||||
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()
|
||||
@@ -581,12 +590,12 @@ describe('dsh-agent-spine-demo bundle', () => {
|
||||
}).toThrow('agent-spine-demo: dshHome and skills.local.dshHome must resolve to the same directory')
|
||||
})
|
||||
|
||||
it('places workspace instructions before the skill catalog in the session prefix', 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('ok')])
|
||||
const adapter = new MockAdapter([textResponse('first')])
|
||||
const ctx = await mount({ workspaceContext: { maxBytes: 65536 } })
|
||||
await ctx.plugin(LocalFileSystem, { cwd: '/' })
|
||||
ctx.llm.registerAdapter(['mock'], adapter)
|
||||
@@ -605,8 +614,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(messageText(adapter.requests[0]?.messages[1])).toContain('workspace rule before skills')
|
||||
expect(messageText(adapter.requests[0]?.messages[2])).toContain('prefix-order-skill')
|
||||
expect(adapter.requests).toHaveLength(1)
|
||||
const workspaceIndex = adapter.requests[0]!.messages.findIndex(
|
||||
message => messageText(message).includes('workspace rule before skills'),
|
||||
)
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user