@springbrand/message-panel 0.1.3-alpha.32 → 0.1.3-alpha.34

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.
@@ -34,11 +34,7 @@ import {
34
34
  SuggestionsBlock,
35
35
  type ApprovalDecision,
36
36
  } from "./rich-blocks";
37
- import {
38
- ToolGroupRow,
39
- WorkDescriptionRow,
40
- WorkTraceDisclosure,
41
- } from "./tool-rows";
37
+ import { ThinkingTraceRow, ToolGroupRow } from "./tool-rows";
42
38
  import { CloudOsActivityIndicator } from "./activity-indicator";
43
39
  import { ProductGeneration } from "./image-generation";
44
40
  import { GenerationLoader } from "./loading-state";
@@ -52,14 +48,10 @@ import {
52
48
  deriveTurnActivity,
53
49
  formatClockTime,
54
50
  formatFullTimestamp,
55
- partitionAssistantBlocks,
56
51
  rhythmTopClass,
57
52
  type CloudOsEntry,
58
53
  type CloudOsActionPresentation,
59
54
  } from "./transcript-model";
60
- import { useDisclosureExpandedKeys } from "./use-lifecycle-disclosure";
61
-
62
- const NO_RUNNING_DISCLOSURES: ReadonlySet<string> = new Set();
63
55
 
64
56
  export type CloudOsChatStatus = "ready" | "submitted" | "streaming" | "error";
65
57
 
@@ -353,6 +345,12 @@ export function CloudOsChatMessages({
353
345
  const scrollRef = useRef<HTMLDivElement>(null);
354
346
  const endRef = useRef<HTMLDivElement>(null);
355
347
  const [showScrollButton, setShowScrollButton] = useState(false);
348
+ const [expandedToolCalls, setExpandedToolCalls] = useState<ReadonlySet<string>>(
349
+ () => new Set(),
350
+ );
351
+ const [expandedCompactions, setExpandedCompactions] = useState<
352
+ ReadonlySet<string>
353
+ >(() => new Set());
356
354
  const { copied, copy } = useCopyAction();
357
355
  const isActive =
358
356
  turnActive ?? (status === "submitted" || status === "streaming");
@@ -367,74 +365,6 @@ export function CloudOsChatMessages({
367
365
  }),
368
366
  [approvalIdOf, isActive, messages, showThinkingTraces],
369
367
  );
370
- const workEntryKeys = useMemo(
371
- () =>
372
- new Set(
373
- entries.flatMap((entry) =>
374
- entry.type === "assistant" &&
375
- partitionAssistantBlocks(entry.blocks).work.length > 0
376
- ? [entry.key]
377
- : [],
378
- ),
379
- ),
380
- [entries],
381
- );
382
- const runningWorkEntryKeys = useMemo(() => {
383
- const keys = new Set<string>();
384
- if (!isActive) return keys;
385
- const entry = entries.findLast(
386
- (candidate) => candidate.type === "assistant",
387
- );
388
- if (entry?.type !== "assistant") return keys;
389
- const { work, content } = partitionAssistantBlocks(entry.blocks);
390
- if (work.length > 0 && !content.some((block) => block.kind === "text")) {
391
- keys.add(entry.key);
392
- }
393
- return keys;
394
- }, [entries, isActive]);
395
- const toolCallKeys = useMemo(
396
- () =>
397
- new Set(
398
- entries.flatMap((entry) =>
399
- entry.type === "assistant"
400
- ? entry.blocks.flatMap((block) =>
401
- block.kind === "toolGroup" ? [block.group.key] : [],
402
- )
403
- : [],
404
- ),
405
- ),
406
- [entries],
407
- );
408
- const runningToolCallKeys = useMemo(
409
- () =>
410
- new Set(
411
- entries.flatMap((entry) =>
412
- entry.type === "assistant" && runningWorkEntryKeys.has(entry.key)
413
- ? entry.blocks.flatMap((block) =>
414
- block.kind === "toolGroup" && block.group.hasRunning
415
- ? [block.group.key]
416
- : [],
417
- )
418
- : [],
419
- ),
420
- ),
421
- [entries, runningWorkEntryKeys],
422
- );
423
- const compactionKeys = useMemo(
424
- () =>
425
- new Set(
426
- entries.flatMap((entry) =>
427
- entry.type === "compactionBoundary" ? [entry.key] : [],
428
- ),
429
- ),
430
- [entries],
431
- );
432
- const [expandedToolCalls, toggleToolCall] =
433
- useDisclosureExpandedKeys(toolCallKeys, runningToolCallKeys);
434
- const [expandedWorkEntries, toggleWorkEntry] =
435
- useDisclosureExpandedKeys(workEntryKeys, runningWorkEntryKeys);
436
- const [expandedCompactions, toggleCompaction] =
437
- useDisclosureExpandedKeys(compactionKeys, NO_RUNNING_DISCLOSURES);
438
368
 
439
369
  const entryTopClasses = useMemo(
440
370
  () =>
@@ -444,6 +374,24 @@ export function CloudOsChatMessages({
444
374
  [entries],
445
375
  );
446
376
 
377
+ const toggleToolCall = useCallback((key: string) => {
378
+ setExpandedToolCalls((current) => {
379
+ const next = new Set(current);
380
+ if (next.has(key)) next.delete(key);
381
+ else next.add(key);
382
+ return next;
383
+ });
384
+ }, []);
385
+
386
+ const toggleCompaction = useCallback((key: string) => {
387
+ setExpandedCompactions((current) => {
388
+ const next = new Set(current);
389
+ if (next.has(key)) next.delete(key);
390
+ else next.add(key);
391
+ return next;
392
+ });
393
+ }, []);
394
+
447
395
  const syncScrollButton = useCallback(() => {
448
396
  const element = scrollRef.current;
449
397
  if (!element) return;
@@ -584,7 +532,7 @@ export function CloudOsChatMessages({
584
532
  <span className="h-px flex-1 bg-kumo-line" aria-hidden="true" />
585
533
  </div>
586
534
  {expanded && (
587
- <div className="cos-markdown mt-3 rounded-2xl border border-kumo-line/70 bg-kumo-elevated/45 p-3.5 text-[13px] leading-[19px]">
535
+ <div className="themed-surface-inset cos-markdown mt-3 rounded-2xl border border-kumo-line/70 bg-kumo-elevated/45 p-3.5 text-[13px] leading-[19px]">
588
536
  <MarkdownMessage
589
537
  message={entry.summary}
590
538
  resolveUrl={resolveUrl}
@@ -597,21 +545,16 @@ export function CloudOsChatMessages({
597
545
  );
598
546
  }
599
547
 
600
- const { work: workBlocks, content: contentBlocks } =
601
- partitionAssistantBlocks(entry.blocks);
602
- const workGroups = workBlocks.flatMap((block) =>
603
- block.kind === "toolGroup" ? [block.group] : [],
604
- );
605
- const hasNarrative = contentBlocks.some(
548
+ const hasNarrative = entry.blocks.some(
606
549
  (block) => block.kind === "text",
607
550
  );
608
- const insufficientFailures = contentBlocks.filter(
551
+ const insufficientFailures = entry.blocks.filter(
609
552
  (block) => block.kind === "actionPresentation" &&
610
553
  block.presentation.state === "failed" &&
611
554
  block.presentation.failureCode === "insufficient_credits",
612
555
  );
613
556
  const firstInsufficientFailure = insufficientFailures[0];
614
- const hasCompletedAction = contentBlocks.some(
557
+ const hasCompletedAction = entry.blocks.some(
615
558
  (block) => block.kind === "actionPresentation" &&
616
559
  block.presentation.state === "ready",
617
560
  );
@@ -619,83 +562,17 @@ export function CloudOsChatMessages({
619
562
  return (
620
563
  <div
621
564
  key={entry.key}
622
- className={`${topClass} min-w-0 w-full max-w-[860px]`}
565
+ className={`${topClass} min-w-0 w-full max-w-[860px] space-y-2`}
623
566
  >
624
- <div className="group/agentMessage relative space-y-4">
625
- {workBlocks.length > 0 && (
626
- <WorkTraceDisclosure
627
- durationMs={entry.durationMs}
628
- groups={workGroups}
629
- completed={!runningWorkEntryKeys.has(entry.key)}
630
- open={expandedWorkEntries.has(entry.key)}
631
- onToggle={() => toggleWorkEntry(entry.key)}
632
- >
633
- {workBlocks.map((block) => {
634
- switch (block.kind) {
635
- case "reasoning":
636
- case "text":
637
- return (
638
- <WorkDescriptionRow
639
- key={block.key}
640
- text={block.text}
641
- running={runningWorkEntryKeys.has(entry.key)}
642
- resolveUrl={resolveUrl}
643
- />
644
- );
645
- case "toolGroup":
646
- return (
647
- <ToolGroupRow
648
- key={block.key}
649
- group={block.group}
650
- open={expandedToolCalls.has(block.group.key)}
651
- expandedKeys={expandedToolCalls}
652
- onToggle={toggleToolCall}
653
- />
654
- );
655
- case "plan":
656
- return (
657
- <PlanBlock
658
- key={block.key}
659
- steps={block.steps}
660
- running={
661
- runningWorkEntryKeys.has(entry.key) && block.running
662
- }
663
- showCollapsedSummary={false}
664
- />
665
- );
666
- case "parallel":
667
- return (
668
- <ParallelBlock
669
- key={block.key}
670
- label={block.label}
671
- tools={block.tools}
672
- running={runningWorkEntryKeys.has(entry.key)}
673
- />
674
- );
675
- case "subagents":
676
- return (
677
- <SubAgentsBlock
678
- key={block.key}
679
- agents={block.agents}
680
- running={runningWorkEntryKeys.has(entry.key)}
681
- />
682
- );
683
- default:
684
- return null;
685
- }
686
- })}
687
- </WorkTraceDisclosure>
688
- )}
689
-
690
- {contentBlocks.map((block) => {
567
+ <div className="group/agentMessage relative space-y-1.5">
568
+ {entry.blocks.map((block) => {
691
569
  switch (block.kind) {
692
570
  case "reasoning":
693
571
  return (
694
- <WorkDescriptionRow
572
+ <ThinkingTraceRow
695
573
  key={block.key}
696
- text={block.text}
574
+ reasoning={block.text}
697
575
  running={block.running}
698
- resolveUrl={resolveUrl}
699
576
  />
700
577
  );
701
578
  case "text": {
@@ -733,9 +610,7 @@ export function CloudOsChatMessages({
733
610
  <PlanBlock
734
611
  key={block.key}
735
612
  steps={block.steps}
736
- running={
737
- runningWorkEntryKeys.has(entry.key) && block.running
738
- }
613
+ running={block.running}
739
614
  />
740
615
  );
741
616
  case "askUser":
@@ -747,7 +622,13 @@ export function CloudOsChatMessages({
747
622
  />
748
623
  );
749
624
  case "suggestions":
750
- return null;
625
+ return (
626
+ <SuggestionsBlock
627
+ key={block.key}
628
+ items={block.items}
629
+ onSuggestion={(text) => onSuggestion?.(text)}
630
+ />
631
+ );
751
632
  case "schedule":
752
633
  return (
753
634
  <ScheduleBlock
@@ -784,16 +665,11 @@ export function CloudOsChatMessages({
784
665
  key={block.key}
785
666
  label={block.label}
786
667
  tools={block.tools}
787
- running={runningWorkEntryKeys.has(entry.key)}
788
668
  />
789
669
  );
790
670
  case "subagents":
791
671
  return (
792
- <SubAgentsBlock
793
- key={block.key}
794
- agents={block.agents}
795
- running={runningWorkEntryKeys.has(entry.key)}
796
- />
672
+ <SubAgentsBlock key={block.key} agents={block.agents} />
797
673
  );
798
674
  case "image":
799
675
  {
@@ -874,7 +750,7 @@ export function CloudOsChatMessages({
874
750
  )}
875
751
 
876
752
  {hasNarrative && entry.timestamp !== undefined && (
877
- <div className="mt-0.5 -ml-1 flex items-center gap-1">
753
+ <div className="mt-0.5 -ml-1 flex items-center gap-1 opacity-0 transition-opacity duration-150 ease-out group-hover/agentMessage:opacity-100 group-focus-within/agentMessage:opacity-100">
878
754
  <Tooltip
879
755
  content={copied === entry.copyText ? "Copied!" : "Copy message"}
880
756
  asChild
@@ -899,16 +775,6 @@ export function CloudOsChatMessages({
899
775
  </Tooltip>
900
776
  </div>
901
777
  )}
902
-
903
- {contentBlocks.map((block) =>
904
- block.kind === "suggestions" ? (
905
- <SuggestionsBlock
906
- key={block.key}
907
- items={block.items}
908
- onSuggestion={(text) => onSuggestion?.(text)}
909
- />
910
- ) : null
911
- )}
912
778
  </div>
913
779
  </div>
914
780
  );