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