@pluno/product-agent-web 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INTEGRATION.md +1 -1
- package/README.md +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/product-agent-sdk.js +76 -59
- package/dist/product-agent-widget.js +367 -222
- package/package.json +3 -8
package/INTEGRATION.md
CHANGED
|
@@ -65,7 +65,7 @@ redaction pipeline before data leaves the browser.
|
|
|
65
65
|
```html
|
|
66
66
|
<script
|
|
67
67
|
type="module"
|
|
68
|
-
src="https://
|
|
68
|
+
src="https://app.pluno.ai/product-agent/product-agent-widget.js"
|
|
69
69
|
data-pluno-token-endpoint="/api/pluno-product-agent-token"
|
|
70
70
|
data-pluno-launcher-label="Ask AI..."
|
|
71
71
|
data-pluno-accent-color="#18181b"
|
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ The SDK always captures product network activity by patching `fetch` and `XMLHtt
|
|
|
40
40
|
```html
|
|
41
41
|
<script
|
|
42
42
|
type="module"
|
|
43
|
-
src="https://
|
|
43
|
+
src="https://app.pluno.ai/product-agent/product-agent-widget.js"
|
|
44
44
|
data-pluno-token-endpoint="/api/pluno-product-agent-token"
|
|
45
45
|
data-pluno-launcher-label="Ask AI..."
|
|
46
46
|
data-pluno-accent-color="#18181b"
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export type ProductAgentState = {
|
|
|
22
22
|
status: "idle" | "connecting" | "connected" | "reconnecting" | "closed" | "error";
|
|
23
23
|
user: ProductAgentUser | null;
|
|
24
24
|
sessionId: string | null;
|
|
25
|
+
starterPrompts: string[];
|
|
25
26
|
messages: ProductAgentMessage[];
|
|
26
27
|
assistantDraft: string;
|
|
27
28
|
isThinking: boolean;
|
|
@@ -3,7 +3,7 @@ const A = "pluno.productAgent.state.";
|
|
|
3
3
|
class I {
|
|
4
4
|
constructor(t) {
|
|
5
5
|
this.options = t;
|
|
6
|
-
const s =
|
|
6
|
+
const s = W(t.clientId);
|
|
7
7
|
s && (this.state = {
|
|
8
8
|
...this.state,
|
|
9
9
|
...s,
|
|
@@ -28,6 +28,7 @@ class I {
|
|
|
28
28
|
status: "idle",
|
|
29
29
|
user: null,
|
|
30
30
|
sessionId: null,
|
|
31
|
+
starterPrompts: [],
|
|
31
32
|
messages: [],
|
|
32
33
|
assistantDraft: "",
|
|
33
34
|
isThinking: !1,
|
|
@@ -36,8 +37,8 @@ class I {
|
|
|
36
37
|
static async init(t) {
|
|
37
38
|
const s = new I({
|
|
38
39
|
...t,
|
|
39
|
-
backendUrl:
|
|
40
|
-
clientId: t.clientId ??
|
|
40
|
+
backendUrl: H(t.backendUrl ?? O),
|
|
41
|
+
clientId: t.clientId ?? x()
|
|
41
42
|
});
|
|
42
43
|
try {
|
|
43
44
|
s.enableNetworkCapture(), t.autoConnect !== !1 && await s.connect();
|
|
@@ -53,6 +54,7 @@ class I {
|
|
|
53
54
|
getState() {
|
|
54
55
|
return {
|
|
55
56
|
...this.state,
|
|
57
|
+
starterPrompts: [...this.state.starterPrompts],
|
|
56
58
|
messages: [...this.state.messages]
|
|
57
59
|
};
|
|
58
60
|
}
|
|
@@ -82,7 +84,7 @@ class I {
|
|
|
82
84
|
const s = t.trim();
|
|
83
85
|
if (!s)
|
|
84
86
|
return;
|
|
85
|
-
const n =
|
|
87
|
+
const n = m(), r = {
|
|
86
88
|
id: `local-${Date.now()}`,
|
|
87
89
|
role: "user",
|
|
88
90
|
content: s,
|
|
@@ -106,8 +108,13 @@ class I {
|
|
|
106
108
|
this.state.sessionId && (this.send({ type: "run.stop", sessionId: this.state.sessionId }), this.setState({ isThinking: !1 }));
|
|
107
109
|
}
|
|
108
110
|
startNewSession() {
|
|
109
|
-
this.state.sessionId && this.state.isThinking && this.sendNow({ type: "run.stop", sessionId: this.state.sessionId }), this.queuedClientEvents = this.queuedClientEvents.filter((t) => t.type !== "chat.user_message"), this.
|
|
111
|
+
this.state.sessionId && this.state.isThinking && this.sendNow({ type: "run.stop", sessionId: this.state.sessionId }), this.queuedClientEvents = this.queuedClientEvents.filter((t) => t.type !== "chat.user_message"), this.send({
|
|
112
|
+
type: "session.reset",
|
|
113
|
+
sessionId: this.state.sessionId ?? void 0,
|
|
114
|
+
page: m()
|
|
115
|
+
}), this.setState({
|
|
110
116
|
sessionId: null,
|
|
117
|
+
starterPrompts: [...this.state.starterPrompts],
|
|
111
118
|
messages: [],
|
|
112
119
|
assistantDraft: "",
|
|
113
120
|
isThinking: !1,
|
|
@@ -134,13 +141,17 @@ class I {
|
|
|
134
141
|
}
|
|
135
142
|
handleServerEvent(t) {
|
|
136
143
|
if (t.type === "auth.ok") {
|
|
137
|
-
this.setState({
|
|
144
|
+
this.setState({
|
|
145
|
+
user: $(t.user),
|
|
146
|
+
starterPrompts: B(t, "starterPrompts"),
|
|
147
|
+
status: "connected"
|
|
148
|
+
});
|
|
138
149
|
return;
|
|
139
150
|
}
|
|
140
151
|
if (t.type === "conversation.state") {
|
|
141
152
|
this.setState({
|
|
142
153
|
sessionId: _(t.session, "id") ?? this.state.sessionId,
|
|
143
|
-
messages:
|
|
154
|
+
messages: j(t.items)
|
|
144
155
|
});
|
|
145
156
|
return;
|
|
146
157
|
}
|
|
@@ -151,7 +162,7 @@ class I {
|
|
|
151
162
|
if (t.type === "session.item") {
|
|
152
163
|
const s = R(t.item);
|
|
153
164
|
s && (this.setState({
|
|
154
|
-
messages:
|
|
165
|
+
messages: F(this.state.messages, s),
|
|
155
166
|
assistantDraft: s.role === "assistant" ? "" : this.state.assistantDraft
|
|
156
167
|
}), this.emit("message", s));
|
|
157
168
|
return;
|
|
@@ -177,9 +188,9 @@ class I {
|
|
|
177
188
|
}
|
|
178
189
|
async executeToolCall(t) {
|
|
179
190
|
const s = typeof t.sessionId == "string" ? t.sessionId : null, n = typeof t.callId == "string" ? t.callId : null, r = t.rawInput;
|
|
180
|
-
if (!s || !n || !
|
|
191
|
+
if (!s || !n || !Y(r))
|
|
181
192
|
return;
|
|
182
|
-
const i = await
|
|
193
|
+
const i = await P(r).catch((a) => ({
|
|
183
194
|
ok: !1,
|
|
184
195
|
exception: {
|
|
185
196
|
message: a instanceof Error ? a.message : String(a)
|
|
@@ -200,19 +211,19 @@ class I {
|
|
|
200
211
|
return;
|
|
201
212
|
const t = window.fetch.bind(window), s = XMLHttpRequest.prototype.open, n = XMLHttpRequest.prototype.setRequestHeader, r = XMLHttpRequest.prototype.send;
|
|
202
213
|
window.fetch = async (i, a) => {
|
|
203
|
-
const o = Date.now(), c = new Date(o).toISOString(), u = i instanceof Request ? i : null, f = typeof i == "string" ? i : i instanceof URL ? i.toString() : u?.url ?? "",
|
|
214
|
+
const o = Date.now(), c = new Date(o).toISOString(), u = i instanceof Request ? i : null, f = typeof i == "string" ? i : i instanceof URL ? i.toString() : u?.url ?? "", w = (a?.method ?? u?.method ?? "GET").toUpperCase(), E = k(new Headers(a?.headers ?? u?.headers ?? void 0)), T = await V(u, a);
|
|
204
215
|
try {
|
|
205
216
|
const l = await t(i, a);
|
|
206
217
|
return this.enqueueNetworkEvent({
|
|
207
218
|
requestId: g("fetch"),
|
|
208
219
|
url: f,
|
|
209
|
-
method:
|
|
210
|
-
requestHeaders:
|
|
211
|
-
requestBody:
|
|
220
|
+
method: w,
|
|
221
|
+
requestHeaders: E,
|
|
222
|
+
requestBody: T,
|
|
212
223
|
resourceType: "fetch",
|
|
213
224
|
responseStatus: l.status,
|
|
214
225
|
responseHeaders: k(l.headers),
|
|
215
|
-
responseBody: await
|
|
226
|
+
responseBody: await Z(l),
|
|
216
227
|
startedAt: c,
|
|
217
228
|
durationMs: Date.now() - o
|
|
218
229
|
}), l;
|
|
@@ -220,9 +231,9 @@ class I {
|
|
|
220
231
|
throw this.enqueueNetworkEvent({
|
|
221
232
|
requestId: g("fetch"),
|
|
222
233
|
url: f,
|
|
223
|
-
method:
|
|
224
|
-
requestHeaders:
|
|
225
|
-
requestBody:
|
|
234
|
+
method: w,
|
|
235
|
+
requestHeaders: E,
|
|
236
|
+
requestBody: T,
|
|
226
237
|
resourceType: "fetch",
|
|
227
238
|
errorText: l instanceof Error ? l.message : String(l),
|
|
228
239
|
startedAt: c,
|
|
@@ -265,8 +276,8 @@ class I {
|
|
|
265
276
|
requestBody: typeof this.__plunoMeta.requestBody == "string" ? this.__plunoMeta.requestBody : void 0,
|
|
266
277
|
resourceType: "xhr",
|
|
267
278
|
responseStatus: this.status,
|
|
268
|
-
responseHeaders:
|
|
269
|
-
responseBody:
|
|
279
|
+
responseHeaders: tt(this.getAllResponseHeaders()),
|
|
280
|
+
responseBody: Q(this),
|
|
270
281
|
errorText: this.status === 0 ? "XHR request failed or was aborted" : void 0,
|
|
271
282
|
startedAt: String(this.__plunoMeta.startedAt),
|
|
272
283
|
durationMs: Date.now() - Number(this.__plunoMeta.startedAtMs ?? Date.now())
|
|
@@ -285,7 +296,7 @@ class I {
|
|
|
285
296
|
s.length === 0 || this.socket?.readyState !== WebSocket.OPEN || this.sendNow({
|
|
286
297
|
type: "network.batch",
|
|
287
298
|
sessionId: this.state.sessionId ?? void 0,
|
|
288
|
-
page:
|
|
299
|
+
page: m(),
|
|
289
300
|
events: s
|
|
290
301
|
});
|
|
291
302
|
}, 1e3));
|
|
@@ -306,13 +317,13 @@ class I {
|
|
|
306
317
|
this.heartbeatTimer !== null && (window.clearInterval(this.heartbeatTimer), this.heartbeatTimer = null);
|
|
307
318
|
}
|
|
308
319
|
setState(t) {
|
|
309
|
-
this.state = { ...this.state, ...t },
|
|
320
|
+
this.state = { ...this.state, ...t }, J(this.options.clientId, this.state), this.emit("state", this.getState());
|
|
310
321
|
}
|
|
311
322
|
emit(t, s) {
|
|
312
323
|
this.listeners[t]?.forEach((r) => r(s));
|
|
313
324
|
}
|
|
314
325
|
}
|
|
315
|
-
async function
|
|
326
|
+
async function P(e) {
|
|
316
327
|
const t = Object.getPrototypeOf(async function() {
|
|
317
328
|
}).constructor, s = e.timeoutMs ?? 15e3, n = Date.now(), r = [], i = {
|
|
318
329
|
log: console.log,
|
|
@@ -358,14 +369,14 @@ async function H(e) {
|
|
|
358
369
|
console.log = i.log, console.info = i.info, console.warn = i.warn, console.error = i.error;
|
|
359
370
|
}
|
|
360
371
|
}
|
|
361
|
-
function
|
|
372
|
+
function H(e) {
|
|
362
373
|
return e.replace(/\/+$/, "");
|
|
363
374
|
}
|
|
364
375
|
function U(e) {
|
|
365
376
|
const t = new URL("/api/product-agent/embed/ws", e);
|
|
366
377
|
return t.protocol = t.protocol === "https:" ? "wss:" : "ws:", t.toString();
|
|
367
378
|
}
|
|
368
|
-
function
|
|
379
|
+
function m() {
|
|
369
380
|
return {
|
|
370
381
|
url: location.href,
|
|
371
382
|
title: document.title,
|
|
@@ -380,14 +391,20 @@ function L(e) {
|
|
|
380
391
|
return { type: "error", message: "Invalid server event" };
|
|
381
392
|
}
|
|
382
393
|
}
|
|
383
|
-
function B() {
|
|
394
|
+
function B(e, t) {
|
|
395
|
+
if (!e || typeof e != "object")
|
|
396
|
+
return [];
|
|
397
|
+
const s = e[t];
|
|
398
|
+
return Array.isArray(s) ? s.filter((n) => typeof n == "string" && n.trim().length > 0) : [];
|
|
399
|
+
}
|
|
400
|
+
function x() {
|
|
384
401
|
const e = "pluno.productAgent.clientId", t = window.localStorage.getItem(e);
|
|
385
402
|
if (t)
|
|
386
403
|
return t;
|
|
387
404
|
const s = crypto.randomUUID();
|
|
388
405
|
return window.localStorage.setItem(e, s), s;
|
|
389
406
|
}
|
|
390
|
-
function
|
|
407
|
+
function $(e) {
|
|
391
408
|
if (!e || typeof e != "object")
|
|
392
409
|
return null;
|
|
393
410
|
const t = e, s = typeof t.id == "string" ? t.id : null;
|
|
@@ -398,7 +415,7 @@ function x(e) {
|
|
|
398
415
|
avatarUrl: typeof t.avatarUrl == "string" ? t.avatarUrl : null
|
|
399
416
|
} : null;
|
|
400
417
|
}
|
|
401
|
-
function
|
|
418
|
+
function j(e) {
|
|
402
419
|
return Array.isArray(e) ? e.map(R).filter((t) => t !== null) : [];
|
|
403
420
|
}
|
|
404
421
|
function R(e) {
|
|
@@ -413,20 +430,20 @@ function R(e) {
|
|
|
413
430
|
return {
|
|
414
431
|
id: String(t.id ?? crypto.randomUUID()),
|
|
415
432
|
role: r,
|
|
416
|
-
content:
|
|
433
|
+
content: z(n.content),
|
|
417
434
|
createdAt: typeof t.createdAt == "string" ? t.createdAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
418
435
|
};
|
|
419
436
|
}
|
|
420
437
|
return n.type === "function_call" || n.type === "tool_call" || n.type === "web_search_call" ? {
|
|
421
438
|
id: String(t.id ?? crypto.randomUUID()),
|
|
422
439
|
role: "tool",
|
|
423
|
-
content:
|
|
440
|
+
content: X(n),
|
|
424
441
|
createdAt: typeof t.createdAt == "string" ? t.createdAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
425
442
|
dataType: String(n.type),
|
|
426
443
|
loading: n.localExecutionStatus === "running"
|
|
427
444
|
} : null;
|
|
428
445
|
}
|
|
429
|
-
function
|
|
446
|
+
function X(e) {
|
|
430
447
|
if (e.type === "web_search_call") {
|
|
431
448
|
const t = e.action;
|
|
432
449
|
if (t && typeof t == "object") {
|
|
@@ -438,9 +455,9 @@ function j(e) {
|
|
|
438
455
|
}
|
|
439
456
|
return "Searching the web";
|
|
440
457
|
}
|
|
441
|
-
return
|
|
458
|
+
return v(e);
|
|
442
459
|
}
|
|
443
|
-
function
|
|
460
|
+
function v(e) {
|
|
444
461
|
if (typeof e.summary == "string" && e.summary.trim().length > 0)
|
|
445
462
|
return e.summary;
|
|
446
463
|
if (typeof e.arguments == "string")
|
|
@@ -453,7 +470,7 @@ function X(e) {
|
|
|
453
470
|
}
|
|
454
471
|
return typeof e.name == "string" && e.name.trim().length > 0 ? e.name : "Run tool";
|
|
455
472
|
}
|
|
456
|
-
function
|
|
473
|
+
function z(e) {
|
|
457
474
|
return typeof e == "string" ? e : Array.isArray(e) ? e.map((t) => {
|
|
458
475
|
if (!t || typeof t != "object")
|
|
459
476
|
return "";
|
|
@@ -461,14 +478,14 @@ function v(e) {
|
|
|
461
478
|
return typeof s.text == "string" ? s.text : typeof s.content == "string" ? s.content : "";
|
|
462
479
|
}).filter(Boolean).join("") : "";
|
|
463
480
|
}
|
|
464
|
-
function
|
|
465
|
-
const s =
|
|
481
|
+
function F(e, t) {
|
|
482
|
+
const s = G(e, t), n = s.findIndex((i) => i.id === t.id);
|
|
466
483
|
if (n === -1)
|
|
467
484
|
return [...s, t];
|
|
468
485
|
const r = [...s];
|
|
469
486
|
return r[n] = t, r;
|
|
470
487
|
}
|
|
471
|
-
function
|
|
488
|
+
function G(e, t) {
|
|
472
489
|
if (t.role !== "user")
|
|
473
490
|
return e;
|
|
474
491
|
const s = e.findIndex(
|
|
@@ -482,12 +499,12 @@ function F(e, t) {
|
|
|
482
499
|
function _(e, t) {
|
|
483
500
|
return e && typeof e == "object" && typeof e[t] == "string" ? e[t] : null;
|
|
484
501
|
}
|
|
485
|
-
function
|
|
502
|
+
function W(e) {
|
|
486
503
|
try {
|
|
487
504
|
const t = window.localStorage.getItem(`${A}${e}`);
|
|
488
505
|
if (!t)
|
|
489
506
|
return null;
|
|
490
|
-
const s = JSON.parse(t), n = Array.isArray(s.messages) ? s.messages.map(
|
|
507
|
+
const s = JSON.parse(t), n = Array.isArray(s.messages) ? s.messages.map(K).filter((r) => !!r) : [];
|
|
491
508
|
return {
|
|
492
509
|
sessionId: typeof s.sessionId == "string" ? s.sessionId : null,
|
|
493
510
|
messages: n
|
|
@@ -496,7 +513,7 @@ function G(e) {
|
|
|
496
513
|
return null;
|
|
497
514
|
}
|
|
498
515
|
}
|
|
499
|
-
function
|
|
516
|
+
function J(e, t) {
|
|
500
517
|
try {
|
|
501
518
|
window.localStorage.setItem(
|
|
502
519
|
`${A}${e}`,
|
|
@@ -509,7 +526,7 @@ function W(e, t) {
|
|
|
509
526
|
return;
|
|
510
527
|
}
|
|
511
528
|
}
|
|
512
|
-
function
|
|
529
|
+
function K(e) {
|
|
513
530
|
if (!e || typeof e != "object")
|
|
514
531
|
return null;
|
|
515
532
|
const t = e;
|
|
@@ -522,7 +539,7 @@ function J(e) {
|
|
|
522
539
|
loading: typeof t.loading == "boolean" ? t.loading : void 0
|
|
523
540
|
};
|
|
524
541
|
}
|
|
525
|
-
function
|
|
542
|
+
function Y(e) {
|
|
526
543
|
return !!e && typeof e == "object" && typeof e.summary == "string" && typeof e.javascript == "string";
|
|
527
544
|
}
|
|
528
545
|
function k(e) {
|
|
@@ -531,7 +548,7 @@ function k(e) {
|
|
|
531
548
|
t[n] = s;
|
|
532
549
|
}), t;
|
|
533
550
|
}
|
|
534
|
-
async function
|
|
551
|
+
async function V(e, t) {
|
|
535
552
|
if (typeof t?.body < "u")
|
|
536
553
|
return C(t.body);
|
|
537
554
|
if (e)
|
|
@@ -541,14 +558,14 @@ async function Y(e, t) {
|
|
|
541
558
|
return;
|
|
542
559
|
}
|
|
543
560
|
}
|
|
544
|
-
async function
|
|
561
|
+
async function Z(e) {
|
|
545
562
|
try {
|
|
546
563
|
return p(await e.clone().text());
|
|
547
564
|
} catch (t) {
|
|
548
565
|
return { error: t instanceof Error ? t.message : "unavailable" };
|
|
549
566
|
}
|
|
550
567
|
}
|
|
551
|
-
function
|
|
568
|
+
function Q(e) {
|
|
552
569
|
try {
|
|
553
570
|
return e.responseType === "" || e.responseType === "text" ? p(e.responseText ?? "") : e.responseType === "json" ? p(JSON.stringify(e.response)) : `[unsupported xhr responseType: ${e.responseType || "unknown"}]`;
|
|
554
571
|
} catch (t) {
|
|
@@ -574,7 +591,7 @@ function C(e) {
|
|
|
574
591
|
}
|
|
575
592
|
}
|
|
576
593
|
}
|
|
577
|
-
function
|
|
594
|
+
function tt(e) {
|
|
578
595
|
const t = {};
|
|
579
596
|
for (const s of e.trim().split(/[\r\n]+/)) {
|
|
580
597
|
const n = s.indexOf(":");
|
|
@@ -588,16 +605,16 @@ function p(e) {
|
|
|
588
605
|
function g(e) {
|
|
589
606
|
return `${e}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
590
607
|
}
|
|
591
|
-
const
|
|
608
|
+
const S = "[REDACTED_SECRET]", d = "[REDACTED_TOKEN]", et = "[REDACTED_SIGNED_URL]", st = 20, nt = /^(access_token|accessToken|refresh_token|refreshToken|id_token|idToken|authToken|token|api_key|apiKey|apikey|key|secret|signature|sig|password|passwd|pwd|code|state|session|jwt|csrf|csrfToken|xsrf|xsrfToken)$/i, N = /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/gi, D = /\bBasic\s+[A-Za-z0-9+/=-]{12,}/gi, M = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, b = /\b(access_token|accessToken|refresh_token|refreshToken|id_token|idToken|authToken|api_key|apiKey|apikey|client_secret|clientSecret|password|secret|token|jwt|csrf|csrfToken|xsrf|xsrfToken)\b\s*[:=]\s*["']?[^"',&\s}]+/gi, rt = /\bhttps?:\/\/[^\s"'<>]+(?:X-Amz-Signature|X-Goog-Signature|Signature|sig=)[^\s"'<>]*/gi, ot = /\bhttps?:\/\/[^\s"'<>]+/gi, it = /[),.;\]]+$/;
|
|
592
609
|
function h(e) {
|
|
593
610
|
return y(e, 0, /* @__PURE__ */ new WeakSet());
|
|
594
611
|
}
|
|
595
612
|
function y(e, t, s) {
|
|
596
613
|
if (typeof e == "string")
|
|
597
|
-
return
|
|
614
|
+
return ut(e);
|
|
598
615
|
if (e === null || typeof e != "object")
|
|
599
616
|
return e;
|
|
600
|
-
if (t >=
|
|
617
|
+
if (t >= st)
|
|
601
618
|
return "[REDACTED_MAX_DEPTH]";
|
|
602
619
|
if (s.has(e))
|
|
603
620
|
return "[REDACTED_CIRCULAR]";
|
|
@@ -605,34 +622,34 @@ function y(e, t, s) {
|
|
|
605
622
|
return e.map((r) => y(r, t + 1, s));
|
|
606
623
|
const n = {};
|
|
607
624
|
for (const [r, i] of Object.entries(e))
|
|
608
|
-
|
|
625
|
+
at(r) ? n[r] = S : n[r] = r.toLowerCase() === "url" ? ct(i) : y(i, t + 1, s);
|
|
609
626
|
return n;
|
|
610
627
|
}
|
|
611
|
-
function
|
|
628
|
+
function at(e) {
|
|
612
629
|
const t = e.replace(/[^a-z0-9]/gi, "").toLowerCase();
|
|
613
630
|
return t.includes("authorization") || t.includes("cookie") || t.includes("password") || t.includes("passwd") || t === "pwd" || t.includes("secret") || t === "token" || t.endsWith("token") || t.includes("apikey") || t.includes("csrf") || t.includes("xsrf") || t === "jwt" || t === "session" || t === "signature" || t.includes("privatekey");
|
|
614
631
|
}
|
|
615
|
-
function
|
|
632
|
+
function ct(e) {
|
|
616
633
|
return typeof e == "string" ? q(e) : y(e, 0, /* @__PURE__ */ new WeakSet());
|
|
617
634
|
}
|
|
618
635
|
function q(e) {
|
|
619
636
|
try {
|
|
620
637
|
const t = new URL(e, location.href);
|
|
621
638
|
for (const s of Array.from(t.searchParams.keys()))
|
|
622
|
-
|
|
639
|
+
nt.test(s) && t.searchParams.set(s, d);
|
|
623
640
|
return t.username && (t.username = d), t.password && (t.password = d), t.toString();
|
|
624
641
|
} catch {
|
|
625
|
-
return
|
|
642
|
+
return lt(e);
|
|
626
643
|
}
|
|
627
644
|
}
|
|
628
|
-
function ct(e) {
|
|
629
|
-
return e.replace(nt, tt).replace(rt, lt).replace(N, `Bearer ${d}`).replace(D, `Basic ${d}`).replace(M, d).replace(b, (t, s) => `${s}: ${m}`);
|
|
630
|
-
}
|
|
631
645
|
function ut(e) {
|
|
632
|
-
return e.replace(N, `Bearer ${d}`).replace(D, `Basic ${d}`).replace(M, d).replace(b, (t, s) => `${s}: ${
|
|
646
|
+
return e.replace(rt, et).replace(ot, dt).replace(N, `Bearer ${d}`).replace(D, `Basic ${d}`).replace(M, d).replace(b, (t, s) => `${s}: ${S}`);
|
|
633
647
|
}
|
|
634
648
|
function lt(e) {
|
|
635
|
-
|
|
649
|
+
return e.replace(N, `Bearer ${d}`).replace(D, `Basic ${d}`).replace(M, d).replace(b, (t, s) => `${s}: ${S}`);
|
|
650
|
+
}
|
|
651
|
+
function dt(e) {
|
|
652
|
+
const t = e.match(it)?.[0] ?? "", s = t ? e.slice(0, -t.length) : e;
|
|
636
653
|
return `${q(s)}${t}`;
|
|
637
654
|
}
|
|
638
655
|
export {
|
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
import { PlunoProductAgent as
|
|
2
|
-
const
|
|
1
|
+
import { PlunoProductAgent as q } from "./product-agent-sdk.js";
|
|
2
|
+
const L = {
|
|
3
3
|
launcherLabel: "Ask AI...",
|
|
4
4
|
accentColor: "#18181b",
|
|
5
5
|
colorScheme: "light",
|
|
6
6
|
position: "bottom-right"
|
|
7
7
|
};
|
|
8
|
-
async function
|
|
9
|
-
const
|
|
10
|
-
launcherLabel: e.launcherLabel ??
|
|
11
|
-
accentColor: e.accentColor ??
|
|
12
|
-
colorScheme: e.colorScheme ??
|
|
13
|
-
position: e.position ??
|
|
8
|
+
async function K(e = {}) {
|
|
9
|
+
const t = {
|
|
10
|
+
launcherLabel: e.launcherLabel ?? L.launcherLabel,
|
|
11
|
+
accentColor: e.accentColor ?? L.accentColor,
|
|
12
|
+
colorScheme: e.colorScheme ?? L.colorScheme,
|
|
13
|
+
position: e.position ?? L.position,
|
|
14
14
|
token: e.token,
|
|
15
15
|
tokenProvider: e.tokenProvider,
|
|
16
16
|
tokenEndpoint: e.tokenEndpoint,
|
|
17
17
|
backendUrl: e.backendUrl,
|
|
18
18
|
webSocketFactory: e.webSocketFactory
|
|
19
|
-
},
|
|
20
|
-
|
|
19
|
+
}, o = document.createElement("div");
|
|
20
|
+
o.className = "pluno-pa-widget-host";
|
|
21
|
+
const n = o.attachShadow({ mode: "open" }), a = document.createElement("div");
|
|
22
|
+
a.className = `pluno-pa-widget pluno-pa-widget--${t.position}`, a.innerHTML = `
|
|
21
23
|
<form class="pluno-pa-widget__launcher">
|
|
22
|
-
<input class="pluno-pa-widget__launcher-input" type="text" placeholder="${
|
|
24
|
+
<input class="pluno-pa-widget__launcher-input" type="text" placeholder="${W(t.launcherLabel)}" aria-label="${W(t.launcherLabel)}" />
|
|
23
25
|
</form>
|
|
24
26
|
<button type="button" class="pluno-pa-widget__close" aria-label="Close" hidden>
|
|
25
27
|
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
@@ -50,278 +52,341 @@ async function I(e = {}) {
|
|
|
50
52
|
</div>
|
|
51
53
|
</form>
|
|
52
54
|
</section>
|
|
53
|
-
`,
|
|
54
|
-
const
|
|
55
|
-
|
|
55
|
+
`, n.appendChild(a);
|
|
56
|
+
const w = await R(), s = w.ownerDocument;
|
|
57
|
+
w.appendChild(o), a.classList.add(`pluno-pa-widget--${t.colorScheme}`), I(n, t.accentColor);
|
|
58
|
+
const l = a.querySelector(".pluno-pa-widget__launcher"), d = a.querySelector(".pluno-pa-widget__launcher-input"), r = a.querySelector(".pluno-pa-widget__panel"), c = a.querySelector(".pluno-pa-widget__close"), h = a.querySelector(".pluno-pa-widget__composer"), i = a.querySelector(".pluno-pa-widget__input"), p = a.querySelector(".pluno-pa-widget__send"), g = a.querySelector(".pluno-pa-widget__new-chat"), b = a.querySelector(".pluno-pa-widget__timeline");
|
|
59
|
+
if (!l || !d || !r || !c || !h || !i || !p || !g || !b)
|
|
56
60
|
throw new Error("Failed to mount Product Agent widget");
|
|
57
|
-
const
|
|
58
|
-
if (!
|
|
61
|
+
const _ = t.token || t.webSocketFactory ? void 0 : t.tokenProvider ?? (async () => {
|
|
62
|
+
if (!t.tokenEndpoint)
|
|
59
63
|
throw new Error("Product Agent widget requires token or tokenEndpoint");
|
|
60
|
-
const
|
|
64
|
+
const u = await fetch(t.tokenEndpoint, {
|
|
61
65
|
method: "POST",
|
|
62
66
|
credentials: "include",
|
|
63
67
|
headers: { "content-type": "application/json" },
|
|
64
68
|
body: JSON.stringify({ origin: location.origin, url: location.href })
|
|
65
69
|
});
|
|
66
|
-
if (!
|
|
70
|
+
if (!u.ok)
|
|
67
71
|
throw new Error("Failed to load Product Agent token");
|
|
68
|
-
const
|
|
69
|
-
if (!
|
|
72
|
+
const y = await u.json();
|
|
73
|
+
if (!y.token)
|
|
70
74
|
throw new Error("Product Agent token endpoint did not return a token");
|
|
71
|
-
return
|
|
72
|
-
}),
|
|
73
|
-
token:
|
|
74
|
-
tokenProvider:
|
|
75
|
-
backendUrl:
|
|
76
|
-
webSocketFactory:
|
|
77
|
-
}),
|
|
78
|
-
let
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
75
|
+
return y.token;
|
|
76
|
+
}), m = await q.init({
|
|
77
|
+
token: t.token,
|
|
78
|
+
tokenProvider: _,
|
|
79
|
+
backendUrl: t.backendUrl,
|
|
80
|
+
webSocketFactory: t.webSocketFactory
|
|
81
|
+
}), E = J(t), S = new Set(E.openToolGroupKeys);
|
|
82
|
+
let x = null, z = !1;
|
|
83
|
+
const H = () => {
|
|
84
|
+
z || typeof document > "u" || (I(n, t.accentColor), o.isConnected || s.body?.appendChild(o));
|
|
85
|
+
}, P = new MutationObserver(H);
|
|
86
|
+
P.observe(s.documentElement, { childList: !0, subtree: !0 });
|
|
87
|
+
const v = () => {
|
|
88
|
+
Z(t, {
|
|
89
|
+
isOpen: a.classList.contains("pluno-pa-widget--open"),
|
|
90
|
+
composerValue: i.value,
|
|
91
|
+
openToolGroupKeys: [...S]
|
|
84
92
|
});
|
|
85
|
-
},
|
|
86
|
-
if (
|
|
87
|
-
|
|
93
|
+
}, k = (u = "", y = !0) => {
|
|
94
|
+
if (x !== null && (window.clearTimeout(x), x = null), r.hidden = !1, c.hidden = !1, a.classList.remove("pluno-pa-widget--closing"), !y) {
|
|
95
|
+
a.classList.add("pluno-pa-widget--open"), l.hidden = !0, u && (i.value = u, C(i)), i.focus(), i.setSelectionRange(i.value.length, i.value.length), v();
|
|
88
96
|
return;
|
|
89
97
|
}
|
|
90
98
|
window.requestAnimationFrame(() => {
|
|
91
|
-
|
|
92
|
-
|
|
99
|
+
a.classList.add("pluno-pa-widget--open"), u && (i.value = u, C(i)), i.focus(), i.setSelectionRange(i.value.length, i.value.length), v(), x = window.setTimeout(() => {
|
|
100
|
+
l.hidden = !0;
|
|
93
101
|
}, 220);
|
|
94
102
|
});
|
|
95
|
-
},
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
}, A = () => {
|
|
104
|
+
x !== null && (window.clearTimeout(x), x = null), l.hidden = !1, a.classList.add("pluno-pa-widget--closing"), a.classList.remove("pluno-pa-widget--open"), v(), x = window.setTimeout(() => {
|
|
105
|
+
r.hidden = !0, c.hidden = !0, a.classList.remove("pluno-pa-widget--closing");
|
|
98
106
|
}, 220);
|
|
99
107
|
};
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}),
|
|
103
|
-
|
|
104
|
-
}),
|
|
105
|
-
if (!
|
|
108
|
+
l.addEventListener("submit", (u) => {
|
|
109
|
+
u.preventDefault(), k(d.value), d.value = "";
|
|
110
|
+
}), d.addEventListener("focus", () => {
|
|
111
|
+
k(d.value), d.value = "";
|
|
112
|
+
}), d.addEventListener("input", () => {
|
|
113
|
+
if (!d.value)
|
|
106
114
|
return;
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
}),
|
|
110
|
-
const
|
|
111
|
-
if (!(!
|
|
112
|
-
if (
|
|
113
|
-
|
|
115
|
+
const u = d.value;
|
|
116
|
+
k(u), d.value = "";
|
|
117
|
+
}), c.addEventListener("click", A);
|
|
118
|
+
const M = (u) => {
|
|
119
|
+
if (!(!u.metaKey || u.key.toLowerCase() !== "k")) {
|
|
120
|
+
if (u.preventDefault(), r.hidden || !a.classList.contains("pluno-pa-widget--open")) {
|
|
121
|
+
k();
|
|
114
122
|
return;
|
|
115
123
|
}
|
|
116
|
-
|
|
124
|
+
A();
|
|
117
125
|
}
|
|
118
126
|
};
|
|
119
|
-
return
|
|
120
|
-
|
|
121
|
-
}),
|
|
122
|
-
if (
|
|
123
|
-
|
|
127
|
+
return s.addEventListener("keydown", M), h.addEventListener("submit", (u) => {
|
|
128
|
+
u.preventDefault(), N(m, i);
|
|
129
|
+
}), p.addEventListener("click", () => {
|
|
130
|
+
if (m.getState().isThinking) {
|
|
131
|
+
m.stop();
|
|
124
132
|
return;
|
|
125
133
|
}
|
|
126
|
-
|
|
127
|
-
}),
|
|
128
|
-
|
|
129
|
-
}),
|
|
130
|
-
|
|
131
|
-
}),
|
|
132
|
-
|
|
133
|
-
}),
|
|
134
|
+
N(m, i);
|
|
135
|
+
}), g.addEventListener("click", () => {
|
|
136
|
+
m.startNewSession(), S.clear(), i.value = "", C(i), v(), i.focus();
|
|
137
|
+
}), i.addEventListener("input", () => {
|
|
138
|
+
C(i), v();
|
|
139
|
+
}), i.addEventListener("keydown", (u) => {
|
|
140
|
+
u.key !== "Enter" || u.shiftKey || (u.preventDefault(), N(m, i));
|
|
141
|
+
}), E.composerValue && (i.value = E.composerValue, C(i)), E.isOpen && k(i.value, !1), m.on(
|
|
134
142
|
"state",
|
|
135
|
-
(
|
|
136
|
-
|
|
137
|
-
|
|
143
|
+
(u) => $(b, p, g, u, S, v, (y) => {
|
|
144
|
+
m.sendMessage(y);
|
|
145
|
+
})
|
|
146
|
+
), $(b, p, g, m.getState(), S, v, (u) => {
|
|
147
|
+
m.sendMessage(u);
|
|
148
|
+
}), {
|
|
149
|
+
agent: m,
|
|
138
150
|
destroy: () => {
|
|
139
|
-
|
|
151
|
+
z = !0, P.disconnect(), m.destroy(), s.removeEventListener("keydown", M), o.remove();
|
|
140
152
|
}
|
|
141
153
|
};
|
|
142
154
|
}
|
|
143
|
-
function
|
|
144
|
-
const
|
|
145
|
-
|
|
155
|
+
function N(e, t) {
|
|
156
|
+
const o = t.value.trim();
|
|
157
|
+
o && (t.value = "", t.style.height = "", t.style.overflowY = "hidden", e.sendMessage(o), t.dispatchEvent(new Event("input", { bubbles: !0 })));
|
|
146
158
|
}
|
|
147
|
-
function
|
|
159
|
+
function C(e) {
|
|
148
160
|
e.style.height = "0px";
|
|
149
|
-
const
|
|
150
|
-
e.style.height = `${
|
|
161
|
+
const t = Math.min(e.scrollHeight, 140);
|
|
162
|
+
e.style.height = `${t}px`, e.style.overflowY = e.scrollHeight > 140 ? "auto" : "hidden";
|
|
151
163
|
}
|
|
152
|
-
function
|
|
153
|
-
const l = [...
|
|
154
|
-
e.innerHTML = "",
|
|
155
|
-
const
|
|
156
|
-
if (
|
|
157
|
-
|
|
164
|
+
function $(e, t, o, n, a, w, s) {
|
|
165
|
+
const l = [...n.messages];
|
|
166
|
+
e.innerHTML = "", V(t, n.isThinking);
|
|
167
|
+
const d = l.length > 0 || !!n.assistantDraft;
|
|
168
|
+
if (o.hidden = !d, l.length === 0 && !n.assistantDraft && !n.lastError) {
|
|
169
|
+
const p = document.createElement("div");
|
|
170
|
+
p.className = "pluno-pa-widget__empty-state";
|
|
171
|
+
const g = document.createElement("div");
|
|
172
|
+
if (g.className = "pluno-pa-widget__empty", g.textContent = "What can I help you with?", p.appendChild(g), n.starterPrompts.length > 0) {
|
|
173
|
+
const b = document.createElement("div");
|
|
174
|
+
b.className = "pluno-pa-widget__starter-prompts";
|
|
175
|
+
for (const _ of n.starterPrompts) {
|
|
176
|
+
const m = document.createElement("button");
|
|
177
|
+
m.type = "button", m.className = "pluno-pa-widget__starter-prompt", m.textContent = _, m.addEventListener("click", () => {
|
|
178
|
+
s(_);
|
|
179
|
+
}), b.appendChild(m);
|
|
180
|
+
}
|
|
181
|
+
p.appendChild(b);
|
|
182
|
+
}
|
|
183
|
+
e.appendChild(p);
|
|
158
184
|
return;
|
|
159
185
|
}
|
|
160
|
-
let
|
|
161
|
-
const
|
|
162
|
-
if (
|
|
186
|
+
let r = null, c = null, h = [];
|
|
187
|
+
const i = () => {
|
|
188
|
+
if (h.length === 0)
|
|
163
189
|
return;
|
|
164
|
-
const p =
|
|
165
|
-
e.appendChild(p),
|
|
190
|
+
const p = G(h, a, w);
|
|
191
|
+
e.appendChild(p), r = null, c = p, h = [];
|
|
166
192
|
};
|
|
167
193
|
for (let p = 0; p < l.length; p += 1) {
|
|
168
|
-
const
|
|
169
|
-
if (
|
|
170
|
-
|
|
194
|
+
const g = l[p];
|
|
195
|
+
if (g.role === "tool") {
|
|
196
|
+
h.push(g);
|
|
171
197
|
continue;
|
|
172
198
|
}
|
|
173
|
-
if (
|
|
199
|
+
if (g.role === "system")
|
|
174
200
|
continue;
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
|
|
201
|
+
i();
|
|
202
|
+
const b = O(g.content), _ = document.createElement("div");
|
|
203
|
+
_.className = `pluno-pa-widget__message pluno-pa-widget__message--${g.role}`, g.role === "assistant" ? B(_, b) : _.textContent = b, _.appendChild(D(b)), e.appendChild(_), r = _, c = null;
|
|
178
204
|
}
|
|
179
|
-
if (
|
|
180
|
-
const p = document.createElement("div");
|
|
181
|
-
|
|
205
|
+
if (i(), n.assistantDraft) {
|
|
206
|
+
const p = O(n.assistantDraft), g = document.createElement("div");
|
|
207
|
+
g.className = "pluno-pa-widget__message pluno-pa-widget__message--assistant", B(g, p), g.appendChild(D(p)), e.appendChild(g), r = g, c = null;
|
|
182
208
|
}
|
|
183
|
-
if (
|
|
209
|
+
if (n.isThinking && !n.assistantDraft) {
|
|
184
210
|
const p = document.createElement("div");
|
|
185
|
-
p.className = "pluno-pa-widget__status", p.textContent = "Thinking...", e.appendChild(p),
|
|
211
|
+
p.className = "pluno-pa-widget__status", p.textContent = "Thinking...", e.appendChild(p), r = null, c = p;
|
|
186
212
|
}
|
|
187
|
-
if (
|
|
213
|
+
if (n.lastError) {
|
|
188
214
|
const p = document.createElement("div");
|
|
189
|
-
p.className = "pluno-pa-widget__error", p.textContent =
|
|
215
|
+
p.className = "pluno-pa-widget__error", p.textContent = n.lastError, e.appendChild(p), r = p, c = null;
|
|
190
216
|
}
|
|
191
|
-
|
|
217
|
+
r?.classList.add("pluno-pa-widget__message--bottom-reserve"), c?.classList.add("pluno-pa-widget__bottom-reserve-compact"), e.scrollTop = e.scrollHeight;
|
|
218
|
+
}
|
|
219
|
+
function D(e) {
|
|
220
|
+
const t = document.createElement("button");
|
|
221
|
+
return t.type = "button", t.className = "pluno-pa-widget__message-copy", t.setAttribute("aria-label", "Copy message"), t.title = "Copy message", t.innerHTML = '<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg>', t.addEventListener("click", (o) => {
|
|
222
|
+
o.preventDefault(), o.stopPropagation(), navigator.clipboard.writeText(e);
|
|
223
|
+
}), t;
|
|
192
224
|
}
|
|
193
|
-
function
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
225
|
+
function O(e) {
|
|
226
|
+
return e.replace(/\uE200[^\uE201]*(?:\uE201|$)/g, "");
|
|
227
|
+
}
|
|
228
|
+
function G(e, t, o) {
|
|
229
|
+
const n = document.createElement("article");
|
|
230
|
+
n.className = "pluno-pa-widget__tool-group", n.title = new Date(e[e.length - 1].createdAt).toLocaleString();
|
|
231
|
+
const a = document.createElement("details"), w = U(e);
|
|
232
|
+
a.open = t.has(w), a.addEventListener("toggle", () => {
|
|
233
|
+
a.open ? t.add(w) : t.delete(w), o();
|
|
199
234
|
});
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
const
|
|
203
|
-
if (
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
for (const
|
|
235
|
+
const s = document.createElement("summary");
|
|
236
|
+
s.className = "pluno-pa-widget__tool-summary", e.some((r) => r.loading) && s.appendChild(j());
|
|
237
|
+
const d = document.createElement("span");
|
|
238
|
+
if (d.textContent = e[e.length - 1].content || "Run tool", s.appendChild(d), a.appendChild(s), e.length > 0) {
|
|
239
|
+
const r = document.createElement("div");
|
|
240
|
+
r.className = "pluno-pa-widget__tool-lines";
|
|
241
|
+
for (const c of e) {
|
|
207
242
|
const h = document.createElement("div");
|
|
208
|
-
h.className = "pluno-pa-widget__tool-line",
|
|
209
|
-
const
|
|
210
|
-
|
|
243
|
+
h.className = "pluno-pa-widget__tool-line", c.loading && h.appendChild(j());
|
|
244
|
+
const i = document.createElement("span");
|
|
245
|
+
i.textContent = c.content || "Run tool", h.appendChild(i), r.appendChild(h);
|
|
211
246
|
}
|
|
212
|
-
|
|
247
|
+
a.appendChild(r);
|
|
213
248
|
}
|
|
214
|
-
return
|
|
249
|
+
return n.appendChild(a), n;
|
|
215
250
|
}
|
|
216
|
-
function
|
|
217
|
-
return `tools:${e.map((
|
|
251
|
+
function U(e) {
|
|
252
|
+
return `tools:${e.map((t) => t.id).join("|")}`;
|
|
218
253
|
}
|
|
219
|
-
function
|
|
254
|
+
function j() {
|
|
220
255
|
const e = document.createElement("span");
|
|
221
256
|
return e.className = "pluno-pa-widget__spinner", e.setAttribute("aria-hidden", "true"), e;
|
|
222
257
|
}
|
|
223
|
-
function
|
|
224
|
-
e.setAttribute("aria-label",
|
|
258
|
+
function V(e, t) {
|
|
259
|
+
e.setAttribute("aria-label", t ? "Stop" : "Send"), e.classList.toggle("pluno-pa-widget__send--stop", t), e.innerHTML = t ? '<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2" /></svg>' : '<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="12" y1="19" x2="12" y2="5" /><polyline points="5 12 12 5 19 12" /></svg>';
|
|
225
260
|
}
|
|
226
|
-
function
|
|
227
|
-
const
|
|
261
|
+
function B(e, t) {
|
|
262
|
+
const o = t.replace(/\r\n/g, `
|
|
228
263
|
`).split(`
|
|
229
264
|
`);
|
|
230
|
-
let
|
|
231
|
-
for (;
|
|
232
|
-
const
|
|
233
|
-
if (!
|
|
234
|
-
|
|
265
|
+
let n = 0;
|
|
266
|
+
for (; n < o.length; ) {
|
|
267
|
+
const a = o[n];
|
|
268
|
+
if (!a.trim()) {
|
|
269
|
+
n += 1;
|
|
235
270
|
continue;
|
|
236
271
|
}
|
|
237
|
-
if (
|
|
238
|
-
const
|
|
239
|
-
for (
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
h.textContent =
|
|
244
|
-
`),
|
|
272
|
+
if (a.match(/^```(\w+)?\s*$/)) {
|
|
273
|
+
const r = [];
|
|
274
|
+
for (n += 1; n < o.length && !/^```\s*$/.test(o[n]); )
|
|
275
|
+
r.push(o[n]), n += 1;
|
|
276
|
+
n += n < o.length ? 1 : 0;
|
|
277
|
+
const c = document.createElement("pre"), h = document.createElement("code");
|
|
278
|
+
h.textContent = r.join(`
|
|
279
|
+
`), c.appendChild(h), e.appendChild(c);
|
|
245
280
|
continue;
|
|
246
281
|
}
|
|
247
|
-
const
|
|
248
|
-
if (
|
|
249
|
-
const
|
|
250
|
-
|
|
282
|
+
const s = a.match(/^(#{1,3})\s+(.+)$/);
|
|
283
|
+
if (s) {
|
|
284
|
+
const r = document.createElement(`h${s[1].length + 2}`);
|
|
285
|
+
T(r, s[2]), e.appendChild(r), n += 1;
|
|
251
286
|
continue;
|
|
252
287
|
}
|
|
253
|
-
if (/^\s*[-*+]\s+/.test(
|
|
254
|
-
const
|
|
255
|
-
for (;
|
|
256
|
-
const
|
|
257
|
-
|
|
288
|
+
if (/^\s*[-*+]\s+/.test(a)) {
|
|
289
|
+
const r = document.createElement("ul");
|
|
290
|
+
for (; n < o.length && /^\s*[-*+]\s+/.test(o[n]); ) {
|
|
291
|
+
const c = document.createElement("li");
|
|
292
|
+
T(c, o[n].replace(/^\s*[-*+]\s+/, "")), r.appendChild(c), n += 1;
|
|
258
293
|
}
|
|
259
|
-
e.appendChild(
|
|
294
|
+
e.appendChild(r);
|
|
260
295
|
continue;
|
|
261
296
|
}
|
|
262
|
-
if (/^\s*\d+\.\s+/.test(
|
|
263
|
-
const
|
|
264
|
-
for (;
|
|
265
|
-
const
|
|
266
|
-
|
|
297
|
+
if (/^\s*\d+\.\s+/.test(a)) {
|
|
298
|
+
const r = document.createElement("ol");
|
|
299
|
+
for (; n < o.length && /^\s*\d+\.\s+/.test(o[n]); ) {
|
|
300
|
+
const c = document.createElement("li");
|
|
301
|
+
T(c, o[n].replace(/^\s*\d+\.\s+/, "")), r.appendChild(c), n += 1;
|
|
267
302
|
}
|
|
268
|
-
e.appendChild(
|
|
303
|
+
e.appendChild(r);
|
|
269
304
|
continue;
|
|
270
305
|
}
|
|
271
|
-
const
|
|
272
|
-
for (
|
|
273
|
-
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}), e.appendChild(
|
|
306
|
+
const l = [a];
|
|
307
|
+
for (n += 1; n < o.length && o[n].trim() && !/^```/.test(o[n]) && !/^(#{1,3})\s+/.test(o[n]) && !/^\s*[-*+]\s+/.test(o[n]) && !/^\s*\d+\.\s+/.test(o[n]); )
|
|
308
|
+
l.push(o[n]), n += 1;
|
|
309
|
+
const d = document.createElement("p");
|
|
310
|
+
l.forEach((r, c) => {
|
|
311
|
+
c > 0 && d.appendChild(document.createElement("br")), T(d, r);
|
|
312
|
+
}), e.appendChild(d);
|
|
278
313
|
}
|
|
279
314
|
}
|
|
280
|
-
function
|
|
281
|
-
const
|
|
282
|
-
let
|
|
283
|
-
for (const
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
const
|
|
287
|
-
if (
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
} else if (
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
} else if (
|
|
294
|
-
const
|
|
295
|
-
|
|
315
|
+
function T(e, t) {
|
|
316
|
+
const o = /(`[^`]+`|\*\*[^*]+\*\*|\*[^*]+\*|\[[^\]]+\]\(([^)\s]+)\))/g;
|
|
317
|
+
let n = 0;
|
|
318
|
+
for (const a of t.matchAll(o)) {
|
|
319
|
+
const w = a.index ?? 0;
|
|
320
|
+
w > n && e.appendChild(document.createTextNode(t.slice(n, w)));
|
|
321
|
+
const s = a[0];
|
|
322
|
+
if (s.startsWith("`")) {
|
|
323
|
+
const l = document.createElement("code");
|
|
324
|
+
l.textContent = s.slice(1, -1), e.appendChild(l);
|
|
325
|
+
} else if (s.startsWith("**")) {
|
|
326
|
+
const l = document.createElement("strong");
|
|
327
|
+
l.textContent = s.slice(2, -2), e.appendChild(l);
|
|
328
|
+
} else if (s.startsWith("*")) {
|
|
329
|
+
const l = document.createElement("em");
|
|
330
|
+
l.textContent = s.slice(1, -1), e.appendChild(l);
|
|
296
331
|
} else {
|
|
297
|
-
const
|
|
298
|
-
if (
|
|
299
|
-
const
|
|
300
|
-
|
|
332
|
+
const l = s.match(/^\[([^\]]+)\]\(([^)\s]+)\)$/);
|
|
333
|
+
if (l && Y(l[2])) {
|
|
334
|
+
const d = document.createElement("a");
|
|
335
|
+
d.href = l[2], d.target = "_top", d.rel = "noreferrer", d.textContent = l[1], e.appendChild(d);
|
|
301
336
|
} else
|
|
302
|
-
e.appendChild(document.createTextNode(
|
|
337
|
+
e.appendChild(document.createTextNode(s));
|
|
303
338
|
}
|
|
304
|
-
|
|
339
|
+
n = w + s.length;
|
|
305
340
|
}
|
|
306
|
-
|
|
341
|
+
n < t.length && e.appendChild(document.createTextNode(t.slice(n)));
|
|
307
342
|
}
|
|
308
|
-
function
|
|
343
|
+
function Y(e) {
|
|
309
344
|
if (e.startsWith("/") || e.startsWith("#"))
|
|
310
345
|
return !0;
|
|
311
346
|
try {
|
|
312
|
-
const
|
|
313
|
-
return ["http:", "https:", "mailto:"].includes(
|
|
347
|
+
const t = new URL(e);
|
|
348
|
+
return ["http:", "https:", "mailto:"].includes(t.protocol);
|
|
314
349
|
} catch {
|
|
315
350
|
return !1;
|
|
316
351
|
}
|
|
317
352
|
}
|
|
318
|
-
function
|
|
319
|
-
if (
|
|
353
|
+
function I(e, t) {
|
|
354
|
+
if (e.getElementById("pluno-pa-widget-styles"))
|
|
320
355
|
return;
|
|
321
|
-
const o =
|
|
356
|
+
const o = e.ownerDocument.createElement("style");
|
|
322
357
|
o.id = "pluno-pa-widget-styles", o.textContent = `
|
|
358
|
+
:host {
|
|
359
|
+
all: initial;
|
|
360
|
+
color-scheme: light;
|
|
361
|
+
}
|
|
362
|
+
*,
|
|
363
|
+
*::before,
|
|
364
|
+
*::after {
|
|
365
|
+
box-sizing: border-box;
|
|
366
|
+
}
|
|
367
|
+
input,
|
|
368
|
+
textarea,
|
|
369
|
+
button {
|
|
370
|
+
margin: 0;
|
|
371
|
+
font: inherit;
|
|
372
|
+
color: inherit;
|
|
373
|
+
-webkit-appearance: none;
|
|
374
|
+
appearance: none;
|
|
375
|
+
}
|
|
376
|
+
button,
|
|
377
|
+
summary {
|
|
378
|
+
cursor: pointer;
|
|
379
|
+
}
|
|
380
|
+
input,
|
|
381
|
+
textarea {
|
|
382
|
+
cursor: text;
|
|
383
|
+
}
|
|
384
|
+
svg {
|
|
385
|
+
display: block;
|
|
386
|
+
flex: 0 0 auto;
|
|
387
|
+
}
|
|
323
388
|
.pluno-pa-widget {
|
|
324
|
-
--pluno-pa-accent: ${
|
|
389
|
+
--pluno-pa-accent: ${t};
|
|
325
390
|
--pluno-pa-bg: #fafaf9;
|
|
326
391
|
--pluno-pa-surface: #f4f4f2;
|
|
327
392
|
--pluno-pa-bubble: #eeeded;
|
|
@@ -356,9 +421,6 @@ function B(e) {
|
|
|
356
421
|
--pluno-pa-accent-soft: rgba(245, 245, 244, 0.22);
|
|
357
422
|
--pluno-pa-accent-contrast: #18181b;
|
|
358
423
|
}
|
|
359
|
-
.pluno-pa-widget * {
|
|
360
|
-
box-sizing: border-box;
|
|
361
|
-
}
|
|
362
424
|
.pluno-pa-widget [hidden] {
|
|
363
425
|
display: none !important;
|
|
364
426
|
}
|
|
@@ -581,6 +643,7 @@ function B(e) {
|
|
|
581
643
|
background: transparent;
|
|
582
644
|
}
|
|
583
645
|
.pluno-pa-widget__message {
|
|
646
|
+
position: relative;
|
|
584
647
|
min-width: 0;
|
|
585
648
|
color: var(--pluno-pa-text);
|
|
586
649
|
font-size: 14px;
|
|
@@ -601,6 +664,43 @@ function B(e) {
|
|
|
601
664
|
align-self: stretch;
|
|
602
665
|
padding: 0 2px;
|
|
603
666
|
}
|
|
667
|
+
.pluno-pa-widget__message-copy {
|
|
668
|
+
position: absolute;
|
|
669
|
+
bottom: -24px;
|
|
670
|
+
z-index: 3;
|
|
671
|
+
width: 22px;
|
|
672
|
+
height: 22px;
|
|
673
|
+
display: inline-flex;
|
|
674
|
+
align-items: center;
|
|
675
|
+
justify-content: center;
|
|
676
|
+
border: 1px solid var(--pluno-pa-divider);
|
|
677
|
+
border-radius: 999px;
|
|
678
|
+
background: color-mix(in srgb, var(--pluno-pa-bg) 92%, transparent);
|
|
679
|
+
color: var(--pluno-pa-muted);
|
|
680
|
+
box-shadow: 0 4px 10px rgba(24, 24, 27, 0.08);
|
|
681
|
+
cursor: pointer;
|
|
682
|
+
opacity: 0;
|
|
683
|
+
pointer-events: none;
|
|
684
|
+
transform: translateY(-2px);
|
|
685
|
+
transition: opacity 120ms ease, transform 120ms ease, background 120ms ease, color 120ms ease;
|
|
686
|
+
}
|
|
687
|
+
.pluno-pa-widget__message--user .pluno-pa-widget__message-copy {
|
|
688
|
+
right: 4px;
|
|
689
|
+
}
|
|
690
|
+
.pluno-pa-widget__message--assistant .pluno-pa-widget__message-copy {
|
|
691
|
+
left: 2px;
|
|
692
|
+
}
|
|
693
|
+
.pluno-pa-widget__message:hover .pluno-pa-widget__message-copy,
|
|
694
|
+
.pluno-pa-widget__message:focus-within .pluno-pa-widget__message-copy {
|
|
695
|
+
opacity: 1;
|
|
696
|
+
pointer-events: auto;
|
|
697
|
+
transform: translateY(0);
|
|
698
|
+
}
|
|
699
|
+
.pluno-pa-widget__message-copy:hover,
|
|
700
|
+
.pluno-pa-widget__message-copy:focus-visible {
|
|
701
|
+
background: var(--pluno-pa-surface);
|
|
702
|
+
color: var(--pluno-pa-text);
|
|
703
|
+
}
|
|
604
704
|
.pluno-pa-widget__message--bottom-reserve {
|
|
605
705
|
margin-bottom: 46px;
|
|
606
706
|
}
|
|
@@ -613,6 +713,9 @@ function B(e) {
|
|
|
613
713
|
.pluno-pa-widget__message--assistant > :last-child {
|
|
614
714
|
margin-bottom: 0;
|
|
615
715
|
}
|
|
716
|
+
.pluno-pa-widget__message--assistant > :nth-last-child(2) {
|
|
717
|
+
margin-bottom: 0;
|
|
718
|
+
}
|
|
616
719
|
.pluno-pa-widget__message--assistant p,
|
|
617
720
|
.pluno-pa-widget__message--assistant ul,
|
|
618
721
|
.pluno-pa-widget__message--assistant ol,
|
|
@@ -814,6 +917,40 @@ function B(e) {
|
|
|
814
917
|
margin: auto;
|
|
815
918
|
padding: 24px 0;
|
|
816
919
|
}
|
|
920
|
+
.pluno-pa-widget__empty-state {
|
|
921
|
+
margin: auto;
|
|
922
|
+
display: grid;
|
|
923
|
+
gap: 12px;
|
|
924
|
+
justify-items: center;
|
|
925
|
+
width: 100%;
|
|
926
|
+
padding: 24px 0;
|
|
927
|
+
}
|
|
928
|
+
.pluno-pa-widget__empty-state .pluno-pa-widget__empty {
|
|
929
|
+
margin: 0;
|
|
930
|
+
padding: 0;
|
|
931
|
+
}
|
|
932
|
+
.pluno-pa-widget__starter-prompts {
|
|
933
|
+
display: grid;
|
|
934
|
+
gap: 8px;
|
|
935
|
+
width: min(100%, 320px);
|
|
936
|
+
}
|
|
937
|
+
.pluno-pa-widget__starter-prompt {
|
|
938
|
+
border: 1px solid var(--pluno-pa-border);
|
|
939
|
+
border-radius: 16px;
|
|
940
|
+
background: var(--pluno-pa-surface);
|
|
941
|
+
color: var(--pluno-pa-text);
|
|
942
|
+
font: inherit;
|
|
943
|
+
font-size: 12px;
|
|
944
|
+
line-height: 1.45;
|
|
945
|
+
padding: 10px 12px;
|
|
946
|
+
text-align: left;
|
|
947
|
+
cursor: pointer;
|
|
948
|
+
transition: border-color 120ms ease, background 120ms ease;
|
|
949
|
+
}
|
|
950
|
+
.pluno-pa-widget__starter-prompt:hover {
|
|
951
|
+
border-color: rgba(255, 255, 255, 0.18);
|
|
952
|
+
background: rgba(255, 255, 255, 0.05);
|
|
953
|
+
}
|
|
817
954
|
.pluno-pa-widget__status {
|
|
818
955
|
display: inline-flex;
|
|
819
956
|
align-items: center;
|
|
@@ -853,49 +990,57 @@ function B(e) {
|
|
|
853
990
|
.pluno-pa-widget__error.pluno-pa-widget__message--bottom-reserve {
|
|
854
991
|
margin-bottom: 46px;
|
|
855
992
|
}
|
|
856
|
-
`,
|
|
993
|
+
`, e.appendChild(o);
|
|
994
|
+
}
|
|
995
|
+
async function R() {
|
|
996
|
+
return document.body ? document.body : await new Promise((e) => {
|
|
997
|
+
const t = new MutationObserver(() => {
|
|
998
|
+
document.body && (t.disconnect(), e(document.body));
|
|
999
|
+
});
|
|
1000
|
+
t.observe(document.documentElement, { childList: !0 });
|
|
1001
|
+
});
|
|
857
1002
|
}
|
|
858
|
-
function
|
|
859
|
-
const
|
|
860
|
-
return
|
|
1003
|
+
function W(e) {
|
|
1004
|
+
const t = document.createElement("span");
|
|
1005
|
+
return t.textContent = e, t.innerHTML;
|
|
861
1006
|
}
|
|
862
|
-
function
|
|
1007
|
+
function F(e) {
|
|
863
1008
|
return `pluno.productAgent.widgetState.${location.origin}.${e.backendUrl ?? ""}.${e.tokenEndpoint ?? ""}.${e.position ?? ""}`;
|
|
864
1009
|
}
|
|
865
|
-
function
|
|
1010
|
+
function J(e) {
|
|
866
1011
|
try {
|
|
867
|
-
const
|
|
868
|
-
if (!
|
|
1012
|
+
const t = window.localStorage.getItem(F(e));
|
|
1013
|
+
if (!t)
|
|
869
1014
|
return { isOpen: !1, composerValue: "", openToolGroupKeys: [] };
|
|
870
|
-
const
|
|
1015
|
+
const o = JSON.parse(t);
|
|
871
1016
|
return {
|
|
872
|
-
isOpen:
|
|
873
|
-
composerValue: typeof
|
|
874
|
-
openToolGroupKeys: Array.isArray(
|
|
1017
|
+
isOpen: o.isOpen === !0,
|
|
1018
|
+
composerValue: typeof o.composerValue == "string" ? o.composerValue : "",
|
|
1019
|
+
openToolGroupKeys: Array.isArray(o.openToolGroupKeys) ? o.openToolGroupKeys.filter((n) => typeof n == "string") : []
|
|
875
1020
|
};
|
|
876
1021
|
} catch {
|
|
877
1022
|
return { isOpen: !1, composerValue: "", openToolGroupKeys: [] };
|
|
878
1023
|
}
|
|
879
1024
|
}
|
|
880
|
-
function
|
|
1025
|
+
function Z(e, t) {
|
|
881
1026
|
try {
|
|
882
|
-
window.localStorage.setItem(
|
|
1027
|
+
window.localStorage.setItem(F(e), JSON.stringify(t));
|
|
883
1028
|
} catch {
|
|
884
1029
|
return;
|
|
885
1030
|
}
|
|
886
1031
|
}
|
|
887
|
-
const
|
|
888
|
-
|
|
889
|
-
token:
|
|
890
|
-
tokenEndpoint:
|
|
891
|
-
backendUrl:
|
|
892
|
-
launcherLabel:
|
|
893
|
-
accentColor:
|
|
894
|
-
colorScheme:
|
|
895
|
-
position:
|
|
1032
|
+
const f = document.currentScript;
|
|
1033
|
+
f && f.dataset.plunoAutoMount !== "false" && K({
|
|
1034
|
+
token: f?.dataset.plunoToken,
|
|
1035
|
+
tokenEndpoint: f?.dataset.plunoTokenEndpoint,
|
|
1036
|
+
backendUrl: f?.dataset.plunoBackendUrl,
|
|
1037
|
+
launcherLabel: f?.dataset.plunoLauncherLabel,
|
|
1038
|
+
accentColor: f?.dataset.plunoAccentColor,
|
|
1039
|
+
colorScheme: f?.dataset.plunoColorScheme === "dark" ? "dark" : "light",
|
|
1040
|
+
position: f?.dataset.plunoPosition === "bottom-left" ? "bottom-left" : "bottom-right"
|
|
896
1041
|
}).catch((e) => {
|
|
897
1042
|
console.error("Failed to mount Pluno Product Agent widget", e);
|
|
898
1043
|
});
|
|
899
1044
|
export {
|
|
900
|
-
|
|
1045
|
+
K as mountPlunoProductAgentWidget
|
|
901
1046
|
};
|
package/package.json
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluno/product-agent-web",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Browser SDK and default widget for embedding Pluno Product Agent into customer web apps.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/product-agent-sdk.js",
|
|
8
8
|
"module": "dist/product-agent-sdk.js",
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/unbrainedgmbh/pluno.git",
|
|
13
|
-
"directory": "product-agent-web-sdk"
|
|
14
|
-
},
|
|
15
10
|
"homepage": "https://pluno.ai",
|
|
16
11
|
"bugs": {
|
|
17
12
|
"url": "https://github.com/unbrainedgmbh/pluno/issues"
|
|
@@ -50,6 +45,6 @@
|
|
|
50
45
|
"jsdom": "^26.1.0",
|
|
51
46
|
"typescript": "^5.9.2",
|
|
52
47
|
"vite": "^7.1.3",
|
|
53
|
-
"vitest": "
|
|
48
|
+
"vitest": "3.2.4"
|
|
54
49
|
}
|
|
55
|
-
}
|
|
50
|
+
}
|