@skippr/live-agent-sdk 0.26.0 → 0.27.0

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.md CHANGED
@@ -193,7 +193,7 @@ Self-contained widget component. Renders a floating button that opens a sidebar
193
193
  | `welcomeMessage` | `string` | — | Message shown on the minimized bubble |
194
194
  | `startSessionLabel` | `string` | `'Talk to Skippr'` | Label for the start-session button |
195
195
  | `autoFocusChat` | `boolean` | `true` | Whether the chat input auto-focuses when opened |
196
- | `showObservingBanner` | `boolean` | `true` | Whether to show the "Skippr is observing this page" banner during screen share |
196
+ | `showAgentStateBanner` | `boolean` | `true` | Whether to show the top-pinned status banner (talking / thinking / listening / observing) while connected |
197
197
 
198
198
  ### `useLiveAgent()`
199
199
 
@@ -232,7 +232,7 @@ All hooks must be called within `<LiveAgent>`.
232
232
  | Hook | Returns | Description |
233
233
  |------|---------|-------------|
234
234
  | `useMediaControls()` | `{ isMuted, isScreenSharing, toggleMute, toggleScreenShare }` | Mic and screen share state and toggles |
235
- | `useAgentVoiceState()` | `{ isSpeaking, isThinking }` | Agent voice activity state |
235
+ | `useAgentVoiceState()` | `{ state, isSpeaking, isListening }` | Agent voice activity state — `state` is the full agent state (`'listening' \| 'thinking' \| 'speaking' \| ...`) |
236
236
  | `useIsLocalSpeaking()` | `boolean` | Whether the local user is currently speaking |
237
237
  | `useElapsedSeconds(isRunning)` | `number` | Drift-safe elapsed seconds since the flag flipped to `true` |
238
238
 
@@ -283,36 +283,6 @@ function useSession({ agentId, authToken, appKey, userToken }) {
283
283
  pendingScreenStream
284
284
  };
285
285
  }
286
-
287
- // src/components/AutoStartMedia.tsx
288
- import { useConnectionState, useLocalParticipant } from "@livekit/components-react";
289
- import { ConnectionState, Track } from "livekit-client";
290
- import { useEffect as useEffect3, useRef } from "react";
291
- function AutoStartMedia({ pendingScreenStream }) {
292
- const { localParticipant } = useLocalParticipant();
293
- const connectionState = useConnectionState();
294
- const didStartRef = useRef(false);
295
- useEffect3(() => {
296
- if (didStartRef.current)
297
- return;
298
- if (connectionState !== ConnectionState.Connected)
299
- return;
300
- didStartRef.current = true;
301
- localParticipant.setMicrophoneEnabled(true).catch((error) => console.error("Failed to enable microphone:", error));
302
- if (pendingScreenStream) {
303
- const videoTrack = pendingScreenStream.getVideoTracks()[0];
304
- if (videoTrack) {
305
- videoTrack.contentHint = "detail";
306
- localParticipant.publishTrack(videoTrack, { source: Track.Source.ScreenShare }).catch((error) => {
307
- console.error("Failed to publish screen share track:", error);
308
- for (const track of pendingScreenStream.getTracks())
309
- track.stop();
310
- });
311
- }
312
- }
313
- }, [connectionState, localParticipant, pendingScreenStream]);
314
- return null;
315
- }
316
286
  // ../../node_modules/.bun/lucide-react@1.8.0+83d5fd7b249dbeef/node_modules/lucide-react/dist/esm/createLucideIcon.js
317
287
  import { forwardRef as forwardRef2, createElement as createElement3 } from "react";
318
288
 
@@ -542,9 +512,6 @@ var __iconNode16 = [
542
512
  ["path", { d: "m21.854 2.147-10.94 10.939", key: "12cjpa" }]
543
513
  ];
544
514
  var Send = createLucideIcon("send", __iconNode16);
545
- // src/components/MinimizedBubble.tsx
546
- import { useEffect as useEffect4 } from "react";
547
-
548
515
  // src/hooks/useAgentVoiceState.ts
549
516
  import { useVoiceAssistant } from "@livekit/components-react";
550
517
  function useAgentVoiceState() {
@@ -568,7 +535,7 @@ function useLiveAgent() {
568
535
  }
569
536
 
570
537
  // src/hooks/useMediaControls.ts
571
- import { useLocalParticipant as useLocalParticipant2 } from "@livekit/components-react";
538
+ import { useLocalParticipant } from "@livekit/components-react";
572
539
  import { ScreenSharePresets } from "livekit-client";
573
540
  import { useCallback as useCallback3 } from "react";
574
541
  var SCREEN_SHARE_OPTIONS = {
@@ -577,7 +544,7 @@ var SCREEN_SHARE_OPTIONS = {
577
544
  contentHint: "detail"
578
545
  };
579
546
  function useMediaControls() {
580
- const { localParticipant } = useLocalParticipant2();
547
+ const { localParticipant } = useLocalParticipant();
581
548
  const isMuted = !localParticipant.isMicrophoneEnabled;
582
549
  const isScreenSharing = localParticipant.isScreenShareEnabled;
583
550
  const toggleMute = useCallback3(async () => {
@@ -597,6 +564,156 @@ function useMediaControls() {
597
564
  return { isMuted, toggleMute, isScreenSharing, toggleScreenShare };
598
565
  }
599
566
 
567
+ // src/components/AgentStateBanner.tsx
568
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
569
+ function AgentStateBanner() {
570
+ const { isConnected } = useLiveAgent();
571
+ const { isScreenSharing } = useMediaControls();
572
+ const { state } = useAgentVoiceState();
573
+ if (!isConnected)
574
+ return null;
575
+ return /* @__PURE__ */ jsx("div", {
576
+ className: "skippr:fixed skippr:top-0 skippr:left-0 skippr:right-0 skippr:z-[2147483647] skippr:flex skippr:justify-center skippr:pointer-events-none",
577
+ children: /* @__PURE__ */ jsx("div", {
578
+ className: "skippr:pointer-events-auto skippr:flex skippr:items-center skippr:gap-2 skippr:bg-indigo-500/95 skippr:backdrop-blur-sm skippr:text-white skippr:text-xs skippr:font-medium skippr:px-4 skippr:py-1.5 skippr:rounded-b-lg skippr:shadow-lg",
579
+ children: /* @__PURE__ */ jsx(BannerContent, {
580
+ state,
581
+ isScreenSharing
582
+ })
583
+ })
584
+ });
585
+ }
586
+ function BannerContent({
587
+ state,
588
+ isScreenSharing
589
+ }) {
590
+ if (state === "speaking") {
591
+ return /* @__PURE__ */ jsxs(Fragment, {
592
+ children: [
593
+ /* @__PURE__ */ jsx(SpeakingBars, {}),
594
+ /* @__PURE__ */ jsx("span", {
595
+ children: "Skippr is talking"
596
+ })
597
+ ]
598
+ });
599
+ }
600
+ if (state === "thinking") {
601
+ return /* @__PURE__ */ jsxs(Fragment, {
602
+ children: [
603
+ /* @__PURE__ */ jsx(ThinkingDots, {}),
604
+ /* @__PURE__ */ jsx("span", {
605
+ children: "Skippr is thinking"
606
+ })
607
+ ]
608
+ });
609
+ }
610
+ if (state === "listening" && isScreenSharing) {
611
+ return /* @__PURE__ */ jsxs(Fragment, {
612
+ children: [
613
+ /* @__PURE__ */ jsx(ObservingDot, {}),
614
+ /* @__PURE__ */ jsx(Eye, {
615
+ className: "skippr:size-3.5"
616
+ }),
617
+ /* @__PURE__ */ jsx("span", {
618
+ children: "Skippr is observing this page"
619
+ })
620
+ ]
621
+ });
622
+ }
623
+ return /* @__PURE__ */ jsxs(Fragment, {
624
+ children: [
625
+ /* @__PURE__ */ jsx(ObservingDot, {}),
626
+ /* @__PURE__ */ jsx("span", {
627
+ children: "Skippr is connected"
628
+ })
629
+ ]
630
+ });
631
+ }
632
+ function ObservingDot() {
633
+ return /* @__PURE__ */ jsxs("span", {
634
+ className: "skippr:relative skippr:flex skippr:size-1.5",
635
+ children: [
636
+ /* @__PURE__ */ jsx("span", {
637
+ className: "skippr:absolute skippr:inline-flex skippr:size-full skippr:animate-ping skippr:rounded-full skippr:bg-emerald-400 skippr:opacity-75"
638
+ }),
639
+ /* @__PURE__ */ jsx("span", {
640
+ className: "skippr:relative skippr:inline-flex skippr:size-1.5 skippr:rounded-full skippr:bg-emerald-400"
641
+ })
642
+ ]
643
+ });
644
+ }
645
+ function ThinkingDots() {
646
+ return /* @__PURE__ */ jsxs("span", {
647
+ className: "skippr:flex skippr:items-center skippr:gap-[3px]",
648
+ children: [
649
+ /* @__PURE__ */ jsx("span", {
650
+ className: "skippr:size-1 skippr:rounded-full skippr:bg-white skippr:animate-bounce skippr:[animation-delay:0ms]"
651
+ }),
652
+ /* @__PURE__ */ jsx("span", {
653
+ className: "skippr:size-1 skippr:rounded-full skippr:bg-white skippr:animate-bounce skippr:[animation-delay:150ms]"
654
+ }),
655
+ /* @__PURE__ */ jsx("span", {
656
+ className: "skippr:size-1 skippr:rounded-full skippr:bg-white skippr:animate-bounce skippr:[animation-delay:300ms]"
657
+ })
658
+ ]
659
+ });
660
+ }
661
+ function SpeakingBars() {
662
+ return /* @__PURE__ */ jsxs("span", {
663
+ className: "skippr:flex skippr:items-center skippr:gap-[2px] skippr:h-3.5",
664
+ children: [
665
+ /* @__PURE__ */ jsx("span", {
666
+ className: "skippr:w-[2px] skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_infinite] skippr:h-1.5"
667
+ }),
668
+ /* @__PURE__ */ jsx("span", {
669
+ className: "skippr:w-[2px] skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_0.15s_infinite] skippr:h-3"
670
+ }),
671
+ /* @__PURE__ */ jsx("span", {
672
+ className: "skippr:w-[2px] skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_0.3s_infinite] skippr:h-2"
673
+ }),
674
+ /* @__PURE__ */ jsx("span", {
675
+ className: "skippr:w-[2px] skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_0.45s_infinite] skippr:h-3.5"
676
+ }),
677
+ /* @__PURE__ */ jsx("span", {
678
+ className: "skippr:w-[2px] skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_0.6s_infinite] skippr:h-1"
679
+ })
680
+ ]
681
+ });
682
+ }
683
+
684
+ // src/components/AutoStartMedia.tsx
685
+ import { useConnectionState, useLocalParticipant as useLocalParticipant2 } from "@livekit/components-react";
686
+ import { ConnectionState, Track } from "livekit-client";
687
+ import { useEffect as useEffect3, useRef } from "react";
688
+ function AutoStartMedia({ pendingScreenStream }) {
689
+ const { localParticipant } = useLocalParticipant2();
690
+ const connectionState = useConnectionState();
691
+ const didStartRef = useRef(false);
692
+ useEffect3(() => {
693
+ if (didStartRef.current)
694
+ return;
695
+ if (connectionState !== ConnectionState.Connected)
696
+ return;
697
+ didStartRef.current = true;
698
+ localParticipant.setMicrophoneEnabled(true).catch((error) => console.error("Failed to enable microphone:", error));
699
+ if (pendingScreenStream) {
700
+ const videoTrack = pendingScreenStream.getVideoTracks()[0];
701
+ if (videoTrack) {
702
+ videoTrack.contentHint = "detail";
703
+ localParticipant.publishTrack(videoTrack, { source: Track.Source.ScreenShare }).catch((error) => {
704
+ console.error("Failed to publish screen share track:", error);
705
+ for (const track of pendingScreenStream.getTracks())
706
+ track.stop();
707
+ });
708
+ }
709
+ }
710
+ }, [connectionState, localParticipant, pendingScreenStream]);
711
+ return null;
712
+ }
713
+
714
+ // src/components/MinimizedBubble.tsx
715
+ import { useEffect as useEffect4 } from "react";
716
+
600
717
  // src/lib/utils.ts
601
718
  import { clsx } from "clsx";
602
719
  import { twMerge } from "tailwind-merge";
@@ -606,12 +723,12 @@ function cn(...inputs) {
606
723
 
607
724
  // src/components/Logo.tsx
608
725
  import { useId } from "react";
609
- import { jsx, jsxs } from "react/jsx-runtime";
726
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
610
727
  function Logo({ className }) {
611
728
  const reactId = useId().replace(/:/g, "");
612
729
  const clipId = `skippr-logo-clip-${reactId}`;
613
730
  const gradientId = `skippr-logo-gradient-${reactId}`;
614
- return /* @__PURE__ */ jsxs("svg", {
731
+ return /* @__PURE__ */ jsxs2("svg", {
615
732
  width: "1em",
616
733
  height: "1em",
617
734
  viewBox: "0 0 30 30",
@@ -621,14 +738,14 @@ function Logo({ className }) {
621
738
  "aria-label": "Skippr",
622
739
  className,
623
740
  children: [
624
- /* @__PURE__ */ jsxs("g", {
741
+ /* @__PURE__ */ jsxs2("g", {
625
742
  clipPath: `url(#${clipId})`,
626
743
  children: [
627
- /* @__PURE__ */ jsx("path", {
744
+ /* @__PURE__ */ jsx2("path", {
628
745
  d: "M0 10C0 4.47715 4.47715 0 10 0H20C25.5228 0 30 4.47715 30 10V20C30 25.5228 25.5228 30 20 30H10C4.47715 30 0 25.5228 0 20V10Z",
629
746
  fill: "#2D2D3F"
630
747
  }),
631
- /* @__PURE__ */ jsx("rect", {
748
+ /* @__PURE__ */ jsx2("rect", {
632
749
  x: "7.83325",
633
750
  y: "14.9404",
634
751
  width: "12.4083",
@@ -637,11 +754,11 @@ function Logo({ className }) {
637
754
  transform: "rotate(-45 7.83325 14.9404)",
638
755
  fill: "#52FFF9"
639
756
  }),
640
- /* @__PURE__ */ jsx("path", {
757
+ /* @__PURE__ */ jsx2("path", {
641
758
  d: "M18.8975 12.5928C20.2728 12.5928 21.3877 13.647 21.3877 14.9474C21.3877 16.2479 20.2728 17.3021 18.8975 17.3021L11.4269 17.3021C10.0516 17.3021 8.93665 16.2479 8.93665 14.9474C8.93665 13.647 10.0516 12.5928 11.4269 12.5928L18.8975 12.5928Z",
642
759
  fill: `url(#${gradientId})`
643
760
  }),
644
- /* @__PURE__ */ jsx("rect", {
761
+ /* @__PURE__ */ jsx2("rect", {
645
762
  x: "10.1665",
646
763
  y: "20.4404",
647
764
  width: "12.4083",
@@ -652,9 +769,9 @@ function Logo({ className }) {
652
769
  })
653
770
  ]
654
771
  }),
655
- /* @__PURE__ */ jsxs("defs", {
772
+ /* @__PURE__ */ jsxs2("defs", {
656
773
  children: [
657
- /* @__PURE__ */ jsxs("linearGradient", {
774
+ /* @__PURE__ */ jsxs2("linearGradient", {
658
775
  id: gradientId,
659
776
  x1: "18.9237",
660
777
  y1: "16.9997",
@@ -662,19 +779,19 @@ function Logo({ className }) {
662
779
  y2: "14.1904",
663
780
  gradientUnits: "userSpaceOnUse",
664
781
  children: [
665
- /* @__PURE__ */ jsx("stop", {
782
+ /* @__PURE__ */ jsx2("stop", {
666
783
  offset: "0.473958",
667
784
  stopColor: "white"
668
785
  }),
669
- /* @__PURE__ */ jsx("stop", {
786
+ /* @__PURE__ */ jsx2("stop", {
670
787
  offset: "1",
671
788
  stopColor: "#52FFF9"
672
789
  })
673
790
  ]
674
791
  }),
675
- /* @__PURE__ */ jsx("clipPath", {
792
+ /* @__PURE__ */ jsx2("clipPath", {
676
793
  id: clipId,
677
- children: /* @__PURE__ */ jsx("rect", {
794
+ children: /* @__PURE__ */ jsx2("rect", {
678
795
  width: "30",
679
796
  height: "30",
680
797
  fill: "white"
@@ -687,18 +804,18 @@ function Logo({ className }) {
687
804
  }
688
805
 
689
806
  // src/components/ui/tooltip.tsx
690
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
807
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
691
808
  var ALIGN_CLASSES = {
692
809
  center: "skippr:left-1/2 skippr:-translate-x-1/2",
693
810
  start: "skippr:left-0",
694
811
  end: "skippr:right-0"
695
812
  };
696
813
  function Tooltip({ label, children, position = "top", align = "center" }) {
697
- return /* @__PURE__ */ jsxs2("span", {
814
+ return /* @__PURE__ */ jsxs3("span", {
698
815
  className: "skippr:relative skippr:inline-flex skippr:group",
699
816
  children: [
700
817
  children,
701
- /* @__PURE__ */ jsx2("span", {
818
+ /* @__PURE__ */ jsx3("span", {
702
819
  className: cn("skippr:pointer-events-none skippr:absolute skippr:z-10", "skippr:whitespace-nowrap skippr:rounded-md skippr:bg-foreground skippr:px-2 skippr:py-1", "skippr:text-[11px] skippr:text-background skippr:font-medium", "skippr:opacity-0 skippr:scale-95 skippr:transition-all skippr:duration-150", "skippr:group-hover:opacity-100 skippr:group-hover:scale-100", "skippr:group-focus-within:opacity-100 skippr:group-focus-within:scale-100", ALIGN_CLASSES[align], position === "top" && "skippr:bottom-full skippr:mb-1.5", position === "bottom" && "skippr:top-full skippr:mt-1.5"),
703
820
  "aria-hidden": "true",
704
821
  children: label
@@ -708,111 +825,67 @@ function Tooltip({ label, children, position = "top", align = "center" }) {
708
825
  }
709
826
 
710
827
  // src/components/MinimizedBubble.tsx
711
- import { jsx as jsx3, jsxs as jsxs3, Fragment } from "react/jsx-runtime";
828
+ import { jsx as jsx4, jsxs as jsxs4, Fragment as Fragment2 } from "react/jsx-runtime";
712
829
  var BUBBLE_BUTTON = "skippr:flex skippr:size-12 skippr:cursor-pointer skippr:items-center skippr:justify-center skippr:rounded-[14px] skippr:shadow-[0_4px_16px_rgba(45,43,61,0.45),0_2px_4px_rgba(0,0,0,0.1)] skippr:transition-all skippr:hover:-translate-y-0.5 skippr:active:translate-y-0";
713
- function AgentBubbleContent({ agentState }) {
714
- if (agentState === "speaking") {
715
- return /* @__PURE__ */ jsxs3("div", {
716
- className: "skippr:flex skippr:h-5 skippr:items-center skippr:justify-center skippr:gap-[3px]",
717
- children: [
718
- /* @__PURE__ */ jsx3("span", {
719
- className: "skippr:w-[3px] skippr:h-2 skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_infinite]"
720
- }),
721
- /* @__PURE__ */ jsx3("span", {
722
- className: "skippr:w-[3px] skippr:h-3.5 skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_0.15s_infinite]"
723
- }),
724
- /* @__PURE__ */ jsx3("span", {
725
- className: "skippr:w-[3px] skippr:h-2.5 skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_0.3s_infinite]"
726
- }),
727
- /* @__PURE__ */ jsx3("span", {
728
- className: "skippr:w-[3px] skippr:h-4 skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_0.45s_infinite]"
729
- }),
730
- /* @__PURE__ */ jsx3("span", {
731
- className: "skippr:w-[3px] skippr:h-1.5 skippr:rounded-sm skippr:bg-white skippr:animate-[skippr-speak_1.1s_ease-in-out_0.6s_infinite]"
732
- })
733
- ]
734
- });
735
- }
736
- if (agentState === "thinking") {
737
- return /* @__PURE__ */ jsxs3("div", {
738
- className: "skippr:flex skippr:items-center skippr:justify-center skippr:gap-[4px]",
739
- children: [
740
- /* @__PURE__ */ jsx3("span", {
741
- className: "skippr:size-1.5 skippr:rounded-full skippr:bg-white skippr:animate-bounce skippr:[animation-delay:0ms]"
742
- }),
743
- /* @__PURE__ */ jsx3("span", {
744
- className: "skippr:size-1.5 skippr:rounded-full skippr:bg-white skippr:animate-bounce skippr:[animation-delay:150ms]"
745
- }),
746
- /* @__PURE__ */ jsx3("span", {
747
- className: "skippr:size-1.5 skippr:rounded-full skippr:bg-white skippr:animate-bounce skippr:[animation-delay:300ms]"
748
- })
749
- ]
750
- });
751
- }
752
- return /* @__PURE__ */ jsx3(Logo, {
753
- className: "skippr:size-7"
754
- });
755
- }
756
830
  function ConnectedBubbleContent() {
757
831
  const { expandPanel, disconnect, position } = useLiveAgent();
758
- const { state: agentState } = useAgentVoiceState();
759
832
  const { isMuted, toggleMute, isScreenSharing, toggleScreenShare } = useMediaControls();
760
833
  const tooltipAlign = position === "right" ? "end" : "start";
761
- return /* @__PURE__ */ jsxs3(Fragment, {
834
+ return /* @__PURE__ */ jsxs4(Fragment2, {
762
835
  children: [
763
- /* @__PURE__ */ jsx3(Tooltip, {
836
+ /* @__PURE__ */ jsx4(Tooltip, {
764
837
  label: isMuted ? "Unmute" : "Mute",
765
838
  align: tooltipAlign,
766
- children: /* @__PURE__ */ jsx3("button", {
839
+ children: /* @__PURE__ */ jsx4("button", {
767
840
  type: "button",
768
841
  onClick: toggleMute,
769
842
  "aria-label": isMuted ? "Unmute" : "Mute",
770
843
  className: cn(BUBBLE_BUTTON, isMuted ? "skippr:bg-destructive skippr:text-destructive-foreground skippr:hover:bg-destructive/90" : "skippr:bg-white skippr:text-foreground skippr:hover:bg-muted"),
771
- children: isMuted ? /* @__PURE__ */ jsx3(MicOff, {
844
+ children: isMuted ? /* @__PURE__ */ jsx4(MicOff, {
772
845
  className: "skippr:size-5"
773
- }) : /* @__PURE__ */ jsx3(Mic, {
846
+ }) : /* @__PURE__ */ jsx4(Mic, {
774
847
  className: "skippr:size-5"
775
848
  })
776
849
  })
777
850
  }),
778
- /* @__PURE__ */ jsx3(Tooltip, {
851
+ /* @__PURE__ */ jsx4(Tooltip, {
779
852
  label: isScreenSharing ? "Stop sharing" : "Share screen",
780
853
  align: tooltipAlign,
781
- children: /* @__PURE__ */ jsx3("button", {
854
+ children: /* @__PURE__ */ jsx4("button", {
782
855
  type: "button",
783
856
  onClick: toggleScreenShare,
784
857
  "aria-label": isScreenSharing ? "Stop sharing screen" : "Share screen",
785
858
  className: cn(BUBBLE_BUTTON, isScreenSharing ? "skippr:bg-bubble skippr:text-white skippr:hover:brightness-110" : "skippr:bg-white skippr:text-foreground skippr:hover:bg-muted"),
786
- children: isScreenSharing ? /* @__PURE__ */ jsx3(MonitorOff, {
859
+ children: isScreenSharing ? /* @__PURE__ */ jsx4(MonitorOff, {
787
860
  className: "skippr:size-5"
788
- }) : /* @__PURE__ */ jsx3(Monitor, {
861
+ }) : /* @__PURE__ */ jsx4(Monitor, {
789
862
  className: "skippr:size-5"
790
863
  })
791
864
  })
792
865
  }),
793
- /* @__PURE__ */ jsx3(Tooltip, {
866
+ /* @__PURE__ */ jsx4(Tooltip, {
794
867
  label: "End session",
795
868
  align: tooltipAlign,
796
- children: /* @__PURE__ */ jsx3("button", {
869
+ children: /* @__PURE__ */ jsx4("button", {
797
870
  type: "button",
798
871
  onClick: () => disconnect(),
799
872
  "aria-label": "End session",
800
873
  className: cn(BUBBLE_BUTTON, "skippr:bg-destructive skippr:text-destructive-foreground skippr:hover:bg-destructive/90"),
801
- children: /* @__PURE__ */ jsx3(PhoneOff, {
874
+ children: /* @__PURE__ */ jsx4(PhoneOff, {
802
875
  className: "skippr:size-5"
803
876
  })
804
877
  })
805
878
  }),
806
- /* @__PURE__ */ jsx3(Tooltip, {
879
+ /* @__PURE__ */ jsx4(Tooltip, {
807
880
  label: "Open chat & transcript",
808
881
  align: tooltipAlign,
809
- children: /* @__PURE__ */ jsx3("button", {
882
+ children: /* @__PURE__ */ jsx4("button", {
810
883
  type: "button",
811
884
  onClick: expandPanel,
812
885
  "aria-label": "Open chat & transcript",
813
886
  className: cn(BUBBLE_BUTTON, "skippr:bg-bubble skippr:hover:brightness-110"),
814
- children: /* @__PURE__ */ jsx3(AgentBubbleContent, {
815
- agentState
887
+ children: /* @__PURE__ */ jsx4(Logo, {
888
+ className: "skippr:size-7"
816
889
  })
817
890
  })
818
891
  })
@@ -822,19 +895,19 @@ function ConnectedBubbleContent() {
822
895
  function IdleBubbleContent() {
823
896
  const { expandPanel, position } = useLiveAgent();
824
897
  const tooltipAlign = position === "right" ? "end" : "start";
825
- return /* @__PURE__ */ jsx3(Tooltip, {
898
+ return /* @__PURE__ */ jsx4(Tooltip, {
826
899
  label: "Open Skippr assistant",
827
900
  align: tooltipAlign,
828
- children: /* @__PURE__ */ jsxs3("button", {
901
+ children: /* @__PURE__ */ jsxs4("button", {
829
902
  type: "button",
830
903
  onClick: expandPanel,
831
904
  "aria-label": "Skippr assistant",
832
905
  className: cn(BUBBLE_BUTTON, "skippr:relative skippr:bg-bubble skippr:hover:brightness-110"),
833
906
  children: [
834
- /* @__PURE__ */ jsx3(Logo, {
907
+ /* @__PURE__ */ jsx4(Logo, {
835
908
  className: "skippr:relative skippr:z-10 skippr:size-7"
836
909
  }),
837
- /* @__PURE__ */ jsx3("span", {
910
+ /* @__PURE__ */ jsx4("span", {
838
911
  className: "skippr:absolute skippr:-inset-[3px] skippr:animate-pulse skippr:rounded-[17px] skippr:border-2 skippr:border-bubble/50"
839
912
  })
840
913
  ]
@@ -850,14 +923,14 @@ function WelcomeBubble({
850
923
  const timer = setTimeout(onDismiss, 5000);
851
924
  return () => clearTimeout(timer);
852
925
  }, [onDismiss]);
853
- return /* @__PURE__ */ jsxs3("button", {
926
+ return /* @__PURE__ */ jsxs4("button", {
854
927
  type: "button",
855
928
  className: cn("skippr:absolute skippr:bottom-full skippr:mb-3", "skippr:max-w-64 skippr:rounded-xl skippr:bg-card skippr:shadow-lg", "skippr:border skippr:border-border skippr:px-4 skippr:py-3", "skippr:text-sm skippr:text-foreground skippr:leading-relaxed skippr:text-left", "skippr:animate-[skippr-fade-in_0.3s_ease-out]", "skippr:cursor-pointer", position === "right" ? "skippr:right-0" : "skippr:left-0"),
856
929
  onClick: onDismiss,
857
930
  "aria-label": "Dismiss",
858
931
  children: [
859
932
  message,
860
- /* @__PURE__ */ jsx3("span", {
933
+ /* @__PURE__ */ jsx4("span", {
861
934
  className: cn("skippr:absolute skippr:top-full skippr:size-2.5", "skippr:border-l skippr:border-t skippr:border-border skippr:bg-card", "skippr:rotate-[225deg]", position === "right" ? "skippr:right-5" : "skippr:left-5", "skippr:-mt-[5px]")
862
935
  })
863
936
  ]
@@ -870,53 +943,19 @@ function MinimizedBubble({
870
943
  }) {
871
944
  const { isConnected, isStarting, position } = useLiveAgent();
872
945
  const inSession = isConnected || isStarting;
873
- return /* @__PURE__ */ jsxs3("div", {
946
+ return /* @__PURE__ */ jsxs4("div", {
874
947
  className: cn("skippr:fixed skippr:bottom-6 skippr:z-[9999]", "skippr:flex skippr:items-center skippr:gap-2", position === "right" ? "skippr:right-6" : "skippr:left-6"),
875
948
  children: [
876
- welcomeMessage && !inSession && !welcomeDismissed && /* @__PURE__ */ jsx3(WelcomeBubble, {
949
+ welcomeMessage && !inSession && !welcomeDismissed && /* @__PURE__ */ jsx4(WelcomeBubble, {
877
950
  message: welcomeMessage,
878
951
  position,
879
952
  onDismiss: onDismissWelcome
880
953
  }),
881
- inSession ? /* @__PURE__ */ jsx3(ConnectedBubbleContent, {}) : /* @__PURE__ */ jsx3(IdleBubbleContent, {})
954
+ inSession ? /* @__PURE__ */ jsx4(ConnectedBubbleContent, {}) : /* @__PURE__ */ jsx4(IdleBubbleContent, {})
882
955
  ]
883
956
  });
884
957
  }
885
958
 
886
- // src/components/ObservingBanner.tsx
887
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
888
- function ObservingBanner() {
889
- const { isConnected } = useLiveAgent();
890
- const { isScreenSharing } = useMediaControls();
891
- if (!isConnected || !isScreenSharing)
892
- return null;
893
- return /* @__PURE__ */ jsx4("div", {
894
- className: "skippr:fixed skippr:top-0 skippr:left-0 skippr:right-0 skippr:z-[2147483647] skippr:flex skippr:justify-center skippr:pointer-events-none",
895
- children: /* @__PURE__ */ jsxs4("div", {
896
- className: "skippr:pointer-events-auto skippr:flex skippr:items-center skippr:gap-2 skippr:bg-indigo-500/95 skippr:backdrop-blur-sm skippr:text-white skippr:text-xs skippr:font-medium skippr:px-4 skippr:py-1.5 skippr:rounded-b-lg skippr:shadow-lg",
897
- children: [
898
- /* @__PURE__ */ jsxs4("span", {
899
- className: "skippr:relative skippr:flex skippr:size-1.5",
900
- children: [
901
- /* @__PURE__ */ jsx4("span", {
902
- className: "skippr:absolute skippr:inline-flex skippr:size-full skippr:animate-ping skippr:rounded-full skippr:bg-emerald-400 skippr:opacity-75"
903
- }),
904
- /* @__PURE__ */ jsx4("span", {
905
- className: "skippr:relative skippr:inline-flex skippr:size-1.5 skippr:rounded-full skippr:bg-emerald-400"
906
- })
907
- ]
908
- }),
909
- /* @__PURE__ */ jsx4(Eye, {
910
- className: "skippr:size-3.5"
911
- }),
912
- /* @__PURE__ */ jsx4("span", {
913
- children: "Skippr is observing this page"
914
- })
915
- ]
916
- })
917
- });
918
- }
919
-
920
959
  // src/components/Sidebar.tsx
921
960
  import { useEffect as useEffect11 } from "react";
922
961
 
@@ -1719,8 +1758,8 @@ function MessageList({
1719
1758
 
1720
1759
  // src/components/SessionAgenda.tsx
1721
1760
  import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
1722
- function SessionAgenda({ phases }) {
1723
- if (phases.length === 0) {
1761
+ function SessionAgenda({ phases, hasStarted }) {
1762
+ if (phases.length === 0 || !hasStarted) {
1724
1763
  return /* @__PURE__ */ jsx14("div", {
1725
1764
  className: "skippr:flex skippr:flex-1 skippr:items-center skippr:justify-center",
1726
1765
  children: /* @__PURE__ */ jsx14(LoadingDots, {
@@ -1816,7 +1855,7 @@ function StartSessionPrompt({
1816
1855
  }
1817
1856
 
1818
1857
  // src/components/Sidebar.tsx
1819
- import { jsx as jsx17, jsxs as jsxs15, Fragment as Fragment2 } from "react/jsx-runtime";
1858
+ import { jsx as jsx17, jsxs as jsxs15, Fragment as Fragment3 } from "react/jsx-runtime";
1820
1859
  function Sidebar({
1821
1860
  hideControls = false,
1822
1861
  hideHeader = false,
@@ -1899,7 +1938,7 @@ function AuthenticatedContent({
1899
1938
  startSessionLabel,
1900
1939
  autoFocusChat
1901
1940
  }) {
1902
- return /* @__PURE__ */ jsxs15(Fragment2, {
1941
+ return /* @__PURE__ */ jsxs15(Fragment3, {
1903
1942
  children: [
1904
1943
  isConnected && /* @__PURE__ */ jsx17(ConnectedBanner, {}),
1905
1944
  /* @__PURE__ */ jsxs15("div", {
@@ -1937,7 +1976,7 @@ function AuthenticatedContent({
1937
1976
  }),
1938
1977
  /* @__PURE__ */ jsx17("div", {
1939
1978
  className: "skippr:flex skippr:min-h-0 skippr:flex-1 skippr:flex-col",
1940
- children: isConnected ? /* @__PURE__ */ jsx17(ConnectedBody, {
1979
+ children: isConnected || isStarting ? /* @__PURE__ */ jsx17(ConnectedBody, {
1941
1980
  activeTab,
1942
1981
  autoFocusChat
1943
1982
  }) : /* @__PURE__ */ jsx17("div", {
@@ -1972,7 +2011,8 @@ function ConnectedBody({
1972
2011
  return /* @__PURE__ */ jsx17("div", {
1973
2012
  className: "skippr:min-h-0 skippr:flex-1 skippr:overflow-y-auto skippr:animate-skippr-tab-fade",
1974
2013
  children: /* @__PURE__ */ jsx17(SessionAgenda, {
1975
- phases
2014
+ phases,
2015
+ hasStarted: allMessages.length > 0 || agentState === "speaking"
1976
2016
  })
1977
2017
  }, "agenda");
1978
2018
  }
@@ -2025,7 +2065,7 @@ function LiveAgent({
2025
2065
  hideHeader = false,
2026
2066
  startSessionLabel = "Talk to Skippr",
2027
2067
  autoFocusChat = true,
2028
- showObservingBanner = true,
2068
+ showAgentStateBanner = true,
2029
2069
  children
2030
2070
  }) {
2031
2071
  const auth = useAuth({ appKey });
@@ -2158,7 +2198,7 @@ function LiveAgent({
2158
2198
  onDisconnected: disconnect,
2159
2199
  children: [
2160
2200
  connection && /* @__PURE__ */ jsx19(RoomAudioRenderer, {}),
2161
- showObservingBanner && /* @__PURE__ */ jsx19(ObservingBanner, {}),
2201
+ showAgentStateBanner && /* @__PURE__ */ jsx19(AgentStateBanner, {}),
2162
2202
  connection && /* @__PURE__ */ jsx19(AutoStartMedia, {
2163
2203
  pendingScreenStream
2164
2204
  }),