Merge remote-tracking branch 'origin/master' into feat/todo-multi-in-progress
# Conflicts: # .agents/notes/implemented/feature/2026-06-29-todo-write-tool.i18n.yaml # .agents/notes/implemented/feature/2026-07-23-web-todo-display.i18n.yaml # docs/core-data-structures/session.i18n.yaml # examples/acp-agent/tests/snapshots/fs-policy-reject/session.jsonl # examples/acp-agent/tests/snapshots/fs-write-overwrite/session.jsonl # examples/acp-agent/tests/snapshots/fs-write/session.jsonl # examples/acp-agent/tests/snapshots/todo-write/session.jsonl # examples/headless-agent/tests/todo-write.e2e.ts # packages/client/ui-conversation/README.i18n.yaml # packages/client/ui-conversation/README.md # packages/client/ui-conversation/README.zh.md # packages/todo/tool-todo/README.i18n.yaml
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { createUserMessage } from '@deepseek-ai/dsh-llm'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session'
|
||||
@@ -59,12 +60,12 @@ describe('todo_write tool through the agent loop', () => {
|
||||
const ctx = await harness(adapter)
|
||||
const agent = ctx.agentLoop.create(SessionId('it-todo'), { provider: 'mock', model: 'mock' })
|
||||
|
||||
agent.followup({ content: [{ type: 'text', text: 'plan a two-step task' }], source: { kind: 'user' } })
|
||||
agent.followup(createUserMessage({ content: [{ type: 'text', text: 'plan a two-step task' }], source: { kind: 'user' } }))
|
||||
await waitForIdle(ctx, agent)
|
||||
|
||||
const log = agent.session.events
|
||||
expect(findEvent(log, 'tool/call').data.name).toBe('todo_write')
|
||||
expect(findEvent(log, 'tool/result').data.isError).toBe(false)
|
||||
expect(findEvent(log, 'tool/result').data.message.content[0].isError).toBe(false)
|
||||
|
||||
const todoEvent = findEvent(log, 'todo/write')
|
||||
expect(todoEvent.data.todos).toEqual([
|
||||
@@ -87,7 +88,7 @@ describe('todo_write tool through the agent loop', () => {
|
||||
const ctx = await harness(adapter)
|
||||
const agent = ctx.agentLoop.create(SessionId('it-todo-2'), { provider: 'mock', model: 'mock' })
|
||||
|
||||
agent.followup({ content: [{ type: 'text', text: 'plan then update' }], source: { kind: 'user' } })
|
||||
agent.followup(createUserMessage({ content: [{ type: 'text', text: 'plan then update' }], source: { kind: 'user' } }))
|
||||
await waitForIdle(ctx, agent)
|
||||
|
||||
const todoEvents = agent.session.events.filter(e => e.type === 'todo/write')
|
||||
|
||||
@@ -11,6 +11,7 @@ import { describe, expect, it } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import AgentRegistry from '@deepseek-ai/dsh-agent'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
import { createUserMessage } from '@deepseek-ai/dsh-llm'
|
||||
import SessionStore from '@deepseek-ai/dsh-session'
|
||||
import type { Session, TodoItem } from '@deepseek-ai/dsh-session'
|
||||
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
||||
@@ -58,7 +59,10 @@ async function harness(withTodoTool: boolean): Promise<Bench> {
|
||||
|
||||
/** One paginable message so the tail page is non-degenerate. */
|
||||
function seedMessage(session: Session): void {
|
||||
session.append('user/message', { content: [{ type: 'text', text: 'hi' }], source: { kind: 'user' } }, { surfaceOp: 'append' })
|
||||
session.append('user/message', createUserMessage({
|
||||
content: [{ type: 'text', text: 'hi' }],
|
||||
source: { kind: 'user' },
|
||||
}), { surfaceOp: 'append' })
|
||||
}
|
||||
|
||||
describe('todos projection provider', () => {
|
||||
@@ -87,6 +91,20 @@ describe('todos projection provider', () => {
|
||||
expect(projections?.asOfSeq).toBe(session.seq - 1)
|
||||
})
|
||||
|
||||
it('clears the standing plan on the next turn/start (turn/end keeps it)', async () => {
|
||||
const bench = await harness(true)
|
||||
const session = bench.session
|
||||
seedMessage(session)
|
||||
const list: TodoItem[] = [{ content: 'done', status: 'completed' }]
|
||||
session.append('todo/write', { todos: list })
|
||||
session.append('turn/end', { turn: 0, reason: { kind: 'completed' } })
|
||||
expect((await bench.tailProjections())?.values.todos).toEqual(list)
|
||||
session.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
const cleared = await bench.tailProjections()
|
||||
expect(cleared?.values.todos).toBeNull()
|
||||
expect(cleared?.asOfSeq).toBe(session.seq - 1)
|
||||
})
|
||||
|
||||
it('has no todos key when tool-todo is not composed', async () => {
|
||||
const bench = await harness(false)
|
||||
seedMessage(bench.session)
|
||||
|
||||
Reference in New Issue
Block a user