@skippr/live-agent-sdk 0.57.0 → 0.59.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.
@@ -732,6 +732,7 @@ var NAME_MAX_CHARS = 80;
732
732
  // src/lib/launcher.ts
733
733
  var DEFAULT_LAUNCHER_BOTTOM_PX = 48;
734
734
  var LAUNCHER_HEIGHT_PX = 50;
735
+ var WIDGET_EDGE_MARGIN_PX = 12;
735
736
  var SESSION_BAR_CLEARANCE_PX = 76;
736
737
  var TRIGGER_HEIGHT_PX = 48;
737
738
  var IDLE_TRIGGER_CLEARANCE_PX = TRIGGER_HEIGHT_PX + 16;
@@ -1060,7 +1061,7 @@ var __iconNode21 = [
1060
1061
  ];
1061
1062
  var X = createLucideIcon("x", __iconNode21);
1062
1063
  // src/components/AgentCursor.tsx
1063
- import { useEffect as useEffect6, useLayoutEffect, useRef as useRef2, useState as useState6 } from "react";
1064
+ import { useContext as useContext2, useEffect as useEffect6, useLayoutEffect, useRef as useRef2, useState as useState6 } from "react";
1064
1065
 
1065
1066
  // src/capture/elementRef.ts
1066
1067
  function safeGetIframeDocument(iframe) {
@@ -1212,9 +1213,6 @@ var BASIC_ACT_DELAY_MS = 150;
1212
1213
  var TRACK_GLIDE_MS = 90;
1213
1214
  var GESTURE_GLIDE_MS = 500;
1214
1215
  var GESTURE_ACT_DELAY_MS = 200;
1215
- function cursorEntryPoint() {
1216
- return { x: window.innerWidth - 72, y: window.innerHeight - 80 };
1217
- }
1218
1216
  function gesturePoint(direction) {
1219
1217
  return {
1220
1218
  x: window.innerWidth / 2,
@@ -1224,6 +1222,13 @@ function gesturePoint(direction) {
1224
1222
  function centerOf(rect) {
1225
1223
  return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
1226
1224
  }
1225
+ function launcherCenter(position, launcherBottomPx) {
1226
+ const edge = WIDGET_EDGE_MARGIN_PX + LAUNCHER_HEIGHT_PX / 2;
1227
+ return {
1228
+ x: position === "left" ? edge : window.innerWidth - edge,
1229
+ y: window.innerHeight - launcherBottomPx - LAUNCHER_HEIGHT_PX / 2
1230
+ };
1231
+ }
1227
1232
  function ringTopLeft(rect) {
1228
1233
  return { x: rect.left - RING_PAD + 1 + ringRadius(rect), y: rect.top - RING_PAD + 1 };
1229
1234
  }
@@ -1238,6 +1243,7 @@ function AgentCursor({
1238
1243
  target,
1239
1244
  animated = false
1240
1245
  }) {
1246
+ const ctx = useContext2(LiveAgentContext);
1241
1247
  const [cursor, setCursor] = useState6(null);
1242
1248
  const [glideMs, setGlideMs] = useState6(0);
1243
1249
  const [phase, setPhase] = useState6("idle");
@@ -1307,7 +1313,8 @@ function AgentCursor({
1307
1313
  setPhase("done");
1308
1314
  setRingBox(null);
1309
1315
  const destination = gesturePoint(target.gesture.direction);
1310
- startGlide(prevCursorRef.current ?? cursorEntryPoint(), destination, GESTURE_GLIDE_MS, () => {
1316
+ const from2 = prevCursorRef.current ?? launcherCenter(ctx?.position ?? "right", ctx?.launcherBottomPx ?? 0);
1317
+ startGlide(from2, destination, GESTURE_GLIDE_MS, () => {
1311
1318
  if (target.mode === "act") {
1312
1319
  after(GESTURE_ACT_DELAY_MS, () => target.onAct?.());
1313
1320
  }
@@ -1345,7 +1352,7 @@ function AgentCursor({
1345
1352
  return cancelAnimation;
1346
1353
  }
1347
1354
  setPhase("travel");
1348
- const from = prevCursorRef.current ?? cursorEntryPoint();
1355
+ const from = prevCursorRef.current ?? launcherCenter(ctx?.position ?? "right", ctx?.launcherBottomPx ?? 0);
1349
1356
  const start = ringTopLeft(rect);
1350
1357
  startGlide(from, start, glideDuration(from, start), () => {
1351
1358
  after(DRAW_START_DELAY_MS, () => {
@@ -1800,7 +1807,47 @@ function isActionBlocked(element) {
1800
1807
  function escapeAttributeValue(value) {
1801
1808
  return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/[\r\n]+/g, " ");
1802
1809
  }
1803
- function extractAttrs(element, role) {
1810
+ var GENERIC_ICON_NAMES = new Set(["icon", "icons", "image", "img", "sprite", "sprites", "asset"]);
1811
+ function sanitizeIconName(src) {
1812
+ if (!src || src.startsWith("data:"))
1813
+ return null;
1814
+ const withoutQuery = src.split(/[?#]/)[0] ?? "";
1815
+ const basename = withoutQuery.slice(withoutQuery.lastIndexOf("/") + 1);
1816
+ const core = basename.split(".")[0] ?? "";
1817
+ const cleaned = core.replace(/^(?:icon[-_]?|ic[-_]|svg[-_])/i, "").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim().toLowerCase().replace(/\s*\bicons?$/, "").trim();
1818
+ if (!cleaned)
1819
+ return null;
1820
+ if (/^[0-9a-f]{8,}$/i.test(cleaned))
1821
+ return null;
1822
+ if (/^\d+$/.test(cleaned))
1823
+ return null;
1824
+ if (GENERIC_ICON_NAMES.has(cleaned))
1825
+ return null;
1826
+ if (cleaned.split(" ").length > 3)
1827
+ return null;
1828
+ return cleaned.slice(0, NAME_MAX_CHARS);
1829
+ }
1830
+ function hasInteractiveAncestorWithin(image, boundary) {
1831
+ let node = image.parentElement;
1832
+ while (node && node !== boundary) {
1833
+ if (isInteractive(node, inferRole(node)))
1834
+ return true;
1835
+ node = node.parentElement;
1836
+ }
1837
+ return false;
1838
+ }
1839
+ function iconNameHint(element) {
1840
+ if (element.tagName === "IMG") {
1841
+ return sanitizeIconName(element.getAttribute("src") || "");
1842
+ }
1843
+ const image = element.querySelector("img[src]");
1844
+ if (!image)
1845
+ return null;
1846
+ if (hasInteractiveAncestorWithin(image, element))
1847
+ return null;
1848
+ return sanitizeIconName(image.getAttribute("src") || "");
1849
+ }
1850
+ function extractAttrs(element, role, name) {
1804
1851
  const attributes = [];
1805
1852
  if (role === "link") {
1806
1853
  const href = element.getAttribute("href");
@@ -1884,6 +1931,11 @@ function extractAttrs(element, role) {
1884
1931
  if (/\.gif(\?|$)/i.test(imageSrc))
1885
1932
  attributes.push("animated");
1886
1933
  }
1934
+ if (!name && isInteractive(element, role)) {
1935
+ const hint = iconNameHint(element);
1936
+ if (hint)
1937
+ attributes.push(`iconName="${escapeAttributeValue(hint)}"`);
1938
+ }
1887
1939
  if (isScrollableContainer(element, role))
1888
1940
  attributes.push("scrollable");
1889
1941
  const isNativelyDisabled = "disabled" in element && element.disabled === true;
@@ -1943,12 +1995,13 @@ function walkAndCollect(element, depth, entries) {
1943
1995
  let childDepth = depth;
1944
1996
  if (isVisibleAndEmittable && role) {
1945
1997
  const ref = ensureStableRef(element);
1998
+ const name = accessibleName(element);
1946
1999
  entries.push({
1947
2000
  depth,
1948
2001
  role,
1949
- name: accessibleName(element),
2002
+ name,
1950
2003
  ref,
1951
- attrs: extractAttrs(element, role),
2004
+ attrs: extractAttrs(element, role, name),
1952
2005
  area: rect.width * rect.height
1953
2006
  });
1954
2007
  childDepth = depth + 1;
@@ -2501,7 +2554,7 @@ function HighlightOverlay() {
2501
2554
  }
2502
2555
 
2503
2556
  // src/components/MinimizedBubble.tsx
2504
- import { useContext as useContext2, useEffect as useEffect11, useRef as useRef7, useState as useState7 } from "react";
2557
+ import { useContext as useContext3, useEffect as useEffect11, useRef as useRef7, useState as useState7 } from "react";
2505
2558
 
2506
2559
  // src/hooks/useLauncherDrag.ts
2507
2560
  import { useEffect as useEffect10, useRef as useRef6 } from "react";
@@ -2788,7 +2841,7 @@ function MinimizedBubble({
2788
2841
  welcomeDismissed,
2789
2842
  onDismissWelcome
2790
2843
  }) {
2791
- const ctx = useContext2(LiveAgentContext);
2844
+ const ctx = useContext3(LiveAgentContext);
2792
2845
  if (!ctx) {
2793
2846
  throw new Error("MinimizedBubble must be used within a <LiveAgent> provider");
2794
2847
  }
@@ -3281,7 +3334,7 @@ function PageActionHandler() {
3281
3334
  }
3282
3335
 
3283
3336
  // src/components/SessionControlBar.tsx
3284
- import { useContext as useContext5, useRef as useRef10 } from "react";
3337
+ import { useContext as useContext6, useRef as useRef10 } from "react";
3285
3338
 
3286
3339
  // src/hooks/useAgentVoiceState.ts
3287
3340
  import { useVoiceAssistant } from "@livekit/components-react/hooks";
@@ -3353,9 +3406,9 @@ function useAudioLevelBars(mediaStreamTrack, { barCount, idleHeightPx, maxGrowth
3353
3406
  }
3354
3407
 
3355
3408
  // src/hooks/useLiveAgent.ts
3356
- import { useContext as useContext3 } from "react";
3409
+ import { useContext as useContext4 } from "react";
3357
3410
  function useLiveAgent() {
3358
- const ctx = useContext3(LiveAgentContext);
3411
+ const ctx = useContext4(LiveAgentContext);
3359
3412
  if (!ctx) {
3360
3413
  throw new Error("useLiveAgent must be used within a <LiveAgent> provider");
3361
3414
  }
@@ -3428,7 +3481,7 @@ function useMicLevel(enabled) {
3428
3481
  }
3429
3482
 
3430
3483
  // src/hooks/usePhaseUpdates.ts
3431
- import { useCallback as useCallback8, useContext as useContext4, useEffect as useEffect15 } from "react";
3484
+ import { useCallback as useCallback8, useContext as useContext5, useEffect as useEffect15 } from "react";
3432
3485
 
3433
3486
  // src/hooks/useAgentState.ts
3434
3487
  import { useRemoteParticipants } from "@livekit/components-react/hooks";
@@ -3484,7 +3537,7 @@ function parsePhases(json) {
3484
3537
  function usePhaseUpdates() {
3485
3538
  const parse = useCallback8(parsePhases, []);
3486
3539
  const livePhases = useAgentState("phases", parse, []);
3487
- const ctx = useContext4(LiveAgentContext);
3540
+ const ctx = useContext5(LiveAgentContext);
3488
3541
  useEffect15(() => {
3489
3542
  if (livePhases.length > 0)
3490
3543
  ctx?.setPhasesSnapshot(livePhases);
@@ -3584,7 +3637,7 @@ function SessionControlBar() {
3584
3637
  position,
3585
3638
  variant
3586
3639
  } = useLiveAgent();
3587
- const internalCtx = useContext5(LiveAgentContext);
3640
+ const internalCtx = useContext6(LiveAgentContext);
3588
3641
  const textMode = internalCtx?.textMode ?? false;
3589
3642
  const launcherBottomPx = internalCtx?.launcherBottomPx ?? DEFAULT_LAUNCHER_BOTTOM_PX;
3590
3643
  const popsDown = internalCtx?.popsDown ?? false;
@@ -3827,10 +3880,10 @@ function ShadowHost({ children }) {
3827
3880
  }
3828
3881
 
3829
3882
  // src/components/Sidebar.tsx
3830
- import { useContext as useContext9, useEffect as useEffect20 } from "react";
3883
+ import { useContext as useContext10, useEffect as useEffect20 } from "react";
3831
3884
 
3832
3885
  // src/hooks/useCombinedMessages.ts
3833
- import { useContext as useContext6, useMemo as useMemo5 } from "react";
3886
+ import { useContext as useContext7, useMemo as useMemo5 } from "react";
3834
3887
 
3835
3888
  // src/hooks/useChatMessages.ts
3836
3889
  import { useChat, useLocalParticipant as useLocalParticipant5 } from "@livekit/components-react/hooks";
@@ -3898,7 +3951,7 @@ function useCombinedMessages() {
3898
3951
  const { transcriptMessages } = useStreamingTranscript();
3899
3952
  const { chatMessages, sendChatMessage, isSendingChat } = useChatMessages();
3900
3953
  const { state: agentState } = useAgentVoiceState();
3901
- const historyMessages = useContext6(LiveAgentContext)?.historyMessages ?? [];
3954
+ const historyMessages = useContext7(LiveAgentContext)?.historyMessages ?? [];
3902
3955
  const liveMessages = useMemo5(() => {
3903
3956
  if (chatMessages.length === 0)
3904
3957
  return transcriptMessages;
@@ -3952,10 +4005,10 @@ function useSessionRemaining() {
3952
4005
 
3953
4006
  // src/hooks/useTextMode.ts
3954
4007
  import { useLocalParticipant as useLocalParticipant7 } from "@livekit/components-react/hooks";
3955
- import { useCallback as useCallback9, useContext as useContext7, useRef as useRef13 } from "react";
4008
+ import { useCallback as useCallback9, useContext as useContext8, useRef as useRef13 } from "react";
3956
4009
  var textEncoder3 = new TextEncoder;
3957
4010
  function useTextMode() {
3958
- const ctx = useContext7(LiveAgentContext);
4011
+ const ctx = useContext8(LiveAgentContext);
3959
4012
  if (!ctx) {
3960
4013
  throw new Error("useTextMode must be used within a <LiveAgent> provider");
3961
4014
  }
@@ -3984,7 +4037,7 @@ function useTextMode() {
3984
4037
  }
3985
4038
 
3986
4039
  // src/components/ChatHeader.tsx
3987
- import { useContext as useContext8 } from "react";
4040
+ import { useContext as useContext9 } from "react";
3988
4041
 
3989
4042
  // src/hooks/useElapsedSeconds.ts
3990
4043
  import { useEffect as useEffect17, useState as useState12 } from "react";
@@ -4009,7 +4062,7 @@ function useElapsedSeconds(isRunning) {
4009
4062
  import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
4010
4063
  function ChatHeader() {
4011
4064
  const { isConnected, variant } = useLiveAgent();
4012
- const internalCtx = useContext8(LiveAgentContext);
4065
+ const internalCtx = useContext9(LiveAgentContext);
4013
4066
  const panelExpanded = internalCtx?.panelExpanded ?? false;
4014
4067
  const togglePanelExpanded = internalCtx?.togglePanelExpanded ?? (() => {});
4015
4068
  const elapsed = useElapsedSeconds(isConnected);
@@ -4723,7 +4776,7 @@ function Sidebar({
4723
4776
  agentMode,
4724
4777
  agentControls
4725
4778
  } = useLiveAgent();
4726
- const internalCtx = useContext9(LiveAgentContext);
4779
+ const internalCtx = useContext10(LiveAgentContext);
4727
4780
  const usesHostAuth = internalCtx?.usesHostAuth ?? false;
4728
4781
  const authFailed = internalCtx?.authFailed ?? false;
4729
4782
  const launcherBottomPx = internalCtx?.launcherBottomPx ?? DEFAULT_LAUNCHER_BOTTOM_PX;
@@ -4983,7 +5036,7 @@ function ConnectedBody({
4983
5036
  }
4984
5037
 
4985
5038
  // src/components/SidebarTrigger.tsx
4986
- import { useContext as useContext10 } from "react";
5039
+ import { useContext as useContext11 } from "react";
4987
5040
 
4988
5041
  // src/components/Logo.tsx
4989
5042
  import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
@@ -5035,7 +5088,7 @@ function SidebarTrigger() {
5035
5088
  isStarting,
5036
5089
  isPausing
5037
5090
  } = useLiveAgent();
5038
- const internalCtx = useContext10(LiveAgentContext);
5091
+ const internalCtx = useContext11(LiveAgentContext);
5039
5092
  const launcherBottomPx = internalCtx?.launcherBottomPx ?? DEFAULT_LAUNCHER_BOTTOM_PX;
5040
5093
  const popsDown = internalCtx?.popsDown ?? false;
5041
5094
  if (isMinimized || isConnected || isStarting || isPausing)