Merge remote-tracking branch 'origin/master' into feat/plan-mode

# Conflicts:
#	docs/architecture.md
#	docs/config-catalog.md
#	docs/module-graph.md
#	examples/acp-agent/tests/goal-snapshots/goal-session/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/advanced-toolchain/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/bash-spill/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/both-mode-turn/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/cancel-tool-calls/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/cancel/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/code-mode-turn/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/code-mode-workspace-context/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/error-finish/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/fs-edit/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/fs-policy-reject/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/fs-read-window/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/fs-read/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/fs-terminal-card/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/fs-write-overwrite/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/fs-write/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-posttool-block/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-posttool-context/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-pretool-deny/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-promptsubmit-context/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/hook-cc-stop-continue/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-posttool-block/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-posttool-context/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-pretool-block/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-promptsubmit-context/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/hook-codex-stop-continue/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/lsp-definition/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/model-switching/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/multi-turn/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/parallel-tool-calls/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/repeat-tool-guard/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/skill-load/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/subagent-depth-two-rejection/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/subagent-fork/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/subagent-mixed/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/subagent-multi/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/subagent-spawn/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/text-turn/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/todo-plan/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/tool-call-turn/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/workflow-run/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/workspace-context/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/workspace-edit/stdout.expected.jsonl
This commit is contained in:
kingwl
2026-07-22 02:28:47 +08:00
256 changed files with 12551 additions and 6988 deletions
+26
View File
@@ -4,6 +4,7 @@ import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { PROTOCOL_VERSION } from '@agentclientprotocol/sdk'
import { SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session'
import type {} from '@deepseek-ai/dsh-session-title'
import { makeBridgeHarness, textResponse, toolCallResponse, type BridgeHarness, type CapturedUpdate } from './harness.ts'
/** Concatenate the text of all agent_message_chunk updates. */
@@ -56,6 +57,31 @@ describe('acp bridge — session/load replay', () => {
expect(userText).toBe('remember this')
})
it('streams and replays the same persisted session_info_update for a title event', async () => {
live = await makeBridgeHarness({ storageDir, script: [] })
await live.client.initialize({ protocolVersion: PROTOCOL_VERSION, clientCapabilities: {} })
const { sessionId } = await live.client.newSession({ cwd: process.cwd(), mcpServers: [] })
const session = live.ctx.agents.get(SessionId(sessionId))!.session
const event = await live.ctx.sessions.appendOutOfBand(session, 'session/title', {
title: 'Durable ACP title',
messageSeqs: [1],
source: { kind: 'fallback' },
}, { kind: 'session-title' })
const expected = {
sessionUpdate: 'session_info_update' as const,
title: 'Durable ACP title',
updatedAt: new Date(event.time).toISOString(),
}
expect(live.updates).toContainEqual(expected)
await live.dispose()
live = undefined
loader = await makeBridgeHarness({ storageDir, script: [] })
await loader.client.initialize({ protocolVersion: PROTOCOL_VERSION, clientCapabilities: {} })
await loader.client.loadSession({ sessionId, cwd: process.cwd(), mcpServers: [] })
expect(loader.updates).toContainEqual(expected)
})
it('replays a persisted tool call with the TOOL-OWNED presentation (title/rawInput/console output)', async () => {
// Persist a real bash call, then replay it through a fresh bridge. A throwaway presenter pairs
// call and result in log order so replay uses the shipping tool's same cards as live streaming.
@@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest'
import { Context } from 'cordis'
import { CallId } from '@deepseek-ai/dsh-llm'
import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session'
import type {} from '@deepseek-ai/dsh-session-title'
import type { SessionNotification } from '@agentclientprotocol/sdk'
import type { ToolDefinition, ToolRegistry as ToolRegistryType } from '@deepseek-ai/dsh-tools'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
@@ -50,6 +51,23 @@ function evt<T extends SessionEvent['type']>(type: T, data: Extract<SessionEvent
}
describe('streamSessionEventUpdate', () => {
it('maps a title event to session_info_update with the event timestamp', () => {
expect(updatesFor({
type: 'session/title',
seq: 3,
time: 1_725_000_000_000,
data: {
title: 'Log-backed titles',
messageSeqs: [1],
source: { kind: 'fallback' },
},
})).toEqual([{
sessionUpdate: 'session_info_update',
title: 'Log-backed titles',
updatedAt: new Date(1_725_000_000_000).toISOString(),
}])
})
it('maps assistant/chunk text-delta to agent_message_chunk', () => {
expect(updatesFor(evt('assistant/chunk', { turn: 1, step: 1, chunk: { type: 'text-delta', index: 0, text: 'hi' } })))
.toEqual([{ sessionUpdate: 'agent_message_chunk', content: { type: 'text', text: 'hi' } }])