@webless/agent 0.2.15 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.cjs CHANGED
@@ -335,9 +335,8 @@ function clearPersistedAgentSession(visitorSessionId, options) {
335
335
  function isTurnBoundary(event) {
336
336
  return event.type === "session.waiting" || event.type === "session.completed" || event.type === "session.failed";
337
337
  }
338
- function applyMessageEvent(event, rendered, handlers) {
339
- const step = mapStepLabel(event);
340
- if (step) handlers.onStep?.(step.label, step.detail);
338
+ function applyMessageEvent(event, rendered, handlers, workItems) {
339
+ applyWorkEvent(event, handlers, workItems);
341
340
  if (event.type === "session.failed") {
342
341
  throw new Error(event.data.message || event.data.code);
343
342
  }
@@ -380,13 +379,120 @@ function renderTurn(events) {
380
379
  }
381
380
  return rendered;
382
381
  }
383
- function mapStepLabel(event) {
384
- if (event.type !== "step.started") return null;
385
- const stepIndex = event.data.stepIndex;
386
- return {
387
- label: "Model step running",
388
- detail: typeof stepIndex === "number" ? `Step ${stepIndex + 1}` : void 0
389
- };
382
+ function emitWorkItem(item, handlers, workItems) {
383
+ workItems.set(item.id, item);
384
+ handlers.onWork?.(item);
385
+ handlers.onStep?.(item.label, item.detail);
386
+ }
387
+ function completePlanning(handlers, workItems) {
388
+ const planning = workItems.get("planning");
389
+ if (!planning || planning.state !== "active") return;
390
+ emitWorkItem(
391
+ {
392
+ ...planning,
393
+ detail: "Picked the best way to help",
394
+ state: "completed"
395
+ },
396
+ handlers,
397
+ workItems
398
+ );
399
+ }
400
+ function specialistNameFromInput(input) {
401
+ const message = input.message;
402
+ if (typeof message !== "string") return void 0;
403
+ const match = /^Webless-Agent-Name:\s*(.+)$/imu.exec(message);
404
+ return match?.[1]?.trim() || void 0;
405
+ }
406
+ function requestedWorkItem(action) {
407
+ if (action.kind === "tool-call" && action.toolName === "search_discovery") {
408
+ return {
409
+ id: action.callId,
410
+ kind: "search",
411
+ label: "Search & Discovery",
412
+ detail: "Searching this site",
413
+ state: "active"
414
+ };
415
+ }
416
+ if (action.kind === "subagent-call" || action.kind === "remote-agent-call" || action.kind === "tool-call" && action.toolName === "agent") {
417
+ const name = specialistNameFromInput(action.input) ?? "Specialist";
418
+ return {
419
+ id: action.callId,
420
+ kind: "specialist",
421
+ label: name,
422
+ detail: "Reviewing your question",
423
+ state: "active"
424
+ };
425
+ }
426
+ return null;
427
+ }
428
+ function applyWorkEvent(event, handlers, workItems) {
429
+ if (event.type === "step.started" && workItems.size === 0) {
430
+ emitWorkItem(
431
+ {
432
+ id: "planning",
433
+ kind: "planning",
434
+ label: "Understanding your question",
435
+ state: "active"
436
+ },
437
+ handlers,
438
+ workItems
439
+ );
440
+ return;
441
+ }
442
+ if (event.type === "actions.requested") {
443
+ completePlanning(handlers, workItems);
444
+ for (const action of event.data.actions) {
445
+ const item = requestedWorkItem(action);
446
+ if (item) emitWorkItem(item, handlers, workItems);
447
+ }
448
+ return;
449
+ }
450
+ if (event.type === "subagent.called") {
451
+ completePlanning(handlers, workItems);
452
+ const current2 = workItems.get(event.data.callId);
453
+ if (!current2) {
454
+ emitWorkItem(
455
+ {
456
+ id: event.data.callId,
457
+ kind: "specialist",
458
+ label: event.data.name || "Specialist",
459
+ detail: "Reviewing your question",
460
+ state: "active"
461
+ },
462
+ handlers,
463
+ workItems
464
+ );
465
+ }
466
+ return;
467
+ }
468
+ if (event.type === "subagent.completed") {
469
+ const current2 = workItems.get(event.data.callId);
470
+ if (!current2) return;
471
+ emitWorkItem(
472
+ {
473
+ ...current2,
474
+ detail: "Guidance received",
475
+ state: "completed"
476
+ },
477
+ handlers,
478
+ workItems
479
+ );
480
+ return;
481
+ }
482
+ if (event.type !== "action.result") return;
483
+ const { result, status } = event.data;
484
+ const current = workItems.get(result.callId);
485
+ if (!current) return;
486
+ const failed = status !== "completed" || result.isError === true;
487
+ emitWorkItem(
488
+ {
489
+ ...current,
490
+ detail: failed ? "Couldn\u2019t complete; continuing with available information" : current.kind === "search" ? "Found relevant site content" : "Guidance received",
491
+ state: failed ? "error" : "completed"
492
+ },
493
+ handlers,
494
+ workItems
495
+ );
390
496
  }
391
497
  var AgentSession = class {
392
498
  constructor(indexId, version, runtimeOrigin, visitorSessionId, storeOptions, getUnpublishedPreviewGrant) {
@@ -504,10 +610,11 @@ var AgentSession = class {
504
610
  this.activeResponse = response;
505
611
  let streamIndex = session?.state.streamIndex ?? 0;
506
612
  let rendered = "";
613
+ const workItems = /* @__PURE__ */ new Map();
507
614
  try {
508
615
  for await (const event of response) {
509
616
  if (signal.aborted) break;
510
- rendered = applyMessageEvent(event, rendered, handlers);
617
+ rendered = applyMessageEvent(event, rendered, handlers, workItems);
511
618
  streamIndex += 1;
512
619
  if (session) {
513
620
  savePersistedAgentSession(
@@ -549,6 +656,10 @@ var AgentSession = class {
549
656
  return null;
550
657
  }
551
658
  let rendered = renderTurn(turnEvents);
659
+ const workItems = /* @__PURE__ */ new Map();
660
+ for (const event of turnEvents) {
661
+ applyWorkEvent(event, handlers, workItems);
662
+ }
552
663
  if (rendered.startsWith(initialText)) {
553
664
  const missedText = rendered.slice(initialText.length);
554
665
  if (missedText) handlers.onDelta(missedText);
@@ -583,7 +694,7 @@ var AgentSession = class {
583
694
  let streamIndex = snapshot.session.streamIndex;
584
695
  for await (const event of session.stream({ signal })) {
585
696
  if (signal.aborted) break;
586
- rendered = applyMessageEvent(event, rendered, handlers);
697
+ rendered = applyMessageEvent(event, rendered, handlers, workItems);
587
698
  streamIndex += 1;
588
699
  savePersistedAgentSession(
589
700
  this.visitorSessionId,
@@ -736,57 +847,54 @@ function clearPersistedAgentConversation(storageKeyPrefix, visitorSessionId) {
736
847
  }
737
848
 
738
849
  // src/react/hooks/useAgentChat.ts
739
- var GREETING_MESSAGE = {
740
- id: "greeting",
741
- role: "agent",
742
- text: "Hi! I'm connected to the Webless Agent Runtime. Ask anything about your published site index.",
743
- createdAt: 0
744
- };
745
- var INITIAL_STATE = {
746
- phase: "idle",
747
- messages: [GREETING_MESSAGE],
748
- toolSteps: [],
749
- journey: null,
750
- followUps: [],
751
- streamingText: "",
752
- error: null
753
- };
754
- function stateFromConversation(conversation) {
755
- if (!conversation || conversation.messages.length === 0) return INITIAL_STATE;
850
+ var DEFAULT_GREETING = "Hi! I can search this site or bring in a specialist when it helps. What would you like to know?";
851
+ function createInitialState(greeting = DEFAULT_GREETING) {
852
+ return {
853
+ phase: "idle",
854
+ messages: [
855
+ {
856
+ id: "greeting",
857
+ role: "agent",
858
+ text: greeting,
859
+ createdAt: 0
860
+ }
861
+ ],
862
+ toolSteps: [],
863
+ journey: null,
864
+ followUps: [],
865
+ streamingText: "",
866
+ error: null
867
+ };
868
+ }
869
+ function stateFromConversation(conversation, initialState) {
870
+ if (!conversation || conversation.messages.length === 0) return initialState;
756
871
  return {
757
- ...INITIAL_STATE,
872
+ ...initialState,
758
873
  messages: conversation.messages,
759
874
  phase: conversation.pending ? conversation.streamingText ? "streaming" : "thinking" : "complete",
760
875
  streamingText: conversation.streamingText
761
876
  };
762
877
  }
763
- var STATUS_SEQUENCE = [
764
- { id: "s1", label: "Starting Eve session", ms: 400 },
765
- { id: "s2", label: "Connecting to runtime", ms: 500 }
766
- ];
767
- function delay(ms, signal) {
768
- return new Promise((resolve, reject) => {
769
- const timer = window.setTimeout(resolve, ms);
770
- signal.addEventListener(
771
- "abort",
772
- () => {
773
- window.clearTimeout(timer);
774
- reject(new DOMException("Aborted", "AbortError"));
775
- },
776
- { once: true }
777
- );
778
- });
779
- }
780
- async function runStatusSequence(signal, onStep) {
781
- for (const item of STATUS_SEQUENCE) {
782
- onStep({
783
- id: item.id,
784
- label: item.label,
785
- detail: item.detail,
786
- state: "active"
787
- });
788
- await delay(item.ms, signal);
789
- }
878
+ function upsertToolStep(steps, item) {
879
+ const next = {
880
+ id: item.id,
881
+ kind: item.kind,
882
+ label: item.label,
883
+ state: item.state,
884
+ ...item.detail ? { detail: item.detail } : {}
885
+ };
886
+ const index = steps.findIndex((step) => step.id === item.id);
887
+ if (index < 0) return [...steps, next];
888
+ return steps.map((step, stepIndex) => stepIndex === index ? next : step);
889
+ }
890
+ function completeActivePlanning(steps) {
891
+ return steps.map(
892
+ (step) => step.kind === "planning" && step.state === "active" ? {
893
+ ...step,
894
+ detail: "Prepared a response",
895
+ state: "completed"
896
+ } : step
897
+ );
790
898
  }
791
899
  function useAgentChat({
792
900
  customerId,
@@ -795,8 +903,13 @@ function useAgentChat({
795
903
  version,
796
904
  runtimeOrigin,
797
905
  visitorSessionId,
798
- storageKeyPrefix
906
+ storageKeyPrefix,
907
+ greeting
799
908
  }) {
909
+ const initialState = (0, import_react2.useMemo)(
910
+ () => createInitialState(greeting?.trim() || DEFAULT_GREETING),
911
+ [greeting]
912
+ );
800
913
  const previewGrantProviderRef = (0, import_react2.useRef)(getUnpublishedPreviewGrant);
801
914
  previewGrantProviderRef.current = getUnpublishedPreviewGrant;
802
915
  const resolveUnpublishedPreviewGrant = () => {
@@ -827,7 +940,8 @@ function useAgentChat({
827
940
  );
828
941
  const [state, setState] = (0, import_react2.useState)(
829
942
  () => stateFromConversation(
830
- loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
943
+ loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
944
+ initialState
831
945
  )
832
946
  );
833
947
  const runRef = (0, import_react2.useRef)(null);
@@ -842,7 +956,7 @@ function useAgentChat({
842
956
  storageKeyPrefix: resolvedStorageKeyPrefix
843
957
  })
844
958
  );
845
- const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}`;
959
+ const identityKey = `${customerId ?? ""}|${indexId}|${version ?? "published"}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}|${greeting ?? ""}`;
846
960
  const identityRef = (0, import_react2.useRef)(identityKey);
847
961
  (0, import_react2.useEffect)(() => {
848
962
  if (identityRef.current === identityKey) {
@@ -862,13 +976,15 @@ function useAgentChat({
862
976
  });
863
977
  setState(
864
978
  stateFromConversation(
865
- loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId)
979
+ loadPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId),
980
+ initialState
866
981
  )
867
982
  );
868
983
  }, [
869
984
  customerId,
870
985
  identityKey,
871
986
  indexId,
987
+ initialState,
872
988
  runtimeOrigin,
873
989
  resolvedStorageKeyPrefix,
874
990
  version,
@@ -893,8 +1009,8 @@ function useAgentChat({
893
1009
  runRef.current = null;
894
1010
  clientRef.current.reset();
895
1011
  clearPersistedAgentConversation(resolvedStorageKeyPrefix, visitorId);
896
- setState(INITIAL_STATE);
897
- }, [resolvedStorageKeyPrefix, visitorId]);
1012
+ setState(initialState);
1013
+ }, [initialState, resolvedStorageKeyPrefix, visitorId]);
898
1014
  const runTurn = (0, import_react2.useCallback)(
899
1015
  async (input) => {
900
1016
  const { controller, initialText = "", resume, visitorText } = input;
@@ -903,35 +1019,23 @@ function useAgentChat({
903
1019
  try {
904
1020
  let streamStarted = Boolean(initialText);
905
1021
  let streamed = initialText;
906
- const planningPromise = resume ? Promise.resolve() : runStatusSequence(signal, (step) => {
907
- if (streamStarted || !isActiveRun()) return;
908
- setState((prev) => ({
909
- ...prev,
910
- phase: "running-tools",
911
- toolSteps: [step]
912
- }));
913
- });
914
1022
  const handlers = {
915
- onStep: (label, detail) => {
916
- if (streamStarted || !isActiveRun()) return;
1023
+ onWork: (item) => {
1024
+ if (!isActiveRun()) return;
917
1025
  setState((prev) => ({
918
1026
  ...prev,
919
- phase: "running-tools",
920
- toolSteps: [
921
- { id: `step-${label}`, label, detail, state: "active" }
922
- ]
1027
+ phase: item.state === "active" ? "running-tools" : prev.phase,
1028
+ toolSteps: upsertToolStep(prev.toolSteps, item)
923
1029
  }));
924
1030
  },
925
1031
  onDelta: (delta) => {
926
1032
  if (!isActiveRun()) return;
927
- void planningPromise.catch(() => {
928
- });
929
1033
  if (!streamStarted) {
930
1034
  streamStarted = true;
931
1035
  setState((prev) => ({
932
1036
  ...prev,
933
1037
  phase: "streaming",
934
- toolSteps: [],
1038
+ toolSteps: completeActivePlanning(prev.toolSteps),
935
1039
  streamingText: ""
936
1040
  }));
937
1041
  }
@@ -959,8 +1063,6 @@ function useAgentChat({
959
1063
  signal
960
1064
  });
961
1065
  }
962
- await planningPromise.catch(() => {
963
- });
964
1066
  if (!isActiveRun() || finalText === null) return;
965
1067
  const agentMessage = {
966
1068
  id: `agent-${Date.now()}`,
@@ -972,7 +1074,7 @@ function useAgentChat({
972
1074
  ...prev,
973
1075
  phase: "complete",
974
1076
  messages: [...prev.messages, agentMessage],
975
- toolSteps: [],
1077
+ toolSteps: completeActivePlanning(prev.toolSteps),
976
1078
  streamingText: "",
977
1079
  followUps: [],
978
1080
  journey: null
@@ -987,7 +1089,13 @@ function useAgentChat({
987
1089
  setState((prev) => ({
988
1090
  ...prev,
989
1091
  phase: "complete",
990
- toolSteps: [],
1092
+ toolSteps: prev.toolSteps.map(
1093
+ (step) => step.state === "active" ? {
1094
+ ...step,
1095
+ detail: "Couldn\u2019t complete this step",
1096
+ state: "error"
1097
+ } : step
1098
+ ),
991
1099
  streamingText: "",
992
1100
  error: message
993
1101
  }));
@@ -1015,7 +1123,12 @@ function useAgentChat({
1015
1123
  phase: "thinking",
1016
1124
  messages: [...prev.messages, visitorMessage],
1017
1125
  toolSteps: [
1018
- { id: "s1", label: "Starting Eve session", state: "active" }
1126
+ {
1127
+ id: "planning",
1128
+ kind: "planning",
1129
+ label: "Understanding your question",
1130
+ state: "active"
1131
+ }
1019
1132
  ],
1020
1133
  journey: null,
1021
1134
  followUps: [],
@@ -1122,79 +1235,93 @@ function unregisterAgentPanelController(customerId) {
1122
1235
  // src/react/components/AgentRail/AgentRail.tsx
1123
1236
  var import_react5 = require("react");
1124
1237
 
1125
- // src/react/components/ToolTimeline/ToolTimeline.tsx
1126
- var import_jsx_runtime = require("react/jsx-runtime");
1127
- function SpinnerIcon() {
1128
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className: "agent-status__spinner", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
1129
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "8", cy: "8", r: "6", stroke: "currentColor", strokeWidth: "1.5", strokeOpacity: "0.25" }),
1130
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 8a6 6 0 0 0-6-6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
1131
- ] });
1132
- }
1133
- function getCurrentStep(steps) {
1134
- const active = steps.find((step) => step.state === "active");
1135
- if (active) return active;
1136
- const error = steps.find((step) => step.state === "error");
1137
- if (error) return error;
1138
- const pending = steps.find((step) => step.state === "pending");
1139
- if (pending) return pending;
1140
- return steps.at(-1) ?? null;
1141
- }
1142
- function ToolTimeline({
1143
- steps,
1144
- streamingText,
1145
- showStreaming = false,
1146
- inline = false
1147
- }) {
1148
- if (steps.length === 0 && !(showStreaming && streamingText)) return null;
1149
- const currentStep = getCurrentStep(steps);
1150
- const showStatus = currentStep && currentStep.state !== "completed" && !(showStreaming && streamingText);
1151
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1152
- "div",
1153
- {
1154
- className: `tool-timeline${inline ? " tool-timeline--inline" : ""}`,
1155
- role: "status",
1156
- "aria-live": "polite",
1157
- "aria-label": "Agent progress",
1158
- children: [
1159
- showStatus ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-status", children: [
1160
- 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, {}) }),
1161
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-status__copy", children: [
1162
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__label", children: currentStep.label }),
1163
- currentStep.detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__detail", children: currentStep.detail }) : null
1164
- ] })
1165
- ] }, currentStep.id) : null,
1166
- showStreaming && streamingText ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "tool-timeline__streaming-text", children: [
1167
- streamingText,
1168
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tool-timeline__cursor", "aria-hidden": "true" })
1169
- ] }) : null
1170
- ]
1171
- }
1172
- );
1173
- }
1238
+ // src/react/types/conversation.ts
1239
+ var defaultAgentRailTheme = {
1240
+ railMaxWidth: "450px",
1241
+ brand: "#6f16ff",
1242
+ brandSoft: "#f3edff",
1243
+ brandDeep: "#12043e",
1244
+ surface: "#ffffff",
1245
+ surfaceMuted: "#f4f6fb",
1246
+ text: "#171b2a",
1247
+ textMuted: "#5a6378",
1248
+ textSubtle: "#8a94a8",
1249
+ border: "rgb(42 51 70 / 0.1)",
1250
+ visitorBubble: "#6f16ff",
1251
+ visitorText: "#ffffff",
1252
+ success: "#18794e",
1253
+ danger: "#c94b63",
1254
+ fontBody: '"Mulish", "Avenir Next", "Segoe UI", sans-serif',
1255
+ fontDisplay: '"Space Grotesk", sans-serif'
1256
+ };
1174
1257
 
1175
1258
  // src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
1176
- var import_jsx_runtime2 = require("react/jsx-runtime");
1177
- function AgentActivityBubble({
1178
- steps,
1179
- streamingText,
1180
- showStreaming = false
1181
- }) {
1182
- 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)(
1183
- ToolTimeline,
1184
- {
1185
- steps,
1186
- streamingText,
1187
- showStreaming,
1188
- inline: true
1189
- }
1190
- ) }) });
1259
+ var import_jsx_runtime = require("react/jsx-runtime");
1260
+ function workSummary(steps) {
1261
+ const active = [...steps].reverse().find((step) => step.state === "active");
1262
+ if (active?.kind === "specialist") return `Working with ${active.label}`;
1263
+ if (active?.kind === "search") return "Searching this site";
1264
+ if (active) return active.label;
1265
+ const hasError = steps.some((step) => step.state === "error");
1266
+ const specialists = steps.filter(
1267
+ (step) => step.kind === "specialist" && step.state === "completed"
1268
+ );
1269
+ const searched = steps.some(
1270
+ (step) => step.kind === "search" && step.state === "completed"
1271
+ );
1272
+ if (hasError) return "Answered with available information";
1273
+ if (specialists.length > 1)
1274
+ return `Consulted ${specialists.length} specialists`;
1275
+ if (specialists.length === 1) return `Consulted ${specialists[0]?.label}`;
1276
+ if (searched) return "Searched this site";
1277
+ return "Prepared a response";
1278
+ }
1279
+ function AgentActivityBubble({ steps }) {
1280
+ const active = steps.some((step) => step.state === "active");
1281
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("article", { className: "agent-activity-bubble", children: [
1282
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "agent-activity-bubble__status", "aria-live": "polite", children: [
1283
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1284
+ "span",
1285
+ {
1286
+ className: `agent-activity-bubble__pulse${active ? " is-active" : ""}`,
1287
+ "aria-hidden": "true"
1288
+ }
1289
+ ),
1290
+ workSummary(steps)
1291
+ ] }),
1292
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { className: "agent-activity-bubble__details", open: active, children: [
1293
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: "Work details" }),
1294
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "agent-activity-bubble__steps", children: steps.map((step) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1295
+ "li",
1296
+ {
1297
+ className: "agent-activity-bubble__step",
1298
+ "data-state": step.state,
1299
+ children: [
1300
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1301
+ "span",
1302
+ {
1303
+ className: "agent-activity-bubble__step-icon",
1304
+ "aria-hidden": "true",
1305
+ children: step.state === "completed" ? "\u2713" : step.state === "error" ? "!" : ""
1306
+ }
1307
+ ),
1308
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "agent-activity-bubble__step-copy", children: [
1309
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: step.label }),
1310
+ step.detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: step.detail }) : null
1311
+ ] })
1312
+ ]
1313
+ },
1314
+ step.id
1315
+ )) })
1316
+ ] })
1317
+ ] });
1191
1318
  }
1192
1319
 
1193
1320
  // src/react/components/Composer/Composer.tsx
1194
1321
  var import_react4 = require("react");
1195
- var import_jsx_runtime3 = require("react/jsx-runtime");
1322
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1196
1323
  function SendIcon() {
1197
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M8 12V4M8 4l-3 3M8 4l3 3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
1324
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8 12V4M8 4l-3 3M8 4l3 3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
1198
1325
  }
1199
1326
  function Composer({
1200
1327
  disabled = false,
@@ -1221,8 +1348,8 @@ function Composer({
1221
1348
  submitCurrent();
1222
1349
  }
1223
1350
  }
1224
- 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: [
1225
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1351
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("form", { className: `composer${variant === "dock" ? " composer--dock" : ""}`, onSubmit: handleSubmit, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "composer__field", children: [
1352
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1226
1353
  "textarea",
1227
1354
  {
1228
1355
  ref: inputRef,
@@ -1236,21 +1363,21 @@ function Composer({
1236
1363
  onKeyDown: handleKeyDown
1237
1364
  }
1238
1365
  ),
1239
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1366
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1240
1367
  "button",
1241
1368
  {
1242
1369
  type: "submit",
1243
1370
  className: "composer__send",
1244
1371
  disabled: disabled || !value.trim(),
1245
1372
  "aria-label": "Send message",
1246
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
1373
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SendIcon, {})
1247
1374
  }
1248
1375
  )
1249
1376
  ] }) });
1250
1377
  }
1251
1378
 
1252
1379
  // src/react/components/FollowUpChips/FollowUpChips.tsx
1253
- var import_jsx_runtime4 = require("react/jsx-runtime");
1380
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1254
1381
  function FollowUpChips({
1255
1382
  suggestions,
1256
1383
  disabled = false,
@@ -1260,7 +1387,7 @@ function FollowUpChips({
1260
1387
  }) {
1261
1388
  if (suggestions.length === 0) return null;
1262
1389
  if (variant === "dock") {
1263
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "followups followups--dock", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "followups__scroll", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1390
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "followups followups--dock", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "followups__scroll", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1264
1391
  "button",
1265
1392
  {
1266
1393
  type: "button",
@@ -1272,9 +1399,9 @@ function FollowUpChips({
1272
1399
  suggestion.id
1273
1400
  )) }) });
1274
1401
  }
1275
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "followups", children: [
1276
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "followups__label", children: label }),
1277
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "followups__list", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1402
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "followups", children: [
1403
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "followups__label", children: label }),
1404
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "followups__list", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1278
1405
  "button",
1279
1406
  {
1280
1407
  type: "button",
@@ -1291,12 +1418,12 @@ function FollowUpChips({
1291
1418
  // src/react/components/MessageBubble/MessageBubble.tsx
1292
1419
  var import_streamdown = require("streamdown");
1293
1420
  var import_styles = require("streamdown/styles.css");
1294
- var import_jsx_runtime5 = require("react/jsx-runtime");
1421
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1295
1422
  function MessageBubble({ message }) {
1296
1423
  if (message.role === "visitor") {
1297
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "message-bubble__text", children: message.text }) });
1424
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("article", { className: "message-bubble message-bubble--visitor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "message-bubble__text", children: message.text }) });
1298
1425
  }
1299
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("article", { className: "message-bubble message-bubble--agent", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "message-bubble__text", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1426
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("article", { className: "message-bubble message-bubble--agent", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "message-bubble__text", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1300
1427
  import_streamdown.Streamdown,
1301
1428
  {
1302
1429
  animated: true,
@@ -1313,12 +1440,20 @@ function MessageBubble({ message }) {
1313
1440
  }
1314
1441
 
1315
1442
  // src/react/components/AgentRail/AgentRail.tsx
1316
- var import_jsx_runtime6 = require("react/jsx-runtime");
1443
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1317
1444
  function MinimizeIcon() {
1318
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3.5 8h9", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
1445
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1446
+ "path",
1447
+ {
1448
+ d: "M3.5 8h9",
1449
+ stroke: "currentColor",
1450
+ strokeWidth: "1.7",
1451
+ strokeLinecap: "round"
1452
+ }
1453
+ ) });
1319
1454
  }
1320
1455
  function ExpandIcon() {
1321
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1456
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1322
1457
  "path",
1323
1458
  {
1324
1459
  d: "M6 3.5H3.5V6M10 3.5h2.5V6M10 12.5h2.5V10M6 12.5H3.5V10",
@@ -1330,7 +1465,7 @@ function ExpandIcon() {
1330
1465
  ) });
1331
1466
  }
1332
1467
  function RestoreIcon() {
1333
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1468
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1334
1469
  "path",
1335
1470
  {
1336
1471
  d: "M5.5 5.5H3.5V7.5M10.5 5.5h2V7.5M10.5 10.5h2V8.5M5.5 10.5H3.5V8.5",
@@ -1345,6 +1480,7 @@ function AgentRail({
1345
1480
  state,
1346
1481
  theme,
1347
1482
  brandLabel = "Webless Assist",
1483
+ brandLogoUrl,
1348
1484
  poweredByLabel = "Powered by Webless",
1349
1485
  composerPlaceholder = "Ask anything\u2026",
1350
1486
  mobileFullscreen = false,
@@ -1356,10 +1492,31 @@ function AgentRail({
1356
1492
  onFollowUpSelect
1357
1493
  }) {
1358
1494
  const transcriptRef = (0, import_react5.useRef)(null);
1359
- const railStyle = theme?.railMaxWidth ? { ["--rail-width"]: theme.railMaxWidth, ["--as-rail-max-width"]: theme.railMaxWidth } : void 0;
1495
+ const resolvedTheme = { ...defaultAgentRailTheme, ...theme };
1496
+ const railStyle = {
1497
+ "--rail-width": resolvedTheme.railMaxWidth,
1498
+ "--as-rail-max-width": resolvedTheme.railMaxWidth,
1499
+ "--as-brand": resolvedTheme.brand,
1500
+ "--as-brand-soft": resolvedTheme.brandSoft,
1501
+ "--as-brand-deep": resolvedTheme.brandDeep,
1502
+ "--as-surface": resolvedTheme.surface,
1503
+ "--as-surface-muted": resolvedTheme.surfaceMuted,
1504
+ "--as-text": resolvedTheme.text,
1505
+ "--as-text-muted": resolvedTheme.textMuted,
1506
+ "--as-text-subtle": resolvedTheme.textSubtle,
1507
+ "--as-border": resolvedTheme.border,
1508
+ "--as-visitor-bubble": resolvedTheme.visitorBubble,
1509
+ "--as-visitor-text": resolvedTheme.visitorText,
1510
+ "--as-success": resolvedTheme.success,
1511
+ "--as-danger": resolvedTheme.danger,
1512
+ "--as-font-body": resolvedTheme.fontBody,
1513
+ "--as-font-display": resolvedTheme.fontDisplay
1514
+ };
1360
1515
  const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming";
1361
- const showActivity = state.toolSteps.length > 0 && (state.phase === "thinking" || state.phase === "running-tools");
1362
- const hasVisitorMessages2 = state.messages.some((message) => message.role === "visitor");
1516
+ const showActivity = state.toolSteps.length > 0;
1517
+ const hasVisitorMessages2 = state.messages.some(
1518
+ (message) => message.role === "visitor"
1519
+ );
1363
1520
  const showIdleFollowUps = !hasVisitorMessages2 && state.followUps.length > 0;
1364
1521
  const showDockFollowUps = expanded && showIdleFollowUps;
1365
1522
  const streamingMessage = state.phase === "streaming" && state.streamingText ? {
@@ -1373,42 +1530,73 @@ function AgentRail({
1373
1530
  const node = transcriptRef.current;
1374
1531
  if (!node) return;
1375
1532
  node.scrollTop = node.scrollHeight;
1376
- }, [state.messages, state.toolSteps, state.streamingText, state.followUps, state.journey]);
1377
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1533
+ }, [
1534
+ state.messages,
1535
+ state.toolSteps,
1536
+ state.streamingText,
1537
+ state.followUps,
1538
+ state.journey
1539
+ ]);
1540
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1378
1541
  "aside",
1379
1542
  {
1380
1543
  className: `agent-rail${mobileFullscreen ? " agent-rail--mobile-fullscreen" : ""}${expanded ? " agent-rail--expanded" : ""}`,
1381
1544
  style: railStyle,
1382
1545
  "aria-label": "Agent conversation",
1383
1546
  children: [
1384
- /* @__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: [
1385
- onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1547
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("header", { className: "agent-rail__header", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__brand-row", children: [
1548
+ onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1386
1549
  "button",
1387
1550
  {
1388
1551
  type: "button",
1389
1552
  className: "agent-rail__collapse",
1390
1553
  "aria-label": "Collapse assist",
1391
1554
  onClick: onCollapse,
1392
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MinimizeIcon, {})
1555
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MinimizeIcon, {})
1556
+ }
1557
+ ) : onClose ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1558
+ "button",
1559
+ {
1560
+ type: "button",
1561
+ className: "agent-rail__close",
1562
+ "aria-label": "Close agent",
1563
+ onClick: onClose,
1564
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MinimizeIcon, {})
1393
1565
  }
1394
- ) : 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" }),
1395
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-label", children: brandLabel }),
1396
- onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1566
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" }),
1567
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "agent-rail__identity", children: [
1568
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "agent-rail__brand-mark", "aria-hidden": "true", children: [
1569
+ brandLabel.slice(0, 1).toUpperCase(),
1570
+ brandLogoUrl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1571
+ "img",
1572
+ {
1573
+ className: "agent-rail__brand-logo",
1574
+ src: brandLogoUrl,
1575
+ alt: "",
1576
+ onError: (event) => {
1577
+ event.currentTarget.hidden = true;
1578
+ }
1579
+ }
1580
+ ) : null
1581
+ ] }),
1582
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-label", children: brandLabel })
1583
+ ] }),
1584
+ onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1397
1585
  "button",
1398
1586
  {
1399
1587
  type: "button",
1400
1588
  className: "agent-rail__expand",
1401
1589
  "aria-label": expanded ? "Restore assist panel" : "Expand assist panel",
1402
1590
  onClick: onExpandToggle,
1403
- children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpandIcon, {})
1591
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ExpandIcon, {})
1404
1592
  }
1405
- ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" })
1593
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" })
1406
1594
  ] }) }),
1407
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: [
1408
- state.messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message }, message.id)),
1409
- streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message: streamingMessage }) : null,
1410
- showActivity ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AgentActivityBubble, { steps: state.toolSteps }) : null,
1411
- !expanded && showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1595
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: [
1596
+ state.messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MessageBubble, { message }, message.id)),
1597
+ streamingMessage ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MessageBubble, { message: streamingMessage }) : null,
1598
+ showActivity ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AgentActivityBubble, { steps: state.toolSteps }) : null,
1599
+ !expanded && showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1412
1600
  FollowUpChips,
1413
1601
  {
1414
1602
  suggestions: state.followUps,
@@ -1417,10 +1605,17 @@ function AgentRail({
1417
1605
  onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
1418
1606
  }
1419
1607
  ) }) : null,
1420
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "alert", style: { fontSize: 13, color: "var(--as-danger)", margin: 0 }, children: state.error }) : null
1608
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1609
+ "p",
1610
+ {
1611
+ role: "alert",
1612
+ style: { fontSize: 13, color: "var(--as-danger)", margin: 0 },
1613
+ children: state.error
1614
+ }
1615
+ ) : null
1421
1616
  ] }),
1422
- expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__dock-wrap", children: [
1423
- showDockFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__dock-followups", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1617
+ expanded ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__dock-wrap", children: [
1618
+ showDockFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__dock-followups", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1424
1619
  FollowUpChips,
1425
1620
  {
1426
1621
  variant: "dock",
@@ -1429,7 +1624,7 @@ function AgentRail({
1429
1624
  onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
1430
1625
  }
1431
1626
  ) }) : null,
1432
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__dock", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1627
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "agent-rail__dock", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1433
1628
  Composer,
1434
1629
  {
1435
1630
  variant: "dock",
@@ -1438,12 +1633,12 @@ function AgentRail({
1438
1633
  onSubmit
1439
1634
  }
1440
1635
  ) }),
1441
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__footer", children: [
1442
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1443
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1636
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__footer", children: [
1637
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1638
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1444
1639
  ] })
1445
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
1446
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1640
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
1641
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1447
1642
  Composer,
1448
1643
  {
1449
1644
  disabled: isBusy,
@@ -1451,9 +1646,9 @@ function AgentRail({
1451
1646
  onSubmit
1452
1647
  }
1453
1648
  ),
1454
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__footer", children: [
1455
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1456
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1649
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "agent-rail__footer", children: [
1650
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
1651
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
1457
1652
  ] })
1458
1653
  ] })
1459
1654
  ]
@@ -1462,22 +1657,67 @@ function AgentRail({
1462
1657
  }
1463
1658
 
1464
1659
  // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
1465
- var import_jsx_runtime7 = require("react/jsx-runtime");
1660
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1466
1661
  function SparklesIcon() {
1467
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { className: "assist-edge-tab__sparkles", viewBox: "0 0 18 16", fill: "none", "aria-hidden": "true", children: [
1468
- /* @__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" }),
1469
- /* @__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" }),
1470
- /* @__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" })
1471
- ] });
1662
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1663
+ "svg",
1664
+ {
1665
+ className: "assist-edge-tab__sparkles",
1666
+ viewBox: "0 0 18 16",
1667
+ fill: "none",
1668
+ "aria-hidden": "true",
1669
+ children: [
1670
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1671
+ "path",
1672
+ {
1673
+ d: "M8 1.2l.95 2.7 2.85.05-2.25 1.75.8 2.75L8 6.7 5.65 8.45l.8-2.75L4.2 3.95l2.85-.05L8 1.2z",
1674
+ fill: "currentColor"
1675
+ }
1676
+ ),
1677
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1678
+ "path",
1679
+ {
1680
+ d: "M14.2 6.4l.55 1.55 1.65.03-1.3 1 .46 1.58-1.36-1-1.36 1 .46-1.58-1.3-1 1.65-.03.55-1.55z",
1681
+ fill: "currentColor"
1682
+ }
1683
+ ),
1684
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1685
+ "path",
1686
+ {
1687
+ d: "M3.1 9.1l.4 1.15 1.22.02-.96.74.34 1.17-1-.74-1 .74.34-1.17-.96-.74 1.22-.02.4-1.15z",
1688
+ fill: "currentColor"
1689
+ }
1690
+ )
1691
+ ]
1692
+ }
1693
+ );
1472
1694
  }
1473
1695
  function ChevronLeftIcon() {
1474
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M10 4L6 8l4 4", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) });
1696
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1697
+ "path",
1698
+ {
1699
+ d: "M10 4L6 8l4 4",
1700
+ stroke: "currentColor",
1701
+ strokeWidth: "1.6",
1702
+ strokeLinecap: "round",
1703
+ strokeLinejoin: "round"
1704
+ }
1705
+ ) });
1475
1706
  }
1476
1707
  function ChevronDownIcon() {
1477
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M4 6l4 4 4-4", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) });
1708
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1709
+ "path",
1710
+ {
1711
+ d: "M4 6l4 4 4-4",
1712
+ stroke: "currentColor",
1713
+ strokeWidth: "1.6",
1714
+ strokeLinecap: "round",
1715
+ strokeLinejoin: "round"
1716
+ }
1717
+ ) });
1478
1718
  }
1479
1719
  function DragDots() {
1480
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__dots", "aria-hidden": "true", children: Array.from({ length: 12 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("i", {}, index)) });
1720
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__dots", "aria-hidden": "true", children: Array.from({ length: 12 }, (_, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("i", {}, index)) });
1481
1721
  }
1482
1722
  var VARIANT_COPY = {
1483
1723
  outline: { label: "Assist", aria: "Open Assist" },
@@ -1490,38 +1730,71 @@ function AssistEdgeTab({
1490
1730
  along,
1491
1731
  inset,
1492
1732
  visible,
1733
+ label,
1734
+ logoUrl,
1735
+ brandColor,
1736
+ fontFamily,
1493
1737
  onOpen
1494
1738
  }) {
1495
1739
  const copy = VARIANT_COPY[variant];
1740
+ const visibleLabel = label?.trim() || copy.label;
1496
1741
  const style = {
1497
1742
  "--tab-along": `${along}%`,
1498
- "--tab-inset": `${inset}px`
1743
+ "--tab-inset": `${inset}px`,
1744
+ ...brandColor ? { "--as-brand": brandColor } : {},
1745
+ ...fontFamily ? { "--as-font-display": fontFamily } : {}
1499
1746
  };
1500
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1747
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1501
1748
  "button",
1502
1749
  {
1503
1750
  type: "button",
1504
1751
  className: `assist-edge-tab assist-edge-tab--${variant} assist-edge-tab--${side}${visible ? " is-visible" : ""}`,
1505
1752
  style,
1506
- "aria-label": copy.aria,
1753
+ "aria-label": `Open ${visibleLabel}`,
1507
1754
  "aria-hidden": !visible,
1508
1755
  tabIndex: visible ? 0 : -1,
1509
1756
  onClick: onOpen,
1510
1757
  children: [
1511
- variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1512
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {}),
1513
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
1514
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronDownIcon, {})
1758
+ variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1759
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
1760
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparklesIcon, {}),
1761
+ logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1762
+ "img",
1763
+ {
1764
+ className: "assist-edge-tab__logo",
1765
+ src: logoUrl,
1766
+ alt: "",
1767
+ onError: (event) => {
1768
+ event.currentTarget.hidden = true;
1769
+ }
1770
+ }
1771
+ ) : null
1772
+ ] }),
1773
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1774
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronDownIcon, {})
1515
1775
  ] }) : null,
1516
- variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1517
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {}),
1518
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
1519
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DragDots, {})
1776
+ variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1777
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronLeftIcon, {}),
1778
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1779
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DragDots, {})
1520
1780
  ] }) : null,
1521
- variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1522
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {}),
1523
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
1524
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {})
1781
+ variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1782
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "assist-edge-tab__mark", "aria-hidden": "true", children: [
1783
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SparklesIcon, {}),
1784
+ logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1785
+ "img",
1786
+ {
1787
+ className: "assist-edge-tab__logo",
1788
+ src: logoUrl,
1789
+ alt: "",
1790
+ onError: (event) => {
1791
+ event.currentTarget.hidden = true;
1792
+ }
1793
+ }
1794
+ ) : null
1795
+ ] }),
1796
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "assist-edge-tab__label", children: visibleLabel }),
1797
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronLeftIcon, {})
1525
1798
  ] }) : null
1526
1799
  ]
1527
1800
  }
@@ -1529,7 +1802,7 @@ function AssistEdgeTab({
1529
1802
  }
1530
1803
 
1531
1804
  // src/react/components/AgentWidget/AgentWidget.tsx
1532
- var import_jsx_runtime8 = require("react/jsx-runtime");
1805
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1533
1806
  function AgentWidget({
1534
1807
  indexId,
1535
1808
  customerId,
@@ -1539,7 +1812,8 @@ function AgentWidget({
1539
1812
  placement: placementInput,
1540
1813
  defaultCollapsed = true,
1541
1814
  pageShift = true,
1542
- registerPanelController = false
1815
+ registerPanelController = false,
1816
+ branding
1543
1817
  }) {
1544
1818
  const isMobile = useIsMobile();
1545
1819
  const placement = normalizeAgentPlacement(placementInput);
@@ -1561,8 +1835,27 @@ function AgentWidget({
1561
1835
  getUnpublishedPreviewGrant,
1562
1836
  indexId,
1563
1837
  version,
1564
- runtimeOrigin
1838
+ runtimeOrigin,
1839
+ greeting: branding?.greeting
1565
1840
  });
1841
+ const agentName = branding?.agentName ?? "Webless Guide";
1842
+ const theme = {
1843
+ ...branding?.fontFamily ? { fontBody: branding.fontFamily, fontDisplay: branding.fontFamily } : {},
1844
+ ...branding?.colors?.primary ? {
1845
+ brand: branding.colors.primary,
1846
+ visitorBubble: branding.colors.primary
1847
+ } : {},
1848
+ ...branding?.colors?.primarySoft ? { brandSoft: branding.colors.primarySoft } : {},
1849
+ ...branding?.colors?.primaryForeground ? { visitorText: branding.colors.primaryForeground } : {},
1850
+ ...branding?.colors?.surface ? { surface: branding.colors.surface } : {},
1851
+ ...branding?.colors?.surfaceMuted ? { surfaceMuted: branding.colors.surfaceMuted } : {},
1852
+ ...branding?.colors?.text ? { text: branding.colors.text } : {},
1853
+ ...branding?.colors?.textMuted ? {
1854
+ textMuted: branding.colors.textMuted,
1855
+ textSubtle: branding.colors.textMuted
1856
+ } : {},
1857
+ ...branding?.colors?.border ? { border: branding.colors.border } : {}
1858
+ };
1566
1859
  const idle = state.phase === "idle" && !hasVisitorMessages(state.messages);
1567
1860
  (0, import_react6.useEffect)(() => {
1568
1861
  if (!registerPanelController) return;
@@ -1579,48 +1872,56 @@ function AgentWidget({
1579
1872
  if (isMobile) setRailCollapsed(false);
1580
1873
  await submit(message);
1581
1874
  }
1582
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "webless-agent-root", children: [
1583
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1875
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "webless-agent-root", children: [
1876
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1584
1877
  "div",
1585
1878
  {
1586
1879
  className: `webless-agent-root__shell${railCollapsed ? " webless-agent-root__shell--collapsed" : ""}${railExpanded ? " webless-agent-root__shell--expanded" : ""}`,
1587
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1588
- "div",
1589
- {
1590
- ref: railSlotRef,
1591
- className: "webless-agent-root__rail-slot",
1592
- inert: railCollapsed || void 0,
1593
- "aria-hidden": railCollapsed,
1594
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1595
- AgentRail,
1596
- {
1597
- state: idle ? {
1598
- ...state,
1599
- followUps: createIdleSuggestions()
1600
- } : state,
1601
- mobileFullscreen: isMobile && !railCollapsed,
1602
- expanded: railExpanded,
1603
- onCollapse: !isMobile ? () => setRailCollapsed(true) : void 0,
1604
- onClose: isMobile ? () => setRailCollapsed(true) : void 0,
1605
- onExpandToggle: !isMobile ? () => setRailExpanded((current) => !current) : void 0,
1606
- onSubmit: handleSubmit,
1607
- onFollowUpSelect: (label) => void handleSubmit(label)
1608
- }
1609
- )
1610
- }
1611
- )
1880
+ children: [
1881
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1882
+ "div",
1883
+ {
1884
+ ref: railSlotRef,
1885
+ className: "webless-agent-root__rail-slot",
1886
+ inert: railCollapsed || void 0,
1887
+ "aria-hidden": railCollapsed,
1888
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1889
+ AgentRail,
1890
+ {
1891
+ theme,
1892
+ brandLabel: agentName,
1893
+ brandLogoUrl: branding?.logoUrl,
1894
+ composerPlaceholder: branding?.composerPlaceholder ?? `Ask ${agentName}\u2026`,
1895
+ poweredByLabel: branding?.poweredByLabel ?? "Powered by Webless",
1896
+ state: idle ? {
1897
+ ...state,
1898
+ followUps: createIdleSuggestions()
1899
+ } : state,
1900
+ mobileFullscreen: isMobile && !railCollapsed,
1901
+ expanded: railExpanded,
1902
+ onCollapse: !isMobile ? () => setRailCollapsed(true) : void 0,
1903
+ onClose: isMobile ? () => setRailCollapsed(true) : void 0,
1904
+ onExpandToggle: !isMobile ? () => setRailExpanded((current) => !current) : void 0,
1905
+ onSubmit: handleSubmit,
1906
+ onFollowUpSelect: (label) => void handleSubmit(label)
1907
+ }
1908
+ )
1909
+ }
1910
+ ),
1911
+ !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1912
+ "button",
1913
+ {
1914
+ type: "button",
1915
+ className: "webless-agent-root__backdrop",
1916
+ tabIndex: -1,
1917
+ "aria-label": "Close expanded assist",
1918
+ onClick: () => setRailExpanded(false)
1919
+ }
1920
+ ) : null
1921
+ ]
1612
1922
  }
1613
1923
  ),
1614
- !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1615
- "button",
1616
- {
1617
- type: "button",
1618
- className: "webless-agent-root__backdrop",
1619
- "aria-label": "Close expanded assist",
1620
- onClick: () => setRailExpanded(false)
1621
- }
1622
- ) : null,
1623
- railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1924
+ railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1624
1925
  AssistEdgeTab,
1625
1926
  {
1626
1927
  variant: placement.variant,
@@ -1628,29 +1929,15 @@ function AgentWidget({
1628
1929
  along: placement.along,
1629
1930
  inset: placement.inset,
1630
1931
  visible: true,
1932
+ label: agentName,
1933
+ logoUrl: branding?.logoUrl,
1934
+ brandColor: branding?.colors?.primary,
1935
+ fontFamily: branding?.fontFamily,
1631
1936
  onOpen: () => setRailCollapsed(false)
1632
1937
  }
1633
1938
  ) : null
1634
1939
  ] });
1635
1940
  }
1636
-
1637
- // src/react/types/conversation.ts
1638
- var defaultAgentRailTheme = {
1639
- railMaxWidth: "450px",
1640
- brand: "#6f16ff",
1641
- brandSoft: "#f3edff",
1642
- brandDeep: "#12043e",
1643
- surface: "#ffffff",
1644
- surfaceMuted: "#f4f6fb",
1645
- text: "#171b2a",
1646
- textMuted: "#5a6378",
1647
- textSubtle: "#8a94a8",
1648
- border: "rgb(42 51 70 / 0.1)",
1649
- visitorBubble: "#6f16ff",
1650
- visitorText: "#ffffff",
1651
- success: "#18794e",
1652
- danger: "#c94b63"
1653
- };
1654
1941
  // Annotate the CommonJS export names for ESM import in node:
1655
1942
  0 && (module.exports = {
1656
1943
  AgentRail,