@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/embed.cjs CHANGED
@@ -50,10 +50,90 @@ function closeAgentPanel(customerId) {
50
50
  }
51
51
 
52
52
  // src/react/components/AgentWidget/AgentWidget.tsx
53
- var import_react5 = require("react");
53
+ var import_react6 = require("react");
54
54
 
55
- // src/react/hooks/useAgentChat.ts
55
+ // src/react/page-shift.ts
56
56
  var import_react = require("react");
57
+ var PAGE_SHIFT_CLASS = "webless-agent-page-shift";
58
+ var DEFAULT_RAIL_WIDTH_PX = 450;
59
+ function shouldApplyPageShift(input) {
60
+ return input.pageShift && !input.isMobile && !input.railCollapsed && !input.railExpanded;
61
+ }
62
+ function resolvePageShiftWidth(railWidth) {
63
+ if (typeof railWidth === "number" && railWidth > 0) {
64
+ return railWidth;
65
+ }
66
+ if (typeof document !== "undefined") {
67
+ const token = getComputedStyle(document.documentElement).getPropertyValue("--as-rail-max-width").trim();
68
+ const parsed = Number.parseFloat(token);
69
+ if (Number.isFinite(parsed) && parsed > 0) {
70
+ return parsed;
71
+ }
72
+ }
73
+ return DEFAULT_RAIL_WIDTH_PX;
74
+ }
75
+ var savedPageMargin = null;
76
+ function readPageMarginSnapshot(style) {
77
+ return {
78
+ value: style.getPropertyValue("margin-right"),
79
+ priority: style.getPropertyPriority("margin-right")
80
+ };
81
+ }
82
+ function restorePageMargin(style, snapshot) {
83
+ if (snapshot.value) {
84
+ style.setProperty("margin-right", snapshot.value, snapshot.priority || void 0);
85
+ return;
86
+ }
87
+ style.removeProperty("margin-right");
88
+ }
89
+ function snapshotPageMarginIfNeeded() {
90
+ if (savedPageMargin !== null) {
91
+ return;
92
+ }
93
+ savedPageMargin = readPageMarginSnapshot(document.documentElement.style);
94
+ }
95
+ function setPageMargin(margin) {
96
+ snapshotPageMarginIfNeeded();
97
+ document.documentElement.style.setProperty("margin-right", margin, "important");
98
+ }
99
+ function clearPageMargin() {
100
+ if (savedPageMargin === null) {
101
+ return;
102
+ }
103
+ restorePageMargin(document.documentElement.style, savedPageMargin);
104
+ savedPageMargin = null;
105
+ }
106
+ function usePageShift(input) {
107
+ const { active, railSlotRef } = input;
108
+ (0, import_react.useEffect)(() => {
109
+ if (typeof document === "undefined") {
110
+ return;
111
+ }
112
+ if (!active) {
113
+ document.documentElement.classList.remove(PAGE_SHIFT_CLASS);
114
+ clearPageMargin();
115
+ return;
116
+ }
117
+ document.documentElement.classList.add(PAGE_SHIFT_CLASS);
118
+ function applyMargin() {
119
+ const rail = railSlotRef.current?.querySelector(".agent-rail");
120
+ const width = resolvePageShiftWidth(
121
+ rail instanceof HTMLElement ? rail.offsetWidth : null
122
+ );
123
+ setPageMargin(`${width}px`);
124
+ }
125
+ applyMargin();
126
+ const frame = requestAnimationFrame(applyMargin);
127
+ return () => {
128
+ cancelAnimationFrame(frame);
129
+ document.documentElement.classList.remove(PAGE_SHIFT_CLASS);
130
+ clearPageMargin();
131
+ };
132
+ }, [active, railSlotRef]);
133
+ }
134
+
135
+ // src/react/hooks/useAgentChat.ts
136
+ var import_react2 = require("react");
57
137
 
58
138
  // src/runtime/client.ts
59
139
  var import_client2 = require("eve/client");
@@ -271,9 +351,8 @@ function clearPersistedAgentSession(visitorSessionId, options) {
271
351
  function isTurnBoundary(event) {
272
352
  return event.type === "session.waiting" || event.type === "session.completed" || event.type === "session.failed";
273
353
  }
274
- function applyMessageEvent(event, rendered, handlers) {
275
- const step = mapStepLabel(event);
276
- if (step) handlers.onStep?.(step.label, step.detail);
354
+ function applyMessageEvent(event, rendered, handlers, workItems) {
355
+ applyWorkEvent(event, handlers, workItems);
277
356
  if (event.type === "session.failed") {
278
357
  throw new Error(event.data.message || event.data.code);
279
358
  }
@@ -316,13 +395,120 @@ function renderTurn(events) {
316
395
  }
317
396
  return rendered;
318
397
  }
319
- function mapStepLabel(event) {
320
- if (event.type !== "step.started") return null;
321
- const stepIndex = event.data.stepIndex;
322
- return {
323
- label: "Model step running",
324
- detail: typeof stepIndex === "number" ? `Step ${stepIndex + 1}` : void 0
325
- };
398
+ function emitWorkItem(item, handlers, workItems) {
399
+ workItems.set(item.id, item);
400
+ handlers.onWork?.(item);
401
+ handlers.onStep?.(item.label, item.detail);
402
+ }
403
+ function completePlanning(handlers, workItems) {
404
+ const planning = workItems.get("planning");
405
+ if (!planning || planning.state !== "active") return;
406
+ emitWorkItem(
407
+ {
408
+ ...planning,
409
+ detail: "Picked the best way to help",
410
+ state: "completed"
411
+ },
412
+ handlers,
413
+ workItems
414
+ );
415
+ }
416
+ function specialistNameFromInput(input) {
417
+ const message = input.message;
418
+ if (typeof message !== "string") return void 0;
419
+ const match = /^Webless-Agent-Name:\s*(.+)$/imu.exec(message);
420
+ return match?.[1]?.trim() || void 0;
421
+ }
422
+ function requestedWorkItem(action) {
423
+ if (action.kind === "tool-call" && action.toolName === "search_discovery") {
424
+ return {
425
+ id: action.callId,
426
+ kind: "search",
427
+ label: "Search & Discovery",
428
+ detail: "Searching this site",
429
+ state: "active"
430
+ };
431
+ }
432
+ if (action.kind === "subagent-call" || action.kind === "remote-agent-call" || action.kind === "tool-call" && action.toolName === "agent") {
433
+ const name = specialistNameFromInput(action.input) ?? "Specialist";
434
+ return {
435
+ id: action.callId,
436
+ kind: "specialist",
437
+ label: name,
438
+ detail: "Reviewing your question",
439
+ state: "active"
440
+ };
441
+ }
442
+ return null;
443
+ }
444
+ function applyWorkEvent(event, handlers, workItems) {
445
+ if (event.type === "step.started" && workItems.size === 0) {
446
+ emitWorkItem(
447
+ {
448
+ id: "planning",
449
+ kind: "planning",
450
+ label: "Understanding your question",
451
+ state: "active"
452
+ },
453
+ handlers,
454
+ workItems
455
+ );
456
+ return;
457
+ }
458
+ if (event.type === "actions.requested") {
459
+ completePlanning(handlers, workItems);
460
+ for (const action of event.data.actions) {
461
+ const item = requestedWorkItem(action);
462
+ if (item) emitWorkItem(item, handlers, workItems);
463
+ }
464
+ return;
465
+ }
466
+ if (event.type === "subagent.called") {
467
+ completePlanning(handlers, workItems);
468
+ const current2 = workItems.get(event.data.callId);
469
+ if (!current2) {
470
+ emitWorkItem(
471
+ {
472
+ id: event.data.callId,
473
+ kind: "specialist",
474
+ label: event.data.name || "Specialist",
475
+ detail: "Reviewing your question",
476
+ state: "active"
477
+ },
478
+ handlers,
479
+ workItems
480
+ );
481
+ }
482
+ return;
483
+ }
484
+ if (event.type === "subagent.completed") {
485
+ const current2 = workItems.get(event.data.callId);
486
+ if (!current2) return;
487
+ emitWorkItem(
488
+ {
489
+ ...current2,
490
+ detail: "Guidance received",
491
+ state: "completed"
492
+ },
493
+ handlers,
494
+ workItems
495
+ );
496
+ return;
497
+ }
498
+ if (event.type !== "action.result") return;
499
+ const { result, status } = event.data;
500
+ const current = workItems.get(result.callId);
501
+ if (!current) return;
502
+ const failed = status !== "completed" || result.isError === true;
503
+ emitWorkItem(
504
+ {
505
+ ...current,
506
+ detail: failed ? "Couldn\u2019t complete; continuing with available information" : current.kind === "search" ? "Found relevant site content" : "Guidance received",
507
+ state: failed ? "error" : "completed"
508
+ },
509
+ handlers,
510
+ workItems
511
+ );
326
512
  }
327
513
  var AgentSession = class {
328
514
  constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, getUnpublishedPreviewGrant) {
@@ -440,10 +626,11 @@ var AgentSession = class {
440
626
  this.activeResponse = response;
441
627
  let streamIndex = session?.state.streamIndex ?? 0;
442
628
  let rendered = "";
629
+ const workItems = /* @__PURE__ */ new Map();
443
630
  try {
444
631
  for await (const event of response) {
445
632
  if (signal.aborted) break;
446
- rendered = applyMessageEvent(event, rendered, handlers);
633
+ rendered = applyMessageEvent(event, rendered, handlers, workItems);
447
634
  streamIndex += 1;
448
635
  if (session) {
449
636
  savePersistedAgentSession(
@@ -485,6 +672,10 @@ var AgentSession = class {
485
672
  return null;
486
673
  }
487
674
  let rendered = renderTurn(turnEvents);
675
+ const workItems = /* @__PURE__ */ new Map();
676
+ for (const event of turnEvents) {
677
+ applyWorkEvent(event, handlers, workItems);
678
+ }
488
679
  if (rendered.startsWith(initialText)) {
489
680
  const missedText = rendered.slice(initialText.length);
490
681
  if (missedText) handlers.onDelta(missedText);
@@ -519,7 +710,7 @@ var AgentSession = class {
519
710
  let streamIndex = snapshot.session.streamIndex;
520
711
  for await (const event of session.stream({ signal })) {
521
712
  if (signal.aborted) break;
522
- rendered = applyMessageEvent(event, rendered, handlers);
713
+ rendered = applyMessageEvent(event, rendered, handlers, workItems);
523
714
  streamIndex += 1;
524
715
  savePersistedAgentSession(
525
716
  this.visitorSessionId,
@@ -672,57 +863,54 @@ function clearPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
672
863
  }
673
864
 
674
865
  // src/react/hooks/useAgentChat.ts
675
- var GREETING_MESSAGE = {
676
- id: "greeting",
677
- role: "agent",
678
- text: "Hi! I'm connected to the Webless Agent Runtime. Ask anything about your published site index.",
679
- createdAt: 0
680
- };
681
- var INITIAL_STATE = {
682
- phase: "idle",
683
- messages: [GREETING_MESSAGE],
684
- toolSteps: [],
685
- journey: null,
686
- followUps: [],
687
- streamingText: "",
688
- error: null
689
- };
690
- function stateFromConversation(conversation) {
691
- if (!conversation || conversation.messages.length === 0) return INITIAL_STATE;
866
+ var DEFAULT_GREETING = "Hi! I can search this site or bring in a specialist when it helps. What would you like to know?";
867
+ function createInitialState(greeting = DEFAULT_GREETING) {
692
868
  return {
693
- ...INITIAL_STATE,
869
+ phase: "idle",
870
+ messages: [
871
+ {
872
+ id: "greeting",
873
+ role: "agent",
874
+ text: greeting,
875
+ createdAt: 0
876
+ }
877
+ ],
878
+ toolSteps: [],
879
+ journey: null,
880
+ followUps: [],
881
+ streamingText: "",
882
+ error: null
883
+ };
884
+ }
885
+ function stateFromConversation(conversation, initialState) {
886
+ if (!conversation || conversation.messages.length === 0) return initialState;
887
+ return {
888
+ ...initialState,
694
889
  messages: conversation.messages,
695
890
  phase: conversation.pending ? conversation.streamingText ? "streaming" : "thinking" : "complete",
696
891
  streamingText: conversation.streamingText
697
892
  };
698
893
  }
699
- var STATUS_SEQUENCE = [
700
- { id: "s1", label: "Starting Eve session", ms: 400 },
701
- { id: "s2", label: "Connecting to runtime", ms: 500 }
702
- ];
703
- function delay(ms, signal) {
704
- return new Promise((resolve, reject) => {
705
- const timer = window.setTimeout(resolve, ms);
706
- signal.addEventListener(
707
- "abort",
708
- () => {
709
- window.clearTimeout(timer);
710
- reject(new DOMException("Aborted", "AbortError"));
711
- },
712
- { once: true }
713
- );
714
- });
715
- }
716
- async function runStatusSequence(signal, onStep) {
717
- for (const item of STATUS_SEQUENCE) {
718
- onStep({
719
- id: item.id,
720
- label: item.label,
721
- detail: item.detail,
722
- state: "active"
723
- });
724
- await delay(item.ms, signal);
725
- }
894
+ function upsertToolStep(steps, item) {
895
+ const next = {
896
+ id: item.id,
897
+ kind: item.kind,
898
+ label: item.label,
899
+ state: item.state,
900
+ ...item.detail ? { detail: item.detail } : {}
901
+ };
902
+ const index = steps.findIndex((step) => step.id === item.id);
903
+ if (index < 0) return [...steps, next];
904
+ return steps.map((step, stepIndex) => stepIndex === index ? next : step);
905
+ }
906
+ function completeActivePlanning(steps) {
907
+ return steps.map(
908
+ (step) => step.kind === "planning" && step.state === "active" ? {
909
+ ...step,
910
+ detail: "Prepared a response",
911
+ state: "completed"
912
+ } : step
913
+ );
726
914
  }
727
915
  function useAgentChat({
728
916
  customerId,
@@ -731,9 +919,14 @@ function useAgentChat({
731
919
  version,
732
920
  runtimeOrigin,
733
921
  visitorSessionId,
734
- storageKeyPrefix
922
+ storageKeyPrefix,
923
+ greeting
735
924
  }) {
736
- const previewGrantProviderRef = (0, import_react.useRef)(getUnpublishedPreviewGrant);
925
+ const initialState = (0, import_react2.useMemo)(
926
+ () => createInitialState(greeting?.trim() || DEFAULT_GREETING),
927
+ [greeting]
928
+ );
929
+ const previewGrantProviderRef = (0, import_react2.useRef)(getUnpublishedPreviewGrant);
737
930
  previewGrantProviderRef.current = getUnpublishedPreviewGrant;
738
931
  const resolveUnpublishedPreviewGrant = () => {
739
932
  const provider = previewGrantProviderRef.current;
@@ -746,7 +939,7 @@ function useAgentChat({
746
939
  }
747
940
  return provider();
748
941
  };
749
- const resolvedStorageKeyPrefix = (0, import_react.useMemo)(
942
+ const resolvedStorageKeyPrefix = (0, import_react2.useMemo)(
750
943
  () => storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({
751
944
  customerId,
752
945
  indexId,
@@ -755,19 +948,20 @@ function useAgentChat({
755
948
  }),
756
949
  [customerId, indexId, runtimeOrigin, storageKeyPrefix, version]
757
950
  );
758
- const visitorId = (0, import_react.useMemo)(
951
+ const visitorId = (0, import_react2.useMemo)(
759
952
  () => visitorSessionId?.trim() || getOrCreateVisitorSessionId({
760
953
  storageKeyPrefix: resolvedStorageKeyPrefix
761
954
  }),
762
955
  [resolvedStorageKeyPrefix, visitorSessionId]
763
956
  );
764
- const [state, setState] = (0, import_react.useState)(
957
+ const [state, setState] = (0, import_react2.useState)(
765
958
  () => stateFromConversation(
766
- loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
959
+ loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
960
+ initialState
767
961
  )
768
962
  );
769
- const runRef = (0, import_react.useRef)(null);
770
- const clientRef = (0, import_react.useRef)(
963
+ const runRef = (0, import_react2.useRef)(null);
964
+ const clientRef = (0, import_react2.useRef)(
771
965
  createAgentClient({
772
966
  customerId,
773
967
  getUnpublishedPreviewGrant: resolveUnpublishedPreviewGrant,
@@ -778,9 +972,9 @@ function useAgentChat({
778
972
  storageKeyPrefix: resolvedStorageKeyPrefix
779
973
  })
780
974
  );
781
- const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}`;
782
- const identityRef = (0, import_react.useRef)(identityKey);
783
- (0, import_react.useEffect)(() => {
975
+ const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}|${greeting ?? ""}`;
976
+ const identityRef = (0, import_react2.useRef)(identityKey);
977
+ (0, import_react2.useEffect)(() => {
784
978
  if (identityRef.current === identityKey) {
785
979
  return;
786
980
  }
@@ -798,19 +992,21 @@ function useAgentChat({
798
992
  });
799
993
  setState(
800
994
  stateFromConversation(
801
- loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
995
+ loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
996
+ initialState
802
997
  )
803
998
  );
804
999
  }, [
805
1000
  customerId,
806
1001
  identityKey,
807
1002
  indexId,
1003
+ initialState,
808
1004
  runtimeOrigin,
809
1005
  resolvedStorageKeyPrefix,
810
1006
  version,
811
1007
  visitorId
812
1008
  ]);
813
- (0, import_react.useEffect)(() => {
1009
+ (0, import_react2.useEffect)(() => {
814
1010
  if (!hasVisitorMessages(state.messages)) return;
815
1011
  savePersistedAgentConversation(resolvedStorageKeyPrefix, visitorId, {
816
1012
  messages: state.messages,
@@ -824,14 +1020,14 @@ function useAgentChat({
824
1020
  state.streamingText,
825
1021
  visitorId
826
1022
  ]);
827
- const reset = (0, import_react.useCallback)(() => {
1023
+ const reset = (0, import_react2.useCallback)(() => {
828
1024
  runRef.current?.abort();
829
1025
  runRef.current = null;
830
1026
  clientRef.current.reset();
831
1027
  clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
832
- setState(INITIAL_STATE);
833
- }, [resolvedStorageKeyPrefix, visitorId]);
834
- const runTurn = (0, import_react.useCallback)(
1028
+ setState(initialState);
1029
+ }, [initialState, resolvedStorageKeyPrefix, visitorId]);
1030
+ const runTurn = (0, import_react2.useCallback)(
835
1031
  async (input) => {
836
1032
  const { controller, initialText = "", resume, visitorText } = input;
837
1033
  const { signal } = controller;
@@ -839,35 +1035,23 @@ function useAgentChat({
839
1035
  try {
840
1036
  let streamStarted = Boolean(initialText);
841
1037
  let streamed = initialText;
842
- const planningPromise = resume ? Promise.resolve() : runStatusSequence(signal, (step) => {
843
- if (streamStarted || !isActiveRun()) return;
844
- setState((prev) => ({
845
- ...prev,
846
- phase: "running-tools",
847
- toolSteps: [step]
848
- }));
849
- });
850
1038
  const handlers = {
851
- onStep: (label, detail) => {
852
- if (streamStarted || !isActiveRun()) return;
1039
+ onWork: (item) => {
1040
+ if (!isActiveRun()) return;
853
1041
  setState((prev) => ({
854
1042
  ...prev,
855
- phase: "running-tools",
856
- toolSteps: [
857
- { id: `step-${label}`, label, detail, state: "active" }
858
- ]
1043
+ phase: item.state === "active" ? "running-tools" : prev.phase,
1044
+ toolSteps: upsertToolStep(prev.toolSteps, item)
859
1045
  }));
860
1046
  },
861
1047
  onDelta: (delta) => {
862
1048
  if (!isActiveRun()) return;
863
- void planningPromise.catch(() => {
864
- });
865
1049
  if (!streamStarted) {
866
1050
  streamStarted = true;
867
1051
  setState((prev) => ({
868
1052
  ...prev,
869
1053
  phase: "streaming",
870
- toolSteps: [],
1054
+ toolSteps: completeActivePlanning(prev.toolSteps),
871
1055
  streamingText: ""
872
1056
  }));
873
1057
  }
@@ -895,8 +1079,6 @@ function useAgentChat({
895
1079
  signal
896
1080
  });
897
1081
  }
898
- await planningPromise.catch(() => {
899
- });
900
1082
  if (!isActiveRun() || finalText === null) return;
901
1083
  const agentMessage = {
902
1084
  id: `agent-${Date.now()}`,
@@ -908,7 +1090,7 @@ function useAgentChat({
908
1090
  ...prev,
909
1091
  phase: "complete",
910
1092
  messages: [...prev.messages, agentMessage],
911
- toolSteps: [],
1093
+ toolSteps: completeActivePlanning(prev.toolSteps),
912
1094
  streamingText: "",
913
1095
  followUps: [],
914
1096
  journey: null
@@ -923,7 +1105,13 @@ function useAgentChat({
923
1105
  setState((prev) => ({
924
1106
  ...prev,
925
1107
  phase: "complete",
926
- toolSteps: [],
1108
+ toolSteps: prev.toolSteps.map(
1109
+ (step) => step.state === "active" ? {
1110
+ ...step,
1111
+ detail: "Couldn\u2019t complete this step",
1112
+ state: "error"
1113
+ } : step
1114
+ ),
927
1115
  streamingText: "",
928
1116
  error: message
929
1117
  }));
@@ -932,7 +1120,7 @@ function useAgentChat({
932
1120
  },
933
1121
  []
934
1122
  );
935
- const submit = (0, import_react.useCallback)(
1123
+ const submit = (0, import_react2.useCallback)(
936
1124
  async (visitorText) => {
937
1125
  if (runRef.current) {
938
1126
  runRef.current.abort();
@@ -951,7 +1139,12 @@ function useAgentChat({
951
1139
  phase: "thinking",
952
1140
  messages: [...prev.messages, visitorMessage],
953
1141
  toolSteps: [
954
- { id: "s1", label: "Starting Eve session", state: "active" }
1142
+ {
1143
+ id: "planning",
1144
+ kind: "planning",
1145
+ label: "Understanding your question",
1146
+ state: "active"
1147
+ }
955
1148
  ],
956
1149
  journey: null,
957
1150
  followUps: [],
@@ -962,7 +1155,7 @@ function useAgentChat({
962
1155
  },
963
1156
  [runTurn]
964
1157
  );
965
- (0, import_react.useEffect)(() => {
1158
+ (0, import_react2.useEffect)(() => {
966
1159
  const conversation = loadPersistedAgentConversation(
967
1160
  resolvedStorageKeyPrefix,
968
1161
  visitorId
@@ -985,7 +1178,7 @@ function useAgentChat({
985
1178
  controller.abort();
986
1179
  };
987
1180
  }, [identityKey, resolvedStorageKeyPrefix, runTurn, visitorId]);
988
- (0, import_react.useEffect)(() => {
1181
+ (0, import_react2.useEffect)(() => {
989
1182
  return () => {
990
1183
  runRef.current?.abort();
991
1184
  runRef.current = null;
@@ -1014,12 +1207,12 @@ function isAgentBusy(phase) {
1014
1207
  }
1015
1208
 
1016
1209
  // src/react/hooks/useIsMobile.ts
1017
- var import_react2 = require("react");
1210
+ var import_react3 = require("react");
1018
1211
  function useIsMobile(breakpoint = 767) {
1019
- const [isMobile, setIsMobile] = (0, import_react2.useState)(
1212
+ const [isMobile, setIsMobile] = (0, import_react3.useState)(
1020
1213
  () => typeof window !== "undefined" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
1021
1214
  );
1022
- (0, import_react2.useEffect)(() => {
1215
+ (0, import_react3.useEffect)(() => {
1023
1216
  const media = window.matchMedia(`(max-width: ${breakpoint}px)`);
1024
1217
  const onChange = () => setIsMobile(media.matches);
1025
1218
  onChange();
@@ -1047,81 +1240,95 @@ function normalizeAgentPlacement(placement) {
1047
1240
  }
1048
1241
 
1049
1242
  // src/react/components/AgentRail/AgentRail.tsx
1050
- var import_react4 = require("react");
1243
+ var import_react5 = require("react");
1051
1244
 
1052
- // src/react/components/ToolTimeline/ToolTimeline.tsx
1053
- var import_jsx_runtime = require("react/jsx-runtime");
1054
- function SpinnerIcon() {
1055
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className: "agent-status__spinner", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
1056
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "8", cy: "8", r: "6", stroke: "currentColor", strokeWidth: "1.5", strokeOpacity: "0.25" }),
1057
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 8a6 6 0 0 0-6-6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
1058
- ] });
1059
- }
1060
- function getCurrentStep(steps) {
1061
- const active = steps.find((step) => step.state === "active");
1062
- if (active) return active;
1063
- const error = steps.find((step) => step.state === "error");
1064
- if (error) return error;
1065
- const pending = steps.find((step) => step.state === "pending");
1066
- if (pending) return pending;
1067
- return steps.at(-1) ?? null;
1068
- }
1069
- function ToolTimeline({
1070
- steps,
1071
- streamingText,
1072
- showStreaming = false,
1073
- inline = false
1074
- }) {
1075
- if (steps.length === 0 && !(showStreaming && streamingText)) return null;
1076
- const currentStep = getCurrentStep(steps);
1077
- const showStatus = currentStep && currentStep.state !== "completed" && !(showStreaming && streamingText);
1078
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1079
- "div",
1080
- {
1081
- className: `tool-timeline${inline ? " tool-timeline--inline" : ""}`,
1082
- role: "status",
1083
- "aria-live": "polite",
1084
- "aria-label": "Agent progress",
1085
- children: [
1086
- showStatus ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-status", children: [
1087
- 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, {}) }),
1088
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-status__copy", children: [
1089
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__label", children: currentStep.label }),
1090
- currentStep.detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__detail", children: currentStep.detail }) : null
1091
- ] })
1092
- ] }, currentStep.id) : null,
1093
- showStreaming && streamingText ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "tool-timeline__streaming-text", children: [
1094
- streamingText,
1095
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tool-timeline__cursor", "aria-hidden": "true" })
1096
- ] }) : null
1097
- ]
1098
- }
1099
- );
1100
- }
1245
+ // src/react/types/conversation.ts
1246
+ var defaultAgentRailTheme = {
1247
+ railMaxWidth: "450px",
1248
+ brand: "#6f16ff",
1249
+ brandSoft: "#f3edff",
1250
+ brandDeep: "#12043e",
1251
+ surface: "#ffffff",
1252
+ surfaceMuted: "#f4f6fb",
1253
+ text: "#171b2a",
1254
+ textMuted: "#5a6378",
1255
+ textSubtle: "#8a94a8",
1256
+ border: "rgb(42 51 70 / 0.1)",
1257
+ visitorBubble: "#6f16ff",
1258
+ visitorText: "#ffffff",
1259
+ success: "#18794e",
1260
+ danger: "#c94b63",
1261
+ fontBody: '"Mulish", "Avenir Next", "Segoe UI", sans-serif',
1262
+ fontDisplay: '"Space Grotesk", sans-serif'
1263
+ };
1101
1264
 
1102
1265
  // src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
1103
- var import_jsx_runtime2 = require("react/jsx-runtime");
1104
- function AgentActivityBubble({
1105
- steps,
1106
- streamingText,
1107
- showStreaming = false
1108
- }) {
1109
- 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)(
1110
- ToolTimeline,
1111
- {
1112
- steps,
1113
- streamingText,
1114
- showStreaming,
1115
- inline: true
1116
- }
1117
- ) }) });
1266
+ var import_jsx_runtime = require("react/jsx-runtime");
1267
+ function workSummary(steps) {
1268
+ const active = [...steps].reverse().find((step) => step.state === "active");
1269
+ if (active?.kind === "specialist") return `Working with ${active.label}`;
1270
+ if (active?.kind === "search") return "Searching this site";
1271
+ if (active) return active.label;
1272
+ const hasError = steps.some((step) => step.state === "error");
1273
+ const specialists = steps.filter(
1274
+ (step) => step.kind === "specialist" && step.state === "completed"
1275
+ );
1276
+ const searched = steps.some(
1277
+ (step) => step.kind === "search" && step.state === "completed"
1278
+ );
1279
+ if (hasError) return "Answered with available information";
1280
+ if (specialists.length > 1)
1281
+ return `Consulted ${specialists.length} specialists`;
1282
+ if (specialists.length === 1) return `Consulted ${specialists[0]?.label}`;
1283
+ if (searched) return "Searched this site";
1284
+ return "Prepared a response";
1285
+ }
1286
+ function AgentActivityBubble({ steps }) {
1287
+ const active = steps.some((step) => step.state === "active");
1288
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", { className: "agent-activity-bubble", children: [
1289
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "agent-activity-bubble__status", "aria-live": "polite", children: [
1290
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1291
+ "span",
1292
+ {
1293
+ className: `agent-activity-bubble__pulse${active ? " is-active" : ""}`,
1294
+ "aria-hidden": "true"
1295
+ }
1296
+ ),
1297
+ workSummary(steps)
1298
+ ] }),
1299
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { className: "agent-activity-bubble__details", open: active, children: [
1300
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: "Work details" }),
1301
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "agent-activity-bubble__steps", children: steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1302
+ "li",
1303
+ {
1304
+ className: "agent-activity-bubble__step",
1305
+ "data-state": step.state,
1306
+ children: [
1307
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1308
+ "span",
1309
+ {
1310
+ className: "agent-activity-bubble__step-icon",
1311
+ "aria-hidden": "true",
1312
+ children: step.state === "completed" ? "\u2713" : step.state === "error" ? "!" : ""
1313
+ }
1314
+ ),
1315
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "agent-activity-bubble__step-copy", children: [
1316
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: step.label }),
1317
+ step.detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: step.detail }) : null
1318
+ ] })
1319
+ ]
1320
+ },
1321
+ step.id
1322
+ )) })
1323
+ ] })
1324
+ ] });
1118
1325
  }
1119
1326
 
1120
1327
  // src/react/components/Composer/Composer.tsx
1121
- var import_react3 = require("react");
1122
- var import_jsx_runtime3 = require("react/jsx-runtime");
1328
+ var import_react4 = require("react");
1329
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1123
1330
  function SendIcon() {
1124
- 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" }) });
1331
+ 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" }) });
1125
1332
  }
1126
1333
  function Composer({
1127
1334
  disabled = false,
@@ -1129,8 +1336,8 @@ function Composer({
1129
1336
  variant = "default",
1130
1337
  onSubmit
1131
1338
  }) {
1132
- const [value, setValue] = (0, import_react3.useState)("");
1133
- const inputRef = (0, import_react3.useRef)(null);
1339
+ const [value, setValue] = (0, import_react4.useState)("");
1340
+ const inputRef = (0, import_react4.useRef)(null);
1134
1341
  function submitCurrent() {
1135
1342
  const trimmed = value.trim();
1136
1343
  if (!trimmed || disabled) return;
@@ -1148,8 +1355,8 @@ function Composer({
1148
1355
  submitCurrent();
1149
1356
  }
1150
1357
  }
1151
- 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: [
1152
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1358
+ 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: [
1359
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1153
1360
  "textarea",
1154
1361
  {
1155
1362
  ref: inputRef,
@@ -1163,21 +1370,21 @@ function Composer({
1163
1370
  onKeyDown: handleKeyDown
1164
1371
  }
1165
1372
  ),
1166
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1373
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1167
1374
  "button",
1168
1375
  {
1169
1376
  type: "submit",
1170
1377
  className: "composer__send",
1171
1378
  disabled: disabled || !value.trim(),
1172
1379
  "aria-label": "Send message",
1173
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
1380
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SendIcon, {})
1174
1381
  }
1175
1382
  )
1176
1383
  ] }) });
1177
1384
  }
1178
1385
 
1179
1386
  // src/react/components/FollowUpChips/FollowUpChips.tsx
1180
- var import_jsx_runtime4 = require("react/jsx-runtime");
1387
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1181
1388
  function FollowUpChips({
1182
1389
  suggestions,
1183
1390
  disabled = false,
@@ -1187,7 +1394,7 @@ function FollowUpChips({
1187
1394
  }) {
1188
1395
  if (suggestions.length === 0) return null;
1189
1396
  if (variant === "dock") {
1190
- 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)(
1397
+ 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)(
1191
1398
  "button",
1192
1399
  {
1193
1400
  type: "button",
@@ -1199,9 +1406,9 @@ function FollowUpChips({
1199
1406
  suggestion.id
1200
1407
  )) }) });
1201
1408
  }
1202
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "followups", children: [
1203
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "followups__label", children: label }),
1204
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "followups__list", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1409
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "followups", children: [
1410
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "followups__label", children: label }),
1411
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "followups__list", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1205
1412
  "button",
1206
1413
  {
1207
1414
  type: "button",
@@ -1218,12 +1425,12 @@ function FollowUpChips({
1218
1425
  // src/react/components/MessageBubble/MessageBubble.tsx
1219
1426
  var import_streamdown = require("streamdown");
1220
1427
  var import_styles = require("streamdown/styles.css");
1221
- var import_jsx_runtime5 = require("react/jsx-runtime");
1428
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1222
1429
  function MessageBubble({ message }) {
1223
1430
  if (message.role === "visitor") {
1224
- 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 }) });
1431
+ 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 }) });
1225
1432
  }
1226
- 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)(
1433
+ 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)(
1227
1434
  import_streamdown.Streamdown,
1228
1435
  {
1229
1436
  animated: true,
@@ -1240,12 +1447,20 @@ function MessageBubble({ message }) {
1240
1447
  }
1241
1448
 
1242
1449
  // src/react/components/AgentRail/AgentRail.tsx
1243
- var import_jsx_runtime6 = require("react/jsx-runtime");
1450
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1244
1451
  function MinimizeIcon() {
1245
- 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" }) });
1452
+ 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)(
1453
+ "path",
1454
+ {
1455
+ d: "M3.5 8h9",
1456
+ stroke: "currentColor",
1457
+ strokeWidth: "1.7",
1458
+ strokeLinecap: "round"
1459
+ }
1460
+ ) });
1246
1461
  }
1247
1462
  function ExpandIcon() {
1248
- 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)(
1463
+ 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)(
1249
1464
  "path",
1250
1465
  {
1251
1466
  d: "M6 3.5H3.5V6M10 3.5h2.5V6M10 12.5h2.5V10M6 12.5H3.5V10",
@@ -1257,7 +1472,7 @@ function ExpandIcon() {
1257
1472
  ) });
1258
1473
  }
1259
1474
  function RestoreIcon() {
1260
- 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)(
1475
+ 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)(
1261
1476
  "path",
1262
1477
  {
1263
1478
  d: "M5.5 5.5H3.5V7.5M10.5 5.5h2V7.5M10.5 10.5h2V8.5M5.5 10.5H3.5V8.5",
@@ -1272,6 +1487,7 @@ function AgentRail({
1272
1487
  state,
1273
1488
  theme,
1274
1489
  brandLabel = "Webless Assist",
1490
+ brandLogoUrl,
1275
1491
  poweredByLabel = "Powered by Webless",
1276
1492
  composerPlaceholder = "Ask anything\u2026",
1277
1493
  mobileFullscreen = false,
@@ -1282,11 +1498,32 @@ function AgentRail({
1282
1498
  onSubmit,
1283
1499
  onFollowUpSelect
1284
1500
  }) {
1285
- const transcriptRef = (0, import_react4.useRef)(null);
1286
- const railStyle = theme?.railMaxWidth ? { ["--rail-width"]: theme.railMaxWidth, ["--as-rail-max-width"]: theme.railMaxWidth } : void 0;
1501
+ const transcriptRef = (0, import_react5.useRef)(null);
1502
+ const resolvedTheme = { ...defaultAgentRailTheme, ...theme };
1503
+ const railStyle = {
1504
+ "--rail-width": resolvedTheme.railMaxWidth,
1505
+ "--as-rail-max-width": resolvedTheme.railMaxWidth,
1506
+ "--as-brand": resolvedTheme.brand,
1507
+ "--as-brand-soft": resolvedTheme.brandSoft,
1508
+ "--as-brand-deep": resolvedTheme.brandDeep,
1509
+ "--as-surface": resolvedTheme.surface,
1510
+ "--as-surface-muted": resolvedTheme.surfaceMuted,
1511
+ "--as-text": resolvedTheme.text,
1512
+ "--as-text-muted": resolvedTheme.textMuted,
1513
+ "--as-text-subtle": resolvedTheme.textSubtle,
1514
+ "--as-border": resolvedTheme.border,
1515
+ "--as-visitor-bubble": resolvedTheme.visitorBubble,
1516
+ "--as-visitor-text": resolvedTheme.visitorText,
1517
+ "--as-success": resolvedTheme.success,
1518
+ "--as-danger": resolvedTheme.danger,
1519
+ "--as-font-body": resolvedTheme.fontBody,
1520
+ "--as-font-display": resolvedTheme.fontDisplay
1521
+ };
1287
1522
  const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming";
1288
- const showActivity = state.toolSteps.length > 0 && (state.phase === "thinking" || state.phase === "running-tools");
1289
- const hasVisitorMessages2 = state.messages.some((message) => message.role === "visitor");
1523
+ const showActivity = state.toolSteps.length > 0;
1524
+ const hasVisitorMessages2 = state.messages.some(
1525
+ (message) => message.role === "visitor"
1526
+ );
1290
1527
  const showIdleFollowUps = !hasVisitorMessages2 && state.followUps.length > 0;
1291
1528
  const showDockFollowUps = expanded && showIdleFollowUps;
1292
1529
  const streamingMessage = state.phase === "streaming" && state.streamingText ? {
@@ -1296,46 +1533,77 @@ function AgentRail({
1296
1533
  streaming: true,
1297
1534
  text: state.streamingText
1298
1535
  } : null;
1299
- (0, import_react4.useEffect)(() => {
1536
+ (0, import_react5.useEffect)(() => {
1300
1537
  const node = transcriptRef.current;
1301
1538
  if (!node) return;
1302
1539
  node.scrollTop = node.scrollHeight;
1303
- }, [state.messages, state.toolSteps, state.streamingText, state.followUps, state.journey]);
1304
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1540
+ }, [
1541
+ state.messages,
1542
+ state.toolSteps,
1543
+ state.streamingText,
1544
+ state.followUps,
1545
+ state.journey
1546
+ ]);
1547
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1305
1548
  "aside",
1306
1549
  {
1307
1550
  className: `agent-rail${mobileFullscreen ? " agent-rail--mobile-fullscreen" : ""}${expanded ? " agent-rail--expanded" : ""}`,
1308
1551
  style: railStyle,
1309
1552
  "aria-label": "Agent conversation",
1310
1553
  children: [
1311
- /* @__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: [
1312
- onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1554
+ /* @__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: [
1555
+ onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1313
1556
  "button",
1314
1557
  {
1315
1558
  type: "button",
1316
1559
  className: "agent-rail__collapse",
1317
1560
  "aria-label": "Collapse assist",
1318
1561
  onClick: onCollapse,
1319
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MinimizeIcon, {})
1562
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MinimizeIcon, {})
1563
+ }
1564
+ ) : onClose ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1565
+ "button",
1566
+ {
1567
+ type: "button",
1568
+ className: "agent-rail__close",
1569
+ "aria-label": "Close agent",
1570
+ onClick: onClose,
1571
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MinimizeIcon, {})
1320
1572
  }
1321
- ) : 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" }),
1322
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-label", children: brandLabel }),
1323
- onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1573
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
1574
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "agent-rail__identity", children: [
1575
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "agent-rail__brand-mark", "aria-hidden": "true", children: [
1576
+ brandLabel.slice(0, 1).toUpperCase(),
1577
+ brandLogoUrl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1578
+ "img",
1579
+ {
1580
+ className: "agent-rail__brand-logo",
1581
+ src: brandLogoUrl,
1582
+ alt: "",
1583
+ onError: (event) => {
1584
+ event.currentTarget.hidden = true;
1585
+ }
1586
+ }
1587
+ ) : null
1588
+ ] }),
1589
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-label", children: brandLabel })
1590
+ ] }),
1591
+ onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1324
1592
  "button",
1325
1593
  {
1326
1594
  type: "button",
1327
1595
  className: "agent-rail__expand",
1328
1596
  "aria-label": expanded ? "Restore assist panel" : "Expand assist panel",
1329
1597
  onClick: onExpandToggle,
1330
- children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpandIcon, {})
1598
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpandIcon, {})
1331
1599
  }
1332
- ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" })
1600
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" })
1333
1601
  ] }) }),
1334
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: [
1335
- state.messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message }, message.id)),
1336
- streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message: streamingMessage }) : null,
1337
- showActivity ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AgentActivityBubble, { steps: state.toolSteps }) : null,
1338
- !expanded && showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1602
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: [
1603
+ state.messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MessageBubble, { message }, message.id)),
1604
+ streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MessageBubble, { message: streamingMessage }) : null,
1605
+ showActivity ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AgentActivityBubble, { steps: state.toolSteps }) : null,
1606
+ !expanded && showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1339
1607
  FollowUpChips,
1340
1608
  {
1341
1609
  suggestions: state.followUps,
@@ -1344,10 +1612,17 @@ function AgentRail({
1344
1612
  onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
1345
1613
  }
1346
1614
  ) }) : null,
1347
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "alert", style: { fontSize: 13, color: "var(--as-danger)", margin: 0 }, children: state.error }) : null
1615
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1616
+ "p",
1617
+ {
1618
+ role: "alert",
1619
+ style: { fontSize: 13, color: "var(--as-danger)", margin: 0 },
1620
+ children: state.error
1621
+ }
1622
+ ) : null
1348
1623
  ] }),
1349
- expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__dock-wrap", children: [
1350
- showDockFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__dock-followups", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1624
+ expanded ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__dock-wrap", children: [
1625
+ showDockFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__dock-followups", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1351
1626
  FollowUpChips,
1352
1627
  {
1353
1628
  variant: "dock",
@@ -1356,7 +1631,7 @@ function AgentRail({
1356
1631
  onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
1357
1632
  }
1358
1633
  ) }) : null,
1359
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__dock", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1634
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__dock", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1360
1635
  Composer,
1361
1636
  {
1362
1637
  variant: "dock",
@@ -1365,12 +1640,12 @@ function AgentRail({
1365
1640
  onSubmit
1366
1641
  }
1367
1642
  ) }),
1368
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__footer", children: [
1369
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1370
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1643
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__footer", children: [
1644
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1645
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1371
1646
  ] })
1372
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
1373
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1647
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
1648
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1374
1649
  Composer,
1375
1650
  {
1376
1651
  disabled: isBusy,
@@ -1378,9 +1653,9 @@ function AgentRail({
1378
1653
  onSubmit
1379
1654
  }
1380
1655
  ),
1381
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__footer", children: [
1382
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1383
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1656
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__footer", children: [
1657
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1658
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1384
1659
  ] })
1385
1660
  ] })
1386
1661
  ]
@@ -1389,22 +1664,67 @@ function AgentRail({
1389
1664
  }
1390
1665
 
1391
1666
  // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
1392
- var import_jsx_runtime7 = require("react/jsx-runtime");
1667
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1393
1668
  function SparklesIcon() {
1394
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { className: "assist-edge-tab__sparkles", viewBox: "0 0 18 16", fill: "none", "aria-hidden": "true", children: [
1395
- /* @__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" }),
1396
- /* @__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" }),
1397
- /* @__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" })
1398
- ] });
1669
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1670
+ "svg",
1671
+ {
1672
+ className: "assist-edge-tab__sparkles",
1673
+ viewBox: "0 0 18 16",
1674
+ fill: "none",
1675
+ "aria-hidden": "true",
1676
+ children: [
1677
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1678
+ "path",
1679
+ {
1680
+ 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",
1681
+ fill: "currentColor"
1682
+ }
1683
+ ),
1684
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1685
+ "path",
1686
+ {
1687
+ 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",
1688
+ fill: "currentColor"
1689
+ }
1690
+ ),
1691
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1692
+ "path",
1693
+ {
1694
+ 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",
1695
+ fill: "currentColor"
1696
+ }
1697
+ )
1698
+ ]
1699
+ }
1700
+ );
1399
1701
  }
1400
1702
  function ChevronLeftIcon() {
1401
- 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" }) });
1703
+ 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)(
1704
+ "path",
1705
+ {
1706
+ d: "M10 4L6 8l4 4",
1707
+ stroke: "currentColor",
1708
+ strokeWidth: "1.6",
1709
+ strokeLinecap: "round",
1710
+ strokeLinejoin: "round"
1711
+ }
1712
+ ) });
1402
1713
  }
1403
1714
  function ChevronDownIcon() {
1404
- 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" }) });
1715
+ 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)(
1716
+ "path",
1717
+ {
1718
+ d: "M4 6l4 4 4-4",
1719
+ stroke: "currentColor",
1720
+ strokeWidth: "1.6",
1721
+ strokeLinecap: "round",
1722
+ strokeLinejoin: "round"
1723
+ }
1724
+ ) });
1405
1725
  }
1406
1726
  function DragDots() {
1407
- 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)) });
1727
+ 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)) });
1408
1728
  }
1409
1729
  var VARIANT_COPY = {
1410
1730
  outline: { label: "Assist", aria: "Open Assist" },
@@ -1417,38 +1737,71 @@ function AssistEdgeTab({
1417
1737
  along,
1418
1738
  inset,
1419
1739
  visible,
1740
+ label,
1741
+ logoUrl,
1742
+ brandColor,
1743
+ fontFamily,
1420
1744
  onOpen
1421
1745
  }) {
1422
1746
  const copy = VARIANT_COPY[variant];
1747
+ const visibleLabel = label?.trim() || copy.label;
1423
1748
  const style = {
1424
1749
  "--tab-along": `${along}%`,
1425
- "--tab-inset": `${inset}px`
1750
+ "--tab-inset": `${inset}px`,
1751
+ ...brandColor ? { "--as-brand": brandColor } : {},
1752
+ ...fontFamily ? { "--as-font-display": fontFamily } : {}
1426
1753
  };
1427
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1754
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1428
1755
  "button",
1429
1756
  {
1430
1757
  type: "button",
1431
1758
  className: `assist-edge-tab assist-edge-tab--${variant} assist-edge-tab--${side}${visible ? " is-visible" : ""}`,
1432
1759
  style,
1433
- "aria-label": copy.aria,
1760
+ "aria-label": `Open ${visibleLabel}`,
1434
1761
  "aria-hidden": !visible,
1435
1762
  tabIndex: visible ? 0 : -1,
1436
1763
  onClick: onOpen,
1437
1764
  children: [
1438
- variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1439
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {}),
1440
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
1441
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronDownIcon, {})
1765
+ variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1766
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
1767
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparklesIcon, {}),
1768
+ logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1769
+ "img",
1770
+ {
1771
+ className: "assist-edge-tab__logo",
1772
+ src: logoUrl,
1773
+ alt: "",
1774
+ onError: (event) => {
1775
+ event.currentTarget.hidden = true;
1776
+ }
1777
+ }
1778
+ ) : null
1779
+ ] }),
1780
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1781
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronDownIcon, {})
1442
1782
  ] }) : null,
1443
- variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1444
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {}),
1445
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
1446
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DragDots, {})
1783
+ variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1784
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronLeftIcon, {}),
1785
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1786
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DragDots, {})
1447
1787
  ] }) : null,
1448
- variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1449
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {}),
1450
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
1451
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {})
1788
+ variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1789
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
1790
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparklesIcon, {}),
1791
+ logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1792
+ "img",
1793
+ {
1794
+ className: "assist-edge-tab__logo",
1795
+ src: logoUrl,
1796
+ alt: "",
1797
+ onError: (event) => {
1798
+ event.currentTarget.hidden = true;
1799
+ }
1800
+ }
1801
+ ) : null
1802
+ ] }),
1803
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1804
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronLeftIcon, {})
1452
1805
  ] }) : null
1453
1806
  ]
1454
1807
  }
@@ -1456,7 +1809,7 @@ function AssistEdgeTab({
1456
1809
  }
1457
1810
 
1458
1811
  // src/react/components/AgentWidget/AgentWidget.tsx
1459
- var import_jsx_runtime8 = require("react/jsx-runtime");
1812
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1460
1813
  function AgentWidget({
1461
1814
  indexId,
1462
1815
  customerId,
@@ -1465,21 +1818,53 @@ function AgentWidget({
1465
1818
  runtimeOrigin,
1466
1819
  placement: placementInput,
1467
1820
  defaultCollapsed = true,
1468
- registerPanelController = false
1821
+ pageShift = true,
1822
+ registerPanelController = false,
1823
+ branding
1469
1824
  }) {
1470
1825
  const isMobile = useIsMobile();
1471
1826
  const placement = normalizeAgentPlacement(placementInput);
1472
- const [railCollapsed, setRailCollapsed] = (0, import_react5.useState)(defaultCollapsed);
1473
- const [railExpanded, setRailExpanded] = (0, import_react5.useState)(false);
1827
+ const railSlotRef = (0, import_react6.useRef)(null);
1828
+ const [railCollapsed, setRailCollapsed] = (0, import_react6.useState)(defaultCollapsed);
1829
+ const [railExpanded, setRailExpanded] = (0, import_react6.useState)(false);
1830
+ const pageShiftActive = shouldApplyPageShift({
1831
+ pageShift,
1832
+ isMobile,
1833
+ railCollapsed,
1834
+ railExpanded
1835
+ });
1836
+ usePageShift({
1837
+ active: pageShiftActive,
1838
+ railSlotRef
1839
+ });
1474
1840
  const { state, submit } = useAgentChat({
1475
1841
  customerId,
1476
1842
  getUnpublishedPreviewGrant,
1477
1843
  indexId,
1478
1844
  version,
1479
- runtimeOrigin
1845
+ runtimeOrigin,
1846
+ greeting: branding?.greeting
1480
1847
  });
1848
+ const agentName = branding?.agentName ?? "Webless Guide";
1849
+ const theme = {
1850
+ ...branding?.fontFamily ? { fontBody: branding.fontFamily, fontDisplay: branding.fontFamily } : {},
1851
+ ...branding?.colors?.primary ? {
1852
+ brand: branding.colors.primary,
1853
+ visitorBubble: branding.colors.primary
1854
+ } : {},
1855
+ ...branding?.colors?.primarySoft ? { brandSoft: branding.colors.primarySoft } : {},
1856
+ ...branding?.colors?.primaryForeground ? { visitorText: branding.colors.primaryForeground } : {},
1857
+ ...branding?.colors?.surface ? { surface: branding.colors.surface } : {},
1858
+ ...branding?.colors?.surfaceMuted ? { surfaceMuted: branding.colors.surfaceMuted } : {},
1859
+ ...branding?.colors?.text ? { text: branding.colors.text } : {},
1860
+ ...branding?.colors?.textMuted ? {
1861
+ textMuted: branding.colors.textMuted,
1862
+ textSubtle: branding.colors.textMuted
1863
+ } : {},
1864
+ ...branding?.colors?.border ? { border: branding.colors.border } : {}
1865
+ };
1481
1866
  const idle = state.phase === "idle" && !hasVisitorMessages(state.messages);
1482
- (0, import_react5.useEffect)(() => {
1867
+ (0, import_react6.useEffect)(() => {
1483
1868
  if (!registerPanelController) return;
1484
1869
  registerAgentPanelController(customerId, {
1485
1870
  open: () => setRailCollapsed(false),
@@ -1494,47 +1879,56 @@ function AgentWidget({
1494
1879
  if (isMobile) setRailCollapsed(false);
1495
1880
  await submit(message);
1496
1881
  }
1497
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "webless-agent-root", children: [
1498
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1882
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "webless-agent-root", children: [
1883
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1499
1884
  "div",
1500
1885
  {
1501
1886
  className: `webless-agent-root__shell${railCollapsed ? " webless-agent-root__shell--collapsed" : ""}${railExpanded ? " webless-agent-root__shell--expanded" : ""}`,
1502
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1503
- "div",
1504
- {
1505
- className: "webless-agent-root__rail-slot",
1506
- inert: railCollapsed || void 0,
1507
- "aria-hidden": railCollapsed,
1508
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1509
- AgentRail,
1510
- {
1511
- state: idle ? {
1512
- ...state,
1513
- followUps: createIdleSuggestions()
1514
- } : state,
1515
- mobileFullscreen: isMobile && !railCollapsed,
1516
- expanded: railExpanded,
1517
- onCollapse: !isMobile ? () => setRailCollapsed(true) : void 0,
1518
- onClose: isMobile ? () => setRailCollapsed(true) : void 0,
1519
- onExpandToggle: !isMobile ? () => setRailExpanded((current) => !current) : void 0,
1520
- onSubmit: handleSubmit,
1521
- onFollowUpSelect: (label) => void handleSubmit(label)
1522
- }
1523
- )
1524
- }
1525
- )
1887
+ children: [
1888
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1889
+ "div",
1890
+ {
1891
+ ref: railSlotRef,
1892
+ className: "webless-agent-root__rail-slot",
1893
+ inert: railCollapsed || void 0,
1894
+ "aria-hidden": railCollapsed,
1895
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1896
+ AgentRail,
1897
+ {
1898
+ theme,
1899
+ brandLabel: agentName,
1900
+ brandLogoUrl: branding?.logoUrl,
1901
+ composerPlaceholder: branding?.composerPlaceholder ?? `Ask ${agentName}\u2026`,
1902
+ poweredByLabel: branding?.poweredByLabel ?? "Powered by Webless",
1903
+ state: idle ? {
1904
+ ...state,
1905
+ followUps: createIdleSuggestions()
1906
+ } : state,
1907
+ mobileFullscreen: isMobile && !railCollapsed,
1908
+ expanded: railExpanded,
1909
+ onCollapse: !isMobile ? () => setRailCollapsed(true) : void 0,
1910
+ onClose: isMobile ? () => setRailCollapsed(true) : void 0,
1911
+ onExpandToggle: !isMobile ? () => setRailExpanded((current) => !current) : void 0,
1912
+ onSubmit: handleSubmit,
1913
+ onFollowUpSelect: (label) => void handleSubmit(label)
1914
+ }
1915
+ )
1916
+ }
1917
+ ),
1918
+ !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1919
+ "button",
1920
+ {
1921
+ type: "button",
1922
+ className: "webless-agent-root__backdrop",
1923
+ tabIndex: -1,
1924
+ "aria-label": "Close expanded assist",
1925
+ onClick: () => setRailExpanded(false)
1926
+ }
1927
+ ) : null
1928
+ ]
1526
1929
  }
1527
1930
  ),
1528
- !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1529
- "button",
1530
- {
1531
- type: "button",
1532
- className: "webless-agent-root__backdrop",
1533
- "aria-label": "Close expanded assist",
1534
- onClick: () => setRailExpanded(false)
1535
- }
1536
- ) : null,
1537
- railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1931
+ railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1538
1932
  AssistEdgeTab,
1539
1933
  {
1540
1934
  variant: placement.variant,
@@ -1542,6 +1936,10 @@ function AgentWidget({
1542
1936
  along: placement.along,
1543
1937
  inset: placement.inset,
1544
1938
  visible: true,
1939
+ label: agentName,
1940
+ logoUrl: branding?.logoUrl,
1941
+ brandColor: branding?.colors?.primary,
1942
+ fontFamily: branding?.fontFamily,
1545
1943
  onOpen: () => setRailCollapsed(false)
1546
1944
  }
1547
1945
  ) : null
@@ -1549,9 +1947,11 @@ function AgentWidget({
1549
1947
  }
1550
1948
 
1551
1949
  // src/embed/AgentWidget.tsx
1552
- var import_jsx_runtime9 = require("react/jsx-runtime");
1553
- function AgentWidget2({ manifest }) {
1554
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1950
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1951
+ function AgentWidget2({
1952
+ manifest
1953
+ }) {
1954
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1555
1955
  AgentWidget,
1556
1956
  {
1557
1957
  indexId: manifest.indexId,
@@ -1559,6 +1959,8 @@ function AgentWidget2({ manifest }) {
1559
1959
  version: manifest.version,
1560
1960
  runtimeOrigin: manifest.runtimeOrigin,
1561
1961
  placement: manifest.placement,
1962
+ pageShift: manifest.pageShift,
1963
+ branding: manifest.branding,
1562
1964
  defaultCollapsed: true,
1563
1965
  registerPanelController: true
1564
1966
  }
@@ -1584,6 +1986,7 @@ function normalizeAgentTagManifest(manifest) {
1584
1986
  version,
1585
1987
  runtimeOrigin: manifest.runtimeOrigin?.trim() || DEFAULT_RUNTIME_ORIGIN
1586
1988
  });
1989
+ const branding = normalizeAgentBranding(manifest.branding);
1587
1990
  return {
1588
1991
  customerId,
1589
1992
  indexId,
@@ -1593,12 +1996,37 @@ function normalizeAgentTagManifest(manifest) {
1593
1996
  selector: manifest.mount?.selector?.trim(),
1594
1997
  strategy: manifest.mount?.strategy ?? "body"
1595
1998
  },
1596
- placement: normalizeAgentPlacement(manifest.placement)
1999
+ placement: normalizeAgentPlacement(manifest.placement),
2000
+ pageShift: manifest.pageShift ?? true,
2001
+ ...branding ? { branding } : {}
1597
2002
  };
1598
2003
  }
2004
+ function normalizeOptionalValue(value) {
2005
+ const normalized = value?.trim();
2006
+ return normalized || void 0;
2007
+ }
2008
+ function normalizeAgentBranding(branding) {
2009
+ if (!branding) return void 0;
2010
+ const colors = branding.colors ? Object.fromEntries(
2011
+ Object.entries(branding.colors).flatMap(([key, value]) => {
2012
+ const normalized2 = normalizeOptionalValue(value);
2013
+ return normalized2 ? [[key, normalized2]] : [];
2014
+ })
2015
+ ) : void 0;
2016
+ const normalized = {
2017
+ agentName: normalizeOptionalValue(branding.agentName),
2018
+ logoUrl: normalizeOptionalValue(branding.logoUrl),
2019
+ greeting: normalizeOptionalValue(branding.greeting),
2020
+ composerPlaceholder: normalizeOptionalValue(branding.composerPlaceholder),
2021
+ poweredByLabel: normalizeOptionalValue(branding.poweredByLabel),
2022
+ fontFamily: normalizeOptionalValue(branding.fontFamily),
2023
+ colors: colors && Object.keys(colors).length > 0 ? colors : void 0
2024
+ };
2025
+ return Object.values(normalized).some((value) => value !== void 0) ? normalized : void 0;
2026
+ }
1599
2027
 
1600
2028
  // src/embed/mount.tsx
1601
- var import_jsx_runtime10 = require("react/jsx-runtime");
2029
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1602
2030
  var mountedHandles = /* @__PURE__ */ new Map();
1603
2031
  var latestCustomerId = null;
1604
2032
  function resolveMountHost(manifest, script) {
@@ -1628,7 +2056,7 @@ function mountAgent(input) {
1628
2056
  const host = createHost(manifest.customerId);
1629
2057
  mountTarget.append(host);
1630
2058
  const root = (0, import_client5.createRoot)(host);
1631
- root.render(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentWidget2, { manifest }));
2059
+ root.render(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentWidget2, { manifest }));
1632
2060
  const handle = {
1633
2061
  customerId: manifest.customerId,
1634
2062
  manifest,