Andrew commited on
Commit
4bb32e9
·
1 Parent(s): a2bcf5b

(fix) Smooth persona carousel think rendering

Browse files
src/lib/components/chat/PersonaResponseCarousel.svelte CHANGED
@@ -4,11 +4,12 @@
4
  import CarbonChevronRight from "~icons/carbon/chevron-right";
5
  import CarbonChevronDown from "~icons/carbon/chevron-down";
6
  import CarbonChevronUp from "~icons/carbon/chevron-up";
7
- import MarkdownRenderer from "./MarkdownRenderer.svelte";
8
- import OpenReasoningResults from "./OpenReasoningResults.svelte";
9
- import CopyToClipBoardBtn from "../CopyToClipBoardBtn.svelte";
10
- import CarbonRotate360 from "~icons/carbon/rotate-360";
11
- import { THINK_BLOCK_REGEX } from "$lib/constants/thinkBlockRegex";
 
12
 
13
  interface Props {
14
  personaResponses: PersonaResponse[];
@@ -156,7 +157,7 @@
156
 
157
  // Check if content has <think> blocks
158
  function hasClientThink(content: string | undefined): boolean {
159
- return content ? THINK_BLOCK_REGEX.test(content) : false;
160
  }
161
 
162
  let showLeftArrow = $derived(currentIndex > 0);
@@ -268,28 +269,28 @@
268
  class="content-wrapper relative"
269
  style={isExpanded ? '' : `max-height: ${MAX_COLLAPSED_HEIGHT}px; overflow: hidden;`}
270
  >
271
- {#if hasClientThink(displayedResponse.content)}
272
- {#each displayedResponse.content.split(THINK_BLOCK_REGEX) as part, _i}
273
- {#if part && part.startsWith("<think>")}
274
- {@const isClosed = part.endsWith("</think>")}
275
- {@const thinkContent = part.slice(7, isClosed ? -8 : undefined)}
276
- {@const summary = isClosed
277
- ? thinkContent.trim().split(/\n+/)[0] || "Reasoning"
278
- : "Thinking..."}
279
-
280
- <OpenReasoningResults
281
- {summary}
282
- content={thinkContent}
283
- loading={loading && !isClosed}
284
- />
285
- {:else if part && part.trim().length > 0}
286
- <div
287
- class="prose max-w-none dark:prose-invert max-sm:prose-sm prose-headings:font-semibold prose-h1:text-lg prose-h2:text-base prose-h3:text-base prose-pre:bg-gray-800 dark:prose-pre:bg-gray-900"
288
- >
289
- <MarkdownRenderer content={part} {loading} />
290
- </div>
291
  {/if}
292
- {/each}
 
 
 
 
 
 
 
293
  {:else}
294
  <div
295
  class="prose max-w-none dark:prose-invert max-sm:prose-sm prose-headings:font-semibold prose-h1:text-lg prose-h2:text-base prose-h3:text-base prose-pre:bg-gray-800 dark:prose-pre:bg-gray-900"
 
4
  import CarbonChevronRight from "~icons/carbon/chevron-right";
5
  import CarbonChevronDown from "~icons/carbon/chevron-down";
6
  import CarbonChevronUp from "~icons/carbon/chevron-up";
7
+ import MarkdownRenderer from "./MarkdownRenderer.svelte";
8
+ import OpenReasoningResults from "./OpenReasoningResults.svelte";
9
+ import CopyToClipBoardBtn from "../CopyToClipBoardBtn.svelte";
10
+ import CarbonRotate360 from "~icons/carbon/rotate-360";
11
+ import ThinkingPlaceholder from "./ThinkingPlaceholder.svelte";
12
+ import { hasThinkSegments, splitThinkSegments } from "$lib/utils/stripThinkBlocks";
13
 
14
  interface Props {
15
  personaResponses: PersonaResponse[];
 
157
 
158
  // Check if content has <think> blocks
159
  function hasClientThink(content: string | undefined): boolean {
160
+ return content ? hasThinkSegments(content) : false;
161
  }
162
 
163
  let showLeftArrow = $derived(currentIndex > 0);
 
269
  class="content-wrapper relative"
270
  style={isExpanded ? '' : `max-height: ${MAX_COLLAPSED_HEIGHT}px; overflow: hidden;`}
271
  >
272
+ {#if hasClientThink(displayedResponse.content)}
273
+ {@const segments = splitThinkSegments(displayedResponse.content ?? "")}
274
+ {#each segments as part, _i}
275
+ {#if part && part.startsWith("<think>")}
276
+ {@const trimmed = part.trimEnd()}
277
+ {@const isClosed = trimmed.endsWith("</think>")}
278
+
279
+ {#if isClosed}
280
+ {@const thinkContent = trimmed.slice(7, -8)}
281
+ {@const summary = thinkContent.trim().split(/\n+/)[0] || "Reasoning"}
282
+ <OpenReasoningResults {summary} content={thinkContent} loading={false} />
283
+ {:else}
284
+ <ThinkingPlaceholder />
 
 
 
 
 
 
 
285
  {/if}
286
+ {:else if part && part.trim().length > 0}
287
+ <div
288
+ class="prose max-w-none dark:prose-invert max-sm:prose-sm prose-headings:font-semibold prose-h1:text-lg prose-h2:text-base prose-h3:text-base prose-pre:bg-gray-800 dark:prose-pre:bg-gray-900"
289
+ >
290
+ <MarkdownRenderer content={part} {loading} />
291
+ </div>
292
+ {/if}
293
+ {/each}
294
  {:else}
295
  <div
296
  class="prose max-w-none dark:prose-invert max-sm:prose-sm prose-headings:font-semibold prose-h1:text-lg prose-h2:text-base prose-h3:text-base prose-pre:bg-gray-800 dark:prose-pre:bg-gray-900"