Files
deepseek-harness/packages/client/ui-conversation
07akioni 61b65d3147 fix(web): show system prompts in chat
Render reconstructable system prompts at each request-series boundary, preserve series declarations through pre-step wrappers, and keep the presentation and replay snapshots aligned across clients.
2026-08-25 14:44:08 +08:00
..
2026-08-25 14:44:08 +08:00

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

English | 中文

ui-conversation owns target-neutral Conversation assembly and the shared browser shell. It consumes Session Controller event feeds, exposes React-free registries and per-Session bindings through ctx.uiConversation, and contributes the useConversation, useInput, and inputActions standard props through ctx.uiSession. It also owns the per-session durable image URL cache: ctx.uiConversation.imageUrl(sessionId, attachment) resolves one session-authorized browser URL per attachment and revokes it with the Session binding, so every Conversation target shares one session.attachment read. Concrete targets such as Chat are separate packages that register their own Definitions, snapshot builders, Views, and renderers.

Conversation assembly

UiConversation.events is the single registry for event Definitions, and UiConversation.views is the single registry for target snapshot builders. Both registries reject duplicate keys, preserve registration order, return idempotent disposers, and rebuild existing bindings when their contribution roster changes. UiConversation.binding(bindingOrSessionId) returns one identity-stable Conversation binding for the current Session Controller binding. It does not open another event source.

The adapter converts each SessionEventEntry to a { event } ConversationEventInput and preserves the raw Session event, including tool-result metadata. Contiguous append and prepend revisions use incremental assembly; replacement windows and revision gaps rebuild from the complete loaded window. The assembler owns Context matching, Turn/Step locations, target node materialization, target activity, and stable target sources. ConversationSnapshot contains only target-neutral views and active-target facts; Session lifecycle state remains in SessionSnapshot.

Target packages declaration-merge their snapshot and Location data maps, then register with ctx.uiConversation.events.register(...) and ctx.uiConversation.views.register(...). A target reads its Session-owned source with ctx.uiConversation.binding(binding).target(targetId). Registrations are Cordis effects and their returned disposers remove the contribution from the same registry.

Shell and standard props

The package registers the optional-Session conversation shell, strict Session header/body entries, View list, composer chain and bar, input regions, Hero regions, queue dock, draft persistence, and phase calculation. ctx.uiSession.provide() materializes the Conversation and input sources from the same Session binding and supplies inputActions as a stable standard prop.

View selection is deterministic: a registered persisted selection wins, otherwise registered chat wins, otherwise no View renders. It never chooses the first registered View. Shell phase combines Session lifecycle with the active-target set; no target-specific snapshot is read by the shell.

The resident composer survives no-Session and Session transitions. The no-Session state keeps the same textarea mounted but inert while the Workspace picker connects a blank Session. Draft text is mirrored into the per-Session Conversation store. Queue operations address exact queue occurrences through the scoped ctx.conversation service. Busy Enter behavior is stored in the Host-backed ui-conversation settings namespace.

An ordinary running composer keeps Stop as its primary pointer action while its draft is empty or an owner block makes input unavailable. Actionable text or attachments switch the same seat to Queue Send; clearing or successfully submitting the draft restores Stop. Keyboard Queue/Steer selection remains governed by the busy-Enter setting, while continuable subagents keep independent Send and Stop actions (decision).

Temporary composer entries

conversation.composer is a generic chain. Its complete owner currency is:

/** 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
}

A business package may install one entry only while a Remote waterfall request is pending:

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()
}

The selector must be a pure function of the owner currency. Its non-null return is delivered to the component as matched; PropsRuntime<'conversation.composer'> supplies the standard Session and global props. Chain order remains ascending priority, then registration order, and the first non-null selector wins. The shell keeps the default composer mounted beneath a takeover. Request state, listeners, response encoding, and any request-specific child slots belong to the business package; they are not carried by SessionSnapshot or declared by this core package.

Model Experience

None, as this package renders browser state and sends user-admitted inputs through Session Controller APIs without constructing model requests.

KV Cache effect

None; Conversation assembly and browser input state do not alter provider-side prompt caching.

Known Limitations and Deferred Work

  • Only registered targets can render — the shell deliberately has no implicit fallback target beyond the registered chat preference.