@webless/agent 0.2.14 → 0.3.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/dist/react.cjs CHANGED
@@ -34,10 +34,90 @@ __export(react_exports, {
34
34
  module.exports = __toCommonJS(react_exports);
35
35
 
36
36
  // src/react/components/AgentWidget/AgentWidget.tsx
37
- var import_react5 = require("react");
37
+ var import_react6 = require("react");
38
38
 
39
- // src/react/hooks/useAgentChat.ts
39
+ // src/react/page-shift.ts
40
40
  var import_react = require("react");
41
+ var PAGE_SHIFT_CLASS = "webless-agent-page-shift";
42
+ var DEFAULT_RAIL_WIDTH_PX = 450;
43
+ function shouldApplyPageShift(input) {
44
+ return input.pageShift && !input.isMobile && !input.railCollapsed && !input.railExpanded;
45
+ }
46
+ function resolvePageShiftWidth(railWidth) {
47
+ if (typeof railWidth === "number" && railWidth > 0) {
48
+ return railWidth;
49
+ }
50
+ if (typeof document !== "undefined") {
51
+ const token = getComputedStyle(document.documentElement).getPropertyValue("--as-rail-max-width").trim();
52
+ const parsed = Number.parseFloat(token);
53
+ if (Number.isFinite(parsed) && parsed > 0) {
54
+ return parsed;
55
+ }
56
+ }
57
+ return DEFAULT_RAIL_WIDTH_PX;
58
+ }
59
+ var savedPageMargin = null;
60
+ function readPageMarginSnapshot(style) {
61
+ return {
62
+ value: style.getPropertyValue("margin-right"),
63
+ priority: style.getPropertyPriority("margin-right")
64
+ };
65
+ }
66
+ function restorePageMargin(style, snapshot) {
67
+ if (snapshot.value) {
68
+ style.setProperty("margin-right", snapshot.value, snapshot.priority || void 0);
69
+ return;
70
+ }
71
+ style.removeProperty("margin-right");
72
+ }
73
+ function snapshotPageMarginIfNeeded() {
74
+ if (savedPageMargin !== null) {
75
+ return;
76
+ }
77
+ savedPageMargin = readPageMarginSnapshot(document.documentElement.style);
78
+ }
79
+ function setPageMargin(margin) {
80
+ snapshotPageMarginIfNeeded();
81
+ document.documentElement.style.setProperty("margin-right", margin, "important");
82
+ }
83
+ function clearPageMargin() {
84
+ if (savedPageMargin === null) {
85
+ return;
86
+ }
87
+ restorePageMargin(document.documentElement.style, savedPageMargin);
88
+ savedPageMargin = null;
89
+ }
90
+ function usePageShift(input) {
91
+ const { active, railSlotRef } = input;
92
+ (0, import_react.useEffect)(() => {
93
+ if (typeof document === "undefined") {
94
+ return;
95
+ }
96
+ if (!active) {
97
+ document.documentElement.classList.remove(PAGE_SHIFT_CLASS);
98
+ clearPageMargin();
99
+ return;
100
+ }
101
+ document.documentElement.classList.add(PAGE_SHIFT_CLASS);
102
+ function applyMargin() {
103
+ const rail = railSlotRef.current?.querySelector(".agent-rail");
104
+ const width = resolvePageShiftWidth(
105
+ rail instanceof HTMLElement ? rail.offsetWidth : null
106
+ );
107
+ setPageMargin(`${width}px`);
108
+ }
109
+ applyMargin();
110
+ const frame = requestAnimationFrame(applyMargin);
111
+ return () => {
112
+ cancelAnimationFrame(frame);
113
+ document.documentElement.classList.remove(PAGE_SHIFT_CLASS);
114
+ clearPageMargin();
115
+ };
116
+ }, [active, railSlotRef]);
117
+ }
118
+
119
+ // src/react/hooks/useAgentChat.ts
120
+ var import_react2 = require("react");
41
121
 
42
122
  // src/runtime/client.ts
43
123
  var import_client2 = require("eve/client");
@@ -255,9 +335,8 @@ function clearPersistedAgentSession(visitorSessionId, options) {
255
335
  function isTurnBoundary(event) {
256
336
  return event.type === "session.waiting" || event.type === "session.completed" || event.type === "session.failed";
257
337
  }
258
- function applyMessageEvent(event, rendered, handlers) {
259
- const step = mapStepLabel(event);
260
- if (step) handlers.onStep?.(step.label, step.detail);
338
+ function applyMessageEvent(event, rendered, handlers, workItems) {
339
+ applyWorkEvent(event, handlers, workItems);
261
340
  if (event.type === "session.failed") {
262
341
  throw new Error(event.data.message || event.data.code);
263
342
  }
@@ -300,13 +379,120 @@ function renderTurn(events) {
300
379
  }
301
380
  return rendered;
302
381
  }
303
- function mapStepLabel(event) {
304
- if (event.type !== "step.started") return null;
305
- const stepIndex = event.data.stepIndex;
306
- return {
307
- label: "Model step running",
308
- detail: typeof stepIndex === "number" ? `Step ${stepIndex + 1}` : void 0
309
- };
382
+ function emitWorkItem(item, handlers, workItems) {
383
+ workItems.set(item.id, item);
384
+ handlers.onWork?.(item);
385
+ handlers.onStep?.(item.label, item.detail);
386
+ }
387
+ function completePlanning(handlers, workItems) {
388
+ const planning = workItems.get("planning");
389
+ if (!planning || planning.state !== "active") return;
390
+ emitWorkItem(
391
+ {
392
+ ...planning,
393
+ detail: "Picked the best way to help",
394
+ state: "completed"
395
+ },
396
+ handlers,
397
+ workItems
398
+ );
399
+ }
400
+ function specialistNameFromInput(input) {
401
+ const message = input.message;
402
+ if (typeof message !== "string") return void 0;
403
+ const match = /^Webless-Agent-Name:\s*(.+)$/imu.exec(message);
404
+ return match?.[1]?.trim() || void 0;
405
+ }
406
+ function requestedWorkItem(action) {
407
+ if (action.kind === "tool-call" && action.toolName === "search_discovery") {
408
+ return {
409
+ id: action.callId,
410
+ kind: "search",
411
+ label: "Search & Discovery",
412
+ detail: "Searching this site",
413
+ state: "active"
414
+ };
415
+ }
416
+ if (action.kind === "subagent-call" || action.kind === "remote-agent-call" || action.kind === "tool-call" && action.toolName === "agent") {
417
+ const name = specialistNameFromInput(action.input) ?? "Specialist";
418
+ return {
419
+ id: action.callId,
420
+ kind: "specialist",
421
+ label: name,
422
+ detail: "Reviewing your question",
423
+ state: "active"
424
+ };
425
+ }
426
+ return null;
427
+ }
428
+ function applyWorkEvent(event, handlers, workItems) {
429
+ if (event.type === "step.started" && workItems.size === 0) {
430
+ emitWorkItem(
431
+ {
432
+ id: "planning",
433
+ kind: "planning",
434
+ label: "Understanding your question",
435
+ state: "active"
436
+ },
437
+ handlers,
438
+ workItems
439
+ );
440
+ return;
441
+ }
442
+ if (event.type === "actions.requested") {
443
+ completePlanning(handlers, workItems);
444
+ for (const action of event.data.actions) {
445
+ const item = requestedWorkItem(action);
446
+ if (item) emitWorkItem(item, handlers, workItems);
447
+ }
448
+ return;
449
+ }
450
+ if (event.type === "subagent.called") {
451
+ completePlanning(handlers, workItems);
452
+ const current2 = workItems.get(event.data.callId);
453
+ if (!current2) {
454
+ emitWorkItem(
455
+ {
456
+ id: event.data.callId,
457
+ kind: "specialist",
458
+ label: event.data.name || "Specialist",
459
+ detail: "Reviewing your question",
460
+ state: "active"
461
+ },
462
+ handlers,
463
+ workItems
464
+ );
465
+ }
466
+ return;
467
+ }
468
+ if (event.type === "subagent.completed") {
469
+ const current2 = workItems.get(event.data.callId);
470
+ if (!current2) return;
471
+ emitWorkItem(
472
+ {
473
+ ...current2,
474
+ detail: "Guidance received",
475
+ state: "completed"
476
+ },
477
+ handlers,
478
+ workItems
479
+ );
480
+ return;
481
+ }
482
+ if (event.type !== "action.result") return;
483
+ const { result, status } = event.data;
484
+ const current = workItems.get(result.callId);
485
+ if (!current) return;
486
+ const failed = status !== "completed" || result.isError === true;
487
+ emitWorkItem(
488
+ {
489
+ ...current,
490
+ detail: failed ? "Couldn\u2019t complete; continuing with available information" : current.kind === "search" ? "Found relevant site content" : "Guidance received",
491
+ state: failed ? "error" : "completed"
492
+ },
493
+ handlers,
494
+ workItems
495
+ );
310
496
  }
311
497
  var AgentSession = class {
312
498
  constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, getUnpublishedPreviewGrant) {
@@ -424,10 +610,11 @@ var AgentSession = class {
424
610
  this.activeResponse = response;
425
611
  let streamIndex = session?.state.streamIndex ?? 0;
426
612
  let rendered = "";
613
+ const workItems = /* @__PURE__ */ new Map();
427
614
  try {
428
615
  for await (const event of response) {
429
616
  if (signal.aborted) break;
430
- rendered = applyMessageEvent(event, rendered, handlers);
617
+ rendered = applyMessageEvent(event, rendered, handlers, workItems);
431
618
  streamIndex += 1;
432
619
  if (session) {
433
620
  savePersistedAgentSession(
@@ -469,6 +656,10 @@ var AgentSession = class {
469
656
  return null;
470
657
  }
471
658
  let rendered = renderTurn(turnEvents);
659
+ const workItems = /* @__PURE__ */ new Map();
660
+ for (const event of turnEvents) {
661
+ applyWorkEvent(event, handlers, workItems);
662
+ }
472
663
  if (rendered.startsWith(initialText)) {
473
664
  const missedText = rendered.slice(initialText.length);
474
665
  if (missedText) handlers.onDelta(missedText);
@@ -503,7 +694,7 @@ var AgentSession = class {
503
694
  let streamIndex = snapshot.session.streamIndex;
504
695
  for await (const event of session.stream({ signal })) {
505
696
  if (signal.aborted) break;
506
- rendered = applyMessageEvent(event, rendered, handlers);
697
+ rendered = applyMessageEvent(event, rendered, handlers, workItems);
507
698
  streamIndex += 1;
508
699
  savePersistedAgentSession(
509
700
  this.visitorSessionId,
@@ -656,57 +847,54 @@ function clearPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
656
847
  }
657
848
 
658
849
  // src/react/hooks/useAgentChat.ts
659
- var GREETING_MESSAGE = {
660
- id: "greeting",
661
- role: "agent",
662
- text: "Hi! I'm connected to the Webless Agent Runtime. Ask anything about your published site index.",
663
- createdAt: 0
664
- };
665
- var INITIAL_STATE = {
666
- phase: "idle",
667
- messages: [GREETING_MESSAGE],
668
- toolSteps: [],
669
- journey: null,
670
- followUps: [],
671
- streamingText: "",
672
- error: null
673
- };
674
- function stateFromConversation(conversation) {
675
- if (!conversation || conversation.messages.length === 0) return INITIAL_STATE;
850
+ var DEFAULT_GREETING = "Hi! I can search this site or bring in a specialist when it helps. What would you like to know?";
851
+ function createInitialState(greeting = DEFAULT_GREETING) {
852
+ return {
853
+ phase: "idle",
854
+ messages: [
855
+ {
856
+ id: "greeting",
857
+ role: "agent",
858
+ text: greeting,
859
+ createdAt: 0
860
+ }
861
+ ],
862
+ toolSteps: [],
863
+ journey: null,
864
+ followUps: [],
865
+ streamingText: "",
866
+ error: null
867
+ };
868
+ }
869
+ function stateFromConversation(conversation, initialState) {
870
+ if (!conversation || conversation.messages.length === 0) return initialState;
676
871
  return {
677
- ...INITIAL_STATE,
872
+ ...initialState,
678
873
  messages: conversation.messages,
679
874
  phase: conversation.pending ? conversation.streamingText ? "streaming" : "thinking" : "complete",
680
875
  streamingText: conversation.streamingText
681
876
  };
682
877
  }
683
- var STATUS_SEQUENCE = [
684
- { id: "s1", label: "Starting Eve session", ms: 400 },
685
- { id: "s2", label: "Connecting to runtime", ms: 500 }
686
- ];
687
- function delay(ms, signal) {
688
- return new Promise((resolve, reject) => {
689
- const timer = window.setTimeout(resolve, ms);
690
- signal.addEventListener(
691
- "abort",
692
- () => {
693
- window.clearTimeout(timer);
694
- reject(new DOMException("Aborted", "AbortError"));
695
- },
696
- { once: true }
697
- );
698
- });
878
+ function upsertToolStep(steps, item) {
879
+ const next = {
880
+ id: item.id,
881
+ kind: item.kind,
882
+ label: item.label,
883
+ state: item.state,
884
+ ...item.detail ? { detail: item.detail } : {}
885
+ };
886
+ const index = steps.findIndex((step) => step.id === item.id);
887
+ if (index < 0) return [...steps, next];
888
+ return steps.map((step, stepIndex) => stepIndex === index ? next : step);
699
889
  }
700
- async function runStatusSequence(signal, onStep) {
701
- for (const item of STATUS_SEQUENCE) {
702
- onStep({
703
- id: item.id,
704
- label: item.label,
705
- detail: item.detail,
706
- state: "active"
707
- });
708
- await delay(item.ms, signal);
709
- }
890
+ function completeActivePlanning(steps) {
891
+ return steps.map(
892
+ (step) => step.kind === "planning" && step.state === "active" ? {
893
+ ...step,
894
+ detail: "Prepared a response",
895
+ state: "completed"
896
+ } : step
897
+ );
710
898
  }
711
899
  function useAgentChat({
712
900
  customerId,
@@ -715,9 +903,14 @@ function useAgentChat({
715
903
  version,
716
904
  runtimeOrigin,
717
905
  visitorSessionId,
718
- storageKeyPrefix
906
+ storageKeyPrefix,
907
+ greeting
719
908
  }) {
720
- const previewGrantProviderRef = (0, import_react.useRef)(getUnpublishedPreviewGrant);
909
+ const initialState = (0, import_react2.useMemo)(
910
+ () => createInitialState(greeting?.trim() || DEFAULT_GREETING),
911
+ [greeting]
912
+ );
913
+ const previewGrantProviderRef = (0, import_react2.useRef)(getUnpublishedPreviewGrant);
721
914
  previewGrantProviderRef.current = getUnpublishedPreviewGrant;
722
915
  const resolveUnpublishedPreviewGrant = () => {
723
916
  const provider = previewGrantProviderRef.current;
@@ -730,7 +923,7 @@ function useAgentChat({
730
923
  }
731
924
  return provider();
732
925
  };
733
- const resolvedStorageKeyPrefix = (0, import_react.useMemo)(
926
+ const resolvedStorageKeyPrefix = (0, import_react2.useMemo)(
734
927
  () => storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({
735
928
  customerId,
736
929
  indexId,
@@ -739,19 +932,20 @@ function useAgentChat({
739
932
  }),
740
933
  [customerId, indexId, runtimeOrigin, storageKeyPrefix, version]
741
934
  );
742
- const visitorId = (0, import_react.useMemo)(
935
+ const visitorId = (0, import_react2.useMemo)(
743
936
  () => visitorSessionId?.trim() || getOrCreateVisitorSessionId({
744
937
  storageKeyPrefix: resolvedStorageKeyPrefix
745
938
  }),
746
939
  [resolvedStorageKeyPrefix, visitorSessionId]
747
940
  );
748
- const [state, setState] = (0, import_react.useState)(
941
+ const [state, setState] = (0, import_react2.useState)(
749
942
  () => stateFromConversation(
750
- loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
943
+ loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
944
+ initialState
751
945
  )
752
946
  );
753
- const runRef = (0, import_react.useRef)(null);
754
- const clientRef = (0, import_react.useRef)(
947
+ const runRef = (0, import_react2.useRef)(null);
948
+ const clientRef = (0, import_react2.useRef)(
755
949
  createAgentClient({
756
950
  customerId,
757
951
  getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
@@ -762,9 +956,9 @@ function useAgentChat({
762
956
  storageKeyPrefix: resolvedStorageKeyPrefix
763
957
  })
764
958
  );
765
- const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}`;
766
- const identityRef = (0, import_react.useRef)(identityKey);
767
- (0, import_react.useEffect)(() => {
959
+ const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}|${greeting ?? ""}`;
960
+ const identityRef = (0, import_react2.useRef)(identityKey);
961
+ (0, import_react2.useEffect)(() => {
768
962
  if (identityRef.current === identityKey) {
769
963
  return;
770
964
  }
@@ -782,19 +976,21 @@ function useAgentChat({
782
976
  });
783
977
  setState(
784
978
  stateFromConversation(
785
- loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
979
+ loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
980
+ initialState
786
981
  )
787
982
  );
788
983
  }, [
789
984
  customerId,
790
985
  identityKey,
791
986
  indexId,
987
+ initialState,
792
988
  runtimeOrigin,
793
989
  resolvedStorageKeyPrefix,
794
990
  version,
795
991
  visitorId
796
992
  ]);
797
- (0, import_react.useEffect)(() => {
993
+ (0, import_react2.useEffect)(() => {
798
994
  if (!hasVisitorMessages(state.messages)) return;
799
995
  savePersistedAgentConversation(resolvedStorageKeyPrefix, visitorId, {
800
996
  messages: state.messages,
@@ -808,14 +1004,14 @@ function useAgentChat({
808
1004
  state.streamingText,
809
1005
  visitorId
810
1006
  ]);
811
- const reset = (0, import_react.useCallback)(() => {
1007
+ const reset = (0, import_react2.useCallback)(() => {
812
1008
  runRef.current?.abort();
813
1009
  runRef.current = null;
814
1010
  clientRef.current.reset();
815
1011
  clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
816
- setState(INITIAL_STATE);
817
- }, [resolvedStorageKeyPrefix, visitorId]);
818
- const runTurn = (0, import_react.useCallback)(
1012
+ setState(initialState);
1013
+ }, [initialState, resolvedStorageKeyPrefix, visitorId]);
1014
+ const runTurn = (0, import_react2.useCallback)(
819
1015
  async (input) => {
820
1016
  const { controller, initialText = "", resume, visitorText } = input;
821
1017
  const { signal } = controller;
@@ -823,35 +1019,23 @@ function useAgentChat({
823
1019
  try {
824
1020
  let streamStarted = Boolean(initialText);
825
1021
  let streamed = initialText;
826
- const planningPromise = resume ? Promise.resolve() : runStatusSequence(signal, (step) => {
827
- if (streamStarted || !isActiveRun()) return;
828
- setState((prev) => ({
829
- ...prev,
830
- phase: "running-tools",
831
- toolSteps: [step]
832
- }));
833
- });
834
1022
  const handlers = {
835
- onStep: (label, detail) => {
836
- if (streamStarted || !isActiveRun()) return;
1023
+ onWork: (item) => {
1024
+ if (!isActiveRun()) return;
837
1025
  setState((prev) => ({
838
1026
  ...prev,
839
- phase: "running-tools",
840
- toolSteps: [
841
- { id: `step-${label}`, label, detail, state: "active" }
842
- ]
1027
+ phase: item.state === "active" ? "running-tools" : prev.phase,
1028
+ toolSteps: upsertToolStep(prev.toolSteps, item)
843
1029
  }));
844
1030
  },
845
1031
  onDelta: (delta) => {
846
1032
  if (!isActiveRun()) return;
847
- void planningPromise.catch(() => {
848
- });
849
1033
  if (!streamStarted) {
850
1034
  streamStarted = true;
851
1035
  setState((prev) => ({
852
1036
  ...prev,
853
1037
  phase: "streaming",
854
- toolSteps: [],
1038
+ toolSteps: completeActivePlanning(prev.toolSteps),
855
1039
  streamingText: ""
856
1040
  }));
857
1041
  }
@@ -879,8 +1063,6 @@ function useAgentChat({
879
1063
  signal
880
1064
  });
881
1065
  }
882
- await planningPromise.catch(() => {
883
- });
884
1066
  if (!isActiveRun() || finalText === null) return;
885
1067
  const agentMessage = {
886
1068
  id: `agent-${Date.now()}`,
@@ -892,7 +1074,7 @@ function useAgentChat({
892
1074
  ...prev,
893
1075
  phase: "complete",
894
1076
  messages: [...prev.messages, agentMessage],
895
- toolSteps: [],
1077
+ toolSteps: completeActivePlanning(prev.toolSteps),
896
1078
  streamingText: "",
897
1079
  followUps: [],
898
1080
  journey: null
@@ -907,7 +1089,13 @@ function useAgentChat({
907
1089
  setState((prev) => ({
908
1090
  ...prev,
909
1091
  phase: "complete",
910
- toolSteps: [],
1092
+ toolSteps: prev.toolSteps.map(
1093
+ (step) => step.state === "active" ? {
1094
+ ...step,
1095
+ detail: "Couldn\u2019t complete this step",
1096
+ state: "error"
1097
+ } : step
1098
+ ),
911
1099
  streamingText: "",
912
1100
  error: message
913
1101
  }));
@@ -916,7 +1104,7 @@ function useAgentChat({
916
1104
  },
917
1105
  []
918
1106
  );
919
- const submit = (0, import_react.useCallback)(
1107
+ const submit = (0, import_react2.useCallback)(
920
1108
  async (visitorText) => {
921
1109
  if (runRef.current) {
922
1110
  runRef.current.abort();
@@ -935,7 +1123,12 @@ function useAgentChat({
935
1123
  phase: "thinking",
936
1124
  messages: [...prev.messages, visitorMessage],
937
1125
  toolSteps: [
938
- { id: "s1", label: "Starting Eve session", state: "active" }
1126
+ {
1127
+ id: "planning",
1128
+ kind: "planning",
1129
+ label: "Understanding your question",
1130
+ state: "active"
1131
+ }
939
1132
  ],
940
1133
  journey: null,
941
1134
  followUps: [],
@@ -946,7 +1139,7 @@ function useAgentChat({
946
1139
  },
947
1140
  [runTurn]
948
1141
  );
949
- (0, import_react.useEffect)(() => {
1142
+ (0, import_react2.useEffect)(() => {
950
1143
  const conversation = loadPersistedAgentConversation(
951
1144
  resolvedStorageKeyPrefix,
952
1145
  visitorId
@@ -969,7 +1162,7 @@ function useAgentChat({
969
1162
  controller.abort();
970
1163
  };
971
1164
  }, [identityKey, resolvedStorageKeyPrefix, runTurn, visitorId]);
972
- (0, import_react.useEffect)(() => {
1165
+ (0, import_react2.useEffect)(() => {
973
1166
  return () => {
974
1167
  runRef.current?.abort();
975
1168
  runRef.current = null;
@@ -998,12 +1191,12 @@ function isAgentBusy(phase) {
998
1191
  }
999
1192
 
1000
1193
  // src/react/hooks/useIsMobile.ts
1001
- var import_react2 = require("react");
1194
+ var import_react3 = require("react");
1002
1195
  function useIsMobile(breakpoint = 767) {
1003
- const [isMobile, setIsMobile] = (0, import_react2.useState)(
1196
+ const [isMobile, setIsMobile] = (0, import_react3.useState)(
1004
1197
  () => typeof window !== "undefined" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
1005
1198
  );
1006
- (0, import_react2.useEffect)(() => {
1199
+ (0, import_react3.useEffect)(() => {
1007
1200
  const media = window.matchMedia(`(max-width: ${breakpoint}px)`);
1008
1201
  const onChange = () => setIsMobile(media.matches);
1009
1202
  onChange();
@@ -1040,81 +1233,95 @@ function unregisterAgentPanelController(customerId) {
1040
1233
  }
1041
1234
 
1042
1235
  // src/react/components/AgentRail/AgentRail.tsx
1043
- var import_react4 = require("react");
1236
+ var import_react5 = require("react");
1044
1237
 
1045
- // src/react/components/ToolTimeline/ToolTimeline.tsx
1238
+ // src/react/types/conversation.ts
1239
+ var defaultAgentRailTheme = {
1240
+ railMaxWidth: "450px",
1241
+ brand: "#6f16ff",
1242
+ brandSoft: "#f3edff",
1243
+ brandDeep: "#12043e",
1244
+ surface: "#ffffff",
1245
+ surfaceMuted: "#f4f6fb",
1246
+ text: "#171b2a",
1247
+ textMuted: "#5a6378",
1248
+ textSubtle: "#8a94a8",
1249
+ border: "rgb(42 51 70 / 0.1)",
1250
+ visitorBubble: "#6f16ff",
1251
+ visitorText: "#ffffff",
1252
+ success: "#18794e",
1253
+ danger: "#c94b63",
1254
+ fontBody: '"Mulish", "Avenir Next", "Segoe UI", sans-serif',
1255
+ fontDisplay: '"Space Grotesk", sans-serif'
1256
+ };
1257
+
1258
+ // src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
1046
1259
  var import_jsx_runtime = require("react/jsx-runtime");
1047
- function SpinnerIcon() {
1048
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className: "agent-status__spinner", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
1049
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "8", cy: "8", r: "6", stroke: "currentColor", strokeWidth: "1.5", strokeOpacity: "0.25" }),
1050
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 8a6 6 0 0 0-6-6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
1051
- ] });
1052
- }
1053
- function getCurrentStep(steps) {
1054
- const active = steps.find((step) => step.state === "active");
1055
- if (active) return active;
1056
- const error = steps.find((step) => step.state === "error");
1057
- if (error) return error;
1058
- const pending = steps.find((step) => step.state === "pending");
1059
- if (pending) return pending;
1060
- return steps.at(-1) ?? null;
1061
- }
1062
- function ToolTimeline({
1063
- steps,
1064
- streamingText,
1065
- showStreaming = false,
1066
- inline = false
1067
- }) {
1068
- if (steps.length === 0 && !(showStreaming && streamingText)) return null;
1069
- const currentStep = getCurrentStep(steps);
1070
- const showStatus = currentStep && currentStep.state !== "completed" && !(showStreaming && streamingText);
1071
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1072
- "div",
1073
- {
1074
- className: `tool-timeline${inline ? " tool-timeline--inline" : ""}`,
1075
- role: "status",
1076
- "aria-live": "polite",
1077
- "aria-label": "Agent progress",
1078
- children: [
1079
- showStatus ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-status", children: [
1080
- currentStep.state === "error" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__icon agent-status__icon--error", "aria-hidden": "true", children: "!" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SpinnerIcon, {}) }),
1081
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-status__copy", children: [
1082
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__label", children: currentStep.label }),
1083
- currentStep.detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__detail", children: currentStep.detail }) : null
1084
- ] })
1085
- ] }, currentStep.id) : null,
1086
- showStreaming && streamingText ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "tool-timeline__streaming-text", children: [
1087
- streamingText,
1088
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tool-timeline__cursor", "aria-hidden": "true" })
1089
- ] }) : null
1090
- ]
1091
- }
1260
+ function workSummary(steps) {
1261
+ const active = [...steps].reverse().find((step) => step.state === "active");
1262
+ if (active?.kind === "specialist") return `Working with ${active.label}`;
1263
+ if (active?.kind === "search") return "Searching this site";
1264
+ if (active) return active.label;
1265
+ const hasError = steps.some((step) => step.state === "error");
1266
+ const specialists = steps.filter(
1267
+ (step) => step.kind === "specialist" && step.state === "completed"
1092
1268
  );
1269
+ const searched = steps.some(
1270
+ (step) => step.kind === "search" && step.state === "completed"
1271
+ );
1272
+ if (hasError) return "Answered with available information";
1273
+ if (specialists.length > 1)
1274
+ return `Consulted ${specialists.length} specialists`;
1275
+ if (specialists.length === 1) return `Consulted ${specialists[0]?.label}`;
1276
+ if (searched) return "Searched this site";
1277
+ return "Prepared a response";
1093
1278
  }
1094
-
1095
- // src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
1096
- var import_jsx_runtime2 = require("react/jsx-runtime");
1097
- function AgentActivityBubble({
1098
- steps,
1099
- streamingText,
1100
- showStreaming = false
1101
- }) {
1102
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("article", { className: "agent-activity-bubble", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "agent-activity-bubble__shell", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1103
- ToolTimeline,
1104
- {
1105
- steps,
1106
- streamingText,
1107
- showStreaming,
1108
- inline: true
1109
- }
1110
- ) }) });
1279
+ function AgentActivityBubble({ steps }) {
1280
+ const active = steps.some((step) => step.state === "active");
1281
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", { className: "agent-activity-bubble", children: [
1282
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "agent-activity-bubble__status", "aria-live": "polite", children: [
1283
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1284
+ "span",
1285
+ {
1286
+ className: `agent-activity-bubble__pulse${active ? " is-active" : ""}`,
1287
+ "aria-hidden": "true"
1288
+ }
1289
+ ),
1290
+ workSummary(steps)
1291
+ ] }),
1292
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { className: "agent-activity-bubble__details", open: active, children: [
1293
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: "Work details" }),
1294
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "agent-activity-bubble__steps", children: steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1295
+ "li",
1296
+ {
1297
+ className: "agent-activity-bubble__step",
1298
+ "data-state": step.state,
1299
+ children: [
1300
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1301
+ "span",
1302
+ {
1303
+ className: "agent-activity-bubble__step-icon",
1304
+ "aria-hidden": "true",
1305
+ children: step.state === "completed" ? "\u2713" : step.state === "error" ? "!" : ""
1306
+ }
1307
+ ),
1308
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "agent-activity-bubble__step-copy", children: [
1309
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: step.label }),
1310
+ step.detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: step.detail }) : null
1311
+ ] })
1312
+ ]
1313
+ },
1314
+ step.id
1315
+ )) })
1316
+ ] })
1317
+ ] });
1111
1318
  }
1112
1319
 
1113
1320
  // src/react/components/Composer/Composer.tsx
1114
- var import_react3 = require("react");
1115
- var import_jsx_runtime3 = require("react/jsx-runtime");
1321
+ var import_react4 = require("react");
1322
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1116
1323
  function SendIcon() {
1117
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M8 12V4M8 4l-3 3M8 4l3 3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
1324
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8 12V4M8 4l-3 3M8 4l3 3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
1118
1325
  }
1119
1326
  function Composer({
1120
1327
  disabled = false,
@@ -1122,8 +1329,8 @@ function Composer({
1122
1329
  variant = "default",
1123
1330
  onSubmit
1124
1331
  }) {
1125
- const [value, setValue] = (0, import_react3.useState)("");
1126
- const inputRef = (0, import_react3.useRef)(null);
1332
+ const [value, setValue] = (0, import_react4.useState)("");
1333
+ const inputRef = (0, import_react4.useRef)(null);
1127
1334
  function submitCurrent() {
1128
1335
  const trimmed = value.trim();
1129
1336
  if (!trimmed || disabled) return;
@@ -1141,8 +1348,8 @@ function Composer({
1141
1348
  submitCurrent();
1142
1349
  }
1143
1350
  }
1144
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("form", { className: `composer${variant === "dock" ? " composer--dock" : ""}`, onSubmit: handleSubmit, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "composer__field", children: [
1145
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1351
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("form", { className: `composer${variant === "dock" ? " composer--dock" : ""}`, onSubmit: handleSubmit, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "composer__field", children: [
1352
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1146
1353
  "textarea",
1147
1354
  {
1148
1355
  ref: inputRef,
@@ -1156,21 +1363,21 @@ function Composer({
1156
1363
  onKeyDown: handleKeyDown
1157
1364
  }
1158
1365
  ),
1159
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1366
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1160
1367
  "button",
1161
1368
  {
1162
1369
  type: "submit",
1163
1370
  className: "composer__send",
1164
1371
  disabled: disabled || !value.trim(),
1165
1372
  "aria-label": "Send message",
1166
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
1373
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SendIcon, {})
1167
1374
  }
1168
1375
  )
1169
1376
  ] }) });
1170
1377
  }
1171
1378
 
1172
1379
  // src/react/components/FollowUpChips/FollowUpChips.tsx
1173
- var import_jsx_runtime4 = require("react/jsx-runtime");
1380
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1174
1381
  function FollowUpChips({
1175
1382
  suggestions,
1176
1383
  disabled = false,
@@ -1180,7 +1387,7 @@ function FollowUpChips({
1180
1387
  }) {
1181
1388
  if (suggestions.length === 0) return null;
1182
1389
  if (variant === "dock") {
1183
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "followups followups--dock", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "followups__scroll", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1390
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "followups followups--dock", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "followups__scroll", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1184
1391
  "button",
1185
1392
  {
1186
1393
  type: "button",
@@ -1192,9 +1399,9 @@ function FollowUpChips({
1192
1399
  suggestion.id
1193
1400
  )) }) });
1194
1401
  }
1195
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "followups", children: [
1196
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "followups__label", children: label }),
1197
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "followups__list", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1402
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "followups", children: [
1403
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "followups__label", children: label }),
1404
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "followups__list", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1198
1405
  "button",
1199
1406
  {
1200
1407
  type: "button",
@@ -1211,12 +1418,12 @@ function FollowUpChips({
1211
1418
  // src/react/components/MessageBubble/MessageBubble.tsx
1212
1419
  var import_streamdown = require("streamdown");
1213
1420
  var import_styles = require("streamdown/styles.css");
1214
- var import_jsx_runtime5 = require("react/jsx-runtime");
1421
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1215
1422
  function MessageBubble({ message }) {
1216
1423
  if (message.role === "visitor") {
1217
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "message-bubble__text", children: message.text }) });
1424
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "message-bubble__text", children: message.text }) });
1218
1425
  }
1219
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("article", { className: "message-bubble message-bubble--agent", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "message-bubble__text", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1426
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("article", { className: "message-bubble message-bubble--agent", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "message-bubble__text", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1220
1427
  import_streamdown.Streamdown,
1221
1428
  {
1222
1429
  animated: true,
@@ -1233,12 +1440,20 @@ function MessageBubble({ message }) {
1233
1440
  }
1234
1441
 
1235
1442
  // src/react/components/AgentRail/AgentRail.tsx
1236
- var import_jsx_runtime6 = require("react/jsx-runtime");
1443
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1237
1444
  function MinimizeIcon() {
1238
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3.5 8h9", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
1445
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1446
+ "path",
1447
+ {
1448
+ d: "M3.5 8h9",
1449
+ stroke: "currentColor",
1450
+ strokeWidth: "1.7",
1451
+ strokeLinecap: "round"
1452
+ }
1453
+ ) });
1239
1454
  }
1240
1455
  function ExpandIcon() {
1241
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1456
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1242
1457
  "path",
1243
1458
  {
1244
1459
  d: "M6 3.5H3.5V6M10 3.5h2.5V6M10 12.5h2.5V10M6 12.5H3.5V10",
@@ -1250,7 +1465,7 @@ function ExpandIcon() {
1250
1465
  ) });
1251
1466
  }
1252
1467
  function RestoreIcon() {
1253
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1468
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1254
1469
  "path",
1255
1470
  {
1256
1471
  d: "M5.5 5.5H3.5V7.5M10.5 5.5h2V7.5M10.5 10.5h2V8.5M5.5 10.5H3.5V8.5",
@@ -1265,6 +1480,7 @@ function AgentRail({
1265
1480
  state,
1266
1481
  theme,
1267
1482
  brandLabel = "Webless Assist",
1483
+ brandLogoUrl,
1268
1484
  poweredByLabel = "Powered by Webless",
1269
1485
  composerPlaceholder = "Ask anything\u2026",
1270
1486
  mobileFullscreen = false,
@@ -1275,11 +1491,32 @@ function AgentRail({
1275
1491
  onSubmit,
1276
1492
  onFollowUpSelect
1277
1493
  }) {
1278
- const transcriptRef = (0, import_react4.useRef)(null);
1279
- const railStyle = theme?.railMaxWidth ? { ["--rail-width"]: theme.railMaxWidth, ["--as-rail-max-width"]: theme.railMaxWidth } : void 0;
1494
+ const transcriptRef = (0, import_react5.useRef)(null);
1495
+ const resolvedTheme = { ...defaultAgentRailTheme, ...theme };
1496
+ const railStyle = {
1497
+ "--rail-width": resolvedTheme.railMaxWidth,
1498
+ "--as-rail-max-width": resolvedTheme.railMaxWidth,
1499
+ "--as-brand": resolvedTheme.brand,
1500
+ "--as-brand-soft": resolvedTheme.brandSoft,
1501
+ "--as-brand-deep": resolvedTheme.brandDeep,
1502
+ "--as-surface": resolvedTheme.surface,
1503
+ "--as-surface-muted": resolvedTheme.surfaceMuted,
1504
+ "--as-text": resolvedTheme.text,
1505
+ "--as-text-muted": resolvedTheme.textMuted,
1506
+ "--as-text-subtle": resolvedTheme.textSubtle,
1507
+ "--as-border": resolvedTheme.border,
1508
+ "--as-visitor-bubble": resolvedTheme.visitorBubble,
1509
+ "--as-visitor-text": resolvedTheme.visitorText,
1510
+ "--as-success": resolvedTheme.success,
1511
+ "--as-danger": resolvedTheme.danger,
1512
+ "--as-font-body": resolvedTheme.fontBody,
1513
+ "--as-font-display": resolvedTheme.fontDisplay
1514
+ };
1280
1515
  const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming";
1281
- const showActivity = state.toolSteps.length > 0 && (state.phase === "thinking" || state.phase === "running-tools");
1282
- const hasVisitorMessages2 = state.messages.some((message) => message.role === "visitor");
1516
+ const showActivity = state.toolSteps.length > 0;
1517
+ const hasVisitorMessages2 = state.messages.some(
1518
+ (message) => message.role === "visitor"
1519
+ );
1283
1520
  const showIdleFollowUps = !hasVisitorMessages2 && state.followUps.length > 0;
1284
1521
  const showDockFollowUps = expanded && showIdleFollowUps;
1285
1522
  const streamingMessage = state.phase === "streaming" && state.streamingText ? {
@@ -1289,46 +1526,77 @@ function AgentRail({
1289
1526
  streaming: true,
1290
1527
  text: state.streamingText
1291
1528
  } : null;
1292
- (0, import_react4.useEffect)(() => {
1529
+ (0, import_react5.useEffect)(() => {
1293
1530
  const node = transcriptRef.current;
1294
1531
  if (!node) return;
1295
1532
  node.scrollTop = node.scrollHeight;
1296
- }, [state.messages, state.toolSteps, state.streamingText, state.followUps, state.journey]);
1297
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1533
+ }, [
1534
+ state.messages,
1535
+ state.toolSteps,
1536
+ state.streamingText,
1537
+ state.followUps,
1538
+ state.journey
1539
+ ]);
1540
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1298
1541
  "aside",
1299
1542
  {
1300
1543
  className: `agent-rail${mobileFullscreen ? " agent-rail--mobile-fullscreen" : ""}${expanded ? " agent-rail--expanded" : ""}`,
1301
1544
  style: railStyle,
1302
1545
  "aria-label": "Agent conversation",
1303
1546
  children: [
1304
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("header", { className: "agent-rail__header", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__brand-row", children: [
1305
- onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1547
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("header", { className: "agent-rail__header", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__brand-row", children: [
1548
+ onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1306
1549
  "button",
1307
1550
  {
1308
1551
  type: "button",
1309
1552
  className: "agent-rail__collapse",
1310
1553
  "aria-label": "Collapse assist",
1311
1554
  onClick: onCollapse,
1312
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MinimizeIcon, {})
1555
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MinimizeIcon, {})
1556
+ }
1557
+ ) : onClose ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1558
+ "button",
1559
+ {
1560
+ type: "button",
1561
+ className: "agent-rail__close",
1562
+ "aria-label": "Close agent",
1563
+ onClick: onClose,
1564
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MinimizeIcon, {})
1313
1565
  }
1314
- ) : onClose ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "agent-rail__close", "aria-label": "Close agent", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MinimizeIcon, {}) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
1315
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-label", children: brandLabel }),
1316
- onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1566
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
1567
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "agent-rail__identity", children: [
1568
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "agent-rail__brand-mark", "aria-hidden": "true", children: [
1569
+ brandLabel.slice(0, 1).toUpperCase(),
1570
+ brandLogoUrl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1571
+ "img",
1572
+ {
1573
+ className: "agent-rail__brand-logo",
1574
+ src: brandLogoUrl,
1575
+ alt: "",
1576
+ onError: (event) => {
1577
+ event.currentTarget.hidden = true;
1578
+ }
1579
+ }
1580
+ ) : null
1581
+ ] }),
1582
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-label", children: brandLabel })
1583
+ ] }),
1584
+ onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1317
1585
  "button",
1318
1586
  {
1319
1587
  type: "button",
1320
1588
  className: "agent-rail__expand",
1321
1589
  "aria-label": expanded ? "Restore assist panel" : "Expand assist panel",
1322
1590
  onClick: onExpandToggle,
1323
- children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpandIcon, {})
1591
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpandIcon, {})
1324
1592
  }
1325
- ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" })
1593
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" })
1326
1594
  ] }) }),
1327
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: [
1328
- state.messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message }, message.id)),
1329
- streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message: streamingMessage }) : null,
1330
- showActivity ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AgentActivityBubble, { steps: state.toolSteps }) : null,
1331
- !expanded && showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1595
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: [
1596
+ state.messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MessageBubble, { message }, message.id)),
1597
+ streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MessageBubble, { message: streamingMessage }) : null,
1598
+ showActivity ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AgentActivityBubble, { steps: state.toolSteps }) : null,
1599
+ !expanded && showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1332
1600
  FollowUpChips,
1333
1601
  {
1334
1602
  suggestions: state.followUps,
@@ -1337,10 +1605,17 @@ function AgentRail({
1337
1605
  onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
1338
1606
  }
1339
1607
  ) }) : null,
1340
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "alert", style: { fontSize: 13, color: "var(--as-danger)", margin: 0 }, children: state.error }) : null
1608
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1609
+ "p",
1610
+ {
1611
+ role: "alert",
1612
+ style: { fontSize: 13, color: "var(--as-danger)", margin: 0 },
1613
+ children: state.error
1614
+ }
1615
+ ) : null
1341
1616
  ] }),
1342
- expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__dock-wrap", children: [
1343
- showDockFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__dock-followups", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1617
+ expanded ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__dock-wrap", children: [
1618
+ showDockFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__dock-followups", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1344
1619
  FollowUpChips,
1345
1620
  {
1346
1621
  variant: "dock",
@@ -1349,7 +1624,7 @@ function AgentRail({
1349
1624
  onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
1350
1625
  }
1351
1626
  ) }) : null,
1352
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__dock", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1627
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__dock", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1353
1628
  Composer,
1354
1629
  {
1355
1630
  variant: "dock",
@@ -1358,12 +1633,12 @@ function AgentRail({
1358
1633
  onSubmit
1359
1634
  }
1360
1635
  ) }),
1361
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__footer", children: [
1362
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1363
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1636
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__footer", children: [
1637
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1638
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1364
1639
  ] })
1365
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
1366
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1640
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
1641
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1367
1642
  Composer,
1368
1643
  {
1369
1644
  disabled: isBusy,
@@ -1371,9 +1646,9 @@ function AgentRail({
1371
1646
  onSubmit
1372
1647
  }
1373
1648
  ),
1374
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__footer", children: [
1375
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1376
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1649
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__footer", children: [
1650
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1651
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1377
1652
  ] })
1378
1653
  ] })
1379
1654
  ]
@@ -1382,22 +1657,67 @@ function AgentRail({
1382
1657
  }
1383
1658
 
1384
1659
  // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
1385
- var import_jsx_runtime7 = require("react/jsx-runtime");
1660
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1386
1661
  function SparklesIcon() {
1387
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { className: "assist-edge-tab__sparkles", viewBox: "0 0 18 16", fill: "none", "aria-hidden": "true", children: [
1388
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M8 1.2l.95 2.7 2.85.05-2.25 1.75.8 2.75L8 6.7 5.65 8.45l.8-2.75L4.2 3.95l2.85-.05L8 1.2z", fill: "currentColor" }),
1389
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M14.2 6.4l.55 1.55 1.65.03-1.3 1 .46 1.58-1.36-1-1.36 1 .46-1.58-1.3-1 1.65-.03.55-1.55z", fill: "currentColor" }),
1390
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M3.1 9.1l.4 1.15 1.22.02-.96.74.34 1.17-1-.74-1 .74.34-1.17-.96-.74 1.22-.02.4-1.15z", fill: "currentColor" })
1391
- ] });
1662
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1663
+ "svg",
1664
+ {
1665
+ className: "assist-edge-tab__sparkles",
1666
+ viewBox: "0 0 18 16",
1667
+ fill: "none",
1668
+ "aria-hidden": "true",
1669
+ children: [
1670
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1671
+ "path",
1672
+ {
1673
+ d: "M8 1.2l.95 2.7 2.85.05-2.25 1.75.8 2.75L8 6.7 5.65 8.45l.8-2.75L4.2 3.95l2.85-.05L8 1.2z",
1674
+ fill: "currentColor"
1675
+ }
1676
+ ),
1677
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1678
+ "path",
1679
+ {
1680
+ d: "M14.2 6.4l.55 1.55 1.65.03-1.3 1 .46 1.58-1.36-1-1.36 1 .46-1.58-1.3-1 1.65-.03.55-1.55z",
1681
+ fill: "currentColor"
1682
+ }
1683
+ ),
1684
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1685
+ "path",
1686
+ {
1687
+ d: "M3.1 9.1l.4 1.15 1.22.02-.96.74.34 1.17-1-.74-1 .74.34-1.17-.96-.74 1.22-.02.4-1.15z",
1688
+ fill: "currentColor"
1689
+ }
1690
+ )
1691
+ ]
1692
+ }
1693
+ );
1392
1694
  }
1393
1695
  function ChevronLeftIcon() {
1394
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M10 4L6 8l4 4", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) });
1696
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1697
+ "path",
1698
+ {
1699
+ d: "M10 4L6 8l4 4",
1700
+ stroke: "currentColor",
1701
+ strokeWidth: "1.6",
1702
+ strokeLinecap: "round",
1703
+ strokeLinejoin: "round"
1704
+ }
1705
+ ) });
1395
1706
  }
1396
1707
  function ChevronDownIcon() {
1397
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M4 6l4 4 4-4", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) });
1708
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1709
+ "path",
1710
+ {
1711
+ d: "M4 6l4 4 4-4",
1712
+ stroke: "currentColor",
1713
+ strokeWidth: "1.6",
1714
+ strokeLinecap: "round",
1715
+ strokeLinejoin: "round"
1716
+ }
1717
+ ) });
1398
1718
  }
1399
1719
  function DragDots() {
1400
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__dots", "aria-hidden": "true", children: Array.from({ length: 12 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("i", {}, index)) });
1720
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__dots", "aria-hidden": "true", children: Array.from({ length: 12 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("i", {}, index)) });
1401
1721
  }
1402
1722
  var VARIANT_COPY = {
1403
1723
  outline: { label: "Assist", aria: "Open Assist" },
@@ -1410,38 +1730,71 @@ function AssistEdgeTab({
1410
1730
  along,
1411
1731
  inset,
1412
1732
  visible,
1733
+ label,
1734
+ logoUrl,
1735
+ brandColor,
1736
+ fontFamily,
1413
1737
  onOpen
1414
1738
  }) {
1415
1739
  const copy = VARIANT_COPY[variant];
1740
+ const visibleLabel = label?.trim() || copy.label;
1416
1741
  const style = {
1417
1742
  "--tab-along": `${along}%`,
1418
- "--tab-inset": `${inset}px`
1743
+ "--tab-inset": `${inset}px`,
1744
+ ...brandColor ? { "--as-brand": brandColor } : {},
1745
+ ...fontFamily ? { "--as-font-display": fontFamily } : {}
1419
1746
  };
1420
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1747
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1421
1748
  "button",
1422
1749
  {
1423
1750
  type: "button",
1424
1751
  className: `assist-edge-tab assist-edge-tab--${variant} assist-edge-tab--${side}${visible ? " is-visible" : ""}`,
1425
1752
  style,
1426
- "aria-label": copy.aria,
1753
+ "aria-label": `Open ${visibleLabel}`,
1427
1754
  "aria-hidden": !visible,
1428
1755
  tabIndex: visible ? 0 : -1,
1429
1756
  onClick: onOpen,
1430
1757
  children: [
1431
- variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1432
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {}),
1433
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
1434
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronDownIcon, {})
1758
+ variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1759
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
1760
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparklesIcon, {}),
1761
+ logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1762
+ "img",
1763
+ {
1764
+ className: "assist-edge-tab__logo",
1765
+ src: logoUrl,
1766
+ alt: "",
1767
+ onError: (event) => {
1768
+ event.currentTarget.hidden = true;
1769
+ }
1770
+ }
1771
+ ) : null
1772
+ ] }),
1773
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1774
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronDownIcon, {})
1435
1775
  ] }) : null,
1436
- variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1437
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {}),
1438
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
1439
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DragDots, {})
1776
+ variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1777
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronLeftIcon, {}),
1778
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1779
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DragDots, {})
1440
1780
  ] }) : null,
1441
- variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1442
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {}),
1443
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
1444
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {})
1781
+ variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1782
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
1783
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparklesIcon, {}),
1784
+ logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1785
+ "img",
1786
+ {
1787
+ className: "assist-edge-tab__logo",
1788
+ src: logoUrl,
1789
+ alt: "",
1790
+ onError: (event) => {
1791
+ event.currentTarget.hidden = true;
1792
+ }
1793
+ }
1794
+ ) : null
1795
+ ] }),
1796
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1797
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronLeftIcon, {})
1445
1798
  ] }) : null
1446
1799
  ]
1447
1800
  }
@@ -1449,7 +1802,7 @@ function AssistEdgeTab({
1449
1802
  }
1450
1803
 
1451
1804
  // src/react/components/AgentWidget/AgentWidget.tsx
1452
- var import_jsx_runtime8 = require("react/jsx-runtime");
1805
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1453
1806
  function AgentWidget({
1454
1807
  indexId,
1455
1808
  customerId,
@@ -1458,21 +1811,53 @@ function AgentWidget({
1458
1811
  runtimeOrigin,
1459
1812
  placement: placementInput,
1460
1813
  defaultCollapsed = true,
1461
- registerPanelController = false
1814
+ pageShift = true,
1815
+ registerPanelController = false,
1816
+ branding
1462
1817
  }) {
1463
1818
  const isMobile = useIsMobile();
1464
1819
  const placement = normalizeAgentPlacement(placementInput);
1465
- const [railCollapsed, setRailCollapsed] = (0, import_react5.useState)(defaultCollapsed);
1466
- const [railExpanded, setRailExpanded] = (0, import_react5.useState)(false);
1820
+ const railSlotRef = (0, import_react6.useRef)(null);
1821
+ const [railCollapsed, setRailCollapsed] = (0, import_react6.useState)(defaultCollapsed);
1822
+ const [railExpanded, setRailExpanded] = (0, import_react6.useState)(false);
1823
+ const pageShiftActive = shouldApplyPageShift({
1824
+ pageShift,
1825
+ isMobile,
1826
+ railCollapsed,
1827
+ railExpanded
1828
+ });
1829
+ usePageShift({
1830
+ active: pageShiftActive,
1831
+ railSlotRef
1832
+ });
1467
1833
  const { state, submit } = useAgentChat({
1468
1834
  customerId,
1469
1835
  getUnpublishedPreviewGrant,
1470
1836
  indexId,
1471
1837
  version,
1472
- runtimeOrigin
1838
+ runtimeOrigin,
1839
+ greeting: branding?.greeting
1473
1840
  });
1841
+ const agentName = branding?.agentName ?? "Webless Guide";
1842
+ const theme = {
1843
+ ...branding?.fontFamily ? { fontBody: branding.fontFamily, fontDisplay: branding.fontFamily } : {},
1844
+ ...branding?.colors?.primary ? {
1845
+ brand: branding.colors.primary,
1846
+ visitorBubble: branding.colors.primary
1847
+ } : {},
1848
+ ...branding?.colors?.primarySoft ? { brandSoft: branding.colors.primarySoft } : {},
1849
+ ...branding?.colors?.primaryForeground ? { visitorText: branding.colors.primaryForeground } : {},
1850
+ ...branding?.colors?.surface ? { surface: branding.colors.surface } : {},
1851
+ ...branding?.colors?.surfaceMuted ? { surfaceMuted: branding.colors.surfaceMuted } : {},
1852
+ ...branding?.colors?.text ? { text: branding.colors.text } : {},
1853
+ ...branding?.colors?.textMuted ? {
1854
+ textMuted: branding.colors.textMuted,
1855
+ textSubtle: branding.colors.textMuted
1856
+ } : {},
1857
+ ...branding?.colors?.border ? { border: branding.colors.border } : {}
1858
+ };
1474
1859
  const idle = state.phase === "idle" && !hasVisitorMessages(state.messages);
1475
- (0, import_react5.useEffect)(() => {
1860
+ (0, import_react6.useEffect)(() => {
1476
1861
  if (!registerPanelController) return;
1477
1862
  registerAgentPanelController(customerId, {
1478
1863
  open: () => setRailCollapsed(false),
@@ -1487,47 +1872,56 @@ function AgentWidget({
1487
1872
  if (isMobile) setRailCollapsed(false);
1488
1873
  await submit(message);
1489
1874
  }
1490
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "webless-agent-root", children: [
1491
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1875
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "webless-agent-root", children: [
1876
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1492
1877
  "div",
1493
1878
  {
1494
1879
  className: `webless-agent-root__shell${railCollapsed ? " webless-agent-root__shell--collapsed" : ""}${railExpanded ? " webless-agent-root__shell--expanded" : ""}`,
1495
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1496
- "div",
1497
- {
1498
- className: "webless-agent-root__rail-slot",
1499
- inert: railCollapsed || void 0,
1500
- "aria-hidden": railCollapsed,
1501
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1502
- AgentRail,
1503
- {
1504
- state: idle ? {
1505
- ...state,
1506
- followUps: createIdleSuggestions()
1507
- } : state,
1508
- mobileFullscreen: isMobile && !railCollapsed,
1509
- expanded: railExpanded,
1510
- onCollapse: !isMobile ? () => setRailCollapsed(true) : void 0,
1511
- onClose: isMobile ? () => setRailCollapsed(true) : void 0,
1512
- onExpandToggle: !isMobile ? () => setRailExpanded((current) => !current) : void 0,
1513
- onSubmit: handleSubmit,
1514
- onFollowUpSelect: (label) => void handleSubmit(label)
1515
- }
1516
- )
1517
- }
1518
- )
1880
+ children: [
1881
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1882
+ "div",
1883
+ {
1884
+ ref: railSlotRef,
1885
+ className: "webless-agent-root__rail-slot",
1886
+ inert: railCollapsed || void 0,
1887
+ "aria-hidden": railCollapsed,
1888
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1889
+ AgentRail,
1890
+ {
1891
+ theme,
1892
+ brandLabel: agentName,
1893
+ brandLogoUrl: branding?.logoUrl,
1894
+ composerPlaceholder: branding?.composerPlaceholder ?? `Ask ${agentName}\u2026`,
1895
+ poweredByLabel: branding?.poweredByLabel ?? "Powered by Webless",
1896
+ state: idle ? {
1897
+ ...state,
1898
+ followUps: createIdleSuggestions()
1899
+ } : state,
1900
+ mobileFullscreen: isMobile && !railCollapsed,
1901
+ expanded: railExpanded,
1902
+ onCollapse: !isMobile ? () => setRailCollapsed(true) : void 0,
1903
+ onClose: isMobile ? () => setRailCollapsed(true) : void 0,
1904
+ onExpandToggle: !isMobile ? () => setRailExpanded((current) => !current) : void 0,
1905
+ onSubmit: handleSubmit,
1906
+ onFollowUpSelect: (label) => void handleSubmit(label)
1907
+ }
1908
+ )
1909
+ }
1910
+ ),
1911
+ !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1912
+ "button",
1913
+ {
1914
+ type: "button",
1915
+ className: "webless-agent-root__backdrop",
1916
+ tabIndex: -1,
1917
+ "aria-label": "Close expanded assist",
1918
+ onClick: () => setRailExpanded(false)
1919
+ }
1920
+ ) : null
1921
+ ]
1519
1922
  }
1520
1923
  ),
1521
- !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1522
- "button",
1523
- {
1524
- type: "button",
1525
- className: "webless-agent-root__backdrop",
1526
- "aria-label": "Close expanded assist",
1527
- onClick: () => setRailExpanded(false)
1528
- }
1529
- ) : null,
1530
- railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1924
+ railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1531
1925
  AssistEdgeTab,
1532
1926
  {
1533
1927
  variant: placement.variant,
@@ -1535,29 +1929,15 @@ function AgentWidget({
1535
1929
  along: placement.along,
1536
1930
  inset: placement.inset,
1537
1931
  visible: true,
1932
+ label: agentName,
1933
+ logoUrl: branding?.logoUrl,
1934
+ brandColor: branding?.colors?.primary,
1935
+ fontFamily: branding?.fontFamily,
1538
1936
  onOpen: () => setRailCollapsed(false)
1539
1937
  }
1540
1938
  ) : null
1541
1939
  ] });
1542
1940
  }
1543
-
1544
- // src/react/types/conversation.ts
1545
- var defaultAgentRailTheme = {
1546
- railMaxWidth: "450px",
1547
- brand: "#6f16ff",
1548
- brandSoft: "#f3edff",
1549
- brandDeep: "#12043e",
1550
- surface: "#ffffff",
1551
- surfaceMuted: "#f4f6fb",
1552
- text: "#171b2a",
1553
- textMuted: "#5a6378",
1554
- textSubtle: "#8a94a8",
1555
- border: "rgb(42 51 70 / 0.1)",
1556
- visitorBubble: "#6f16ff",
1557
- visitorText: "#ffffff",
1558
- success: "#18794e",
1559
- danger: "#c94b63"
1560
- };
1561
1941
  // Annotate the CommonJS export names for ESM import in node:
1562
1942
  0 && (module.exports = {
1563
1943
  AgentRail,