Files
deepseek-harness/packages/client/ui-conversation/README.zh.md
T

5.1 KiB
Raw Blame History

@deepseek-ai/dsh-client-ui-conversation

English | 中文

ui-conversation 拥有与 target 无关的 Conversation 组装和共享浏览器 shell。它消费 Session Controller event feed,通过 ctx.uiConversation 暴露不依赖 React 的 registry 与逐 Session binding,并通过 ctx.uiSession 提供 useConversationuseInputinputActions 标准 props。Chat 等具体 target 位于独立 package,由各自 package 注册 Definition、snapshot builder、View 和 renderer。

Conversation 组装

UiConversation.events 是 event Definition 的唯一 registryUiConversation.views 是 target snapshot builder 的唯一 registry。两者都拒绝重复 key、保持注册顺序、返回幂等 disposer,并在 contribution roster 变化时重建现有 binding。UiConversation.binding(bindingOrSessionId) 为当前 Session Controller binding 返回 identity 稳定的 Conversation binding,不会另开 event source。

adapter 将每个 SessionEventEntry 转换成 { event, view? } 形式的 ConversationEventInput:原始 Session event 保持不变,仅在 envelope-level tool view 存在时携带 view。连续 revision 的 append 和 prepend 使用增量组装;replace window 或 revision 断档从完整已加载窗口重建。assembler 拥有 Context 匹配、Turn/Step location、target node 物化、target activity 和稳定 target source。ConversationSnapshot 只包含与 target 无关的 View 与 active-target 事实;Session lifecycle 状态仍属于 SessionSnapshot

target package 通过 declaration merge 扩展 snapshot 与 Location data map,再调用 ctx.uiConversation.events.register(...)ctx.uiConversation.views.register(...)。target 通过 ctx.uiConversation.binding(binding).target(targetId) 读取其 Session-owned source。注册属于 Cordis effect,返回的 disposer 从同一个 registry 移除 contribution。

Shell 与标准 props

本包注册 optional-Session conversation shell、strict Session header/body、View list、composer chain 与 bar、输入区域、Hero 区域、queue dock、草稿持久化和 phase 计算。ctx.uiSession.provide() 从同一个 Session binding 物化 Conversation 与 input source,并将 inputActions 作为稳定标准 prop 提供。

View 选择规则固定:有效且已注册的持久化选择优先,其次是已注册的 chat,否则不渲染 View;绝不选择第一个已注册 View。Shell phase 只组合 Session lifecycle 与 active-target set,不读取任何 target-specific snapshot。

常驻 composer 在无 Session 与有 Session 之间保持挂载。无 Session 时,同一个 textarea 保持 inertWorkspace picker 连接 blank Session;草稿文本镜像到逐 Session Conversation store。Queue 操作通过 scoped ctx.conversation service 寻址准确的 queue occurrence。繁忙时 Enter 行为保存在 Host-backed ui-conversation settings namespace。

临时 composer entry

conversation.composer 是通用 chain,其完整 owner currency 为:

/** Owner values used to elect a composer takeover. */
interface ComposerChainProps {
  /** Current Session identity used by temporary business-owned entries. */
  sessionId: SessionId | undefined
  /** Current Session lifecycle state, absent without a selected Session. */
  session: SessionSnapshot | undefined
  /** Effective business-owned interaction awaiting the user in this Session. */
  pendingInteraction: SessionPendingInteraction | undefined
}

业务 package 可仅在一个 Remote waterfall request pending 期间安装 entry

import type { ComposerChainProps } from '@deepseek-ai/dsh-client-ui-conversation/client'
import type { ChainSelect, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
import type { SessionId } from '@deepseek-ai/dsh-session/types'

interface Request {
  readonly sessionId: SessionId
}

type RequestComposerProps =
  PropsRuntime<'conversation.composer'> & { matched: Request }

const select: ChainSelect<ComposerChainProps, Request> = owner =>
  owner.sessionId === request.sessionId ? request : null

const dispose = ctx.slots.register(
  { name: 'conversation.composer', select },
  RequestComposer,
)

try {
  return await request.result
} finally {
  dispose()
}

selector 必须是 owner currency 的纯函数。非 null 返回值作为 matched 传给组件;PropsRuntime<'conversation.composer'> 提供标准 Session 与 global props。Chain 顺序仍按 priority 升序,再按注册顺序;首个返回非 null 的 selector 获选。Shell 会在 takeover 下保持默认 composer 挂载。Request 状态、listener、response encoding 和任何 request-specific child slot 都属于业务 package,不进入 SessionSnapshot,也不由 core package 声明。

模型体验

无,因为本包渲染浏览器状态,并通过 Session Controller API 发送用户确认提交的输入,而不构造模型请求。

KV Cache 影响

无;Conversation 组装和浏览器输入状态不会改变提供方侧的 prompt cache。

已知限制与暂缓事项

  • 只有已注册 target 可以渲染——除已注册的 chat 偏好外,shell 刻意不提供隐式 fallback target。