dsh-smooth-stream 0.3.1 → 0.3.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.en.md +12 -10
- package/README.md +12 -10
- package/lib/client.js +1140 -347
- package/lib/client.js.map +1 -1
- package/package.json +3 -1
- package/src/client/FollowHost.tsx +49 -4
- package/src/client/TypewriterAssistantNodeView.module.css +3 -2
- package/src/client/TypewriterAssistantNodeView.tsx +160 -23
- package/src/client/TypewriterToolNodeView.tsx +183 -8
- package/src/client/index.ts +25 -8
- package/src/client/teleprompterGlide.ts +763 -213
- package/src/client/useProgressiveDomText.ts +206 -0
- package/src/client/useSmoothStreamContent.ts +139 -73
- package/src/config.ts +3 -6
package/src/client/index.ts
CHANGED
|
@@ -28,9 +28,22 @@ type AssistantProps = ChatNodeViewProps<'assistant-step'>
|
|
|
28
28
|
const STREAM_MODES: readonly string[] = ['typewriter', 'teleprompter']
|
|
29
29
|
const STREAM_PRESETS: readonly string[] = ['realtime', 'balanced', 'silky']
|
|
30
30
|
|
|
31
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* The assistant renderer owns its own character queue and conversation
|
|
33
|
+
* follower, so wrapping it again would create two scroll owners. Human input
|
|
34
|
+
* stays immediate; every Agent-owned output renderer goes through the same
|
|
35
|
+
* generic follow boundary. This is deliberately keyed by the owner that
|
|
36
|
+
* provides the renderer, not by individual tool names, so new Context,
|
|
37
|
+
* Command, and Tool rows are covered automatically.
|
|
38
|
+
*/
|
|
32
39
|
const SKIP_WRAP = new Set(['assistant-step', 'user', 'steering', 'command-input'])
|
|
33
40
|
|
|
41
|
+
/** React function/class or an exotic component such as memo/forwardRef/lazy. */
|
|
42
|
+
function isWrappableComponent(value: unknown): value is ComponentType<FollowWrapProps> {
|
|
43
|
+
return typeof value === 'function'
|
|
44
|
+
|| (value !== null && typeof value === 'object' && '$$typeof' in value)
|
|
45
|
+
}
|
|
46
|
+
|
|
34
47
|
/**
|
|
35
48
|
* Read the Host-bridged boot config. The inline script is produced by this
|
|
36
49
|
* plugin's Host half from a schema-validated value, so only the structural
|
|
@@ -60,16 +73,19 @@ function readBootConfig(): StreamConfig {
|
|
|
60
73
|
}
|
|
61
74
|
|
|
62
75
|
/**
|
|
63
|
-
* Wrap every keyed Chat row except
|
|
76
|
+
* Wrap every Agent-owned keyed Chat row except the assistant renderer in
|
|
77
|
+
* place. A second
|
|
64
78
|
* register with the same `children` table throws because the child slot is
|
|
65
79
|
* already declared, and only the winning entry receives `renderSlot`;
|
|
66
80
|
* swapping `entry.component` keeps the original children, locale, and inject
|
|
67
81
|
* seats. `assistant-step` is replaced below so text and Think use the
|
|
68
|
-
* typewriter reveal.
|
|
82
|
+
* typewriter reveal. The wrapper owns only the shared layout-growth/follow
|
|
83
|
+
* lifecycle; the Harness keeps each renderer's controls, disclosures, and
|
|
84
|
+
* cards intact.
|
|
69
85
|
* @param ctx - Browser context carrying the slot registry.
|
|
70
86
|
* @returns Restorer that puts the original components back.
|
|
71
87
|
*/
|
|
72
|
-
function
|
|
88
|
+
function wrapAgentChatRows(ctx: ClientContext): () => void {
|
|
73
89
|
const restores: Array<() => void> = []
|
|
74
90
|
const wrapped = new WeakSet<object>()
|
|
75
91
|
|
|
@@ -78,7 +94,7 @@ function wrapGrowingChatRows(ctx: ClientContext): () => void {
|
|
|
78
94
|
const key = entry.options.key
|
|
79
95
|
if (key === undefined || SKIP_WRAP.has(key)) continue
|
|
80
96
|
const current = entry.component
|
|
81
|
-
if (
|
|
97
|
+
if (!isWrappableComponent(current) || wrapped.has(current)) continue
|
|
82
98
|
const inner = current as ComponentType<FollowWrapProps>
|
|
83
99
|
const next = wrapFollowNodeView(inner)
|
|
84
100
|
wrapped.add(next)
|
|
@@ -145,8 +161,9 @@ class PreferenceCell {
|
|
|
145
161
|
/**
|
|
146
162
|
* Register the typewriter renderer after the conversation package declares the
|
|
147
163
|
* keyed Chat node seat. A lower priority shadows the built-in assistant row;
|
|
148
|
-
* every other
|
|
149
|
-
* workflow runs share
|
|
164
|
+
* every other keyed renderer is wrapped in place so Context, commands, Tool
|
|
165
|
+
* cards, retries, and workflow runs share one extensible follow boundary. The
|
|
166
|
+
* Host-bridged configuration
|
|
150
167
|
* selects the render direction, smoothing preset, and glide speed; the
|
|
151
168
|
* plugin-owned settings RPC supplies the live auto-expand preference when the
|
|
152
169
|
* settings surface is composed.
|
|
@@ -199,7 +216,7 @@ export function apply(ctx: ClientContext): void {
|
|
|
199
216
|
})
|
|
200
217
|
}
|
|
201
218
|
ctx.slots.inject('conversation.chat.node', () => {
|
|
202
|
-
const unwrap =
|
|
219
|
+
const unwrap = wrapAgentChatRows(ctx)
|
|
203
220
|
const unshadow = ctx.slots.register({
|
|
204
221
|
name: 'conversation.chat.node',
|
|
205
222
|
key: 'assistant-step',
|