See-Sol-Lab/DeepSeekGUI--packages-client-ui-conversation ↗★ 274
@deepseek-ai/dsh-client-ui-conversation
Target-neutral Conversation assembly, shell, composer, queue, and view navigation
Other repositories with this package name
- deepseek-ai/deepseek-harness--packages-client-ui-conversation
- whitelonng/dshcode--packages-client-ui-conversation
- fufankeji/deepseek-harness-studio--packages-client-ui-conversation
- op7418/pilot-harness--packages-client-ui-conversation
- SuperJJ007/papermachine--packages-client-ui-conversation
- peiyuwang54/deepseek-harness-cli--packages-client-ui-conversation
Install
This plugin has no verified bundle, or compatibility checks failed. Read the repository notes first. Read the full README ↗
README
Read the full README ↗description: "Target-neutral conversation assembly and browser shell: event and view registries, per-session bindings, input state, slots, and temporary composer takeovers." kind: "package-reference"
@deepseek-ai/dsh-client-ui-conversation
English | 中文
Desktop product events use the optional product analytics service; ordinary Web interactions are excluded.
Summary
ui-conversation owns target-neutral Conversation assembly and the shared browser shell. It consumes Session Controller SessionEventLikeEntry 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.
Table of Contents
- Conversation assembly
- Sent user text
- Shell and standard props
- Temporary composer entries
- Model Experience
- Known Limitations and Deferred Work
- Dev Note
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. A View Definition may declare toolCallFocus to translate a tool-call id into its focus identity. Conversation supplies an Inspect callback only while such a target has a visible View entry; Chat consumes this callback without selecting a target.
ConversationBinding.openTurn is an identity-stable, read-only source of the latest turn number when its start is loaded and it remains open, or undefined otherwise. Observed turn changes publish synchronously even when no View is active. Fixed stop input reads this source alongside Session running and pending-interaction state. Unloading the Session binding detaches its event-source subscription.
The adapter passes each SessionEventLikeEntry directly to the assembler. Its outer type distinguishes durable events from Client-only transient events, while its inner event always exposes type, seq, time, and data; Definitions receive that inner SessionEventLike. Replacement windows may include both entry variants, while historical prepends carry durable entries and live appends may carry either. Definitions use the same match/start/update interface for durable and transient events. The earliest loaded start initializes State; every later Match, including another start for that identity, updates it. Definitions that do not consume Assistant deltas return null for assistant/live-chunk. Replacement windows and revision gaps rebuild from the complete loaded window; contiguous append, prepend, and Assistant-settlement revisions use incremental assembly. Settlement removes only the named attempt's transient matches, applies its optional durable entry, and recomputes the affected Contexts from their remaining earliest start, refreshing predecessor indexes and dependents without replacing unrelated target nodes. A Context with no remaining start has no State. Its key and previously published nodes remain available to later evidence until a full window rebuild; the owning Definition may hide those nodes. 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.
Definitions may share the same read-only Match and Location for one input and lifecycle role. Each Definition keeps its own Context, State, and ordered Match list; Match objects are not reused across assembler instances.
Registration accepts the existing callable match or a read-only event-type-to-handler table. The Registry copies table entries and precomputes ordered candidate Sets on registration changes. Function-form Definitions keep their callable API and receive every event; table handlers receive only their declared types. Changing a table requires unregistering and registering again. Legacy assembler adapters with only entries() and fallbackEntry() retain their original dispatch path.
All accepted Matches update State in order. Repeated updates to one Context are coalesced between flushes. A Context retains its key while kind and id match; Definition-facing Context snapshots remain distinct objects. The fallback handles only inputs that no ordinary Definition of its target matched. A Definition can return exclusive: true from match() to claim an event on its target: other Definitions of that target do not receive the event and the target's fallback does not run (semantics).
Location lookup indexes Steps by Turn and Step number, so a non-boundary append does not scan the Turn's Step array. Each input's numeric coordinates and resolved Location share one private index record; published Location values remain immutable. Boundary updates, replacement, and prepend keep the indexes aligned with the current timeline.
A target becomes active when shell selection resolves it or when its source receives a first subscriber. The assembler replaces that target from current Contexts once and keeps it active for later incremental flushes; creating a source does not activate it and unsubscription does not deactivate it.
UiConversation.groups registers one optional business Group Definition per existing target. It consumes projected Node changes, changed Turns, and indexed target positions after Node materialization, including first activation, and owns all segmentation and group data. Indexed Turn reads preserve interruptions from neighbouring Nodes, allowing business updates to stay within affected Turns and groups. The assembler validates and installs root references and keyed group snapshots before publishing Node, Group, and Location data sources. Ungrouped targets retain their original path. Grouping defines input lifetime, typed registration, atomic updates, and renderer responsibilities.
Group registration rejects a missing View target. Removing an already registered View Definition pauses its grouping and clears its published results without removing the Group Definition; registering that View again rebuilds from the current loaded timeline through the existing replacement flow. Switching View tabs does not remove a View Definition.
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. The shared request inspection serves every target: ctx.uiConversation.inspectSystemPrompt(previous, event) interprets system messages and positional replacements as immutable loaded-surface state. It selects the last nonempty surviving system node in surface order, retains only surviving replacement positions for chained rewrites, and withholds the prompt after an unindexed older endpoint until prepend replay supplies its order. Target-owned Definitions retain historical cards independently. ctx.uiConversation.inspectRequestPrompt(previous, header, system) classifies request changes against that effective prompt; ordinary messages and stream chunks require no system-state work.
Sent user text
UiConversation.userText registers synchronous match(text, from, context) rules. Each call offers one business or Text candidate; the evaluator selects the earliest start and uses order and stable ID only for same-start ties. Each caller owns its query cache. Context.read(key) invalidates only readers of changed Facts, while future candidates and no-match results are reused within their recorded search ranges. Inputs and outputs use readonly types without runtime freezing. See the UserText types and design decision.
Businesses extend UserTextDataMap and UserTextFacts on this package's /client entry, register a matcher through ctx.uiConversation.userText, and contribute their renderer to conversation.user.text.node. The session-scoped conversation.user.text Factory owns this inline keyed Slot. Whitespace rules also return ordinary Text candidates through the same scheduler; trim wins same-start edge collisions with collapse. Node registrations supply their own actions; interactive and CSS ellipsis remain React Props. Missing renderers display the original fragment; matching failures retain the complete original text and report the rule error.
Queue previews enable whitespace collapsing and document-edge trimming, retain emoji, and use CSS ellipsis without truncating the input. Editing and copying retain the original text; native attachments use their separate presentation.
Shell and standard props
The shared image slot props keep display choices separate from durable references: thumbnail requests a contained attachment-list thumbnail, while compact requests a cropped gallery tile. An optional per-image label supplies the accessible display name; loading and cache identity still use the original attachment reference. MessageImagesContentInput adds optional complete MessageImageLabels for the root-scoped conversation.images.content Factory. Message, tool, and Factory inputs carry the view's authorized loadImage callback explicitly; loading and URL caching remain with the resource owner. ui-attachment provides this Factory and owns rendering and the lightbox.
The composer measures its expanded control groups after size, content, visibility, or font-loading changes. If they cannot share a line, the row sets --dsh-composer-model-text-display: none and --dsh-composer-model-icon-display: block for the model seat; their defaults are block and none. Wrapping remains available if even the icon cannot fit.
The context meter follows the statistics-control radius.
The context-occupancy button shows a ring and percentage below the input card, after the Session statistics. Clicking it opens the token breakdown in a panel kept inside the viewport, including when no statistics are shown; the button stays hidden until context usage and capacity are available.
With Coding Tools off, the shell hides only Trajectory; other plugin-contributed Views remain available. The View tab bar is hidden when fewer than two Views are available. Turning Coding Tools off while Trajectory is active returns to Chat; stored View preferences and recorded Session data remain intact. Turning it on makes Trajectory available again. View owners receive the available roster so their navigation actions can follow the same visibility.
The composer registers the File command action and owns its label, availability, and native file-dialog callback. Menu availability and invocation both consult the mounted composer's current attachment-intake policy. Unmounting or locking the composer disables that action; disposing the plugin removes its registration. The callback binding stays inside the input module.
SessionInputShell owns one Lexical editor per Session through its private DraftEditorRuntime, while retaining submission, attachment selection, and recovery decisions. DraftEditor renders the borrowed editor; InputBar retains its Hooks and refs and installs DOM behavior through view-binding. Editor-facing types live in draft-editor.ts, with shared input and submission types in input.ts. Background editor updates retain the draft selection without changing the document selection or reclaiming focus from another control; explicit Composer focus restores its selection. This separation does not support simultaneous editable roots for one Session; the two-stage isolation proposal defines the remaining work.
Drafts retain plain text and file, folder, and Session reference chips across Session switching and reload. Public input methods accept text; internal restoration and Workspace transfer preserve structured references. The input model imports saved content before its first published read; React only mounts that editor and binds the existing Conversation store writer. The original storage key accepts legacy strings and writes semantic snapshots without runtime node IDs. A pending skill catalog does not block editing: slash names remain ordinary text until a matching catalog entry arrives. Arrival rematches the current text without changing chips, selection, or Undo history. Browser-owned attachment File objects are not persisted by this mechanism. The draft initialization decision defines ownership and restoration.
A claimed command is one atomic chip at the start of the draft, and the claim lasts exactly as long as that chip. Deleting the arguments and separator keeps the claim. At the chip's edge, the first Backspace or Delete selects the whole chip and the next one removes it and releases the claim, leaving the arguments as plain text; any other key, a click, or a caret move clears the selection. Text or a line break inserted before the chip turns it back into its literal token and releases the claim, and undo restores a deleted chip together with its claim. The persisted draft records the chip's token, so a reload rebuilds the chip once the command catalog resolves the claim; editing the draft first keeps the literal token, which Enter still submits as the command. The same rules apply to every command and locale, including /goal, /目标, /plan, and /计划. Command hints and ordinary placeholders remain hidden throughout IME composition and reappear only after the editor commits the final text and the corresponding input is empty.
Workspace selection uses uiWorkspace.openWorkspace to prepare the target and commit navigation. Draft content, including structured references, and attachments move in its synchronous preparation callback only while that request is current; later navigation or owner disposal leaves the original draft intact.
The package occupies the root-scoped main key conversation. Its main.conversation shell keeps the resident conversation.header outside the optional-Session conversation.content Component Factory. The header hosts root-scoped navigation witho