@deepseek-ai/dsh-client-ui-conversation 0.1.1-rc.2 → 0.1.2-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +89 -33
- package/README.zh.md +89 -33
- package/lib/client.js +14882 -8908
- package/lib/index.js +1 -2
- package/lib/invariant.js +2 -4
- package/lib/types/client/apply.d.ts +5 -4
- package/lib/types/client/context-occupancy.d.ts +14 -0
- package/lib/types/client/contract/composer-blocks.d.ts +28 -0
- package/lib/types/client/contract/context-provenance.d.ts +29 -0
- package/lib/types/client/contract/conversation.d.ts +240 -0
- package/lib/types/client/contract/input.d.ts +419 -0
- package/lib/types/client/contract/queue.d.ts +6 -6
- package/lib/types/client/contract/records.d.ts +271 -0
- package/lib/types/client/contract/request-inspection.d.ts +97 -0
- package/lib/types/client/contract/slots.d.ts +154 -579
- package/lib/types/client/contract/snapshot.d.ts +20 -0
- package/lib/types/client/contract/views.d.ts +13 -26
- package/lib/types/client/conversation/assembler.d.ts +120 -0
- package/lib/types/client/conversation/assembly.d.ts +87 -0
- package/lib/types/client/conversation/definition-registry.d.ts +33 -0
- package/lib/types/client/conversation/event-registry.d.ts +24 -0
- package/lib/types/client/conversation/historical-images.d.ts +51 -0
- package/lib/types/client/conversation/location-index.d.ts +71 -0
- package/lib/types/client/conversation/view-registry.d.ts +12 -0
- package/lib/types/client/image-labels.d.ts +3 -2
- package/lib/types/client/index.d.ts +25 -21
- package/lib/types/client/input/blocks.d.ts +3 -33
- package/lib/types/client/input/decorations.d.ts +6 -46
- package/lib/types/client/input/editor/ComposerContentEditable.d.ts +16 -0
- package/lib/types/client/input/editor/DecoratorPortals.d.ts +14 -0
- package/lib/types/client/input/editor/ReferenceChip.d.ts +17 -0
- package/lib/types/client/input/editor/chip-node.d.ts +110 -0
- package/lib/types/client/input/editor/claim-decor.d.ts +23 -0
- package/lib/types/client/input/editor/keymap.d.ts +41 -0
- package/lib/types/client/input/editor/projection.d.ts +93 -0
- package/lib/types/client/input/editor/span-map.d.ts +38 -0
- package/lib/types/client/input/editor/text-ref.d.ts +60 -0
- package/lib/types/client/input/facade.d.ts +128 -69
- package/lib/types/client/input/hub.d.ts +13 -13
- package/lib/types/client/input/machine.d.ts +28 -117
- package/lib/types/client/{queue/store.d.ts → input/queue-store.d.ts} +5 -4
- package/lib/types/client/input/submission-policy.d.ts +2 -1
- package/lib/types/client/locales.d.ts +102 -156
- package/lib/types/client/queue/QueueDock.d.ts +5 -9
- package/lib/types/client/service.d.ts +18 -22
- package/lib/types/client/settings/EnterBehaviorRow.d.ts +1 -1
- package/lib/types/client/skeleton/ContextMeter.d.ts +1 -1
- package/lib/types/client/skeleton/ConversationRoot.d.ts +1 -1
- package/lib/types/client/skeleton/ConversationSession.d.ts +2 -2
- package/lib/types/client/skeleton/EmptyHero.d.ts +1 -12
- package/lib/types/client/skeleton/InputBar.d.ts +8 -1
- package/lib/types/client/skeleton/TodoPanel.d.ts +3 -10
- package/lib/types/client/stores.d.ts +18 -16
- package/lib/types/client/view-selection.d.ts +9 -0
- package/package.json +48 -57
- package/lib/types/client/chat/AssistantMarkdown.d.ts +0 -18
- package/lib/types/client/chat/AssistantNodeView.d.ts +0 -4
- package/lib/types/client/chat/ChatNodeSeat.d.ts +0 -11
- package/lib/types/client/chat/ChatView.d.ts +0 -7
- package/lib/types/client/chat/CommandNodeView.d.ts +0 -9
- package/lib/types/client/chat/CompactionCommandCard.d.ts +0 -8
- package/lib/types/client/chat/CompactionItem.d.ts +0 -19
- package/lib/types/client/chat/ContextBody.d.ts +0 -130
- package/lib/types/client/chat/ContextInjectionRow.d.ts +0 -26
- package/lib/types/client/chat/GenericCommandCard.d.ts +0 -9
- package/lib/types/client/chat/MessageIconActions.d.ts +0 -36
- package/lib/types/client/chat/MessageItem.d.ts +0 -28
- package/lib/types/client/chat/ReasoningRow.d.ts +0 -14
- package/lib/types/client/chat/StatsLine.d.ts +0 -87
- package/lib/types/client/chat/TurnTailNodeView.d.ts +0 -7
- package/lib/types/client/chat/message-chrome.d.ts +0 -49
- package/lib/types/client/chat/register-node-renderers.d.ts +0 -7
- package/lib/types/client/chat/tool-node-reader.d.ts +0 -16
- package/lib/types/client/chat/turn-assistant.d.ts +0 -8
- package/lib/types/client/chat/turn-metrics.d.ts +0 -38
- package/lib/types/client/chat/use-calendar-day.d.ts +0 -6
- package/lib/types/client/chat/use-throttled-visual-update.d.ts +0 -8
- package/lib/types/client/contract/chat-nodes.d.ts +0 -68
- package/lib/types/client/conversation-nodes/assistant.d.ts +0 -35
- package/lib/types/client/conversation-nodes/chat-snapshot-builder.d.ts +0 -29
- package/lib/types/client/conversation-nodes/command.d.ts +0 -54
- package/lib/types/client/conversation-nodes/common.d.ts +0 -40
- package/lib/types/client/conversation-nodes/compaction.d.ts +0 -21
- package/lib/types/client/conversation-nodes/fallback.d.ts +0 -16
- package/lib/types/client/conversation-nodes/inbox.d.ts +0 -21
- package/lib/types/client/conversation-nodes/message.d.ts +0 -30
- package/lib/types/client/conversation-nodes/register.d.ts +0 -7
- package/lib/types/client/conversation-nodes/retry.d.ts +0 -23
- package/lib/types/client/conversation-nodes/tool.d.ts +0 -23
- package/lib/types/client/conversation-nodes/turn-error.d.ts +0 -30
- package/lib/types/client/conversation-nodes/turn-max-tokens.d.ts +0 -22
- package/lib/types/client/conversation-nodes/turn-tail.d.ts +0 -28
- package/lib/types/client/input/contract.d.ts +0 -336
- package/lib/types/client/reference/ReferenceIcon.d.ts +0 -16
- package/lib/types/client/skeleton/ApprovalPanel.d.ts +0 -13
- package/lib/types/client/skeleton/DetailsPanel.d.ts +0 -5
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/ui-conversation/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: ce99ede306e0b0aeac24d7b21beacd0a538380b6
|
|
6
|
+
README.zh.md: 5a2e481071ed3303983d5b57c68690ea9f4c4ab3
|
package/README.md
CHANGED
|
@@ -1,67 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Target-neutral conversation assembly and browser shell: event and view registries, per-session bindings, input state, slots, and temporary composer takeovers."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-client-ui-conversation
|
|
2
7
|
|
|
3
8
|
English | [中文](README.zh.md)
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
`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.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Conversation assembly](#conversation-assembly)
|
|
17
|
+
- [Shell and standard props](#shell-and-standard-props)
|
|
18
|
+
- [Temporary composer entries](#temporary-composer-entries)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="conversation-assembly"></a>
|
|
26
|
+
## Conversation assembly
|
|
27
|
+
|
|
28
|
+
`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.
|
|
6
29
|
|
|
7
|
-
|
|
30
|
+
The adapter passes each `SessionEventLikeEntry` directly to the assembler. Its outer `type` distinguishes scalar and packed records, while its inner `event` always exposes `type`, `seq`, `time`, and `data`; Definitions receive that inner `SessionEventLike`. Historical replace and prepend accept both entry variants, while live append accepts only `SessionLiveEventEntry`. Every Definition uses the same `match` and `update` methods for both event forms, while `start` receives only a standard event and the assembler rejects a packed start. Definitions that do not consume Assistant deltas return `null` for the packed tags. Replacement windows and revision gaps rebuild from the complete loaded window; contiguous append and prepend revisions use incremental assembly without expanding packed members. 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`.
|
|
8
31
|
|
|
9
|
-
|
|
32
|
+
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.
|
|
10
33
|
|
|
11
|
-
|
|
34
|
+
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.
|
|
12
35
|
|
|
13
|
-
|
|
36
|
+
<a id="shell-and-standard-props"></a>
|
|
37
|
+
## Shell and standard props
|
|
14
38
|
|
|
15
|
-
|
|
39
|
+
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.
|
|
16
40
|
|
|
17
|
-
|
|
41
|
+
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.
|
|
18
42
|
|
|
19
|
-
The
|
|
43
|
+
The shell reads the persisted View preference before rendering when a Session first binds or a cached Session becomes current, activates the registered preferred View or Chat fallback, and activates later tab or focus selections before committing them to the store. A blank Session still omits the `conversation.view` slot; no unselected target is activated.
|
|
20
44
|
|
|
21
|
-
|
|
45
|
+
The resident composer survives no-Session and Session transitions. The no-Session state keeps the same composer surface mounted but inert while the Workspace picker connects a blank Session. The surface is a shell-owned Lexical editor: reference chips are atomic decorator nodes carrying the owner's serialization identity (submission expands them through the owner codec), claimed slash commands stay styled leading text, folder text references carry the folder glyph as an icon prefix, and the draft's clipboard projection is mirrored into the per-Session Conversation store. Queue operations address exact queue occurrences through the scoped `ctx.conversation` service; queue previews render sent text through the shared inline reference projection from `ui-primitives` (wire session forms fold to their label) and show local image previews or durable image parts as thumbnails, while an edit exposes the literal sent text. Durable thumbnails resolve through the session image URL cache. Busy Enter behavior is stored in the Host-backed `ui-conversation` settings namespace.
|
|
22
46
|
|
|
23
|
-
|
|
47
|
+
Default sends commit optimistically: Enter clears the draft, occurrence table, and undo history in the same transaction, keeps the composer in `plain`, and runs the send as a detached attempt, so typing and further sends continue during the flight. `sendSession` registers a Session submission echo (`session.beginSubmission`) with the delivery mode before serializing; Session derives the placement from that mode and its current running state, so idle sends use the transcript, busy Queue sends use QueueDock, and busy Steer sends use the pending-steering surface. It then yields one paint and encodes images through the browser's native `FileReader` data-URL path. Concurrent failures are restored together in submission order until the user edits the restored content; command submissions keep the frozen `submitting` phase. Detached attempts retain their image ids through admission and Session scope disposal. When an echo retires as observed, the durable image cache exposes its preview immediately, fetches the admitted attachment, replaces the preview with the canonical URL, and revokes each URL after its use ends. Direct subagent continuations skip local echoes because their transport does not preserve the browser request id.
|
|
24
48
|
|
|
25
|
-
|
|
49
|
+
While a normal composer is running, its primary pointer action remains Stop when the draft is empty or input is unavailable. Actionable text or attachments switch the same seat to Queue Send; clearing or successfully submitting the draft restores Stop. The busy-Enter setting continues to select the Queue or Steer keyboard action. Continuable subagents keep separate Send and Stop actions ([decision](../../../.agents/notes/implemented/bug-fix/2026-08-20-running-draft-primary-send.md)).
|
|
26
50
|
|
|
27
|
-
|
|
51
|
+
<a id="temporary-composer-entries"></a>
|
|
52
|
+
## Temporary composer entries
|
|
28
53
|
|
|
29
|
-
`
|
|
54
|
+
`conversation.composer` is a generic chain. Its complete owner currency is:
|
|
30
55
|
|
|
31
|
-
|
|
56
|
+
```ts type-equiv
|
|
57
|
+
/** Owner values used to elect a composer takeover. */
|
|
58
|
+
interface ComposerChainProps {
|
|
59
|
+
/** Current Session identity used by temporary business-owned entries. */
|
|
60
|
+
sessionId: SessionId | undefined
|
|
61
|
+
/** Current Session lifecycle state, absent without a selected Session. */
|
|
62
|
+
session: SessionSnapshot | undefined
|
|
63
|
+
/** Effective business-owned interaction awaiting the user in this Session. */
|
|
64
|
+
pendingInteraction: SessionPendingInteraction | undefined
|
|
65
|
+
}
|
|
66
|
+
```
|
|
32
67
|
|
|
33
|
-
|
|
68
|
+
A business package may install one entry only while a Remote waterfall request is pending:
|
|
34
69
|
|
|
35
|
-
|
|
70
|
+
```tsx
|
|
71
|
+
import type { ComposerChainProps } from '@deepseek-ai/dsh-client-ui-conversation/client'
|
|
72
|
+
import type { ChainSelect, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
|
|
73
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types'
|
|
36
74
|
|
|
37
|
-
|
|
75
|
+
interface Request {
|
|
76
|
+
readonly sessionId: SessionId
|
|
77
|
+
}
|
|
38
78
|
|
|
39
|
-
|
|
79
|
+
type RequestComposerProps =
|
|
80
|
+
PropsRuntime<'conversation.composer'> & { matched: Request }
|
|
40
81
|
|
|
41
|
-
|
|
82
|
+
const select: ChainSelect<ComposerChainProps, Request> = owner =>
|
|
83
|
+
owner.sessionId === request.sessionId ? request : null
|
|
42
84
|
|
|
43
|
-
|
|
85
|
+
const dispose = ctx.slots.register(
|
|
86
|
+
{ name: 'conversation.composer', select },
|
|
87
|
+
RequestComposer,
|
|
88
|
+
)
|
|
44
89
|
|
|
45
|
-
|
|
90
|
+
try {
|
|
91
|
+
return await request.result
|
|
92
|
+
} finally {
|
|
93
|
+
dispose()
|
|
94
|
+
}
|
|
95
|
+
```
|
|
46
96
|
|
|
47
|
-
|
|
97
|
+
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.
|
|
48
98
|
|
|
99
|
+
<a id="model-experience"></a>
|
|
49
100
|
## Model Experience
|
|
50
101
|
|
|
51
|
-
None, as
|
|
102
|
+
None, as this package renders browser state and sends user-admitted inputs through Session Controller APIs without constructing model requests.
|
|
52
103
|
|
|
53
104
|
#### KV Cache effect
|
|
54
105
|
|
|
55
|
-
None;
|
|
106
|
+
None; Conversation assembly and browser input state do not alter provider-side prompt caching.
|
|
56
107
|
|
|
57
108
|
## Known Limitations and Deferred Work
|
|
58
109
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
- **
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
110
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
111
|
+
|
|
112
|
+
- **Only registered targets can render** — the shell deliberately has no implicit fallback target beyond the registered `chat` preference.
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
<a id="dev-note"></a>
|
|
116
|
+
### Dev Note
|
|
117
|
+
|
|
118
|
+
<details>
|
|
119
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
120
|
+
|
|
121
|
+
None.
|
|
122
|
+
|
|
123
|
+
</details>
|
package/README.zh.md
CHANGED
|
@@ -1,67 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Target-neutral 对话装配与浏览器 shell:事件和视图注册表、逐会话 binding、输入状态、slot 与临时 composer takeover。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-client-ui-conversation
|
|
2
7
|
|
|
3
8
|
[English](README.md) | 中文
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
`ui-conversation` 拥有与 target 无关的 Conversation 组装和共享浏览器 shell。它消费 Session Controller 的 `SessionEventLikeEntry` feed,通过 `ctx.uiConversation` 暴露不依赖 React 的 registry 与逐 Session binding,并通过 `ctx.uiSession` 提供 `useConversation`、`useInput` 和 `inputActions` 标准 props。它还拥有按会话的持久化图片 URL 缓存:`ctx.uiConversation.imageUrl(sessionId, attachment)` 为每个附件解析一个经会话授权的浏览器 URL,并随 Session binding 释放而撤销,因此所有 Conversation target 共享一次 `session.attachment` 读取。Chat 等具体 target 位于独立 package,由各自 package 注册 Definition、snapshot builder、View 和 renderer。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [Conversation 组装](#conversation-assembly)
|
|
17
|
+
- [Shell 与标准 props](#shell-and-standard-props)
|
|
18
|
+
- [临时 composer entry](#temporary-composer-entries)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与暂缓事项](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="conversation-assembly"></a>
|
|
26
|
+
## Conversation 组装
|
|
27
|
+
|
|
28
|
+
`UiConversation.events` 是 event Definition 的唯一 registry,`UiConversation.views` 是 target snapshot builder 的唯一 registry。两者都拒绝重复 key、保持注册顺序、返回幂等 disposer,并在 contribution roster 变化时重建现有 binding。`UiConversation.binding(bindingOrSessionId)` 为当前 Session Controller binding 返回 identity 稳定的 Conversation binding,不会另开 event source。
|
|
6
29
|
|
|
7
|
-
|
|
30
|
+
adapter 把每个 `SessionEventLikeEntry` 直接交给 assembler。外层 `type` 区分 scalar 与 packed record,内部 `event` 则统一公开 `type`、`seq`、`time` 与 `data`;Definition 接收这个内部 `SessionEventLike`。历史 replace 与 prepend 接受两种 entry,实时 append 只接受 `SessionLiveEventEntry`。两种 event 都使用 Definition 的同一组 `match` 与 `update` 方法,`start` 则只接收标准 event,assembler 会拒绝 packed start。不消费 Assistant delta 的 Definition 对 packed tag 返回 `null`。replace window 或 revision 断档从完整已加载窗口重建;连续 revision 的 append 和 prepend 使用增量组装,并且不展开 packed member。assembler 拥有 Context 匹配、Turn/Step location、target node 物化、target activity 和稳定 target source。`ConversationSnapshot` 只包含与 target 无关的 View 与 active-target 事实;Session lifecycle 状态仍属于 `SessionSnapshot`。
|
|
8
31
|
|
|
9
|
-
|
|
32
|
+
shell 选择解析出 target 或 target source 收到首个 subscriber 时,该 target 进入 active 状态。assembler 从当前 Context 对它执行一次 replace,并使它参与后续增量 flush;创建 source 不会激活 target,取消订阅也不会停用 target。
|
|
10
33
|
|
|
11
|
-
|
|
34
|
+
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。
|
|
12
35
|
|
|
13
|
-
|
|
36
|
+
<a id="shell-and-standard-props"></a>
|
|
37
|
+
## Shell 与标准 props
|
|
14
38
|
|
|
15
|
-
|
|
39
|
+
本包注册 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 提供。
|
|
16
40
|
|
|
17
|
-
|
|
41
|
+
View 选择规则固定:有效且已注册的持久化选择优先,其次是已注册的 `chat`,否则不渲染 View;绝不选择第一个已注册 View。Shell phase 只组合 Session lifecycle 与 active-target set,不读取任何 target-specific snapshot。
|
|
18
42
|
|
|
19
|
-
|
|
43
|
+
Session 首次绑定或缓存的 Session 成为 current 时,shell 会在渲染前读取持久化 View 偏好,激活已注册的偏好 View 或 Chat fallback,并在后续 tab 或 focus 选择写入 store 前先激活对应 target。blank Session 仍不渲染 `conversation.view` slot;未选中的 target 不会激活。
|
|
20
44
|
|
|
21
|
-
|
|
45
|
+
常驻 composer 在无 Session 与有 Session 之间保持挂载。无 Session 时,同一个编辑器表面保持 inert,Workspace picker 连接 blank Session。该表面是 shell 所有的 Lexical 编辑器:引用 chip 是携带 owner 序列化身份的原子 decorator 节点(提交时经 owner codec 展开),已认领的 slash command 保持为带样式的行首文本,文件夹文本引用以图标前缀携带文件夹图形,草稿的剪贴板投影镜像到逐 Session Conversation store。Queue 操作通过 scoped `ctx.conversation` service 寻址准确的 queue occurrence;queue 预览经 `ui-primitives` 的共享行内引用投影渲染已发送文本(wire 会话形式折叠为其标签),并把本地图片预览或持久化图片部分显示为缩略图,编辑态则展示字面发送文本。持久化缩略图通过会话图片 URL 缓存解析。繁忙时 Enter 行为保存在 Host-backed `ui-conversation` settings namespace。
|
|
22
46
|
|
|
23
|
-
|
|
47
|
+
默认发送采用乐观提交:Enter 在同一事务里清空草稿、occurrence 表和撤销历史,composer 保持 `plain`,发送作为 detached attempt 运行,发送期间可以继续输入和提交。`sendSession` 在序列化之前用投递模式注册 Session 提交回显(`session.beginSubmission`);Session 根据该模式与当前运行状态推导位置,因此空闲发送进入 transcript,繁忙时 Queue 进入 QueueDock,繁忙时 Steer 进入 pending-steering 区域。随后让出一帧,图片经浏览器原生 `FileReader` data-URL 路径编码。多个并发发送失败时,在用户编辑还原内容之前按提交顺序合并还原;命令提交保持冻结的 `submitting` 阶段。Detached attempt 持有图片 id,直到 admission 完成或 Session scope 销毁。回显以 observed 退休时,durable 图片缓存立即公开预览 URL,同时读取 admitted 附件,随后用规范化 URL 替换预览,并在两个 URL 各自停止使用后撤销。直接 subagent continuation 不创建本地回显,因为其 transport 不保留浏览器 request id。
|
|
24
48
|
|
|
25
|
-
|
|
49
|
+
普通 composer 运行时,如果草稿为空或输入不可用,主指针操作保持为 Stop。可提交的文字或附件会把同一位置切换为 Queue Send;清空或成功提交草稿后恢复 Stop。繁忙态 Enter 设置继续选择 Queue 或 Steer 键盘操作。可继续 subagent 保留独立的 Send 与 Stop 操作([决策](../../../.agents/notes/implemented/bug-fix/2026-08-20-running-draft-primary-send.zh.md))。
|
|
26
50
|
|
|
27
|
-
|
|
51
|
+
<a id="temporary-composer-entries"></a>
|
|
52
|
+
## 临时 composer entry
|
|
28
53
|
|
|
29
|
-
`
|
|
54
|
+
`conversation.composer` 是通用 chain,其完整 owner currency 为:
|
|
30
55
|
|
|
31
|
-
|
|
56
|
+
```ts type-equiv
|
|
57
|
+
/** Owner values used to elect a composer takeover. */
|
|
58
|
+
interface ComposerChainProps {
|
|
59
|
+
/** Current Session identity used by temporary business-owned entries. */
|
|
60
|
+
sessionId: SessionId | undefined
|
|
61
|
+
/** Current Session lifecycle state, absent without a selected Session. */
|
|
62
|
+
session: SessionSnapshot | undefined
|
|
63
|
+
/** Effective business-owned interaction awaiting the user in this Session. */
|
|
64
|
+
pendingInteraction: SessionPendingInteraction | undefined
|
|
65
|
+
}
|
|
66
|
+
```
|
|
32
67
|
|
|
33
|
-
|
|
68
|
+
业务 package 可仅在一个 Remote waterfall request pending 期间安装 entry:
|
|
34
69
|
|
|
35
|
-
|
|
70
|
+
```tsx
|
|
71
|
+
import type { ComposerChainProps } from '@deepseek-ai/dsh-client-ui-conversation/client'
|
|
72
|
+
import type { ChainSelect, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
|
|
73
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types'
|
|
36
74
|
|
|
37
|
-
|
|
75
|
+
interface Request {
|
|
76
|
+
readonly sessionId: SessionId
|
|
77
|
+
}
|
|
38
78
|
|
|
39
|
-
|
|
79
|
+
type RequestComposerProps =
|
|
80
|
+
PropsRuntime<'conversation.composer'> & { matched: Request }
|
|
40
81
|
|
|
41
|
-
|
|
82
|
+
const select: ChainSelect<ComposerChainProps, Request> = owner =>
|
|
83
|
+
owner.sessionId === request.sessionId ? request : null
|
|
42
84
|
|
|
43
|
-
|
|
85
|
+
const dispose = ctx.slots.register(
|
|
86
|
+
{ name: 'conversation.composer', select },
|
|
87
|
+
RequestComposer,
|
|
88
|
+
)
|
|
44
89
|
|
|
45
|
-
|
|
90
|
+
try {
|
|
91
|
+
return await request.result
|
|
92
|
+
} finally {
|
|
93
|
+
dispose()
|
|
94
|
+
}
|
|
95
|
+
```
|
|
46
96
|
|
|
47
|
-
|
|
97
|
+
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 声明。
|
|
48
98
|
|
|
99
|
+
<a id="model-experience"></a>
|
|
49
100
|
## 模型体验
|
|
50
101
|
|
|
51
|
-
|
|
102
|
+
无,因为本包渲染浏览器状态,并通过 Session Controller API 发送用户确认提交的输入,而不构造模型请求。
|
|
52
103
|
|
|
53
104
|
#### KV Cache 影响
|
|
54
105
|
|
|
55
|
-
|
|
106
|
+
无;Conversation 组装和浏览器输入状态不会改变提供方侧的 prompt cache。
|
|
56
107
|
|
|
57
108
|
## 已知限制与暂缓事项
|
|
58
109
|
|
|
59
|
-
-
|
|
60
|
-
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
110
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
111
|
+
|
|
112
|
+
- **只有已注册 target 可以渲染**——除已注册的 `chat` 偏好外,shell 刻意不提供隐式 fallback target。
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
<a id="dev-note"></a>
|
|
116
|
+
### 开发备注
|
|
117
|
+
|
|
118
|
+
<details>
|
|
119
|
+
<summary>维护者工作上下文——点击展开</summary>
|
|
120
|
+
|
|
121
|
+
无。
|
|
122
|
+
|
|
123
|
+
</details>
|