@webless/agent 0.2.15 → 0.3.1

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
@@ -351,9 +351,8 @@ function clearPersistedAgentSession(visitorSessionId, options) {
351
351
  function isTurnBoundary(event) {
352
352
  return event.type === "session.waiting" || event.type === "session.completed" || event.type === "session.failed";
353
353
  }
354
- function applyMessageEvent(event, rendered, handlers) {
355
- const step = mapStepLabel(event);
356
- if (step) handlers.onStep?.(step.label, step.detail);
354
+ function applyMessageEvent(event, rendered, handlers, workItems) {
355
+ applyWorkEvent(event, handlers, workItems);
357
356
  if (event.type === "session.failed") {
358
357
  throw new Error(event.data.message || event.data.code);
359
358
  }
@@ -396,13 +395,120 @@ function renderTurn(events) {
396
395
  }
397
396
  return rendered;
398
397
  }
399
- function mapStepLabel(event) {
400
- if (event.type !== "step.started") return null;
401
- const stepIndex = event.data.stepIndex;
402
- return {
403
- label: "Model step running",
404
- detail: typeof stepIndex === "number" ? `Step ${stepIndex + 1}` : void 0
405
- };
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
+ );
406
512
  }
407
513
  var AgentSession = class {
408
514
  constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, getUnpublishedPreviewGrant) {
@@ -520,10 +626,11 @@ var AgentSession = class {
520
626
  this.activeResponse = response;
521
627
  let streamIndex = session?.state.streamIndex ?? 0;
522
628
  let rendered = "";
629
+ const workItems = /* @__PURE__ */ new Map();
523
630
  try {
524
631
  for await (const event of response) {
525
632
  if (signal.aborted) break;
526
- rendered = applyMessageEvent(event, rendered, handlers);
633
+ rendered = applyMessageEvent(event, rendered, handlers, workItems);
527
634
  streamIndex += 1;
528
635
  if (session) {
529
636
  savePersistedAgentSession(
@@ -565,6 +672,10 @@ var AgentSession = class {
565
672
  return null;
566
673
  }
567
674
  let rendered = renderTurn(turnEvents);
675
+ const workItems = /* @__PURE__ */ new Map();
676
+ for (const event of turnEvents) {
677
+ applyWorkEvent(event, handlers, workItems);
678
+ }
568
679
  if (rendered.startsWith(initialText)) {
569
680
  const missedText = rendered.slice(initialText.length);
570
681
  if (missedText) handlers.onDelta(missedText);
@@ -599,7 +710,7 @@ var AgentSession = class {
599
710
  let streamIndex = snapshot.session.streamIndex;
600
711
  for await (const event of session.stream({ signal })) {
601
712
  if (signal.aborted) break;
602
- rendered = applyMessageEvent(event, rendered, handlers);
713
+ rendered = applyMessageEvent(event, rendered, handlers, workItems);
603
714
  streamIndex += 1;
604
715
  savePersistedAgentSession(
605
716
  this.visitorSessionId,
@@ -679,6 +790,11 @@ function createAgentClient(options) {
679
790
 
680
791
  // src/runtime/errors.ts
681
792
  var import_client3 = require("eve/client");
793
+ var TRANSIENT_AGENT_ERROR_MESSAGE = "I couldn\u2019t finish that answer. Please try again.";
794
+ function isTransientRuntimeMessage(message) {
795
+ const normalized = message.trim().toLowerCase();
796
+ return normalized.includes("empty response from runtime") || normalized.includes("failed to fetch") || normalized.includes("networkerror") || normalized.includes("load failed");
797
+ }
682
798
  function formatAgentError(error) {
683
799
  if (error instanceof import_client3.ClientError) {
684
800
  if (error.status === 401 && error.code === "index_required") {
@@ -690,13 +806,18 @@ function formatAgentError(error) {
690
806
  if (error.status === 409 && error.code === "session_not_active") {
691
807
  return "Session expired \u2014 send a new message to start again.";
692
808
  }
693
- return error.message || `Runtime error (${error.status})`;
809
+ if (error.status >= 500 || error.message && isTransientRuntimeMessage(error.message)) {
810
+ return TRANSIENT_AGENT_ERROR_MESSAGE;
811
+ }
812
+ return error.message || "This assistant is unavailable right now.";
694
813
  }
695
814
  if (error instanceof DOMException && error.name === "AbortError") {
696
815
  return "";
697
816
  }
698
- if (error instanceof Error) return error.message;
699
- return "Runtime request failed";
817
+ if (error instanceof Error) {
818
+ return isTransientRuntimeMessage(error.message) ? TRANSIENT_AGENT_ERROR_MESSAGE : error.message;
819
+ }
820
+ return TRANSIENT_AGENT_ERROR_MESSAGE;
700
821
  }
701
822
 
702
823
  // src/react/persisted-conversation.ts
@@ -752,57 +873,54 @@ function clearPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
752
873
  }
753
874
 
754
875
  // src/react/hooks/useAgentChat.ts
755
- var GREETING_MESSAGE = {
756
- id: "greeting",
757
- role: "agent",
758
- text: "Hi! I'm connected to the Webless Agent Runtime. Ask anything about your published site index.",
759
- createdAt: 0
760
- };
761
- var INITIAL_STATE = {
762
- phase: "idle",
763
- messages: [GREETING_MESSAGE],
764
- toolSteps: [],
765
- journey: null,
766
- followUps: [],
767
- streamingText: "",
768
- error: null
769
- };
770
- function stateFromConversation(conversation) {
771
- if (!conversation || conversation.messages.length === 0) return INITIAL_STATE;
876
+ var DEFAULT_GREETING = "Hi! I can search this site or bring in a specialist when it helps. What would you like to know?";
877
+ function createInitialState(greeting = DEFAULT_GREETING) {
878
+ return {
879
+ phase: "idle",
880
+ messages: [
881
+ {
882
+ id: "greeting",
883
+ role: "agent",
884
+ text: greeting,
885
+ createdAt: 0
886
+ }
887
+ ],
888
+ toolSteps: [],
889
+ journey: null,
890
+ followUps: [],
891
+ streamingText: "",
892
+ error: null
893
+ };
894
+ }
895
+ function stateFromConversation(conversation, initialState) {
896
+ if (!conversation || conversation.messages.length === 0) return initialState;
772
897
  return {
773
- ...INITIAL_STATE,
898
+ ...initialState,
774
899
  messages: conversation.messages,
775
900
  phase: conversation.pending ? conversation.streamingText ? "streaming" : "thinking" : "complete",
776
901
  streamingText: conversation.streamingText
777
902
  };
778
903
  }
779
- var STATUS_SEQUENCE = [
780
- { id: "s1", label: "Starting Eve session", ms: 400 },
781
- { id: "s2", label: "Connecting to runtime", ms: 500 }
782
- ];
783
- function delay(ms, signal) {
784
- return new Promise((resolve, reject) => {
785
- const timer = window.setTimeout(resolve, ms);
786
- signal.addEventListener(
787
- "abort",
788
- () => {
789
- window.clearTimeout(timer);
790
- reject(new DOMException("Aborted", "AbortError"));
791
- },
792
- { once: true }
793
- );
794
- });
795
- }
796
- async function runStatusSequence(signal, onStep) {
797
- for (const item of STATUS_SEQUENCE) {
798
- onStep({
799
- id: item.id,
800
- label: item.label,
801
- detail: item.detail,
802
- state: "active"
803
- });
804
- await delay(item.ms, signal);
805
- }
904
+ function upsertToolStep(steps, item) {
905
+ const next = {
906
+ id: item.id,
907
+ kind: item.kind,
908
+ label: item.label,
909
+ state: item.state,
910
+ ...item.detail ? { detail: item.detail } : {}
911
+ };
912
+ const index = steps.findIndex((step) => step.id === item.id);
913
+ if (index < 0) return [...steps, next];
914
+ return steps.map((step, stepIndex) => stepIndex === index ? next : step);
915
+ }
916
+ function completeActivePlanning(steps) {
917
+ return steps.map(
918
+ (step) => step.kind === "planning" && step.state === "active" ? {
919
+ ...step,
920
+ detail: "Prepared a response",
921
+ state: "completed"
922
+ } : step
923
+ );
806
924
  }
807
925
  function useAgentChat({
808
926
  customerId,
@@ -811,8 +929,13 @@ function useAgentChat({
811
929
  version,
812
930
  runtimeOrigin,
813
931
  visitorSessionId,
814
- storageKeyPrefix
932
+ storageKeyPrefix,
933
+ greeting
815
934
  }) {
935
+ const initialState = (0, import_react2.useMemo)(
936
+ () => createInitialState(greeting?.trim() || DEFAULT_GREETING),
937
+ [greeting]
938
+ );
816
939
  const previewGrantProviderRef = (0, import_react2.useRef)(getUnpublishedPreviewGrant);
817
940
  previewGrantProviderRef.current = getUnpublishedPreviewGrant;
818
941
  const resolveUnpublishedPreviewGrant = () => {
@@ -843,7 +966,8 @@ function useAgentChat({
843
966
  );
844
967
  const [state, setState] = (0, import_react2.useState)(
845
968
  () => stateFromConversation(
846
- loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
969
+ loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
970
+ initialState
847
971
  )
848
972
  );
849
973
  const runRef = (0, import_react2.useRef)(null);
@@ -858,7 +982,7 @@ function useAgentChat({
858
982
  storageKeyPrefix: resolvedStorageKeyPrefix
859
983
  })
860
984
  );
861
- const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}`;
985
+ const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}|${greeting ?? ""}`;
862
986
  const identityRef = (0, import_react2.useRef)(identityKey);
863
987
  (0, import_react2.useEffect)(() => {
864
988
  if (identityRef.current === identityKey) {
@@ -878,13 +1002,15 @@ function useAgentChat({
878
1002
  });
879
1003
  setState(
880
1004
  stateFromConversation(
881
- loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
1005
+ loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
1006
+ initialState
882
1007
  )
883
1008
  );
884
1009
  }, [
885
1010
  customerId,
886
1011
  identityKey,
887
1012
  indexId,
1013
+ initialState,
888
1014
  runtimeOrigin,
889
1015
  resolvedStorageKeyPrefix,
890
1016
  version,
@@ -909,8 +1035,8 @@ function useAgentChat({
909
1035
  runRef.current = null;
910
1036
  clientRef.current.reset();
911
1037
  clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
912
- setState(INITIAL_STATE);
913
- }, [resolvedStorageKeyPrefix, visitorId]);
1038
+ setState(initialState);
1039
+ }, [initialState, resolvedStorageKeyPrefix, visitorId]);
914
1040
  const runTurn = (0, import_react2.useCallback)(
915
1041
  async (input) => {
916
1042
  const { controller, initialText = "", resume, visitorText } = input;
@@ -919,35 +1045,23 @@ function useAgentChat({
919
1045
  try {
920
1046
  let streamStarted = Boolean(initialText);
921
1047
  let streamed = initialText;
922
- const planningPromise = resume ? Promise.resolve() : runStatusSequence(signal, (step) => {
923
- if (streamStarted || !isActiveRun()) return;
924
- setState((prev) => ({
925
- ...prev,
926
- phase: "running-tools",
927
- toolSteps: [step]
928
- }));
929
- });
930
1048
  const handlers = {
931
- onStep: (label, detail) => {
932
- if (streamStarted || !isActiveRun()) return;
1049
+ onWork: (item) => {
1050
+ if (!isActiveRun()) return;
933
1051
  setState((prev) => ({
934
1052
  ...prev,
935
- phase: "running-tools",
936
- toolSteps: [
937
- { id: `step-${label}`, label, detail, state: "active" }
938
- ]
1053
+ phase: item.state === "active" ? "running-tools" : prev.phase,
1054
+ toolSteps: upsertToolStep(prev.toolSteps, item)
939
1055
  }));
940
1056
  },
941
1057
  onDelta: (delta) => {
942
1058
  if (!isActiveRun()) return;
943
- void planningPromise.catch(() => {
944
- });
945
1059
  if (!streamStarted) {
946
1060
  streamStarted = true;
947
1061
  setState((prev) => ({
948
1062
  ...prev,
949
1063
  phase: "streaming",
950
- toolSteps: [],
1064
+ toolSteps: completeActivePlanning(prev.toolSteps),
951
1065
  streamingText: ""
952
1066
  }));
953
1067
  }
@@ -975,8 +1089,6 @@ function useAgentChat({
975
1089
  signal
976
1090
  });
977
1091
  }
978
- await planningPromise.catch(() => {
979
- });
980
1092
  if (!isActiveRun() || finalText === null) return;
981
1093
  const agentMessage = {
982
1094
  id: `agent-${Date.now()}`,
@@ -988,7 +1100,7 @@ function useAgentChat({
988
1100
  ...prev,
989
1101
  phase: "complete",
990
1102
  messages: [...prev.messages, agentMessage],
991
- toolSteps: [],
1103
+ toolSteps: completeActivePlanning(prev.toolSteps),
992
1104
  streamingText: "",
993
1105
  followUps: [],
994
1106
  journey: null
@@ -1003,7 +1115,13 @@ function useAgentChat({
1003
1115
  setState((prev) => ({
1004
1116
  ...prev,
1005
1117
  phase: "complete",
1006
- toolSteps: [],
1118
+ toolSteps: prev.toolSteps.map(
1119
+ (step) => step.state === "active" ? {
1120
+ ...step,
1121
+ detail: "Couldn\u2019t complete this step",
1122
+ state: "error"
1123
+ } : step
1124
+ ),
1007
1125
  streamingText: "",
1008
1126
  error: message
1009
1127
  }));
@@ -1031,7 +1149,12 @@ function useAgentChat({
1031
1149
  phase: "thinking",
1032
1150
  messages: [...prev.messages, visitorMessage],
1033
1151
  toolSteps: [
1034
- { id: "s1", label: "Starting Eve session", state: "active" }
1152
+ {
1153
+ id: "planning",
1154
+ kind: "planning",
1155
+ label: "Understanding your question",
1156
+ state: "active"
1157
+ }
1035
1158
  ],
1036
1159
  journey: null,
1037
1160
  followUps: [],
@@ -1129,79 +1252,93 @@ function normalizeAgentPlacement(placement) {
1129
1252
  // src/react/components/AgentRail/AgentRail.tsx
1130
1253
  var import_react5 = require("react");
1131
1254
 
1132
- // src/react/components/ToolTimeline/ToolTimeline.tsx
1133
- var import_jsx_runtime = require("react/jsx-runtime");
1134
- function SpinnerIcon() {
1135
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className: "agent-status__spinner", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
1136
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "8", cy: "8", r: "6", stroke: "currentColor", strokeWidth: "1.5", strokeOpacity: "0.25" }),
1137
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 8a6 6 0 0 0-6-6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
1138
- ] });
1139
- }
1140
- function getCurrentStep(steps) {
1141
- const active = steps.find((step) => step.state === "active");
1142
- if (active) return active;
1143
- const error = steps.find((step) => step.state === "error");
1144
- if (error) return error;
1145
- const pending = steps.find((step) => step.state === "pending");
1146
- if (pending) return pending;
1147
- return steps.at(-1) ?? null;
1148
- }
1149
- function ToolTimeline({
1150
- steps,
1151
- streamingText,
1152
- showStreaming = false,
1153
- inline = false
1154
- }) {
1155
- if (steps.length === 0 && !(showStreaming && streamingText)) return null;
1156
- const currentStep = getCurrentStep(steps);
1157
- const showStatus = currentStep && currentStep.state !== "completed" && !(showStreaming && streamingText);
1158
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1159
- "div",
1160
- {
1161
- className: `tool-timeline${inline ? " tool-timeline--inline" : ""}`,
1162
- role: "status",
1163
- "aria-live": "polite",
1164
- "aria-label": "Agent progress",
1165
- children: [
1166
- showStatus ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-status", children: [
1167
- 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, {}) }),
1168
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-status__copy", children: [
1169
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__label", children: currentStep.label }),
1170
- currentStep.detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__detail", children: currentStep.detail }) : null
1171
- ] })
1172
- ] }, currentStep.id) : null,
1173
- showStreaming && streamingText ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "tool-timeline__streaming-text", children: [
1174
- streamingText,
1175
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tool-timeline__cursor", "aria-hidden": "true" })
1176
- ] }) : null
1177
- ]
1178
- }
1179
- );
1180
- }
1255
+ // src/react/types/conversation.ts
1256
+ var defaultAgentRailTheme = {
1257
+ railMaxWidth: "450px",
1258
+ brand: "#6f16ff",
1259
+ brandSoft: "#f3edff",
1260
+ brandDeep: "#12043e",
1261
+ surface: "#ffffff",
1262
+ surfaceMuted: "#f4f6fb",
1263
+ text: "#171b2a",
1264
+ textMuted: "#5a6378",
1265
+ textSubtle: "#8a94a8",
1266
+ border: "rgb(42 51 70 / 0.1)",
1267
+ visitorBubble: "#6f16ff",
1268
+ visitorText: "#ffffff",
1269
+ success: "#18794e",
1270
+ danger: "#c94b63",
1271
+ fontBody: '"Mulish", "Avenir Next", "Segoe UI", sans-serif',
1272
+ fontDisplay: '"Space Grotesk", sans-serif'
1273
+ };
1181
1274
 
1182
1275
  // src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
1183
- var import_jsx_runtime2 = require("react/jsx-runtime");
1184
- function AgentActivityBubble({
1185
- steps,
1186
- streamingText,
1187
- showStreaming = false
1188
- }) {
1189
- 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)(
1190
- ToolTimeline,
1191
- {
1192
- steps,
1193
- streamingText,
1194
- showStreaming,
1195
- inline: true
1196
- }
1197
- ) }) });
1276
+ var import_jsx_runtime = require("react/jsx-runtime");
1277
+ function workSummary(steps) {
1278
+ const active = [...steps].reverse().find((step) => step.state === "active");
1279
+ if (active?.kind === "specialist") return `Working with ${active.label}`;
1280
+ if (active?.kind === "search") return "Searching this site";
1281
+ if (active) return active.label;
1282
+ const hasError = steps.some((step) => step.state === "error");
1283
+ const specialists = steps.filter(
1284
+ (step) => step.kind === "specialist" && step.state === "completed"
1285
+ );
1286
+ const searched = steps.some(
1287
+ (step) => step.kind === "search" && step.state === "completed"
1288
+ );
1289
+ if (hasError) return "Answered with available information";
1290
+ if (specialists.length > 1)
1291
+ return `Consulted ${specialists.length} specialists`;
1292
+ if (specialists.length === 1) return `Consulted ${specialists[0]?.label}`;
1293
+ if (searched) return "Searched this site";
1294
+ return "Prepared a response";
1295
+ }
1296
+ function AgentActivityBubble({ steps }) {
1297
+ const active = steps.some((step) => step.state === "active");
1298
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", { className: "agent-activity-bubble", children: [
1299
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "agent-activity-bubble__status", "aria-live": "polite", children: [
1300
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1301
+ "span",
1302
+ {
1303
+ className: `agent-activity-bubble__pulse${active ? " is-active" : ""}`,
1304
+ "aria-hidden": "true"
1305
+ }
1306
+ ),
1307
+ workSummary(steps)
1308
+ ] }),
1309
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { className: "agent-activity-bubble__details", open: active, children: [
1310
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: "Work details" }),
1311
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "agent-activity-bubble__steps", children: steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1312
+ "li",
1313
+ {
1314
+ className: "agent-activity-bubble__step",
1315
+ "data-state": step.state,
1316
+ children: [
1317
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1318
+ "span",
1319
+ {
1320
+ className: "agent-activity-bubble__step-icon",
1321
+ "aria-hidden": "true",
1322
+ children: step.state === "completed" ? "\u2713" : step.state === "error" ? "!" : ""
1323
+ }
1324
+ ),
1325
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "agent-activity-bubble__step-copy", children: [
1326
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: step.label }),
1327
+ step.detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: step.detail }) : null
1328
+ ] })
1329
+ ]
1330
+ },
1331
+ step.id
1332
+ )) })
1333
+ ] })
1334
+ ] });
1198
1335
  }
1199
1336
 
1200
1337
  // src/react/components/Composer/Composer.tsx
1201
1338
  var import_react4 = require("react");
1202
- var import_jsx_runtime3 = require("react/jsx-runtime");
1339
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1203
1340
  function SendIcon() {
1204
- 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" }) });
1341
+ 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" }) });
1205
1342
  }
1206
1343
  function Composer({
1207
1344
  disabled = false,
@@ -1228,8 +1365,8 @@ function Composer({
1228
1365
  submitCurrent();
1229
1366
  }
1230
1367
  }
1231
- 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: [
1232
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1368
+ 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: [
1369
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1233
1370
  "textarea",
1234
1371
  {
1235
1372
  ref: inputRef,
@@ -1243,21 +1380,21 @@ function Composer({
1243
1380
  onKeyDown: handleKeyDown
1244
1381
  }
1245
1382
  ),
1246
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1383
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1247
1384
  "button",
1248
1385
  {
1249
1386
  type: "submit",
1250
1387
  className: "composer__send",
1251
1388
  disabled: disabled || !value.trim(),
1252
1389
  "aria-label": "Send message",
1253
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
1390
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SendIcon, {})
1254
1391
  }
1255
1392
  )
1256
1393
  ] }) });
1257
1394
  }
1258
1395
 
1259
1396
  // src/react/components/FollowUpChips/FollowUpChips.tsx
1260
- var import_jsx_runtime4 = require("react/jsx-runtime");
1397
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1261
1398
  function FollowUpChips({
1262
1399
  suggestions,
1263
1400
  disabled = false,
@@ -1267,7 +1404,7 @@ function FollowUpChips({
1267
1404
  }) {
1268
1405
  if (suggestions.length === 0) return null;
1269
1406
  if (variant === "dock") {
1270
- 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)(
1407
+ 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)(
1271
1408
  "button",
1272
1409
  {
1273
1410
  type: "button",
@@ -1279,9 +1416,9 @@ function FollowUpChips({
1279
1416
  suggestion.id
1280
1417
  )) }) });
1281
1418
  }
1282
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "followups", children: [
1283
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "followups__label", children: label }),
1284
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "followups__list", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1419
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "followups", children: [
1420
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "followups__label", children: label }),
1421
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "followups__list", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1285
1422
  "button",
1286
1423
  {
1287
1424
  type: "button",
@@ -1298,12 +1435,12 @@ function FollowUpChips({
1298
1435
  // src/react/components/MessageBubble/MessageBubble.tsx
1299
1436
  var import_streamdown = require("streamdown");
1300
1437
  var import_styles = require("streamdown/styles.css");
1301
- var import_jsx_runtime5 = require("react/jsx-runtime");
1438
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1302
1439
  function MessageBubble({ message }) {
1303
1440
  if (message.role === "visitor") {
1304
- 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 }) });
1441
+ 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 }) });
1305
1442
  }
1306
- 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)(
1443
+ 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)(
1307
1444
  import_streamdown.Streamdown,
1308
1445
  {
1309
1446
  animated: true,
@@ -1320,12 +1457,20 @@ function MessageBubble({ message }) {
1320
1457
  }
1321
1458
 
1322
1459
  // src/react/components/AgentRail/AgentRail.tsx
1323
- var import_jsx_runtime6 = require("react/jsx-runtime");
1460
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1324
1461
  function MinimizeIcon() {
1325
- 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" }) });
1462
+ 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)(
1463
+ "path",
1464
+ {
1465
+ d: "M3.5 8h9",
1466
+ stroke: "currentColor",
1467
+ strokeWidth: "1.7",
1468
+ strokeLinecap: "round"
1469
+ }
1470
+ ) });
1326
1471
  }
1327
1472
  function ExpandIcon() {
1328
- 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)(
1473
+ 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)(
1329
1474
  "path",
1330
1475
  {
1331
1476
  d: "M6 3.5H3.5V6M10 3.5h2.5V6M10 12.5h2.5V10M6 12.5H3.5V10",
@@ -1337,7 +1482,7 @@ function ExpandIcon() {
1337
1482
  ) });
1338
1483
  }
1339
1484
  function RestoreIcon() {
1340
- 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)(
1485
+ 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)(
1341
1486
  "path",
1342
1487
  {
1343
1488
  d: "M5.5 5.5H3.5V7.5M10.5 5.5h2V7.5M10.5 10.5h2V8.5M5.5 10.5H3.5V8.5",
@@ -1352,6 +1497,7 @@ function AgentRail({
1352
1497
  state,
1353
1498
  theme,
1354
1499
  brandLabel = "Webless Assist",
1500
+ brandLogoUrl,
1355
1501
  poweredByLabel = "Powered by Webless",
1356
1502
  composerPlaceholder = "Ask anything\u2026",
1357
1503
  mobileFullscreen = false,
@@ -1363,10 +1509,31 @@ function AgentRail({
1363
1509
  onFollowUpSelect
1364
1510
  }) {
1365
1511
  const transcriptRef = (0, import_react5.useRef)(null);
1366
- const railStyle = theme?.railMaxWidth ? { ["--rail-width"]: theme.railMaxWidth, ["--as-rail-max-width"]: theme.railMaxWidth } : void 0;
1512
+ const resolvedTheme = { ...defaultAgentRailTheme, ...theme };
1513
+ const railStyle = {
1514
+ "--rail-width": resolvedTheme.railMaxWidth,
1515
+ "--as-rail-max-width": resolvedTheme.railMaxWidth,
1516
+ "--as-brand": resolvedTheme.brand,
1517
+ "--as-brand-soft": resolvedTheme.brandSoft,
1518
+ "--as-brand-deep": resolvedTheme.brandDeep,
1519
+ "--as-surface": resolvedTheme.surface,
1520
+ "--as-surface-muted": resolvedTheme.surfaceMuted,
1521
+ "--as-text": resolvedTheme.text,
1522
+ "--as-text-muted": resolvedTheme.textMuted,
1523
+ "--as-text-subtle": resolvedTheme.textSubtle,
1524
+ "--as-border": resolvedTheme.border,
1525
+ "--as-visitor-bubble": resolvedTheme.visitorBubble,
1526
+ "--as-visitor-text": resolvedTheme.visitorText,
1527
+ "--as-success": resolvedTheme.success,
1528
+ "--as-danger": resolvedTheme.danger,
1529
+ "--as-font-body": resolvedTheme.fontBody,
1530
+ "--as-font-display": resolvedTheme.fontDisplay
1531
+ };
1367
1532
  const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming";
1368
- const showActivity = state.toolSteps.length > 0 && (state.phase === "thinking" || state.phase === "running-tools");
1369
- const hasVisitorMessages2 = state.messages.some((message) => message.role === "visitor");
1533
+ const showActivity = state.toolSteps.length > 0;
1534
+ const hasVisitorMessages2 = state.messages.some(
1535
+ (message) => message.role === "visitor"
1536
+ );
1370
1537
  const showIdleFollowUps = !hasVisitorMessages2 && state.followUps.length > 0;
1371
1538
  const showDockFollowUps = expanded && showIdleFollowUps;
1372
1539
  const streamingMessage = state.phase === "streaming" && state.streamingText ? {
@@ -1380,42 +1547,73 @@ function AgentRail({
1380
1547
  const node = transcriptRef.current;
1381
1548
  if (!node) return;
1382
1549
  node.scrollTop = node.scrollHeight;
1383
- }, [state.messages, state.toolSteps, state.streamingText, state.followUps, state.journey]);
1384
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1550
+ }, [
1551
+ state.messages,
1552
+ state.toolSteps,
1553
+ state.streamingText,
1554
+ state.followUps,
1555
+ state.journey
1556
+ ]);
1557
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1385
1558
  "aside",
1386
1559
  {
1387
1560
  className: `agent-rail${mobileFullscreen ? " agent-rail--mobile-fullscreen" : ""}${expanded ? " agent-rail--expanded" : ""}`,
1388
1561
  style: railStyle,
1389
1562
  "aria-label": "Agent conversation",
1390
1563
  children: [
1391
- /* @__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: [
1392
- onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1564
+ /* @__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: [
1565
+ onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1393
1566
  "button",
1394
1567
  {
1395
1568
  type: "button",
1396
1569
  className: "agent-rail__collapse",
1397
1570
  "aria-label": "Collapse assist",
1398
1571
  onClick: onCollapse,
1399
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MinimizeIcon, {})
1572
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MinimizeIcon, {})
1573
+ }
1574
+ ) : onClose ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1575
+ "button",
1576
+ {
1577
+ type: "button",
1578
+ className: "agent-rail__close",
1579
+ "aria-label": "Close agent",
1580
+ onClick: onClose,
1581
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MinimizeIcon, {})
1400
1582
  }
1401
- ) : 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" }),
1402
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-label", children: brandLabel }),
1403
- onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1583
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
1584
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "agent-rail__identity", children: [
1585
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "agent-rail__brand-mark", "aria-hidden": "true", children: [
1586
+ brandLabel.slice(0, 1).toUpperCase(),
1587
+ brandLogoUrl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1588
+ "img",
1589
+ {
1590
+ className: "agent-rail__brand-logo",
1591
+ src: brandLogoUrl,
1592
+ alt: "",
1593
+ onError: (event) => {
1594
+ event.currentTarget.hidden = true;
1595
+ }
1596
+ }
1597
+ ) : null
1598
+ ] }),
1599
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-label", children: brandLabel })
1600
+ ] }),
1601
+ onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1404
1602
  "button",
1405
1603
  {
1406
1604
  type: "button",
1407
1605
  className: "agent-rail__expand",
1408
1606
  "aria-label": expanded ? "Restore assist panel" : "Expand assist panel",
1409
1607
  onClick: onExpandToggle,
1410
- children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpandIcon, {})
1608
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpandIcon, {})
1411
1609
  }
1412
- ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" })
1610
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" })
1413
1611
  ] }) }),
1414
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: [
1415
- state.messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message }, message.id)),
1416
- streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message: streamingMessage }) : null,
1417
- showActivity ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AgentActivityBubble, { steps: state.toolSteps }) : null,
1418
- !expanded && showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1612
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: [
1613
+ state.messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MessageBubble, { message }, message.id)),
1614
+ streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MessageBubble, { message: streamingMessage }) : null,
1615
+ showActivity ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AgentActivityBubble, { steps: state.toolSteps }) : null,
1616
+ !expanded && showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1419
1617
  FollowUpChips,
1420
1618
  {
1421
1619
  suggestions: state.followUps,
@@ -1424,10 +1622,17 @@ function AgentRail({
1424
1622
  onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
1425
1623
  }
1426
1624
  ) }) : null,
1427
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "alert", style: { fontSize: 13, color: "var(--as-danger)", margin: 0 }, children: state.error }) : null
1625
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1626
+ "p",
1627
+ {
1628
+ role: "alert",
1629
+ style: { fontSize: 13, color: "var(--as-danger)", margin: 0 },
1630
+ children: state.error
1631
+ }
1632
+ ) : null
1428
1633
  ] }),
1429
- expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__dock-wrap", children: [
1430
- showDockFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__dock-followups", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1634
+ expanded ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__dock-wrap", children: [
1635
+ showDockFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__dock-followups", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1431
1636
  FollowUpChips,
1432
1637
  {
1433
1638
  variant: "dock",
@@ -1436,7 +1641,7 @@ function AgentRail({
1436
1641
  onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
1437
1642
  }
1438
1643
  ) }) : null,
1439
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__dock", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1644
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__dock", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1440
1645
  Composer,
1441
1646
  {
1442
1647
  variant: "dock",
@@ -1445,12 +1650,12 @@ function AgentRail({
1445
1650
  onSubmit
1446
1651
  }
1447
1652
  ) }),
1448
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__footer", children: [
1449
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1450
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1653
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__footer", children: [
1654
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1655
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1451
1656
  ] })
1452
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
1453
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1657
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
1658
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1454
1659
  Composer,
1455
1660
  {
1456
1661
  disabled: isBusy,
@@ -1458,9 +1663,9 @@ function AgentRail({
1458
1663
  onSubmit
1459
1664
  }
1460
1665
  ),
1461
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__footer", children: [
1462
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1463
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1666
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__footer", children: [
1667
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1668
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1464
1669
  ] })
1465
1670
  ] })
1466
1671
  ]
@@ -1469,22 +1674,67 @@ function AgentRail({
1469
1674
  }
1470
1675
 
1471
1676
  // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
1472
- var import_jsx_runtime7 = require("react/jsx-runtime");
1677
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1473
1678
  function SparklesIcon() {
1474
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { className: "assist-edge-tab__sparkles", viewBox: "0 0 18 16", fill: "none", "aria-hidden": "true", children: [
1475
- /* @__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" }),
1476
- /* @__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" }),
1477
- /* @__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" })
1478
- ] });
1679
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1680
+ "svg",
1681
+ {
1682
+ className: "assist-edge-tab__sparkles",
1683
+ viewBox: "0 0 18 16",
1684
+ fill: "none",
1685
+ "aria-hidden": "true",
1686
+ children: [
1687
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1688
+ "path",
1689
+ {
1690
+ 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",
1691
+ fill: "currentColor"
1692
+ }
1693
+ ),
1694
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1695
+ "path",
1696
+ {
1697
+ 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",
1698
+ fill: "currentColor"
1699
+ }
1700
+ ),
1701
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1702
+ "path",
1703
+ {
1704
+ 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",
1705
+ fill: "currentColor"
1706
+ }
1707
+ )
1708
+ ]
1709
+ }
1710
+ );
1479
1711
  }
1480
1712
  function ChevronLeftIcon() {
1481
- 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" }) });
1713
+ 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)(
1714
+ "path",
1715
+ {
1716
+ d: "M10 4L6 8l4 4",
1717
+ stroke: "currentColor",
1718
+ strokeWidth: "1.6",
1719
+ strokeLinecap: "round",
1720
+ strokeLinejoin: "round"
1721
+ }
1722
+ ) });
1482
1723
  }
1483
1724
  function ChevronDownIcon() {
1484
- 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" }) });
1725
+ 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)(
1726
+ "path",
1727
+ {
1728
+ d: "M4 6l4 4 4-4",
1729
+ stroke: "currentColor",
1730
+ strokeWidth: "1.6",
1731
+ strokeLinecap: "round",
1732
+ strokeLinejoin: "round"
1733
+ }
1734
+ ) });
1485
1735
  }
1486
1736
  function DragDots() {
1487
- 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)) });
1737
+ 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)) });
1488
1738
  }
1489
1739
  var VARIANT_COPY = {
1490
1740
  outline: { label: "Assist", aria: "Open Assist" },
@@ -1497,38 +1747,71 @@ function AssistEdgeTab({
1497
1747
  along,
1498
1748
  inset,
1499
1749
  visible,
1750
+ label,
1751
+ logoUrl,
1752
+ brandColor,
1753
+ fontFamily,
1500
1754
  onOpen
1501
1755
  }) {
1502
1756
  const copy = VARIANT_COPY[variant];
1757
+ const visibleLabel = label?.trim() || copy.label;
1503
1758
  const style = {
1504
1759
  "--tab-along": `${along}%`,
1505
- "--tab-inset": `${inset}px`
1760
+ "--tab-inset": `${inset}px`,
1761
+ ...brandColor ? { "--as-brand": brandColor } : {},
1762
+ ...fontFamily ? { "--as-font-display": fontFamily } : {}
1506
1763
  };
1507
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1764
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1508
1765
  "button",
1509
1766
  {
1510
1767
  type: "button",
1511
1768
  className: `assist-edge-tab assist-edge-tab--${variant} assist-edge-tab--${side}${visible ? " is-visible" : ""}`,
1512
1769
  style,
1513
- "aria-label": copy.aria,
1770
+ "aria-label": `Open ${visibleLabel}`,
1514
1771
  "aria-hidden": !visible,
1515
1772
  tabIndex: visible ? 0 : -1,
1516
1773
  onClick: onOpen,
1517
1774
  children: [
1518
- variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1519
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {}),
1520
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
1521
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronDownIcon, {})
1775
+ variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1776
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
1777
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparklesIcon, {}),
1778
+ logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1779
+ "img",
1780
+ {
1781
+ className: "assist-edge-tab__logo",
1782
+ src: logoUrl,
1783
+ alt: "",
1784
+ onError: (event) => {
1785
+ event.currentTarget.hidden = true;
1786
+ }
1787
+ }
1788
+ ) : null
1789
+ ] }),
1790
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1791
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronDownIcon, {})
1522
1792
  ] }) : null,
1523
- variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1524
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {}),
1525
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
1526
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DragDots, {})
1793
+ variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1794
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronLeftIcon, {}),
1795
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1796
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DragDots, {})
1527
1797
  ] }) : null,
1528
- variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1529
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {}),
1530
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
1531
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {})
1798
+ variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1799
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
1800
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparklesIcon, {}),
1801
+ logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1802
+ "img",
1803
+ {
1804
+ className: "assist-edge-tab__logo",
1805
+ src: logoUrl,
1806
+ alt: "",
1807
+ onError: (event) => {
1808
+ event.currentTarget.hidden = true;
1809
+ }
1810
+ }
1811
+ ) : null
1812
+ ] }),
1813
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1814
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronLeftIcon, {})
1532
1815
  ] }) : null
1533
1816
  ]
1534
1817
  }
@@ -1536,7 +1819,7 @@ function AssistEdgeTab({
1536
1819
  }
1537
1820
 
1538
1821
  // src/react/components/AgentWidget/AgentWidget.tsx
1539
- var import_jsx_runtime8 = require("react/jsx-runtime");
1822
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1540
1823
  function AgentWidget({
1541
1824
  indexId,
1542
1825
  customerId,
@@ -1546,7 +1829,8 @@ function AgentWidget({
1546
1829
  placement: placementInput,
1547
1830
  defaultCollapsed = true,
1548
1831
  pageShift = true,
1549
- registerPanelController = false
1832
+ registerPanelController = false,
1833
+ branding
1550
1834
  }) {
1551
1835
  const isMobile = useIsMobile();
1552
1836
  const placement = normalizeAgentPlacement(placementInput);
@@ -1568,8 +1852,27 @@ function AgentWidget({
1568
1852
  getUnpublishedPreviewGrant,
1569
1853
  indexId,
1570
1854
  version,
1571
- runtimeOrigin
1855
+ runtimeOrigin,
1856
+ greeting: branding?.greeting
1572
1857
  });
1858
+ const agentName = branding?.agentName ?? "Webless Guide";
1859
+ const theme = {
1860
+ ...branding?.fontFamily ? { fontBody: branding.fontFamily, fontDisplay: branding.fontFamily } : {},
1861
+ ...branding?.colors?.primary ? {
1862
+ brand: branding.colors.primary,
1863
+ visitorBubble: branding.colors.primary
1864
+ } : {},
1865
+ ...branding?.colors?.primarySoft ? { brandSoft: branding.colors.primarySoft } : {},
1866
+ ...branding?.colors?.primaryForeground ? { visitorText: branding.colors.primaryForeground } : {},
1867
+ ...branding?.colors?.surface ? { surface: branding.colors.surface } : {},
1868
+ ...branding?.colors?.surfaceMuted ? { surfaceMuted: branding.colors.surfaceMuted } : {},
1869
+ ...branding?.colors?.text ? { text: branding.colors.text } : {},
1870
+ ...branding?.colors?.textMuted ? {
1871
+ textMuted: branding.colors.textMuted,
1872
+ textSubtle: branding.colors.textMuted
1873
+ } : {},
1874
+ ...branding?.colors?.border ? { border: branding.colors.border } : {}
1875
+ };
1573
1876
  const idle = state.phase === "idle" && !hasVisitorMessages(state.messages);
1574
1877
  (0, import_react6.useEffect)(() => {
1575
1878
  if (!registerPanelController) return;
@@ -1586,48 +1889,56 @@ function AgentWidget({
1586
1889
  if (isMobile) setRailCollapsed(false);
1587
1890
  await submit(message);
1588
1891
  }
1589
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "webless-agent-root", children: [
1590
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1892
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "webless-agent-root", children: [
1893
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1591
1894
  "div",
1592
1895
  {
1593
1896
  className: `webless-agent-root__shell${railCollapsed ? " webless-agent-root__shell--collapsed" : ""}${railExpanded ? " webless-agent-root__shell--expanded" : ""}`,
1594
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1595
- "div",
1596
- {
1597
- ref: railSlotRef,
1598
- className: "webless-agent-root__rail-slot",
1599
- inert: railCollapsed || void 0,
1600
- "aria-hidden": railCollapsed,
1601
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1602
- AgentRail,
1603
- {
1604
- state: idle ? {
1605
- ...state,
1606
- followUps: createIdleSuggestions()
1607
- } : state,
1608
- mobileFullscreen: isMobile && !railCollapsed,
1609
- expanded: railExpanded,
1610
- onCollapse: !isMobile ? () => setRailCollapsed(true) : void 0,
1611
- onClose: isMobile ? () => setRailCollapsed(true) : void 0,
1612
- onExpandToggle: !isMobile ? () => setRailExpanded((current) => !current) : void 0,
1613
- onSubmit: handleSubmit,
1614
- onFollowUpSelect: (label) => void handleSubmit(label)
1615
- }
1616
- )
1617
- }
1618
- )
1897
+ children: [
1898
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1899
+ "div",
1900
+ {
1901
+ ref: railSlotRef,
1902
+ className: "webless-agent-root__rail-slot",
1903
+ inert: railCollapsed || void 0,
1904
+ "aria-hidden": railCollapsed,
1905
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1906
+ AgentRail,
1907
+ {
1908
+ theme,
1909
+ brandLabel: agentName,
1910
+ brandLogoUrl: branding?.logoUrl,
1911
+ composerPlaceholder: branding?.composerPlaceholder ?? `Ask ${agentName}\u2026`,
1912
+ poweredByLabel: branding?.poweredByLabel ?? "Powered by Webless",
1913
+ state: idle ? {
1914
+ ...state,
1915
+ followUps: createIdleSuggestions()
1916
+ } : state,
1917
+ mobileFullscreen: isMobile && !railCollapsed,
1918
+ expanded: railExpanded,
1919
+ onCollapse: !isMobile ? () => setRailCollapsed(true) : void 0,
1920
+ onClose: isMobile ? () => setRailCollapsed(true) : void 0,
1921
+ onExpandToggle: !isMobile ? () => setRailExpanded((current) => !current) : void 0,
1922
+ onSubmit: handleSubmit,
1923
+ onFollowUpSelect: (label) => void handleSubmit(label)
1924
+ }
1925
+ )
1926
+ }
1927
+ ),
1928
+ !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1929
+ "button",
1930
+ {
1931
+ type: "button",
1932
+ className: "webless-agent-root__backdrop",
1933
+ tabIndex: -1,
1934
+ "aria-label": "Close expanded assist",
1935
+ onClick: () => setRailExpanded(false)
1936
+ }
1937
+ ) : null
1938
+ ]
1619
1939
  }
1620
1940
  ),
1621
- !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1622
- "button",
1623
- {
1624
- type: "button",
1625
- className: "webless-agent-root__backdrop",
1626
- "aria-label": "Close expanded assist",
1627
- onClick: () => setRailExpanded(false)
1628
- }
1629
- ) : null,
1630
- railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1941
+ railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1631
1942
  AssistEdgeTab,
1632
1943
  {
1633
1944
  variant: placement.variant,
@@ -1635,6 +1946,10 @@ function AgentWidget({
1635
1946
  along: placement.along,
1636
1947
  inset: placement.inset,
1637
1948
  visible: true,
1949
+ label: agentName,
1950
+ logoUrl: branding?.logoUrl,
1951
+ brandColor: branding?.colors?.primary,
1952
+ fontFamily: branding?.fontFamily,
1638
1953
  onOpen: () => setRailCollapsed(false)
1639
1954
  }
1640
1955
  ) : null
@@ -1642,9 +1957,11 @@ function AgentWidget({
1642
1957
  }
1643
1958
 
1644
1959
  // src/embed/AgentWidget.tsx
1645
- var import_jsx_runtime9 = require("react/jsx-runtime");
1646
- function AgentWidget2({ manifest }) {
1647
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1960
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1961
+ function AgentWidget2({
1962
+ manifest
1963
+ }) {
1964
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1648
1965
  AgentWidget,
1649
1966
  {
1650
1967
  indexId: manifest.indexId,
@@ -1653,6 +1970,7 @@ function AgentWidget2({ manifest }) {
1653
1970
  runtimeOrigin: manifest.runtimeOrigin,
1654
1971
  placement: manifest.placement,
1655
1972
  pageShift: manifest.pageShift,
1973
+ branding: manifest.branding,
1656
1974
  defaultCollapsed: true,
1657
1975
  registerPanelController: true
1658
1976
  }
@@ -1678,6 +1996,7 @@ function normalizeAgentTagManifest(manifest) {
1678
1996
  version,
1679
1997
  runtimeOrigin: manifest.runtimeOrigin?.trim() || DEFAULT_RUNTIME_ORIGIN
1680
1998
  });
1999
+ const branding = normalizeAgentBranding(manifest.branding);
1681
2000
  return {
1682
2001
  customerId,
1683
2002
  indexId,
@@ -1688,12 +2007,36 @@ function normalizeAgentTagManifest(manifest) {
1688
2007
  strategy: manifest.mount?.strategy ?? "body"
1689
2008
  },
1690
2009
  placement: normalizeAgentPlacement(manifest.placement),
1691
- pageShift: manifest.pageShift ?? true
2010
+ pageShift: manifest.pageShift ?? true,
2011
+ ...branding ? { branding } : {}
1692
2012
  };
1693
2013
  }
2014
+ function normalizeOptionalValue(value) {
2015
+ const normalized = value?.trim();
2016
+ return normalized || void 0;
2017
+ }
2018
+ function normalizeAgentBranding(branding) {
2019
+ if (!branding) return void 0;
2020
+ const colors = branding.colors ? Object.fromEntries(
2021
+ Object.entries(branding.colors).flatMap(([key, value]) => {
2022
+ const normalized2 = normalizeOptionalValue(value);
2023
+ return normalized2 ? [[key, normalized2]] : [];
2024
+ })
2025
+ ) : void 0;
2026
+ const normalized = {
2027
+ agentName: normalizeOptionalValue(branding.agentName),
2028
+ logoUrl: normalizeOptionalValue(branding.logoUrl),
2029
+ greeting: normalizeOptionalValue(branding.greeting),
2030
+ composerPlaceholder: normalizeOptionalValue(branding.composerPlaceholder),
2031
+ poweredByLabel: normalizeOptionalValue(branding.poweredByLabel),
2032
+ fontFamily: normalizeOptionalValue(branding.fontFamily),
2033
+ colors: colors && Object.keys(colors).length > 0 ? colors : void 0
2034
+ };
2035
+ return Object.values(normalized).some((value) => value !== void 0) ? normalized : void 0;
2036
+ }
1694
2037
 
1695
2038
  // src/embed/mount.tsx
1696
- var import_jsx_runtime10 = require("react/jsx-runtime");
2039
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1697
2040
  var mountedHandles = /* @__PURE__ */ new Map();
1698
2041
  var latestCustomerId = null;
1699
2042
  function resolveMountHost(manifest, script) {
@@ -1723,7 +2066,7 @@ function mountAgent(input) {
1723
2066
  const host = createHost(manifest.customerId);
1724
2067
  mountTarget.append(host);
1725
2068
  const root = (0, import_client5.createRoot)(host);
1726
- root.render(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AgentWidget2, { manifest }));
2069
+ root.render(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentWidget2, { manifest }));
1727
2070
  const handle = {
1728
2071
  customerId: manifest.customerId,
1729
2072
  manifest,