Skip to content

Commit 449191f

Browse files
committed
test: Adds ChatMessage component stories for different thinking blocks
1 parent 4f45062 commit 449191f

File tree

1 file changed

+156
-0
lines changed

1 file changed

+156
-0
lines changed

tools/server/webui/src/stories/ChatMessage.stories.svelte

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,60 @@
5959
thinking: '',
6060
children: []
6161
});
62+
63+
// Message with <think> format thinking content
64+
const thinkTagMessage: DatabaseMessage = {
65+
id: '6',
66+
convId: 'conv-1',
67+
type: 'message',
68+
timestamp: Date.now() - 1000 * 60 * 2,
69+
role: 'assistant',
70+
content:
71+
"<think>\nLet me analyze this step by step:\n\n1. The user is asking about thinking formats\n2. I need to demonstrate the &lt;think&gt; tag format\n3. This content should be displayed in the thinking section\n4. The main response should be separate\n\nThis is a good example of reasoning content.\n</think>\n\nHere's my response after thinking through the problem. The thinking content above should be displayed separately from this main response content.",
72+
parent: '1',
73+
thinking: '',
74+
children: []
75+
};
76+
77+
// Message with [THINK] format thinking content
78+
const thinkBracketMessage: DatabaseMessage = {
79+
id: '7',
80+
convId: 'conv-1',
81+
type: 'message',
82+
timestamp: Date.now() - 1000 * 60 * 1,
83+
role: 'assistant',
84+
content:
85+
'[THINK]\nThis is the DeepSeek-style thinking format:\n\n- Using square brackets instead of angle brackets\n- Should work identically to the &lt;think&gt; format\n- Content parsing should extract this reasoning\n- Display should be the same as &lt;think&gt; format\n\nBoth formats should be supported seamlessly.\n[/THINK]\n\nThis is the main response content that comes after the [THINK] block. The reasoning above should be parsed and displayed in the thinking section.',
86+
parent: '1',
87+
thinking: '',
88+
children: []
89+
};
90+
91+
// Streaming message for <think> format
92+
let streamingThinkMessage = $state({
93+
id: '8',
94+
convId: 'conv-1',
95+
type: 'message',
96+
timestamp: 0, // No timestamp = streaming
97+
role: 'assistant',
98+
content: '',
99+
parent: '1',
100+
thinking: '',
101+
children: []
102+
});
103+
104+
// Streaming message for [THINK] format
105+
let streamingBracketMessage = $state({
106+
id: '9',
107+
convId: 'conv-1',
108+
type: 'message',
109+
timestamp: 0, // No timestamp = streaming
110+
role: 'assistant',
111+
content: '',
112+
parent: '1',
113+
thinking: '',
114+
children: []
115+
});
62116
</script>
63117

64118
<Story
@@ -144,3 +198,105 @@
144198
await new Promise(resolve => setTimeout(resolve, 100));
145199
}}
146200
/>
201+
202+
<Story
203+
name="ThinkTagFormat"
204+
args={{
205+
class: 'max-w-[56rem] w-[calc(100vw-2rem)]',
206+
message: thinkTagMessage
207+
}}
208+
/>
209+
210+
<Story
211+
name="ThinkBracketFormat"
212+
args={{
213+
class: 'max-w-[56rem] w-[calc(100vw-2rem)]',
214+
message: thinkBracketMessage
215+
}}
216+
/>
217+
218+
<Story
219+
name="StreamingThinkTag"
220+
args={{
221+
message: streamingThinkMessage
222+
}}
223+
asChild
224+
play={async () => {
225+
// Phase 1: Stream <think> reasoning content
226+
const thinkingContent =
227+
'Let me work through this problem systematically:\n\n1. First, I need to understand what the user is asking\n2. Then I should consider different approaches\n3. I need to evaluate the pros and cons\n4. Finally, I should provide a clear recommendation\n\nThis step-by-step approach will ensure accuracy.';
228+
229+
let currentContent = '<think>\n';
230+
streamingThinkMessage.content = currentContent;
231+
232+
for (let i = 0; i < thinkingContent.length; i++) {
233+
currentContent += thinkingContent[i];
234+
streamingThinkMessage.content = currentContent;
235+
await new Promise((resolve) => setTimeout(resolve, 20));
236+
}
237+
238+
// Close the thinking block
239+
currentContent += '\n</think>\n\n';
240+
streamingThinkMessage.content = currentContent;
241+
await new Promise((resolve) => setTimeout(resolve, 200));
242+
243+
// Phase 2: Stream main response content
244+
const responseContent =
245+
"Based on my analysis above, here's the solution:\n\n**Key Points:**\n- The approach should be systematic\n- We need to consider all factors\n- Implementation should be step-by-step\n\nThis ensures the best possible outcome.";
246+
247+
for (let i = 0; i < responseContent.length; i++) {
248+
currentContent += responseContent[i];
249+
streamingThinkMessage.content = currentContent;
250+
await new Promise((resolve) => setTimeout(resolve, 30));
251+
}
252+
253+
streamingThinkMessage.timestamp = Date.now();
254+
}}
255+
>
256+
<div class="w-[56rem]">
257+
<ChatMessage message={streamingThinkMessage} />
258+
</div>
259+
</Story>
260+
261+
<Story
262+
name="StreamingThinkBracket"
263+
args={{
264+
message: streamingBracketMessage
265+
}}
266+
asChild
267+
play={async () => {
268+
// Phase 1: Stream [THINK] reasoning content
269+
const thinkingContent =
270+
'Using the DeepSeek format now:\n\n- This demonstrates the &#91;THINK&#93; bracket format\n- Should parse identically to &lt;think&gt; tags\n- The UI should display this in the thinking section\n- Main content should be separate\n\nBoth formats provide the same functionality.';
271+
272+
let currentContent = '[THINK]\n';
273+
streamingBracketMessage.content = currentContent;
274+
275+
for (let i = 0; i < thinkingContent.length; i++) {
276+
currentContent += thinkingContent[i];
277+
streamingBracketMessage.content = currentContent;
278+
await new Promise((resolve) => setTimeout(resolve, 25));
279+
}
280+
281+
// Close the thinking block
282+
currentContent += '\n[/THINK]\n\n';
283+
streamingBracketMessage.content = currentContent;
284+
await new Promise((resolve) => setTimeout(resolve, 200));
285+
286+
// Phase 2: Stream main response content
287+
const responseContent =
288+
"Here's my response after using the &#91;THINK&#93; format:\n\n**Observations:**\n- Both &lt;think&gt; and &#91;THINK&#93; formats work seamlessly\n- The parsing logic handles both cases\n- UI display is consistent across formats\n\nThis demonstrates the enhanced thinking content support.";
289+
290+
for (let i = 0; i < responseContent.length; i++) {
291+
currentContent += responseContent[i];
292+
streamingBracketMessage.content = currentContent;
293+
await new Promise((resolve) => setTimeout(resolve, 30));
294+
}
295+
296+
streamingBracketMessage.timestamp = Date.now();
297+
}}
298+
>
299+
<div class="w-[56rem]">
300+
<ChatMessage message={streamingBracketMessage} />
301+
</div>
302+
</Story>

0 commit comments

Comments
 (0)