@pluno/product-agent-web 0.1.66 → 0.1.68
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 +41 -3
- package/README.md +37 -1
- package/dist/index.d.ts +36 -2
- package/dist/product-agent-sdk.js +1053 -609
- package/dist/product-agent-widget.js +1226 -1138
- package/dist/transportIdentity.d.ts +26 -0
- package/dist/widget.d.ts +13 -11
- package/package.json +1 -1
package/INTEGRATION.md
CHANGED
|
@@ -57,8 +57,10 @@ const agent = await PlunoProductAgent.init({
|
|
|
57
57
|
});
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
Network capture is always enabled. The SDK
|
|
61
|
-
|
|
60
|
+
Network capture is always enabled. The SDK passively observes resource URL/timing metadata and adds richer fetch/XHR
|
|
61
|
+
metadata only when it can do so without delaying or consuming host traffic. Small declared-length textual bodies are
|
|
62
|
+
read in a detached, capped task; streaming, unknown-length, large, upload, token, Pluno, and internal bodies are skipped.
|
|
63
|
+
Captured values use the built-in limits and redaction pipeline before data leaves the browser.
|
|
62
64
|
|
|
63
65
|
## Default Widget
|
|
64
66
|
|
|
@@ -84,14 +86,50 @@ Supported widget script-tag attributes:
|
|
|
84
86
|
- optional `data-pluno-accent-color`
|
|
85
87
|
- optional `data-pluno-color-scheme`
|
|
86
88
|
- optional `data-pluno-font-family`
|
|
89
|
+
- optional `data-pluno-scribble-style="false"` to disable the default scribble appearance
|
|
87
90
|
- optional `data-pluno-position`
|
|
88
91
|
- optional `data-pluno-auto-mount="false"`
|
|
89
92
|
|
|
93
|
+
### Advanced programmatic widget
|
|
94
|
+
|
|
95
|
+
Keep the script-tag integration as the default. When the customer token endpoint requires bearer auth, CSRF, tenant
|
|
96
|
+
headers, or other custom request logic, import the same hosted ES module and pass a `tokenProvider`:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
const { mountPlunoProductAgentWidget } = await import(
|
|
100
|
+
"https://app.pluno.ai/product-agent/product-agent-widget.js"
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const widget = await mountPlunoProductAgentWidget({
|
|
104
|
+
tokenProvider: async () => {
|
|
105
|
+
const response = await fetch("/api/pluno-product-agent-token", {
|
|
106
|
+
method: "POST",
|
|
107
|
+
credentials: "include",
|
|
108
|
+
headers: {
|
|
109
|
+
Authorization: `Bearer ${customerAccessToken}`,
|
|
110
|
+
"X-CSRF-Token": csrfToken,
|
|
111
|
+
"X-Tenant-ID": tenantId,
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
if (!response.ok) throw new Error("Could not create Pluno session token");
|
|
115
|
+
return (await response.json()).token;
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
widget.openPanel();
|
|
120
|
+
function removeProductAgentWidget() {
|
|
121
|
+
widget.destroy();
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
A programmatic import does not auto-mount. Only a widget script tag with Pluno data attributes auto-mounts; callers of
|
|
126
|
+
the hosted module explicitly own the returned widget handle and should call `destroy()` when removing the integration.
|
|
127
|
+
|
|
90
128
|
## Security Decisions
|
|
91
129
|
|
|
92
130
|
- Integration secrets are backend-only.
|
|
93
131
|
- Embed tokens are short-lived Pluno-signed JWTs.
|
|
94
132
|
- The runtime validates the token origin against the integration allowlist.
|
|
95
133
|
- The runtime validates the browser WebSocket `Origin` header against the token origin.
|
|
96
|
-
- Network capture is always installed by the SDK/widget. There is intentionally no configuration or opt-out for now.
|
|
134
|
+
- Network capture is always installed by the SDK/widget, shared across instances, and removed after final teardown. There is intentionally no configuration or opt-out for now.
|
|
97
135
|
- Browser-side redaction runs before network events and tool results are sent to Pluno.
|
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ agent.on("state", (state) => {
|
|
|
33
33
|
agent.sendMessage("Update my settings");
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
The SDK
|
|
36
|
+
The SDK captures passive resource URL/timing metadata with `PerformanceObserver` and adds bounded method, header, status, and small textual body metadata through shared `fetch`/`XMLHttpRequest` instrumentation. Capture is best effort and detached from host requests: streaming, unknown-length, large, upload, token, Pluno, and internal bodies are not read, captured values are capped and redacted, and the instrumentation is removed after the final SDK instance is destroyed.
|
|
37
37
|
|
|
38
38
|
## Drop-In Widget
|
|
39
39
|
|
|
@@ -45,9 +45,45 @@ The SDK always captures product network activity by patching `fetch` and `XMLHtt
|
|
|
45
45
|
data-pluno-launcher-label="Ask for anything..."
|
|
46
46
|
data-pluno-accent-color="#7c3aed"
|
|
47
47
|
data-pluno-font-family='Inter, system-ui, sans-serif'
|
|
48
|
+
data-pluno-scribble-style="false"
|
|
48
49
|
></script>
|
|
49
50
|
```
|
|
50
51
|
|
|
52
|
+
Scribble style is enabled by default. Set `data-pluno-scribble-style="false"` in the snippet, or `scribbleStyle: false`
|
|
53
|
+
for programmatic mounts, to use the standard widget appearance.
|
|
54
|
+
|
|
55
|
+
This script-tag setup is the recommended integration. If your token endpoint needs custom browser-side authentication,
|
|
56
|
+
import the same hosted widget module and provide the request logic programmatically:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const { mountPlunoProductAgentWidget } = await import(
|
|
60
|
+
"https://app.pluno.ai/product-agent/product-agent-widget.js"
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const widget = await mountPlunoProductAgentWidget({
|
|
64
|
+
tokenProvider: async () => {
|
|
65
|
+
const response = await fetch("/api/pluno-product-agent-token", {
|
|
66
|
+
method: "POST",
|
|
67
|
+
credentials: "include",
|
|
68
|
+
headers: {
|
|
69
|
+
Authorization: `Bearer ${customerAccessToken}`,
|
|
70
|
+
"X-CSRF-Token": csrfToken,
|
|
71
|
+
"X-Tenant-ID": tenantId,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
if (!response.ok) throw new Error("Could not create Pluno session token");
|
|
75
|
+
return (await response.json()).token;
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
function removeProductAgentWidget() {
|
|
80
|
+
widget.destroy();
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Importing the hosted module does not mount anything by itself. `mountPlunoProductAgentWidget` returns a handle containing
|
|
85
|
+
the underlying `agent`, `openPanel()`, appearance/auth update methods, and `destroy()`.
|
|
86
|
+
|
|
51
87
|
The token endpoint must be implemented by the customer backend. It should authenticate the current user, then call Pluno's `/api/product-agent/embed/token` endpoint with:
|
|
52
88
|
|
|
53
89
|
- `public_key`
|
package/dist/index.d.ts
CHANGED
|
@@ -130,19 +130,45 @@ export type ProductAgentEventMap = {
|
|
|
130
130
|
};
|
|
131
131
|
type EventName = keyof ProductAgentEventMap;
|
|
132
132
|
type Listener<T extends EventName> = (payload: ProductAgentEventMap[T]) => void;
|
|
133
|
+
type CapturedRequest = {
|
|
134
|
+
requestId: string;
|
|
135
|
+
url: string;
|
|
136
|
+
method: string;
|
|
137
|
+
requestHeaders?: Record<string, string>;
|
|
138
|
+
requestBody?: string;
|
|
139
|
+
resourceType: "fetch" | "xhr" | "resource";
|
|
140
|
+
responseStatus?: number;
|
|
141
|
+
responseHeaders?: Record<string, string>;
|
|
142
|
+
responseBody?: unknown;
|
|
143
|
+
errorText?: string;
|
|
144
|
+
startedAt: string;
|
|
145
|
+
durationMs?: number;
|
|
146
|
+
};
|
|
147
|
+
type NetworkCaptureSubscriber = (event: CapturedRequest) => void;
|
|
148
|
+
type NetworkCaptureManager = {
|
|
149
|
+
subscribers: Set<NetworkCaptureSubscriber>;
|
|
150
|
+
destroy: () => void;
|
|
151
|
+
};
|
|
152
|
+
export declare function calculateReconnectDelay(attempt: number, random?: () => number): number;
|
|
133
153
|
export declare class PlunoProductAgent {
|
|
134
154
|
private readonly options;
|
|
135
155
|
private readonly listeners;
|
|
136
156
|
private socket;
|
|
137
157
|
private reconnectTimer;
|
|
138
158
|
private heartbeatTimer;
|
|
159
|
+
private heartbeatAckTimer;
|
|
160
|
+
private socketConnectTimer;
|
|
161
|
+
private socketAuthTimer;
|
|
162
|
+
private reconnectAttempts;
|
|
163
|
+
private connectionAttemptId;
|
|
164
|
+
private connectionInProgress;
|
|
139
165
|
private token;
|
|
140
166
|
private networkCaptureCleanup;
|
|
141
167
|
private networkBatchTimer;
|
|
142
168
|
private queuedNetworkEvents;
|
|
143
169
|
private queuedClientEvents;
|
|
144
170
|
private pendingSessionHistoryRequests;
|
|
145
|
-
private readonly
|
|
171
|
+
private readonly transportIdentity;
|
|
146
172
|
private retryAttemptsByClientMessageId;
|
|
147
173
|
private retryTimersByClientMessageId;
|
|
148
174
|
private thinkingWatchdogTimer;
|
|
@@ -158,6 +184,8 @@ export declare class PlunoProductAgent {
|
|
|
158
184
|
private readonly attachmentFiles;
|
|
159
185
|
private readonly attachmentBlobCache;
|
|
160
186
|
private sessionUserFilesApiCleanup;
|
|
187
|
+
private readonly activeBrowserToolCalls;
|
|
188
|
+
private pageLifecycleCleanup;
|
|
161
189
|
private transientStarterPromptsRequestInFlight;
|
|
162
190
|
private transientStarterPromptsRequestAttempted;
|
|
163
191
|
private locationChangeCleanup;
|
|
@@ -214,6 +242,7 @@ export declare class PlunoProductAgent {
|
|
|
214
242
|
private recoverStuckThinking;
|
|
215
243
|
private resyncThinkingSession;
|
|
216
244
|
private executeToolCall;
|
|
245
|
+
private startPageLifecycleRecovery;
|
|
217
246
|
private installSessionUserFilesApi;
|
|
218
247
|
private cleanupSessionUserFilesApi;
|
|
219
248
|
private executeRuntimeHelper;
|
|
@@ -222,12 +251,17 @@ export declare class PlunoProductAgent {
|
|
|
222
251
|
private scheduleReconnect;
|
|
223
252
|
private startHeartbeat;
|
|
224
253
|
private stopHeartbeat;
|
|
254
|
+
private clearHeartbeatAckTimer;
|
|
255
|
+
private clearSocketConnectTimer;
|
|
256
|
+
private clearSocketAuthTimer;
|
|
257
|
+
private clearSocketPhaseTimers;
|
|
258
|
+
private replaceTimedOutSocket;
|
|
225
259
|
private setState;
|
|
226
260
|
private emit;
|
|
227
261
|
}
|
|
228
262
|
declare global {
|
|
229
263
|
interface Window {
|
|
230
|
-
|
|
264
|
+
__plunoProductAgentNetworkCapture?: NetworkCaptureManager;
|
|
231
265
|
}
|
|
232
266
|
}
|
|
233
267
|
export declare function getProductAgentOriginAccessErrorMessage(message: string, runtimeOrigin?: string): string | null;
|