@webless/agent 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +121 -0
- package/dist/chunk-WLQDMWO6.js +932 -0
- package/dist/chunk-WLQDMWO6.js.map +1 -0
- package/dist/embed.cjs +1188 -0
- package/dist/embed.cjs.map +1 -0
- package/dist/embed.css +945 -0
- package/dist/embed.css.map +1 -0
- package/dist/embed.d.cts +55 -0
- package/dist/embed.d.ts +55 -0
- package/dist/embed.js +248 -0
- package/dist/embed.js.map +1 -0
- package/dist/index.cjs +368 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +73 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +332 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +978 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.css +798 -0
- package/dist/react.css.map +1 -0
- package/dist/react.d.cts +113 -0
- package/dist/react.d.ts +113 -0
- package/dist/react.js +36 -0
- package/dist/react.js.map +1 -0
- package/package.json +61 -0
- package/scripts/build-agent-manifest-bundle-impl.mjs +87 -0
- package/scripts/build-agent-manifest-bundle.mjs +42 -0
package/dist/embed.cjs
ADDED
|
@@ -0,0 +1,1188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/embed/index.ts
|
|
21
|
+
var embed_exports = {};
|
|
22
|
+
__export(embed_exports, {
|
|
23
|
+
DEFAULT_AGENT_PLACEMENT: () => DEFAULT_AGENT_PLACEMENT,
|
|
24
|
+
bootstrapAgent: () => bootstrapAgent,
|
|
25
|
+
getMountedAgent: () => getMountedAgent,
|
|
26
|
+
mountAgent: () => mountAgent,
|
|
27
|
+
normalizeAgentPlacement: () => normalizeAgentPlacement,
|
|
28
|
+
normalizeAgentTagManifest: () => normalizeAgentTagManifest,
|
|
29
|
+
unmountAgent: () => unmountAgent
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(embed_exports);
|
|
32
|
+
|
|
33
|
+
// src/embed/mount.tsx
|
|
34
|
+
var import_client4 = require("react-dom/client");
|
|
35
|
+
|
|
36
|
+
// src/embed/controller.ts
|
|
37
|
+
var controllers = /* @__PURE__ */ new Map();
|
|
38
|
+
function registerAgentPanelController(customerId, controller) {
|
|
39
|
+
controllers.set(customerId, controller);
|
|
40
|
+
}
|
|
41
|
+
function unregisterAgentPanelController(customerId) {
|
|
42
|
+
controllers.delete(customerId);
|
|
43
|
+
}
|
|
44
|
+
function openAgentPanel(customerId) {
|
|
45
|
+
controllers.get(customerId)?.open();
|
|
46
|
+
}
|
|
47
|
+
function closeAgentPanel(customerId) {
|
|
48
|
+
controllers.get(customerId)?.close();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/embed/AgentWidget.tsx
|
|
52
|
+
var import_react4 = require("react");
|
|
53
|
+
|
|
54
|
+
// src/react/components/AgentRail/AgentRail.tsx
|
|
55
|
+
var import_react2 = require("react");
|
|
56
|
+
|
|
57
|
+
// src/react/components/ToolTimeline/ToolTimeline.tsx
|
|
58
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
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
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/react/components/AgentActivityBubble/AgentActivityBubble.tsx
|
|
108
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
109
|
+
function AgentActivityBubble({
|
|
110
|
+
steps,
|
|
111
|
+
streamingText,
|
|
112
|
+
showStreaming = false
|
|
113
|
+
}) {
|
|
114
|
+
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)(
|
|
115
|
+
ToolTimeline,
|
|
116
|
+
{
|
|
117
|
+
steps,
|
|
118
|
+
streamingText,
|
|
119
|
+
showStreaming,
|
|
120
|
+
inline: true
|
|
121
|
+
}
|
|
122
|
+
) }) });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/react/components/Composer/Composer.tsx
|
|
126
|
+
var import_react = require("react");
|
|
127
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
128
|
+
function SendIcon() {
|
|
129
|
+
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" }) });
|
|
130
|
+
}
|
|
131
|
+
function Composer({
|
|
132
|
+
disabled = false,
|
|
133
|
+
placeholder = "Ask anything\u2026",
|
|
134
|
+
variant = "default",
|
|
135
|
+
onSubmit
|
|
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
|
+
}
|
|
155
|
+
}
|
|
156
|
+
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: [
|
|
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
|
+
] }) });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/react/components/FollowUpChips/FollowUpChips.tsx
|
|
185
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
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
|
+
)) }) });
|
|
206
|
+
}
|
|
207
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "followups", children: [
|
|
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
|
+
] });
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/react/components/MessageBubble/MessageBubble.tsx
|
|
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
|
+
] }) });
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/react/components/AgentRail/AgentRail.tsx
|
|
236
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
237
|
+
function MinimizeIcon() {
|
|
238
|
+
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" }) });
|
|
239
|
+
}
|
|
240
|
+
function ExpandIcon() {
|
|
241
|
+
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)(
|
|
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
|
+
) });
|
|
251
|
+
}
|
|
252
|
+
function RestoreIcon() {
|
|
253
|
+
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)(
|
|
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`;
|
|
524
|
+
}
|
|
525
|
+
function loadPersistedAgentSession(visitorSessionId, options) {
|
|
526
|
+
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim()) return null;
|
|
527
|
+
const prefix = resolvePrefix(options);
|
|
528
|
+
const sessionId = sessionStorage.getItem(runtimeSessionIdKey(visitorSessionId, prefix))?.trim();
|
|
529
|
+
if (!sessionId) return null;
|
|
530
|
+
const rawIndex = sessionStorage.getItem(runtimeStreamIndexKey(visitorSessionId, prefix));
|
|
531
|
+
const streamIndex = rawIndex ? Number.parseInt(rawIndex, 10) : 0;
|
|
532
|
+
return {
|
|
533
|
+
sessionId,
|
|
534
|
+
streamIndex: Number.isFinite(streamIndex) && streamIndex >= 0 ? streamIndex : 0
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
function savePersistedAgentSession(visitorSessionId, sessionId, streamIndex, options) {
|
|
538
|
+
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim() || !sessionId.trim()) {
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
const prefix = resolvePrefix(options);
|
|
542
|
+
sessionStorage.setItem(runtimeSessionIdKey(visitorSessionId, prefix), sessionId);
|
|
543
|
+
sessionStorage.setItem(
|
|
544
|
+
runtimeStreamIndexKey(visitorSessionId, prefix),
|
|
545
|
+
String(Math.max(0, streamIndex))
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
function clearPersistedAgentSession(visitorSessionId, options) {
|
|
549
|
+
if (typeof sessionStorage === "undefined" || !visitorSessionId.trim()) return;
|
|
550
|
+
const prefix = resolvePrefix(options);
|
|
551
|
+
sessionStorage.removeItem(runtimeSessionIdKey(visitorSessionId, prefix));
|
|
552
|
+
sessionStorage.removeItem(runtimeStreamIndexKey(visitorSessionId, prefix));
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// src/runtime/client.ts
|
|
556
|
+
function mapStepLabel(event) {
|
|
557
|
+
if (event.type !== "step.started") return null;
|
|
558
|
+
const stepIndex = event.data.stepIndex;
|
|
559
|
+
return {
|
|
560
|
+
label: "Model step running",
|
|
561
|
+
detail: typeof stepIndex === "number" ? `Step ${stepIndex + 1}` : void 0
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
var AgentSession = class {
|
|
565
|
+
constructor(indexId, runtimeOrigin, visitorSessionId, storeOptions) {
|
|
566
|
+
this.indexId = indexId;
|
|
567
|
+
this.runtimeOrigin = runtimeOrigin;
|
|
568
|
+
this.visitorSessionId = visitorSessionId;
|
|
569
|
+
this.storeOptions = storeOptions;
|
|
570
|
+
}
|
|
571
|
+
indexId;
|
|
572
|
+
runtimeOrigin;
|
|
573
|
+
visitorSessionId;
|
|
574
|
+
storeOptions;
|
|
575
|
+
client;
|
|
576
|
+
clientHost;
|
|
577
|
+
session;
|
|
578
|
+
activeResponse;
|
|
579
|
+
renderedPrefix = "";
|
|
580
|
+
getActiveSessionId() {
|
|
581
|
+
return this.session?.state.sessionId ?? loadPersistedAgentSession(this.visitorSessionId, this.storeOptions)?.sessionId;
|
|
582
|
+
}
|
|
583
|
+
reset() {
|
|
584
|
+
void this.activeResponse?.cancel().catch(() => {
|
|
585
|
+
});
|
|
586
|
+
this.activeResponse = void 0;
|
|
587
|
+
this.session = void 0;
|
|
588
|
+
this.renderedPrefix = "";
|
|
589
|
+
clearPersistedAgentSession(this.visitorSessionId, this.storeOptions);
|
|
590
|
+
}
|
|
591
|
+
persistSessionCursor(session) {
|
|
592
|
+
savePersistedAgentSession(
|
|
593
|
+
this.visitorSessionId,
|
|
594
|
+
session.state.sessionId,
|
|
595
|
+
session.state.streamIndex,
|
|
596
|
+
this.storeOptions
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
ensureClient() {
|
|
600
|
+
const config = resolveAgentRuntimeConfig({
|
|
601
|
+
indexId: this.indexId,
|
|
602
|
+
runtimeOrigin: this.runtimeOrigin
|
|
603
|
+
});
|
|
604
|
+
if (!config.indexId) {
|
|
605
|
+
throw new Error("indexId is required.");
|
|
606
|
+
}
|
|
607
|
+
if (this.client && this.clientHost === config.host) {
|
|
608
|
+
return this.client;
|
|
609
|
+
}
|
|
610
|
+
this.reset();
|
|
611
|
+
this.client = new import_client.Client({ host: config.host });
|
|
612
|
+
this.clientHost = config.host;
|
|
613
|
+
return this.client;
|
|
614
|
+
}
|
|
615
|
+
attachPersistedSession(client) {
|
|
616
|
+
const persisted = loadPersistedAgentSession(this.visitorSessionId, this.storeOptions);
|
|
617
|
+
if (!persisted?.sessionId) return void 0;
|
|
618
|
+
this.renderedPrefix = "";
|
|
619
|
+
return client.sessions.attach(persisted.sessionId, {
|
|
620
|
+
streamIndex: persisted.streamIndex
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
async sendTurn(message, signal, handlers) {
|
|
624
|
+
const client = this.ensureClient();
|
|
625
|
+
let response;
|
|
626
|
+
let session = this.session ?? this.attachPersistedSession(client);
|
|
627
|
+
if (session) {
|
|
628
|
+
this.session = session;
|
|
629
|
+
try {
|
|
630
|
+
response = await session.send(message, { signal });
|
|
631
|
+
} catch (error) {
|
|
632
|
+
if (error instanceof import_client.ClientError && error.status === 409 && error.code === "session_not_active") {
|
|
633
|
+
clearPersistedAgentSession(this.visitorSessionId, this.storeOptions);
|
|
634
|
+
this.session = void 0;
|
|
635
|
+
session = void 0;
|
|
636
|
+
} else {
|
|
637
|
+
throw error;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
if (!response) {
|
|
642
|
+
const created = await client.sessions.create({ message, signal });
|
|
643
|
+
response = created.response;
|
|
644
|
+
session = created.session;
|
|
645
|
+
this.session = session;
|
|
646
|
+
this.renderedPrefix = "";
|
|
647
|
+
this.persistSessionCursor(session);
|
|
648
|
+
}
|
|
649
|
+
this.activeResponse = response;
|
|
650
|
+
let rendered = this.renderedPrefix;
|
|
651
|
+
try {
|
|
652
|
+
for await (const event of response) {
|
|
653
|
+
if (signal.aborted) break;
|
|
654
|
+
const step = mapStepLabel(event);
|
|
655
|
+
if (step) handlers.onStep?.(step.label, step.detail);
|
|
656
|
+
if (event.type === "message.appended") {
|
|
657
|
+
const { messageDelta, messageSoFar } = event.data;
|
|
658
|
+
let delta = messageDelta;
|
|
659
|
+
if (messageSoFar.startsWith(rendered)) {
|
|
660
|
+
delta = messageSoFar.slice(rendered.length);
|
|
661
|
+
rendered = messageSoFar;
|
|
662
|
+
} else if (messageDelta) {
|
|
663
|
+
rendered += messageDelta;
|
|
664
|
+
}
|
|
665
|
+
if (delta) handlers.onDelta(delta);
|
|
666
|
+
}
|
|
667
|
+
if (event.type === "message.completed") {
|
|
668
|
+
handlers.onComplete?.();
|
|
669
|
+
}
|
|
670
|
+
if (event.type === "session.failed") {
|
|
671
|
+
throw new Error(event.data.message || event.data.code);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
} finally {
|
|
675
|
+
this.activeResponse = void 0;
|
|
676
|
+
this.renderedPrefix = rendered;
|
|
677
|
+
if (session) {
|
|
678
|
+
this.persistSessionCursor(session);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (!rendered.trim() && !signal.aborted) {
|
|
682
|
+
throw new Error("Empty response from runtime");
|
|
683
|
+
}
|
|
684
|
+
if (signal.aborted) {
|
|
685
|
+
await response.cancel().catch(() => {
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
return rendered.trim();
|
|
689
|
+
}
|
|
690
|
+
cancelActive() {
|
|
691
|
+
this.activeResponse?.cancel().catch(() => {
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
function createAgentClient(options) {
|
|
696
|
+
const indexId = options.indexId.trim();
|
|
697
|
+
if (!indexId) {
|
|
698
|
+
throw new Error("indexId is required.");
|
|
699
|
+
}
|
|
700
|
+
const runtimeOrigin = options.runtimeOrigin?.trim() || resolveAgentRuntimeConfig({ indexId }).origin;
|
|
701
|
+
const storeOptions = {
|
|
702
|
+
storageKeyPrefix: options.storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({
|
|
703
|
+
customerId: options.customerId,
|
|
704
|
+
indexId,
|
|
705
|
+
runtimeOrigin
|
|
706
|
+
})
|
|
707
|
+
};
|
|
708
|
+
const visitorSessionId = options.visitorSessionId?.trim() || getOrCreateVisitorSessionId(storeOptions);
|
|
709
|
+
const session = new AgentSession(indexId, runtimeOrigin, visitorSessionId, storeOptions);
|
|
710
|
+
return {
|
|
711
|
+
indexId,
|
|
712
|
+
runtimeOrigin,
|
|
713
|
+
visitorSessionId,
|
|
714
|
+
sendTurn: (message, sendOptions) => session.sendTurn(
|
|
715
|
+
message,
|
|
716
|
+
sendOptions.signal ?? new AbortController().signal,
|
|
717
|
+
sendOptions.handlers
|
|
718
|
+
),
|
|
719
|
+
reset: () => session.reset(),
|
|
720
|
+
cancelActive: () => session.cancelActive(),
|
|
721
|
+
getActiveSessionId: () => session.getActiveSessionId()
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// src/runtime/errors.ts
|
|
726
|
+
var import_client2 = require("eve/client");
|
|
727
|
+
function formatAgentError(error) {
|
|
728
|
+
if (error instanceof import_client2.ClientError) {
|
|
729
|
+
if (error.status === 401 && error.code === "index_required") {
|
|
730
|
+
return "Missing indexId \u2014 pass a published index id to createAgentClient().";
|
|
731
|
+
}
|
|
732
|
+
if (error.status === 403 && error.code === "agent_unavailable") {
|
|
733
|
+
return "Agent unavailable for this index (disabled or unpublished).";
|
|
734
|
+
}
|
|
735
|
+
if (error.status === 409 && error.code === "session_not_active") {
|
|
736
|
+
return "Session expired \u2014 send a new message to start again.";
|
|
737
|
+
}
|
|
738
|
+
return error.message || `Runtime error (${error.status})`;
|
|
739
|
+
}
|
|
740
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
741
|
+
return "";
|
|
742
|
+
}
|
|
743
|
+
if (error instanceof Error) return error.message;
|
|
744
|
+
return "Runtime request failed";
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// src/react/hooks/useAgentChat.ts
|
|
748
|
+
var GREETING_MESSAGE = {
|
|
749
|
+
id: "greeting",
|
|
750
|
+
role: "agent",
|
|
751
|
+
text: "Hi! I'm connected to the Webless Agent Runtime. Ask anything about your published site index.",
|
|
752
|
+
createdAt: 0
|
|
753
|
+
};
|
|
754
|
+
var INITIAL_STATE = {
|
|
755
|
+
phase: "idle",
|
|
756
|
+
messages: [GREETING_MESSAGE],
|
|
757
|
+
toolSteps: [],
|
|
758
|
+
journey: null,
|
|
759
|
+
followUps: [],
|
|
760
|
+
streamingText: "",
|
|
761
|
+
error: null
|
|
762
|
+
};
|
|
763
|
+
var STATUS_SEQUENCE = [
|
|
764
|
+
{ id: "s1", label: "Starting Eve session", ms: 400 },
|
|
765
|
+
{ id: "s2", label: "Connecting to runtime", ms: 500 }
|
|
766
|
+
];
|
|
767
|
+
var DEFAULT_FOLLOW_UPS = [
|
|
768
|
+
{ id: "fu-1", label: "What can you help me with?" },
|
|
769
|
+
{ id: "fu-2", label: "Summarize your capabilities" },
|
|
770
|
+
{ id: "fu-3", label: "What should I ask next?" }
|
|
771
|
+
];
|
|
772
|
+
function delay(ms, signal) {
|
|
773
|
+
return new Promise((resolve, reject) => {
|
|
774
|
+
const timer = window.setTimeout(resolve, ms);
|
|
775
|
+
signal.addEventListener(
|
|
776
|
+
"abort",
|
|
777
|
+
() => {
|
|
778
|
+
window.clearTimeout(timer);
|
|
779
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
780
|
+
},
|
|
781
|
+
{ once: true }
|
|
782
|
+
);
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
async function runStatusSequence(signal, onStep) {
|
|
786
|
+
for (const item of STATUS_SEQUENCE) {
|
|
787
|
+
onStep({ id: item.id, label: item.label, detail: item.detail, state: "active" });
|
|
788
|
+
await delay(item.ms, signal);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
function useAgentChat({
|
|
792
|
+
customerId,
|
|
793
|
+
indexId,
|
|
794
|
+
runtimeOrigin,
|
|
795
|
+
visitorSessionId,
|
|
796
|
+
storageKeyPrefix
|
|
797
|
+
}) {
|
|
798
|
+
const [state, setState] = (0, import_react3.useState)(INITIAL_STATE);
|
|
799
|
+
const runRef = (0, import_react3.useRef)(null);
|
|
800
|
+
const resolvedStorageKeyPrefix = (0, import_react3.useMemo)(
|
|
801
|
+
() => storageKeyPrefix?.trim() || buildAgentStorageKeyPrefix({ customerId, indexId, runtimeOrigin }),
|
|
802
|
+
[customerId, indexId, runtimeOrigin, storageKeyPrefix]
|
|
803
|
+
);
|
|
804
|
+
const visitorId = (0, import_react3.useMemo)(
|
|
805
|
+
() => visitorSessionId?.trim() || getOrCreateVisitorSessionId({ storageKeyPrefix: resolvedStorageKeyPrefix }),
|
|
806
|
+
[resolvedStorageKeyPrefix, visitorSessionId]
|
|
807
|
+
);
|
|
808
|
+
const clientRef = (0, import_react3.useRef)(
|
|
809
|
+
createAgentClient({
|
|
810
|
+
customerId,
|
|
811
|
+
indexId,
|
|
812
|
+
runtimeOrigin,
|
|
813
|
+
visitorSessionId: visitorId,
|
|
814
|
+
storageKeyPrefix: resolvedStorageKeyPrefix
|
|
815
|
+
})
|
|
816
|
+
);
|
|
817
|
+
const identityRef = (0, import_react3.useRef)(null);
|
|
818
|
+
const identityKey = `${customerId ?? ""}|${indexId}|${runtimeOrigin ?? ""}|${resolvedStorageKeyPrefix}|${visitorId}`;
|
|
819
|
+
(0, import_react3.useEffect)(() => {
|
|
820
|
+
if (identityRef.current === null) {
|
|
821
|
+
identityRef.current = identityKey;
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
if (identityRef.current === identityKey) {
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
identityRef.current = identityKey;
|
|
828
|
+
runRef.current?.abort();
|
|
829
|
+
runRef.current = null;
|
|
830
|
+
clientRef.current.reset();
|
|
831
|
+
clientRef.current = createAgentClient({
|
|
832
|
+
customerId,
|
|
833
|
+
indexId,
|
|
834
|
+
runtimeOrigin,
|
|
835
|
+
visitorSessionId: visitorId,
|
|
836
|
+
storageKeyPrefix: resolvedStorageKeyPrefix
|
|
837
|
+
});
|
|
838
|
+
setState(INITIAL_STATE);
|
|
839
|
+
}, [customerId, identityKey, indexId, runtimeOrigin, resolvedStorageKeyPrefix, visitorId]);
|
|
840
|
+
const reset = (0, import_react3.useCallback)(() => {
|
|
841
|
+
runRef.current?.abort();
|
|
842
|
+
runRef.current = null;
|
|
843
|
+
clientRef.current.reset();
|
|
844
|
+
setState(INITIAL_STATE);
|
|
845
|
+
}, []);
|
|
846
|
+
const submit = (0, import_react3.useCallback)(
|
|
847
|
+
async (visitorText) => {
|
|
848
|
+
runRef.current?.abort();
|
|
849
|
+
clientRef.current.cancelActive();
|
|
850
|
+
const controller = new AbortController();
|
|
851
|
+
runRef.current = controller;
|
|
852
|
+
const { signal } = controller;
|
|
853
|
+
const isActiveRun = () => runRef.current === controller && !signal.aborted;
|
|
854
|
+
const visitorMessage = {
|
|
855
|
+
id: `visitor-${Date.now()}`,
|
|
856
|
+
role: "visitor",
|
|
857
|
+
text: visitorText,
|
|
858
|
+
createdAt: Date.now()
|
|
859
|
+
};
|
|
860
|
+
setState((prev) => ({
|
|
861
|
+
...prev,
|
|
862
|
+
phase: "thinking",
|
|
863
|
+
messages: [...prev.messages, visitorMessage],
|
|
864
|
+
toolSteps: [{ id: "s1", label: "Starting Eve session", state: "active" }],
|
|
865
|
+
journey: null,
|
|
866
|
+
followUps: [],
|
|
867
|
+
streamingText: "",
|
|
868
|
+
error: null
|
|
869
|
+
}));
|
|
870
|
+
try {
|
|
871
|
+
let streamStarted = false;
|
|
872
|
+
const planningPromise = runStatusSequence(signal, (step) => {
|
|
873
|
+
if (streamStarted || !isActiveRun()) return;
|
|
874
|
+
setState((prev) => ({ ...prev, phase: "running-tools", toolSteps: [step] }));
|
|
875
|
+
});
|
|
876
|
+
let streamed = "";
|
|
877
|
+
const finalText = await clientRef.current.sendTurn(visitorText, {
|
|
878
|
+
signal,
|
|
879
|
+
handlers: {
|
|
880
|
+
onStep: (label, detail) => {
|
|
881
|
+
if (streamStarted || !isActiveRun()) return;
|
|
882
|
+
setState((prev) => ({
|
|
883
|
+
...prev,
|
|
884
|
+
phase: "running-tools",
|
|
885
|
+
toolSteps: [{ id: `step-${label}`, label, detail, state: "active" }]
|
|
886
|
+
}));
|
|
887
|
+
},
|
|
888
|
+
onDelta: (delta) => {
|
|
889
|
+
if (!isActiveRun()) return;
|
|
890
|
+
void planningPromise.catch(() => {
|
|
891
|
+
});
|
|
892
|
+
if (!streamStarted) {
|
|
893
|
+
streamStarted = true;
|
|
894
|
+
setState((prev) => ({
|
|
895
|
+
...prev,
|
|
896
|
+
phase: "streaming",
|
|
897
|
+
toolSteps: [],
|
|
898
|
+
streamingText: ""
|
|
899
|
+
}));
|
|
900
|
+
}
|
|
901
|
+
streamed += delta;
|
|
902
|
+
setState((prev) => ({ ...prev, phase: "streaming", streamingText: streamed }));
|
|
903
|
+
},
|
|
904
|
+
onComplete: () => {
|
|
905
|
+
if (!isActiveRun()) return;
|
|
906
|
+
streamStarted = true;
|
|
907
|
+
}
|
|
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]
|
|
943
|
+
);
|
|
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
|
+
}
|
|
958
|
+
function hasVisitorMessages(messages) {
|
|
959
|
+
return messages.some((message) => message.role === "visitor");
|
|
960
|
+
}
|
|
961
|
+
function createIdleSuggestions() {
|
|
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
|
+
];
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// src/embed/AgentWidget.tsx
|
|
970
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
971
|
+
function useIsMobile(breakpoint = 767) {
|
|
972
|
+
const [isMobile, setIsMobile] = (0, import_react4.useState)(
|
|
973
|
+
() => typeof window !== "undefined" && window.matchMedia(`(max-width: ${breakpoint}px)`).matches
|
|
974
|
+
);
|
|
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
|
+
}
|
|
984
|
+
function AgentWidget({ manifest }) {
|
|
985
|
+
const isMobile = useIsMobile();
|
|
986
|
+
const [railCollapsed, setRailCollapsed] = (0, import_react4.useState)(true);
|
|
987
|
+
const [railExpanded, setRailExpanded] = (0, import_react4.useState)(false);
|
|
988
|
+
const { state, submit } = useAgentChat({
|
|
989
|
+
customerId: manifest.customerId,
|
|
990
|
+
indexId: manifest.indexId,
|
|
991
|
+
runtimeOrigin: manifest.runtimeOrigin
|
|
992
|
+
});
|
|
993
|
+
const idle = state.phase === "idle" && !hasVisitorMessages(state.messages);
|
|
994
|
+
const placement = manifest.placement;
|
|
995
|
+
(0, import_react4.useEffect)(() => {
|
|
996
|
+
registerAgentPanelController(manifest.customerId, {
|
|
997
|
+
open: () => setRailCollapsed(false),
|
|
998
|
+
close: () => {
|
|
999
|
+
setRailCollapsed(true);
|
|
1000
|
+
setRailExpanded(false);
|
|
1001
|
+
}
|
|
1002
|
+
});
|
|
1003
|
+
return () => unregisterAgentPanelController(manifest.customerId);
|
|
1004
|
+
}, [manifest.customerId]);
|
|
1005
|
+
async function handleSubmit(message) {
|
|
1006
|
+
if (isMobile) setRailCollapsed(false);
|
|
1007
|
+
await submit(message);
|
|
1008
|
+
}
|
|
1009
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
1010
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1011
|
+
"div",
|
|
1012
|
+
{
|
|
1013
|
+
className: `webless-agent-root__shell${railCollapsed ? " webless-agent-root__shell--collapsed" : ""}${railExpanded ? " webless-agent-root__shell--expanded" : ""}`,
|
|
1014
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1015
|
+
"div",
|
|
1016
|
+
{
|
|
1017
|
+
className: "webless-agent-root__rail-slot",
|
|
1018
|
+
inert: railCollapsed || void 0,
|
|
1019
|
+
"aria-hidden": railCollapsed,
|
|
1020
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1021
|
+
AgentRail,
|
|
1022
|
+
{
|
|
1023
|
+
state: idle ? {
|
|
1024
|
+
...state,
|
|
1025
|
+
followUps: createIdleSuggestions()
|
|
1026
|
+
} : state,
|
|
1027
|
+
mobileFullscreen: isMobile && !railCollapsed,
|
|
1028
|
+
expanded: railExpanded,
|
|
1029
|
+
onCollapse: !isMobile ? () => setRailCollapsed(true) : void 0,
|
|
1030
|
+
onClose: isMobile ? () => setRailCollapsed(true) : void 0,
|
|
1031
|
+
onExpandToggle: !isMobile ? () => setRailExpanded((current) => !current) : void 0,
|
|
1032
|
+
onSubmit: handleSubmit,
|
|
1033
|
+
onFollowUpSelect: (label) => void handleSubmit(label)
|
|
1034
|
+
}
|
|
1035
|
+
)
|
|
1036
|
+
}
|
|
1037
|
+
)
|
|
1038
|
+
}
|
|
1039
|
+
),
|
|
1040
|
+
!isMobile && railExpanded && !railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1041
|
+
"button",
|
|
1042
|
+
{
|
|
1043
|
+
type: "button",
|
|
1044
|
+
className: "webless-agent-root__backdrop",
|
|
1045
|
+
"aria-label": "Close expanded assist",
|
|
1046
|
+
onClick: () => setRailExpanded(false)
|
|
1047
|
+
}
|
|
1048
|
+
) : null,
|
|
1049
|
+
railCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1050
|
+
AssistEdgeTab,
|
|
1051
|
+
{
|
|
1052
|
+
variant: placement.variant,
|
|
1053
|
+
side: placement.side,
|
|
1054
|
+
along: placement.along,
|
|
1055
|
+
inset: placement.inset,
|
|
1056
|
+
visible: true,
|
|
1057
|
+
onOpen: () => setRailCollapsed(false)
|
|
1058
|
+
}
|
|
1059
|
+
) : null
|
|
1060
|
+
] });
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// src/embed/manifest.ts
|
|
1064
|
+
var DEFAULT_AGENT_PLACEMENT = {
|
|
1065
|
+
side: "right",
|
|
1066
|
+
along: 50,
|
|
1067
|
+
inset: 0,
|
|
1068
|
+
variant: "outline"
|
|
1069
|
+
};
|
|
1070
|
+
function normalizeAgentPlacement(placement) {
|
|
1071
|
+
const along = placement?.along ?? DEFAULT_AGENT_PLACEMENT.along;
|
|
1072
|
+
return {
|
|
1073
|
+
side: placement?.side ?? DEFAULT_AGENT_PLACEMENT.side,
|
|
1074
|
+
along: Math.min(100, Math.max(0, along)),
|
|
1075
|
+
inset: Math.max(0, placement?.inset ?? DEFAULT_AGENT_PLACEMENT.inset),
|
|
1076
|
+
variant: placement?.variant ?? DEFAULT_AGENT_PLACEMENT.variant
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
function normalizeAgentTagManifest(manifest) {
|
|
1080
|
+
const indexId = manifest.indexId.trim();
|
|
1081
|
+
if (!indexId) {
|
|
1082
|
+
throw new Error("Agent manifest requires indexId.");
|
|
1083
|
+
}
|
|
1084
|
+
const customerId = manifest.customerId.trim();
|
|
1085
|
+
if (!customerId) {
|
|
1086
|
+
throw new Error("Agent manifest requires customerId.");
|
|
1087
|
+
}
|
|
1088
|
+
const runtime = resolveAgentRuntimeConfig({
|
|
1089
|
+
indexId,
|
|
1090
|
+
runtimeOrigin: manifest.runtimeOrigin?.trim() || DEFAULT_RUNTIME_ORIGIN
|
|
1091
|
+
});
|
|
1092
|
+
return {
|
|
1093
|
+
customerId,
|
|
1094
|
+
indexId,
|
|
1095
|
+
runtimeOrigin: runtime.origin,
|
|
1096
|
+
version: manifest.version?.trim() || "published",
|
|
1097
|
+
mount: {
|
|
1098
|
+
selector: manifest.mount?.selector?.trim(),
|
|
1099
|
+
strategy: manifest.mount?.strategy ?? "body"
|
|
1100
|
+
},
|
|
1101
|
+
placement: normalizeAgentPlacement(manifest.placement)
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// src/embed/mount.tsx
|
|
1106
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1107
|
+
var mountedHandles = /* @__PURE__ */ new Map();
|
|
1108
|
+
var latestCustomerId = null;
|
|
1109
|
+
function resolveMountHost(manifest, script) {
|
|
1110
|
+
const strategy = manifest.mount.strategy ?? "body";
|
|
1111
|
+
if (strategy === "script-parent" && script?.parentElement instanceof HTMLElement) {
|
|
1112
|
+
return script.parentElement;
|
|
1113
|
+
}
|
|
1114
|
+
if (strategy === "selector" && manifest.mount.selector) {
|
|
1115
|
+
const target = document.querySelector(manifest.mount.selector);
|
|
1116
|
+
if (target instanceof HTMLElement) return target;
|
|
1117
|
+
}
|
|
1118
|
+
return document.body;
|
|
1119
|
+
}
|
|
1120
|
+
function createHost(customerId) {
|
|
1121
|
+
const host = document.createElement("div");
|
|
1122
|
+
host.className = "webless-agent-root";
|
|
1123
|
+
host.dataset.weblessAgentCustomerId = customerId;
|
|
1124
|
+
host.setAttribute("data-webless-agent", customerId);
|
|
1125
|
+
return host;
|
|
1126
|
+
}
|
|
1127
|
+
function mountAgent(input) {
|
|
1128
|
+
const manifest = normalizeAgentTagManifest(input.manifest);
|
|
1129
|
+
const existing = mountedHandles.get(manifest.customerId);
|
|
1130
|
+
if (existing) {
|
|
1131
|
+
return existing;
|
|
1132
|
+
}
|
|
1133
|
+
const mountTarget = resolveMountHost(manifest, input.script ?? null);
|
|
1134
|
+
const host = createHost(manifest.customerId);
|
|
1135
|
+
mountTarget.append(host);
|
|
1136
|
+
const root = (0, import_client4.createRoot)(host);
|
|
1137
|
+
root.render(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AgentWidget, { manifest }));
|
|
1138
|
+
const handle = {
|
|
1139
|
+
customerId: manifest.customerId,
|
|
1140
|
+
manifest,
|
|
1141
|
+
host,
|
|
1142
|
+
root,
|
|
1143
|
+
open: () => {
|
|
1144
|
+
openAgentPanel(manifest.customerId);
|
|
1145
|
+
},
|
|
1146
|
+
close: () => {
|
|
1147
|
+
closeAgentPanel(manifest.customerId);
|
|
1148
|
+
},
|
|
1149
|
+
unmount: () => {
|
|
1150
|
+
root.unmount();
|
|
1151
|
+
host.remove();
|
|
1152
|
+
mountedHandles.delete(manifest.customerId);
|
|
1153
|
+
if (latestCustomerId === manifest.customerId) {
|
|
1154
|
+
latestCustomerId = null;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
};
|
|
1158
|
+
mountedHandles.set(manifest.customerId, handle);
|
|
1159
|
+
latestCustomerId = manifest.customerId;
|
|
1160
|
+
return handle;
|
|
1161
|
+
}
|
|
1162
|
+
function unmountAgent(customerId) {
|
|
1163
|
+
const id = customerId ?? latestCustomerId;
|
|
1164
|
+
if (!id) return false;
|
|
1165
|
+
const handle = mountedHandles.get(id);
|
|
1166
|
+
if (!handle) return false;
|
|
1167
|
+
handle.unmount();
|
|
1168
|
+
return true;
|
|
1169
|
+
}
|
|
1170
|
+
function getMountedAgent(customerId) {
|
|
1171
|
+
if (customerId) return mountedHandles.get(customerId) ?? null;
|
|
1172
|
+
if (latestCustomerId) return mountedHandles.get(latestCustomerId) ?? null;
|
|
1173
|
+
return mountedHandles.values().next().value ?? null;
|
|
1174
|
+
}
|
|
1175
|
+
function bootstrapAgent(manifest, script) {
|
|
1176
|
+
return mountAgent({ manifest, script });
|
|
1177
|
+
}
|
|
1178
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1179
|
+
0 && (module.exports = {
|
|
1180
|
+
DEFAULT_AGENT_PLACEMENT,
|
|
1181
|
+
bootstrapAgent,
|
|
1182
|
+
getMountedAgent,
|
|
1183
|
+
mountAgent,
|
|
1184
|
+
normalizeAgentPlacement,
|
|
1185
|
+
normalizeAgentTagManifest,
|
|
1186
|
+
unmountAgent
|
|
1187
|
+
});
|
|
1188
|
+
//# sourceMappingURL=embed.cjs.map
|