genassist-chat-react 1.0.38 → 1.0.40

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.
@@ -0,0 +1,32 @@
1
+ export type LiveVoiceStatus = 'idle' | 'connecting' | 'listening' | 'speaking' | 'error';
2
+ interface UseLiveVoiceOptions {
3
+ baseUrl: string;
4
+ apiKey: string;
5
+ guestToken?: string | null;
6
+ tenant?: string;
7
+ agentId?: string | null;
8
+ conversationId?: string | null;
9
+ language?: string;
10
+ onError?: (error: Error) => void;
11
+ onInputTranscript?: (text: string) => void;
12
+ onOutputTranscript?: (text: string) => void;
13
+ onTurnComplete?: (turn: {
14
+ transcript: string;
15
+ response: string;
16
+ }) => void;
17
+ }
18
+ interface UseLiveVoiceReturn {
19
+ isActive: boolean;
20
+ status: LiveVoiceStatus;
21
+ start: () => Promise<void>;
22
+ stop: () => void;
23
+ }
24
+ /**
25
+ * Continuous, two-way voice conversation with a Voice Agent node.
26
+ *
27
+ * Streams 16 kHz mic PCM up a WebSocket to a persistent Gemini Live session and
28
+ * plays the 24 kHz reply audio back as it arrives (no record/stop/send). Supports
29
+ * barge-in: when the agent is interrupted, queued playback is flushed instantly.
30
+ */
31
+ export declare function useLiveVoice(opts: UseLiveVoiceOptions): UseLiveVoiceReturn;
32
+ export {};
@@ -0,0 +1,292 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ var __generator = (this && this.__generator) || function (thisArg, body) {
11
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
12
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ function verb(n) { return function (v) { return step([n, v]); }; }
14
+ function step(op) {
15
+ if (f) throw new TypeError("Generator is already executing.");
16
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
17
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
18
+ if (y = 0, t) op = [op[0] & 2, t.value];
19
+ switch (op[0]) {
20
+ case 0: case 1: t = op; break;
21
+ case 4: _.label++; return { value: op[1], done: false };
22
+ case 5: _.label++; y = op[1]; op = [0]; continue;
23
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
24
+ default:
25
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
26
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
27
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
28
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
29
+ if (t[2]) _.ops.pop();
30
+ _.trys.pop(); continue;
31
+ }
32
+ op = body.call(thisArg, _);
33
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
34
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
35
+ }
36
+ };
37
+ import { useCallback, useEffect, useRef, useState } from 'react';
38
+ import { createWebSocket } from '../utils/websocket';
39
+ var LIVE_INPUT_SAMPLE_RATE = 16000; // Gemini Live expects 16 kHz mono PCM in
40
+ var LIVE_OUTPUT_SAMPLE_RATE = 24000; // Gemini Live emits 24 kHz mono PCM out
41
+ var CAPTURE_BUFFER_SIZE = 4096;
42
+ /** Downsample a mono Float32 buffer to 16 kHz Int16 PCM (little-endian). */
43
+ function floatTo16kPcm(input, inputRate) {
44
+ var ratio = inputRate / LIVE_INPUT_SAMPLE_RATE;
45
+ var outLength = Math.floor(input.length / ratio);
46
+ var out = new Int16Array(outLength);
47
+ for (var i = 0; i < outLength; i++) {
48
+ var sample = input[Math.floor(i * ratio)] || 0;
49
+ var clamped = Math.max(-1, Math.min(1, sample));
50
+ out[i] = clamped < 0 ? clamped * 0x8000 : clamped * 0x7fff;
51
+ }
52
+ return out.buffer;
53
+ }
54
+ function buildLiveUrl(opts, threadId) {
55
+ // Live voice is a stateful 1:1 audio stream held by the backend, so the plugin
56
+ // connects directly to the backend (not the fan-out websocket service).
57
+ var wsBase = opts.baseUrl.replace(/^http/, 'ws').replace(/\/$/, '');
58
+ var auth = opts.guestToken
59
+ ? "access_token=".concat(encodeURIComponent(opts.guestToken))
60
+ : "api_key=".concat(encodeURIComponent(opts.apiKey));
61
+ var params = [auth, "thread_id=".concat(encodeURIComponent(threadId))];
62
+ if (opts.tenant)
63
+ params.push("x-tenant-id=".concat(encodeURIComponent(opts.tenant)));
64
+ if (opts.language)
65
+ params.push("lang=".concat(encodeURIComponent(opts.language)));
66
+ return "".concat(wsBase, "/api/voice/live/").concat(opts.agentId, "?").concat(params.join('&'));
67
+ }
68
+ /**
69
+ * Continuous, two-way voice conversation with a Voice Agent node.
70
+ *
71
+ * Streams 16 kHz mic PCM up a WebSocket to a persistent Gemini Live session and
72
+ * plays the 24 kHz reply audio back as it arrives (no record/stop/send). Supports
73
+ * barge-in: when the agent is interrupted, queued playback is flushed instantly.
74
+ */
75
+ export function useLiveVoice(opts) {
76
+ var _this = this;
77
+ var _a = useState(false), isActive = _a[0], setIsActive = _a[1];
78
+ var _b = useState('idle'), status = _b[0], setStatus = _b[1];
79
+ var wsRef = useRef(null);
80
+ var streamRef = useRef(null);
81
+ var captureCtxRef = useRef(null);
82
+ var processorRef = useRef(null);
83
+ var playbackCtxRef = useRef(null);
84
+ var playheadRef = useRef(0);
85
+ var sourcesRef = useRef([]);
86
+ var speakingTimerRef = useRef(null);
87
+ // Mirror `isActive` into a ref so async callbacks (e.g. the speaking timer)
88
+ // can read the latest value without being re-created.
89
+ var isActiveRef = useRef(false);
90
+ isActiveRef.current = isActive;
91
+ // Keep the latest callbacks without re-creating start/stop.
92
+ var optsRef = useRef(opts);
93
+ optsRef.current = opts;
94
+ var flushPlayback = useCallback(function () {
95
+ sourcesRef.current.forEach(function (src) {
96
+ try {
97
+ src.stop();
98
+ }
99
+ catch (_a) {
100
+ /* already stopped */
101
+ }
102
+ });
103
+ sourcesRef.current = [];
104
+ if (playbackCtxRef.current) {
105
+ playheadRef.current = playbackCtxRef.current.currentTime;
106
+ }
107
+ }, []);
108
+ var stop = useCallback(function () {
109
+ var _a, _b, _c, _d;
110
+ if (speakingTimerRef.current)
111
+ clearTimeout(speakingTimerRef.current);
112
+ flushPlayback();
113
+ (_a = processorRef.current) === null || _a === void 0 ? void 0 : _a.disconnect();
114
+ processorRef.current = null;
115
+ (_b = streamRef.current) === null || _b === void 0 ? void 0 : _b.getTracks().forEach(function (t) { return t.stop(); });
116
+ streamRef.current = null;
117
+ (_c = captureCtxRef.current) === null || _c === void 0 ? void 0 : _c.close().catch(function () { return undefined; });
118
+ captureCtxRef.current = null;
119
+ (_d = playbackCtxRef.current) === null || _d === void 0 ? void 0 : _d.close().catch(function () { return undefined; });
120
+ playbackCtxRef.current = null;
121
+ if (wsRef.current) {
122
+ wsRef.current.onclose = null;
123
+ try {
124
+ wsRef.current.close();
125
+ }
126
+ catch (_e) {
127
+ /* noop */
128
+ }
129
+ wsRef.current = null;
130
+ }
131
+ setIsActive(false);
132
+ setStatus('idle');
133
+ }, [flushPlayback]);
134
+ var playPcmChunk = useCallback(function (pcm) {
135
+ var ctx = playbackCtxRef.current;
136
+ if (!ctx)
137
+ return;
138
+ var ints = new Int16Array(pcm);
139
+ if (ints.length === 0)
140
+ return;
141
+ var floats = new Float32Array(ints.length);
142
+ for (var i = 0; i < ints.length; i++)
143
+ floats[i] = ints[i] / 0x8000;
144
+ var buffer = ctx.createBuffer(1, floats.length, LIVE_OUTPUT_SAMPLE_RATE);
145
+ buffer.copyToChannel(floats, 0);
146
+ var source = ctx.createBufferSource();
147
+ source.buffer = buffer;
148
+ source.connect(ctx.destination);
149
+ var startAt = Math.max(ctx.currentTime, playheadRef.current);
150
+ source.start(startAt);
151
+ playheadRef.current = startAt + buffer.duration;
152
+ sourcesRef.current.push(source);
153
+ source.onended = function () {
154
+ sourcesRef.current = sourcesRef.current.filter(function (s) { return s !== source; });
155
+ };
156
+ // Reflect "speaking" until the scheduled audio drains.
157
+ setStatus('speaking');
158
+ if (speakingTimerRef.current)
159
+ clearTimeout(speakingTimerRef.current);
160
+ var remainingMs = (playheadRef.current - ctx.currentTime) * 1000 + 150;
161
+ speakingTimerRef.current = setTimeout(function () {
162
+ if (isActiveRef.current)
163
+ setStatus('listening');
164
+ }, remainingMs);
165
+ }, []);
166
+ var handleEvent = useCallback(function (data) {
167
+ var _a, _b, _c, _d, _e, _f, _g;
168
+ var cb = optsRef.current;
169
+ switch (data.type) {
170
+ case 'ready':
171
+ setStatus('listening');
172
+ break;
173
+ case 'input_transcript':
174
+ if (typeof data.text === 'string')
175
+ (_a = cb.onInputTranscript) === null || _a === void 0 ? void 0 : _a.call(cb, data.text);
176
+ break;
177
+ case 'output_transcript':
178
+ if (typeof data.text === 'string')
179
+ (_b = cb.onOutputTranscript) === null || _b === void 0 ? void 0 : _b.call(cb, data.text);
180
+ break;
181
+ case 'interrupted':
182
+ flushPlayback();
183
+ setStatus('listening');
184
+ break;
185
+ case 'turn_complete':
186
+ (_c = cb.onTurnComplete) === null || _c === void 0 ? void 0 : _c.call(cb, {
187
+ transcript: String((_d = data.transcript) !== null && _d !== void 0 ? _d : ''),
188
+ response: String((_e = data.response) !== null && _e !== void 0 ? _e : ''),
189
+ });
190
+ break;
191
+ case 'error':
192
+ (_f = cb.onError) === null || _f === void 0 ? void 0 : _f.call(cb, new Error(String((_g = data.message) !== null && _g !== void 0 ? _g : 'Live voice error')));
193
+ setStatus('error');
194
+ break;
195
+ default:
196
+ break;
197
+ }
198
+ }, [flushPlayback]);
199
+ var start = useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
200
+ var cb, threadId, stream_1, AudioCtx, captureCtx_1, ws_1, err_1;
201
+ var _a, _b;
202
+ return __generator(this, function (_c) {
203
+ switch (_c.label) {
204
+ case 0:
205
+ cb = optsRef.current;
206
+ if (!cb.agentId) {
207
+ (_a = cb.onError) === null || _a === void 0 ? void 0 : _a.call(cb, new Error('Live voice unavailable: agent is still loading'));
208
+ return [2 /*return*/];
209
+ }
210
+ if (wsRef.current)
211
+ return [2 /*return*/]; // already active
212
+ setStatus('connecting');
213
+ // Persistence (transcript/dashboard) keys off an existing conversation UUID.
214
+ // Without one the call still works, but the backend skips saving the turns.
215
+ if (!cb.conversationId) {
216
+ console.warn('[useLiveVoice] No conversationId yet — the live call will run but its ' +
217
+ 'transcripts will not be persisted.');
218
+ }
219
+ threadId = cb.conversationId ||
220
+ (typeof crypto !== 'undefined' && 'randomUUID' in crypto
221
+ ? crypto.randomUUID()
222
+ : "live-".concat(Date.now()));
223
+ _c.label = 1;
224
+ case 1:
225
+ _c.trys.push([1, 3, , 4]);
226
+ return [4 /*yield*/, navigator.mediaDevices.getUserMedia({
227
+ audio: { channelCount: 1, echoCancellation: true, noiseSuppression: true },
228
+ })];
229
+ case 2:
230
+ stream_1 = _c.sent();
231
+ streamRef.current = stream_1;
232
+ AudioCtx = window.AudioContext ||
233
+ window.webkitAudioContext;
234
+ captureCtx_1 = new AudioCtx();
235
+ captureCtxRef.current = captureCtx_1;
236
+ playbackCtxRef.current = new AudioCtx();
237
+ playheadRef.current = playbackCtxRef.current.currentTime;
238
+ ws_1 = createWebSocket(buildLiveUrl(cb, threadId));
239
+ ws_1.binaryType = 'arraybuffer';
240
+ wsRef.current = ws_1;
241
+ ws_1.onopen = function () {
242
+ var source = captureCtx_1.createMediaStreamSource(stream_1);
243
+ // TODO: migrate to AudioWorklet — ScriptProcessorNode is deprecated and
244
+ // runs the downsample on the main thread (can jank on slow devices).
245
+ var processor = captureCtx_1.createScriptProcessor(CAPTURE_BUFFER_SIZE, 1, 1);
246
+ processorRef.current = processor;
247
+ processor.onaudioprocess = function (e) {
248
+ if (ws_1.readyState !== ws_1.OPEN)
249
+ return;
250
+ var pcm = floatTo16kPcm(e.inputBuffer.getChannelData(0), captureCtx_1.sampleRate);
251
+ ws_1.send(pcm);
252
+ };
253
+ source.connect(processor);
254
+ processor.connect(captureCtx_1.destination); // required to drive onaudioprocess
255
+ setIsActive(true);
256
+ setStatus('listening');
257
+ };
258
+ ws_1.onmessage = function (event) {
259
+ if (event.data instanceof ArrayBuffer) {
260
+ playPcmChunk(event.data);
261
+ }
262
+ else if (typeof event.data === 'string') {
263
+ try {
264
+ handleEvent(JSON.parse(event.data));
265
+ }
266
+ catch (_a) {
267
+ /* ignore malformed event */
268
+ }
269
+ }
270
+ };
271
+ ws_1.onerror = function () {
272
+ var _a;
273
+ (_a = cb.onError) === null || _a === void 0 ? void 0 : _a.call(cb, new Error('Live voice connection error'));
274
+ };
275
+ ws_1.onclose = function () {
276
+ stop();
277
+ };
278
+ return [3 /*break*/, 4];
279
+ case 3:
280
+ err_1 = _c.sent();
281
+ (_b = cb.onError) === null || _b === void 0 ? void 0 : _b.call(cb, err_1 instanceof Error ? err_1 : new Error(String(err_1)));
282
+ stop();
283
+ return [3 /*break*/, 4];
284
+ case 4: return [2 /*return*/];
285
+ }
286
+ });
287
+ }); }, [handleEvent, playPcmChunk, stop]);
288
+ // Tear down on unmount.
289
+ useEffect(function () { return function () { return stop(); }; }, [stop]);
290
+ return { isActive: isActive, status: status, start: start, stop: stop };
291
+ }
292
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlTGl2ZVZvaWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hvb2tzL3VzZUxpdmVWb2ljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sT0FBTyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVyRCxJQUFNLHNCQUFzQixHQUFHLEtBQUssQ0FBQyxDQUFDLHlDQUF5QztBQUMvRSxJQUFNLHVCQUF1QixHQUFHLEtBQUssQ0FBQyxDQUFDLHdDQUF3QztBQUMvRSxJQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQztBQWlDakMsNEVBQTRFO0FBQzVFLFNBQVMsYUFBYSxDQUFDLEtBQW1CLEVBQUUsU0FBaUI7SUFDM0QsSUFBTSxLQUFLLEdBQUcsU0FBUyxHQUFHLHNCQUFzQixDQUFDO0lBQ2pELElBQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsQ0FBQztJQUNuRCxJQUFNLEdBQUcsR0FBRyxJQUFJLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN0QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDbkMsSUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2pELElBQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUNsRCxHQUFH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T0FBQSxFQUFFLElBQUksTUFBQSxFQUFFLENBQUM7QUFDM0MsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHVzZUNhbGxiYWNrLCB1c2VFZmZlY3QsIHVzZVJlZiwgdXNlU3RhdGUgfSBmcm9tICdyZWFjdCc7XG5pbXBvcnQgeyBjcmVhdGVXZWJTb2NrZXQgfSBmcm9tICcuLi91dGlscy93ZWJzb2NrZXQnO1xuXG5jb25zdCBMSVZFX0lOUFVUX1NBTVBMRV9SQVRFID0gMTYwMDA7IC8vIEdlbWluaSBMaXZlIGV4cGVjdHMgMTYga0h6IG1vbm8gUENNIGluXG5jb25zdCBMSVZFX09VVFBVVF9TQU1QTEVfUkFURSA9IDI0MDAwOyAvLyBHZW1pbmkgTGl2ZSBlbWl0cyAyNCBrSHogbW9ubyBQQ00gb3V0XG5jb25zdCBDQVBUVVJFX0JVRkZFUl9TSVpFID0gNDA5NjtcblxuZXhwb3J0IHR5cGUgTGl2ZVZvaWNlU3RhdHVzID1cbiAgfCAnaWRsZSdcbiAgfCAnY29ubmVjdGluZydcbiAgfCAnbGlzdGVuaW5nJ1xuICB8ICdzcGVha2luZydcbiAgfCAnZXJyb3InO1xuXG5pbnRlcmZhY2UgVXNlTGl2ZVZvaWNlT3B0aW9ucyB7XG4gIC8vIEJhY2tlbmQgYmFzZSBVUkwgKGh0dHAvaHR0cHMpLiBMaXZlIHZvaWNlIGlzIGEgc3RhdGVmdWwgMToxIGF1ZGlvIHN0cmVhbVxuICAvLyBoZWxkIGJ5IHRoZSBiYWNrZW5kLCBzbyB0aGUgcGx1Z2luIGNvbm5lY3RzIHRoZXJlIGRpcmVjdGx5ICh0aGUgZmFuLW91dFxuICAvLyB3ZWJzb2NrZXQgc2VydmljZSBpcyBub3QgaW52b2x2ZWQpLlxuICBiYXNlVXJsOiBzdHJpbmc7XG4gIGFwaUtleTogc3RyaW5nO1xuICBndWVzdFRva2VuPzogc3RyaW5nIHwgbnVsbDtcbiAgdGVuYW50Pzogc3RyaW5nO1xuICBhZ2VudElkPzogc3RyaW5nIHwgbnVsbDtcbiAgY29udmVyc2F0aW9uSWQ/OiBzdHJpbmcgfCBudWxsO1xuICBsYW5ndWFnZT86IHN0cmluZztcbiAgb25FcnJvcj86IChlcnJvcjogRXJyb3IpID0+IHZvaWQ7XG4gIG9uSW5wdXRUcmFuc2NyaXB0PzogKHRleHQ6IHN0cmluZykgPT4gdm9pZDtcbiAgb25PdXRwdXRUcmFuc2NyaXB0PzogKHRleHQ6IHN0cmluZykgPT4gdm9pZDtcbiAgb25UdXJuQ29tcGxldGU/OiAodHVybjogeyB0cmFuc2NyaXB0OiBzdHJpbmc7IHJlc3BvbnNlOiBzdHJpbmcgfSkgPT4gdm9pZDtcbn1cblxuaW50ZXJmYWNlIFVzZUxpdmVWb2ljZVJldHVybiB7XG4gIGlzQWN0aXZlOiBib29sZWFuO1xuICBzdGF0dXM6IExpdmVWb2ljZVN0YXR1cztcbiAgc3RhcnQ6ICgpID0+IFByb21pc2U8dm9pZD47XG4gIHN0b3A6ICgpID0+IHZvaWQ7XG59XG5cbi8qKiBEb3duc2FtcGxlIGEgbW9ubyBGbG9hdDMyIGJ1ZmZlciB0byAxNiBrSHogSW50MTYgUENNIChsaXR0bGUtZW5kaWFuKS4gKi9cbmZ1bmN0aW9uIGZsb2F0VG8xNmtQY20oaW5wdXQ6IEZsb2F0MzJBcnJheSwgaW5wdXRSYXRlOiBudW1iZXIpOiBBcnJheUJ1ZmZlciB7XG4gIGNvbnN0IHJhdGlvID0gaW5wdXRSYXRlIC8gTElWRV9JTlBVVF9TQU1QTEVfUkFURTtcbiAgY29uc3Qgb3V0TGVuZ3RoID0gTWF0aC5mbG9vcihpbnB1dC5sZW5ndGggLyByYXRpbyk7XG4gIGNvbnN0IG91dCA9IG5ldyBJbnQxNkFycmF5KG91dExlbmd0aCk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgb3V0TGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBzYW1wbGUgPSBpbnB1dFtNYXRoLmZsb29yKGkgKiByYXRpbyldIHx8IDA7XG4gICAgY29uc3QgY2xhbXBlZCA9IE1hdGgubWF4KC0xLCBNYXRoLm1pbigxLCBzYW1wbGUpKTtcbiAgICBvdXRbaV0gPSBjbGFtcGVkIDwgMCA/IGNsYW1wZWQgKiAweDgwMDAgOiBjbGFtcGVkICogMHg3ZmZmO1xuICB9XG4gIHJldHVybiBvdXQuYnVmZmVyO1xufVxuXG5mdW5jdGlvbiBidWlsZExpdmVVcmwob3B0czogVXNlTGl2ZVZvaWNlT3B0aW9ucywgdGhyZWFkSWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIC8vIExpdmUgdm9pY2UgaXMgYSBzdGF0ZWZ1bCAxOjEgYXVkaW8gc3RyZWFtIGhlbGQgYnkgdGhlIGJhY2tlbmQsIHNvIHRoZSBwbHVnaW5cbiAgLy8gY29ubmVjdHMgZGlyZWN0bHkgdG8gdGhlIGJhY2tlbmQgKG5vdCB0aGUgZmFuLW91dCB3ZWJzb2NrZXQgc2VydmljZSkuXG4gIGNvbnN0IHdzQmFzZSA9IG9wdHMuYmFzZVVybC5yZXBsYWNlKC9eaHR0cC8sICd3cycpLnJlcGxhY2UoL1xcLyQvLCAnJyk7XG4gIGNvbnN0IGF1dGggPSBvcHRzLmd1ZXN0VG9rZW5cbiAgICA/IGBhY2Nlc3NfdG9rZW49JHtlbmNvZGVVUklDb21wb25lbnQob3B0cy5ndWVzdFRva2VuKX1gXG4gICAgOiBgYXBpX2tleT0ke2VuY29kZVVSSUNvbXBvbmVudChvcHRzLmFwaUtleSl9YDtcbiAgY29uc3QgcGFyYW1zID0gW2F1dGgsIGB0aHJlYWRfaWQ9JHtlbmNvZGVVUklDb21wb25lbnQodGhyZWFkSWQpfWBdO1xuICBpZiAob3B0cy50ZW5hbnQpIHBhcmFtcy5wdXNoKGB4LXRlbmFudC1pZD0ke2VuY29kZVVSSUNvbXBvbmVudChvcHRzLnRlbmFudCl9YCk7XG4gIGlmIChvcHRzLmxhbmd1YWdlKSBwYXJhbXMucHVzaChgbGFuZz0ke2VuY29kZVVSSUNvbXBvbmVudChvcHRzLmxhbmd1YWdlKX1gKTtcbiAgcmV0dXJuIGAke3dzQmFzZX0vYXBpL3ZvaWNlL2xpdmUvJHtvcHRzLmFnZW50SWR9PyR7cGFyYW1zLmpvaW4oJyYnKX1gO1xufVxuXG4vKipcbiAqIENvbnRpbnVvdXMsIHR3by13YXkgdm9pY2UgY29udmVyc2F0aW9uIHdpdGggYSBWb2ljZSBBZ2VudCBub2RlLlxuICpcbiAqIFN0cmVhbXMgMTYga0h6IG1pYyBQQ00gdXAgYSBXZWJTb2NrZXQgdG8gYSBwZXJzaXN0ZW50IEdlbWluaSBMaXZlIHNlc3Npb24gYW5kXG4gKiBwbGF5cyB0aGUgMjQga0h6IHJlcGx5IGF1ZGlvIGJhY2sgYXMgaXQgYXJyaXZlcyAobm8gcmVjb3JkL3N0b3Avc2VuZCkuIFN1cHBvcnRzXG4gKiBiYXJnZS1pbjogd2hlbiB0aGUgYWdlbnQgaXMgaW50ZXJydXB0ZWQsIHF1ZXVlZCBwbGF5YmFjayBpcyBmbHVzaGVkIGluc3RhbnRseS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVzZUxpdmVWb2ljZShvcHRzOiBVc2VMaXZlVm9pY2VPcHRpb25zKTogVXNlTGl2ZVZvaWNlUmV0dXJuIHtcbiAgY29uc3QgW2lzQWN0aXZlLCBzZXRJc0FjdGl2ZV0gPSB1c2VTdGF0ZShmYWxzZSk7XG4gIGNvbnN0IFtzdGF0dXMsIHNldFN0YXR1c10gPSB1c2VTdGF0ZTxMaXZlVm9pY2VTdGF0dXM+KCdpZGxlJyk7XG5cbiAgY29uc3Qgd3NSZWYgPSB1c2VSZWY8V2ViU29ja2V0IHwgbnVsbD4obnVsbCk7XG4gIGNvbnN0IHN0cmVhbVJlZiA9IHVzZVJlZjxNZWRpYVN0cmVhbSB8IG51bGw+KG51bGwpO1xuICBjb25zdCBjYXB0dXJlQ3R4UmVmID0gdXNlUmVmPEF1ZGlvQ29udGV4dCB8IG51bGw+KG51bGwpO1xuICBjb25zdCBwcm9jZXNzb3JSZWYgPSB1c2VSZWY8U2NyaXB0UHJvY2Vzc29yTm9kZSB8IG51bGw+KG51bGwpO1xuICBjb25zdCBwbGF5YmFja0N0eFJlZiA9IHVzZVJlZjxBdWRpb0NvbnRleHQgfCBudWxsPihudWxsKTtcbiAgY29uc3QgcGxheWhlYWRSZWYgPSB1c2VSZWY8bnVtYmVyPigwKTtcbiAgY29uc3Qgc291cmNlc1JlZiA9IHVzZVJlZjxBdWRpb0J1ZmZlclNvdXJjZU5vZGVbXT4oW10pO1xuICBjb25zdCBzcGVha2luZ1RpbWVyUmVmID0gdXNlUmVmPFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbD4obnVsbCk7XG5cbiAgLy8gTWlycm9yIGBpc0FjdGl2ZWAgaW50byBhIHJlZiBzbyBhc3luYyBjYWxsYmFja3MgKGUuZy4gdGhlIHNwZWFraW5nIHRpbWVyKVxuICAvLyBjYW4gcmVhZCB0aGUgbGF0ZXN0IHZhbHVlIHdpdGhvdXQgYmVpbmcgcmUtY3JlYXRlZC5cbiAgY29uc3QgaXNBY3RpdmVSZWYgPSB1c2VSZWYoZmFsc2UpO1xuICBpc0FjdGl2ZVJlZi5jdXJyZW50ID0gaXNBY3RpdmU7XG5cbiAgLy8gS2VlcCB0aGUgbGF0ZXN0IGNhbGxiYWNrcyB3aXRob3V0IHJlLWNyZWF0aW5nIHN0YXJ0L3N0b3AuXG4gIGNvbnN0IG9wdHNSZWYgPSB1c2VSZWYob3B0cyk7XG4gIG9wdHNSZWYuY3VycmVudCA9IG9wdHM7XG5cbiAgY29uc3QgZmx1c2hQbGF5YmFjayA9IHVzZUNhbGxiYWNrKCgpID0+IHtcbiAgICBzb3VyY2VzUmVmLmN1cnJlbnQuZm9yRWFjaCgoc3JjKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBzcmMuc3RvcCgpO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8qIGFscmVhZHkgc3RvcHBlZCAqL1xuICAgICAgfVxuICAgIH0pO1xuICAgIHNvdXJjZXNSZWYuY3VycmVudCA9IFtdO1xuICAgIGlmIChwbGF5YmFja0N0eFJlZi5jdXJyZW50KSB7XG4gICAgICBwbGF5aGVhZFJlZi5jdXJyZW50ID0gcGxheWJhY2tDdHhSZWYuY3VycmVudC5jdXJyZW50VGltZTtcbiAgICB9XG4gIH0sIFtdKTtcblxuICBjb25zdCBzdG9wID0gdXNlQ2FsbGJhY2soKCkgPT4ge1xuICAgIGlmIChzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQpIGNsZWFyVGltZW91dChzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQpO1xuICAgIGZsdXNoUGxheWJhY2soKTtcbiAgICBwcm9jZXNzb3JSZWYuY3VycmVudD8uZGlzY29ubmVjdCgpO1xuICAgIHByb2Nlc3NvclJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICBzdHJlYW1SZWYuY3VycmVudD8uZ2V0VHJhY2tzKCkuZm9yRWFjaCgodCkgPT4gdC5zdG9wKCkpO1xuICAgIHN0cmVhbVJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICBjYXB0dXJlQ3R4UmVmLmN1cnJlbnQ/LmNsb3NlKCkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICBjYXB0dXJlQ3R4UmVmLmN1cnJlbnQgPSBudWxsO1xuICAgIHBsYXliYWNrQ3R4UmVmLmN1cnJlbnQ/LmNsb3NlKCkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICBwbGF5YmFja0N0eFJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICBpZiAod3NSZWYuY3VycmVudCkge1xuICAgICAgd3NSZWYuY3VycmVudC5vbmNsb3NlID0gbnVsbDtcbiAgICAgIHRyeSB7XG4gICAgICAgIHdzUmVmLmN1cnJlbnQuY2xvc2UoKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvKiBub29wICovXG4gICAgICB9XG4gICAgICB3c1JlZi5jdXJyZW50ID0gbnVsbDtcbiAgICB9XG4gICAgc2V0SXNBY3RpdmUoZmFsc2UpO1xuICAgIHNldFN0YXR1cygnaWRsZScpO1xuICB9LCBbZmx1c2hQbGF5YmFja10pO1xuXG4gIGNvbnN0IHBsYXlQY21DaHVuayA9IHVzZUNhbGxiYWNrKChwY206IEFycmF5QnVmZmVyKSA9PiB7XG4gICAgY29uc3QgY3R4ID0gcGxheWJhY2tDdHhSZWYuY3VycmVudDtcbiAgICBpZiAoIWN0eCkgcmV0dXJuO1xuICAgIGNvbnN0IGludHMgPSBuZXcgSW50MTZBcnJheShwY20pO1xuICAgIGlmIChpbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAgIGNvbnN0IGZsb2F0cyA9IG5ldyBGbG9hdDMyQXJyYXkoaW50cy5sZW5ndGgpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaW50cy5sZW5ndGg7IGkrKykgZmxvYXRzW2ldID0gaW50c1tpXSAvIDB4ODAwMDtcblxuICAgIGNvbnN0IGJ1ZmZlciA9IGN0eC5jcmVhdGVCdWZmZXIoMSwgZmxvYXRzLmxlbmd0aCwgTElWRV9PVVRQVVRfU0FNUExFX1JBVEUpO1xuICAgIGJ1ZmZlci5jb3B5VG9DaGFubmVsKGZsb2F0cywgMCk7XG4gICAgY29uc3Qgc291cmNlID0gY3R4LmNyZWF0ZUJ1ZmZlclNvdXJjZSgpO1xuICAgIHNvdXJjZS5idWZmZXIgPSBidWZmZXI7XG4gICAgc291cmNlLmNvbm5lY3QoY3R4LmRlc3RpbmF0aW9uKTtcblxuICAgIGNvbnN0IHN0YXJ0QXQgPSBNYXRoLm1heChjdHguY3VycmVudFRpbWUsIHBsYXloZWFkUmVmLmN1cnJlbnQpO1xuICAgIHNvdXJjZS5zdGFydChzdGFydEF0KTtcbiAgICBwbGF5aGVhZFJlZi5jdXJyZW50ID0gc3RhcnRBdCArIGJ1ZmZlci5kdXJhdGlvbjtcbiAgICBzb3VyY2VzUmVmLmN1cnJlbnQucHVzaChzb3VyY2UpO1xuICAgIHNvdXJjZS5vbmVuZGVkID0gKCkgPT4ge1xuICAgICAgc291cmNlc1JlZi5jdXJyZW50ID0gc291cmNlc1JlZi5jdXJyZW50LmZpbHRlcigocykgPT4gcyAhPT0gc291cmNlKTtcbiAgICB9O1xuXG4gICAgLy8gUmVmbGVjdCBcInNwZWFraW5nXCIgdW50aWwgdGhlIHNjaGVkdWxlZCBhdWRpbyBkcmFpbnMuXG4gICAgc2V0U3RhdHVzKCdzcGVha2luZycpO1xuICAgIGlmIChzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQpIGNsZWFyVGltZW91dChzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQpO1xuICAgIGNvbnN0IHJlbWFpbmluZ01zID0gKHBsYXloZWFkUmVmLmN1cnJlbnQgLSBjdHguY3VycmVudFRpbWUpICogMTAwMCArIDE1MDtcbiAgICBzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIGlmIChpc0FjdGl2ZVJlZi5jdXJyZW50KSBzZXRTdGF0dXMoJ2xpc3RlbmluZycpO1xuICAgIH0sIHJlbWFpbmluZ01zKTtcbiAgfSwgW10pO1xuXG4gIGNvbnN0IGhhbmRsZUV2ZW50ID0gdXNlQ2FsbGJhY2soKGRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiB7XG4gICAgY29uc3QgY2IgPSBvcHRzUmVmLmN1cnJlbnQ7XG4gICAgc3dpdGNoIChkYXRhLnR5cGUpIHtcbiAgICAgIGNhc2UgJ3JlYWR5JzpcbiAgICAgICAgc2V0U3RhdHVzKCdsaXN0ZW5pbmcnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdpbnB1dF90cmFuc2NyaXB0JzpcbiAgICAgICAgaWYgKHR5cGVvZiBkYXRhLnRleHQgPT09ICdzdHJpbmcnKSBjYi5vbklucHV0VHJhbnNjcmlwdD8uKGRhdGEudGV4dCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnb3V0cHV0X3RyYW5zY3JpcHQnOlxuICAgICAgICBpZiAodHlwZW9mIGRhdGEudGV4dCA9PT0gJ3N0cmluZycpIGNiLm9uT3V0cHV0VHJhbnNjcmlwdD8uKGRhdGEudGV4dCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnaW50ZXJydXB0ZWQnOlxuICAgICAgICBmbHVzaFBsYXliYWNrKCk7XG4gICAgICAgIHNldFN0YXR1cygnbGlzdGVuaW5nJyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAndHVybl9jb21wbGV0ZSc6XG4gICAgICAgIGNiLm9uVHVybkNvbXBsZXRlPy4oe1xuICAgICAgICAgIHRyYW5zY3JpcHQ6IFN0cmluZyhkYXRhLnRyYW5zY3JpcHQgPz8gJycpLFxuICAgICAgICAgIHJlc3BvbnNlOiBTdHJpbmcoZGF0YS5yZXNwb25zZSA/PyAnJyksXG4gICAgICAgIH0pO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2Vycm9yJzpcbiAgICAgICAgY2Iub25FcnJvcj8uKG5ldyBFcnJvcihTdHJpbmcoZGF0YS5tZXNzYWdlID8/ICdMaXZlIHZvaWNlIGVycm9yJykpKTtcbiAgICAgICAgc2V0U3RhdHVzKCdlcnJvcicpO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfSwgW2ZsdXNoUGxheWJhY2tdKTtcblxuICBjb25zdCBzdGFydCA9IHVzZUNhbGxiYWNrKGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBjYiA9IG9wdHNSZWYuY3VycmVudDtcbiAgICBpZiAoIWNiLmFnZW50SWQpIHtcbiAgICAgIGNiLm9uRXJyb3I/LihuZXcgRXJyb3IoJ0xpdmUgdm9pY2UgdW5hdmFpbGFibGU6IGFnZW50IGlzIHN0aWxsIGxvYWRpbmcnKSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICh3c1JlZi5jdXJyZW50KSByZXR1cm47IC8vIGFscmVhZHkgYWN0aXZlXG5cbiAgICBzZXRTdGF0dXMoJ2Nvbm5lY3RpbmcnKTtcbiAgICAvLyBQZXJzaXN0ZW5jZSAodHJhbnNjcmlwdC9kYXNoYm9hcmQpIGtleXMgb2ZmIGFuIGV4aXN0aW5nIGNvbnZlcnNhdGlvbiBVVUlELlxuICAgIC8vIFdpdGhvdXQgb25lIHRoZSBjYWxsIHN0aWxsIHdvcmtzLCBidXQgdGhlIGJhY2tlbmQgc2tpcHMgc2F2aW5nIHRoZSB0dXJucy5cbiAgICBpZiAoIWNiLmNvbnZlcnNhdGlvbklkKSB7XG4gICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICdbdXNlTGl2ZVZvaWNlXSBObyBjb252ZXJzYXRpb25JZCB5ZXQg4oCUIHRoZSBsaXZlIGNhbGwgd2lsbCBydW4gYnV0IGl0cyAnICtcbiAgICAgICAgICAndHJhbnNjcmlwdHMgd2lsbCBub3QgYmUgcGVyc2lzdGVkLicsXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCB0aHJlYWRJZCA9XG4gICAgICBjYi5jb252ZXJzYXRpb25JZCB8fFxuICAgICAgKHR5cGVvZiBjcnlwdG8gIT09ICd1bmRlZmluZWQnICYmICdyYW5kb21VVUlEJyBpbiBjcnlwdG9cbiAgICAgICAgPyBjcnlwdG8ucmFuZG9tVVVJRCgpXG4gICAgICAgIDogYGxpdmUtJHtEYXRlLm5vdygpfWApO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHN0cmVhbSA9IGF3YWl0IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKHtcbiAgICAgICAgYXVkaW86IHsgY2hhbm5lbENvdW50OiAxLCBlY2hvQ2FuY2VsbGF0aW9uOiB0cnVlLCBub2lzZVN1cHByZXNzaW9uOiB0cnVlIH0sXG4gICAgICB9KTtcbiAgICAgIHN0cmVhbVJlZi5jdXJyZW50ID0gc3RyZWFtO1xuXG4gICAgICBjb25zdCBBdWRpb0N0eCA9XG4gICAgICAgIHdpbmRvdy5BdWRpb0NvbnRleHQgfHxcbiAgICAgICAgKHdpbmRvdyBhcyB1bmtub3duIGFzIHsgd2Via2l0QXVkaW9Db250ZXh0OiB0eXBlb2YgQXVkaW9Db250ZXh0IH0pLndlYmtpdEF1ZGlvQ29udGV4dDtcbiAgICAgIGNvbnN0IGNhcHR1cmVDdHggPSBuZXcgQXVkaW9DdHgoKTtcbiAgICAgIGNhcHR1cmVDdHhSZWYuY3VycmVudCA9IGNhcHR1cmVDdHg7XG4gICAgICBwbGF5YmFja0N0eFJlZi5jdXJyZW50ID0gbmV3IEF1ZGlvQ3R4KCk7XG4gICAgICBwbGF5aGVhZFJlZi5jdXJyZW50ID0gcGxheWJhY2tDdHhSZWYuY3VycmVudC5jdXJyZW50VGltZTtcblxuICAgICAgY29uc3Qgd3MgPSBjcmVhdGVXZWJTb2NrZXQoYnVpbGRMaXZlVXJsKGNiLCB0aHJlYWRJZCkpO1xuICAgICAgd3MuYmluYXJ5VHlwZSA9ICdhcnJheWJ1ZmZlcic7XG4gICAgICB3c1JlZi5jdXJyZW50ID0gd3M7XG5cbiAgICAgIHdzLm9ub3BlbiA9ICgpID0+IHtcbiAgICAgICAgY29uc3Qgc291cmNlID0gY2FwdHVyZUN0eC5jcmVhdGVNZWRpYVN0cmVhbVNvdXJjZShzdHJlYW0pO1xuICAgICAgICAvLyBUT0RPOiBtaWdyYXRlIHRvIEF1ZGlvV29ya2xldCDigJQgU2NyaXB0UHJvY2Vzc29yTm9kZSBpcyBkZXByZWNhdGVkIGFuZFxuICAgICAgICAvLyBydW5zIHRoZSBkb3duc2FtcGxlIG9uIHRoZSBtYWluIHRocmVhZCAoY2FuIGphbmsgb24gc2xvdyBkZXZpY2VzKS5cbiAgICAgICAgY29uc3QgcHJvY2Vzc29yID0gY2FwdHVyZUN0eC5jcmVhdGVTY3JpcHRQcm9jZXNzb3IoQ0FQVFVSRV9CVUZGRVJfU0laRSwgMSwgMSk7XG4gICAgICAgIHByb2Nlc3NvclJlZi5jdXJyZW50ID0gcHJvY2Vzc29yO1xuICAgICAgICBwcm9jZXNzb3Iub25hdWRpb3Byb2Nlc3MgPSAoZSkgPT4ge1xuICAgICAgICAgIGlmICh3cy5yZWFkeVN0YXRlICE9PSB3cy5PUEVOKSByZXR1cm47XG4gICAgICAgICAgY29uc3QgcGNtID0gZmxvYXRUbzE2a1BjbShlLmlucHV0QnVmZmVyLmdldENoYW5uZWxEYXRhKDApLCBjYXB0dXJlQ3R4LnNhbXBsZVJhdGUpO1xuICAgICAgICAgIHdzLnNlbmQocGNtKTtcbiAgICAgICAgfTtcbiAgICAgICAgc291cmNlLmNvbm5lY3QocHJvY2Vzc29yKTtcbiAgICAgICAgcHJvY2Vzc29yLmNvbm5lY3QoY2FwdHVyZUN0eC5kZXN0aW5hdGlvbik7IC8vIHJlcXVpcmVkIHRvIGRyaXZlIG9uYXVkaW9wcm9jZXNzXG4gICAgICAgIHNldElzQWN0aXZlKHRydWUpO1xuICAgICAgICBzZXRTdGF0dXMoJ2xpc3RlbmluZycpO1xuICAgICAgfTtcblxuICAgICAgd3Mub25tZXNzYWdlID0gKGV2ZW50OiBNZXNzYWdlRXZlbnQpID0+IHtcbiAgICAgICAgaWYgKGV2ZW50LmRhdGEgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikge1xuICAgICAgICAgIHBsYXlQY21DaHVuayhldmVudC5kYXRhKTtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgZXZlbnQuZGF0YSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgaGFuZGxlRXZlbnQoSlNPTi5wYXJzZShldmVudC5kYXRhKSk7XG4gICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAvKiBpZ25vcmUgbWFsZm9ybWVkIGV2ZW50ICovXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICB3cy5vbmVycm9yID0gKCkgPT4ge1xuICAgICAgICBjYi5vbkVycm9yPy4obmV3IEVycm9yKCdMaXZlIHZvaWNlIGNvbm5lY3Rpb24gZXJyb3InKSk7XG4gICAgICB9O1xuXG4gICAgICB3cy5vbmNsb3NlID0gKCkgPT4ge1xuICAgICAgICBzdG9wKCk7XG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY2Iub25FcnJvcj8uKGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyIDogbmV3IEVycm9yKFN0cmluZyhlcnIpKSk7XG4gICAgICBzdG9wKCk7XG4gICAgfVxuICB9LCBbaGFuZGxlRXZlbnQsIHBsYXlQY21DaHVuaywgc3RvcF0pO1xuXG4gIC8vIFRlYXIgZG93biBvbiB1bm1vdW50LlxuICB1c2VFZmZlY3QoKCkgPT4gKCkgPT4gc3RvcCgpLCBbc3RvcF0pO1xuXG4gIHJldHVybiB7IGlzQWN0aXZlLCBzdGF0dXMsIHN0YXJ0LCBzdG9wIH07XG59XG4iXX0=
@@ -1,4 +1,4 @@
1
- import { ChatMessage, AgentInfoResponse, AgentChatLocalesResponse, Attachment, AgentThinkingConfig, AgentWelcomeData, FileUploadResponse, InProgressPollMessage } from "../types";
1
+ import { ChatMessage, AgentInfoResponse, AgentChatLocalesResponse, FormNodeLocale, Attachment, AgentThinkingConfig, AgentWelcomeData, FileUploadResponse, InProgressPollMessage } from "../types";
2
2
  export declare const GENASSIST_AGENT_METADATA_UPDATED = "genassist_agent_metadata_updated";
3
3
  export declare class ChatService {
4
4
  private baseUrl;
@@ -20,6 +20,7 @@ export declare class ChatService {
20
20
  private welcomeData;
21
21
  private thinkingConfig;
22
22
  private chatInputMetadata;
23
+ private triggerStartForm;
23
24
  private welcomeObjectUrl;
24
25
  private tenant;
25
26
  private agentId;
@@ -75,6 +76,11 @@ export declare class ChatService {
75
76
  * Used to show workflow-defined metadata in the config panel.
76
77
  */
77
78
  getChatInputMetadata(): Record<string, unknown>;
79
+ /**
80
+ * Whether the widget should auto-run the workflow as the conversation opens to surface
81
+ * a Human In The Loop form wired directly after Start (its "show_on_start" is enabled).
82
+ */
83
+ shouldTriggerStartForm(): boolean;
78
84
  /**
79
85
  * Supported languages for the current agent (if provided by the server).
80
86
  */
@@ -96,6 +102,8 @@ export declare class ChatService {
96
102
  thinkingPhrases: string[];
97
103
  thinkingDelayMs: number;
98
104
  } | null;
105
+ /** HITL form strings from the locale bundle, as `{ lang: { nodeId: slice } }`. */
106
+ getFormNodeLocales(): Record<string, Record<string, FormNodeLocale>>;
99
107
  /**
100
108
  * Load a saved conversation ID from localStorage
101
109
  */
@@ -125,7 +133,16 @@ export declare class ChatService {
125
133
  getConversationCreateTime(): number | null;
126
134
  isConversationFinalized(): boolean;
127
135
  startConversation(reCaptchaToken?: string | undefined): Promise<string>;
128
- sendMessage(message: string, attachments?: Attachment[], extraMetadata?: Record<string, any>, reCaptchaToken?: string): Promise<void>;
136
+ sendMessage(message: string, attachments?: Attachment[], extraMetadata?: Record<string, any>, reCaptchaToken?: string, opts?: {
137
+ silent?: boolean;
138
+ }): Promise<void>;
139
+ /**
140
+ * Run the workflow as the conversation opens to surface a Human In The Loop form wired
141
+ * directly after Start (its "show_on_start" is enabled). Sends an empty, invisible
142
+ * trigger message flagged so the backend runs the workflow but neither shows nor stores
143
+ * it — only the resulting form comes back through the normal response/WS path.
144
+ */
145
+ sendStartFormTrigger(reCaptchaToken?: string): Promise<void>;
129
146
  sendAudioMessage(audioBlob: Blob, audioFormat: string, extraMetadata?: Record<string, any>): Promise<void>;
130
147
  uploadFile(chatId: string, file: File): Promise<FileUploadResponse | null>;
131
148
  /**