@pluno/product-agent-web 0.1.2 → 0.1.4

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 CHANGED
@@ -67,7 +67,7 @@ redaction pipeline before data leaves the browser.
67
67
  type="module"
68
68
  src="https://app.pluno.ai/product-agent/product-agent-widget.js"
69
69
  data-pluno-token-endpoint="/api/pluno-product-agent-token"
70
- data-pluno-launcher-label="Ask AI..."
70
+ data-pluno-launcher-label="Ask for anything..."
71
71
  data-pluno-accent-color="#18181b"
72
72
  data-pluno-color-scheme="light"
73
73
  data-pluno-position="bottom-right"
package/README.md CHANGED
@@ -42,7 +42,7 @@ The SDK always captures product network activity by patching `fetch` and `XMLHtt
42
42
  type="module"
43
43
  src="https://app.pluno.ai/product-agent/product-agent-widget.js"
44
44
  data-pluno-token-endpoint="/api/pluno-product-agent-token"
45
- data-pluno-launcher-label="Ask AI..."
45
+ data-pluno-launcher-label="Ask for anything..."
46
46
  data-pluno-accent-color="#18181b"
47
47
  ></script>
48
48
  ```
package/dist/index.d.ts CHANGED
@@ -64,6 +64,7 @@ export declare class PlunoProductAgent {
64
64
  private networkBatchTimer;
65
65
  private queuedNetworkEvents;
66
66
  private queuedClientEvents;
67
+ private retryAttemptsByClientMessageId;
67
68
  private state;
68
69
  private constructor();
69
70
  static init(options: ProductAgentInitOptions): Promise<PlunoProductAgent>;
@@ -79,6 +80,7 @@ export declare class PlunoProductAgent {
79
80
  private sendNow;
80
81
  private flushQueuedClientEvents;
81
82
  private handleServerEvent;
83
+ private retryAfterRetryableError;
82
84
  private executeToolCall;
83
85
  private enableNetworkCapture;
84
86
  private enqueueNetworkEvent;
@@ -1,9 +1,9 @@
1
1
  const O = "https://app.pluno.ai";
2
- const A = "pluno.productAgent.state.";
2
+ const k = "pluno.productAgent.state.";
3
3
  class I {
4
4
  constructor(t) {
5
5
  this.options = t;
6
- const s = W(t.clientId);
6
+ const s = v(t.clientId);
7
7
  s && (this.state = {
8
8
  ...this.state,
9
9
  ...s,
@@ -24,6 +24,7 @@ class I {
24
24
  networkBatchTimer = null;
25
25
  queuedNetworkEvents = [];
26
26
  queuedClientEvents = [];
27
+ retryAttemptsByClientMessageId = {};
27
28
  state = {
28
29
  status: "idle",
29
30
  user: null,
@@ -37,8 +38,8 @@ class I {
37
38
  static async init(t) {
38
39
  const s = new I({
39
40
  ...t,
40
- backendUrl: H(t.backendUrl ?? O),
41
- clientId: t.clientId ?? x()
41
+ backendUrl: U(t.backendUrl ?? O),
42
+ clientId: t.clientId ?? $()
42
43
  });
43
44
  try {
44
45
  s.enableNetworkCapture(), t.autoConnect !== !1 && await s.connect();
@@ -63,7 +64,7 @@ class I {
63
64
  return;
64
65
  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)
65
66
  throw new Error("Product Agent requires a token or tokenProvider");
66
- const t = U(this.options.backendUrl);
67
+ const t = B(this.options.backendUrl);
67
68
  this.socket = this.options.webSocketFactory?.(t) ?? new WebSocket(t), this.socket.addEventListener("open", () => {
68
69
  this.token && this.sendNow({ type: "auth.session", token: this.token, clientId: this.options.clientId }), this.flushQueuedClientEvents(), this.startHeartbeat(), this.setState({ status: "connected", lastError: null });
69
70
  }), this.socket.addEventListener("message", (s) => this.handleServerEvent(L(s.data))), this.socket.addEventListener("close", () => {
@@ -84,20 +85,21 @@ class I {
84
85
  const s = t.trim();
85
86
  if (!s)
86
87
  return;
87
- const n = m(), r = {
88
- id: `local-${Date.now()}`,
88
+ const n = m(), r = j(), o = {
89
+ id: `local-${r}`,
89
90
  role: "user",
90
91
  content: s,
91
92
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
92
93
  };
93
94
  this.setState({
94
- messages: [...this.state.messages, r],
95
+ messages: [...this.state.messages, o],
95
96
  assistantDraft: "",
96
97
  isThinking: !0,
97
98
  lastError: null
98
- }), this.emit("message", r), this.send({
99
+ }), this.emit("message", o), this.send({
99
100
  type: "chat.user_message",
100
101
  sessionId: this.state.sessionId ?? void 0,
102
+ clientMessageId: r,
101
103
  content: s,
102
104
  page: n,
103
105
  model: this.options.model,
@@ -142,8 +144,8 @@ class I {
142
144
  handleServerEvent(t) {
143
145
  if (t.type === "auth.ok") {
144
146
  this.setState({
145
- user: $(t.user),
146
- starterPrompts: B(t, "starterPrompts"),
147
+ user: X(t.user),
148
+ starterPrompts: x(t, "starterPrompts"),
147
149
  status: "connected"
148
150
  });
149
151
  return;
@@ -151,7 +153,7 @@ class I {
151
153
  if (t.type === "conversation.state") {
152
154
  this.setState({
153
155
  sessionId: _(t.session, "id") ?? this.state.sessionId,
154
- messages: j(t.items)
156
+ messages: z(t.items)
155
157
  });
156
158
  return;
157
159
  }
@@ -162,7 +164,7 @@ class I {
162
164
  if (t.type === "session.item") {
163
165
  const s = R(t.item);
164
166
  s && (this.setState({
165
- messages: F(this.state.messages, s),
167
+ messages: J(this.state.messages, s),
166
168
  assistantDraft: s.role === "assistant" ? "" : this.state.assistantDraft
167
169
  }), this.emit("message", s));
168
170
  return;
@@ -182,15 +184,34 @@ class I {
182
184
  return;
183
185
  }
184
186
  if (t.type === "error") {
187
+ if (this.retryAfterRetryableError(t))
188
+ return;
185
189
  const s = new Error(typeof t.message == "string" ? t.message : "Product Agent error");
186
190
  this.setState({ status: "error", isThinking: !1, lastError: s.message }), this.emit("error", s);
187
191
  }
188
192
  }
193
+ retryAfterRetryableError(t) {
194
+ const s = typeof t.sessionId == "string" ? t.sessionId : this.state.sessionId, n = typeof t.clientMessageId == "string" ? t.clientMessageId : null;
195
+ if (!(t.retryable === !0 || t.code === "transient_model_error") || !s || !n)
196
+ return !1;
197
+ const o = this.retryAttemptsByClientMessageId[n] ?? 0;
198
+ if (o >= 1)
199
+ return !1;
200
+ this.retryAttemptsByClientMessageId[n] = o + 1;
201
+ const a = typeof t.retryAfterMs == "number" ? t.retryAfterMs : 2e3;
202
+ return this.setState({ status: "reconnecting", isThinking: !0, lastError: null }), window.setTimeout(() => {
203
+ this.setState({ status: "connected", isThinking: !0, lastError: null }), this.send({
204
+ type: "chat.retry_last_user_message",
205
+ sessionId: s,
206
+ clientMessageId: n
207
+ });
208
+ }, a), !0;
209
+ }
189
210
  async executeToolCall(t) {
190
211
  const s = typeof t.sessionId == "string" ? t.sessionId : null, n = typeof t.callId == "string" ? t.callId : null, r = t.rawInput;
191
- if (!s || !n || !Y(r))
212
+ if (!s || !n || !Z(r))
192
213
  return;
193
- const i = await P(r).catch((a) => ({
214
+ const o = await H(r).catch((a) => ({
194
215
  ok: !1,
195
216
  exception: {
196
217
  message: a instanceof Error ? a.message : String(a)
@@ -203,61 +224,61 @@ class I {
203
224
  toolName: "execute_code",
204
225
  summary: r.summary,
205
226
  rawInput: h(r),
206
- rawOutput: h(i)
227
+ rawOutput: h(o)
207
228
  });
208
229
  }
209
230
  enableNetworkCapture() {
210
231
  if (this.networkCaptureCleanup)
211
232
  return;
212
233
  const t = window.fetch.bind(window), s = XMLHttpRequest.prototype.open, n = XMLHttpRequest.prototype.setRequestHeader, r = XMLHttpRequest.prototype.send;
213
- window.fetch = async (i, a) => {
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);
234
+ window.fetch = async (o, a) => {
235
+ const i = Date.now(), c = new Date(i).toISOString(), u = o instanceof Request ? o : null, f = typeof o == "string" ? o : o instanceof URL ? o.toString() : u?.url ?? "", E = (a?.method ?? u?.method ?? "GET").toUpperCase(), w = A(new Headers(a?.headers ?? u?.headers ?? void 0)), T = await Q(u, a);
215
236
  try {
216
- const l = await t(i, a);
237
+ const l = await t(o, a);
217
238
  return this.enqueueNetworkEvent({
218
239
  requestId: g("fetch"),
219
240
  url: f,
220
- method: w,
221
- requestHeaders: E,
241
+ method: E,
242
+ requestHeaders: w,
222
243
  requestBody: T,
223
244
  resourceType: "fetch",
224
245
  responseStatus: l.status,
225
- responseHeaders: k(l.headers),
226
- responseBody: await Z(l),
246
+ responseHeaders: A(l.headers),
247
+ responseBody: await tt(l),
227
248
  startedAt: c,
228
- durationMs: Date.now() - o
249
+ durationMs: Date.now() - i
229
250
  }), l;
230
251
  } catch (l) {
231
252
  throw this.enqueueNetworkEvent({
232
253
  requestId: g("fetch"),
233
254
  url: f,
234
- method: w,
235
- requestHeaders: E,
255
+ method: E,
256
+ requestHeaders: w,
236
257
  requestBody: T,
237
258
  resourceType: "fetch",
238
259
  errorText: l instanceof Error ? l.message : String(l),
239
260
  startedAt: c,
240
- durationMs: Date.now() - o
261
+ durationMs: Date.now() - i
241
262
  }), l;
242
263
  }
243
- }, XMLHttpRequest.prototype.open = function(a, o, c, u, f) {
264
+ }, XMLHttpRequest.prototype.open = function(a, i, c, u, f) {
244
265
  return this.__plunoMeta = {
245
266
  requestId: g("xhr"),
246
267
  method: String(a ?? "GET").toUpperCase(),
247
- url: typeof o == "string" ? o : o.toString(),
268
+ url: typeof i == "string" ? i : i.toString(),
248
269
  requestHeaders: {},
249
270
  startedAtMs: Date.now(),
250
271
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
251
- }, s.call(this, a, o, c ?? !0, u ?? void 0, f ?? void 0);
252
- }, XMLHttpRequest.prototype.setRequestHeader = function(a, o) {
272
+ }, s.call(this, a, i, c ?? !0, u ?? void 0, f ?? void 0);
273
+ }, XMLHttpRequest.prototype.setRequestHeader = function(a, i) {
253
274
  const c = this.__plunoMeta;
254
275
  if (c) {
255
276
  const u = c.requestHeaders ?? {};
256
- u[a] = o, c.requestHeaders = u;
277
+ u[a] = i, c.requestHeaders = u;
257
278
  }
258
- return n.call(this, a, o);
279
+ return n.call(this, a, i);
259
280
  }, XMLHttpRequest.prototype.send = function(a) {
260
- const o = window.__plunoProductAgentInstance, c = this.__plunoMeta ?? {
281
+ const i = window.__plunoProductAgentInstance, c = this.__plunoMeta ?? {
261
282
  requestId: g("xhr"),
262
283
  method: "GET",
263
284
  url: "",
@@ -268,7 +289,7 @@ class I {
268
289
  return c.requestBody = C(a), this.__plunoMeta = c, this.addEventListener(
269
290
  "loadend",
270
291
  function() {
271
- !o || !this.__plunoMeta || o.enqueueNetworkEvent({
292
+ !i || !this.__plunoMeta || i.enqueueNetworkEvent({
272
293
  requestId: String(this.__plunoMeta.requestId),
273
294
  url: String(this.__plunoMeta.url ?? ""),
274
295
  method: String(this.__plunoMeta.method ?? "GET"),
@@ -276,8 +297,8 @@ class I {
276
297
  requestBody: typeof this.__plunoMeta.requestBody == "string" ? this.__plunoMeta.requestBody : void 0,
277
298
  resourceType: "xhr",
278
299
  responseStatus: this.status,
279
- responseHeaders: tt(this.getAllResponseHeaders()),
280
- responseBody: Q(this),
300
+ responseHeaders: st(this.getAllResponseHeaders()),
301
+ responseBody: et(this),
281
302
  errorText: this.status === 0 ? "XHR request failed or was aborted" : void 0,
282
303
  startedAt: String(this.__plunoMeta.startedAt),
283
304
  durationMs: Date.now() - Number(this.__plunoMeta.startedAtMs ?? Date.now())
@@ -317,21 +338,22 @@ class I {
317
338
  this.heartbeatTimer !== null && (window.clearInterval(this.heartbeatTimer), this.heartbeatTimer = null);
318
339
  }
319
340
  setState(t) {
320
- this.state = { ...this.state, ...t }, J(this.options.clientId, this.state), this.emit("state", this.getState());
341
+ this.state = { ...this.state, ...t }, Y(this.options.clientId, this.state), this.emit("state", this.getState());
321
342
  }
322
343
  emit(t, s) {
323
344
  this.listeners[t]?.forEach((r) => r(s));
324
345
  }
325
346
  }
326
- async function P(e) {
347
+ const P = 5e3;
348
+ async function H(e) {
327
349
  const t = Object.getPrototypeOf(async function() {
328
- }).constructor, s = e.timeoutMs ?? 15e3, n = Date.now(), r = [], i = {
350
+ }).constructor, s = P, n = Date.now(), r = [], o = {
329
351
  log: console.log,
330
352
  info: console.info,
331
353
  warn: console.warn,
332
354
  error: console.error
333
- }, a = (o) => (...c) => {
334
- r.push({ level: o, args: c }), i[o](...c);
355
+ }, a = (i) => (...c) => {
356
+ r.push({ level: i, args: c }), o[i](...c);
335
357
  };
336
358
  console.log = a("log"), console.info = a("info"), console.warn = a("warn"), console.error = a("error");
337
359
  try {
@@ -350,14 +372,14 @@ async function P(e) {
350
372
  origin: location.origin
351
373
  }
352
374
  };
353
- } catch (o) {
375
+ } catch (i) {
354
376
  return {
355
377
  ok: !1,
356
378
  console: r,
357
379
  exception: {
358
- name: o instanceof Error ? o.name : "Error",
359
- message: o instanceof Error ? o.message : String(o),
360
- stack: o instanceof Error ? o.stack : void 0
380
+ name: i instanceof Error ? i.name : "Error",
381
+ message: i instanceof Error ? i.message : String(i),
382
+ stack: i instanceof Error ? i.stack : void 0
361
383
  },
362
384
  metadata: {
363
385
  durationMs: Date.now() - n,
@@ -366,13 +388,13 @@ async function P(e) {
366
388
  }
367
389
  };
368
390
  } finally {
369
- console.log = i.log, console.info = i.info, console.warn = i.warn, console.error = i.error;
391
+ console.log = o.log, console.info = o.info, console.warn = o.warn, console.error = o.error;
370
392
  }
371
393
  }
372
- function H(e) {
394
+ function U(e) {
373
395
  return e.replace(/\/+$/, "");
374
396
  }
375
- function U(e) {
397
+ function B(e) {
376
398
  const t = new URL("/api/product-agent/embed/ws", e);
377
399
  return t.protocol = t.protocol === "https:" ? "wss:" : "ws:", t.toString();
378
400
  }
@@ -391,20 +413,23 @@ function L(e) {
391
413
  return { type: "error", message: "Invalid server event" };
392
414
  }
393
415
  }
394
- function B(e, t) {
416
+ function x(e, t) {
395
417
  if (!e || typeof e != "object")
396
418
  return [];
397
419
  const s = e[t];
398
420
  return Array.isArray(s) ? s.filter((n) => typeof n == "string" && n.trim().length > 0) : [];
399
421
  }
400
- function x() {
422
+ function $() {
401
423
  const e = "pluno.productAgent.clientId", t = window.localStorage.getItem(e);
402
424
  if (t)
403
425
  return t;
404
426
  const s = crypto.randomUUID();
405
427
  return window.localStorage.setItem(e, s), s;
406
428
  }
407
- function $(e) {
429
+ function j() {
430
+ return crypto.randomUUID();
431
+ }
432
+ function X(e) {
408
433
  if (!e || typeof e != "object")
409
434
  return null;
410
435
  const t = e, s = typeof t.id == "string" ? t.id : null;
@@ -415,7 +440,7 @@ function $(e) {
415
440
  avatarUrl: typeof t.avatarUrl == "string" ? t.avatarUrl : null
416
441
  } : null;
417
442
  }
418
- function j(e) {
443
+ function z(e) {
419
444
  return Array.isArray(e) ? e.map(R).filter((t) => t !== null) : [];
420
445
  }
421
446
  function R(e) {
@@ -430,20 +455,20 @@ function R(e) {
430
455
  return {
431
456
  id: String(t.id ?? crypto.randomUUID()),
432
457
  role: r,
433
- content: z(n.content),
458
+ content: W(n.content),
434
459
  createdAt: typeof t.createdAt == "string" ? t.createdAt : (/* @__PURE__ */ new Date()).toISOString()
435
460
  };
436
461
  }
437
462
  return n.type === "function_call" || n.type === "tool_call" || n.type === "web_search_call" ? {
438
463
  id: String(t.id ?? crypto.randomUUID()),
439
464
  role: "tool",
440
- content: X(n),
465
+ content: F(n),
441
466
  createdAt: typeof t.createdAt == "string" ? t.createdAt : (/* @__PURE__ */ new Date()).toISOString(),
442
467
  dataType: String(n.type),
443
468
  loading: n.localExecutionStatus === "running"
444
469
  } : null;
445
470
  }
446
- function X(e) {
471
+ function F(e) {
447
472
  if (e.type === "web_search_call") {
448
473
  const t = e.action;
449
474
  if (t && typeof t == "object") {
@@ -455,9 +480,9 @@ function X(e) {
455
480
  }
456
481
  return "Searching the web";
457
482
  }
458
- return v(e);
483
+ return G(e);
459
484
  }
460
- function v(e) {
485
+ function G(e) {
461
486
  if (typeof e.summary == "string" && e.summary.trim().length > 0)
462
487
  return e.summary;
463
488
  if (typeof e.arguments == "string")
@@ -470,7 +495,7 @@ function v(e) {
470
495
  }
471
496
  return typeof e.name == "string" && e.name.trim().length > 0 ? e.name : "Run tool";
472
497
  }
473
- function z(e) {
498
+ function W(e) {
474
499
  return typeof e == "string" ? e : Array.isArray(e) ? e.map((t) => {
475
500
  if (!t || typeof t != "object")
476
501
  return "";
@@ -478,14 +503,14 @@ function z(e) {
478
503
  return typeof s.text == "string" ? s.text : typeof s.content == "string" ? s.content : "";
479
504
  }).filter(Boolean).join("") : "";
480
505
  }
481
- function F(e, t) {
482
- const s = G(e, t), n = s.findIndex((i) => i.id === t.id);
506
+ function J(e, t) {
507
+ const s = K(e, t), n = s.findIndex((o) => o.id === t.id);
483
508
  if (n === -1)
484
509
  return [...s, t];
485
510
  const r = [...s];
486
511
  return r[n] = t, r;
487
512
  }
488
- function G(e, t) {
513
+ function K(e, t) {
489
514
  if (t.role !== "user")
490
515
  return e;
491
516
  const s = e.findIndex(
@@ -499,12 +524,12 @@ function G(e, t) {
499
524
  function _(e, t) {
500
525
  return e && typeof e == "object" && typeof e[t] == "string" ? e[t] : null;
501
526
  }
502
- function W(e) {
527
+ function v(e) {
503
528
  try {
504
- const t = window.localStorage.getItem(`${A}${e}`);
529
+ const t = window.localStorage.getItem(`${k}${e}`);
505
530
  if (!t)
506
531
  return null;
507
- const s = JSON.parse(t), n = Array.isArray(s.messages) ? s.messages.map(K).filter((r) => !!r) : [];
532
+ const s = JSON.parse(t), n = Array.isArray(s.messages) ? s.messages.map(V).filter((r) => !!r) : [];
508
533
  return {
509
534
  sessionId: typeof s.sessionId == "string" ? s.sessionId : null,
510
535
  messages: n
@@ -513,10 +538,10 @@ function W(e) {
513
538
  return null;
514
539
  }
515
540
  }
516
- function J(e, t) {
541
+ function Y(e, t) {
517
542
  try {
518
543
  window.localStorage.setItem(
519
- `${A}${e}`,
544
+ `${k}${e}`,
520
545
  JSON.stringify({
521
546
  sessionId: t.sessionId,
522
547
  messages: t.messages.slice(-100)
@@ -526,7 +551,7 @@ function J(e, t) {
526
551
  return;
527
552
  }
528
553
  }
529
- function K(e) {
554
+ function V(e) {
530
555
  if (!e || typeof e != "object")
531
556
  return null;
532
557
  const t = e;
@@ -539,16 +564,16 @@ function K(e) {
539
564
  loading: typeof t.loading == "boolean" ? t.loading : void 0
540
565
  };
541
566
  }
542
- function Y(e) {
567
+ function Z(e) {
543
568
  return !!e && typeof e == "object" && typeof e.summary == "string" && typeof e.javascript == "string";
544
569
  }
545
- function k(e) {
570
+ function A(e) {
546
571
  const t = {};
547
572
  return e?.forEach((s, n) => {
548
573
  t[n] = s;
549
574
  }), t;
550
575
  }
551
- async function V(e, t) {
576
+ async function Q(e, t) {
552
577
  if (typeof t?.body < "u")
553
578
  return C(t.body);
554
579
  if (e)
@@ -558,14 +583,14 @@ async function V(e, t) {
558
583
  return;
559
584
  }
560
585
  }
561
- async function Z(e) {
586
+ async function tt(e) {
562
587
  try {
563
588
  return p(await e.clone().text());
564
589
  } catch (t) {
565
590
  return { error: t instanceof Error ? t.message : "unavailable" };
566
591
  }
567
592
  }
568
- function Q(e) {
593
+ function et(e) {
569
594
  try {
570
595
  return e.responseType === "" || e.responseType === "text" ? p(e.responseText ?? "") : e.responseType === "json" ? p(JSON.stringify(e.response)) : `[unsupported xhr responseType: ${e.responseType || "unknown"}]`;
571
596
  } catch (t) {
@@ -591,7 +616,7 @@ function C(e) {
591
616
  }
592
617
  }
593
618
  }
594
- function tt(e) {
619
+ function st(e) {
595
620
  const t = {};
596
621
  for (const s of e.trim().split(/[\r\n]+/)) {
597
622
  const n = s.indexOf(":");
@@ -605,51 +630,51 @@ function p(e) {
605
630
  function g(e) {
606
631
  return `${e}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
607
632
  }
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 = /[),.;\]]+$/;
633
+ const S = "[REDACTED_SECRET]", d = "[REDACTED_TOKEN]", nt = "[REDACTED_SIGNED_URL]", rt = 20, ot = /^(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, M = /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/gi, N = /\bBasic\s+[A-Za-z0-9+/=-]{12,}/gi, D = /\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, it = /\bhttps?:\/\/[^\s"'<>]+(?:X-Amz-Signature|X-Goog-Signature|Signature|sig=)[^\s"'<>]*/gi, at = /\bhttps?:\/\/[^\s"'<>]+/gi, ct = /[),.;\]]+$/;
609
634
  function h(e) {
610
635
  return y(e, 0, /* @__PURE__ */ new WeakSet());
611
636
  }
612
637
  function y(e, t, s) {
613
638
  if (typeof e == "string")
614
- return ut(e);
639
+ return dt(e);
615
640
  if (e === null || typeof e != "object")
616
641
  return e;
617
- if (t >= st)
642
+ if (t >= rt)
618
643
  return "[REDACTED_MAX_DEPTH]";
619
644
  if (s.has(e))
620
645
  return "[REDACTED_CIRCULAR]";
621
646
  if (s.add(e), Array.isArray(e))
622
647
  return e.map((r) => y(r, t + 1, s));
623
648
  const n = {};
624
- for (const [r, i] of Object.entries(e))
625
- at(r) ? n[r] = S : n[r] = r.toLowerCase() === "url" ? ct(i) : y(i, t + 1, s);
649
+ for (const [r, o] of Object.entries(e))
650
+ ut(r) ? n[r] = S : n[r] = r.toLowerCase() === "url" ? lt(o) : y(o, t + 1, s);
626
651
  return n;
627
652
  }
628
- function at(e) {
653
+ function ut(e) {
629
654
  const t = e.replace(/[^a-z0-9]/gi, "").toLowerCase();
630
655
  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");
631
656
  }
632
- function ct(e) {
657
+ function lt(e) {
633
658
  return typeof e == "string" ? q(e) : y(e, 0, /* @__PURE__ */ new WeakSet());
634
659
  }
635
660
  function q(e) {
636
661
  try {
637
662
  const t = new URL(e, location.href);
638
663
  for (const s of Array.from(t.searchParams.keys()))
639
- nt.test(s) && t.searchParams.set(s, d);
664
+ ot.test(s) && t.searchParams.set(s, d);
640
665
  return t.username && (t.username = d), t.password && (t.password = d), t.toString();
641
666
  } catch {
642
- return lt(e);
667
+ return pt(e);
643
668
  }
644
669
  }
645
- function ut(e) {
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}`);
670
+ function dt(e) {
671
+ return e.replace(it, nt).replace(at, ht).replace(M, `Bearer ${d}`).replace(N, `Basic ${d}`).replace(D, d).replace(b, (t, s) => `${s}: ${S}`);
647
672
  }
648
- function lt(e) {
649
- return e.replace(N, `Bearer ${d}`).replace(D, `Basic ${d}`).replace(M, d).replace(b, (t, s) => `${s}: ${S}`);
673
+ function pt(e) {
674
+ return e.replace(M, `Bearer ${d}`).replace(N, `Basic ${d}`).replace(D, d).replace(b, (t, s) => `${s}: ${S}`);
650
675
  }
651
- function dt(e) {
652
- const t = e.match(it)?.[0] ?? "", s = t ? e.slice(0, -t.length) : e;
676
+ function ht(e) {
677
+ const t = e.match(ct)?.[0] ?? "", s = t ? e.slice(0, -t.length) : e;
653
678
  return `${q(s)}${t}`;
654
679
  }
655
680
  export {
@@ -1,11 +1,11 @@
1
- import { PlunoProductAgent as q } from "./product-agent-sdk.js";
1
+ import { PlunoProductAgent as K } from "./product-agent-sdk.js";
2
2
  const L = {
3
- launcherLabel: "Ask AI...",
3
+ launcherLabel: "Ask for anything...",
4
4
  accentColor: "#18181b",
5
5
  colorScheme: "light",
6
6
  position: "bottom-right"
7
7
  };
8
- async function K(e = {}) {
8
+ async function G(e = {}) {
9
9
  const t = {
10
10
  launcherLabel: e.launcherLabel ?? L.launcherLabel,
11
11
  accentColor: e.accentColor ?? L.accentColor,
@@ -31,7 +31,7 @@ async function K(e = {}) {
31
31
  <section class="pluno-pa-widget__panel" hidden>
32
32
  <div class="pluno-pa-widget__timeline-wrap">
33
33
  <main class="pluno-pa-widget__timeline">
34
- <div class="pluno-pa-widget__empty">What can I help you with?</div>
34
+ <div class="pluno-pa-widget__empty">What do you want to do today?</div>
35
35
  </main>
36
36
  <button type="button" class="pluno-pa-widget__new-chat" aria-label="New chat" title="New chat" hidden>
37
37
  <svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
@@ -42,7 +42,7 @@ async function K(e = {}) {
42
42
  </div>
43
43
  <form class="pluno-pa-widget__composer">
44
44
  <div class="pluno-pa-widget__composer-inner">
45
- <textarea class="pluno-pa-widget__input" rows="1" placeholder="What can I help you with?"></textarea>
45
+ <textarea class="pluno-pa-widget__input" rows="1" placeholder="Ask for anything..."></textarea>
46
46
  <button type="button" class="pluno-pa-widget__send" aria-label="Send">
47
47
  <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">
48
48
  <line x1="12" y1="19" x2="12" y2="5" />
@@ -54,35 +54,35 @@ async function K(e = {}) {
54
54
  </section>
55
55
  `, n.appendChild(a);
56
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)
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 || !_)
60
60
  throw new Error("Failed to mount Product Agent widget");
61
- const _ = t.token || t.webSocketFactory ? void 0 : t.tokenProvider ?? (async () => {
61
+ const b = 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
- const u = await fetch(t.tokenEndpoint, {
64
+ const c = await fetch(t.tokenEndpoint, {
65
65
  method: "POST",
66
66
  credentials: "include",
67
67
  headers: { "content-type": "application/json" },
68
68
  body: JSON.stringify({ origin: location.origin, url: location.href })
69
69
  });
70
- if (!u.ok)
70
+ if (!c.ok)
71
71
  throw new Error("Failed to load Product Agent token");
72
- const y = await u.json();
72
+ const y = await c.json();
73
73
  if (!y.token)
74
74
  throw new Error("Product Agent token endpoint did not return a token");
75
75
  return y.token;
76
- }), m = await q.init({
76
+ }), m = await K.init({
77
77
  token: t.token,
78
- tokenProvider: _,
78
+ tokenProvider: b,
79
79
  backendUrl: t.backendUrl,
80
80
  webSocketFactory: t.webSocketFactory
81
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);
82
+ let x = null, N = !1;
83
+ const q = () => {
84
+ N || typeof document > "u" || (F(n, t.accentColor), o.isConnected || s.body?.appendChild(o));
85
+ }, P = new MutationObserver(q);
86
86
  P.observe(s.documentElement, { childList: !0, subtree: !0 });
87
87
  const v = () => {
88
88
  Z(t, {
@@ -90,75 +90,75 @@ async function K(e = {}) {
90
90
  composerValue: i.value,
91
91
  openToolGroupKeys: [...S]
92
92
  });
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();
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();
96
96
  return;
97
97
  }
98
98
  window.requestAnimationFrame(() => {
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(() => {
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(() => {
100
100
  l.hidden = !0;
101
101
  }, 220);
102
102
  });
103
103
  }, A = () => {
104
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");
105
+ r.hidden = !0, u.hidden = !0, a.classList.remove("pluno-pa-widget--closing");
106
106
  }, 220);
107
107
  };
108
- l.addEventListener("submit", (u) => {
109
- u.preventDefault(), k(d.value), d.value = "";
108
+ l.addEventListener("submit", (c) => {
109
+ c.preventDefault(), k(d.value), d.value = "";
110
110
  }), d.addEventListener("focus", () => {
111
111
  k(d.value), d.value = "";
112
112
  }), d.addEventListener("input", () => {
113
113
  if (!d.value)
114
114
  return;
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")) {
115
+ const c = d.value;
116
+ k(c), d.value = "";
117
+ }), u.addEventListener("click", A);
118
+ const M = (c) => {
119
+ if (!(!c.metaKey || c.key.toLowerCase() !== "k")) {
120
+ if (c.preventDefault(), r.hidden || !a.classList.contains("pluno-pa-widget--open")) {
121
121
  k();
122
122
  return;
123
123
  }
124
124
  A();
125
125
  }
126
126
  };
127
- return s.addEventListener("keydown", M), h.addEventListener("submit", (u) => {
128
- u.preventDefault(), N(m, i);
127
+ return s.addEventListener("keydown", M), h.addEventListener("submit", (c) => {
128
+ c.preventDefault(), z(m, i);
129
129
  }), p.addEventListener("click", () => {
130
130
  if (m.getState().isThinking) {
131
131
  m.stop();
132
132
  return;
133
133
  }
134
- N(m, i);
134
+ z(m, i);
135
135
  }), g.addEventListener("click", () => {
136
136
  m.startNewSession(), S.clear(), i.value = "", C(i), v(), i.focus();
137
137
  }), i.addEventListener("input", () => {
138
138
  C(i), v();
139
- }), i.addEventListener("keydown", (u) => {
140
- u.key !== "Enter" || u.shiftKey || (u.preventDefault(), N(m, i));
139
+ }), i.addEventListener("keydown", (c) => {
140
+ c.key !== "Enter" || c.shiftKey || (c.preventDefault(), z(m, i));
141
141
  }), E.composerValue && (i.value = E.composerValue, C(i)), E.isOpen && k(i.value, !1), m.on(
142
142
  "state",
143
- (u) => $(b, p, g, u, S, v, (y) => {
143
+ (c) => $(_, p, g, c, S, v, (y) => {
144
144
  m.sendMessage(y);
145
145
  })
146
- ), $(b, p, g, m.getState(), S, v, (u) => {
147
- m.sendMessage(u);
146
+ ), $(_, p, g, m.getState(), S, v, (c) => {
147
+ m.sendMessage(c);
148
148
  }), {
149
149
  agent: m,
150
150
  destroy: () => {
151
- z = !0, P.disconnect(), m.destroy(), s.removeEventListener("keydown", M), o.remove();
151
+ N = !0, P.disconnect(), m.destroy(), s.removeEventListener("keydown", M), o.remove();
152
152
  }
153
153
  };
154
154
  }
155
- function N(e, t) {
155
+ function z(e, t) {
156
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 })));
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
159
  function C(e) {
160
160
  e.style.height = "0px";
161
- const t = Math.min(e.scrollHeight, 140);
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
164
  function $(e, t, o, n, a, w, s) {
@@ -167,28 +167,28 @@ function $(e, t, o, n, a, w, s) {
167
167
  const d = l.length > 0 || !!n.assistantDraft;
168
168
  if (o.hidden = !d, l.length === 0 && !n.assistantDraft && !n.lastError) {
169
169
  const p = document.createElement("div");
170
- p.className = "pluno-pa-widget__empty-state";
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
- 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) {
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) {
176
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);
177
+ m.type = "button", m.className = "pluno-pa-widget__starter-prompt", m.textContent = `"${b}"`, m.addEventListener("click", () => {
178
+ s(b);
179
+ }), _.appendChild(m);
180
180
  }
181
- p.appendChild(b);
181
+ p.appendChild(_);
182
182
  }
183
183
  e.appendChild(p);
184
184
  return;
185
185
  }
186
- let r = null, c = null, h = [];
186
+ let r = null, u = null, h = [];
187
187
  const i = () => {
188
188
  if (h.length === 0)
189
189
  return;
190
- const p = G(h, a, w);
191
- e.appendChild(p), r = null, c = p, h = [];
190
+ const p = I(h, a, w);
191
+ e.appendChild(p), r = null, u = p, h = [];
192
192
  };
193
193
  for (let p = 0; p < l.length; p += 1) {
194
194
  const g = l[p];
@@ -199,22 +199,22 @@ function $(e, t, o, n, a, w, s) {
199
199
  if (g.role === "system")
200
200
  continue;
201
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;
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;
204
204
  }
205
205
  if (i(), n.assistantDraft) {
206
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;
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;
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, c = p;
211
+ p.className = "pluno-pa-widget__status", p.textContent = "Thinking...", e.appendChild(p), r = 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, c = null;
215
+ p.className = "pluno-pa-widget__error", p.textContent = n.lastError, e.appendChild(p), r = p, u = null;
216
216
  }
217
- r?.classList.add("pluno-pa-widget__message--bottom-reserve"), c?.classList.add("pluno-pa-widget__bottom-reserve-compact"), e.scrollTop = e.scrollHeight;
217
+ r?.classList.add("pluno-pa-widget__message--bottom-reserve"), u?.classList.add("pluno-pa-widget__bottom-reserve-compact"), e.scrollTop = e.scrollHeight;
218
218
  }
219
219
  function D(e) {
220
220
  const t = document.createElement("button");
@@ -225,7 +225,7 @@ function D(e) {
225
225
  function O(e) {
226
226
  return e.replace(/\uE200[^\uE201]*(?:\uE201|$)/g, "");
227
227
  }
228
- function G(e, t, o) {
228
+ function I(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
231
  const a = document.createElement("details"), w = U(e);
@@ -238,11 +238,11 @@ function G(e, t, o) {
238
238
  if (d.textContent = e[e.length - 1].content || "Run tool", s.appendChild(d), a.appendChild(s), e.length > 0) {
239
239
  const r = document.createElement("div");
240
240
  r.className = "pluno-pa-widget__tool-lines";
241
- for (const c of e) {
241
+ for (const u of e) {
242
242
  const h = document.createElement("div");
243
- h.className = "pluno-pa-widget__tool-line", c.loading && h.appendChild(j());
243
+ h.className = "pluno-pa-widget__tool-line", u.loading && h.appendChild(j());
244
244
  const i = document.createElement("span");
245
- i.textContent = c.content || "Run tool", h.appendChild(i), r.appendChild(h);
245
+ i.textContent = u.content || "Run tool", h.appendChild(i), r.appendChild(h);
246
246
  }
247
247
  a.appendChild(r);
248
248
  }
@@ -274,9 +274,9 @@ function B(e, t) {
274
274
  for (n += 1; n < o.length && !/^```\s*$/.test(o[n]); )
275
275
  r.push(o[n]), n += 1;
276
276
  n += n < o.length ? 1 : 0;
277
- const c = document.createElement("pre"), h = document.createElement("code");
277
+ const u = document.createElement("pre"), h = document.createElement("code");
278
278
  h.textContent = r.join(`
279
- `), c.appendChild(h), e.appendChild(c);
279
+ `), u.appendChild(h), e.appendChild(u);
280
280
  continue;
281
281
  }
282
282
  const s = a.match(/^(#{1,3})\s+(.+)$/);
@@ -288,8 +288,8 @@ function B(e, t) {
288
288
  if (/^\s*[-*+]\s+/.test(a)) {
289
289
  const r = document.createElement("ul");
290
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;
291
+ const u = document.createElement("li");
292
+ T(u, o[n].replace(/^\s*[-*+]\s+/, "")), r.appendChild(u), n += 1;
293
293
  }
294
294
  e.appendChild(r);
295
295
  continue;
@@ -297,8 +297,8 @@ function B(e, t) {
297
297
  if (/^\s*\d+\.\s+/.test(a)) {
298
298
  const r = document.createElement("ol");
299
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;
300
+ const u = document.createElement("li");
301
+ T(u, o[n].replace(/^\s*\d+\.\s+/, "")), r.appendChild(u), n += 1;
302
302
  }
303
303
  e.appendChild(r);
304
304
  continue;
@@ -307,8 +307,8 @@ function B(e, t) {
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, c) => {
311
- c > 0 && d.appendChild(document.createElement("br")), T(d, r);
310
+ l.forEach((r, u) => {
311
+ u > 0 && d.appendChild(document.createElement("br")), T(d, r);
312
312
  }), e.appendChild(d);
313
313
  }
314
314
  }
@@ -350,7 +350,7 @@ function Y(e) {
350
350
  return !1;
351
351
  }
352
352
  }
353
- function I(e, t) {
353
+ function F(e, t) {
354
354
  if (e.getElementById("pluno-pa-widget-styles"))
355
355
  return;
356
356
  const o = e.ownerDocument.createElement("style");
@@ -652,6 +652,14 @@ function I(e, t) {
652
652
  overflow-wrap: anywhere;
653
653
  word-break: break-word;
654
654
  }
655
+ .pluno-pa-widget__message::after {
656
+ content: "";
657
+ position: absolute;
658
+ bottom: -34px;
659
+ z-index: 2;
660
+ width: 40px;
661
+ height: 34px;
662
+ }
655
663
  .pluno-pa-widget__message--user {
656
664
  align-self: flex-end;
657
665
  max-width: 85%;
@@ -666,10 +674,10 @@ function I(e, t) {
666
674
  }
667
675
  .pluno-pa-widget__message-copy {
668
676
  position: absolute;
669
- bottom: -24px;
677
+ bottom: -30px;
670
678
  z-index: 3;
671
- width: 22px;
672
- height: 22px;
679
+ width: 28px;
680
+ height: 28px;
673
681
  display: inline-flex;
674
682
  align-items: center;
675
683
  justify-content: center;
@@ -684,9 +692,15 @@ function I(e, t) {
684
692
  transform: translateY(-2px);
685
693
  transition: opacity 120ms ease, transform 120ms ease, background 120ms ease, color 120ms ease;
686
694
  }
695
+ .pluno-pa-widget__message--user::after {
696
+ right: 0;
697
+ }
687
698
  .pluno-pa-widget__message--user .pluno-pa-widget__message-copy {
688
699
  right: 4px;
689
700
  }
701
+ .pluno-pa-widget__message--assistant::after {
702
+ left: 0;
703
+ }
690
704
  .pluno-pa-widget__message--assistant .pluno-pa-widget__message-copy {
691
705
  left: 2px;
692
706
  }
@@ -868,6 +882,7 @@ function I(e, t) {
868
882
  font: inherit;
869
883
  font-size: 14px;
870
884
  line-height: 1.45;
885
+ height: 22px;
871
886
  overflow-y: hidden;
872
887
  scrollbar-color: var(--pluno-pa-divider) transparent;
873
888
  scrollbar-width: thin;
@@ -924,32 +939,48 @@ function I(e, t) {
924
939
  justify-items: center;
925
940
  width: 100%;
926
941
  padding: 24px 0;
942
+ text-align: center;
927
943
  }
928
944
  .pluno-pa-widget__empty-state .pluno-pa-widget__empty {
929
945
  margin: 0;
930
946
  padding: 0;
931
947
  }
948
+ .pluno-pa-widget__empty-state--starter {
949
+ --pluno-pa-starter-edge-gap: 40px;
950
+ margin: auto 0 0;
951
+ gap: var(--pluno-pa-starter-edge-gap);
952
+ justify-items: start;
953
+ padding: 36px 4px calc(var(--pluno-pa-starter-edge-gap) - 12px);
954
+ text-align: left;
955
+ }
956
+ .pluno-pa-widget__empty-state--starter .pluno-pa-widget__empty {
957
+ color: var(--pluno-pa-text);
958
+ font-size: 24px;
959
+ font-weight: 500;
960
+ line-height: 1.18;
961
+ text-align: left;
962
+ }
932
963
  .pluno-pa-widget__starter-prompts {
933
964
  display: grid;
934
- gap: 8px;
965
+ gap: 18px;
935
966
  width: min(100%, 320px);
936
967
  }
937
968
  .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);
969
+ border: 0;
970
+ border-radius: 8px;
971
+ background: transparent;
972
+ color: color-mix(in srgb, var(--pluno-pa-text) 72%, transparent);
942
973
  font: inherit;
943
- font-size: 12px;
974
+ font-size: 14px;
944
975
  line-height: 1.45;
945
- padding: 10px 12px;
976
+ padding: 0;
946
977
  text-align: left;
947
978
  cursor: pointer;
948
- transition: border-color 120ms ease, background 120ms ease;
979
+ transition: color 120ms ease, background 120ms ease;
949
980
  }
950
981
  .pluno-pa-widget__starter-prompt:hover {
951
- border-color: rgba(255, 255, 255, 0.18);
952
- background: rgba(255, 255, 255, 0.05);
982
+ color: var(--pluno-pa-text);
983
+ background: transparent;
953
984
  }
954
985
  .pluno-pa-widget__status {
955
986
  display: inline-flex;
@@ -1004,12 +1035,12 @@ function W(e) {
1004
1035
  const t = document.createElement("span");
1005
1036
  return t.textContent = e, t.innerHTML;
1006
1037
  }
1007
- function F(e) {
1038
+ function H(e) {
1008
1039
  return `pluno.productAgent.widgetState.${location.origin}.${e.backendUrl ?? ""}.${e.tokenEndpoint ?? ""}.${e.position ?? ""}`;
1009
1040
  }
1010
1041
  function J(e) {
1011
1042
  try {
1012
- const t = window.localStorage.getItem(F(e));
1043
+ const t = window.localStorage.getItem(H(e));
1013
1044
  if (!t)
1014
1045
  return { isOpen: !1, composerValue: "", openToolGroupKeys: [] };
1015
1046
  const o = JSON.parse(t);
@@ -1024,13 +1055,13 @@ function J(e) {
1024
1055
  }
1025
1056
  function Z(e, t) {
1026
1057
  try {
1027
- window.localStorage.setItem(F(e), JSON.stringify(t));
1058
+ window.localStorage.setItem(H(e), JSON.stringify(t));
1028
1059
  } catch {
1029
1060
  return;
1030
1061
  }
1031
1062
  }
1032
1063
  const f = document.currentScript;
1033
- f && f.dataset.plunoAutoMount !== "false" && K({
1064
+ f && f.dataset.plunoAutoMount !== "false" && G({
1034
1065
  token: f?.dataset.plunoToken,
1035
1066
  tokenEndpoint: f?.dataset.plunoTokenEndpoint,
1036
1067
  backendUrl: f?.dataset.plunoBackendUrl,
@@ -1042,5 +1073,5 @@ f && f.dataset.plunoAutoMount !== "false" && K({
1042
1073
  console.error("Failed to mount Pluno Product Agent widget", e);
1043
1074
  });
1044
1075
  export {
1045
- K as mountPlunoProductAgentWidget
1076
+ G as mountPlunoProductAgentWidget
1046
1077
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluno/product-agent-web",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
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",