Merge remote-tracking branch 'origin/master' into worktree/web-multimodal-image-input

# Conflicts:
#	packages/client/runtime/README.i18n.yaml
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/README.md
#	packages/client/ui-conversation/README.zh.md
#	packages/client/ui-conversation/src/client/chat/MessageItem.tsx
This commit is contained in:
creatixchu
2026-07-31 18:18:07 +08:00
252 changed files with 5337 additions and 2509 deletions
@@ -195,7 +195,7 @@ describe('deriveTrajectoryLayout', () => {
expect(message?.thinkingDetail).toBe(thinking)
})
it('advances the duration cursor over context nodes', () => {
it('advances the duration cursor over context and compaction nodes', () => {
const nodes = [
{ kind: 'user', seq: 1, time: 1_000, content: [{ type: 'text', text: 'hi' }], source: null },
{
@@ -211,17 +211,21 @@ describe('deriveTrajectoryLayout', () => {
kind: 'context', seq: 4, time: 9_000,
content: [{ type: 'text', text: 'extra' }], source: null,
},
// A landed compaction renders no cell, but is still a real log position,
// so it moves the cursor after the visible context row.
{ kind: 'compaction', seq: 5, time: 9_500, summary: 'checkpoint facts' },
{
kind: 'assistant', seq: 5, time: 10_000, turn: 1, step: 0,
kind: 'assistant', seq: 6, time: 10_000, turn: 1, step: 0,
blocks: [{ kind: 'text', text: 'done' }],
},
] as unknown as ConversationSnapshot['nodes']
const turns = deriveTrajectoryLayout({ codeDispatches: new Map(), nodes, partial: null, runningCalls: [] })
const message = turns[0]?.groups
.flatMap(g => g.cells)
.find(c => c.kind === 'message' && c.text === 'done')
// From context at 9s, not from the earlier user/tool surfaces.
expect(message?.timeSeconds).toBe(1)
const cells = turns[0]?.groups.flatMap(g => g.cells) ?? []
const message = cells.find(c => c.kind === 'message' && c.text === 'done')
// From the compaction marker at 9.5s, not from context at 9s or the earlier surfaces.
expect(message?.timeSeconds).toBe(0.5)
// Context remains inspectable in trajectory; the Chat marker is not duplicated.
expect(cells.map(cell => cell.kind)).toEqual(['user', 'message', 'tool', 'context', 'message'])
})
it('uses the recorded step start for assistant duration when timing exists', () => {