@pluno/product-agent-web 0.1.22 → 0.1.23
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 +3 -0
- package/dist/product-agent-sdk.js +55 -42
- package/dist/product-agent-widget.js +1080 -901
- package/dist/widget.d.ts +15 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -44,6 +44,7 @@ export type ProductAgentState = {
|
|
|
44
44
|
assistantDraft: string;
|
|
45
45
|
isThinking: boolean;
|
|
46
46
|
lastError: string | null;
|
|
47
|
+
lastErrorCode: string | null;
|
|
47
48
|
};
|
|
48
49
|
export type ProductAgentInitOptions = {
|
|
49
50
|
token?: string;
|
|
@@ -55,6 +56,8 @@ export type ProductAgentInitOptions = {
|
|
|
55
56
|
autoConnect?: boolean;
|
|
56
57
|
initialStarterPrompts?: string[];
|
|
57
58
|
webSocketFactory?: ProductAgentWebSocketFactory;
|
|
59
|
+
restorePersistedState?: boolean;
|
|
60
|
+
expectedPersistedSessionId?: string | null;
|
|
58
61
|
};
|
|
59
62
|
export type ProductAgentWebSocket = {
|
|
60
63
|
readyState: number;
|
|
@@ -6,7 +6,7 @@ class q {
|
|
|
6
6
|
...this.state,
|
|
7
7
|
starterPrompts: et(t.initialStarterPrompts)
|
|
8
8
|
};
|
|
9
|
-
const s = It(t.clientId);
|
|
9
|
+
const s = t.restorePersistedState === !1 ? null : It(t.clientId, t.expectedPersistedSessionId);
|
|
10
10
|
s && (this.state = {
|
|
11
11
|
...this.state,
|
|
12
12
|
...s,
|
|
@@ -15,7 +15,7 @@ class q {
|
|
|
15
15
|
assistantDraft: "",
|
|
16
16
|
isThinking: !1,
|
|
17
17
|
lastError: null
|
|
18
|
-
}), this.queuedClientEvents =
|
|
18
|
+
}), this.queuedClientEvents = _t(t.clientId);
|
|
19
19
|
}
|
|
20
20
|
options;
|
|
21
21
|
listeners = {};
|
|
@@ -45,7 +45,8 @@ class q {
|
|
|
45
45
|
messages: [],
|
|
46
46
|
assistantDraft: "",
|
|
47
47
|
isThinking: !1,
|
|
48
|
-
lastError: null
|
|
48
|
+
lastError: null,
|
|
49
|
+
lastErrorCode: null
|
|
49
50
|
};
|
|
50
51
|
static async init(t) {
|
|
51
52
|
const s = new q({
|
|
@@ -80,7 +81,7 @@ class q {
|
|
|
80
81
|
throw new Error("Pluno requires a token or tokenProvider");
|
|
81
82
|
const t = Z(this.options.backendUrl), s = this.options.webSocketFactory?.(t) ?? new WebSocket(t);
|
|
82
83
|
this.socket = s, s.addEventListener("open", () => {
|
|
83
|
-
this.socket === s && (
|
|
84
|
+
this.socket === s && (u("web-sdk.agent", "Pluno socket opened", {
|
|
84
85
|
queuedClientEventCount: this.queuedClientEvents.length,
|
|
85
86
|
isThinking: this.state.isThinking
|
|
86
87
|
}), this.token && this.sendNow({
|
|
@@ -92,7 +93,7 @@ class q {
|
|
|
92
93
|
}), s.addEventListener("message", (n) => {
|
|
93
94
|
this.socket === s && this.handleServerEvent(Q(n.data));
|
|
94
95
|
}), s.addEventListener("close", (n) => {
|
|
95
|
-
this.socket === s && (this.stopHeartbeat(), this.socket = null, this.state.status !== "closed" && (
|
|
96
|
+
this.socket === s && (this.stopHeartbeat(), this.socket = null, this.state.status !== "closed" && (u("web-sdk.agent", "Pluno socket closed; scheduling reconnect", {
|
|
96
97
|
code: typeof n?.code == "number" ? n.code : null,
|
|
97
98
|
reason: typeof n?.reason == "string" ? n.reason : "",
|
|
98
99
|
wasClean: typeof n?.wasClean == "boolean" ? n.wasClean : null,
|
|
@@ -100,7 +101,7 @@ class q {
|
|
|
100
101
|
isThinking: this.state.isThinking
|
|
101
102
|
}), this.setState({ status: "reconnecting", lastError: null }), this.scheduleReconnect()));
|
|
102
103
|
}), s.addEventListener("error", () => {
|
|
103
|
-
this.socket !== s || this.state.status === "closed" || (
|
|
104
|
+
this.socket !== s || this.state.status === "closed" || (u("web-sdk.agent", "Pluno socket error; scheduling reconnect", {
|
|
104
105
|
queuedClientEventCount: this.queuedClientEvents.length,
|
|
105
106
|
isThinking: this.state.isThinking
|
|
106
107
|
}), this.stopHeartbeat(), this.socket = null, this.setState({ status: "reconnecting", lastError: null }), this.scheduleReconnect(), s.readyState !== WebSocket.CLOSED && s.readyState !== WebSocket.CLOSING && s.close());
|
|
@@ -170,7 +171,7 @@ class q {
|
|
|
170
171
|
try {
|
|
171
172
|
return s.send(JSON.stringify(t)), !0;
|
|
172
173
|
} catch (n) {
|
|
173
|
-
return
|
|
174
|
+
return u("web-sdk.agent", "Pluno socket send failed; scheduling reconnect", {
|
|
174
175
|
message: n instanceof Error ? n.message : String(n),
|
|
175
176
|
queuedClientEventCount: this.queuedClientEvents.length,
|
|
176
177
|
isThinking: this.state.isThinking
|
|
@@ -194,13 +195,13 @@ class q {
|
|
|
194
195
|
handleServerEvent(t) {
|
|
195
196
|
if (J(t) && this.markThinkingProgress(), t.type === "auth.ok") {
|
|
196
197
|
const s = st(t), n = Object.prototype.hasOwnProperty.call(t, "appearance");
|
|
197
|
-
|
|
198
|
+
u("web-sdk.agent", "Received auth.ok appearance", {
|
|
198
199
|
hasAppearance: n,
|
|
199
200
|
rawAppearance: t.appearance,
|
|
200
201
|
normalizedAppearance: s
|
|
201
202
|
}), this.runtimeHelperJavascript = nt(t.runtimeHelpers)?.javascript ?? null;
|
|
202
203
|
const r = tt(t, "starterPrompts"), i = Object.prototype.hasOwnProperty.call(t, "starterPrompts"), a = {
|
|
203
|
-
user:
|
|
204
|
+
user: lt(t.user),
|
|
204
205
|
status: "connected"
|
|
205
206
|
};
|
|
206
207
|
(i || this.state.starterPrompts.length === 0) && (a.starterPrompts = r), (n || s) && (a.appearance = s), this.setState(a), this.state.sessionId && this.send({
|
|
@@ -215,7 +216,7 @@ class q {
|
|
|
215
216
|
const s = Array.isArray(t.items) ? t.items : [];
|
|
216
217
|
Tt(s) && this.clearRetryTimers(), this.setState({
|
|
217
218
|
sessionId: P(t.session, "id") ?? this.state.sessionId,
|
|
218
|
-
messages:
|
|
219
|
+
messages: ut(s),
|
|
219
220
|
...b(s) ? { assistantDraft: "", isThinking: !1 } : {}
|
|
220
221
|
}), b(s) && this.clearThinkingWatchdog();
|
|
221
222
|
return;
|
|
@@ -251,7 +252,12 @@ class q {
|
|
|
251
252
|
if (this.retryAfterRetryableError(t))
|
|
252
253
|
return;
|
|
253
254
|
const s = new Error(typeof t.message == "string" ? t.message.replace(/Product Agent/g, "Pluno") : "Pluno error");
|
|
254
|
-
this.setState({
|
|
255
|
+
this.setState({
|
|
256
|
+
status: "error",
|
|
257
|
+
isThinking: !1,
|
|
258
|
+
lastError: s.message,
|
|
259
|
+
lastErrorCode: typeof t.code == "string" ? t.code : null
|
|
260
|
+
}), this.clearThinkingWatchdog(), this.emit("error", s);
|
|
255
261
|
}
|
|
256
262
|
}
|
|
257
263
|
retryAfterRetryableError(t) {
|
|
@@ -292,14 +298,14 @@ class q {
|
|
|
292
298
|
return;
|
|
293
299
|
const t = this.activeClientMessageId;
|
|
294
300
|
if (!t) {
|
|
295
|
-
|
|
301
|
+
u("web-sdk.agent", "Pluno thinking watchdog resyncing without active message id", {
|
|
296
302
|
sessionId: this.state.sessionId
|
|
297
303
|
}), this.resyncThinkingSession(), this.scheduleThinkingWatchdog(6e4);
|
|
298
304
|
return;
|
|
299
305
|
}
|
|
300
306
|
const s = this.thinkingWatchdogResyncAttemptsByClientMessageId[t] ?? 0, n = this.thinkingWatchdogRetryAttemptsByClientMessageId[t] ?? 0;
|
|
301
307
|
if (s <= n) {
|
|
302
|
-
this.thinkingWatchdogResyncAttemptsByClientMessageId[t] = s + 1,
|
|
308
|
+
this.thinkingWatchdogResyncAttemptsByClientMessageId[t] = s + 1, u("web-sdk.agent", "Pluno thinking watchdog resyncing session", {
|
|
303
309
|
sessionId: this.state.sessionId,
|
|
304
310
|
clientMessageId: t,
|
|
305
311
|
resyncAttempts: s + 1
|
|
@@ -307,7 +313,7 @@ class q {
|
|
|
307
313
|
return;
|
|
308
314
|
}
|
|
309
315
|
if (n >= 2) {
|
|
310
|
-
|
|
316
|
+
u("web-sdk.agent", "Pluno thinking watchdog retry limit reached; continuing resync", {
|
|
311
317
|
sessionId: this.state.sessionId,
|
|
312
318
|
clientMessageId: t,
|
|
313
319
|
retryAttempts: n
|
|
@@ -318,7 +324,7 @@ class q {
|
|
|
318
324
|
status: this.state.status === "reconnecting" ? "reconnecting" : "connected",
|
|
319
325
|
isThinking: !0,
|
|
320
326
|
lastError: null
|
|
321
|
-
}),
|
|
327
|
+
}), u("web-sdk.agent", "Pluno thinking watchdog retrying last user message", {
|
|
322
328
|
sessionId: this.state.sessionId,
|
|
323
329
|
clientMessageId: t,
|
|
324
330
|
retryAttempts: n + 1
|
|
@@ -369,7 +375,7 @@ class q {
|
|
|
369
375
|
return;
|
|
370
376
|
const t = window.fetch.bind(window), s = XMLHttpRequest.prototype.open, n = XMLHttpRequest.prototype.setRequestHeader, r = XMLHttpRequest.prototype.send;
|
|
371
377
|
window.fetch = async (i, a) => {
|
|
372
|
-
const o = Date.now(), c = new Date(o).toISOString(),
|
|
378
|
+
const o = Date.now(), c = new Date(o).toISOString(), l = i instanceof Request ? i : null, y = typeof i == "string" ? i : i instanceof URL ? i.toString() : l?.url ?? "", w = (a?.method ?? l?.method ?? "GET").toUpperCase(), A = O(new Headers(a?.headers ?? l?.headers ?? void 0)), C = await Rt(l, a);
|
|
373
379
|
try {
|
|
374
380
|
const d = await t(i, a);
|
|
375
381
|
return this.enqueueNetworkEvent({
|
|
@@ -398,7 +404,7 @@ class q {
|
|
|
398
404
|
durationMs: Date.now() - o
|
|
399
405
|
}), d;
|
|
400
406
|
}
|
|
401
|
-
}, XMLHttpRequest.prototype.open = function(a, o, c,
|
|
407
|
+
}, XMLHttpRequest.prototype.open = function(a, o, c, l, y) {
|
|
402
408
|
return this.__plunoMeta = {
|
|
403
409
|
requestId: T("xhr"),
|
|
404
410
|
method: String(a ?? "GET").toUpperCase(),
|
|
@@ -406,12 +412,12 @@ class q {
|
|
|
406
412
|
requestHeaders: {},
|
|
407
413
|
startedAtMs: Date.now(),
|
|
408
414
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
409
|
-
}, s.call(this, a, o, c ?? !0,
|
|
415
|
+
}, s.call(this, a, o, c ?? !0, l ?? void 0, y ?? void 0);
|
|
410
416
|
}, XMLHttpRequest.prototype.setRequestHeader = function(a, o) {
|
|
411
417
|
const c = this.__plunoMeta;
|
|
412
418
|
if (c) {
|
|
413
|
-
const
|
|
414
|
-
|
|
419
|
+
const l = c.requestHeaders ?? {};
|
|
420
|
+
l[a] = o, c.requestHeaders = l;
|
|
415
421
|
}
|
|
416
422
|
return n.call(this, a, o);
|
|
417
423
|
}, XMLHttpRequest.prototype.send = function(a) {
|
|
@@ -462,7 +468,7 @@ class q {
|
|
|
462
468
|
scheduleReconnect() {
|
|
463
469
|
this.reconnectTimer !== null || this.state.status === "closed" || (this.reconnectTimer = window.setTimeout(() => {
|
|
464
470
|
this.reconnectTimer = null, this.connect().catch((t) => {
|
|
465
|
-
|
|
471
|
+
u("web-sdk.agent", "Pluno reconnect failed; retrying", {
|
|
466
472
|
message: t instanceof Error ? t.message : String(t),
|
|
467
473
|
queuedClientEventCount: this.queuedClientEvents.length,
|
|
468
474
|
isThinking: this.state.isThinking
|
|
@@ -479,13 +485,17 @@ class q {
|
|
|
479
485
|
this.heartbeatTimer !== null && (window.clearInterval(this.heartbeatTimer), this.heartbeatTimer = null);
|
|
480
486
|
}
|
|
481
487
|
setState(t) {
|
|
482
|
-
this.state = {
|
|
488
|
+
this.state = {
|
|
489
|
+
...this.state,
|
|
490
|
+
...t,
|
|
491
|
+
...t.lastError === null && t.lastErrorCode === void 0 ? { lastErrorCode: null } : {}
|
|
492
|
+
}, Et(this.options.clientId, this.state), this.emit("state", this.getState());
|
|
483
493
|
}
|
|
484
494
|
emit(t, s) {
|
|
485
495
|
this.listeners[t]?.forEach((r) => r(s));
|
|
486
496
|
}
|
|
487
497
|
}
|
|
488
|
-
function
|
|
498
|
+
function u(e, t, s) {
|
|
489
499
|
if (typeof window > "u")
|
|
490
500
|
return;
|
|
491
501
|
const n = window, r = {
|
|
@@ -521,7 +531,7 @@ async function M(e) {
|
|
|
521
531
|
result: await Promise.race([
|
|
522
532
|
new t(e.javascript)(),
|
|
523
533
|
new Promise(
|
|
524
|
-
(c,
|
|
534
|
+
(c, l) => window.setTimeout(() => l(new Error(`execute_code timed out after ${s}ms`)), s)
|
|
525
535
|
)
|
|
526
536
|
]),
|
|
527
537
|
console: r,
|
|
@@ -631,7 +641,7 @@ function at() {
|
|
|
631
641
|
function ct() {
|
|
632
642
|
return crypto.randomUUID();
|
|
633
643
|
}
|
|
634
|
-
function
|
|
644
|
+
function lt(e) {
|
|
635
645
|
if (!e || typeof e != "object")
|
|
636
646
|
return null;
|
|
637
647
|
const t = e, s = typeof t.id == "string" ? t.id : null;
|
|
@@ -642,8 +652,8 @@ function ut(e) {
|
|
|
642
652
|
avatarUrl: typeof t.avatarUrl == "string" ? t.avatarUrl : null
|
|
643
653
|
} : null;
|
|
644
654
|
}
|
|
645
|
-
function
|
|
646
|
-
return Array.isArray(e) ?
|
|
655
|
+
function ut(e) {
|
|
656
|
+
return Array.isArray(e) ? E(
|
|
647
657
|
e.map(U).filter((t) => t !== null)
|
|
648
658
|
) : [];
|
|
649
659
|
}
|
|
@@ -726,9 +736,9 @@ function ft(e) {
|
|
|
726
736
|
function yt(e, t) {
|
|
727
737
|
const s = mt(e, t), n = s.findIndex((i) => i.id === t.id);
|
|
728
738
|
if (n === -1)
|
|
729
|
-
return
|
|
739
|
+
return E([...s, t]);
|
|
730
740
|
const r = [...s];
|
|
731
|
-
return r[n] = t,
|
|
741
|
+
return r[n] = t, E(r);
|
|
732
742
|
}
|
|
733
743
|
function mt(e, t) {
|
|
734
744
|
if (t.role !== "user")
|
|
@@ -775,7 +785,7 @@ function I(e) {
|
|
|
775
785
|
const t = e;
|
|
776
786
|
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");
|
|
777
787
|
}
|
|
778
|
-
function
|
|
788
|
+
function E(e) {
|
|
779
789
|
return e.filter((t, s) => St(t) ? !kt(e, s) : !0);
|
|
780
790
|
}
|
|
781
791
|
function St(e) {
|
|
@@ -794,21 +804,24 @@ function kt(e, t) {
|
|
|
794
804
|
function P(e, t) {
|
|
795
805
|
return e && typeof e == "object" && typeof e[t] == "string" ? e[t] : null;
|
|
796
806
|
}
|
|
797
|
-
function It(e) {
|
|
807
|
+
function It(e, t) {
|
|
798
808
|
try {
|
|
799
|
-
const
|
|
800
|
-
if (!
|
|
809
|
+
const s = window.localStorage.getItem(`${H}${e}`);
|
|
810
|
+
if (!s)
|
|
811
|
+
return null;
|
|
812
|
+
const n = JSON.parse(s), r = typeof n.sessionId == "string" ? n.sessionId : null;
|
|
813
|
+
if (t !== void 0 && r !== t)
|
|
801
814
|
return null;
|
|
802
|
-
const
|
|
815
|
+
const i = Array.isArray(n.messages) ? n.messages.map(At).filter((a) => !!a) : [];
|
|
803
816
|
return {
|
|
804
|
-
sessionId:
|
|
805
|
-
messages:
|
|
817
|
+
sessionId: r,
|
|
818
|
+
messages: i
|
|
806
819
|
};
|
|
807
820
|
} catch {
|
|
808
821
|
return null;
|
|
809
822
|
}
|
|
810
823
|
}
|
|
811
|
-
function
|
|
824
|
+
function Et(e, t) {
|
|
812
825
|
try {
|
|
813
826
|
window.localStorage.setItem(
|
|
814
827
|
`${H}${e}`,
|
|
@@ -821,7 +834,7 @@ function _t(e, t) {
|
|
|
821
834
|
return;
|
|
822
835
|
}
|
|
823
836
|
}
|
|
824
|
-
function
|
|
837
|
+
function _t(e) {
|
|
825
838
|
try {
|
|
826
839
|
const t = window.localStorage.getItem(`${k}${e}`);
|
|
827
840
|
if (!t)
|
|
@@ -953,7 +966,7 @@ function p(e) {
|
|
|
953
966
|
function T(e) {
|
|
954
967
|
return `${e}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
955
968
|
}
|
|
956
|
-
const
|
|
969
|
+
const _ = "[REDACTED_SECRET]", h = "[REDACTED_TOKEN]", Pt = "[REDACTED_SIGNED_URL]", Dt = 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, j = /\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/gi, G = /\bBasic\s+[A-Za-z0-9+/=-]{12,}/gi, v = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, $ = /\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, Ht = /\bhttps?:\/\/[^\s"'<>]+(?:X-Amz-Signature|X-Goog-Signature|Signature|sig=)[^\s"'<>]*/gi, qt = /\bhttps?:\/\/[^\s"'<>]+/gi, Ut = /[),.;\]]+$/;
|
|
957
970
|
function f(e) {
|
|
958
971
|
return S(e, 0, /* @__PURE__ */ new WeakSet());
|
|
959
972
|
}
|
|
@@ -970,7 +983,7 @@ function S(e, t, s) {
|
|
|
970
983
|
return e.map((r) => S(r, t + 1, s));
|
|
971
984
|
const n = {};
|
|
972
985
|
for (const [r, i] of Object.entries(e))
|
|
973
|
-
Wt(r) ? n[r] =
|
|
986
|
+
Wt(r) ? n[r] = _ : n[r] = r.toLowerCase() === "url" ? xt(i) : S(i, t + 1, s);
|
|
974
987
|
return n;
|
|
975
988
|
}
|
|
976
989
|
function Wt(e) {
|
|
@@ -991,10 +1004,10 @@ function X(e) {
|
|
|
991
1004
|
}
|
|
992
1005
|
}
|
|
993
1006
|
function Bt(e) {
|
|
994
|
-
return e.replace(Ht, Pt).replace(qt, jt).replace(j, `Bearer ${h}`).replace(G, `Basic ${h}`).replace(v, h).replace($, (t, s) => `${s}: ${
|
|
1007
|
+
return e.replace(Ht, Pt).replace(qt, jt).replace(j, `Bearer ${h}`).replace(G, `Basic ${h}`).replace(v, h).replace($, (t, s) => `${s}: ${_}`);
|
|
995
1008
|
}
|
|
996
1009
|
function Lt(e) {
|
|
997
|
-
return e.replace(j, `Bearer ${h}`).replace(G, `Basic ${h}`).replace(v, h).replace($, (t, s) => `${s}: ${
|
|
1010
|
+
return e.replace(j, `Bearer ${h}`).replace(G, `Basic ${h}`).replace(v, h).replace($, (t, s) => `${s}: ${_}`);
|
|
998
1011
|
}
|
|
999
1012
|
function jt(e) {
|
|
1000
1013
|
const t = e.match(Ut)?.[0] ?? "", s = t ? e.slice(0, -t.length) : e;
|