@pluno/product-agent-web 0.1.83 → 0.1.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -52,6 +52,10 @@ The SDK captures passive resource URL/timing metadata with `PerformanceObserver`
52
52
  Scribble style is enabled by default. Set `data-pluno-scribble-style="false"` in the snippet, or `scribbleStyle: false`
53
53
  for programmatic mounts, to use the standard widget appearance.
54
54
 
55
+ The floating widget launcher includes a minimize control by default. Its compact state survives reloads in the
56
+ current tab, while a new tab or browser session starts with the regular launcher. Programmatic mounts can set
57
+ `showLauncherMinimizeButton: false` to hide it.
58
+
55
59
  This script-tag setup is the recommended integration. If your token endpoint needs custom browser-side authentication,
56
60
  import the same hosted widget module and provide the request logic programmatically:
57
61
 
package/dist/index.d.ts CHANGED
@@ -74,6 +74,7 @@ export type ProductAgentSessionHistoryEntry = {
74
74
  createdAt: string;
75
75
  updatedAt: string;
76
76
  lastActiveAt: string;
77
+ isActive: boolean;
77
78
  };
78
79
  export type ProductAgentSessionHistoryPage = {
79
80
  sessions: ProductAgentSessionHistoryEntry[];
@@ -114,6 +115,7 @@ export type ProductAgentInitOptions = {
114
115
  prepareAttachmentUpload?: (input: ProductAgentPrepareAttachmentUploadInput) => Promise<ProductAgentAttachmentUpload>;
115
116
  restorePersistedState?: boolean;
116
117
  expectedPersistedSessionId?: string | null;
118
+ keepRunsActiveOnSessionNavigation?: boolean;
117
119
  };
118
120
  export type ProductAgentWebSocket = {
119
121
  readyState: number;
@@ -126,6 +128,10 @@ export type ProductAgentEventMap = {
126
128
  state: ProductAgentState;
127
129
  message: ProductAgentMessage;
128
130
  delta: string;
131
+ ack: {
132
+ clientMessageId: string;
133
+ sessionId: string | null;
134
+ };
129
135
  error: Error;
130
136
  };
131
137
  type EventName = keyof ProductAgentEventMap;
@@ -2,10 +2,10 @@ const ee = "pluno-product-agent-attachments";
2
2
  const et = "files";
3
3
  async function Ut(e) {
4
4
  const t = await W();
5
- await vt(t, "readwrite", (s) => s.put(e));
5
+ await Dt(t, "readwrite", (s) => s.put(e));
6
6
  }
7
7
  async function se(e) {
8
- const t = await W(), s = await vt(
8
+ const t = await W(), s = await Dt(
9
9
  t,
10
10
  "readonly",
11
11
  (r) => r.get(e)
@@ -13,9 +13,9 @@ async function se(e) {
13
13
  if (!s)
14
14
  return null;
15
15
  const n = Date.now();
16
- return await Dt(e, { lastUsedAt: n }), { ...s, lastUsedAt: n };
16
+ return await vt(e, { lastUsedAt: n }), { ...s, lastUsedAt: n };
17
17
  }
18
- async function Dt(e, t) {
18
+ async function vt(e, t) {
19
19
  const s = await W();
20
20
  await lt(s, "readwrite", async (n) => {
21
21
  const r = await ut(
@@ -43,7 +43,7 @@ function W() {
43
43
  }, s.onsuccess = () => e(s.result), s.onerror = () => t(s.error ?? new Error("Failed to open Product Agent attachment storage"));
44
44
  });
45
45
  }
46
- async function vt(e, t, s) {
46
+ async function Dt(e, t, s) {
47
47
  return await lt(e, t, async (n) => await ut(s(n)));
48
48
  }
49
49
  function lt(e, t, s) {
@@ -368,8 +368,8 @@ function ye() {
368
368
  }
369
369
  };
370
370
  }
371
- const nt = '.pluno-pa-widget-host[data-pluno-product-agent-ui="widget"]', Te = '.pluno-pa-widget[data-pluno-product-agent-ui-root="widget"]', we = ".pluno-pa-widget__panel", Ie = ".pluno-pa-widget__timeline", Tt = `${nt}[data-pluno-sdk-preview-channel]`, Ae = "https://app.pluno.ai", Se = "gpt-5.6-sol", ke = 2e4, Ee = 1e4, Re = 1e4, Ce = 1e4, _e = 1e4, be = 1e3, wt = 3e4, It = 0.2, At = 6e4, Me = 15e3, D = 3, Pe = 2e3, Ue = 15e3, De = 1e3, ve = 100, Ne = 8e3, Oe = 15e3, St = 3, Le = [300, 1e3], dt = 64e3, V = 4e3, ht = 30, Be = 2e3, qe = 1e3, xe = 200 * 1024 * 1024, pt = "Image is too large for model vision input.", He = 100, Bt = "pluno.productAgent.state.", rt = "pluno.productAgent.pendingEvents.", j = "pluno.productAgent.activeToolCalls.", Fe = 100;
372
- function v(e, t = 0) {
371
+ const nt = '.pluno-pa-widget-host[data-pluno-product-agent-ui="widget"]', Te = '.pluno-pa-widget[data-pluno-product-agent-ui-root="widget"]', we = ".pluno-pa-widget__panel", Ie = ".pluno-pa-widget__timeline", Tt = `${nt}[data-pluno-sdk-preview-channel]`, Ae = "https://app.pluno.ai", Se = "gpt-5.6-sol", ke = 2e4, Ee = 1e4, Re = 1e4, Ce = 1e4, _e = 1e4, be = 1e3, wt = 3e4, It = 0.2, At = 6e4, Me = 15e3, v = 3, Pe = 2e3, Ue = 15e3, ve = 1e3, De = 100, Ne = 8e3, Oe = 15e3, St = 3, Le = [300, 1e3], dt = 64e3, V = 4e3, ht = 30, Be = 2e3, qe = 1e3, xe = 200 * 1024 * 1024, pt = "Image is too large for model vision input.", He = 100, Bt = "pluno.productAgent.state.", rt = "pluno.productAgent.pendingEvents.", j = "pluno.productAgent.activeToolCalls.", Fe = 100;
372
+ function D(e, t = 0) {
373
373
  return Math.max(t, Pe * 4 ** e);
374
374
  }
375
375
  const B = /* @__PURE__ */ new Set();
@@ -706,7 +706,7 @@ class qt {
706
706
  return h;
707
707
  }, "Failed to upload attachment"), this.setState({ sessionId: l.sessionId });
708
708
  const c = Gt(l.attachment, this.options.backendUrl);
709
- return this.updateAttachmentInState(s.id, c), s.id && Dt(s.id, {
709
+ return this.updateAttachmentInState(s.id, c), s.id && vt(s.id, {
710
710
  sessionId: l.sessionId,
711
711
  fileUrl: c.fileUrl,
712
712
  gcsPath: c.gcsPath,
@@ -776,7 +776,7 @@ class qt {
776
776
  }
777
777
  startNewSession(t = {}) {
778
778
  const s = t.notifyTransport !== !1;
779
- s && this.state.sessionId && this.state.isThinking && this.sendNow({ type: "run.stop", sessionId: this.state.sessionId }), this.cleanupSessionUserFilesApi(), this.queuedClientEvents = this.queuedClientEvents.filter((n) => n.type !== "chat.user_message"), this.clearThinkingWatchdog(), this.retryableClientMessageId = null, this.retryAttemptsByClientMessageId = {}, this.thinkingWatchdogResyncAttemptsByClientMessageId = {}, s && this.send({
779
+ !this.options.keepRunsActiveOnSessionNavigation && s && this.state.sessionId && this.state.isThinking && this.sendNow({ type: "run.stop", sessionId: this.state.sessionId }), this.cleanupSessionUserFilesApi(), this.queuedClientEvents = this.queuedClientEvents.filter((n) => n.type !== "chat.user_message"), this.clearThinkingWatchdog(), this.retryableClientMessageId = null, this.retryAttemptsByClientMessageId = {}, this.thinkingWatchdogResyncAttemptsByClientMessageId = {}, s && this.send({
780
780
  type: "session.reset",
781
781
  sessionId: this.state.sessionId ?? void 0,
782
782
  page: A()
@@ -811,7 +811,7 @@ class qt {
811
811
  return n;
812
812
  }
813
813
  loadSession(t) {
814
- this.state.sessionId && this.state.isThinking && this.sendNow({ type: "run.stop", sessionId: this.state.sessionId }), this.clearThinkingWatchdog(), this.setState({
814
+ !this.options.keepRunsActiveOnSessionNavigation && this.state.sessionId && this.state.isThinking && this.sendNow({ type: "run.stop", sessionId: this.state.sessionId }), this.clearThinkingWatchdog(), this.setState({
815
815
  sessionId: t,
816
816
  assistantDraft: "",
817
817
  assistantDraftRespondsToUserMessageId: null,
@@ -1051,10 +1051,10 @@ class qt {
1051
1051
  return !0;
1052
1052
  }
1053
1053
  const i = this.retryAttemptsByClientMessageId[n] ?? 0;
1054
- if (i >= D)
1054
+ if (i >= v)
1055
1055
  return !1;
1056
1056
  this.retryAttemptsByClientMessageId[n] = i + 1;
1057
- const o = v(
1057
+ const o = D(
1058
1058
  i,
1059
1059
  typeof t.retryAfterMs == "number" ? t.retryAfterMs : 0
1060
1060
  );
@@ -1071,7 +1071,7 @@ class qt {
1071
1071
  if (this.retryTimersByClientMessageId[s] !== void 0)
1072
1072
  return;
1073
1073
  const n = this.retryAttemptsByClientMessageId[s] ?? 0;
1074
- if (n >= D) {
1074
+ if (n >= v) {
1075
1075
  this.retryableClientMessageId = s, this.setState({
1076
1076
  isThinking: !1,
1077
1077
  lastError: "Pluno could not finish this message. Try it again.",
@@ -1081,7 +1081,7 @@ class qt {
1081
1081
  }
1082
1082
  this.retryAttemptsByClientMessageId[s] = n + 1, this.activeClientMessageId = s, this.latestRecoverableClientMessageId = s, this.setState({ status: "reconnecting", isThinking: !0, lastError: null, lastErrorCode: null }), this.retryTimersByClientMessageId[s] = window.setTimeout(() => {
1083
1083
  delete this.retryTimersByClientMessageId[s], this.setState({ status: "connected", isThinking: !0, lastError: null, lastErrorCode: null }), this.markThinkingProgress(), this.send({ type: "chat.retry_last_user_message", sessionId: t, clientMessageId: s, automatic: !0 });
1084
- }, v(n));
1084
+ }, D(n));
1085
1085
  }
1086
1086
  clearRetryTimers() {
1087
1087
  for (const t of Object.values(this.retryTimersByClientMessageId))
@@ -1106,7 +1106,10 @@ class qt {
1106
1106
  }
1107
1107
  handleRunAck(t) {
1108
1108
  const s = typeof t.clientMessageId == "string" ? t.clientMessageId : null;
1109
- s && this.scheduledChatContinuationScheduler.acknowledgeTask(s), !(!this.state.isThinking || !s || s !== this.activeClientMessageId) && (this.clearRunAckResyncRetryTimer(), this.scheduleRunAckWatchdog(s));
1109
+ s && (this.scheduledChatContinuationScheduler.acknowledgeTask(s), this.emit("ack", {
1110
+ clientMessageId: s,
1111
+ sessionId: typeof t.sessionId == "string" ? t.sessionId : this.state.sessionId
1112
+ })), !(!this.state.isThinking || !s || s !== this.activeClientMessageId) && (this.clearRunAckResyncRetryTimer(), this.scheduleRunAckWatchdog(s));
1110
1113
  }
1111
1114
  scheduleRunAckWatchdog(t) {
1112
1115
  this.runAckWatchdogTimer !== null && window.clearTimeout(this.runAckWatchdogTimer), this.runAckWatchdogTimer = window.setTimeout(() => {
@@ -1122,7 +1125,7 @@ class qt {
1122
1125
  scheduleRunAckResyncRetry(t) {
1123
1126
  this.clearRunAckResyncRetryTimer();
1124
1127
  const s = this.retryAttemptsByClientMessageId[t] ?? 0;
1125
- s >= D || (this.runAckResyncRetryTimer = window.setTimeout(() => {
1128
+ s >= v || (this.runAckResyncRetryTimer = window.setTimeout(() => {
1126
1129
  this.runAckResyncRetryTimer = null, (this.retryAttemptsByClientMessageId[t] ?? 0) === s && (!this.state.isThinking || this.state.status === "closed" || this.activeClientMessageId !== t || this.latestRecoverableClientMessageId !== t || (this.retryAttemptsByClientMessageId[t] = s + 1, this.setState({
1127
1130
  status: this.state.status === "reconnecting" ? "reconnecting" : "connected",
1128
1131
  isThinking: !0,
@@ -1136,7 +1139,7 @@ class qt {
1136
1139
  clientMessageId: t,
1137
1140
  automatic: !0
1138
1141
  }) : this.activeUserMessageEvent && this.send(this.activeUserMessageEvent), this.scheduleThinkingWatchdog(At)));
1139
- }, v(s)));
1142
+ }, D(s)));
1140
1143
  }
1141
1144
  clearRunAckResyncRetryTimer() {
1142
1145
  this.runAckResyncRetryTimer !== null && (window.clearTimeout(this.runAckResyncRetryTimer), this.runAckResyncRetryTimer = null);
@@ -1159,7 +1162,7 @@ class qt {
1159
1162
  return;
1160
1163
  }
1161
1164
  const s = this.thinkingWatchdogResyncAttemptsByClientMessageId[t] ?? 0, n = this.retryAttemptsByClientMessageId[t] ?? 0;
1162
- if (n >= D) {
1165
+ if (n >= v) {
1163
1166
  y("web-sdk.agent", "Pluno run recovery retry exhausted", {
1164
1167
  sessionId: this.state.sessionId,
1165
1168
  clientMessageId: t
@@ -1193,7 +1196,7 @@ class qt {
1193
1196
  clientMessageId: t,
1194
1197
  automatic: !0
1195
1198
  }) : this.activeUserMessageEvent && this.send(this.activeUserMessageEvent), this.markThinkingProgress();
1196
- }, v(n)));
1199
+ }, D(n)));
1197
1200
  }
1198
1201
  resyncThinkingSession() {
1199
1202
  this.state.sessionId ? this.send({
@@ -1291,7 +1294,7 @@ class qt {
1291
1294
  }));
1292
1295
  }
1293
1296
  enqueueNetworkEvent(t) {
1294
- this.queuedNetworkEvents.length >= ve || (this.queuedNetworkEvents.push(hn(t)), this.networkBatchTimer === null && (this.networkBatchTimer = window.setTimeout(() => {
1297
+ this.queuedNetworkEvents.length >= De || (this.queuedNetworkEvents.push(hn(t)), this.networkBatchTimer === null && (this.networkBatchTimer = window.setTimeout(() => {
1295
1298
  this.networkBatchTimer = null;
1296
1299
  const s = this.queuedNetworkEvents.splice(0, this.queuedNetworkEvents.length);
1297
1300
  s.length === 0 || this.socket?.readyState !== WebSocket.OPEN || this.sendNow({
@@ -1300,7 +1303,7 @@ class qt {
1300
1303
  page: A(),
1301
1304
  events: s
1302
1305
  });
1303
- }, De)));
1306
+ }, ve)));
1304
1307
  }
1305
1308
  scheduleReconnect() {
1306
1309
  if (this.reconnectTimer !== null || this.state.status === "closed")
@@ -1994,7 +1997,8 @@ function Es(e) {
1994
1997
  currentPage: s.currentPage ?? null,
1995
1998
  createdAt: r,
1996
1999
  updatedAt: i,
1997
- lastActiveAt: o
2000
+ lastActiveAt: o,
2001
+ isActive: s.isActive === !0
1998
2002
  }
1999
2003
  ];
2000
2004
  }) : [];
@@ -2108,15 +2112,15 @@ function Ft(e, t) {
2108
2112
  if (!s?.attachments?.length)
2109
2113
  return t;
2110
2114
  const n = t.attachments.map((r) => {
2111
- const i = Ds(s.attachments ?? [], r);
2112
- return i ? vs(r, i) : r;
2115
+ const i = vs(s.attachments ?? [], r);
2116
+ return i ? Ds(r, i) : r;
2113
2117
  });
2114
2118
  return { ...t, attachments: n };
2115
2119
  }
2116
- function Ds(e, t) {
2120
+ function vs(e, t) {
2117
2121
  return t.id ? e.find((s) => s.id === t.id) ?? null : null;
2118
2122
  }
2119
- function vs(e, t) {
2123
+ function Ds(e, t) {
2120
2124
  const { previewUrl: s } = t;
2121
2125
  return s ? { ...e, previewUrl: s } : e;
2122
2126
  }