@pluno/product-agent-web 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -65,6 +65,7 @@ export declare class PlunoProductAgent {
65
65
  private queuedNetworkEvents;
66
66
  private queuedClientEvents;
67
67
  private retryAttemptsByClientMessageId;
68
+ private retryTimersByClientMessageId;
68
69
  private runtimeHelperJavascript;
69
70
  private state;
70
71
  private constructor();
@@ -82,6 +83,7 @@ export declare class PlunoProductAgent {
82
83
  private flushQueuedClientEvents;
83
84
  private handleServerEvent;
84
85
  private retryAfterRetryableError;
86
+ private clearRetryTimers;
85
87
  private executeToolCall;
86
88
  private executeRuntimeHelper;
87
89
  private enableNetworkCapture;
@@ -1,9 +1,9 @@
1
- const x = "https://app.pluno.ai";
2
- const R = "pluno.productAgent.state.";
3
- class M {
1
+ const O = "https://app.pluno.ai";
2
+ const M = "pluno.productAgent.state.";
3
+ class C {
4
4
  constructor(t) {
5
5
  this.options = t;
6
- const s = ot(t.clientId);
6
+ const s = at(t.clientId);
7
7
  s && (this.state = {
8
8
  ...this.state,
9
9
  ...s,
@@ -25,6 +25,7 @@ class M {
25
25
  queuedNetworkEvents = [];
26
26
  queuedClientEvents = [];
27
27
  retryAttemptsByClientMessageId = {};
28
+ retryTimersByClientMessageId = {};
28
29
  runtimeHelperJavascript = null;
29
30
  state = {
30
31
  status: "idle",
@@ -37,10 +38,10 @@ class M {
37
38
  lastError: null
38
39
  };
39
40
  static async init(t) {
40
- const s = new M({
41
+ const s = new C({
41
42
  ...t,
42
- backendUrl: B(t.backendUrl ?? x),
43
- clientId: t.clientId ?? J()
43
+ backendUrl: j(t.backendUrl ?? O),
44
+ clientId: t.clientId ?? G()
44
45
  });
45
46
  try {
46
47
  s.enableNetworkCapture(), t.autoConnect !== !1 && await s.connect();
@@ -65,17 +66,17 @@ class M {
65
66
  return;
66
67
  if (this.setState({ status: (this.state.status === "closed", "connecting"), lastError: null }), this.token = this.options.token ?? await this.options.tokenProvider?.() ?? null, !this.token && !this.options.webSocketFactory)
67
68
  throw new Error("Product Agent requires a token or tokenProvider");
68
- const t = L(this.options.backendUrl);
69
+ const t = $(this.options.backendUrl);
69
70
  this.socket = this.options.webSocketFactory?.(t) ?? new WebSocket(t), this.socket.addEventListener("open", () => {
70
71
  this.token && this.sendNow({ type: "auth.session", token: this.token, clientId: this.options.clientId }), this.flushQueuedClientEvents(), this.startHeartbeat(), this.setState({ status: "connected", lastError: null });
71
- }), this.socket.addEventListener("message", (s) => this.handleServerEvent(j(s.data))), this.socket.addEventListener("close", () => {
72
+ }), this.socket.addEventListener("message", (s) => this.handleServerEvent(X(s.data))), this.socket.addEventListener("close", () => {
72
73
  this.stopHeartbeat(), this.socket = null, this.state.status !== "closed" && (this.setState({ status: "reconnecting" }), this.scheduleReconnect());
73
74
  }), this.socket.addEventListener("error", () => {
74
75
  this.setState({ status: "error", lastError: "Product Agent connection failed" });
75
76
  });
76
77
  }
77
78
  disconnect() {
78
- this.setState({ status: "closed", isThinking: !1 }), this.stopHeartbeat(), this.reconnectTimer !== null && (window.clearTimeout(this.reconnectTimer), this.reconnectTimer = null), this.queuedClientEvents = [], this.socket?.close(), this.socket = null;
79
+ this.setState({ status: "closed", isThinking: !1 }), this.stopHeartbeat(), this.clearRetryTimers(), this.reconnectTimer !== null && (window.clearTimeout(this.reconnectTimer), this.reconnectTimer = null), this.queuedClientEvents = [], this.socket?.close(), this.socket = null;
79
80
  }
80
81
  destroy() {
81
82
  this.disconnect(), this.networkCaptureCleanup?.(), this.networkCaptureCleanup = null;
@@ -86,7 +87,7 @@ class M {
86
87
  const s = t.trim();
87
88
  if (!s)
88
89
  return;
89
- const r = g(), n = G(), i = {
90
+ const r = g(), n = W(), i = {
90
91
  id: `local-${n}`,
91
92
  role: "user",
92
93
  content: s,
@@ -125,7 +126,7 @@ class M {
125
126
  });
126
127
  }
127
128
  send(t) {
128
- this.sendNow(f(t)) || (this.queuedClientEvents.push(t), this.setState({ status: "reconnecting" }), this.scheduleReconnect());
129
+ this.sendNow(p(t)) || (this.queuedClientEvents.push(t), this.setState({ status: "reconnecting" }), this.scheduleReconnect());
129
130
  }
130
131
  sendNow(t) {
131
132
  return !this.socket || this.socket.readyState !== WebSocket.OPEN ? !1 : (this.socket.send(JSON.stringify(t)), !0);
@@ -136,7 +137,7 @@ class M {
136
137
  const t = this.queuedClientEvents.splice(0, this.queuedClientEvents.length);
137
138
  for (let s = 0; s < t.length; s += 1) {
138
139
  const r = t[s];
139
- if (!this.sendNow(f(r))) {
140
+ if (!this.sendNow(p(r))) {
140
141
  this.queuedClientEvents.unshift(r, ...t.slice(s + 1));
141
142
  return;
142
143
  }
@@ -144,9 +145,9 @@ class M {
144
145
  }
145
146
  handleServerEvent(t) {
146
147
  if (t.type === "auth.ok") {
147
- this.runtimeHelperJavascript = X(t.runtimeHelpers)?.javascript ?? null, this.setState({
148
- user: W(t.user),
149
- starterPrompts: $(t, "starterPrompts"),
148
+ this.runtimeHelperJavascript = F(t.runtimeHelpers)?.javascript ?? null, this.setState({
149
+ user: K(t.user),
150
+ starterPrompts: z(t, "starterPrompts"),
150
151
  status: "connected"
151
152
  }), this.state.sessionId && this.send({
152
153
  type: "page.upsert",
@@ -158,23 +159,23 @@ class M {
158
159
  }
159
160
  if (t.type === "conversation.state") {
160
161
  const s = Array.isArray(t.items) ? t.items : [];
161
- this.setState({
162
- sessionId: I(t.session, "id") ?? this.state.sessionId,
163
- messages: v(s),
164
- ...et(s) ? { assistantDraft: "", isThinking: !1 } : {}
162
+ nt(s) && this.clearRetryTimers(), this.setState({
163
+ sessionId: k(t.session, "id") ?? this.state.sessionId,
164
+ messages: Y(s),
165
+ ...rt(s) ? { assistantDraft: "", isThinking: !1 } : {}
165
166
  });
166
167
  return;
167
168
  }
168
169
  if (t.type === "session.updated") {
169
- this.setState({ sessionId: I(t.session, "id") ?? this.state.sessionId });
170
+ this.setState({ sessionId: k(t.session, "id") ?? this.state.sessionId });
170
171
  return;
171
172
  }
172
173
  if (t.type === "session.item") {
173
- const s = C(t.item);
174
- s && (this.setState({
175
- messages: Q(this.state.messages, s),
174
+ const s = b(t.item);
175
+ s && (s.role === "assistant" && this.clearRetryTimers(), this.setState({
176
+ messages: et(this.state.messages, s),
176
177
  assistantDraft: s.role === "assistant" ? "" : this.state.assistantDraft,
177
- ...D(t.item.data) ? { assistantDraft: "", isThinking: !1 } : {}
178
+ ...N(t.item.data) ? { assistantDraft: "", isThinking: !1 } : {}
178
179
  }), this.emit("message", s));
179
180
  return;
180
181
  }
@@ -208,17 +209,22 @@ class M {
208
209
  return !1;
209
210
  this.retryAttemptsByClientMessageId[r] = i + 1;
210
211
  const a = typeof t.retryAfterMs == "number" ? t.retryAfterMs : 2e3;
211
- return this.setState({ status: "reconnecting", isThinking: !0, lastError: null }), window.setTimeout(() => {
212
- this.setState({ status: "connected", isThinking: !0, lastError: null }), this.send({
212
+ return this.setState({ status: "reconnecting", isThinking: !0, lastError: null }), this.retryTimersByClientMessageId[r] = window.setTimeout(() => {
213
+ delete this.retryTimersByClientMessageId[r], this.setState({ status: "connected", isThinking: !0, lastError: null }), this.send({
213
214
  type: "chat.retry_last_user_message",
214
215
  sessionId: s,
215
216
  clientMessageId: r
216
217
  });
217
218
  }, a), !0;
218
219
  }
220
+ clearRetryTimers() {
221
+ for (const t of Object.values(this.retryTimersByClientMessageId))
222
+ window.clearTimeout(t);
223
+ this.retryTimersByClientMessageId = {};
224
+ }
219
225
  async executeToolCall(t) {
220
226
  const s = typeof t.sessionId == "string" ? t.sessionId : null, r = typeof t.callId == "string" ? t.callId : null, n = t.rawInput;
221
- if (!s || !r || !ct(n))
227
+ if (!s || !r || !lt(n))
222
228
  return;
223
229
  const i = await this.executeRuntimeHelper(), a = await A(n).catch((o) => ({
224
230
  ok: !1,
@@ -232,8 +238,8 @@ class M {
232
238
  callId: r,
233
239
  toolName: "execute_code",
234
240
  summary: n.summary,
235
- rawInput: f(n),
236
- rawOutput: f(z(a, i))
241
+ rawInput: p(n),
242
+ rawOutput: p(J(a, i))
237
243
  });
238
244
  }
239
245
  async executeRuntimeHelper() {
@@ -242,26 +248,26 @@ class M {
242
248
  const t = await A({
243
249
  javascript: this.runtimeHelperJavascript
244
250
  });
245
- return t.ok === !1 ? F(t) : null;
251
+ return t.ok === !1 ? v(t) : null;
246
252
  }
247
253
  enableNetworkCapture() {
248
254
  if (this.networkCaptureCleanup)
249
255
  return;
250
256
  const t = window.fetch.bind(window), s = XMLHttpRequest.prototype.open, r = XMLHttpRequest.prototype.setRequestHeader, n = XMLHttpRequest.prototype.send;
251
257
  window.fetch = async (i, a) => {
252
- const o = Date.now(), c = new Date(o).toISOString(), u = i instanceof Request ? i : null, h = typeof i == "string" ? i : i instanceof URL ? i.toString() : u?.url ?? "", _ = (a?.method ?? u?.method ?? "GET").toUpperCase(), T = k(new Headers(a?.headers ?? u?.headers ?? void 0)), w = await ut(u, a);
258
+ const o = Date.now(), c = new Date(o).toISOString(), u = i instanceof Request ? i : null, h = typeof i == "string" ? i : i instanceof URL ? i.toString() : u?.url ?? "", E = (a?.method ?? u?.method ?? "GET").toUpperCase(), _ = R(new Headers(a?.headers ?? u?.headers ?? void 0)), w = await dt(u, a);
253
259
  try {
254
260
  const l = await t(i, a);
255
261
  return this.enqueueNetworkEvent({
256
262
  requestId: y("fetch"),
257
263
  url: h,
258
- method: _,
259
- requestHeaders: T,
264
+ method: E,
265
+ requestHeaders: _,
260
266
  requestBody: w,
261
267
  resourceType: "fetch",
262
268
  responseStatus: l.status,
263
- responseHeaders: k(l.headers),
264
- responseBody: await lt(l),
269
+ responseHeaders: R(l.headers),
270
+ responseBody: await ft(l),
265
271
  startedAt: c,
266
272
  durationMs: Date.now() - o
267
273
  }), l;
@@ -269,8 +275,8 @@ class M {
269
275
  throw this.enqueueNetworkEvent({
270
276
  requestId: y("fetch"),
271
277
  url: h,
272
- method: _,
273
- requestHeaders: T,
278
+ method: E,
279
+ requestHeaders: _,
274
280
  requestBody: w,
275
281
  resourceType: "fetch",
276
282
  errorText: l instanceof Error ? l.message : String(l),
@@ -303,7 +309,7 @@ class M {
303
309
  startedAtMs: Date.now(),
304
310
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
305
311
  };
306
- return c.requestBody = b(a), this.__plunoMeta = c, this.addEventListener(
312
+ return c.requestBody = H(a), this.__plunoMeta = c, this.addEventListener(
307
313
  "loadend",
308
314
  function() {
309
315
  !o || !this.__plunoMeta || o.enqueueNetworkEvent({
@@ -314,8 +320,8 @@ class M {
314
320
  requestBody: typeof this.__plunoMeta.requestBody == "string" ? this.__plunoMeta.requestBody : void 0,
315
321
  resourceType: "xhr",
316
322
  responseStatus: this.status,
317
- responseHeaders: pt(this.getAllResponseHeaders()),
318
- responseBody: dt(this),
323
+ responseHeaders: ht(this.getAllResponseHeaders()),
324
+ responseBody: pt(this),
319
325
  errorText: this.status === 0 ? "XHR request failed or was aborted" : void 0,
320
326
  startedAt: String(this.__plunoMeta.startedAt),
321
327
  durationMs: Date.now() - Number(this.__plunoMeta.startedAtMs ?? Date.now())
@@ -328,7 +334,7 @@ class M {
328
334
  };
329
335
  }
330
336
  enqueueNetworkEvent(t) {
331
- this.queuedNetworkEvents.push(f(t)), this.networkBatchTimer === null && (this.networkBatchTimer = window.setTimeout(() => {
337
+ this.queuedNetworkEvents.push(p(t)), this.networkBatchTimer === null && (this.networkBatchTimer = window.setTimeout(() => {
332
338
  this.networkBatchTimer = null;
333
339
  const s = this.queuedNetworkEvents.splice(0, this.queuedNetworkEvents.length);
334
340
  s.length === 0 || this.socket?.readyState !== WebSocket.OPEN || this.sendNow({
@@ -355,16 +361,16 @@ class M {
355
361
  this.heartbeatTimer !== null && (window.clearInterval(this.heartbeatTimer), this.heartbeatTimer = null);
356
362
  }
357
363
  setState(t) {
358
- this.state = { ...this.state, ...t }, it(this.options.clientId, this.state), this.emit("state", this.getState());
364
+ this.state = { ...this.state, ...t }, ct(this.options.clientId, this.state), this.emit("state", this.getState());
359
365
  }
360
366
  emit(t, s) {
361
367
  this.listeners[t]?.forEach((n) => n(s));
362
368
  }
363
369
  }
364
- const O = 5e3;
370
+ const L = 5e3;
365
371
  async function A(e) {
366
372
  const t = Object.getPrototypeOf(async function() {
367
- }).constructor, s = O, r = Date.now(), n = [], i = {
373
+ }).constructor, s = L, r = Date.now(), n = [], i = {
368
374
  log: console.log,
369
375
  info: console.info,
370
376
  warn: console.warn,
@@ -408,10 +414,10 @@ async function A(e) {
408
414
  console.log = i.log, console.info = i.info, console.warn = i.warn, console.error = i.error;
409
415
  }
410
416
  }
411
- function B(e) {
417
+ function j(e) {
412
418
  return e.replace(/\/+$/, "");
413
419
  }
414
- function L(e) {
420
+ function $(e) {
415
421
  const t = new URL("/api/product-agent/embed/ws", e);
416
422
  return t.protocol = t.protocol === "https:" ? "wss:" : "ws:", t.toString();
417
423
  }
@@ -422,7 +428,7 @@ function g() {
422
428
  origin: location.origin
423
429
  };
424
430
  }
425
- function j(e) {
431
+ function X(e) {
426
432
  try {
427
433
  const t = JSON.parse(e);
428
434
  return t && typeof t == "object" ? t : { type: "error", message: "Invalid server event" };
@@ -430,19 +436,19 @@ function j(e) {
430
436
  return { type: "error", message: "Invalid server event" };
431
437
  }
432
438
  }
433
- function $(e, t) {
439
+ function z(e, t) {
434
440
  if (!e || typeof e != "object")
435
441
  return [];
436
442
  const s = e[t];
437
443
  return Array.isArray(s) ? s.filter((r) => typeof r == "string" && r.trim().length > 0) : [];
438
444
  }
439
- function X(e) {
445
+ function F(e) {
440
446
  if (!e || typeof e != "object")
441
447
  return null;
442
448
  const t = e.javascript;
443
449
  return typeof t != "string" || !t.trim() ? null : { javascript: t };
444
450
  }
445
- function z(e, t) {
451
+ function J(e, t) {
446
452
  return t ? e && typeof e == "object" ? {
447
453
  ...e,
448
454
  helperError: t
@@ -452,23 +458,23 @@ function z(e, t) {
452
458
  helperError: t
453
459
  } : e;
454
460
  }
455
- function F(e) {
461
+ function v(e) {
456
462
  if (!e || typeof e != "object")
457
463
  return e;
458
464
  const t = e;
459
465
  return typeof t.exception?.message == "string" ? t.exception.message : typeof t.error == "string" ? t.error : e;
460
466
  }
461
- function J() {
467
+ function G() {
462
468
  const e = "pluno.productAgent.clientId", t = window.localStorage.getItem(e);
463
469
  if (t)
464
470
  return t;
465
471
  const s = crypto.randomUUID();
466
472
  return window.localStorage.setItem(e, s), s;
467
473
  }
468
- function G() {
474
+ function W() {
469
475
  return crypto.randomUUID();
470
476
  }
471
- function W(e) {
477
+ function K(e) {
472
478
  if (!e || typeof e != "object")
473
479
  return null;
474
480
  const t = e, s = typeof t.id == "string" ? t.id : null;
@@ -479,12 +485,12 @@ function W(e) {
479
485
  avatarUrl: typeof t.avatarUrl == "string" ? t.avatarUrl : null
480
486
  } : null;
481
487
  }
482
- function v(e) {
488
+ function Y(e) {
483
489
  return Array.isArray(e) ? S(
484
- e.map(C).filter((t) => t !== null)
490
+ e.map(b).filter((t) => t !== null)
485
491
  ) : [];
486
492
  }
487
- function C(e) {
493
+ function b(e) {
488
494
  if (!e || typeof e != "object")
489
495
  return null;
490
496
  const t = e, s = t.data;
@@ -496,29 +502,29 @@ function C(e) {
496
502
  return {
497
503
  id: String(t.id ?? crypto.randomUUID()),
498
504
  role: n,
499
- content: Z(r.content),
505
+ content: tt(r.content),
500
506
  createdAt: typeof t.createdAt == "string" ? t.createdAt : (/* @__PURE__ */ new Date()).toISOString()
501
507
  };
502
508
  }
503
509
  return r.type === "function_call" || r.type === "tool_call" || r.type === "web_search_call" ? {
504
510
  id: String(t.id ?? crypto.randomUUID()),
505
511
  role: "tool",
506
- content: Y(r),
512
+ content: Z(r),
507
513
  createdAt: typeof t.createdAt == "string" ? t.createdAt : (/* @__PURE__ */ new Date()).toISOString(),
508
514
  dataType: String(r.type),
509
515
  loading: r.localExecutionStatus === "running"
510
516
  } : r.type === "run_status" || r.type === "run_error" ? r.type === "run_status" && (r.status === "running" || r.status === "retrying") || r.type === "run_error" && r.stage === "tool_execution" ? null : {
511
517
  id: String(t.id ?? crypto.randomUUID()),
512
518
  role: "system",
513
- content: K(r),
519
+ content: V(r),
514
520
  createdAt: typeof t.createdAt == "string" ? t.createdAt : (/* @__PURE__ */ new Date()).toISOString(),
515
521
  dataType: String(r.type)
516
522
  } : null;
517
523
  }
518
- function K(e) {
524
+ function V(e) {
519
525
  return typeof e.message == "string" && e.message.trim().length > 0 ? e.message : e.type === "run_status" && e.status === "interrupted" ? "Product Agent was interrupted before it could finish this message." : e.type === "run_status" && e.status === "stopped" ? "Product Agent stopped." : "Product Agent run status changed.";
520
526
  }
521
- function Y(e) {
527
+ function Z(e) {
522
528
  if (e.type === "web_search_call") {
523
529
  const t = e.action;
524
530
  if (t && typeof t == "object") {
@@ -530,9 +536,9 @@ function Y(e) {
530
536
  }
531
537
  return "Searching the web";
532
538
  }
533
- return V(e);
539
+ return Q(e);
534
540
  }
535
- function V(e) {
541
+ function Q(e) {
536
542
  if (typeof e.summary == "string" && e.summary.trim().length > 0)
537
543
  return e.summary;
538
544
  if (typeof e.arguments == "string")
@@ -545,7 +551,7 @@ function V(e) {
545
551
  }
546
552
  return typeof e.name == "string" && e.name.trim().length > 0 ? e.name : "Run tool";
547
553
  }
548
- function Z(e) {
554
+ function tt(e) {
549
555
  return typeof e == "string" ? e : Array.isArray(e) ? e.map((t) => {
550
556
  if (!t || typeof t != "object")
551
557
  return "";
@@ -553,14 +559,14 @@ function Z(e) {
553
559
  return typeof s.text == "string" ? s.text : typeof s.content == "string" ? s.content : "";
554
560
  }).filter(Boolean).join("") : "";
555
561
  }
556
- function Q(e, t) {
557
- const s = tt(e, t), r = s.findIndex((i) => i.id === t.id);
562
+ function et(e, t) {
563
+ const s = st(e, t), r = s.findIndex((i) => i.id === t.id);
558
564
  if (r === -1)
559
565
  return S([...s, t]);
560
566
  const n = [...s];
561
567
  return n[r] = t, S(n);
562
568
  }
563
- function tt(e, t) {
569
+ function st(e, t) {
564
570
  if (t.role !== "user")
565
571
  return e;
566
572
  const s = e.findIndex(
@@ -571,11 +577,15 @@ function tt(e, t) {
571
577
  const r = [...e];
572
578
  return r.splice(s, 1), r;
573
579
  }
574
- function et(e) {
575
- const t = st(e);
576
- return t === null ? !1 : e.slice(t + 1).some((s) => !s || typeof s != "object" ? !1 : D(s.data));
580
+ function rt(e) {
581
+ const t = D(e);
582
+ return t === null ? !1 : e.slice(t + 1).some((s) => !s || typeof s != "object" ? !1 : N(s.data));
583
+ }
584
+ function nt(e) {
585
+ const t = D(e);
586
+ return t === null ? e.some((s) => !s || typeof s != "object" ? !1 : I(s.data)) : e.slice(t + 1).some((s) => !s || typeof s != "object" ? !1 : I(s.data));
577
587
  }
578
- function st(e) {
588
+ function D(e) {
579
589
  for (let t = e.length - 1; t >= 0; t -= 1) {
580
590
  const s = e[t];
581
591
  if (!s || typeof s != "object")
@@ -589,19 +599,25 @@ function st(e) {
589
599
  }
590
600
  return null;
591
601
  }
592
- function D(e) {
602
+ function I(e) {
603
+ if (!e || typeof e != "object")
604
+ return !1;
605
+ const t = e;
606
+ return t.type === "message" && t.role === "assistant";
607
+ }
608
+ function N(e) {
593
609
  if (!e || typeof e != "object")
594
610
  return !1;
595
611
  const t = e;
596
612
  return t.type === "message" && t.role === "assistant" ? !0 : t.type === "run_error" ? t.stage !== "tool_execution" : t.type === "run_status" && (t.status === "stopped" || t.status === "interrupted");
597
613
  }
598
614
  function S(e) {
599
- return e.filter((t, s) => rt(t) ? !nt(e, s) : !0);
615
+ return e.filter((t, s) => ot(t) ? !it(e, s) : !0);
600
616
  }
601
- function rt(e) {
617
+ function ot(e) {
602
618
  return e.role === "system" && (e.dataType === "run_status" || e.dataType === "run_error");
603
619
  }
604
- function nt(e, t) {
620
+ function it(e, t) {
605
621
  for (let s = t + 1; s < e.length; s += 1) {
606
622
  const r = e[s];
607
623
  if (r.role === "user")
@@ -611,15 +627,15 @@ function nt(e, t) {
611
627
  }
612
628
  return !1;
613
629
  }
614
- function I(e, t) {
630
+ function k(e, t) {
615
631
  return e && typeof e == "object" && typeof e[t] == "string" ? e[t] : null;
616
632
  }
617
- function ot(e) {
633
+ function at(e) {
618
634
  try {
619
- const t = window.localStorage.getItem(`${R}${e}`);
635
+ const t = window.localStorage.getItem(`${M}${e}`);
620
636
  if (!t)
621
637
  return null;
622
- const s = JSON.parse(t), r = Array.isArray(s.messages) ? s.messages.map(at).filter((n) => !!n) : [];
638
+ const s = JSON.parse(t), r = Array.isArray(s.messages) ? s.messages.map(ut).filter((n) => !!n) : [];
623
639
  return {
624
640
  sessionId: typeof s.sessionId == "string" ? s.sessionId : null,
625
641
  messages: r
@@ -628,10 +644,10 @@ function ot(e) {
628
644
  return null;
629
645
  }
630
646
  }
631
- function it(e, t) {
647
+ function ct(e, t) {
632
648
  try {
633
649
  window.localStorage.setItem(
634
- `${R}${e}`,
650
+ `${M}${e}`,
635
651
  JSON.stringify({
636
652
  sessionId: t.sessionId,
637
653
  messages: t.messages.slice(-100)
@@ -641,7 +657,7 @@ function it(e, t) {
641
657
  return;
642
658
  }
643
659
  }
644
- function at(e) {
660
+ function ut(e) {
645
661
  if (!e || typeof e != "object")
646
662
  return null;
647
663
  const t = e;
@@ -654,59 +670,59 @@ function at(e) {
654
670
  loading: typeof t.loading == "boolean" ? t.loading : void 0
655
671
  };
656
672
  }
657
- function ct(e) {
673
+ function lt(e) {
658
674
  return !!e && typeof e == "object" && typeof e.summary == "string" && typeof e.javascript == "string";
659
675
  }
660
- function k(e) {
676
+ function R(e) {
661
677
  const t = {};
662
678
  return e?.forEach((s, r) => {
663
679
  t[r] = s;
664
680
  }), t;
665
681
  }
666
- async function ut(e, t) {
682
+ async function dt(e, t) {
667
683
  if (typeof t?.body < "u")
668
- return b(t.body);
684
+ return H(t.body);
669
685
  if (e)
670
686
  try {
671
- return p(await e.clone().text());
687
+ return f(await e.clone().text());
672
688
  } catch {
673
689
  return;
674
690
  }
675
691
  }
676
- async function lt(e) {
692
+ async function ft(e) {
677
693
  try {
678
- return p(await e.clone().text());
694
+ return f(await e.clone().text());
679
695
  } catch (t) {
680
696
  return { error: t instanceof Error ? t.message : "unavailable" };
681
697
  }
682
698
  }
683
- function dt(e) {
699
+ function pt(e) {
684
700
  try {
685
- return e.responseType === "" || e.responseType === "text" ? p(e.responseText ?? "") : e.responseType === "json" ? p(JSON.stringify(e.response)) : `[unsupported xhr responseType: ${e.responseType || "unknown"}]`;
701
+ return e.responseType === "" || e.responseType === "text" ? f(e.responseText ?? "") : e.responseType === "json" ? f(JSON.stringify(e.response)) : `[unsupported xhr responseType: ${e.responseType || "unknown"}]`;
686
702
  } catch (t) {
687
703
  return { error: t instanceof Error ? t.message : "unavailable" };
688
704
  }
689
705
  }
690
- function b(e) {
706
+ function H(e) {
691
707
  if (!(e === null || typeof e > "u")) {
692
708
  if (typeof e == "string")
693
- return p(e);
709
+ return f(e);
694
710
  if (e instanceof URLSearchParams)
695
- return p(e.toString());
711
+ return f(e.toString());
696
712
  if (e instanceof FormData) {
697
713
  const t = [];
698
- return e.forEach((s, r) => t.push([r, s instanceof File ? `[file:${s.name}]` : String(s)])), p(JSON.stringify(t));
714
+ return e.forEach((s, r) => t.push([r, s instanceof File ? `[file:${s.name}]` : String(s)])), f(JSON.stringify(t));
699
715
  }
700
716
  if (e instanceof Blob)
701
717
  return `[blob:${e.type || "application/octet-stream"}:${e.size}]`;
702
718
  try {
703
- return p(JSON.stringify(e));
719
+ return f(JSON.stringify(e));
704
720
  } catch {
705
721
  return `[unserializable body: ${Object.prototype.toString.call(e)}]`;
706
722
  }
707
723
  }
708
724
  }
709
- function pt(e) {
725
+ function ht(e) {
710
726
  const t = {};
711
727
  for (const s of e.trim().split(/[\r\n]+/)) {
712
728
  const r = s.indexOf(":");
@@ -714,22 +730,22 @@ function pt(e) {
714
730
  }
715
731
  return t;
716
732
  }
717
- function p(e) {
733
+ function f(e) {
718
734
  return e.length <= 1e5 ? e : `${e.slice(0, 1e5)}... [truncated ${e.length - 1e5} chars]`;
719
735
  }
720
736
  function y(e) {
721
737
  return `${e}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
722
738
  }
723
- const E = "[REDACTED_SECRET]", d = "[REDACTED_TOKEN]", ft = "[REDACTED_SIGNED_URL]", ht = 20, gt = /^(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, H = /\bBasic\s+[A-Za-z0-9+/=-]{12,}/gi, q = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, U = /\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, yt = /\bhttps?:\/\/[^\s"'<>]+(?:X-Amz-Signature|X-Goog-Signature|Signature|sig=)[^\s"'<>]*/gi, mt = /\bhttps?:\/\/[^\s"'<>]+/gi, St = /[),.;\]]+$/;
724
- function f(e) {
739
+ const T = "[REDACTED_SECRET]", d = "[REDACTED_TOKEN]", gt = "[REDACTED_SIGNED_URL]", yt = 20, mt = /^(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, U = /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/gi, q = /\bBasic\s+[A-Za-z0-9+/=-]{12,}/gi, P = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, x = /\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, St = /\bhttps?:\/\/[^\s"'<>]+(?:X-Amz-Signature|X-Goog-Signature|Signature|sig=)[^\s"'<>]*/gi, Tt = /\bhttps?:\/\/[^\s"'<>]+/gi, Et = /[),.;\]]+$/;
740
+ function p(e) {
725
741
  return m(e, 0, /* @__PURE__ */ new WeakSet());
726
742
  }
727
743
  function m(e, t, s) {
728
744
  if (typeof e == "string")
729
- return Tt(e);
745
+ return At(e);
730
746
  if (e === null || typeof e != "object")
731
747
  return e;
732
- if (t >= ht)
748
+ if (t >= yt)
733
749
  return "[REDACTED_MAX_DEPTH]";
734
750
  if (s.has(e))
735
751
  return "[REDACTED_CIRCULAR]";
@@ -737,37 +753,37 @@ function m(e, t, s) {
737
753
  return e.map((n) => m(n, t + 1, s));
738
754
  const r = {};
739
755
  for (const [n, i] of Object.entries(e))
740
- Et(n) ? r[n] = E : r[n] = n.toLowerCase() === "url" ? _t(i) : m(i, t + 1, s);
756
+ _t(n) ? r[n] = T : r[n] = n.toLowerCase() === "url" ? wt(i) : m(i, t + 1, s);
741
757
  return r;
742
758
  }
743
- function Et(e) {
759
+ function _t(e) {
744
760
  const t = e.replace(/[^a-z0-9]/gi, "").toLowerCase();
745
761
  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");
746
762
  }
747
- function _t(e) {
748
- return typeof e == "string" ? P(e) : m(e, 0, /* @__PURE__ */ new WeakSet());
763
+ function wt(e) {
764
+ return typeof e == "string" ? B(e) : m(e, 0, /* @__PURE__ */ new WeakSet());
749
765
  }
750
- function P(e) {
766
+ function B(e) {
751
767
  try {
752
768
  const t = new URL(e, location.href);
753
769
  for (const s of Array.from(t.searchParams.keys()))
754
- gt.test(s) && t.searchParams.set(s, d);
770
+ mt.test(s) && t.searchParams.set(s, d);
755
771
  return t.username && (t.username = d), t.password && (t.password = d), t.toString();
756
772
  } catch {
757
- return wt(e);
773
+ return It(e);
758
774
  }
759
775
  }
760
- function Tt(e) {
761
- return e.replace(yt, ft).replace(mt, At).replace(N, `Bearer ${d}`).replace(H, `Basic ${d}`).replace(q, d).replace(U, (t, s) => `${s}: ${E}`);
776
+ function At(e) {
777
+ return e.replace(St, gt).replace(Tt, kt).replace(U, `Bearer ${d}`).replace(q, `Basic ${d}`).replace(P, d).replace(x, (t, s) => `${s}: ${T}`);
762
778
  }
763
- function wt(e) {
764
- return e.replace(N, `Bearer ${d}`).replace(H, `Basic ${d}`).replace(q, d).replace(U, (t, s) => `${s}: ${E}`);
779
+ function It(e) {
780
+ return e.replace(U, `Bearer ${d}`).replace(q, `Basic ${d}`).replace(P, d).replace(x, (t, s) => `${s}: ${T}`);
765
781
  }
766
- function At(e) {
767
- const t = e.match(St)?.[0] ?? "", s = t ? e.slice(0, -t.length) : e;
768
- return `${P(s)}${t}`;
782
+ function kt(e) {
783
+ const t = e.match(Et)?.[0] ?? "", s = t ? e.slice(0, -t.length) : e;
784
+ return `${B(s)}${t}`;
769
785
  }
770
786
  export {
771
- M as PlunoProductAgent,
772
- M as default
787
+ C as PlunoProductAgent,
788
+ C as default
773
789
  };
@@ -1,16 +1,16 @@
1
- import { PlunoProductAgent as K } from "./product-agent-sdk.js";
2
- const L = {
1
+ import { PlunoProductAgent as I } from "./product-agent-sdk.js";
2
+ const S = {
3
3
  launcherLabel: "Ask for anything...",
4
4
  accentColor: "#18181b",
5
5
  colorScheme: "light",
6
6
  position: "bottom-right"
7
7
  };
8
- async function G(e = {}) {
8
+ async function K(e = {}) {
9
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,
10
+ launcherLabel: e.launcherLabel ?? S.launcherLabel,
11
+ accentColor: e.accentColor ?? S.accentColor,
12
+ colorScheme: e.colorScheme ?? S.colorScheme,
13
+ position: e.position ?? S.position,
14
14
  token: e.token,
15
15
  tokenProvider: e.tokenProvider,
16
16
  tokenEndpoint: e.tokenEndpoint,
@@ -21,7 +21,7 @@ async function G(e = {}) {
21
21
  const n = o.attachShadow({ mode: "open" }), a = document.createElement("div");
22
22
  a.className = `pluno-pa-widget pluno-pa-widget--${t.position}`, a.innerHTML = `
23
23
  <form class="pluno-pa-widget__launcher">
24
- <input class="pluno-pa-widget__launcher-input" type="text" placeholder="${W(t.launcherLabel)}" aria-label="${W(t.launcherLabel)}" />
24
+ <input class="pluno-pa-widget__launcher-input" type="text" placeholder="${B(t.launcherLabel)}" aria-label="${B(t.launcherLabel)}" />
25
25
  </form>
26
26
  <button type="button" class="pluno-pa-widget__close" aria-label="Close" hidden>
27
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">
@@ -53,12 +53,12 @@ async function G(e = {}) {
53
53
  </form>
54
54
  </section>
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}`), F(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"), u = 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"), _ = a.querySelector(".pluno-pa-widget__timeline");
59
- if (!l || !d || !r || !u || !h || !i || !p || !g || !_)
56
+ const w = await J(), s = w.ownerDocument;
57
+ w.appendChild(o), a.classList.add(`pluno-pa-widget--${t.colorScheme}`), U(n, t.accentColor);
58
+ const l = a.querySelector(".pluno-pa-widget__launcher"), d = a.querySelector(".pluno-pa-widget__launcher-input"), i = a.querySelector(".pluno-pa-widget__panel"), u = a.querySelector(".pluno-pa-widget__close"), h = a.querySelector(".pluno-pa-widget__composer"), r = a.querySelector(".pluno-pa-widget__input"), p = a.querySelector(".pluno-pa-widget__send"), g = a.querySelector(".pluno-pa-widget__new-chat"), f = a.querySelector(".pluno-pa-widget__timeline");
59
+ if (!l || !d || !i || !u || !h || !r || !p || !g || !f)
60
60
  throw new Error("Failed to mount Product Agent widget");
61
- const b = t.token || t.webSocketFactory ? void 0 : t.tokenProvider ?? (async () => {
61
+ const _ = t.token || t.webSocketFactory ? void 0 : t.tokenProvider ?? (async () => {
62
62
  if (!t.tokenEndpoint)
63
63
  throw new Error("Product Agent widget requires token or tokenEndpoint");
64
64
  const c = await fetch(t.tokenEndpoint, {
@@ -69,99 +69,99 @@ async function G(e = {}) {
69
69
  });
70
70
  if (!c.ok)
71
71
  throw new Error("Failed to load Product Agent token");
72
- const y = await c.json();
73
- if (!y.token)
72
+ const v = await c.json();
73
+ if (!v.token)
74
74
  throw new Error("Product Agent token endpoint did not return a token");
75
- return y.token;
76
- }), m = await K.init({
75
+ return v.token;
76
+ }), m = await I.init({
77
77
  token: t.token,
78
- tokenProvider: b,
78
+ tokenProvider: _,
79
79
  backendUrl: t.backendUrl,
80
80
  webSocketFactory: t.webSocketFactory
81
- }), E = J(t), S = new Set(E.openToolGroupKeys);
82
- let x = null, N = !1;
81
+ }), C = Z(t), E = new Set(C.openToolGroupKeys);
82
+ let b = null, z = !1;
83
83
  const q = () => {
84
- N || typeof document > "u" || (F(n, t.accentColor), o.isConnected || s.body?.appendChild(o));
85
- }, P = new MutationObserver(q);
86
- P.observe(s.documentElement, { childList: !0, subtree: !0 });
87
- const v = () => {
88
- Z(t, {
84
+ z || typeof document > "u" || (U(n, t.accentColor), o.isConnected || s.body?.appendChild(o));
85
+ }, M = new MutationObserver(q);
86
+ M.observe(s.documentElement, { childList: !0, subtree: !0 });
87
+ const x = () => {
88
+ Q(t, {
89
89
  isOpen: a.classList.contains("pluno-pa-widget--open"),
90
- composerValue: i.value,
91
- openToolGroupKeys: [...S]
90
+ composerValue: r.value,
91
+ openToolGroupKeys: [...E]
92
92
  });
93
- }, k = (c = "", y = !0) => {
94
- if (x !== null && (window.clearTimeout(x), x = null), r.hidden = !1, u.hidden = !1, a.classList.remove("pluno-pa-widget--closing"), !y) {
95
- a.classList.add("pluno-pa-widget--open"), l.hidden = !0, c && (i.value = c, C(i)), i.focus(), i.setSelectionRange(i.value.length, i.value.length), v();
93
+ }, y = (c = "", v = !0) => {
94
+ if (b !== null && (window.clearTimeout(b), b = null), i.hidden = !1, u.hidden = !1, a.classList.remove("pluno-pa-widget--closing"), !v) {
95
+ a.classList.add("pluno-pa-widget--open"), l.hidden = !0, c && (r.value = c, k(r)), r.focus(), r.setSelectionRange(r.value.length, r.value.length), x();
96
96
  return;
97
97
  }
98
98
  window.requestAnimationFrame(() => {
99
- a.classList.add("pluno-pa-widget--open"), c && (i.value = c, C(i)), i.focus(), i.setSelectionRange(i.value.length, i.value.length), v(), x = window.setTimeout(() => {
99
+ a.classList.add("pluno-pa-widget--open"), c && (r.value = c, k(r)), r.focus(), r.setSelectionRange(r.value.length, r.value.length), x(), b = window.setTimeout(() => {
100
100
  l.hidden = !0;
101
101
  }, 220);
102
102
  });
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, u.hidden = !0, a.classList.remove("pluno-pa-widget--closing");
103
+ }, N = () => {
104
+ b !== null && (window.clearTimeout(b), b = null), l.hidden = !1, a.classList.add("pluno-pa-widget--closing"), a.classList.remove("pluno-pa-widget--open"), x(), b = window.setTimeout(() => {
105
+ i.hidden = !0, u.hidden = !0, a.classList.remove("pluno-pa-widget--closing");
106
106
  }, 220);
107
107
  };
108
108
  l.addEventListener("submit", (c) => {
109
- c.preventDefault(), k(d.value), d.value = "";
109
+ c.preventDefault(), y(d.value), d.value = "";
110
110
  }), d.addEventListener("focus", () => {
111
- k(d.value), d.value = "";
111
+ y(d.value), d.value = "";
112
112
  }), d.addEventListener("input", () => {
113
113
  if (!d.value)
114
114
  return;
115
115
  const c = d.value;
116
- k(c), d.value = "";
117
- }), u.addEventListener("click", A);
118
- const M = (c) => {
116
+ y(c), d.value = "";
117
+ }), u.addEventListener("click", N);
118
+ const P = (c) => {
119
119
  if (!(!c.metaKey || c.key.toLowerCase() !== "k")) {
120
- if (c.preventDefault(), r.hidden || !a.classList.contains("pluno-pa-widget--open")) {
121
- k();
120
+ if (c.preventDefault(), i.hidden || !a.classList.contains("pluno-pa-widget--open")) {
121
+ y();
122
122
  return;
123
123
  }
124
- A();
124
+ N();
125
125
  }
126
126
  };
127
- return s.addEventListener("keydown", M), h.addEventListener("submit", (c) => {
128
- c.preventDefault(), z(m, i);
127
+ return s.addEventListener("keydown", P), h.addEventListener("submit", (c) => {
128
+ c.preventDefault(), T(m, r);
129
129
  }), p.addEventListener("click", () => {
130
130
  if (m.getState().isThinking) {
131
131
  m.stop();
132
132
  return;
133
133
  }
134
- z(m, i);
134
+ T(m, r);
135
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", (c) => {
140
- c.key !== "Enter" || c.shiftKey || (c.preventDefault(), z(m, i));
141
- }), E.composerValue && (i.value = E.composerValue, C(i)), E.isOpen && k(i.value, !1), m.on(
136
+ m.startNewSession(), E.clear(), r.value = "", k(r), x(), r.focus();
137
+ }), r.addEventListener("input", () => {
138
+ k(r), x();
139
+ }), r.addEventListener("keydown", (c) => {
140
+ c.key !== "Enter" || c.shiftKey || (c.preventDefault(), T(m, r));
141
+ }), C.composerValue && (r.value = C.composerValue, k(r)), C.isOpen && y(r.value, !1), m.on(
142
142
  "state",
143
- (c) => $(_, p, g, c, S, v, (y) => {
144
- m.sendMessage(y);
143
+ (c) => A(f, p, g, c, E, x, (v) => {
144
+ m.sendMessage(v);
145
145
  })
146
- ), $(_, p, g, m.getState(), S, v, (c) => {
146
+ ), A(f, p, g, m.getState(), E, x, (c) => {
147
147
  m.sendMessage(c);
148
148
  }), {
149
149
  agent: m,
150
150
  destroy: () => {
151
- N = !0, P.disconnect(), m.destroy(), s.removeEventListener("keydown", M), o.remove();
151
+ z = !0, M.disconnect(), m.destroy(), s.removeEventListener("keydown", P), o.remove();
152
152
  }
153
153
  };
154
154
  }
155
- function z(e, t) {
155
+ function T(e, t) {
156
156
  const o = t.value.trim();
157
157
  o && (t.value = "", t.style.height = "22px", t.style.overflowY = "hidden", e.sendMessage(o), t.dispatchEvent(new Event("input", { bubbles: !0 })));
158
158
  }
159
- function C(e) {
159
+ function k(e) {
160
160
  e.style.height = "0px";
161
161
  const t = Math.max(22, Math.min(e.scrollHeight, 140));
162
162
  e.style.height = `${t}px`, e.style.overflowY = e.scrollHeight > 140 ? "auto" : "hidden";
163
163
  }
164
- function $(e, t, o, n, a, w, s) {
164
+ function A(e, t, o, n, a, w, s) {
165
165
  const l = [...n.messages];
166
166
  e.innerHTML = "", V(t, n.isThinking);
167
167
  const d = l.length > 0 || !!n.assistantDraft;
@@ -170,25 +170,25 @@ function $(e, t, o, n, a, w, s) {
170
170
  p.className = n.starterPrompts.length > 0 ? "pluno-pa-widget__empty-state pluno-pa-widget__empty-state--starter" : "pluno-pa-widget__empty-state";
171
171
  const g = document.createElement("div");
172
172
  if (g.className = "pluno-pa-widget__empty", g.textContent = "What do you want to do today?", p.appendChild(g), n.starterPrompts.length > 0) {
173
- const _ = document.createElement("div");
174
- _.className = "pluno-pa-widget__starter-prompts";
175
- for (const b of n.starterPrompts) {
173
+ const f = document.createElement("div");
174
+ f.className = "pluno-pa-widget__starter-prompts";
175
+ for (const _ of n.starterPrompts) {
176
176
  const m = document.createElement("button");
177
- m.type = "button", m.className = "pluno-pa-widget__starter-prompt", m.textContent = `"${b}"`, m.addEventListener("click", () => {
178
- s(b);
179
- }), _.appendChild(m);
177
+ m.type = "button", m.className = "pluno-pa-widget__starter-prompt", m.textContent = `"${_}"`, m.addEventListener("click", () => {
178
+ s(_);
179
+ }), f.appendChild(m);
180
180
  }
181
- p.appendChild(_);
181
+ p.appendChild(f);
182
182
  }
183
183
  e.appendChild(p);
184
184
  return;
185
185
  }
186
- let r = null, u = null, h = [];
187
- const i = () => {
186
+ let i = null, u = null, h = [];
187
+ const r = () => {
188
188
  if (h.length === 0)
189
189
  return;
190
- const p = I(h, a, w);
191
- e.appendChild(p), r = null, u = p, h = [];
190
+ const p = R(h, a, w);
191
+ e.appendChild(p), i = null, u = p, h = [];
192
192
  };
193
193
  for (let p = 0; p < l.length; p += 1) {
194
194
  const g = l[p];
@@ -198,67 +198,67 @@ function $(e, t, o, n, a, w, s) {
198
198
  }
199
199
  if (g.role === "system")
200
200
  continue;
201
- i();
202
- const _ = O(g.content), b = document.createElement("div");
203
- b.className = `pluno-pa-widget__message pluno-pa-widget__message--${g.role}`, g.role === "assistant" ? B(b, _) : b.textContent = _, b.appendChild(D(_)), e.appendChild(b), r = b, u = null;
201
+ r();
202
+ const f = D(g.content), _ = document.createElement("div");
203
+ _.className = `pluno-pa-widget__message pluno-pa-widget__message--${g.role}`, g.role === "assistant" ? j(_, f) : _.textContent = f, _.appendChild($(f)), e.appendChild(_), i = _, u = null;
204
204
  }
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, u = null;
205
+ if (r(), n.assistantDraft) {
206
+ const p = D(n.assistantDraft), g = document.createElement("div");
207
+ g.className = "pluno-pa-widget__message pluno-pa-widget__message--assistant", j(g, p), g.appendChild($(p)), e.appendChild(g), i = g, u = null;
208
208
  }
209
209
  if (n.isThinking && !n.assistantDraft) {
210
210
  const p = document.createElement("div");
211
- p.className = "pluno-pa-widget__status", p.textContent = "Thinking...", e.appendChild(p), r = null, u = p;
211
+ p.className = "pluno-pa-widget__status", p.textContent = "Thinking...", e.appendChild(p), i = null, u = p;
212
212
  }
213
213
  if (n.lastError) {
214
214
  const p = document.createElement("div");
215
- p.className = "pluno-pa-widget__error", p.textContent = n.lastError, e.appendChild(p), r = p, u = null;
215
+ p.className = "pluno-pa-widget__error", p.textContent = n.lastError, e.appendChild(p), i = p, u = null;
216
216
  }
217
- r?.classList.add("pluno-pa-widget__message--bottom-reserve"), u?.classList.add("pluno-pa-widget__bottom-reserve-compact"), e.scrollTop = e.scrollHeight;
217
+ i?.classList.add("pluno-pa-widget__message--bottom-reserve"), u?.classList.add("pluno-pa-widget__bottom-reserve-compact"), e.scrollTop = e.scrollHeight;
218
218
  }
219
- function D(e) {
219
+ function $(e) {
220
220
  const t = document.createElement("button");
221
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
222
  o.preventDefault(), o.stopPropagation(), navigator.clipboard.writeText(e);
223
223
  }), t;
224
224
  }
225
- function O(e) {
225
+ function D(e) {
226
226
  return e.replace(/\uE200[^\uE201]*(?:\uE201|$)/g, "");
227
227
  }
228
- function I(e, t, o) {
228
+ function R(e, t, o) {
229
229
  const n = document.createElement("article");
230
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);
231
+ const a = document.createElement("details"), w = G(e);
232
232
  a.open = t.has(w), a.addEventListener("toggle", () => {
233
233
  a.open ? t.add(w) : t.delete(w), o();
234
234
  });
235
235
  const s = document.createElement("summary");
236
- s.className = "pluno-pa-widget__tool-summary", e.some((r) => r.loading) && s.appendChild(j());
236
+ s.className = "pluno-pa-widget__tool-summary", e.some((i) => i.loading) && s.appendChild(O());
237
237
  const d = document.createElement("span");
238
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";
239
+ const i = document.createElement("div");
240
+ i.className = "pluno-pa-widget__tool-lines";
241
241
  for (const u of e) {
242
242
  const h = document.createElement("div");
243
- h.className = "pluno-pa-widget__tool-line", u.loading && h.appendChild(j());
244
- const i = document.createElement("span");
245
- i.textContent = u.content || "Run tool", h.appendChild(i), r.appendChild(h);
243
+ h.className = "pluno-pa-widget__tool-line", u.loading && h.appendChild(O());
244
+ const r = document.createElement("span");
245
+ r.textContent = u.content || "Run tool", h.appendChild(r), i.appendChild(h);
246
246
  }
247
- a.appendChild(r);
247
+ a.appendChild(i);
248
248
  }
249
249
  return n.appendChild(a), n;
250
250
  }
251
- function U(e) {
251
+ function G(e) {
252
252
  return `tools:${e.map((t) => t.id).join("|")}`;
253
253
  }
254
- function j() {
254
+ function O() {
255
255
  const e = document.createElement("span");
256
256
  return e.className = "pluno-pa-widget__spinner", e.setAttribute("aria-hidden", "true"), e;
257
257
  }
258
258
  function V(e, t) {
259
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>';
260
260
  }
261
- function B(e, t) {
261
+ function j(e, t) {
262
262
  const o = t.replace(/\r\n/g, `
263
263
  `).split(`
264
264
  `);
@@ -270,49 +270,49 @@ function B(e, t) {
270
270
  continue;
271
271
  }
272
272
  if (a.match(/^```(\w+)?\s*$/)) {
273
- const r = [];
273
+ const i = [];
274
274
  for (n += 1; n < o.length && !/^```\s*$/.test(o[n]); )
275
- r.push(o[n]), n += 1;
275
+ i.push(o[n]), n += 1;
276
276
  n += n < o.length ? 1 : 0;
277
277
  const u = document.createElement("pre"), h = document.createElement("code");
278
- h.textContent = r.join(`
278
+ h.textContent = i.join(`
279
279
  `), u.appendChild(h), e.appendChild(u);
280
280
  continue;
281
281
  }
282
282
  const s = a.match(/^(#{1,3})\s+(.+)$/);
283
283
  if (s) {
284
- const r = document.createElement(`h${s[1].length + 2}`);
285
- T(r, s[2]), e.appendChild(r), n += 1;
284
+ const i = document.createElement(`h${s[1].length + 2}`);
285
+ L(i, s[2]), e.appendChild(i), n += 1;
286
286
  continue;
287
287
  }
288
288
  if (/^\s*[-*+]\s+/.test(a)) {
289
- const r = document.createElement("ul");
289
+ const i = document.createElement("ul");
290
290
  for (; n < o.length && /^\s*[-*+]\s+/.test(o[n]); ) {
291
291
  const u = document.createElement("li");
292
- T(u, o[n].replace(/^\s*[-*+]\s+/, "")), r.appendChild(u), n += 1;
292
+ L(u, o[n].replace(/^\s*[-*+]\s+/, "")), i.appendChild(u), n += 1;
293
293
  }
294
- e.appendChild(r);
294
+ e.appendChild(i);
295
295
  continue;
296
296
  }
297
297
  if (/^\s*\d+\.\s+/.test(a)) {
298
- const r = document.createElement("ol");
298
+ const i = document.createElement("ol");
299
299
  for (; n < o.length && /^\s*\d+\.\s+/.test(o[n]); ) {
300
300
  const u = document.createElement("li");
301
- T(u, o[n].replace(/^\s*\d+\.\s+/, "")), r.appendChild(u), n += 1;
301
+ L(u, o[n].replace(/^\s*\d+\.\s+/, "")), i.appendChild(u), n += 1;
302
302
  }
303
- e.appendChild(r);
303
+ e.appendChild(i);
304
304
  continue;
305
305
  }
306
306
  const l = [a];
307
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
308
  l.push(o[n]), n += 1;
309
309
  const d = document.createElement("p");
310
- l.forEach((r, u) => {
311
- u > 0 && d.appendChild(document.createElement("br")), T(d, r);
310
+ l.forEach((i, u) => {
311
+ u > 0 && d.appendChild(document.createElement("br")), L(d, i);
312
312
  }), e.appendChild(d);
313
313
  }
314
314
  }
315
- function T(e, t) {
315
+ function L(e, t) {
316
316
  const o = /(`[^`]+`|\*\*[^*]+\*\*|\*[^*]+\*|\[[^\]]+\]\(([^)\s]+)\))/g;
317
317
  let n = 0;
318
318
  for (const a of t.matchAll(o)) {
@@ -350,7 +350,7 @@ function Y(e) {
350
350
  return !1;
351
351
  }
352
352
  }
353
- function F(e, t) {
353
+ function U(e, t) {
354
354
  if (e.getElementById("pluno-pa-widget-styles"))
355
355
  return;
356
356
  const o = e.ownerDocument.createElement("style");
@@ -1023,7 +1023,7 @@ function F(e, t) {
1023
1023
  }
1024
1024
  `, e.appendChild(o);
1025
1025
  }
1026
- async function R() {
1026
+ async function J() {
1027
1027
  return document.body ? document.body : await new Promise((e) => {
1028
1028
  const t = new MutationObserver(() => {
1029
1029
  document.body && (t.disconnect(), e(document.body));
@@ -1031,16 +1031,16 @@ async function R() {
1031
1031
  t.observe(document.documentElement, { childList: !0 });
1032
1032
  });
1033
1033
  }
1034
- function W(e) {
1034
+ function B(e) {
1035
1035
  const t = document.createElement("span");
1036
1036
  return t.textContent = e, t.innerHTML;
1037
1037
  }
1038
- function H(e) {
1038
+ function F(e) {
1039
1039
  return `pluno.productAgent.widgetState.${location.origin}.${e.backendUrl ?? ""}.${e.tokenEndpoint ?? ""}.${e.position ?? ""}`;
1040
1040
  }
1041
- function J(e) {
1041
+ function Z(e) {
1042
1042
  try {
1043
- const t = window.localStorage.getItem(H(e));
1043
+ const t = window.localStorage.getItem(F(e));
1044
1044
  if (!t)
1045
1045
  return { isOpen: !1, composerValue: "", openToolGroupKeys: [] };
1046
1046
  const o = JSON.parse(t);
@@ -1053,25 +1053,49 @@ function J(e) {
1053
1053
  return { isOpen: !1, composerValue: "", openToolGroupKeys: [] };
1054
1054
  }
1055
1055
  }
1056
- function Z(e, t) {
1056
+ function Q(e, t) {
1057
1057
  try {
1058
- window.localStorage.setItem(H(e), JSON.stringify(t));
1058
+ window.localStorage.setItem(F(e), JSON.stringify(t));
1059
1059
  } catch {
1060
1060
  return;
1061
1061
  }
1062
1062
  }
1063
- const f = document.currentScript;
1064
- f && f.dataset.plunoAutoMount !== "false" && G({
1065
- token: f?.dataset.plunoToken,
1066
- tokenEndpoint: f?.dataset.plunoTokenEndpoint,
1067
- backendUrl: f?.dataset.plunoBackendUrl,
1068
- launcherLabel: f?.dataset.plunoLauncherLabel,
1069
- accentColor: f?.dataset.plunoAccentColor,
1070
- colorScheme: f?.dataset.plunoColorScheme === "dark" ? "dark" : "light",
1071
- position: f?.dataset.plunoPosition === "bottom-left" ? "bottom-left" : "bottom-right"
1072
- }).catch((e) => {
1073
- console.error("Failed to mount Pluno Product Agent widget", e);
1074
- });
1063
+ const W = /* @__PURE__ */ new WeakSet();
1064
+ function X(e) {
1065
+ return Object.keys(e.dataset).some((t) => t.startsWith("pluno"));
1066
+ }
1067
+ function H(e) {
1068
+ const t = e.pathname.split("/");
1069
+ return t[t.length - 1] ?? "";
1070
+ }
1071
+ function ee(e, t) {
1072
+ const o = new URL(e.src, document.baseURI);
1073
+ return o.href === t.href || o.pathname === t.pathname ? !0 : H(o) === H(t);
1074
+ }
1075
+ function te(e) {
1076
+ const t = document.currentScript;
1077
+ if (t instanceof HTMLScriptElement)
1078
+ return [t];
1079
+ const o = new URL(e, document.baseURI).href, n = new URL(o);
1080
+ return Array.from(document.querySelectorAll("script[type='module'][src]")).filter(
1081
+ (a) => a instanceof HTMLScriptElement && X(a) && ee(a, n)
1082
+ );
1083
+ }
1084
+ function ne(e) {
1085
+ for (const t of te(e))
1086
+ W.has(t) || t.dataset.plunoAutoMount === "false" || (W.add(t), K({
1087
+ token: t.dataset.plunoToken,
1088
+ tokenEndpoint: t.dataset.plunoTokenEndpoint,
1089
+ backendUrl: t.dataset.plunoBackendUrl,
1090
+ launcherLabel: t.dataset.plunoLauncherLabel,
1091
+ accentColor: t.dataset.plunoAccentColor,
1092
+ colorScheme: t.dataset.plunoColorScheme === "dark" ? "dark" : "light",
1093
+ position: t.dataset.plunoPosition === "bottom-left" ? "bottom-left" : "bottom-right"
1094
+ }).catch((o) => {
1095
+ console.error("Failed to mount Pluno Product Agent widget", o);
1096
+ }));
1097
+ }
1098
+ ne(import.meta.url);
1075
1099
  export {
1076
- G as mountPlunoProductAgentWidget
1100
+ K as mountPlunoProductAgentWidget
1077
1101
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluno/product-agent-web",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Browser SDK and default widget for embedding Pluno Product Agent into customer web apps.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",