ttp-agent-sdk 2.46.2 → 2.47.2
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/agent-widget.dev.js
CHANGED
|
@@ -9644,6 +9644,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
9644
9644
|
"use strict";
|
|
9645
9645
|
__webpack_require__.r(__webpack_exports__);
|
|
9646
9646
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
9647
|
+
/* harmony export */ buildAudioConstraints: () => (/* binding */ buildAudioConstraints),
|
|
9647
9648
|
/* harmony export */ "default": () => (/* binding */ AudioRecorder)
|
|
9648
9649
|
/* harmony export */ });
|
|
9649
9650
|
/* harmony import */ var _EventEmitter_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./EventEmitter.js */ "./src/core/EventEmitter.js");
|
|
@@ -11993,7 +11994,7 @@ var TextChatSDK = /*#__PURE__*/function (_EventEmitter) {
|
|
|
11993
11994
|
|
|
11994
11995
|
// SDK build time for debugging
|
|
11995
11996
|
if (true) {
|
|
11996
|
-
helloMessage.lastBuildTime = "2026-07-
|
|
11997
|
+
helloMessage.lastBuildTime = "2026-07-30T20:53:20.013Z";
|
|
11997
11998
|
}
|
|
11998
11999
|
try {
|
|
11999
12000
|
this.ws.send(JSON.stringify(helloMessage));
|
|
@@ -15310,7 +15311,8 @@ var MobileProductCarousel = /*#__PURE__*/function () {
|
|
|
15310
15311
|
__webpack_require__.r(__webpack_exports__);
|
|
15311
15312
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
15312
15313
|
/* harmony export */ PartnerScriptRunner: () => (/* binding */ PartnerScriptRunner),
|
|
15313
|
-
/* harmony export */ buildRunPartnerScriptTool: () => (/* binding */ buildRunPartnerScriptTool)
|
|
15314
|
+
/* harmony export */ buildRunPartnerScriptTool: () => (/* binding */ buildRunPartnerScriptTool),
|
|
15315
|
+
/* harmony export */ compileAdapter: () => (/* binding */ compileAdapter)
|
|
15314
15316
|
/* harmony export */ });
|
|
15315
15317
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
15316
15318
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -15476,19 +15478,62 @@ var AsyncFunction = Object.getPrototypeOf(/*#__PURE__*/_asyncToGenerator(/*#__PU
|
|
|
15476
15478
|
// back to compiling the code as a plain body. AsyncFunction (not
|
|
15477
15479
|
// `new Function`) enforces an async execution context — no accidental sync
|
|
15478
15480
|
// adapter bodies.
|
|
15481
|
+
//
|
|
15482
|
+
// Detection runs against the code with leading comments removed. Adapters are
|
|
15483
|
+
// routinely authored with a header comment block above the function, and a
|
|
15484
|
+
// header-prefixed function expression that falls through to body compilation
|
|
15485
|
+
// is a *silent* no-op: `// h\nasync (ctx) => {...}` is a syntactically valid
|
|
15486
|
+
// statement body that merely constructs the arrow and discards it, so the
|
|
15487
|
+
// adapter compiles, "succeeds", and returns undefined without ever running.
|
|
15479
15488
|
var FN_EXPR_RE = /^\s*(async[\s(])|^\s*function\b|^\s*\(|^\s*[A-Za-z_$][\w$]*\s*=>/;
|
|
15489
|
+
|
|
15490
|
+
// Drop leading whitespace and `//` / `/* */` comments. Detection-only — the
|
|
15491
|
+
// original source is always what gets compiled, so comments (and the line
|
|
15492
|
+
// numbers they occupy in stack traces) are preserved.
|
|
15493
|
+
function stripLeadingComments(code) {
|
|
15494
|
+
var i = 0;
|
|
15495
|
+
for (;;) {
|
|
15496
|
+
while (i < code.length && /\s/.test(code[i])) i++;
|
|
15497
|
+
if (code.startsWith('//', i)) {
|
|
15498
|
+
var nl = code.indexOf('\n', i);
|
|
15499
|
+
if (nl === -1) return '';
|
|
15500
|
+
i = nl + 1;
|
|
15501
|
+
} else if (code.startsWith('/*', i)) {
|
|
15502
|
+
var end = code.indexOf('*/', i + 2);
|
|
15503
|
+
if (end === -1) return '';
|
|
15504
|
+
i = end + 2;
|
|
15505
|
+
} else {
|
|
15506
|
+
return code.slice(i);
|
|
15507
|
+
}
|
|
15508
|
+
}
|
|
15509
|
+
}
|
|
15510
|
+
|
|
15511
|
+
/**
|
|
15512
|
+
* Exported so the offline adapter verifier (`scripts/verify-adapter.mjs`) can
|
|
15513
|
+
* gate authored scripts through the exact compiler the SDK uses at runtime,
|
|
15514
|
+
* rather than a copy that can drift out of sync with it.
|
|
15515
|
+
* @returns {{fn: Function, style: 'expression'|'body'}}
|
|
15516
|
+
*/
|
|
15480
15517
|
function compileAdapter(codeJs) {
|
|
15481
|
-
if (FN_EXPR_RE.test(codeJs)) {
|
|
15518
|
+
if (FN_EXPR_RE.test(stripLeadingComments(codeJs))) {
|
|
15482
15519
|
try {
|
|
15520
|
+
// Newline before `)` so a trailing `//` comment can't swallow it.
|
|
15483
15521
|
// eslint-disable-next-line no-new-func
|
|
15484
|
-
|
|
15522
|
+
var fn = new AsyncFunction('ctx', "\"use strict\"; return (".concat(codeJs, "\n).call(null, ctx);"));
|
|
15523
|
+
return {
|
|
15524
|
+
fn: fn,
|
|
15525
|
+
style: 'expression'
|
|
15526
|
+
};
|
|
15485
15527
|
} catch (e) {
|
|
15486
15528
|
// Looked like an expression but doesn't parse as one (e.g. an
|
|
15487
15529
|
// IIFE-opening statement body) — fall through to body compilation.
|
|
15488
15530
|
}
|
|
15489
15531
|
}
|
|
15490
15532
|
// eslint-disable-next-line no-new-func
|
|
15491
|
-
return
|
|
15533
|
+
return {
|
|
15534
|
+
fn: new AsyncFunction('ctx', "\"use strict\"; ".concat(codeJs)),
|
|
15535
|
+
style: 'body'
|
|
15536
|
+
};
|
|
15492
15537
|
}
|
|
15493
15538
|
|
|
15494
15539
|
// Cheap 32-bit string hash, rendered as 12 hex chars. NOT cryptographic —
|
|
@@ -15607,7 +15652,7 @@ var PartnerScriptRunner = /*#__PURE__*/function () {
|
|
|
15607
15652
|
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
15608
15653
|
_classCallCheck(this, PartnerScriptRunner);
|
|
15609
15654
|
this.genericCtx = !!(opts && opts.genericCtx);
|
|
15610
|
-
/** @type {Map<string, {fn?: Function, version?: number, codeSha256?: string, meta?: object, category?: string|null, beforeActions?: string[], afterActions?: string[], poisoned?: boolean, error?: string}>} */
|
|
15655
|
+
/** @type {Map<string, {fn?: Function, style?: 'expression'|'body', version?: number, codeSha256?: string, meta?: object, category?: string|null, beforeActions?: string[], afterActions?: string[], poisoned?: boolean, error?: string}>} */
|
|
15611
15656
|
this.adapters = new Map();
|
|
15612
15657
|
this.partnerId = null;
|
|
15613
15658
|
this.platform = null;
|
|
@@ -15658,14 +15703,17 @@ var PartnerScriptRunner = /*#__PURE__*/function () {
|
|
|
15658
15703
|
}
|
|
15659
15704
|
try {
|
|
15660
15705
|
var _entry$version2, _entry$category;
|
|
15661
|
-
var
|
|
15706
|
+
var _compileAdapter = compileAdapter(entry.code_js),
|
|
15707
|
+
fn = _compileAdapter.fn,
|
|
15708
|
+
style = _compileAdapter.style;
|
|
15662
15709
|
// Inline pre/post hooks (optional). Compiled with the same
|
|
15663
15710
|
// AsyncFunction strict-mode wrapper as the main body so a syntax
|
|
15664
15711
|
// error in a hook poisons only this entry (caught below).
|
|
15665
|
-
var preFn = typeof entry.pre_code_js === 'string' ? compileAdapter(entry.pre_code_js) : null;
|
|
15666
|
-
var postFn = typeof entry.post_code_js === 'string' ? compileAdapter(entry.post_code_js) : null;
|
|
15712
|
+
var preFn = typeof entry.pre_code_js === 'string' ? compileAdapter(entry.pre_code_js).fn : null;
|
|
15713
|
+
var postFn = typeof entry.post_code_js === 'string' ? compileAdapter(entry.post_code_js).fn : null;
|
|
15667
15714
|
this.adapters.set(action, {
|
|
15668
15715
|
fn: fn,
|
|
15716
|
+
style: style,
|
|
15669
15717
|
preFn: preFn,
|
|
15670
15718
|
postFn: postFn,
|
|
15671
15719
|
version: (_entry$version2 = entry.version) !== null && _entry$version2 !== void 0 ? _entry$version2 : null,
|
|
@@ -15932,7 +15980,7 @@ var PartnerScriptRunner = /*#__PURE__*/function () {
|
|
|
15932
15980
|
}
|
|
15933
15981
|
}
|
|
15934
15982
|
ctx = this._buildCtx(args, action, entry);
|
|
15935
|
-
console.log("".concat(LOG, " exec ").concat(action, " v").concat((_entry$version4 = entry.version) !== null && _entry$version4 !== void 0 ? _entry$version4 : '?', " ") + "sha=".concat((entry.codeSha256 || '').slice(0, 12)));
|
|
15983
|
+
console.log("".concat(LOG, " exec ").concat(action, " v").concat((_entry$version4 = entry.version) !== null && _entry$version4 !== void 0 ? _entry$version4 : '?', " ") + "sha=".concat((entry.codeSha256 || '').slice(0, 12), " as=").concat(entry.style || '?'));
|
|
15936
15984
|
|
|
15937
15985
|
// Inline pre-hook (best-effort): an error is logged and main still runs.
|
|
15938
15986
|
if (!entry.preFn) {
|
|
@@ -21205,8 +21253,8 @@ var VoiceSDK = _v2_VoiceSDK_js__WEBPACK_IMPORTED_MODULE_0__["default"];
|
|
|
21205
21253
|
|
|
21206
21254
|
|
|
21207
21255
|
// Version - injected at build time from package.json via webpack DefinePlugin
|
|
21208
|
-
var VERSION = "2.
|
|
21209
|
-
var BUILD_TIME = "2026-07-
|
|
21256
|
+
var VERSION = "2.47.2";
|
|
21257
|
+
var BUILD_TIME = "2026-07-30T20:53:20.013Z";
|
|
21210
21258
|
console.log("%c TTP Agent SDK v".concat(VERSION, " (").concat(BUILD_TIME, ") "), 'background: #4f46e5; color: white; font-size: 12px; font-weight: bold; padding: 2px 6px; border-radius: 4px;');
|
|
21211
21259
|
|
|
21212
21260
|
// Named exports
|
|
@@ -27491,6 +27539,28 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27491
27539
|
* Mark that a new sentence is starting.
|
|
27492
27540
|
* Call this when audio_start is received, before audio chunks arrive.
|
|
27493
27541
|
*/
|
|
27542
|
+
/**
|
|
27543
|
+
* Clear the stopped flag and reset scheduling state WITHOUT a new sentence marker.
|
|
27544
|
+
* Monitor (listen-only supervision) streams have no audio_start messages, so after a
|
|
27545
|
+
* relayed stop_playing flush nothing would ever clear _isStopped and all later audio
|
|
27546
|
+
* would be rejected. The SDK calls this when the next binary frame arrives — WS
|
|
27547
|
+
* ordering guarantees it is live post-barge-in audio.
|
|
27548
|
+
*/
|
|
27549
|
+
}, {
|
|
27550
|
+
key: "resumeAfterStop",
|
|
27551
|
+
value: function resumeAfterStop() {
|
|
27552
|
+
if (!this._isStopped) {
|
|
27553
|
+
return;
|
|
27554
|
+
}
|
|
27555
|
+
console.log('▶️ AudioPlayer: resumeAfterStop - clearing stopped flag (no sentence marker)');
|
|
27556
|
+
this._isStopped = false;
|
|
27557
|
+
// Same reset as markNewSentence's post-barge-in branch: schedule fresh, drop leftovers.
|
|
27558
|
+
this.nextStartTime = 0;
|
|
27559
|
+
this.scheduledBuffers = 0;
|
|
27560
|
+
this.preparedBuffer = [];
|
|
27561
|
+
this.pcmChunkQueue = [];
|
|
27562
|
+
this.isProcessingPcmQueue = false;
|
|
27563
|
+
}
|
|
27494
27564
|
}, {
|
|
27495
27565
|
key: "markNewSentence",
|
|
27496
27566
|
value: function markNewSentence(text, synced, segmentId) {
|
|
@@ -28514,6 +28584,8 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28514
28584
|
// The backend analyzes the audio stream and detects when user interrupts
|
|
28515
28585
|
// Frontend only responds to backend 'barge_in' messages (handled in handleMessage())
|
|
28516
28586
|
|
|
28587
|
+
// Report the capture track's real settings (AEC ground truth) to the backend
|
|
28588
|
+
_this4._sendClientAudioInfo();
|
|
28517
28589
|
_this4.emit('recordingStarted');
|
|
28518
28590
|
});
|
|
28519
28591
|
this.audioRecorder.on('recordingStopped', function () {
|
|
@@ -28787,6 +28859,83 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28787
28859
|
fullLocale: fullLocale
|
|
28788
28860
|
};
|
|
28789
28861
|
}
|
|
28862
|
+
|
|
28863
|
+
/**
|
|
28864
|
+
* Client environment snapshot sent in hello (`client` field). Static facts known
|
|
28865
|
+
* before the mic opens — device/browser identification for backend logs + Langfuse
|
|
28866
|
+
* trace metadata. Audio-track ground truth (AEC etc.) is sent separately via
|
|
28867
|
+
* client_audio_info once recording starts, because track settings don't exist yet.
|
|
28868
|
+
*/
|
|
28869
|
+
}, {
|
|
28870
|
+
key: "_buildClientEnv",
|
|
28871
|
+
value: function _buildClientEnv() {
|
|
28872
|
+
try {
|
|
28873
|
+
var _uaData$mobile, _window$screen, _window$screen2;
|
|
28874
|
+
var ua = navigator.userAgent || '';
|
|
28875
|
+
var uaData = navigator.userAgentData;
|
|
28876
|
+
var conn = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
|
|
28877
|
+
var isAndroid = /Android/i.test(ua);
|
|
28878
|
+
var isIos = /iPhone|iPad|iPod/i.test(ua) || ua.includes('Mac') && 'ontouchend' in document;
|
|
28879
|
+
// Webview heuristic: Android WebView marks itself with "; wv)" or "Version/x.x Chrome";
|
|
28880
|
+
// iOS in-app webviews lack "Safari" in the UA (real Safari always has it).
|
|
28881
|
+
var webview = isAndroid && (/\bwv\b/.test(ua) || /Version\/[\d.]+.*Chrome/.test(ua)) || isIos && !/Safari/i.test(ua) || false;
|
|
28882
|
+
var env = {
|
|
28883
|
+
sdkVersion: true ? "2.47.2" : 0,
|
|
28884
|
+
ua: ua,
|
|
28885
|
+
platform: (uaData === null || uaData === void 0 ? void 0 : uaData.platform) || navigator.platform || '',
|
|
28886
|
+
mobile: (_uaData$mobile = uaData === null || uaData === void 0 ? void 0 : uaData.mobile) !== null && _uaData$mobile !== void 0 ? _uaData$mobile : isAndroid || isIos,
|
|
28887
|
+
os: isIos ? 'ios' : isAndroid ? 'android' : 'other',
|
|
28888
|
+
webview: webview,
|
|
28889
|
+
screen: "".concat(((_window$screen = window.screen) === null || _window$screen === void 0 ? void 0 : _window$screen.width) || 0, "x").concat(((_window$screen2 = window.screen) === null || _window$screen2 === void 0 ? void 0 : _window$screen2.height) || 0, "@").concat(window.devicePixelRatio || 1),
|
|
28890
|
+
cores: navigator.hardwareConcurrency || null,
|
|
28891
|
+
memoryGb: navigator.deviceMemory || null,
|
|
28892
|
+
connection: (conn === null || conn === void 0 ? void 0 : conn.effectiveType) || null
|
|
28893
|
+
};
|
|
28894
|
+
return env;
|
|
28895
|
+
} catch (e) {
|
|
28896
|
+
console.warn('⚠️ VoiceSDK v2: Failed to build client env:', e);
|
|
28897
|
+
return {
|
|
28898
|
+
sdkVersion: true ? "2.47.2" : 0
|
|
28899
|
+
};
|
|
28900
|
+
}
|
|
28901
|
+
}
|
|
28902
|
+
|
|
28903
|
+
/**
|
|
28904
|
+
* One-shot telemetry sent right after recording starts (t:'client_audio_info').
|
|
28905
|
+
* Reports the capture track's ACTUAL settings from getSettings() — echoCancellation /
|
|
28906
|
+
* noiseSuppression / autoGainControl as the browser really applied them (not what we
|
|
28907
|
+
* requested), which is the ground truth for diagnosing speakerphone echo barge-in —
|
|
28908
|
+
* plus mic label, AudioContext rates, and whether the minimal-constraints fallback fired.
|
|
28909
|
+
*/
|
|
28910
|
+
}, {
|
|
28911
|
+
key: "_sendClientAudioInfo",
|
|
28912
|
+
value: function _sendClientAudioInfo() {
|
|
28913
|
+
try {
|
|
28914
|
+
var _this$audioRecorder, _this$audioRecorder$g, _s$echoCancellation, _s$noiseSuppression, _s$autoGainControl, _s$voiceIsolation, _s$sampleRate, _s$channelCount, _this$audioRecorder2, _this$audioPlayer, _this$audioRecorder3;
|
|
28915
|
+
var track = (_this$audioRecorder = this.audioRecorder) === null || _this$audioRecorder === void 0 || (_this$audioRecorder = _this$audioRecorder.mediaStream) === null || _this$audioRecorder === void 0 || (_this$audioRecorder$g = _this$audioRecorder.getAudioTracks) === null || _this$audioRecorder$g === void 0 ? void 0 : _this$audioRecorder$g.call(_this$audioRecorder)[0];
|
|
28916
|
+
if (!track) return;
|
|
28917
|
+
var s = track.getSettings ? track.getSettings() : {};
|
|
28918
|
+
var audio = {
|
|
28919
|
+
aec: (_s$echoCancellation = s.echoCancellation) !== null && _s$echoCancellation !== void 0 ? _s$echoCancellation : null,
|
|
28920
|
+
ns: (_s$noiseSuppression = s.noiseSuppression) !== null && _s$noiseSuppression !== void 0 ? _s$noiseSuppression : null,
|
|
28921
|
+
agc: (_s$autoGainControl = s.autoGainControl) !== null && _s$autoGainControl !== void 0 ? _s$autoGainControl : null,
|
|
28922
|
+
voiceIsolation: (_s$voiceIsolation = s.voiceIsolation) !== null && _s$voiceIsolation !== void 0 ? _s$voiceIsolation : null,
|
|
28923
|
+
trackRate: (_s$sampleRate = s.sampleRate) !== null && _s$sampleRate !== void 0 ? _s$sampleRate : null,
|
|
28924
|
+
channels: (_s$channelCount = s.channelCount) !== null && _s$channelCount !== void 0 ? _s$channelCount : null,
|
|
28925
|
+
mic: track.label || null,
|
|
28926
|
+
captureCtxRate: ((_this$audioRecorder2 = this.audioRecorder) === null || _this$audioRecorder2 === void 0 || (_this$audioRecorder2 = _this$audioRecorder2.audioContext) === null || _this$audioRecorder2 === void 0 ? void 0 : _this$audioRecorder2.sampleRate) || null,
|
|
28927
|
+
playbackCtxRate: ((_this$audioPlayer = this.audioPlayer) === null || _this$audioPlayer === void 0 || (_this$audioPlayer = _this$audioPlayer.audioContext) === null || _this$audioPlayer === void 0 ? void 0 : _this$audioPlayer.sampleRate) || null,
|
|
28928
|
+
constraintsFallback: ((_this$audioRecorder3 = this.audioRecorder) === null || _this$audioRecorder3 === void 0 || (_this$audioRecorder3 = _this$audioRecorder3.mediaStream) === null || _this$audioRecorder3 === void 0 ? void 0 : _this$audioRecorder3._ttpConstraintsFallback) === true
|
|
28929
|
+
};
|
|
28930
|
+
this.sendMessage({
|
|
28931
|
+
t: 'client_audio_info',
|
|
28932
|
+
audio: audio
|
|
28933
|
+
});
|
|
28934
|
+
console.log('🎛️ VoiceSDK v2: Sent client_audio_info:', audio);
|
|
28935
|
+
} catch (e) {
|
|
28936
|
+
console.warn('⚠️ VoiceSDK v2: Failed to send client_audio_info:', e);
|
|
28937
|
+
}
|
|
28938
|
+
}
|
|
28790
28939
|
}, {
|
|
28791
28940
|
key: "sendHelloMessage",
|
|
28792
28941
|
value: function () {
|
|
@@ -28887,9 +29036,12 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28887
29036
|
|
|
28888
29037
|
// Include SDK build time for debugging
|
|
28889
29038
|
if (true) {
|
|
28890
|
-
helloMessage.lastBuildTime = "2026-07-
|
|
29039
|
+
helloMessage.lastBuildTime = "2026-07-30T20:53:20.013Z";
|
|
28891
29040
|
}
|
|
28892
29041
|
|
|
29042
|
+
// Client environment (device/browser/webview) for backend logs + Langfuse metadata
|
|
29043
|
+
helloMessage.client = this._buildClientEnv();
|
|
29044
|
+
|
|
28893
29045
|
// Page context is intentionally NOT attached to the hello message.
|
|
28894
29046
|
// The backend caches the system prompt across turns (Anthropic prompt
|
|
28895
29047
|
// caching), so anything that varies per-page would invalidate the
|
|
@@ -29026,15 +29178,21 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29026
29178
|
this.stopAudioPlayback();
|
|
29027
29179
|
break;
|
|
29028
29180
|
case 'stop_playing':
|
|
29029
|
-
//
|
|
29030
|
-
//
|
|
29031
|
-
//
|
|
29032
|
-
|
|
29033
|
-
|
|
29034
|
-
|
|
29035
|
-
if (
|
|
29036
|
-
|
|
29037
|
-
|
|
29181
|
+
// An id-bearing stop is a deliberate barge-in flush and is honored UNCONDITIONALLY:
|
|
29182
|
+
// the WebSocket delivers messages in order, so every segment queued locally was sent
|
|
29183
|
+
// BEFORE this stop and is covered by it. The old 200ms-after-audio_start heuristic
|
|
29184
|
+
// silently swallowed barge-in during long multi-sentence replies (an audio_start
|
|
29185
|
+
// arrives every few hundred ms, so the quiet window never opened) — it is kept ONLY
|
|
29186
|
+
// for legacy backends whose stop carries no segmentId.
|
|
29187
|
+
if (message.segmentId == null) {
|
|
29188
|
+
var timeSinceAudioStart = Date.now() - this.lastAudioStartTime;
|
|
29189
|
+
var MIN_STOP_PLAYING_DELAY_MS = 200; // legacy grace period after audio_start
|
|
29190
|
+
if (timeSinceAudioStart < MIN_STOP_PLAYING_DELAY_MS) {
|
|
29191
|
+
console.warn("\u26A0\uFE0F VoiceSDK v2: Ignoring premature legacy stop_playing (".concat(timeSinceAudioStart, "ms after audio_start, minimum ").concat(MIN_STOP_PLAYING_DELAY_MS, "ms required)"));
|
|
29192
|
+
break;
|
|
29193
|
+
}
|
|
29194
|
+
} else {
|
|
29195
|
+
console.log("\uD83D\uDED1 VoiceSDK v2: Barge-in stop_playing (through segmentId ".concat(message.segmentId, ") - flushing playback"));
|
|
29038
29196
|
}
|
|
29039
29197
|
this.emit('stopPlaying', message);
|
|
29040
29198
|
this.stopAudioPlayback();
|
|
@@ -30111,6 +30269,15 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
30111
30269
|
return _regenerator().w(function (_context7) {
|
|
30112
30270
|
while (1) switch (_context7.p = _context7.n) {
|
|
30113
30271
|
case 0:
|
|
30272
|
+
// Monitor (listen-only supervision): no audio_start messages exist to clear the
|
|
30273
|
+
// player's stopped flag after a relayed stop_playing (caller barge-in flush), so
|
|
30274
|
+
// resume on the next binary frame — the server emits in order, so anything after
|
|
30275
|
+
// the stop marker is live post-barge-in audio.
|
|
30276
|
+
if (this.isMonitor() && this.audioPlayer && this.audioPlayer._isStopped) {
|
|
30277
|
+
this.audioPlayer.resumeAfterStop();
|
|
30278
|
+
}
|
|
30279
|
+
|
|
30280
|
+
// Convert Blob to ArrayBuffer if needed
|
|
30114
30281
|
if (!(data instanceof Blob)) {
|
|
30115
30282
|
_context7.n = 2;
|
|
30116
30283
|
break;
|
|
@@ -30353,7 +30520,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
30353
30520
|
}, {
|
|
30354
30521
|
key: "pauseCall",
|
|
30355
30522
|
value: function pauseCall() {
|
|
30356
|
-
var _this$
|
|
30523
|
+
var _this$audioRecorder4;
|
|
30357
30524
|
if (this.isPaused) return;
|
|
30358
30525
|
this.sendMessage({
|
|
30359
30526
|
t: 'pause_call'
|
|
@@ -30363,7 +30530,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
30363
30530
|
this.audioRecorder.stop();
|
|
30364
30531
|
}
|
|
30365
30532
|
// Flush AudioWorklet ring buffer
|
|
30366
|
-
if ((_this$
|
|
30533
|
+
if ((_this$audioRecorder4 = this.audioRecorder) !== null && _this$audioRecorder4 !== void 0 && _this$audioRecorder4.audioWorkletNode) {
|
|
30367
30534
|
this.audioRecorder.audioWorkletNode.port.postMessage({
|
|
30368
30535
|
type: 'flush'
|
|
30369
30536
|
});
|
|
@@ -34914,7 +35081,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34914
35081
|
return;
|
|
34915
35082
|
}
|
|
34916
35083
|
this._ensureAboutStyles();
|
|
34917
|
-
var version = true ? "2.
|
|
35084
|
+
var version = true ? "2.47.2" : 0;
|
|
34918
35085
|
var convId = this._getLastConversationId();
|
|
34919
35086
|
var t = function t(k, fb) {
|
|
34920
35087
|
try {
|
|
@@ -37285,6 +37452,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
37285
37452
|
/* harmony export */ TextInterface: () => (/* binding */ TextInterface)
|
|
37286
37453
|
/* harmony export */ });
|
|
37287
37454
|
/* harmony import */ var _galleryHandler_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./galleryHandler.js */ "./src/widget/galleryHandler.js");
|
|
37455
|
+
/* harmony import */ var _markdown_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./markdown.js */ "./src/widget/markdown.js");
|
|
37288
37456
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
37289
37457
|
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n2 = 0, F = function F() {}; return { s: F, n: function n() { return _n2 >= r.length ? { done: !0 } : { done: !1, value: r[_n2++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
37290
37458
|
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
@@ -37304,6 +37472,7 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
|
|
|
37304
37472
|
*/
|
|
37305
37473
|
|
|
37306
37474
|
|
|
37475
|
+
|
|
37307
37476
|
function panelSolidBackground(panel) {
|
|
37308
37477
|
var bg = panel === null || panel === void 0 ? void 0 : panel.backgroundColor;
|
|
37309
37478
|
if (typeof bg !== 'string' || !bg.startsWith('#')) return '#FFFFFF';
|
|
@@ -37345,6 +37514,9 @@ function rgbTupleFromChromeColor(color, fallbackTuple) {
|
|
|
37345
37514
|
var TEXT_INPUT_MIN_HEIGHT_PX = 36;
|
|
37346
37515
|
var TEXT_INPUT_MAX_HEIGHT_PX = 132;
|
|
37347
37516
|
|
|
37517
|
+
/** How often a streaming agent bubble is re-rendered from its markdown buffer (ms). */
|
|
37518
|
+
var STREAM_RENDER_INTERVAL_MS = 40;
|
|
37519
|
+
|
|
37348
37520
|
/** Resolves voice primary / gradient strings to #rrggbb for CSS hex+alpha suffixes. */
|
|
37349
37521
|
function firstHexFromVoiceColor(c, fallback) {
|
|
37350
37522
|
if (c == null || typeof c !== 'string') return fallback;
|
|
@@ -37529,9 +37701,21 @@ var TextInterface = /*#__PURE__*/function () {
|
|
|
37529
37701
|
}
|
|
37530
37702
|
var accentRgb = rgbTupleFromChromeColor(sendButtonColor);
|
|
37531
37703
|
|
|
37704
|
+
// Markdown tokens for the agent bubble. Derived from the two themes so the
|
|
37705
|
+
// rendered structure (code, tables, rules) reads correctly on both.
|
|
37706
|
+
var mdOnDark = useVoiceTheme || !panelLight;
|
|
37707
|
+
var mdSubtleBg = mdOnDark ? 'rgba(255,255,255,0.10)' : 'rgba(15,23,42,0.045)';
|
|
37708
|
+
var mdSubtlerBg = mdOnDark ? 'rgba(255,255,255,0.05)' : 'rgba(15,23,42,0.022)';
|
|
37709
|
+
var mdBorder = mdOnDark ? 'rgba(255,255,255,0.20)' : 'rgba(15,23,42,0.10)';
|
|
37710
|
+
var mdRule = mdOnDark ? 'rgba(255,255,255,0.16)' : 'rgba(15,23,42,0.08)';
|
|
37711
|
+
var mdMuted = mdOnDark ? 'rgba(255,255,255,0.62)' : 'rgba(15,23,42,0.55)';
|
|
37712
|
+
var mdLink = mdOnDark ? '#c7d2fe' : sendButtonColor;
|
|
37713
|
+
var mdAccent = mdOnDark ? 'rgba(255,255,255,0.45)' : "rgba(".concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", 0.55)");
|
|
37714
|
+
var mdMono = "ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace";
|
|
37715
|
+
|
|
37532
37716
|
// Add !important to display rules when not using Shadow DOM (to override theme CSS)
|
|
37533
37717
|
var important = this.config.useShadowDOM === false ? ' !important' : '';
|
|
37534
|
-
return "\n .text-interface-top-bar {\n flex-shrink: 0".concat(important, ";\n padding: 10px 12px 8px").concat(important, ";\n border-bottom: 1px solid ").concat(topBarBorder).concat(important, ";\n background: ").concat(topBarBg).concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: space-between").concat(important, ";\n }\n .text-interface-top-bar .ttp-info-btn {\n color: ").concat(backBtnColor).concat(important, ";\n }\n .text-interface-top-bar .ttp-info-btn:hover {\n background: ").concat(backBtnHoverBg).concat(important, ";\n color: ").concat(backBtnHoverColor).concat(important, ";\n }\n .text-interface-back-btn {\n display: inline-flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 6px").concat(important, ";\n padding: 6px 10px").concat(important, ";\n margin: 0").concat(important, ";\n border: none").concat(important, ";\n border-radius: 8px").concat(important, ";\n background: transparent").concat(important, ";\n color: ").concat(backBtnColor).concat(important, ";\n font-size: 16px").concat(important, ";\n font-weight: 600").concat(important, ";\n cursor: pointer").concat(important, ";\n font-family: inherit").concat(important, ";\n }\n .text-interface-back-btn:hover {\n background: ").concat(backBtnHoverBg).concat(important, ";\n color: ").concat(backBtnHoverColor).concat(important, ";\n }\n .text-interface-back-icon {\n font-size: 18px").concat(important, ";\n line-height: 1").concat(important, ";\n }\n .text-interface-back-label {\n line-height: 1.2").concat(important, ";\n }\n /* Messages container using new classes */\n #messagesContainer { \n flex: 1").concat(important, "; \n overflow-y: auto").concat(important, "; \n overflow-x: hidden").concat(important, "; \n padding: 20px").concat(important, "; \n background: ").concat(messagesAreaBg).concat(important, "; \n display: flex").concat(important, "; \n flex-direction: column").concat(important, "; \n gap: 16px").concat(important, "; \n min-height: 0").concat(important, "; \n }\n .empty-state { \n flex: 1").concat(important, "; \n display: flex").concat(important, "; \n flex-direction: column").concat(important, "; \n align-items: center").concat(important, "; \n justify-content: center").concat(important, "; \n gap: 12px").concat(important, "; \n color: ").concat(emptyMuted).concat(important, "; \n text-align: center").concat(important, "; \n padding: 20px").concat(important, "; \n }\n .empty-state-icon { font-size: 52px").concat(important, "; opacity: 0.3").concat(important, "; }\n .empty-state-title { font-size: 22px").concat(important, "; font-weight: 700").concat(important, "; color: ").concat(emptyTitle).concat(important, "; }\n .empty-state-text { font-size: 15px").concat(important, "; max-width: 300px").concat(important, "; line-height: 1.45").concat(important, "; }\n\n .text-interface { \n display: none").concat(important, "; \n flex: 1").concat(important, "; \n flex-direction: column").concat(important, "; \n min-height: 0").concat(important, "; \n overflow: hidden").concat(important, "; \n }\n .text-interface.active { display: flex").concat(important, "; }\n \n .message { \n display: flex").concat(important, "; \n gap: 8px").concat(important, "; \n padding: 4px 0").concat(important, "; \n max-width: 100%").concat(important, "; \n align-items: center").concat(important, "; \n }\n .message.edge-left { flex-direction: row").concat(important, "; }\n .message.edge-right { flex-direction: row-reverse").concat(important, "; }\n .message-bubble { \n padding: 14px 16px").concat(important, "; \n border-radius: ").concat(messages.borderRadius, "px").concat(important, "; \n max-width: 80%").concat(important, "; \n font-size: ").concat(messages.fontSize).concat(important, "; \n line-height: 1.45").concat(important, ";\n word-wrap: break-word").concat(important, "; \n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left').concat(important, "; \n direction: ").concat(this.config.direction || 'ltr', ";\n }\n .message.user .message-bubble { \n background: ").concat(userBubbleBg).concat(important, "; \n color: ").concat(userBubbleTextColor).concat(important, "; \n }\n .message.agent .message-bubble { \n background: ").concat(agentBubbleBg).concat(important, "; \n color: ").concat(agentBubbleTextColor).concat(important, "; \n border: ").concat(agentBubbleBorder).concat(important, "; \n }\n\n .message.user { \n align-self: ").concat(this.config.direction === 'rtl' ? 'flex-start' : 'flex-end').concat(important, "; \n }\n .message.agent { \n align-self: ").concat(this.config.direction === 'rtl' ? 'flex-end' : 'flex-start').concat(important, "; \n }\n .message .message-bubble { \n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left', " !important; \n }\n ").concat(this.config.direction === 'rtl' ? "\n .message-bubble {\n text-align: right !important;\n }\n " : '', "\n .message-avatar { \n width: ").concat(avatarSize).concat(important, "; \n height: ").concat(avatarSize).concat(important, "; \n min-width: ").concat(avatarSize).concat(important, "; \n border-radius: 50%").concat(important, "; \n display: flex").concat(important, "; \n align-items: center").concat(important, "; \n justify-content: center").concat(important, "; \n flex-shrink: 0").concat(important, "; \n color: inherit").concat(important, "; \n font-size: ").concat(useVoiceTheme ? '14' : '20', "px").concat(important, "; \n line-height: 1").concat(important, "; \n background: transparent").concat(important, "; \n border: none").concat(important, "; \n box-sizing: border-box").concat(important, "; \n }\n .message-avatar.user { background: ").concat(avatarUserBg).concat(important, "; color: ").concat(avatarUserColor).concat(important, "; }\n .message-avatar.agent { background: ").concat(avatarAgentBg).concat(important, "; }\n \n .message.system {\n background: ").concat(messages.systemBackgroundColor, ";\n align-self: flex-start").concat(important, ";\n }\n .message.error {\n background: ").concat(messages.errorBackgroundColor, ";\n align-self: flex-start").concat(important, ";\n }\n \n .input-container {\n display: flex").concat(important, ";\n gap: 8px").concat(important, ";\n padding: 12px 16px").concat(important, ";\n background: ").concat(inputContainerBg).concat(important, ";\n border-top: 1px solid ").concat(inputContainerBorderTop).concat(important, ";\n align-items: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n flex-direction: ").concat(this.config.direction === 'rtl' ? 'row-reverse' : 'row').concat(important, ";\n }\n \n .input-wrapper {\n position: relative").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n }\n \n .message-input {\n width: 100%").concat(important, ";\n min-height: ").concat(TEXT_INPUT_MIN_HEIGHT_PX, "px").concat(important, ";\n max-height: ").concat(TEXT_INPUT_MAX_HEIGHT_PX, "px").concat(important, ";\n padding: ").concat(inputPadding, ";\n border: 1px solid ").concat(inputBorderColor, ";\n border-radius: ").concat(inputBorderRadius, "px;\n font-size: ").concat(inputFontSize, ";\n font-family: inherit").concat(important, ";\n line-height: 1.4").concat(important, ";\n resize: none").concat(important, ";\n overflow-y: auto").concat(important, ";\n background: ").concat(inputBackgroundColor, ";\n color: ").concat(inputTextColor, ";\n vertical-align: top").concat(important, ";\n margin: 0").concat(important, ";\n display: block").concat(important, ";\n white-space: pre-wrap").concat(important, ";\n word-wrap: break-word").concat(important, ";\n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left').concat(important, ";\n direction: ").concat(this.config.direction || 'ltr', ";\n -webkit-appearance: none").concat(important, ";\n appearance: none").concat(important, ";\n box-sizing: border-box").concat(important, ";\n }\n \n .message-input:focus {\n outline: none").concat(important, ";\n border-color: ").concat(inputFocusColor, ";\n background: ").concat(inputFocusBg).concat(important, ";\n box-shadow: ").concat(inputFocusBoxShadow, ";\n }\n \n .message-input::placeholder {\n color: ").concat(placeholderColor).concat(important, ";\n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left').concat(important, ";\n }\n \n .send-button {\n width: 44px").concat(important, ";\n height: 44px").concat(important, ";\n border-radius: 50%").concat(important, ";\n border: none").concat(important, ";\n background: ").concat(sendButtonColor, ";\n color: ").concat(sendButtonTextColor, ";\n font-size: ").concat(this.config.sendButtonFontSize || ((_this$config$panel15 = this.config.panel) === null || _this$config$panel15 === void 0 ? void 0 : _this$config$panel15.sendButtonFontSize) || '20px', ";\n font-weight: ").concat(this.config.sendButtonFontWeight || ((_this$config$panel16 = this.config.panel) === null || _this$config$panel16 === void 0 ? void 0 : _this$config$panel16.sendButtonFontWeight) || '500', ";\n cursor: pointer").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n transition: all 0.2s ease").concat(important, ";\n box-shadow: 0 4px 12px rgba(").concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", 0.32)").concat(important, ";\n }\n \n .send-button:hover:not(:disabled) {\n background: ").concat(sendButtonHoverColor, ";\n transform: scale(1.05)").concat(important, ";\n box-shadow: 0 6px 16px rgba(").concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", 0.42)").concat(important, ";\n }\n \n .send-button-hint {\n width: 100%").concat(important, ";\n text-align: center").concat(important, ";\n margin-top: 4px").concat(important, ";\n }\n \n .send-button:disabled {\n opacity: 0.5").concat(important, ";\n cursor: not-allowed").concat(important, ";\n }\n \n .typing-indicator {\n display: inline-flex").concat(important, ";\n gap: 4px").concat(important, ";\n align-items: center").concat(important, ";\n }\n \n .typing-dot {\n width: 6px").concat(important, ";\n height: 6px").concat(important, ";\n border-radius: 50%").concat(important, ";\n background: rgba(").concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", ").concat(typingDotAlpha, ")").concat(important, ";\n animation: typingDot 1.4s ease-in-out infinite").concat(important, ";\n }\n \n .typing-dot:nth-child(2) { animation-delay: 0.2s").concat(important, "; }\n .typing-dot:nth-child(3) { animation-delay: 0.4s").concat(important, "; }\n \n @keyframes typingDot {\n 0%, 60%, 100% { transform: translateY(0); opacity: 0.7; }\n 30% { transform: translateY(-8px); opacity: 1; }\n }\n \n .error-message {\n padding: 12px").concat(important, ";\n background: ").concat(errorBubbleBg, ";\n border-radius: ").concat(messages.borderRadius, "px;\n color: ").concat(errorBubbleColor).concat(important, ";\n border: ").concat(errorBubbleBorder).concat(important, ";\n font-size: ").concat(messages.fontSize).concat(important, ";\n margin: 8px 0").concat(important, ";\n }\n \n ").concat(useVoiceTheme ? "\n #textInterface.active .input-container .send-button-hint {\n color: rgba(255,255,255,0.72)".concat(important, ";\n }\n ") : '', "\n \n @media (max-width: 768px) {\n #messagesContainer {\n padding: 12px").concat(important, ";\n gap: 12px").concat(important, ";\n }\n \n .message-bubble {\n max-width: 85%").concat(important, ";\n font-size: ").concat(messages.fontSize).concat(important, ";\n padding: 12px 14px").concat(important, ";\n }\n \n .text-input-container {\n padding: 10px").concat(important, ";\n gap: 8px").concat(important, ";\n }\n \n #text-chat-input {\n font-size: 16px !important; /* Prevents iOS zoom on focus */\n padding: 10px 14px").concat(important, ";\n min-height: 44px").concat(important, ";\n }\n \n #text-chat-send {\n min-width: 56px").concat(important, ";\n min-height: 44px").concat(important, ";\n width: 56px").concat(important, ";\n height: 44px").concat(important, ";\n }\n \n .empty-state-icon {\n font-size: 44px").concat(important, ";\n }\n \n .empty-state-title {\n font-size: 20px").concat(important, ";\n }\n \n .empty-state-text {\n font-size: 14px").concat(important, ";\n }\n }\n \n @media (max-width: 480px) {\n #messagesContainer {\n padding: 10px").concat(important, ";\n gap: 10px").concat(important, ";\n }\n \n .message-bubble {\n max-width: 90%").concat(important, ";\n font-size: ").concat(messages.fontSize).concat(important, ";\n padding: 10px 12px").concat(important, ";\n }\n \n .text-input-container {\n padding: 8px").concat(important, ";\n }\n \n #text-chat-input {\n font-size: 16px !important;\n padding: 8px 12px").concat(important, ";\n }\n }\n ");
|
|
37718
|
+
return "\n .text-interface-top-bar {\n flex-shrink: 0".concat(important, ";\n padding: 10px 12px 8px").concat(important, ";\n border-bottom: 1px solid ").concat(topBarBorder).concat(important, ";\n background: ").concat(topBarBg).concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: space-between").concat(important, ";\n }\n .text-interface-top-bar .ttp-info-btn {\n color: ").concat(backBtnColor).concat(important, ";\n }\n .text-interface-top-bar .ttp-info-btn:hover {\n background: ").concat(backBtnHoverBg).concat(important, ";\n color: ").concat(backBtnHoverColor).concat(important, ";\n }\n .text-interface-back-btn {\n display: inline-flex").concat(important, ";\n align-items: center").concat(important, ";\n gap: 6px").concat(important, ";\n padding: 6px 10px").concat(important, ";\n margin: 0").concat(important, ";\n border: none").concat(important, ";\n border-radius: 8px").concat(important, ";\n background: transparent").concat(important, ";\n color: ").concat(backBtnColor).concat(important, ";\n font-size: 16px").concat(important, ";\n font-weight: 600").concat(important, ";\n cursor: pointer").concat(important, ";\n font-family: inherit").concat(important, ";\n }\n .text-interface-back-btn:hover {\n background: ").concat(backBtnHoverBg).concat(important, ";\n color: ").concat(backBtnHoverColor).concat(important, ";\n }\n .text-interface-back-icon {\n font-size: 18px").concat(important, ";\n line-height: 1").concat(important, ";\n }\n .text-interface-back-label {\n line-height: 1.2").concat(important, ";\n }\n /* Messages container using new classes */\n #messagesContainer { \n flex: 1").concat(important, "; \n overflow-y: auto").concat(important, "; \n overflow-x: hidden").concat(important, "; \n padding: 20px").concat(important, "; \n background: ").concat(messagesAreaBg).concat(important, "; \n display: flex").concat(important, "; \n flex-direction: column").concat(important, "; \n gap: 16px").concat(important, "; \n min-height: 0").concat(important, "; \n }\n .empty-state { \n flex: 1").concat(important, "; \n display: flex").concat(important, "; \n flex-direction: column").concat(important, "; \n align-items: center").concat(important, "; \n justify-content: center").concat(important, "; \n gap: 12px").concat(important, "; \n color: ").concat(emptyMuted).concat(important, "; \n text-align: center").concat(important, "; \n padding: 20px").concat(important, "; \n }\n .empty-state-icon { font-size: 52px").concat(important, "; opacity: 0.3").concat(important, "; }\n .empty-state-title { font-size: 22px").concat(important, "; font-weight: 700").concat(important, "; color: ").concat(emptyTitle).concat(important, "; }\n .empty-state-text { font-size: 15px").concat(important, "; max-width: 300px").concat(important, "; line-height: 1.45").concat(important, "; }\n\n .text-interface { \n display: none").concat(important, "; \n flex: 1").concat(important, "; \n flex-direction: column").concat(important, "; \n min-height: 0").concat(important, "; \n overflow: hidden").concat(important, "; \n }\n .text-interface.active { display: flex").concat(important, "; }\n \n .message { \n display: flex").concat(important, "; \n gap: 8px").concat(important, "; \n padding: 4px 0").concat(important, "; \n max-width: 100%").concat(important, "; \n align-items: center").concat(important, "; \n }\n .message.edge-left { flex-direction: row").concat(important, "; }\n .message.edge-right { flex-direction: row-reverse").concat(important, "; }\n .message-bubble { \n padding: 14px 16px").concat(important, "; \n border-radius: ").concat(messages.borderRadius, "px").concat(important, "; \n max-width: 80%").concat(important, "; \n font-size: ").concat(messages.fontSize).concat(important, "; \n line-height: 1.45").concat(important, ";\n word-wrap: break-word").concat(important, "; \n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left').concat(important, "; \n direction: ").concat(this.config.direction || 'ltr', ";\n }\n .message.user .message-bubble { \n background: ").concat(userBubbleBg).concat(important, "; \n color: ").concat(userBubbleTextColor).concat(important, "; \n }\n .message.agent .message-bubble {\n background: ").concat(agentBubbleBg).concat(important, ";\n color: ").concat(agentBubbleTextColor).concat(important, ";\n border: ").concat(agentBubbleBorder).concat(important, ";\n max-width: 88%").concat(important, ";\n }\n\n /* ---------------------------------------------------------------\n Rendered markdown inside the agent bubble.\n Everything is scoped to .message-bubble so host-page styles can't\n reach in and the user bubble (plain text) is untouched.\n Logical properties (padding-inline-start, border-inline-start) keep\n the layout correct in RTL locales such as Hebrew.\n ---------------------------------------------------------------- */\n .message-bubble.md, .message-bubble .md-seg { line-height: 1.55").concat(important, "; }\n .message-bubble .md-seg { display: block").concat(important, "; }\n\n .message-bubble p {\n margin: 0 0 10px").concat(important, ";\n padding: 0").concat(important, ";\n }\n /* Deliberately gated on .md / .md-seg rather than a bare\n \".message-bubble > *\": the VOICE live-transcript row reuses the\n .message-bubble class in this same shadow root, and its children\n (.live-badge, .ttp-cursor) are not ours to restyle. */\n .message-bubble.md > *:last-child,\n .message-bubble .md-seg:last-child > *:last-child { margin-bottom: 0").concat(important, "; }\n .message-bubble.md > *:first-child,\n .message-bubble .md-seg:first-child > *:first-child { margin-top: 0").concat(important, "; }\n\n .message-bubble .md-h {\n margin: 16px 0 7px").concat(important, ";\n padding: 0").concat(important, ";\n font-weight: 700").concat(important, ";\n line-height: 1.3").concat(important, ";\n color: inherit").concat(important, ";\n }\n .message-bubble .md-h1 { font-size: 1.18em").concat(important, "; }\n .message-bubble .md-h2 { font-size: 1.09em").concat(important, "; }\n .message-bubble .md-h3 { font-size: 1.02em").concat(important, "; }\n .message-bubble .md-h4,\n .message-bubble .md-h5,\n .message-bubble .md-h6 {\n font-size: 0.95em").concat(important, ";\n letter-spacing: 0.02em").concat(important, ";\n color: ").concat(mdMuted).concat(important, ";\n }\n\n /* Logical properties only \u2014 a physical padding-left/border-left after\n these would resolve to the same property and silently win in LTR. */\n .message-bubble ul, .message-bubble ol {\n margin: 8px 0 11px").concat(important, ";\n padding-inline-start: 1.45em").concat(important, ";\n list-style-position: outside").concat(important, ";\n }\n .message-bubble ul { list-style-type: disc").concat(important, "; }\n .message-bubble ol { list-style-type: decimal").concat(important, "; }\n .message-bubble ul ul { list-style-type: circle").concat(important, "; }\n .message-bubble li {\n margin: 0 0 5px").concat(important, ";\n padding: 0").concat(important, ";\n line-height: 1.5").concat(important, ";\n }\n .message-bubble li:last-child { margin-bottom: 0").concat(important, "; }\n .message-bubble li::marker { color: ").concat(mdAccent).concat(important, "; }\n .message-bubble li > ul, .message-bubble li > ol { margin: 5px 0 2px").concat(important, "; }\n .message-bubble li > p { margin: 0 0 5px").concat(important, "; }\n\n .message-bubble strong, .message-bubble b { font-weight: 700").concat(important, "; }\n .message-bubble em, .message-bubble i { font-style: italic").concat(important, "; }\n .message-bubble del { text-decoration: line-through").concat(important, "; opacity: 0.7").concat(important, "; }\n\n .message-bubble a {\n color: ").concat(mdLink).concat(important, ";\n text-decoration: underline").concat(important, ";\n text-underline-offset: 2px").concat(important, ";\n word-break: break-word").concat(important, ";\n }\n .message-bubble a:hover { opacity: 0.82").concat(important, "; }\n\n .message-bubble code {\n font-family: ").concat(mdMono).concat(important, ";\n font-size: 0.88em").concat(important, ";\n background: ").concat(mdSubtleBg).concat(important, ";\n border: 1px solid ").concat(mdBorder).concat(important, ";\n border-radius: 5px").concat(important, ";\n padding: 1px 5px").concat(important, ";\n white-space: break-spaces").concat(important, ";\n word-break: break-word").concat(important, ";\n direction: ltr").concat(important, ";\n unicode-bidi: embed").concat(important, ";\n }\n .message-bubble pre {\n margin: 10px 0 11px").concat(important, ";\n padding: 10px 12px").concat(important, ";\n background: ").concat(mdSubtleBg).concat(important, ";\n border: 1px solid ").concat(mdBorder).concat(important, ";\n border-radius: 10px").concat(important, ";\n overflow-x: auto").concat(important, ";\n direction: ltr").concat(important, ";\n text-align: left").concat(important, ";\n }\n .message-bubble pre code {\n background: none").concat(important, ";\n border: none").concat(important, ";\n border-radius: 0").concat(important, ";\n padding: 0").concat(important, ";\n font-size: 0.85em").concat(important, ";\n line-height: 1.5").concat(important, ";\n white-space: pre").concat(important, ";\n word-break: normal").concat(important, ";\n }\n\n .message-bubble blockquote {\n margin: 10px 0").concat(important, ";\n padding-block: 2px").concat(important, ";\n padding-inline-start: 12px").concat(important, ";\n padding-inline-end: 0").concat(important, ";\n border-inline-start: 3px solid ").concat(mdAccent).concat(important, ";\n color: ").concat(mdMuted).concat(important, ";\n }\n .message-bubble blockquote > *:last-child { margin-bottom: 0").concat(important, "; }\n\n .message-bubble hr {\n border: none").concat(important, ";\n border-top: 1px solid ").concat(mdRule).concat(important, ";\n height: 0").concat(important, ";\n margin: 13px 0").concat(important, ";\n }\n\n .message-bubble .md-table-wrap {\n margin: 10px 0 11px").concat(important, ";\n overflow-x: auto").concat(important, ";\n border: 1px solid ").concat(mdBorder).concat(important, ";\n border-radius: 9px").concat(important, ";\n }\n .message-bubble table {\n border-collapse: collapse").concat(important, ";\n width: 100%").concat(important, ";\n font-size: 0.93em").concat(important, ";\n }\n .message-bubble th, .message-bubble td {\n padding: 7px 11px").concat(important, ";\n text-align: start").concat(important, ";\n border-bottom: 1px solid ").concat(mdBorder).concat(important, ";\n vertical-align: top").concat(important, ";\n }\n .message-bubble thead th {\n background: ").concat(mdSubtleBg).concat(important, ";\n font-weight: 700").concat(important, ";\n }\n .message-bubble tbody tr:nth-child(even) { background: ").concat(mdSubtlerBg).concat(important, "; }\n .message-bubble tbody tr:last-child td { border-bottom: none").concat(important, "; }\n\n .message-bubble .md-img {\n display: block").concat(important, ";\n max-width: 100%").concat(important, ";\n height: auto").concat(important, ";\n border-radius: 8px").concat(important, ";\n margin: 8px 0").concat(important, ";\n }\n\n .message.user { \n align-self: ").concat(this.config.direction === 'rtl' ? 'flex-start' : 'flex-end').concat(important, "; \n }\n .message.agent {\n align-self: ").concat(this.config.direction === 'rtl' ? 'flex-end' : 'flex-start').concat(important, ";\n /* structured answers can be tall \u2014 keep the avatar next to the first line */\n align-items: flex-start").concat(important, ";\n }\n .message.agent .message-avatar { margin-top: 7px").concat(important, "; }\n .message .message-bubble { \n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left', " !important; \n }\n ").concat(this.config.direction === 'rtl' ? "\n .message-bubble {\n text-align: right !important;\n }\n " : '', "\n .message-avatar { \n width: ").concat(avatarSize).concat(important, "; \n height: ").concat(avatarSize).concat(important, "; \n min-width: ").concat(avatarSize).concat(important, "; \n border-radius: 50%").concat(important, "; \n display: flex").concat(important, "; \n align-items: center").concat(important, "; \n justify-content: center").concat(important, "; \n flex-shrink: 0").concat(important, "; \n color: inherit").concat(important, "; \n font-size: ").concat(useVoiceTheme ? '14' : '20', "px").concat(important, "; \n line-height: 1").concat(important, "; \n background: transparent").concat(important, "; \n border: none").concat(important, "; \n box-sizing: border-box").concat(important, "; \n }\n .message-avatar.user { background: ").concat(avatarUserBg).concat(important, "; color: ").concat(avatarUserColor).concat(important, "; }\n .message-avatar.agent { background: ").concat(avatarAgentBg).concat(important, "; }\n \n .message.system {\n background: ").concat(messages.systemBackgroundColor, ";\n align-self: flex-start").concat(important, ";\n }\n .message.error {\n background: ").concat(messages.errorBackgroundColor, ";\n align-self: flex-start").concat(important, ";\n }\n \n .input-container {\n display: flex").concat(important, ";\n gap: 8px").concat(important, ";\n padding: 12px 16px").concat(important, ";\n background: ").concat(inputContainerBg).concat(important, ";\n border-top: 1px solid ").concat(inputContainerBorderTop).concat(important, ";\n align-items: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n flex-direction: ").concat(this.config.direction === 'rtl' ? 'row-reverse' : 'row').concat(important, ";\n }\n \n .input-wrapper {\n position: relative").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n }\n \n .message-input {\n width: 100%").concat(important, ";\n min-height: ").concat(TEXT_INPUT_MIN_HEIGHT_PX, "px").concat(important, ";\n max-height: ").concat(TEXT_INPUT_MAX_HEIGHT_PX, "px").concat(important, ";\n padding: ").concat(inputPadding, ";\n border: 1px solid ").concat(inputBorderColor, ";\n border-radius: ").concat(inputBorderRadius, "px;\n font-size: ").concat(inputFontSize, ";\n font-family: inherit").concat(important, ";\n line-height: 1.4").concat(important, ";\n resize: none").concat(important, ";\n overflow-y: auto").concat(important, ";\n background: ").concat(inputBackgroundColor, ";\n color: ").concat(inputTextColor, ";\n vertical-align: top").concat(important, ";\n margin: 0").concat(important, ";\n display: block").concat(important, ";\n white-space: pre-wrap").concat(important, ";\n word-wrap: break-word").concat(important, ";\n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left').concat(important, ";\n direction: ").concat(this.config.direction || 'ltr', ";\n -webkit-appearance: none").concat(important, ";\n appearance: none").concat(important, ";\n box-sizing: border-box").concat(important, ";\n }\n \n .message-input:focus {\n outline: none").concat(important, ";\n border-color: ").concat(inputFocusColor, ";\n background: ").concat(inputFocusBg).concat(important, ";\n box-shadow: ").concat(inputFocusBoxShadow, ";\n }\n \n .message-input::placeholder {\n color: ").concat(placeholderColor).concat(important, ";\n text-align: ").concat(this.config.direction === 'rtl' ? 'right' : 'left').concat(important, ";\n }\n \n .send-button {\n width: 44px").concat(important, ";\n height: 44px").concat(important, ";\n border-radius: 50%").concat(important, ";\n border: none").concat(important, ";\n background: ").concat(sendButtonColor, ";\n color: ").concat(sendButtonTextColor, ";\n font-size: ").concat(this.config.sendButtonFontSize || ((_this$config$panel15 = this.config.panel) === null || _this$config$panel15 === void 0 ? void 0 : _this$config$panel15.sendButtonFontSize) || '20px', ";\n font-weight: ").concat(this.config.sendButtonFontWeight || ((_this$config$panel16 = this.config.panel) === null || _this$config$panel16 === void 0 ? void 0 : _this$config$panel16.sendButtonFontWeight) || '500', ";\n cursor: pointer").concat(important, ";\n display: flex").concat(important, ";\n align-items: center").concat(important, ";\n justify-content: center").concat(important, ";\n flex-shrink: 0").concat(important, ";\n transition: all 0.2s ease").concat(important, ";\n box-shadow: 0 4px 12px rgba(").concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", 0.32)").concat(important, ";\n }\n \n .send-button:hover:not(:disabled) {\n background: ").concat(sendButtonHoverColor, ";\n transform: scale(1.05)").concat(important, ";\n box-shadow: 0 6px 16px rgba(").concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", 0.42)").concat(important, ";\n }\n \n .send-button-hint {\n width: 100%").concat(important, ";\n text-align: center").concat(important, ";\n margin-top: 4px").concat(important, ";\n }\n \n .send-button:disabled {\n opacity: 0.5").concat(important, ";\n cursor: not-allowed").concat(important, ";\n }\n \n .typing-indicator {\n display: inline-flex").concat(important, ";\n gap: 4px").concat(important, ";\n align-items: center").concat(important, ";\n }\n \n .typing-dot {\n width: 6px").concat(important, ";\n height: 6px").concat(important, ";\n border-radius: 50%").concat(important, ";\n background: rgba(").concat(accentRgb[0], ", ").concat(accentRgb[1], ", ").concat(accentRgb[2], ", ").concat(typingDotAlpha, ")").concat(important, ";\n animation: typingDot 1.4s ease-in-out infinite").concat(important, ";\n }\n \n .typing-dot:nth-child(2) { animation-delay: 0.2s").concat(important, "; }\n .typing-dot:nth-child(3) { animation-delay: 0.4s").concat(important, "; }\n \n @keyframes typingDot {\n 0%, 60%, 100% { transform: translateY(0); opacity: 0.7; }\n 30% { transform: translateY(-8px); opacity: 1; }\n }\n \n .error-message {\n padding: 12px").concat(important, ";\n background: ").concat(errorBubbleBg, ";\n border-radius: ").concat(messages.borderRadius, "px;\n color: ").concat(errorBubbleColor).concat(important, ";\n border: ").concat(errorBubbleBorder).concat(important, ";\n font-size: ").concat(messages.fontSize).concat(important, ";\n margin: 8px 0").concat(important, ";\n }\n \n ").concat(useVoiceTheme ? "\n #textInterface.active .input-container .send-button-hint {\n color: rgba(255,255,255,0.72)".concat(important, ";\n }\n ") : '', "\n \n @media (max-width: 768px) {\n #messagesContainer {\n padding: 12px").concat(important, ";\n gap: 12px").concat(important, ";\n }\n \n .message-bubble {\n max-width: 85%").concat(important, ";\n font-size: ").concat(messages.fontSize).concat(important, ";\n padding: 12px 14px").concat(important, ";\n }\n \n .text-input-container {\n padding: 10px").concat(important, ";\n gap: 8px").concat(important, ";\n }\n \n #text-chat-input {\n font-size: 16px !important; /* Prevents iOS zoom on focus */\n padding: 10px 14px").concat(important, ";\n min-height: 44px").concat(important, ";\n }\n \n #text-chat-send {\n min-width: 56px").concat(important, ";\n min-height: 44px").concat(important, ";\n width: 56px").concat(important, ";\n height: 44px").concat(important, ";\n }\n \n .empty-state-icon {\n font-size: 44px").concat(important, ";\n }\n \n .empty-state-title {\n font-size: 20px").concat(important, ";\n }\n \n .empty-state-text {\n font-size: 14px").concat(important, ";\n }\n }\n \n @media (max-width: 480px) {\n #messagesContainer {\n padding: 10px").concat(important, ";\n gap: 10px").concat(important, ";\n }\n \n .message-bubble {\n max-width: 90%").concat(important, ";\n font-size: ").concat(messages.fontSize).concat(important, ";\n padding: 10px 12px").concat(important, ";\n }\n \n .text-input-container {\n padding: 8px").concat(important, ";\n }\n \n #text-chat-input {\n font-size: 16px !important;\n padding: 8px 12px").concat(important, ";\n }\n }\n ");
|
|
37535
37719
|
}
|
|
37536
37720
|
|
|
37537
37721
|
/**
|
|
@@ -37784,7 +37968,13 @@ var TextInterface = /*#__PURE__*/function () {
|
|
|
37784
37968
|
avatar.textContent = avatarIcon;
|
|
37785
37969
|
var bubble = document.createElement('div');
|
|
37786
37970
|
bubble.className = 'message-bubble';
|
|
37787
|
-
|
|
37971
|
+
if (type === 'agent') {
|
|
37972
|
+
// Agent copy is markdown — render it so lists/bold/tables look designed.
|
|
37973
|
+
bubble.classList.add('md');
|
|
37974
|
+
(0,_markdown_js__WEBPACK_IMPORTED_MODULE_1__.renderMarkdownInto)(bubble, text);
|
|
37975
|
+
} else {
|
|
37976
|
+
bubble.textContent = text;
|
|
37977
|
+
}
|
|
37788
37978
|
|
|
37789
37979
|
// Order is controlled by edgeClass via flex-direction
|
|
37790
37980
|
message.appendChild(avatar);
|
|
@@ -37822,9 +38012,87 @@ var TextInterface = /*#__PURE__*/function () {
|
|
|
37822
38012
|
this.streamingEl = bubble;
|
|
37823
38013
|
this.hasStartedStreaming = false;
|
|
37824
38014
|
this._pendingMedia = []; // Buffer for images that arrive before next text chunk
|
|
38015
|
+
this._streamBuffer = ''; // Raw markdown of the segment currently being written
|
|
38016
|
+
this._streamSegmentEl = null; // The .md-seg element that buffer renders into
|
|
37825
38017
|
messages.scrollTop = messages.scrollHeight;
|
|
37826
38018
|
}
|
|
37827
38019
|
|
|
38020
|
+
/** Drop the typing dots the first time real content arrives. */
|
|
38021
|
+
}, {
|
|
38022
|
+
key: "_clearTypingIndicator",
|
|
38023
|
+
value: function _clearTypingIndicator() {
|
|
38024
|
+
if (this.hasStartedStreaming) return;
|
|
38025
|
+
var dots = this.streamingEl && this.streamingEl.querySelector('.typing-indicator');
|
|
38026
|
+
if (dots) dots.remove();
|
|
38027
|
+
this.hasStartedStreaming = true;
|
|
38028
|
+
}
|
|
38029
|
+
|
|
38030
|
+
/**
|
|
38031
|
+
* The bubble is a sequence of text segments and image galleries. Text is kept
|
|
38032
|
+
* as raw markdown per segment and re-rendered in place as tokens arrive, so a
|
|
38033
|
+
* list or table only "snaps" into shape once its syntax is complete. A gallery
|
|
38034
|
+
* closes the current segment, and the text after it starts a fresh one.
|
|
38035
|
+
*/
|
|
38036
|
+
}, {
|
|
38037
|
+
key: "_ensureStreamSegment",
|
|
38038
|
+
value: function _ensureStreamSegment() {
|
|
38039
|
+
if (this._streamSegmentEl || !this.streamingEl) return this._streamSegmentEl;
|
|
38040
|
+
var seg = document.createElement('div');
|
|
38041
|
+
seg.className = 'md-seg md';
|
|
38042
|
+
this.streamingEl.appendChild(seg);
|
|
38043
|
+
this._streamSegmentEl = seg;
|
|
38044
|
+
return seg;
|
|
38045
|
+
}
|
|
38046
|
+
}, {
|
|
38047
|
+
key: "_renderStreamSegment",
|
|
38048
|
+
value: function _renderStreamSegment() {
|
|
38049
|
+
this._cancelStreamRender();
|
|
38050
|
+
if (!this._streamBuffer) return;
|
|
38051
|
+
var seg = this._ensureStreamSegment();
|
|
38052
|
+
if (seg) (0,_markdown_js__WEBPACK_IMPORTED_MODULE_1__.renderMarkdownInto)(seg, this._streamBuffer);
|
|
38053
|
+
}
|
|
38054
|
+
|
|
38055
|
+
/**
|
|
38056
|
+
* Coalesce re-renders — tokens arrive faster than a person can read.
|
|
38057
|
+
* Deliberately a timer and not requestAnimationFrame: rAF is suspended in
|
|
38058
|
+
* background tabs, so a user who switches away mid-answer would come back to
|
|
38059
|
+
* a bubble that never grew. setTimeout is only throttled, not stopped.
|
|
38060
|
+
*/
|
|
38061
|
+
}, {
|
|
38062
|
+
key: "_scheduleStreamRender",
|
|
38063
|
+
value: function _scheduleStreamRender() {
|
|
38064
|
+
var _this3 = this;
|
|
38065
|
+
if (this._streamTimer) return;
|
|
38066
|
+
this._streamTimer = setTimeout(function () {
|
|
38067
|
+
_this3._streamTimer = null;
|
|
38068
|
+
if (!_this3.streamingEl) return;
|
|
38069
|
+
_this3._renderStreamSegment();
|
|
38070
|
+
_this3._scrollToBottom();
|
|
38071
|
+
}, STREAM_RENDER_INTERVAL_MS);
|
|
38072
|
+
}
|
|
38073
|
+
}, {
|
|
38074
|
+
key: "_cancelStreamRender",
|
|
38075
|
+
value: function _cancelStreamRender() {
|
|
38076
|
+
if (!this._streamTimer) return;
|
|
38077
|
+
clearTimeout(this._streamTimer);
|
|
38078
|
+
this._streamTimer = null;
|
|
38079
|
+
}
|
|
38080
|
+
|
|
38081
|
+
/** Final render of the open segment, then start a new one for later text. */
|
|
38082
|
+
}, {
|
|
38083
|
+
key: "_closeStreamSegment",
|
|
38084
|
+
value: function _closeStreamSegment() {
|
|
38085
|
+
this._renderStreamSegment();
|
|
38086
|
+
this._streamBuffer = '';
|
|
38087
|
+
this._streamSegmentEl = null;
|
|
38088
|
+
}
|
|
38089
|
+
}, {
|
|
38090
|
+
key: "_scrollToBottom",
|
|
38091
|
+
value: function _scrollToBottom() {
|
|
38092
|
+
var messages = this.shadowRoot.getElementById('messagesContainer');
|
|
38093
|
+
if (messages) messages.scrollTop = messages.scrollHeight;
|
|
38094
|
+
}
|
|
38095
|
+
|
|
37828
38096
|
/**
|
|
37829
38097
|
* Append chunk to streaming response.
|
|
37830
38098
|
* Does NOT flush buffered media here — media is flushed only when the
|
|
@@ -37834,24 +38102,10 @@ var TextInterface = /*#__PURE__*/function () {
|
|
|
37834
38102
|
}, {
|
|
37835
38103
|
key: "appendStreamingChunk",
|
|
37836
38104
|
value: function appendStreamingChunk(chunk) {
|
|
37837
|
-
if (!this.streamingEl) return;
|
|
37838
|
-
|
|
37839
|
-
|
|
37840
|
-
|
|
37841
|
-
this.hasStartedStreaming = true;
|
|
37842
|
-
}
|
|
37843
|
-
|
|
37844
|
-
// Append text — use textNode if we have inline media DOM elements
|
|
37845
|
-
var hasInlineMedia = this.streamingEl.querySelector('.inline-media-gallery');
|
|
37846
|
-
if (hasInlineMedia) {
|
|
37847
|
-
this.streamingEl.appendChild(document.createTextNode(chunk));
|
|
37848
|
-
} else {
|
|
37849
|
-
this.streamingEl.textContent += chunk;
|
|
37850
|
-
}
|
|
37851
|
-
var messages = this.shadowRoot.getElementById('messagesContainer');
|
|
37852
|
-
if (messages) {
|
|
37853
|
-
messages.scrollTop = messages.scrollHeight;
|
|
37854
|
-
}
|
|
38105
|
+
if (!this.streamingEl || typeof chunk !== 'string' || chunk === '') return;
|
|
38106
|
+
this._clearTypingIndicator();
|
|
38107
|
+
this._streamBuffer += chunk;
|
|
38108
|
+
this._scheduleStreamRender();
|
|
37855
38109
|
}
|
|
37856
38110
|
|
|
37857
38111
|
/**
|
|
@@ -37872,10 +38126,7 @@ var TextInterface = /*#__PURE__*/function () {
|
|
|
37872
38126
|
key: "appendStreamingMedia",
|
|
37873
38127
|
value: function appendStreamingMedia(images, title) {
|
|
37874
38128
|
if (!this.streamingEl) return;
|
|
37875
|
-
|
|
37876
|
-
this.streamingEl.textContent = '';
|
|
37877
|
-
this.hasStartedStreaming = true;
|
|
37878
|
-
}
|
|
38129
|
+
this._clearTypingIndicator();
|
|
37879
38130
|
|
|
37880
38131
|
// Flush previous media — the text describing those images is complete
|
|
37881
38132
|
this._flushPendingMedia();
|
|
@@ -37896,6 +38147,10 @@ var TextInterface = /*#__PURE__*/function () {
|
|
|
37896
38147
|
value: function _flushPendingMedia() {
|
|
37897
38148
|
if (!this._pendingMedia || this._pendingMedia.length === 0) return;
|
|
37898
38149
|
if (!this.streamingEl) return;
|
|
38150
|
+
|
|
38151
|
+
// Commit the text written so far before the galleries land under it, so the
|
|
38152
|
+
// text that follows them renders as its own segment instead of being merged.
|
|
38153
|
+
this._closeStreamSegment();
|
|
37899
38154
|
var _iterator = _createForOfIteratorHelper(this._pendingMedia),
|
|
37900
38155
|
_step;
|
|
37901
38156
|
try {
|
|
@@ -37919,7 +38174,7 @@ var TextInterface = /*#__PURE__*/function () {
|
|
|
37919
38174
|
}, {
|
|
37920
38175
|
key: "_renderInlineMedia",
|
|
37921
38176
|
value: function _renderInlineMedia(images, title) {
|
|
37922
|
-
var
|
|
38177
|
+
var _this4 = this;
|
|
37923
38178
|
var gallery = document.createElement('div');
|
|
37924
38179
|
gallery.className = 'inline-media-gallery';
|
|
37925
38180
|
gallery.style.cssText = 'display:flex;gap:6px;flex-wrap:wrap;margin:8px 0;';
|
|
@@ -37938,10 +38193,10 @@ var TextInterface = /*#__PURE__*/function () {
|
|
|
37938
38193
|
|
|
37939
38194
|
// Open fullscreen gallery viewer on click (same as voice gallery)
|
|
37940
38195
|
imgEl.addEventListener('click', function () {
|
|
37941
|
-
if (!
|
|
37942
|
-
|
|
38196
|
+
if (!_this4._inlineGalleryHandler) {
|
|
38197
|
+
_this4._inlineGalleryHandler = (0,_galleryHandler_js__WEBPACK_IMPORTED_MODULE_0__.createGalleryHandler)(_this4._widget);
|
|
37943
38198
|
}
|
|
37944
|
-
|
|
38199
|
+
_this4._inlineGalleryHandler.handleShowMedia({
|
|
37945
38200
|
images: images,
|
|
37946
38201
|
title: title
|
|
37947
38202
|
});
|
|
@@ -37977,17 +38232,22 @@ var TextInterface = /*#__PURE__*/function () {
|
|
|
37977
38232
|
key: "finalizeStreaming",
|
|
37978
38233
|
value: function finalizeStreaming(fullText) {
|
|
37979
38234
|
if (this.streamingEl) {
|
|
37980
|
-
|
|
37981
|
-
|
|
38235
|
+
this._cancelStreamRender();
|
|
38236
|
+
// An empty reply must not leave the typing dots spinning forever.
|
|
38237
|
+
this._clearTypingIndicator();
|
|
38238
|
+
var hasGalleries = !!this.streamingEl.querySelector('.inline-media-gallery') || this._pendingMedia && this._pendingMedia.length > 0;
|
|
37982
38239
|
|
|
37983
|
-
//
|
|
37984
|
-
//
|
|
37985
|
-
|
|
37986
|
-
if (!
|
|
37987
|
-
this.
|
|
38240
|
+
// Without interleaved media the `done` payload is the authoritative text,
|
|
38241
|
+
// so re-render from it. With media, the bubble is a mix of segments and
|
|
38242
|
+
// galleries that fullText can't describe — keep what streaming produced.
|
|
38243
|
+
if (!hasGalleries && typeof fullText === 'string' && fullText) {
|
|
38244
|
+
this._streamBuffer = fullText;
|
|
37988
38245
|
}
|
|
37989
|
-
|
|
38246
|
+
this._renderStreamSegment();
|
|
37990
38247
|
|
|
38248
|
+
// Flush trailing galleries (also commits the segment above them)
|
|
38249
|
+
this._flushPendingMedia();
|
|
38250
|
+
this._closeStreamSegment();
|
|
37991
38251
|
var container = this.shadowRoot.getElementById('agent-streaming');
|
|
37992
38252
|
if (container) container.id = '';
|
|
37993
38253
|
this.streamingEl = null;
|
|
@@ -38002,10 +38262,13 @@ var TextInterface = /*#__PURE__*/function () {
|
|
|
38002
38262
|
}, {
|
|
38003
38263
|
key: "stopStreamingState",
|
|
38004
38264
|
value: function stopStreamingState() {
|
|
38265
|
+
this._cancelStreamRender();
|
|
38005
38266
|
var existing = this.shadowRoot.getElementById('agent-streaming');
|
|
38006
38267
|
if (existing) existing.remove();
|
|
38007
38268
|
this.streamingEl = null;
|
|
38008
38269
|
this.hasStartedStreaming = false;
|
|
38270
|
+
this._streamBuffer = '';
|
|
38271
|
+
this._streamSegmentEl = null;
|
|
38009
38272
|
}
|
|
38010
38273
|
|
|
38011
38274
|
/**
|
|
@@ -38877,7 +39140,7 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
38877
39140
|
value: function () {
|
|
38878
39141
|
var _proceedWithVoiceCall = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
|
|
38879
39142
|
var _this3 = this;
|
|
38880
|
-
var isResumeCall, panel, header, toggleText, originalSection, compactSection, idleState, _idleState, activeState, stripOnly, voiceInterface, connected, serverRejected, originalOnError, originalOnDisconnected, attempts, _vs, vs, hasDisclaimers, sendDisclaimerAckAfterMobileMicReady, _vs$lastDisclaimerPay, disclaimerTexts, _this$config$inputFor, _this$config$connecti,
|
|
39143
|
+
var isResumeCall, panel, header, toggleText, originalSection, compactSection, idleState, _idleState, activeState, stripOnly, voiceInterface, connected, serverRejected, originalOnError, originalOnDisconnected, attempts, _vs, vs, hasDisclaimers, sendDisclaimerAckAfterMobileMicReady, _vs$lastDisclaimerPay, disclaimerTexts, _this$config$inputFor, _this$config$connecti, primeSr, audioConstraints, micStream, floatingButton, mobileFab, delayConfig, streamToUse, _this$sdk$voiceSDK, error, existingBar, _existingBar, _idleState2, _floatingButton, updateTimer, isDisclaimerDeclined, deviceInfo, _t, _t2, _t3, _t4, _t5, _t6;
|
|
38881
39144
|
return _regenerator().w(function (_context4) {
|
|
38882
39145
|
while (1) switch (_context4.p = _context4.n) {
|
|
38883
39146
|
case 0:
|
|
@@ -39119,21 +39382,44 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39119
39382
|
|
|
39120
39383
|
// On mobile: get getUserMedia stream once, pass to startListening to avoid double-call
|
|
39121
39384
|
if (!this.isMobile) {
|
|
39122
|
-
_context4.n =
|
|
39385
|
+
_context4.n = 24;
|
|
39123
39386
|
break;
|
|
39124
39387
|
}
|
|
39125
39388
|
_context4.p = 15;
|
|
39126
|
-
|
|
39389
|
+
// This preliminary stream is REUSED as the capture stream (iOS single-stream fix),
|
|
39390
|
+
// so it must carry the same AEC constraints as the desktop path — bare { audio: true }
|
|
39391
|
+
// leaves echoCancellation/noiseSuppression/autoGainControl (and iOS voiceIsolation) to
|
|
39392
|
+
// browser defaults, which can let speakerphone TTS echo cross VAD and trigger barge-in.
|
|
39393
|
+
primeSr = ((_this$config$inputFor = this.config.inputFormat) === null || _this$config$inputFor === void 0 ? void 0 : _this$config$inputFor.sampleRate) || this.config.sampleRate || 16000;
|
|
39394
|
+
audioConstraints = (0,_core_AudioRecorder_js__WEBPACK_IMPORTED_MODULE_1__.buildAudioConstraints)(primeSr, this.config.audioConstraints || {});
|
|
39395
|
+
_context4.p = 16;
|
|
39396
|
+
_context4.n = 17;
|
|
39397
|
+
return navigator.mediaDevices.getUserMedia({
|
|
39398
|
+
audio: audioConstraints
|
|
39399
|
+
});
|
|
39400
|
+
case 17:
|
|
39401
|
+
micStream = _context4.v;
|
|
39402
|
+
_context4.n = 20;
|
|
39403
|
+
break;
|
|
39404
|
+
case 18:
|
|
39405
|
+
_context4.p = 18;
|
|
39406
|
+
_t2 = _context4.v;
|
|
39407
|
+
// Some devices/webviews reject specific constraints (OverconstrainedError etc.).
|
|
39408
|
+
// Fall back to minimal so permission still succeeds, matching prior behavior.
|
|
39409
|
+
console.warn('⚠️ Mobile getUserMedia with AEC constraints failed, retrying minimal:', (_t2 === null || _t2 === void 0 ? void 0 : _t2.name) || _t2);
|
|
39410
|
+
_context4.n = 19;
|
|
39127
39411
|
return navigator.mediaDevices.getUserMedia({
|
|
39128
39412
|
audio: true
|
|
39129
39413
|
});
|
|
39130
|
-
case
|
|
39414
|
+
case 19:
|
|
39131
39415
|
micStream = _context4.v;
|
|
39416
|
+
// Flagged so client_audio_info telemetry reports the AEC constraints were NOT applied
|
|
39417
|
+
micStream._ttpConstraintsFallback = true;
|
|
39418
|
+
case 20:
|
|
39132
39419
|
this._preliminaryInputStream = micStream;
|
|
39133
|
-
|
|
39134
|
-
_context4.n = 17;
|
|
39420
|
+
_context4.n = 21;
|
|
39135
39421
|
return _core_AudioRecorder_js__WEBPACK_IMPORTED_MODULE_1__["default"].primeSharedContext(primeSr);
|
|
39136
|
-
case
|
|
39422
|
+
case 21:
|
|
39137
39423
|
// Hide floating button now that permission is granted
|
|
39138
39424
|
floatingButton = this.shadowRoot.getElementById('text-chat-button') || document.getElementById('text-chat-button');
|
|
39139
39425
|
if (floatingButton) floatingButton.style.display = 'none';
|
|
@@ -39146,51 +39432,51 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39146
39432
|
android: 3000,
|
|
39147
39433
|
ios: 0
|
|
39148
39434
|
};
|
|
39149
|
-
_context4.n =
|
|
39435
|
+
_context4.n = 22;
|
|
39150
39436
|
return (0,_shared_applyDelay_js__WEBPACK_IMPORTED_MODULE_3__.applyDelay)(delayConfig);
|
|
39151
|
-
case
|
|
39437
|
+
case 22:
|
|
39152
39438
|
if (sendDisclaimerAckAfterMobileMicReady) {
|
|
39153
39439
|
vs.sendDisclaimerAck(true);
|
|
39154
39440
|
sendDisclaimerAckAfterMobileMicReady = false;
|
|
39155
39441
|
}
|
|
39156
|
-
_context4.n =
|
|
39442
|
+
_context4.n = 24;
|
|
39157
39443
|
break;
|
|
39158
|
-
case
|
|
39159
|
-
_context4.p =
|
|
39160
|
-
|
|
39161
|
-
console.error('❌ Microphone permission denied:',
|
|
39444
|
+
case 23:
|
|
39445
|
+
_context4.p = 23;
|
|
39446
|
+
_t3 = _context4.v;
|
|
39447
|
+
console.error('❌ Microphone permission denied:', _t3);
|
|
39162
39448
|
this._stopPreliminaryInputStream();
|
|
39163
|
-
throw
|
|
39164
|
-
case
|
|
39165
|
-
_context4.p =
|
|
39449
|
+
throw _t3;
|
|
39450
|
+
case 24:
|
|
39451
|
+
_context4.p = 24;
|
|
39166
39452
|
streamToUse = this._preliminaryInputStream || null;
|
|
39167
39453
|
if (streamToUse) this._preliminaryInputStream = null;
|
|
39168
|
-
_context4.n =
|
|
39454
|
+
_context4.n = 25;
|
|
39169
39455
|
return this.sdk.startListening(streamToUse);
|
|
39170
|
-
case
|
|
39456
|
+
case 25:
|
|
39171
39457
|
if (!(!this.sdk.isConnected || !this.sdk.voiceSDK || !this.sdk.voiceSDK.isConnected || !this.sdk.voiceSDK.websocket || this.sdk.voiceSDK.websocket.readyState !== WebSocket.OPEN)) {
|
|
39172
|
-
_context4.n =
|
|
39458
|
+
_context4.n = 30;
|
|
39173
39459
|
break;
|
|
39174
39460
|
}
|
|
39175
39461
|
if (!((_this$sdk$voiceSDK = this.sdk.voiceSDK) !== null && _this$sdk$voiceSDK !== void 0 && _this$sdk$voiceSDK.isRecording)) {
|
|
39176
|
-
_context4.n =
|
|
39462
|
+
_context4.n = 29;
|
|
39177
39463
|
break;
|
|
39178
39464
|
}
|
|
39179
|
-
_context4.p =
|
|
39180
|
-
_context4.n =
|
|
39465
|
+
_context4.p = 26;
|
|
39466
|
+
_context4.n = 27;
|
|
39181
39467
|
return this.sdk.voiceSDK.stopRecording();
|
|
39182
|
-
case
|
|
39183
|
-
_context4.n =
|
|
39468
|
+
case 27:
|
|
39469
|
+
_context4.n = 29;
|
|
39184
39470
|
break;
|
|
39185
|
-
case
|
|
39186
|
-
_context4.p =
|
|
39187
|
-
|
|
39188
|
-
case
|
|
39471
|
+
case 28:
|
|
39472
|
+
_context4.p = 28;
|
|
39473
|
+
_t4 = _context4.v;
|
|
39474
|
+
case 29:
|
|
39189
39475
|
error = new Error('Connection lost - server may have rejected the call');
|
|
39190
39476
|
error.name = 'ServerRejected';
|
|
39191
39477
|
error.isServerRejection = true;
|
|
39192
39478
|
throw error;
|
|
39193
|
-
case
|
|
39479
|
+
case 30:
|
|
39194
39480
|
console.log('🎤 Started listening - permission granted');
|
|
39195
39481
|
this._stopPreliminaryInputStream();
|
|
39196
39482
|
this.isActive = true;
|
|
@@ -39213,19 +39499,19 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39213
39499
|
this.startDesktopWaveformAnimation();
|
|
39214
39500
|
this.desktop.startLiveWaveformInterval();
|
|
39215
39501
|
}
|
|
39216
|
-
_context4.n =
|
|
39502
|
+
_context4.n = 33;
|
|
39217
39503
|
break;
|
|
39218
|
-
case
|
|
39219
|
-
_context4.p =
|
|
39220
|
-
|
|
39221
|
-
if (!(
|
|
39222
|
-
_context4.n =
|
|
39504
|
+
case 31:
|
|
39505
|
+
_context4.p = 31;
|
|
39506
|
+
_t5 = _context4.v;
|
|
39507
|
+
if (!(_t5.isServerRejection || _t5.name === 'ServerRejected')) {
|
|
39508
|
+
_context4.n = 32;
|
|
39223
39509
|
break;
|
|
39224
39510
|
}
|
|
39225
39511
|
this.resetConnectingState();
|
|
39226
|
-
throw
|
|
39227
|
-
case
|
|
39228
|
-
console.error('❌ Failed to start listening:',
|
|
39512
|
+
throw _t5;
|
|
39513
|
+
case 32:
|
|
39514
|
+
console.error('❌ Failed to start listening:', _t5);
|
|
39229
39515
|
this.resetConnectingState();
|
|
39230
39516
|
if (this.isMobile) {
|
|
39231
39517
|
_existingBar = document.getElementById('mobile-voice-call-bar-container');
|
|
@@ -39240,8 +39526,8 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39240
39526
|
this.config.onDesktopMinimizedStripLauncherRestore();
|
|
39241
39527
|
} catch (_) {}
|
|
39242
39528
|
}
|
|
39243
|
-
throw
|
|
39244
|
-
case
|
|
39529
|
+
throw _t5;
|
|
39530
|
+
case 33:
|
|
39245
39531
|
// Start timer (desktop only - mobile bar owns its own timer)
|
|
39246
39532
|
if (!this.isMobile && !this.callStartTime) {
|
|
39247
39533
|
this.callStartTime = Date.now();
|
|
@@ -39260,14 +39546,14 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39260
39546
|
}, 100);
|
|
39261
39547
|
}
|
|
39262
39548
|
console.log('✅ Voice call started successfully');
|
|
39263
|
-
_context4.n =
|
|
39549
|
+
_context4.n = 40;
|
|
39264
39550
|
break;
|
|
39265
|
-
case
|
|
39266
|
-
_context4.p =
|
|
39267
|
-
|
|
39268
|
-
isDisclaimerDeclined =
|
|
39269
|
-
if (!(
|
|
39270
|
-
console.error('❌ Error starting voice call:',
|
|
39551
|
+
case 34:
|
|
39552
|
+
_context4.p = 34;
|
|
39553
|
+
_t6 = _context4.v;
|
|
39554
|
+
isDisclaimerDeclined = _t6 && _t6.message === 'DISCLAIMER_DECLINED'; // Handle server rejection gracefully (don't log as error)
|
|
39555
|
+
if (!(_t6.isServerRejection || _t6.name === 'ServerRejected') && !isDisclaimerDeclined) {
|
|
39556
|
+
console.error('❌ Error starting voice call:', _t6);
|
|
39271
39557
|
}
|
|
39272
39558
|
this._stopPreliminaryInputStream();
|
|
39273
39559
|
|
|
@@ -39299,7 +39585,7 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39299
39585
|
// User declined server disclaimer: full idle reset (not just resetConnectingState —
|
|
39300
39586
|
// connect path shows voiceActiveState on desktop; without hiding it, call UI stays visible).
|
|
39301
39587
|
if (!isDisclaimerDeclined) {
|
|
39302
|
-
_context4.n =
|
|
39588
|
+
_context4.n = 35;
|
|
39303
39589
|
break;
|
|
39304
39590
|
}
|
|
39305
39591
|
this.resetUIState();
|
|
@@ -39309,12 +39595,12 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39309
39595
|
this.config.onCallEnd();
|
|
39310
39596
|
}
|
|
39311
39597
|
return _context4.a(2);
|
|
39312
|
-
case
|
|
39598
|
+
case 35:
|
|
39313
39599
|
this.resetConnectingState();
|
|
39314
39600
|
|
|
39315
39601
|
// Handle specific error types with appropriate modals
|
|
39316
|
-
if (!(
|
|
39317
|
-
_context4.n =
|
|
39602
|
+
if (!(_t6.name === 'NotAllowedError' || _t6.name === 'PermissionDeniedError')) {
|
|
39603
|
+
_context4.n = 36;
|
|
39318
39604
|
break;
|
|
39319
39605
|
}
|
|
39320
39606
|
// Permission denied - show blocked modal
|
|
@@ -39326,37 +39612,37 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39326
39612
|
// User clicked refresh
|
|
39327
39613
|
window.location.reload();
|
|
39328
39614
|
});
|
|
39329
|
-
_context4.n =
|
|
39615
|
+
_context4.n = 40;
|
|
39330
39616
|
break;
|
|
39331
|
-
case
|
|
39332
|
-
if (!(
|
|
39333
|
-
_context4.n =
|
|
39617
|
+
case 36:
|
|
39618
|
+
if (!(_t6.name === 'NotFoundError' || _t6.name === 'DevicesNotFoundError')) {
|
|
39619
|
+
_context4.n = 37;
|
|
39334
39620
|
break;
|
|
39335
39621
|
}
|
|
39336
39622
|
// No microphone found - show no mic modal
|
|
39337
39623
|
(0,_shared_MicPermissionModals_js__WEBPACK_IMPORTED_MODULE_4__.showNoMicrophoneModal)(function () {
|
|
39338
39624
|
_this3.resetUIState();
|
|
39339
39625
|
});
|
|
39340
|
-
_context4.n =
|
|
39626
|
+
_context4.n = 40;
|
|
39341
39627
|
break;
|
|
39342
|
-
case
|
|
39343
|
-
if (!(
|
|
39344
|
-
_context4.n =
|
|
39628
|
+
case 37:
|
|
39629
|
+
if (!(_t6 && (_t6.message === 'DOMAIN_NOT_WHITELISTED' || _t6.message && _t6.message.includes('Domain not whitelisted')))) {
|
|
39630
|
+
_context4.n = 39;
|
|
39345
39631
|
break;
|
|
39346
39632
|
}
|
|
39347
|
-
_context4.n =
|
|
39633
|
+
_context4.n = 38;
|
|
39348
39634
|
return this.endCallOnServerRejection();
|
|
39349
|
-
case
|
|
39350
|
-
_context4.n =
|
|
39635
|
+
case 38:
|
|
39636
|
+
_context4.n = 40;
|
|
39351
39637
|
break;
|
|
39352
|
-
case
|
|
39638
|
+
case 39:
|
|
39353
39639
|
// Other errors - show in transcript
|
|
39354
|
-
this.showError(
|
|
39640
|
+
this.showError(_t6.message || _t6);
|
|
39355
39641
|
this.resetUIState();
|
|
39356
|
-
case
|
|
39642
|
+
case 40:
|
|
39357
39643
|
return _context4.a(2);
|
|
39358
39644
|
}
|
|
39359
|
-
}, _callee4, this, [[
|
|
39645
|
+
}, _callee4, this, [[26, 28], [24, 31], [16, 18], [15, 23], [2, 4], [0, 34]]);
|
|
39360
39646
|
}));
|
|
39361
39647
|
function proceedWithVoiceCall() {
|
|
39362
39648
|
return _proceedWithVoiceCall.apply(this, arguments);
|
|
@@ -39420,7 +39706,7 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39420
39706
|
key: "endCallOnServerRejection",
|
|
39421
39707
|
value: (function () {
|
|
39422
39708
|
var _endCallOnServerRejection = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
|
|
39423
|
-
var voiceInterfaceEl, landingScreen, _this$sdk$voiceSDK2, _this$sdk$voiceSDK3, audioRecorder, isRecording, _this$sdk$voiceSDK4, activeState, idleState, floatingButton, fallbackButton, mobileFabEnd, errorMsg,
|
|
39709
|
+
var voiceInterfaceEl, landingScreen, _this$sdk$voiceSDK2, _this$sdk$voiceSDK3, audioRecorder, isRecording, _this$sdk$voiceSDK4, activeState, idleState, floatingButton, fallbackButton, mobileFabEnd, errorMsg, _t7, _t8, _t9, _t0, _t1;
|
|
39424
39710
|
return _regenerator().w(function (_context5) {
|
|
39425
39711
|
while (1) switch (_context5.p = _context5.n) {
|
|
39426
39712
|
case 0:
|
|
@@ -39482,8 +39768,8 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39482
39768
|
break;
|
|
39483
39769
|
case 4:
|
|
39484
39770
|
_context5.p = 4;
|
|
39485
|
-
|
|
39486
|
-
console.warn('Error sending stop message to AudioWorklet:',
|
|
39771
|
+
_t7 = _context5.v;
|
|
39772
|
+
console.warn('Error sending stop message to AudioWorklet:', _t7);
|
|
39487
39773
|
case 5:
|
|
39488
39774
|
if (!(this.sdk.voiceSDK && typeof this.sdk.voiceSDK.stopRecording === 'function')) {
|
|
39489
39775
|
_context5.n = 10;
|
|
@@ -39498,8 +39784,8 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39498
39784
|
break;
|
|
39499
39785
|
case 8:
|
|
39500
39786
|
_context5.p = 8;
|
|
39501
|
-
|
|
39502
|
-
console.warn('Error calling stopRecording:',
|
|
39787
|
+
_t8 = _context5.v;
|
|
39788
|
+
console.warn('Error calling stopRecording:', _t8);
|
|
39503
39789
|
case 9:
|
|
39504
39790
|
_context5.n = 14;
|
|
39505
39791
|
break;
|
|
@@ -39519,8 +39805,8 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39519
39805
|
break;
|
|
39520
39806
|
case 13:
|
|
39521
39807
|
_context5.p = 13;
|
|
39522
|
-
|
|
39523
|
-
console.warn('Error calling stopListening:',
|
|
39808
|
+
_t9 = _context5.v;
|
|
39809
|
+
console.warn('Error calling stopListening:', _t9);
|
|
39524
39810
|
case 14:
|
|
39525
39811
|
if (!(audioRecorder && typeof audioRecorder.stop === 'function')) {
|
|
39526
39812
|
_context5.n = 18;
|
|
@@ -39535,8 +39821,8 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39535
39821
|
break;
|
|
39536
39822
|
case 17:
|
|
39537
39823
|
_context5.p = 17;
|
|
39538
|
-
|
|
39539
|
-
console.warn('Error calling AudioRecorder.stop():',
|
|
39824
|
+
_t0 = _context5.v;
|
|
39825
|
+
console.warn('Error calling AudioRecorder.stop():', _t0);
|
|
39540
39826
|
case 18:
|
|
39541
39827
|
console.log('✅ Audio capture/VAD stopped');
|
|
39542
39828
|
case 19:
|
|
@@ -39568,8 +39854,8 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
39568
39854
|
break;
|
|
39569
39855
|
case 20:
|
|
39570
39856
|
_context5.p = 20;
|
|
39571
|
-
|
|
39572
|
-
console.warn('Error stopping listening on server rejection:',
|
|
39857
|
+
_t1 = _context5.v;
|
|
39858
|
+
console.warn('Error stopping listening on server rejection:', _t1);
|
|
39573
39859
|
// Force stop media streams even if stopListening fails
|
|
39574
39860
|
try {
|
|
39575
39861
|
if ((_this$sdk$voiceSDK4 = this.sdk.voiceSDK) !== null && _this$sdk$voiceSDK4 !== void 0 && (_this$sdk$voiceSDK4 = _this$sdk$voiceSDK4.audioRecorder) !== null && _this$sdk$voiceSDK4 !== void 0 && _this$sdk$voiceSDK4.mediaStream) {
|
|
@@ -41006,6 +41292,829 @@ function createGalleryHandler(widget) {
|
|
|
41006
41292
|
|
|
41007
41293
|
/***/ }),
|
|
41008
41294
|
|
|
41295
|
+
/***/ "./src/widget/markdown.js":
|
|
41296
|
+
/*!********************************!*\
|
|
41297
|
+
!*** ./src/widget/markdown.js ***!
|
|
41298
|
+
\********************************/
|
|
41299
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
41300
|
+
|
|
41301
|
+
"use strict";
|
|
41302
|
+
__webpack_require__.r(__webpack_exports__);
|
|
41303
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
41304
|
+
/* harmony export */ parseInline: () => (/* binding */ parseInline),
|
|
41305
|
+
/* harmony export */ parseMarkdown: () => (/* binding */ parseMarkdown),
|
|
41306
|
+
/* harmony export */ renderMarkdownInto: () => (/* binding */ renderMarkdownInto),
|
|
41307
|
+
/* harmony export */ safeHref: () => (/* binding */ safeHref)
|
|
41308
|
+
/* harmony export */ });
|
|
41309
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
41310
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
41311
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
41312
|
+
/**
|
|
41313
|
+
* markdown.js — tiny, dependency-free Markdown renderer for chat bubbles.
|
|
41314
|
+
*
|
|
41315
|
+
* Split in two halves on purpose:
|
|
41316
|
+
* parseMarkdown(text) -> block AST — pure JS, unit-tested in scripts/markdown.test.mjs
|
|
41317
|
+
* renderMarkdownInto(el, text) — walks the AST and builds real DOM nodes
|
|
41318
|
+
*
|
|
41319
|
+
* XSS: content is only ever placed with document.createTextNode / element
|
|
41320
|
+
* properties. Nothing is written through innerHTML, and link hrefs go through
|
|
41321
|
+
* a scheme allowlist (safeHref), so agent text can never inject markup.
|
|
41322
|
+
*
|
|
41323
|
+
* Streaming: the parser is total — an unterminated code fence, a half-written
|
|
41324
|
+
* bold run or a truncated table never throw, they just degrade to text. That
|
|
41325
|
+
* lets the caller re-render the whole accumulated buffer on every token.
|
|
41326
|
+
*/
|
|
41327
|
+
|
|
41328
|
+
/* ------------------------------------------------------------------ */
|
|
41329
|
+
/* Block parsing */
|
|
41330
|
+
/* ------------------------------------------------------------------ */
|
|
41331
|
+
|
|
41332
|
+
var FENCE_RE = /^(\s*)(`{3,}|~{3,})\s*([^\s`]*)\s*$/;
|
|
41333
|
+
var HEADING_RE = /^(\s{0,3})(#{1,6})\s+(.*)$/;
|
|
41334
|
+
var HR_RE = /^\s{0,3}([-*_])[ \t]*(?:\1[ \t]*){2,}$/;
|
|
41335
|
+
var QUOTE_RE = /^\s{0,3}>\s?(.*)$/;
|
|
41336
|
+
var LIST_RE = /^(\s*)(?:([-*+•])|(\d{1,9})[.)])([ \t]+)(.*)$/;
|
|
41337
|
+
var TABLE_SEP_RE = /^\s*\|?[\s:|-]*-[\s:|-]*\|?\s*$/;
|
|
41338
|
+
function isBlank(line) {
|
|
41339
|
+
return !line || /^\s*$/.test(line);
|
|
41340
|
+
}
|
|
41341
|
+
function indentOf(line) {
|
|
41342
|
+
var m = /^[ \t]*/.exec(line)[0];
|
|
41343
|
+
// treat a tab as two columns — LLMs mix tabs and spaces freely
|
|
41344
|
+
return m.replace(/\t/g, ' ').length;
|
|
41345
|
+
}
|
|
41346
|
+
function matchListItem(line) {
|
|
41347
|
+
var m = LIST_RE.exec(line);
|
|
41348
|
+
if (!m) return null;
|
|
41349
|
+
var indent = indentOf(line);
|
|
41350
|
+
var markerLen = m[2] ? 1 : m[3].length + 1;
|
|
41351
|
+
return {
|
|
41352
|
+
indent: indent,
|
|
41353
|
+
ordered: !!m[3],
|
|
41354
|
+
start: m[3] ? parseInt(m[3], 10) : null,
|
|
41355
|
+
contentIndent: indent + markerLen + m[4].replace(/\t/g, ' ').length,
|
|
41356
|
+
text: m[5]
|
|
41357
|
+
};
|
|
41358
|
+
}
|
|
41359
|
+
|
|
41360
|
+
/** True when the line opens a block that must interrupt an open paragraph. */
|
|
41361
|
+
function startsBlock(line) {
|
|
41362
|
+
return FENCE_RE.test(line) || HEADING_RE.test(line) || HR_RE.test(line) || QUOTE_RE.test(line) || matchListItem(line) !== null;
|
|
41363
|
+
}
|
|
41364
|
+
function dedent(line, columns) {
|
|
41365
|
+
var seen = 0;
|
|
41366
|
+
var i = 0;
|
|
41367
|
+
while (i < line.length && seen < columns) {
|
|
41368
|
+
var c = line[i];
|
|
41369
|
+
if (c === ' ') seen += 1;else if (c === '\t') seen += 2;else break;
|
|
41370
|
+
i++;
|
|
41371
|
+
}
|
|
41372
|
+
return line.slice(i);
|
|
41373
|
+
}
|
|
41374
|
+
function splitTableRow(line) {
|
|
41375
|
+
var s = line.trim();
|
|
41376
|
+
if (s.startsWith('|')) s = s.slice(1);
|
|
41377
|
+
if (s.endsWith('|') && !s.endsWith('\\|')) s = s.slice(0, -1);
|
|
41378
|
+
var cells = [];
|
|
41379
|
+
var cur = '';
|
|
41380
|
+
for (var i = 0; i < s.length; i++) {
|
|
41381
|
+
if (s[i] === '\\' && s[i + 1] === '|') {
|
|
41382
|
+
cur += '|';
|
|
41383
|
+
i++;
|
|
41384
|
+
} else if (s[i] === '|') {
|
|
41385
|
+
cells.push(cur.trim());
|
|
41386
|
+
cur = '';
|
|
41387
|
+
} else {
|
|
41388
|
+
cur += s[i];
|
|
41389
|
+
}
|
|
41390
|
+
}
|
|
41391
|
+
cells.push(cur.trim());
|
|
41392
|
+
return cells;
|
|
41393
|
+
}
|
|
41394
|
+
function parseAlignment(sepLine) {
|
|
41395
|
+
return splitTableRow(sepLine).map(function (c) {
|
|
41396
|
+
var left = c.startsWith(':');
|
|
41397
|
+
var right = c.endsWith(':');
|
|
41398
|
+
if (left && right) return 'center';
|
|
41399
|
+
if (right) return 'right';
|
|
41400
|
+
if (left) return 'left';
|
|
41401
|
+
return null;
|
|
41402
|
+
});
|
|
41403
|
+
}
|
|
41404
|
+
function parseFence(lines, i) {
|
|
41405
|
+
var m = FENCE_RE.exec(lines[i]);
|
|
41406
|
+
var marker = m[2][0];
|
|
41407
|
+
var minLen = m[2].length;
|
|
41408
|
+
var stripIndent = m[1].length;
|
|
41409
|
+
var body = [];
|
|
41410
|
+
var j = i + 1;
|
|
41411
|
+
for (; j < lines.length; j++) {
|
|
41412
|
+
var close = FENCE_RE.exec(lines[j]);
|
|
41413
|
+
if (close && close[2][0] === marker && close[2].length >= minLen && !close[3]) {
|
|
41414
|
+
j++;
|
|
41415
|
+
break;
|
|
41416
|
+
}
|
|
41417
|
+
body.push(dedent(lines[j], stripIndent));
|
|
41418
|
+
}
|
|
41419
|
+
// an unterminated fence (mid-stream) still yields a code block
|
|
41420
|
+
return {
|
|
41421
|
+
node: {
|
|
41422
|
+
type: 'code',
|
|
41423
|
+
lang: m[3] || '',
|
|
41424
|
+
text: body.join('\n')
|
|
41425
|
+
},
|
|
41426
|
+
next: j
|
|
41427
|
+
};
|
|
41428
|
+
}
|
|
41429
|
+
function parseQuote(lines, i) {
|
|
41430
|
+
var body = [];
|
|
41431
|
+
var j = i;
|
|
41432
|
+
for (; j < lines.length; j++) {
|
|
41433
|
+
var m = QUOTE_RE.exec(lines[j]);
|
|
41434
|
+
if (m) {
|
|
41435
|
+
body.push(m[1]);
|
|
41436
|
+
continue;
|
|
41437
|
+
}
|
|
41438
|
+
// lazy continuation: plain text directly under a quote line
|
|
41439
|
+
if (!isBlank(lines[j]) && !startsBlock(lines[j]) && body.length && !isBlank(body[body.length - 1])) {
|
|
41440
|
+
body.push(lines[j].trim());
|
|
41441
|
+
continue;
|
|
41442
|
+
}
|
|
41443
|
+
break;
|
|
41444
|
+
}
|
|
41445
|
+
return {
|
|
41446
|
+
node: {
|
|
41447
|
+
type: 'quote',
|
|
41448
|
+
blocks: parseBlocks(body)
|
|
41449
|
+
},
|
|
41450
|
+
next: j
|
|
41451
|
+
};
|
|
41452
|
+
}
|
|
41453
|
+
function parseTable(lines, i) {
|
|
41454
|
+
var head = splitTableRow(lines[i]);
|
|
41455
|
+
var align = parseAlignment(lines[i + 1]);
|
|
41456
|
+
var rows = [];
|
|
41457
|
+
var j = i + 2;
|
|
41458
|
+
for (; j < lines.length; j++) {
|
|
41459
|
+
if (isBlank(lines[j]) || lines[j].indexOf('|') === -1) break;
|
|
41460
|
+
var cells = splitTableRow(lines[j]);
|
|
41461
|
+
while (cells.length < head.length) cells.push('');
|
|
41462
|
+
rows.push(cells.slice(0, head.length).map(parseInline));
|
|
41463
|
+
}
|
|
41464
|
+
return {
|
|
41465
|
+
node: {
|
|
41466
|
+
type: 'table',
|
|
41467
|
+
align: align,
|
|
41468
|
+
head: head.map(parseInline),
|
|
41469
|
+
rows: rows
|
|
41470
|
+
},
|
|
41471
|
+
next: j
|
|
41472
|
+
};
|
|
41473
|
+
}
|
|
41474
|
+
function parseList(lines, i) {
|
|
41475
|
+
var first = matchListItem(lines[i]);
|
|
41476
|
+
var baseIndent = first.indent;
|
|
41477
|
+
var ordered = first.ordered;
|
|
41478
|
+
var items = [];
|
|
41479
|
+
var cur = null;
|
|
41480
|
+
var j = i;
|
|
41481
|
+
while (j < lines.length) {
|
|
41482
|
+
var line = lines[j];
|
|
41483
|
+
if (isBlank(line)) {
|
|
41484
|
+
var k = j + 1;
|
|
41485
|
+
while (k < lines.length && isBlank(lines[k])) k++;
|
|
41486
|
+
if (k >= lines.length) break;
|
|
41487
|
+
var nextItem = matchListItem(lines[k]);
|
|
41488
|
+
var belongs = nextItem && nextItem.indent >= baseIndent && nextItem.ordered === ordered || indentOf(lines[k]) > baseIndent;
|
|
41489
|
+
if (!belongs) break;
|
|
41490
|
+
if (cur) cur.lines.push('');
|
|
41491
|
+
j = k;
|
|
41492
|
+
continue;
|
|
41493
|
+
}
|
|
41494
|
+
var item = matchListItem(line);
|
|
41495
|
+
if (item && item.indent <= baseIndent) {
|
|
41496
|
+
// a sibling item — or a different list starting at the same level
|
|
41497
|
+
if (item.indent < baseIndent || item.ordered !== ordered) break;
|
|
41498
|
+
cur = {
|
|
41499
|
+
lines: [item.text],
|
|
41500
|
+
contentIndent: item.contentIndent
|
|
41501
|
+
};
|
|
41502
|
+
items.push(cur);
|
|
41503
|
+
j++;
|
|
41504
|
+
continue;
|
|
41505
|
+
}
|
|
41506
|
+
if (!cur) break;
|
|
41507
|
+
|
|
41508
|
+
// nested item or indented continuation
|
|
41509
|
+
if (indentOf(line) > baseIndent) {
|
|
41510
|
+
cur.lines.push(dedent(line, cur.contentIndent));
|
|
41511
|
+
j++;
|
|
41512
|
+
continue;
|
|
41513
|
+
}
|
|
41514
|
+
|
|
41515
|
+
// lazy continuation of the current item's paragraph
|
|
41516
|
+
if (startsBlock(line)) break;
|
|
41517
|
+
cur.lines.push(line.trim());
|
|
41518
|
+
j++;
|
|
41519
|
+
}
|
|
41520
|
+
return {
|
|
41521
|
+
node: {
|
|
41522
|
+
type: ordered ? 'ol' : 'ul',
|
|
41523
|
+
start: ordered && first.start !== 1 ? first.start : null,
|
|
41524
|
+
items: items.map(function (it) {
|
|
41525
|
+
return {
|
|
41526
|
+
blocks: parseBlocks(it.lines)
|
|
41527
|
+
};
|
|
41528
|
+
})
|
|
41529
|
+
},
|
|
41530
|
+
next: j
|
|
41531
|
+
};
|
|
41532
|
+
}
|
|
41533
|
+
function parseParagraph(lines, i) {
|
|
41534
|
+
var body = [];
|
|
41535
|
+
var j = i;
|
|
41536
|
+
for (; j < lines.length; j++) {
|
|
41537
|
+
if (isBlank(lines[j])) break;
|
|
41538
|
+
if (j > i && startsBlock(lines[j])) break;
|
|
41539
|
+
if (j > i && lines[j].indexOf('|') !== -1 && j + 1 < lines.length && TABLE_SEP_RE.test(lines[j + 1])) {
|
|
41540
|
+
break;
|
|
41541
|
+
}
|
|
41542
|
+
body.push(lines[j].trim());
|
|
41543
|
+
}
|
|
41544
|
+
return {
|
|
41545
|
+
node: {
|
|
41546
|
+
type: 'p',
|
|
41547
|
+
inline: parseInline(body.join('\n'))
|
|
41548
|
+
},
|
|
41549
|
+
next: j
|
|
41550
|
+
};
|
|
41551
|
+
}
|
|
41552
|
+
|
|
41553
|
+
/**
|
|
41554
|
+
* Parse markdown source into a block AST.
|
|
41555
|
+
* @param {string} src
|
|
41556
|
+
* @returns {Array<object>} block nodes
|
|
41557
|
+
*/
|
|
41558
|
+
function parseMarkdown(src) {
|
|
41559
|
+
if (typeof src !== 'string' || src === '') return [];
|
|
41560
|
+
return parseBlocks(src.replace(/\r\n?/g, '\n').split('\n'));
|
|
41561
|
+
}
|
|
41562
|
+
function parseBlocks(lines) {
|
|
41563
|
+
var blocks = [];
|
|
41564
|
+
var i = 0;
|
|
41565
|
+
while (i < lines.length) {
|
|
41566
|
+
var line = lines[i];
|
|
41567
|
+
if (isBlank(line)) {
|
|
41568
|
+
i++;
|
|
41569
|
+
continue;
|
|
41570
|
+
}
|
|
41571
|
+
if (FENCE_RE.test(line)) {
|
|
41572
|
+
var r = parseFence(lines, i);
|
|
41573
|
+
blocks.push(r.node);
|
|
41574
|
+
i = r.next;
|
|
41575
|
+
continue;
|
|
41576
|
+
}
|
|
41577
|
+
if (HR_RE.test(line)) {
|
|
41578
|
+
blocks.push({
|
|
41579
|
+
type: 'hr'
|
|
41580
|
+
});
|
|
41581
|
+
i++;
|
|
41582
|
+
continue;
|
|
41583
|
+
}
|
|
41584
|
+
var heading = HEADING_RE.exec(line);
|
|
41585
|
+
if (heading) {
|
|
41586
|
+
var text = heading[3].replace(/\s+#+\s*$/, '');
|
|
41587
|
+
blocks.push({
|
|
41588
|
+
type: 'h',
|
|
41589
|
+
level: heading[2].length,
|
|
41590
|
+
inline: parseInline(text)
|
|
41591
|
+
});
|
|
41592
|
+
i++;
|
|
41593
|
+
continue;
|
|
41594
|
+
}
|
|
41595
|
+
if (QUOTE_RE.test(line)) {
|
|
41596
|
+
var _r = parseQuote(lines, i);
|
|
41597
|
+
blocks.push(_r.node);
|
|
41598
|
+
i = _r.next;
|
|
41599
|
+
continue;
|
|
41600
|
+
}
|
|
41601
|
+
if (matchListItem(line)) {
|
|
41602
|
+
var _r2 = parseList(lines, i);
|
|
41603
|
+
// defensive: parseList always consumes at least one line
|
|
41604
|
+
if (_r2.next <= i) {
|
|
41605
|
+
blocks.push({
|
|
41606
|
+
type: 'p',
|
|
41607
|
+
inline: parseInline(line.trim())
|
|
41608
|
+
});
|
|
41609
|
+
i++;
|
|
41610
|
+
continue;
|
|
41611
|
+
}
|
|
41612
|
+
blocks.push(_r2.node);
|
|
41613
|
+
i = _r2.next;
|
|
41614
|
+
continue;
|
|
41615
|
+
}
|
|
41616
|
+
if (line.indexOf('|') !== -1 && i + 1 < lines.length && TABLE_SEP_RE.test(lines[i + 1])) {
|
|
41617
|
+
var _r3 = parseTable(lines, i);
|
|
41618
|
+
blocks.push(_r3.node);
|
|
41619
|
+
i = _r3.next;
|
|
41620
|
+
continue;
|
|
41621
|
+
}
|
|
41622
|
+
var p = parseParagraph(lines, i);
|
|
41623
|
+
if (p.next <= i) {
|
|
41624
|
+
i++;
|
|
41625
|
+
continue;
|
|
41626
|
+
}
|
|
41627
|
+
blocks.push(p.node);
|
|
41628
|
+
i = p.next;
|
|
41629
|
+
}
|
|
41630
|
+
return blocks;
|
|
41631
|
+
}
|
|
41632
|
+
|
|
41633
|
+
/* ------------------------------------------------------------------ */
|
|
41634
|
+
/* Inline parsing */
|
|
41635
|
+
/* ------------------------------------------------------------------ */
|
|
41636
|
+
|
|
41637
|
+
var ESCAPABLE = '\\`*_~[]()#+-.!>|';
|
|
41638
|
+
function matchLink(text, start) {
|
|
41639
|
+
var depth = 0;
|
|
41640
|
+
var j = start;
|
|
41641
|
+
for (; j < text.length; j++) {
|
|
41642
|
+
var ch = text[j];
|
|
41643
|
+
if (ch === '\\') {
|
|
41644
|
+
j++;
|
|
41645
|
+
continue;
|
|
41646
|
+
}
|
|
41647
|
+
if (ch === '\n') return null;
|
|
41648
|
+
if (ch === '[') depth++;else if (ch === ']') {
|
|
41649
|
+
depth--;
|
|
41650
|
+
if (depth === 0) break;
|
|
41651
|
+
}
|
|
41652
|
+
}
|
|
41653
|
+
if (j >= text.length || text[j] !== ']' || text[j + 1] !== '(') return null;
|
|
41654
|
+
var label = text.slice(start + 1, j);
|
|
41655
|
+
var k = j + 2;
|
|
41656
|
+
var pdepth = 1;
|
|
41657
|
+
var dest = '';
|
|
41658
|
+
for (; k < text.length; k++) {
|
|
41659
|
+
var _ch = text[k];
|
|
41660
|
+
if (_ch === '\\') {
|
|
41661
|
+
dest += text[k + 1] || '';
|
|
41662
|
+
k++;
|
|
41663
|
+
continue;
|
|
41664
|
+
}
|
|
41665
|
+
if (_ch === '\n') return null;
|
|
41666
|
+
if (_ch === '(') pdepth++;else if (_ch === ')') {
|
|
41667
|
+
pdepth--;
|
|
41668
|
+
if (pdepth === 0) break;
|
|
41669
|
+
}
|
|
41670
|
+
dest += _ch;
|
|
41671
|
+
}
|
|
41672
|
+
if (k >= text.length || pdepth !== 0) return null;
|
|
41673
|
+
dest = dest.trim();
|
|
41674
|
+
// strip an optional title: (/url "Title")
|
|
41675
|
+
var sp = dest.search(/\s/);
|
|
41676
|
+
var href = sp === -1 ? dest : dest.slice(0, sp);
|
|
41677
|
+
return {
|
|
41678
|
+
label: label,
|
|
41679
|
+
href: href,
|
|
41680
|
+
end: k + 1
|
|
41681
|
+
};
|
|
41682
|
+
}
|
|
41683
|
+
|
|
41684
|
+
/** Length of the run of identical delimiter chars starting at `i`. */
|
|
41685
|
+
function runLength(text, i) {
|
|
41686
|
+
var c = text[i];
|
|
41687
|
+
var n = 0;
|
|
41688
|
+
while (i + n < text.length && text[i + n] === c) n++;
|
|
41689
|
+
return n;
|
|
41690
|
+
}
|
|
41691
|
+
function matchEmphasis(text, start) {
|
|
41692
|
+
var c = text[start];
|
|
41693
|
+
var openRun = runLength(text, start);
|
|
41694
|
+
if (c === '~') {
|
|
41695
|
+
// only ~~strike~~
|
|
41696
|
+
if (openRun < 2) return null;
|
|
41697
|
+
return matchDelimited(text, start, '~~', 'del');
|
|
41698
|
+
}
|
|
41699
|
+
|
|
41700
|
+
// ***both*** — strong wrapping the inner single-delimiter run
|
|
41701
|
+
if (openRun >= 3) {
|
|
41702
|
+
var triple = c.repeat(3);
|
|
41703
|
+
var close = text.indexOf(triple, start + openRun);
|
|
41704
|
+
if (close === -1) return null;
|
|
41705
|
+
return {
|
|
41706
|
+
tag: 'strong',
|
|
41707
|
+
content: c + text.slice(start + 3, close) + c,
|
|
41708
|
+
end: close + 3
|
|
41709
|
+
};
|
|
41710
|
+
}
|
|
41711
|
+
if (c === '_') {
|
|
41712
|
+
var before = start > 0 ? text[start - 1] : '';
|
|
41713
|
+
if (before && /\w/.test(before)) return null; // snake_case
|
|
41714
|
+
}
|
|
41715
|
+
return openRun === 2 ? matchDelimited(text, start, c + c, 'strong') : matchDelimited(text, start, c, 'em');
|
|
41716
|
+
}
|
|
41717
|
+
function matchDelimited(text, start, delim, tag) {
|
|
41718
|
+
var c = delim[0];
|
|
41719
|
+
var single = delim.length === 1;
|
|
41720
|
+
var after = text[start + delim.length];
|
|
41721
|
+
if (after === undefined || /\s/.test(after)) return null;
|
|
41722
|
+
var j = start + delim.length;
|
|
41723
|
+
while (j < text.length) {
|
|
41724
|
+
var k = text.indexOf(delim, j);
|
|
41725
|
+
if (k === -1) return null;
|
|
41726
|
+
if (k === start + delim.length) return null; // empty content
|
|
41727
|
+
|
|
41728
|
+
if (/\s/.test(text[k - 1])) {
|
|
41729
|
+
j = k + delim.length;
|
|
41730
|
+
continue;
|
|
41731
|
+
}
|
|
41732
|
+
|
|
41733
|
+
// a single-char delimiter must not latch onto part of a longer run
|
|
41734
|
+
// ("*a **b** c*" — the closer is the final *, not the one in "**")
|
|
41735
|
+
if (single && (text[k - 1] === c || text[k + 1] === c)) {
|
|
41736
|
+
var end = k;
|
|
41737
|
+
while (end < text.length && text[end] === c) end++;
|
|
41738
|
+
j = end;
|
|
41739
|
+
continue;
|
|
41740
|
+
}
|
|
41741
|
+
if (c === '_') {
|
|
41742
|
+
var next = text[k + delim.length];
|
|
41743
|
+
if (next && /\w/.test(next)) {
|
|
41744
|
+
j = k + delim.length;
|
|
41745
|
+
continue;
|
|
41746
|
+
}
|
|
41747
|
+
}
|
|
41748
|
+
return {
|
|
41749
|
+
tag: tag,
|
|
41750
|
+
content: text.slice(start + delim.length, k),
|
|
41751
|
+
end: k + delim.length
|
|
41752
|
+
};
|
|
41753
|
+
}
|
|
41754
|
+
return null;
|
|
41755
|
+
}
|
|
41756
|
+
|
|
41757
|
+
/**
|
|
41758
|
+
* Parse a run of inline markdown into inline nodes.
|
|
41759
|
+
* @param {string} text
|
|
41760
|
+
* @returns {Array<object>}
|
|
41761
|
+
*/
|
|
41762
|
+
function parseInline(text) {
|
|
41763
|
+
var out = [];
|
|
41764
|
+
var buf = '';
|
|
41765
|
+
var flush = function flush() {
|
|
41766
|
+
if (buf) {
|
|
41767
|
+
out.push({
|
|
41768
|
+
type: 'text',
|
|
41769
|
+
value: buf
|
|
41770
|
+
});
|
|
41771
|
+
buf = '';
|
|
41772
|
+
}
|
|
41773
|
+
};
|
|
41774
|
+
var i = 0;
|
|
41775
|
+
while (i < text.length) {
|
|
41776
|
+
var c = text[i];
|
|
41777
|
+
if (c === '\\' && i + 1 < text.length && ESCAPABLE.indexOf(text[i + 1]) !== -1) {
|
|
41778
|
+
buf += text[i + 1];
|
|
41779
|
+
i += 2;
|
|
41780
|
+
continue;
|
|
41781
|
+
}
|
|
41782
|
+
if (c === '\n') {
|
|
41783
|
+
flush();
|
|
41784
|
+
out.push({
|
|
41785
|
+
type: 'br'
|
|
41786
|
+
});
|
|
41787
|
+
i++;
|
|
41788
|
+
continue;
|
|
41789
|
+
}
|
|
41790
|
+
if (c === '`') {
|
|
41791
|
+
var m = /^(`+)([\s\S]*?)\1(?!`)/.exec(text.slice(i));
|
|
41792
|
+
if (m && m[2].trim()) {
|
|
41793
|
+
flush();
|
|
41794
|
+
out.push({
|
|
41795
|
+
type: 'code',
|
|
41796
|
+
value: m[2].replace(/^ | $/g, '')
|
|
41797
|
+
});
|
|
41798
|
+
i += m[0].length;
|
|
41799
|
+
continue;
|
|
41800
|
+
}
|
|
41801
|
+
}
|
|
41802
|
+
if (c === '!' && text[i + 1] === '[') {
|
|
41803
|
+
var img = matchLink(text, i + 1);
|
|
41804
|
+
if (img) {
|
|
41805
|
+
flush();
|
|
41806
|
+
out.push({
|
|
41807
|
+
type: 'image',
|
|
41808
|
+
src: img.href,
|
|
41809
|
+
alt: img.label
|
|
41810
|
+
});
|
|
41811
|
+
i = img.end;
|
|
41812
|
+
continue;
|
|
41813
|
+
}
|
|
41814
|
+
}
|
|
41815
|
+
if (c === '[') {
|
|
41816
|
+
var link = matchLink(text, i);
|
|
41817
|
+
if (link) {
|
|
41818
|
+
flush();
|
|
41819
|
+
out.push({
|
|
41820
|
+
type: 'link',
|
|
41821
|
+
href: link.href,
|
|
41822
|
+
children: parseInline(link.label)
|
|
41823
|
+
});
|
|
41824
|
+
i = link.end;
|
|
41825
|
+
continue;
|
|
41826
|
+
}
|
|
41827
|
+
}
|
|
41828
|
+
if (c === '*' || c === '_' || c === '~') {
|
|
41829
|
+
var em = matchEmphasis(text, i);
|
|
41830
|
+
if (em) {
|
|
41831
|
+
flush();
|
|
41832
|
+
out.push({
|
|
41833
|
+
type: em.tag,
|
|
41834
|
+
children: parseInline(em.content)
|
|
41835
|
+
});
|
|
41836
|
+
i = em.end;
|
|
41837
|
+
continue;
|
|
41838
|
+
}
|
|
41839
|
+
}
|
|
41840
|
+
if ((c === 'h' || c === 'w') && /^(https?:\/\/|www\.)/.test(text.slice(i))) {
|
|
41841
|
+
var _m = /^(?:https?:\/\/|www\.)[^\s<>"'`\]]+/.exec(text.slice(i));
|
|
41842
|
+
if (_m) {
|
|
41843
|
+
var raw = _m[0].replace(/[.,;:!?)\]]+$/, '');
|
|
41844
|
+
flush();
|
|
41845
|
+
out.push({
|
|
41846
|
+
type: 'link',
|
|
41847
|
+
href: raw.startsWith('www.') ? "https://".concat(raw) : raw,
|
|
41848
|
+
children: [{
|
|
41849
|
+
type: 'text',
|
|
41850
|
+
value: raw
|
|
41851
|
+
}]
|
|
41852
|
+
});
|
|
41853
|
+
i += raw.length;
|
|
41854
|
+
continue;
|
|
41855
|
+
}
|
|
41856
|
+
}
|
|
41857
|
+
buf += c;
|
|
41858
|
+
i++;
|
|
41859
|
+
}
|
|
41860
|
+
flush();
|
|
41861
|
+
return out;
|
|
41862
|
+
}
|
|
41863
|
+
|
|
41864
|
+
/* ------------------------------------------------------------------ */
|
|
41865
|
+
/* URL safety */
|
|
41866
|
+
/* ------------------------------------------------------------------ */
|
|
41867
|
+
|
|
41868
|
+
var SAFE_SCHEME = /^(https?|mailto|tel):/i;
|
|
41869
|
+
|
|
41870
|
+
/**
|
|
41871
|
+
* Returns the href if it is safe to put on an anchor, otherwise null.
|
|
41872
|
+
* Blocks javascript:, data:, vbscript: and anything else exotic.
|
|
41873
|
+
*/
|
|
41874
|
+
function safeHref(href) {
|
|
41875
|
+
if (typeof href !== 'string') return null;
|
|
41876
|
+
var s = href.trim();
|
|
41877
|
+
if (!s) return null;
|
|
41878
|
+
// control characters are used to smuggle "java\nscript:"
|
|
41879
|
+
var clean = s.replace(/[-\s]/g, '');
|
|
41880
|
+
if (/^(\/|#|\.\/|\.\.\/)/.test(clean)) return s; // relative
|
|
41881
|
+
if (SAFE_SCHEME.test(clean)) return s;
|
|
41882
|
+
if (clean.indexOf(':') === -1) return s; // bare host / path
|
|
41883
|
+
return null;
|
|
41884
|
+
}
|
|
41885
|
+
|
|
41886
|
+
/* ------------------------------------------------------------------ */
|
|
41887
|
+
/* DOM rendering */
|
|
41888
|
+
/* ------------------------------------------------------------------ */
|
|
41889
|
+
|
|
41890
|
+
function renderInlineNodes(nodes, parent, doc) {
|
|
41891
|
+
var _iterator = _createForOfIteratorHelper(nodes),
|
|
41892
|
+
_step;
|
|
41893
|
+
try {
|
|
41894
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
41895
|
+
var node = _step.value;
|
|
41896
|
+
switch (node.type) {
|
|
41897
|
+
case 'text':
|
|
41898
|
+
parent.appendChild(doc.createTextNode(node.value));
|
|
41899
|
+
break;
|
|
41900
|
+
case 'br':
|
|
41901
|
+
parent.appendChild(doc.createElement('br'));
|
|
41902
|
+
break;
|
|
41903
|
+
case 'code':
|
|
41904
|
+
{
|
|
41905
|
+
var el = doc.createElement('code');
|
|
41906
|
+
el.textContent = node.value;
|
|
41907
|
+
parent.appendChild(el);
|
|
41908
|
+
break;
|
|
41909
|
+
}
|
|
41910
|
+
case 'strong':
|
|
41911
|
+
case 'em':
|
|
41912
|
+
case 'del':
|
|
41913
|
+
{
|
|
41914
|
+
var _el = doc.createElement(node.type);
|
|
41915
|
+
renderInlineNodes(node.children, _el, doc);
|
|
41916
|
+
parent.appendChild(_el);
|
|
41917
|
+
break;
|
|
41918
|
+
}
|
|
41919
|
+
case 'link':
|
|
41920
|
+
{
|
|
41921
|
+
var href = safeHref(node.href);
|
|
41922
|
+
if (!href) {
|
|
41923
|
+
renderInlineNodes(node.children, parent, doc);
|
|
41924
|
+
break;
|
|
41925
|
+
}
|
|
41926
|
+
var _el2 = doc.createElement('a');
|
|
41927
|
+
_el2.setAttribute('href', href);
|
|
41928
|
+
_el2.setAttribute('target', '_blank');
|
|
41929
|
+
_el2.setAttribute('rel', 'noopener noreferrer nofollow');
|
|
41930
|
+
renderInlineNodes(node.children, _el2, doc);
|
|
41931
|
+
parent.appendChild(_el2);
|
|
41932
|
+
break;
|
|
41933
|
+
}
|
|
41934
|
+
case 'image':
|
|
41935
|
+
{
|
|
41936
|
+
var src = safeHref(node.src);
|
|
41937
|
+
if (!src) {
|
|
41938
|
+
parent.appendChild(doc.createTextNode(node.alt || ''));
|
|
41939
|
+
break;
|
|
41940
|
+
}
|
|
41941
|
+
var _el3 = doc.createElement('img');
|
|
41942
|
+
_el3.setAttribute('src', src);
|
|
41943
|
+
_el3.setAttribute('alt', node.alt || '');
|
|
41944
|
+
_el3.setAttribute('loading', 'lazy');
|
|
41945
|
+
_el3.className = 'md-img';
|
|
41946
|
+
parent.appendChild(_el3);
|
|
41947
|
+
break;
|
|
41948
|
+
}
|
|
41949
|
+
default:
|
|
41950
|
+
break;
|
|
41951
|
+
}
|
|
41952
|
+
}
|
|
41953
|
+
} catch (err) {
|
|
41954
|
+
_iterator.e(err);
|
|
41955
|
+
} finally {
|
|
41956
|
+
_iterator.f();
|
|
41957
|
+
}
|
|
41958
|
+
}
|
|
41959
|
+
function renderBlockNodes(blocks, parent, doc) {
|
|
41960
|
+
var _iterator2 = _createForOfIteratorHelper(blocks),
|
|
41961
|
+
_step2;
|
|
41962
|
+
try {
|
|
41963
|
+
var _loop = function _loop() {
|
|
41964
|
+
var block = _step2.value;
|
|
41965
|
+
switch (block.type) {
|
|
41966
|
+
case 'p':
|
|
41967
|
+
{
|
|
41968
|
+
var el = doc.createElement('p');
|
|
41969
|
+
renderInlineNodes(block.inline, el, doc);
|
|
41970
|
+
parent.appendChild(el);
|
|
41971
|
+
break;
|
|
41972
|
+
}
|
|
41973
|
+
case 'h':
|
|
41974
|
+
{
|
|
41975
|
+
var _el4 = doc.createElement("h".concat(Math.min(block.level + 2, 6)));
|
|
41976
|
+
_el4.className = "md-h md-h".concat(block.level);
|
|
41977
|
+
renderInlineNodes(block.inline, _el4, doc);
|
|
41978
|
+
parent.appendChild(_el4);
|
|
41979
|
+
break;
|
|
41980
|
+
}
|
|
41981
|
+
case 'hr':
|
|
41982
|
+
parent.appendChild(doc.createElement('hr'));
|
|
41983
|
+
break;
|
|
41984
|
+
case 'code':
|
|
41985
|
+
{
|
|
41986
|
+
var pre = doc.createElement('pre');
|
|
41987
|
+
var code = doc.createElement('code');
|
|
41988
|
+
if (block.lang) code.className = "language-".concat(block.lang.replace(/[^\w+-]/g, ''));
|
|
41989
|
+
code.textContent = block.text;
|
|
41990
|
+
pre.appendChild(code);
|
|
41991
|
+
parent.appendChild(pre);
|
|
41992
|
+
break;
|
|
41993
|
+
}
|
|
41994
|
+
case 'quote':
|
|
41995
|
+
{
|
|
41996
|
+
var _el5 = doc.createElement('blockquote');
|
|
41997
|
+
renderBlockNodes(block.blocks, _el5, doc);
|
|
41998
|
+
parent.appendChild(_el5);
|
|
41999
|
+
break;
|
|
42000
|
+
}
|
|
42001
|
+
case 'ul':
|
|
42002
|
+
case 'ol':
|
|
42003
|
+
{
|
|
42004
|
+
var list = doc.createElement(block.type);
|
|
42005
|
+
if (block.type === 'ol' && block.start != null) list.setAttribute('start', String(block.start));
|
|
42006
|
+
var _iterator3 = _createForOfIteratorHelper(block.items),
|
|
42007
|
+
_step3;
|
|
42008
|
+
try {
|
|
42009
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
42010
|
+
var item = _step3.value;
|
|
42011
|
+
var li = doc.createElement('li');
|
|
42012
|
+
// tight item: a lone paragraph renders straight into the <li>
|
|
42013
|
+
if (item.blocks.length === 1 && item.blocks[0].type === 'p') {
|
|
42014
|
+
renderInlineNodes(item.blocks[0].inline, li, doc);
|
|
42015
|
+
} else {
|
|
42016
|
+
renderBlockNodes(item.blocks, li, doc);
|
|
42017
|
+
}
|
|
42018
|
+
list.appendChild(li);
|
|
42019
|
+
}
|
|
42020
|
+
} catch (err) {
|
|
42021
|
+
_iterator3.e(err);
|
|
42022
|
+
} finally {
|
|
42023
|
+
_iterator3.f();
|
|
42024
|
+
}
|
|
42025
|
+
parent.appendChild(list);
|
|
42026
|
+
break;
|
|
42027
|
+
}
|
|
42028
|
+
case 'table':
|
|
42029
|
+
{
|
|
42030
|
+
var wrap = doc.createElement('div');
|
|
42031
|
+
wrap.className = 'md-table-wrap';
|
|
42032
|
+
var table = doc.createElement('table');
|
|
42033
|
+
var thead = doc.createElement('thead');
|
|
42034
|
+
var hrow = doc.createElement('tr');
|
|
42035
|
+
block.head.forEach(function (cell, idx) {
|
|
42036
|
+
var th = doc.createElement('th');
|
|
42037
|
+
if (block.align[idx]) th.style.textAlign = block.align[idx];
|
|
42038
|
+
renderInlineNodes(cell, th, doc);
|
|
42039
|
+
hrow.appendChild(th);
|
|
42040
|
+
});
|
|
42041
|
+
thead.appendChild(hrow);
|
|
42042
|
+
table.appendChild(thead);
|
|
42043
|
+
var tbody = doc.createElement('tbody');
|
|
42044
|
+
var _iterator4 = _createForOfIteratorHelper(block.rows),
|
|
42045
|
+
_step4;
|
|
42046
|
+
try {
|
|
42047
|
+
var _loop2 = function _loop2() {
|
|
42048
|
+
var row = _step4.value;
|
|
42049
|
+
var tr = doc.createElement('tr');
|
|
42050
|
+
row.forEach(function (cell, idx) {
|
|
42051
|
+
var td = doc.createElement('td');
|
|
42052
|
+
if (block.align[idx]) td.style.textAlign = block.align[idx];
|
|
42053
|
+
renderInlineNodes(cell, td, doc);
|
|
42054
|
+
tr.appendChild(td);
|
|
42055
|
+
});
|
|
42056
|
+
tbody.appendChild(tr);
|
|
42057
|
+
};
|
|
42058
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
42059
|
+
_loop2();
|
|
42060
|
+
}
|
|
42061
|
+
} catch (err) {
|
|
42062
|
+
_iterator4.e(err);
|
|
42063
|
+
} finally {
|
|
42064
|
+
_iterator4.f();
|
|
42065
|
+
}
|
|
42066
|
+
table.appendChild(tbody);
|
|
42067
|
+
wrap.appendChild(table);
|
|
42068
|
+
parent.appendChild(wrap);
|
|
42069
|
+
break;
|
|
42070
|
+
}
|
|
42071
|
+
default:
|
|
42072
|
+
break;
|
|
42073
|
+
}
|
|
42074
|
+
};
|
|
42075
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
42076
|
+
_loop();
|
|
42077
|
+
}
|
|
42078
|
+
} catch (err) {
|
|
42079
|
+
_iterator2.e(err);
|
|
42080
|
+
} finally {
|
|
42081
|
+
_iterator2.f();
|
|
42082
|
+
}
|
|
42083
|
+
}
|
|
42084
|
+
|
|
42085
|
+
/**
|
|
42086
|
+
* Replace the contents of `el` with the rendered markdown of `text`.
|
|
42087
|
+
* Safe to call repeatedly with a growing buffer (streaming).
|
|
42088
|
+
*
|
|
42089
|
+
* @param {Element} el target element (emptied first)
|
|
42090
|
+
* @param {string} text markdown source
|
|
42091
|
+
*/
|
|
42092
|
+
function renderMarkdownInto(el, text) {
|
|
42093
|
+
if (!el) return;
|
|
42094
|
+
var doc = el.ownerDocument || document;
|
|
42095
|
+
while (el.firstChild) el.removeChild(el.firstChild);
|
|
42096
|
+
if (typeof text !== 'string' || text === '') return;
|
|
42097
|
+
var blocks;
|
|
42098
|
+
try {
|
|
42099
|
+
blocks = parseMarkdown(text);
|
|
42100
|
+
} catch (err) {
|
|
42101
|
+
// never let a parser bug swallow the agent's answer
|
|
42102
|
+
el.textContent = text;
|
|
42103
|
+
return;
|
|
42104
|
+
}
|
|
42105
|
+
var frag = doc.createDocumentFragment();
|
|
42106
|
+
renderBlockNodes(blocks, frag, doc);
|
|
42107
|
+
|
|
42108
|
+
// A response with no renderable block (e.g. only whitespace) falls back to text.
|
|
42109
|
+
if (!frag.firstChild) {
|
|
42110
|
+
el.textContent = text;
|
|
42111
|
+
return;
|
|
42112
|
+
}
|
|
42113
|
+
el.appendChild(frag);
|
|
42114
|
+
}
|
|
42115
|
+
|
|
42116
|
+
/***/ }),
|
|
42117
|
+
|
|
41009
42118
|
/***/ "./src/widget/voice/desktop.js":
|
|
41010
42119
|
/*!*************************************!*\
|
|
41011
42120
|
!*** ./src/widget/voice/desktop.js ***!
|