feat(web): show command inputs in the human transcript

This commit is contained in:
NI0317
2026-08-10 17:13:01 +08:00
parent 1d12ae62e7
commit d06a7e07e5
31 changed files with 582 additions and 17 deletions

View File

@@ -8,6 +8,7 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import type { SessionEvent } from '@deepseek-ai/dsh-session/types'
import type {} from '@deepseek-ai/dsh-commands/types'
import type { SessionId } from '@deepseek-ai/dsh-client-connection/client'
import { Session } from '../src/client/sessions/session.ts'
import type {
@@ -132,7 +133,11 @@ const TEST_EVENT_DEFINITION: ConversationNodeDefinition<TestEventState> = {
if (context.state === undefined || context.start === undefined) return null
return {
key: context.key,
kind: 'runtime-test-event',
kind: context.start.event.type === 'command/run' && context.start.event.data.name === 'goal'
? 'command-input'
: context.start.event.type === 'command/run' || context.start.event.type === 'command/done'
? 'command'
: 'runtime-test-event',
id: context.id,
target: 'chat',
anchorSeq: context.start.event.seq,
@@ -272,6 +277,24 @@ describe('live event path', () => {
expect(snapshot.composerPhase).toBe('blank')
})
it('activates a fresh conversation for a command-input View Node without opening a model turn', async () => {
const { session } = await opened([])
session.handleBlank(true)
const feed = (event: SessionEvent) => {
session.handleMuxEnvelope('r' as never, { type: 'session/event', sessionId: SID, event })
}
feed(ev.commandRun(0, 'cmd-goal', 'goal', ' '))
feed(ev.commandDone(1, 'cmd-goal', 'success', 'No goal is currently set.'))
expect(session.getSnapshot()).toMatchObject({
blank: true,
composerPhase: 'active',
})
expect(session.getSnapshot().chat.order.map(
key => session.getSnapshot().chat.nodes.get(key)?.kind,
)).toContain('command-input')
})
it('publishes animation-frame Definitions once per frame and lets an immediate event supersede the pending frame', async () => {
const frames: FrameRequestCallback[] = []
vi.stubGlobal('requestAnimationFrame', (callback: FrameRequestCallback) => {