@webless/agent 0.2.0 → 0.2.6

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
@@ -21,482 +21,82 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var react_exports = {};
22
22
  __export(react_exports, {
23
23
  AgentRail: () => AgentRail,
24
+ AgentWidget: () => AgentWidget,
24
25
  AssistEdgeTab: () => AssistEdgeTab,
26
+ DEFAULT_AGENT_PLACEMENT: () => DEFAULT_AGENT_PLACEMENT,
25
27
  createIdleSuggestions: () => createIdleSuggestions,
26
28
  defaultAgentRailTheme: () => defaultAgentRailTheme,
27
29
  hasVisitorMessages: () => hasVisitorMessages,
28
30
  isAgentBusy: () => isAgentBusy,
31
+ normalizeAgentPlacement: () => normalizeAgentPlacement,
29
32
  useAgentChat: () => useAgentChat
30
33
  });
31
34
  module.exports = __toCommonJS(react_exports);
32
35
 
33
- // src/react/components/AgentRail/AgentRail.tsx
34
- var import_react2 = require("react");
36
+ // src/react/components/AgentWidget/AgentWidget.tsx
37
+ var import_react5 = require("react");
35
38
 
36
- // src/react/components/ToolTimeline/ToolTimeline.tsx
37
- var import_jsx_runtime = require("react/jsx-runtime");
38
- function SpinnerIcon() {
39
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className: "agent-status__spinner", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
40
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "8", cy: "8", r: "6", stroke: "currentColor", strokeWidth: "1.5", strokeOpacity: "0.25" }),
41
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 8a6 6 0 0 0-6-6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
42
- ] });
43
- }
44
- function getCurrentStep(steps) {
45
- const active = steps.find((step) => step.state === "active");
46
- if (active) return active;
47
- const error = steps.find((step) => step.state === "error");
48
- if (error) return error;
49
- const pending = steps.find((step) => step.state === "pending");
50
- if (pending) return pending;
51
- return steps.at(-1) ?? null;
52
- }
53
- function ToolTimeline({
54
- steps,
55
- streamingText,
56
- showStreaming = false,
57
- inline = false
58
- }) {
59
- if (steps.length === 0 && !(showStreaming && streamingText)) return null;
60
- const currentStep = getCurrentStep(steps);
61
- const showStatus = currentStep && currentStep.state !== "completed" && !(showStreaming && streamingText);
62
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
63
- "div",
64
- {
65
- className: `tool-timeline${inline ? " tool-timeline--inline" : ""}`,
66
- role: "status",
67
- "aria-live": "polite",
68
- "aria-label": "Agent progress",
69
- children: [
70
- showStatus ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-status", children: [
71
- 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, {}) }),
72
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-status__copy", children: [
73
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__label", children: currentStep.label }),
74
- currentStep.detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__detail", children: currentStep.detail }) : null
75
- ] })
76
- ] }, currentStep.id) : null,
77
- showStreaming && streamingText ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "tool-timeline__streaming-text", children: [
78
- streamingText,
79
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tool-timeline__cursor", "aria-hidden": "true" })
80
- ] }) : null
81
- ]
82
- }
83
- );
84
- }
39
+ // src/react/hooks/useAgentChat.ts
40
+ var import_react = require("react");
85
41
 
86
- // src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
87
- var import_jsx_runtime2 = require("react/jsx-runtime");
88
- function AgentActivityBubble({
89
- steps,
90
- streamingText,
91
- showStreaming = false
92
- }) {
93
- 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)(
94
- ToolTimeline,
95
- {
96
- steps,
97
- streamingText,
98
- showStreaming,
99
- inline: true
100
- }
101
- ) }) });
102
- }
42
+ // src/runtime/client.ts
43
+ var import_client = require("eve/client");
103
44
 
104
- // src/react/components/Composer/Composer.tsx
105
- var import_react = require("react");
106
- var import_jsx_runtime3 = require("react/jsx-runtime");
107
- function SendIcon() {
108
- 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" }) });
45
+ // src/runtime/config.ts
46
+ var DEFAULT_RUNTIME_ORIGIN = "https://runtime.staging.webless.ai";
47
+ var trimTrailingSlash = (value) => value.replace(/\/+$/, "");
48
+ function buildEveHost(origin, indexId) {
49
+ const base = trimTrailingSlash(origin);
50
+ return `${base}?indexId=${encodeURIComponent(indexId.trim())}`;
109
51
  }
110
- function Composer({
111
- disabled = false,
112
- placeholder = "Ask anything\u2026",
113
- variant = "default",
114
- onSubmit
115
- }) {
116
- const [value, setValue] = (0, import_react.useState)("");
117
- const inputRef = (0, import_react.useRef)(null);
118
- function submitCurrent() {
119
- const trimmed = value.trim();
120
- if (!trimmed || disabled) return;
121
- onSubmit?.(trimmed);
122
- setValue("");
123
- inputRef.current?.focus();
124
- }
125
- function handleSubmit(event) {
126
- event.preventDefault();
127
- submitCurrent();
128
- }
129
- function handleKeyDown(event) {
130
- if (event.key === "Enter" && !event.shiftKey) {
131
- event.preventDefault();
132
- submitCurrent();
133
- }
134
- }
135
- 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: [
136
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
137
- "textarea",
138
- {
139
- ref: inputRef,
140
- className: "composer__input",
141
- rows: 1,
142
- value,
143
- placeholder,
144
- disabled,
145
- "aria-label": "Message",
146
- onChange: (event) => setValue(event.target.value),
147
- onKeyDown: handleKeyDown
148
- }
149
- ),
150
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
151
- "button",
152
- {
153
- type: "submit",
154
- className: "composer__send",
155
- disabled: disabled || !value.trim(),
156
- "aria-label": "Send message",
157
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
158
- }
159
- )
160
- ] }) });
52
+ function resolveAgentRuntimeConfig(input) {
53
+ const origin = trimTrailingSlash(input.runtimeOrigin?.trim() || DEFAULT_RUNTIME_ORIGIN);
54
+ const resolvedIndexId = input.indexId.trim();
55
+ return {
56
+ origin,
57
+ indexId: resolvedIndexId,
58
+ host: resolvedIndexId ? buildEveHost(origin, resolvedIndexId) : origin
59
+ };
161
60
  }
162
61
 
163
- // src/react/components/FollowUpChips/FollowUpChips.tsx
164
- var import_jsx_runtime4 = require("react/jsx-runtime");
165
- function FollowUpChips({
166
- suggestions,
167
- disabled = false,
168
- label = "Follow up",
169
- variant = "default",
170
- onSelect
171
- }) {
172
- if (suggestions.length === 0) return null;
173
- if (variant === "dock") {
174
- 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)(
175
- "button",
176
- {
177
- type: "button",
178
- className: "followups__chip followups__chip--dock",
179
- disabled,
180
- onClick: () => onSelect?.(suggestion),
181
- children: suggestion.label
182
- },
183
- suggestion.id
184
- )) }) });
62
+ // src/runtime/session-store.ts
63
+ var DEFAULT_STORAGE_KEY_PREFIX = "webless:agent";
64
+ function normalizeRuntimeOrigin(runtimeOrigin) {
65
+ const trimmed = runtimeOrigin?.trim();
66
+ if (!trimmed) return "_";
67
+ return trimmed.replace(/\/+$/, "");
68
+ }
69
+ function buildAgentStorageKeyPrefix(input) {
70
+ const customerId = input.customerId?.trim() || "_";
71
+ const indexId = input.indexId.trim();
72
+ if (!indexId) {
73
+ throw new Error("indexId is required to build agent storage keys.");
185
74
  }
186
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "followups", children: [
187
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "followups__label", children: label }),
188
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "followups__list", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
189
- "button",
190
- {
191
- type: "button",
192
- className: "followups__chip",
193
- disabled,
194
- onClick: () => onSelect?.(suggestion),
195
- children: suggestion.label
196
- },
197
- suggestion.id
198
- )) })
199
- ] });
75
+ return `${DEFAULT_STORAGE_KEY_PREFIX}:${customerId}:${indexId}:${normalizeRuntimeOrigin(input.runtimeOrigin)}`;
200
76
  }
201
-
202
- // src/react/components/MessageBubble/MessageBubble.tsx
203
- var import_jsx_runtime5 = require("react/jsx-runtime");
204
- function MessageBubble({ message }) {
205
- if (message.role === "visitor") {
206
- 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 }) });
77
+ function createSessionId() {
78
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
79
+ return crypto.randomUUID();
207
80
  }
208
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("article", { className: "message-bubble message-bubble--agent", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "message-bubble__text", children: [
209
- message.text,
210
- message.streaming ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "tool-timeline__cursor", "aria-hidden": "true" }) : null
211
- ] }) });
81
+ return `sess_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
212
82
  }
213
-
214
- // src/react/components/AgentRail/AgentRail.tsx
215
- var import_jsx_runtime6 = require("react/jsx-runtime");
216
- function MinimizeIcon() {
217
- 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" }) });
83
+ function resolvePrefix(options) {
84
+ return options?.storageKeyPrefix?.trim() || DEFAULT_STORAGE_KEY_PREFIX;
218
85
  }
219
- function ExpandIcon() {
220
- 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)(
221
- "path",
222
- {
223
- d: "M6 3.5H3.5V6M10 3.5h2.5V6M10 12.5h2.5V10M6 12.5H3.5V10",
224
- stroke: "currentColor",
225
- strokeWidth: "1.5",
226
- strokeLinecap: "round",
227
- strokeLinejoin: "round"
228
- }
229
- ) });
86
+ function getOrCreateVisitorSessionId(options) {
87
+ const prefix = resolvePrefix(options);
88
+ const visitorKey = `${prefix}:visitorSessionId`;
89
+ if (typeof sessionStorage === "undefined") {
90
+ return createSessionId();
91
+ }
92
+ const existing = sessionStorage.getItem(visitorKey)?.trim();
93
+ if (existing) return existing;
94
+ const next = createSessionId();
95
+ sessionStorage.setItem(visitorKey, next);
96
+ return next;
230
97
  }
231
- function RestoreIcon() {
232
- 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)(
233
- "path",
234
- {
235
- d: "M5.5 5.5H3.5V7.5M10.5 5.5h2V7.5M10.5 10.5h2V8.5M5.5 10.5H3.5V8.5",
236
- stroke: "currentColor",
237
- strokeWidth: "1.5",
238
- strokeLinecap: "round",
239
- strokeLinejoin: "round"
240
- }
241
- ) });
242
- }
243
- function AgentRail({
244
- state,
245
- theme,
246
- brandLabel = "Webless Assist",
247
- poweredByLabel = "Powered by Webless",
248
- composerPlaceholder = "Ask anything\u2026",
249
- mobileFullscreen = false,
250
- expanded = false,
251
- onCollapse,
252
- onClose,
253
- onExpandToggle,
254
- onSubmit,
255
- onFollowUpSelect
256
- }) {
257
- const transcriptRef = (0, import_react2.useRef)(null);
258
- const railStyle = theme?.railMaxWidth ? { ["--rail-width"]: theme.railMaxWidth, ["--as-rail-max-width"]: theme.railMaxWidth } : void 0;
259
- const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming";
260
- const showActivity = state.toolSteps.length > 0 && (state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming");
261
- const showStreamingInActivity = state.phase === "streaming" && Boolean(state.streamingText);
262
- const hasVisitorMessages2 = state.messages.some((message) => message.role === "visitor");
263
- const showIdleFollowUps = !hasVisitorMessages2 && state.followUps.length > 0;
264
- const showCompleteFollowUps = state.phase === "complete" && state.followUps.length > 0 && hasVisitorMessages2;
265
- const showDockFollowUps = expanded && (showIdleFollowUps || showCompleteFollowUps);
266
- (0, import_react2.useEffect)(() => {
267
- const node = transcriptRef.current;
268
- if (!node) return;
269
- node.scrollTop = node.scrollHeight;
270
- }, [state.messages, state.toolSteps, state.streamingText, state.followUps, state.journey]);
271
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
272
- "aside",
273
- {
274
- className: `agent-rail${mobileFullscreen ? " agent-rail--mobile-fullscreen" : ""}${expanded ? " agent-rail--expanded" : ""}`,
275
- style: railStyle,
276
- "aria-label": "Agent conversation",
277
- children: [
278
- /* @__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: [
279
- onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
280
- "button",
281
- {
282
- type: "button",
283
- className: "agent-rail__collapse",
284
- "aria-label": "Collapse assist",
285
- onClick: onCollapse,
286
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MinimizeIcon, {})
287
- }
288
- ) : 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" }),
289
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-label", children: brandLabel }),
290
- onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
291
- "button",
292
- {
293
- type: "button",
294
- className: "agent-rail__expand",
295
- "aria-label": expanded ? "Restore assist panel" : "Expand assist panel",
296
- onClick: onExpandToggle,
297
- children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpandIcon, {})
298
- }
299
- ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" })
300
- ] }) }),
301
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: [
302
- state.messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message }, message.id)),
303
- showActivity ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
304
- AgentActivityBubble,
305
- {
306
- steps: state.toolSteps,
307
- streamingText: state.streamingText,
308
- showStreaming: showStreamingInActivity
309
- }
310
- ) : null,
311
- !expanded && showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
312
- FollowUpChips,
313
- {
314
- suggestions: state.followUps,
315
- disabled: isBusy,
316
- label: "Try asking",
317
- onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
318
- }
319
- ) }) : null,
320
- !expanded && showCompleteFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
321
- FollowUpChips,
322
- {
323
- suggestions: state.followUps,
324
- disabled: isBusy,
325
- onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
326
- }
327
- ) }) : null,
328
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "alert", style: { fontSize: 13, color: "var(--as-danger)", margin: 0 }, children: state.error }) : null
329
- ] }),
330
- expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__dock-wrap", children: [
331
- showDockFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__dock-followups", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
332
- FollowUpChips,
333
- {
334
- variant: "dock",
335
- suggestions: state.followUps,
336
- disabled: isBusy,
337
- onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
338
- }
339
- ) }) : null,
340
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__dock", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
341
- Composer,
342
- {
343
- variant: "dock",
344
- disabled: isBusy,
345
- placeholder: composerPlaceholder,
346
- onSubmit
347
- }
348
- ) }),
349
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__footer", children: [
350
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
351
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
352
- ] })
353
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
354
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
355
- Composer,
356
- {
357
- disabled: isBusy,
358
- placeholder: composerPlaceholder,
359
- onSubmit
360
- }
361
- ),
362
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__footer", children: [
363
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
364
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
365
- ] })
366
- ] })
367
- ]
368
- }
369
- );
370
- }
371
-
372
- // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
373
- var import_jsx_runtime7 = require("react/jsx-runtime");
374
- function SparklesIcon() {
375
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { className: "assist-edge-tab__sparkles", viewBox: "0 0 18 16", fill: "none", "aria-hidden": "true", children: [
376
- /* @__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" }),
377
- /* @__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" }),
378
- /* @__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" })
379
- ] });
380
- }
381
- function ChevronLeftIcon() {
382
- 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" }) });
383
- }
384
- function ChevronDownIcon() {
385
- 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" }) });
386
- }
387
- function DragDots() {
388
- 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)) });
389
- }
390
- var VARIANT_COPY = {
391
- outline: { label: "Assist", aria: "Open Assist" },
392
- ask: { label: "Ask anything", aria: "Ask anything" },
393
- fill: { label: "Assist", aria: "Open Assist" }
394
- };
395
- function AssistEdgeTab({
396
- variant,
397
- side,
398
- along,
399
- inset,
400
- visible,
401
- onOpen
402
- }) {
403
- const copy = VARIANT_COPY[variant];
404
- const style = {
405
- "--tab-along": `${along}%`,
406
- "--tab-inset": `${inset}px`
407
- };
408
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
409
- "button",
410
- {
411
- type: "button",
412
- className: `assist-edge-tab assist-edge-tab--${variant} assist-edge-tab--${side}${visible ? " is-visible" : ""}`,
413
- style,
414
- "aria-label": copy.aria,
415
- "aria-hidden": !visible,
416
- tabIndex: visible ? 0 : -1,
417
- onClick: onOpen,
418
- children: [
419
- variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
420
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {}),
421
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
422
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronDownIcon, {})
423
- ] }) : null,
424
- variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
425
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {}),
426
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
427
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DragDots, {})
428
- ] }) : null,
429
- variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
430
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {}),
431
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
432
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {})
433
- ] }) : null
434
- ]
435
- }
436
- );
437
- }
438
-
439
- // src/react/hooks/useAgentChat.ts
440
- var import_react3 = require("react");
441
-
442
- // src/runtime/client.ts
443
- var import_client = require("eve/client");
444
-
445
- // src/runtime/config.ts
446
- var DEFAULT_RUNTIME_ORIGIN = "https://runtime.staging.webless.ai";
447
- var trimTrailingSlash = (value) => value.replace(/\/+$/, "");
448
- function buildEveHost(origin, indexId) {
449
- const base = trimTrailingSlash(origin);
450
- return `${base}?indexId=${encodeURIComponent(indexId.trim())}`;
451
- }
452
- function resolveAgentRuntimeConfig(input) {
453
- const origin = trimTrailingSlash(input.runtimeOrigin?.trim() || DEFAULT_RUNTIME_ORIGIN);
454
- const resolvedIndexId = input.indexId.trim();
455
- return {
456
- origin,
457
- indexId: resolvedIndexId,
458
- host: resolvedIndexId ? buildEveHost(origin, resolvedIndexId) : origin
459
- };
460
- }
461
-
462
- // src/runtime/session-store.ts
463
- var DEFAULT_STORAGE_KEY_PREFIX = "webless:agent";
464
- function normalizeRuntimeOrigin(runtimeOrigin) {
465
- const trimmed = runtimeOrigin?.trim();
466
- if (!trimmed) return "_";
467
- return trimmed.replace(/\/+$/, "");
468
- }
469
- function buildAgentStorageKeyPrefix(input) {
470
- const customerId = input.customerId?.trim() || "_";
471
- const indexId = input.indexId.trim();
472
- if (!indexId) {
473
- throw new Error("indexId is required to build agent storage keys.");
474
- }
475
- return `${DEFAULT_STORAGE_KEY_PREFIX}:${customerId}:${indexId}:${normalizeRuntimeOrigin(input.runtimeOrigin)}`;
476
- }
477
- function createSessionId() {
478
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
479
- return crypto.randomUUID();
480
- }
481
- return `sess_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
482
- }
483
- function resolvePrefix(options) {
484
- return options?.storageKeyPrefix?.trim() || DEFAULT_STORAGE_KEY_PREFIX;
485
- }
486
- function getOrCreateVisitorSessionId(options) {
487
- const prefix = resolvePrefix(options);
488
- const visitorKey = `${prefix}:visitorSessionId`;
489
- if (typeof sessionStorage === "undefined") {
490
- return createSessionId();
491
- }
492
- const existing = sessionStorage.getItem(visitorKey)?.trim();
493
- if (existing) return existing;
494
- const next = createSessionId();
495
- sessionStorage.setItem(visitorKey, next);
496
- return next;
497
- }
498
- function runtimeSessionIdKey(visitorSessionId, prefix) {
499
- return `${prefix}:eve:${visitorSessionId}:sessionId`;
98
+ function runtimeSessionIdKey(visitorSessionId, prefix) {
99
+ return `${prefix}:eve:${visitorSessionId}:sessionId`;
500
100
  }
501
101
  function runtimeStreamIndexKey(visitorSessionId, prefix) {
502
102
  return `${prefix}:eve:${visitorSessionId}:streamIndex`;
@@ -774,17 +374,17 @@ function useAgentChat({
774
374
  visitorSessionId,
775
375
  storageKeyPrefix
776
376
  }) {
777
- const [state, setState] = (0, import_react3.useState)(INITIAL_STATE);
778
- const runRef = (0, import_react3.useRef)(null);
779
- const resolvedStorageKeyPrefix = (0, import_react3.useMemo)(
377
+ const [state, setState] = (0, import_react.useState)(INITIAL_STATE);
378
+ const runRef = (0, import_react.useRef)(null);
379
+ const resolvedStorageKeyPrefix = (0, import_react.useMemo)(
780
380
  () => storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({ customerId, indexId, runtimeOrigin }),
781
381
  [customerId, indexId, runtimeOrigin, storageKeyPrefix]
782
382
  );
783
- const visitorId = (0, import_react3.useMemo)(
383
+ const visitorId = (0, import_react.useMemo)(
784
384
  () => visitorSessionId?.trim() || getOrCreateVisitorSessionId({ storageKeyPrefix: resolvedStorageKeyPrefix }),
785
385
  [resolvedStorageKeyPrefix, visitorSessionId]
786
386
  );
787
- const clientRef = (0, import_react3.useRef)(
387
+ const clientRef = (0, import_react.useRef)(
788
388
  createAgentClient({
789
389
  customerId,
790
390
  indexId,
@@ -793,9 +393,9 @@ function useAgentChat({
793
393
  storageKeyPrefix: resolvedStorageKeyPrefix
794
394
  })
795
395
  );
796
- const identityRef = (0, import_react3.useRef)(null);
396
+ const identityRef = (0, import_react.useRef)(null);
797
397
  const identityKey = `${customerId ?? ""}|${indexId}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}`;
798
- (0, import_react3.useEffect)(() => {
398
+ (0, import_react.useEffect)(() => {
799
399
  if (identityRef.current === null) {
800
400
  identityRef.current = identityKey;
801
401
  return;
@@ -816,13 +416,13 @@ function useAgentChat({
816
416
  });
817
417
  setState(INITIAL_STATE);
818
418
  }, [customerId, identityKey, indexId, runtimeOrigin, resolvedStorageKeyPrefix, visitorId]);
819
- const reset = (0, import_react3.useCallback)(() => {
419
+ const reset = (0, import_react.useCallback)(() => {
820
420
  runRef.current?.abort();
821
421
  runRef.current = null;
822
422
  clientRef.current.reset();
823
423
  setState(INITIAL_STATE);
824
424
  }, []);
825
- const submit = (0, import_react3.useCallback)(
425
+ const submit = (0, import_react.useCallback)(
826
426
  async (visitorText) => {
827
427
  runRef.current?.abort();
828
428
  clientRef.current.cancelActive();
@@ -920,7 +520,7 @@ function useAgentChat({
920
520
  },
921
521
  [customerId, indexId, runtimeOrigin, resolvedStorageKeyPrefix, visitorId]
922
522
  );
923
- (0, import_react3.useEffect)(() => {
523
+ (0, import_react.useEffect)(() => {
924
524
  return () => {
925
525
  runRef.current?.abort();
926
526
  clientRef.current.cancelActive();
@@ -948,6 +548,543 @@ function isAgentBusy(phase) {
948
548
  return phase === "thinking" || phase === "running-tools" || phase === "streaming";
949
549
  }
950
550
 
551
+ // src/react/hooks/useIsMobile.ts
552
+ var import_react2 = require("react");
553
+ function useIsMobile(breakpoint = 767) {
554
+ const [isMobile, setIsMobile] = (0, import_react2.useState)(
555
+ () => typeof window !== "undefined" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
556
+ );
557
+ (0, import_react2.useEffect)(() => {
558
+ const media = window.matchMedia(`(max-width: ${breakpoint}px)`);
559
+ const onChange = () => setIsMobile(media.matches);
560
+ onChange();
561
+ media.addEventListener("change", onChange);
562
+ return () => media.removeEventListener("change", onChange);
563
+ }, [breakpoint]);
564
+ return isMobile;
565
+ }
566
+
567
+ // src/react/placement.ts
568
+ var DEFAULT_AGENT_PLACEMENT = {
569
+ side: "right",
570
+ along: 50,
571
+ inset: 0,
572
+ variant: "outline"
573
+ };
574
+ function normalizeAgentPlacement(placement) {
575
+ const along = placement?.along ?? DEFAULT_AGENT_PLACEMENT.along;
576
+ return {
577
+ side: placement?.side ?? DEFAULT_AGENT_PLACEMENT.side,
578
+ along: Math.min(100, Math.max(0, along)),
579
+ inset: Math.max(0, placement?.inset ?? DEFAULT_AGENT_PLACEMENT.inset),
580
+ variant: placement?.variant ?? DEFAULT_AGENT_PLACEMENT.variant
581
+ };
582
+ }
583
+
584
+ // src/react/panel-controller.ts
585
+ var controllers = /* @__PURE__ */ new Map();
586
+ function registerAgentPanelController(customerId, controller) {
587
+ controllers.set(customerId, controller);
588
+ }
589
+ function unregisterAgentPanelController(customerId) {
590
+ controllers.delete(customerId);
591
+ }
592
+
593
+ // src/react/components/AgentRail/AgentRail.tsx
594
+ var import_react4 = require("react");
595
+
596
+ // src/react/components/ToolTimeline/ToolTimeline.tsx
597
+ var import_jsx_runtime = require("react/jsx-runtime");
598
+ function SpinnerIcon() {
599
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className: "agent-status__spinner", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
600
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "8", cy: "8", r: "6", stroke: "currentColor", strokeWidth: "1.5", strokeOpacity: "0.25" }),
601
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 8a6 6 0 0 0-6-6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
602
+ ] });
603
+ }
604
+ function getCurrentStep(steps) {
605
+ const active = steps.find((step) => step.state === "active");
606
+ if (active) return active;
607
+ const error = steps.find((step) => step.state === "error");
608
+ if (error) return error;
609
+ const pending = steps.find((step) => step.state === "pending");
610
+ if (pending) return pending;
611
+ return steps.at(-1) ?? null;
612
+ }
613
+ function ToolTimeline({
614
+ steps,
615
+ streamingText,
616
+ showStreaming = false,
617
+ inline = false
618
+ }) {
619
+ if (steps.length === 0 && !(showStreaming && streamingText)) return null;
620
+ const currentStep = getCurrentStep(steps);
621
+ const showStatus = currentStep && currentStep.state !== "completed" && !(showStreaming && streamingText);
622
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
623
+ "div",
624
+ {
625
+ className: `tool-timeline${inline ? " tool-timeline--inline" : ""}`,
626
+ role: "status",
627
+ "aria-live": "polite",
628
+ "aria-label": "Agent progress",
629
+ children: [
630
+ showStatus ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-status", children: [
631
+ 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, {}) }),
632
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "agent-status__copy", children: [
633
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__label", children: currentStep.label }),
634
+ currentStep.detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "agent-status__detail", children: currentStep.detail }) : null
635
+ ] })
636
+ ] }, currentStep.id) : null,
637
+ showStreaming && streamingText ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "tool-timeline__streaming-text", children: [
638
+ streamingText,
639
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tool-timeline__cursor", "aria-hidden": "true" })
640
+ ] }) : null
641
+ ]
642
+ }
643
+ );
644
+ }
645
+
646
+ // src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
647
+ var import_jsx_runtime2 = require("react/jsx-runtime");
648
+ function AgentActivityBubble({
649
+ steps,
650
+ streamingText,
651
+ showStreaming = false
652
+ }) {
653
+ 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)(
654
+ ToolTimeline,
655
+ {
656
+ steps,
657
+ streamingText,
658
+ showStreaming,
659
+ inline: true
660
+ }
661
+ ) }) });
662
+ }
663
+
664
+ // src/react/components/Composer/Composer.tsx
665
+ var import_react3 = require("react");
666
+ var import_jsx_runtime3 = require("react/jsx-runtime");
667
+ function SendIcon() {
668
+ 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" }) });
669
+ }
670
+ function Composer({
671
+ disabled = false,
672
+ placeholder = "Ask anything\u2026",
673
+ variant = "default",
674
+ onSubmit
675
+ }) {
676
+ const [value, setValue] = (0, import_react3.useState)("");
677
+ const inputRef = (0, import_react3.useRef)(null);
678
+ function submitCurrent() {
679
+ const trimmed = value.trim();
680
+ if (!trimmed || disabled) return;
681
+ onSubmit?.(trimmed);
682
+ setValue("");
683
+ inputRef.current?.focus();
684
+ }
685
+ function handleSubmit(event) {
686
+ event.preventDefault();
687
+ submitCurrent();
688
+ }
689
+ function handleKeyDown(event) {
690
+ if (event.key === "Enter" && !event.shiftKey) {
691
+ event.preventDefault();
692
+ submitCurrent();
693
+ }
694
+ }
695
+ 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: [
696
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
697
+ "textarea",
698
+ {
699
+ ref: inputRef,
700
+ className: "composer__input",
701
+ rows: 1,
702
+ value,
703
+ placeholder,
704
+ disabled,
705
+ "aria-label": "Message",
706
+ onChange: (event) => setValue(event.target.value),
707
+ onKeyDown: handleKeyDown
708
+ }
709
+ ),
710
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
711
+ "button",
712
+ {
713
+ type: "submit",
714
+ className: "composer__send",
715
+ disabled: disabled || !value.trim(),
716
+ "aria-label": "Send message",
717
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SendIcon, {})
718
+ }
719
+ )
720
+ ] }) });
721
+ }
722
+
723
+ // src/react/components/FollowUpChips/FollowUpChips.tsx
724
+ var import_jsx_runtime4 = require("react/jsx-runtime");
725
+ function FollowUpChips({
726
+ suggestions,
727
+ disabled = false,
728
+ label = "Follow up",
729
+ variant = "default",
730
+ onSelect
731
+ }) {
732
+ if (suggestions.length === 0) return null;
733
+ if (variant === "dock") {
734
+ 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)(
735
+ "button",
736
+ {
737
+ type: "button",
738
+ className: "followups__chip followups__chip--dock",
739
+ disabled,
740
+ onClick: () => onSelect?.(suggestion),
741
+ children: suggestion.label
742
+ },
743
+ suggestion.id
744
+ )) }) });
745
+ }
746
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "followups", children: [
747
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "followups__label", children: label }),
748
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "followups__list", children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
749
+ "button",
750
+ {
751
+ type: "button",
752
+ className: "followups__chip",
753
+ disabled,
754
+ onClick: () => onSelect?.(suggestion),
755
+ children: suggestion.label
756
+ },
757
+ suggestion.id
758
+ )) })
759
+ ] });
760
+ }
761
+
762
+ // src/react/components/MessageBubble/MessageBubble.tsx
763
+ var import_jsx_runtime5 = require("react/jsx-runtime");
764
+ function MessageBubble({ message }) {
765
+ if (message.role === "visitor") {
766
+ 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 }) });
767
+ }
768
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("article", { className: "message-bubble message-bubble--agent", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "message-bubble__text", children: [
769
+ message.text,
770
+ message.streaming ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "tool-timeline__cursor", "aria-hidden": "true" }) : null
771
+ ] }) });
772
+ }
773
+
774
+ // src/react/components/AgentRail/AgentRail.tsx
775
+ var import_jsx_runtime6 = require("react/jsx-runtime");
776
+ function MinimizeIcon() {
777
+ 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" }) });
778
+ }
779
+ function ExpandIcon() {
780
+ 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)(
781
+ "path",
782
+ {
783
+ d: "M6 3.5H3.5V6M10 3.5h2.5V6M10 12.5h2.5V10M6 12.5H3.5V10",
784
+ stroke: "currentColor",
785
+ strokeWidth: "1.5",
786
+ strokeLinecap: "round",
787
+ strokeLinejoin: "round"
788
+ }
789
+ ) });
790
+ }
791
+ function RestoreIcon() {
792
+ 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)(
793
+ "path",
794
+ {
795
+ d: "M5.5 5.5H3.5V7.5M10.5 5.5h2V7.5M10.5 10.5h2V8.5M5.5 10.5H3.5V8.5",
796
+ stroke: "currentColor",
797
+ strokeWidth: "1.5",
798
+ strokeLinecap: "round",
799
+ strokeLinejoin: "round"
800
+ }
801
+ ) });
802
+ }
803
+ function AgentRail({
804
+ state,
805
+ theme,
806
+ brandLabel = "Webless Assist",
807
+ poweredByLabel = "Powered by Webless",
808
+ composerPlaceholder = "Ask anything\u2026",
809
+ mobileFullscreen = false,
810
+ expanded = false,
811
+ onCollapse,
812
+ onClose,
813
+ onExpandToggle,
814
+ onSubmit,
815
+ onFollowUpSelect
816
+ }) {
817
+ const transcriptRef = (0, import_react4.useRef)(null);
818
+ const railStyle = theme?.railMaxWidth ? { ["--rail-width"]: theme.railMaxWidth, ["--as-rail-max-width"]: theme.railMaxWidth } : void 0;
819
+ const isBusy = state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming";
820
+ const showActivity = state.toolSteps.length > 0 && (state.phase === "thinking" || state.phase === "running-tools" || state.phase === "streaming");
821
+ const showStreamingInActivity = state.phase === "streaming" && Boolean(state.streamingText);
822
+ const hasVisitorMessages2 = state.messages.some((message) => message.role === "visitor");
823
+ const showIdleFollowUps = !hasVisitorMessages2 && state.followUps.length > 0;
824
+ const showCompleteFollowUps = state.phase === "complete" && state.followUps.length > 0 && hasVisitorMessages2;
825
+ const showDockFollowUps = expanded && (showIdleFollowUps || showCompleteFollowUps);
826
+ (0, import_react4.useEffect)(() => {
827
+ const node = transcriptRef.current;
828
+ if (!node) return;
829
+ node.scrollTop = node.scrollHeight;
830
+ }, [state.messages, state.toolSteps, state.streamingText, state.followUps, state.journey]);
831
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
832
+ "aside",
833
+ {
834
+ className: `agent-rail${mobileFullscreen ? " agent-rail--mobile-fullscreen" : ""}${expanded ? " agent-rail--expanded" : ""}`,
835
+ style: railStyle,
836
+ "aria-label": "Agent conversation",
837
+ children: [
838
+ /* @__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: [
839
+ onCollapse ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
840
+ "button",
841
+ {
842
+ type: "button",
843
+ className: "agent-rail__collapse",
844
+ "aria-label": "Collapse assist",
845
+ onClick: onCollapse,
846
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MinimizeIcon, {})
847
+ }
848
+ ) : 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" }),
849
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-label", children: brandLabel }),
850
+ onExpandToggle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
851
+ "button",
852
+ {
853
+ type: "button",
854
+ className: "agent-rail__expand",
855
+ "aria-label": expanded ? "Restore assist panel" : "Expand assist panel",
856
+ onClick: onExpandToggle,
857
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RestoreIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ExpandIcon, {})
858
+ }
859
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "agent-rail__brand-spacer", "aria-hidden": "true" })
860
+ ] }) }),
861
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: transcriptRef, className: "agent-rail__transcript", children: [
862
+ state.messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageBubble, { message }, message.id)),
863
+ showActivity ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
864
+ AgentActivityBubble,
865
+ {
866
+ steps: state.toolSteps,
867
+ streamingText: state.streamingText,
868
+ showStreaming: showStreamingInActivity
869
+ }
870
+ ) : null,
871
+ !expanded && showIdleFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
872
+ FollowUpChips,
873
+ {
874
+ suggestions: state.followUps,
875
+ disabled: isBusy,
876
+ label: "Try asking",
877
+ onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
878
+ }
879
+ ) }) : null,
880
+ !expanded && showCompleteFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__followups-slot", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
881
+ FollowUpChips,
882
+ {
883
+ suggestions: state.followUps,
884
+ disabled: isBusy,
885
+ onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
886
+ }
887
+ ) }) : null,
888
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "alert", style: { fontSize: 13, color: "var(--as-danger)", margin: 0 }, children: state.error }) : null
889
+ ] }),
890
+ expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__dock-wrap", children: [
891
+ showDockFollowUps ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__dock-followups", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
892
+ FollowUpChips,
893
+ {
894
+ variant: "dock",
895
+ suggestions: state.followUps,
896
+ disabled: isBusy,
897
+ onSelect: (suggestion) => onFollowUpSelect?.(suggestion.label)
898
+ }
899
+ ) }) : null,
900
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "agent-rail__dock", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
901
+ Composer,
902
+ {
903
+ variant: "dock",
904
+ disabled: isBusy,
905
+ placeholder: composerPlaceholder,
906
+ onSubmit
907
+ }
908
+ ) }),
909
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__footer", children: [
910
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
911
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
912
+ ] })
913
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__composer-wrap", children: [
914
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
915
+ Composer,
916
+ {
917
+ disabled: isBusy,
918
+ placeholder: composerPlaceholder,
919
+ onSubmit
920
+ }
921
+ ),
922
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "agent-rail__footer", children: [
923
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-disclaimer", children: "AI can make mistakes. Check important info." }),
924
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "agent-rail__footer-note", children: poweredByLabel })
925
+ ] })
926
+ ] })
927
+ ]
928
+ }
929
+ );
930
+ }
931
+
932
+ // src/react/components/AssistEdgeTab/AssistEdgeTab.tsx
933
+ var import_jsx_runtime7 = require("react/jsx-runtime");
934
+ function SparklesIcon() {
935
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { className: "assist-edge-tab__sparkles", viewBox: "0 0 18 16", fill: "none", "aria-hidden": "true", children: [
936
+ /* @__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" }),
937
+ /* @__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" }),
938
+ /* @__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" })
939
+ ] });
940
+ }
941
+ function ChevronLeftIcon() {
942
+ 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" }) });
943
+ }
944
+ function ChevronDownIcon() {
945
+ 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" }) });
946
+ }
947
+ function DragDots() {
948
+ 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)) });
949
+ }
950
+ var VARIANT_COPY = {
951
+ outline: { label: "Assist", aria: "Open Assist" },
952
+ ask: { label: "Ask anything", aria: "Ask anything" },
953
+ fill: { label: "Assist", aria: "Open Assist" }
954
+ };
955
+ function AssistEdgeTab({
956
+ variant,
957
+ side,
958
+ along,
959
+ inset,
960
+ visible,
961
+ onOpen
962
+ }) {
963
+ const copy = VARIANT_COPY[variant];
964
+ const style = {
965
+ "--tab-along": `${along}%`,
966
+ "--tab-inset": `${inset}px`
967
+ };
968
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
969
+ "button",
970
+ {
971
+ type: "button",
972
+ className: `assist-edge-tab assist-edge-tab--${variant} assist-edge-tab--${side}${visible ? " is-visible" : ""}`,
973
+ style,
974
+ "aria-label": copy.aria,
975
+ "aria-hidden": !visible,
976
+ tabIndex: visible ? 0 : -1,
977
+ onClick: onOpen,
978
+ children: [
979
+ variant === "outline" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
980
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {}),
981
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
982
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronDownIcon, {})
983
+ ] }) : null,
984
+ variant === "ask" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
985
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {}),
986
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
987
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DragDots, {})
988
+ ] }) : null,
989
+ variant === "fill" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
990
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparklesIcon, {}),
991
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "assist-edge-tab__label", children: copy.label }),
992
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronLeftIcon, {})
993
+ ] }) : null
994
+ ]
995
+ }
996
+ );
997
+ }
998
+
999
+ // src/react/components/AgentWidget/AgentWidget.tsx
1000
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1001
+ function AgentWidget({
1002
+ indexId,
1003
+ customerId,
1004
+ runtimeOrigin,
1005
+ placement: placementInput,
1006
+ defaultCollapsed = true,
1007
+ registerPanelController = false
1008
+ }) {
1009
+ const isMobile = useIsMobile();
1010
+ const placement = normalizeAgentPlacement(placementInput);
1011
+ const [railCollapsed, setRailCollapsed] = (0, import_react5.useState)(defaultCollapsed);
1012
+ const [railExpanded, setRailExpanded] = (0, import_react5.useState)(false);
1013
+ const { state, submit } = useAgentChat({
1014
+ customerId,
1015
+ indexId,
1016
+ runtimeOrigin
1017
+ });
1018
+ const idle = state.phase === "idle" && !hasVisitorMessages(state.messages);
1019
+ (0, import_react5.useEffect)(() => {
1020
+ if (!registerPanelController) return;
1021
+ registerAgentPanelController(customerId, {
1022
+ open: () => setRailCollapsed(false),
1023
+ close: () => {
1024
+ setRailCollapsed(true);
1025
+ setRailExpanded(false);
1026
+ }
1027
+ });
1028
+ return () => unregisterAgentPanelController(customerId);
1029
+ }, [customerId, registerPanelController]);
1030
+ async function handleSubmit(message) {
1031
+ if (isMobile) setRailCollapsed(false);
1032
+ await submit(message);
1033
+ }
1034
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "webless-agent-root", children: [
1035
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1036
+ "div",
1037
+ {
1038
+ className: `webless-agent-root__shell${railCollapsed ? " webless-agent-root__shell--collapsed" : ""}${railExpanded ? " webless-agent-root__shell--expanded" : ""}`,
1039
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1040
+ "div",
1041
+ {
1042
+ className: "webless-agent-root__rail-slot",
1043
+ inert: railCollapsed || void 0,
1044
+ "aria-hidden": railCollapsed,
1045
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1046
+ AgentRail,
1047
+ {
1048
+ state: idle ? {
1049
+ ...state,
1050
+ followUps: createIdleSuggestions()
1051
+ } : state,
1052
+ mobileFullscreen: isMobile && !railCollapsed,
1053
+ expanded: railExpanded,
1054
+ onCollapse: !isMobile ? () => setRailCollapsed(true) : void 0,
1055
+ onClose: isMobile ? () => setRailCollapsed(true) : void 0,
1056
+ onExpandToggle: !isMobile ? () => setRailExpanded((current) => !current) : void 0,
1057
+ onSubmit: handleSubmit,
1058
+ onFollowUpSelect: (label) => void handleSubmit(label)
1059
+ }
1060
+ )
1061
+ }
1062
+ )
1063
+ }
1064
+ ),
1065
+ !isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1066
+ "button",
1067
+ {
1068
+ type: "button",
1069
+ className: "webless-agent-root__backdrop",
1070
+ "aria-label": "Close expanded assist",
1071
+ onClick: () => setRailExpanded(false)
1072
+ }
1073
+ ) : null,
1074
+ railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1075
+ AssistEdgeTab,
1076
+ {
1077
+ variant: placement.variant,
1078
+ side: placement.side,
1079
+ along: placement.along,
1080
+ inset: placement.inset,
1081
+ visible: true,
1082
+ onOpen: () => setRailCollapsed(false)
1083
+ }
1084
+ ) : null
1085
+ ] });
1086
+ }
1087
+
951
1088
  // src/react/types/conversation.ts
952
1089
  var defaultAgentRailTheme = {
953
1090
  railMaxWidth: "450px",
@@ -968,11 +1105,14 @@ var defaultAgentRailTheme = {
968
1105
  // Annotate the CommonJS export names for ESM import in node:
969
1106
  0 && (module.exports = {
970
1107
  AgentRail,
1108
+ AgentWidget,
971
1109
  AssistEdgeTab,
1110
+ DEFAULT_AGENT_PLACEMENT,
972
1111
  createIdleSuggestions,
973
1112
  defaultAgentRailTheme,
974
1113
  hasVisitorMessages,
975
1114
  isAgentBusy,
1115
+ normalizeAgentPlacement,
976
1116
  useAgentChat
977
1117
  });
978
1118
  //# sourceMappingURL=react.cjs.map