@dabalabs/agent 0.0.2-beta → 0.0.4-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -3
- package/dist/chunk-3BQ6LE6X.cjs +222 -0
- package/dist/chunk-3BQ6LE6X.cjs.map +1 -0
- package/dist/{chunk-CMHPVBEF.js → chunk-ETI4LRM7.js} +841 -100
- package/dist/chunk-ETI4LRM7.js.map +1 -0
- package/dist/chunk-TYOHYQDK.js +220 -0
- package/dist/chunk-TYOHYQDK.js.map +1 -0
- package/dist/{chunk-IMPMGYCG.cjs → chunk-VAIC5ACS.cjs} +841 -99
- package/dist/chunk-VAIC5ACS.cjs.map +1 -0
- package/dist/custom-element.cjs +4 -4
- package/dist/custom-element.d.cts +191 -2
- package/dist/custom-element.d.ts +191 -2
- package/dist/custom-element.js +2 -2
- package/dist/daba-agent.cjs +5 -14
- package/dist/daba-agent.d.cts +2 -4
- package/dist/daba-agent.d.ts +2 -4
- package/dist/daba-agent.js +2 -3
- package/dist/daba-agent.min.js +141 -36
- package/dist/daba-agent.min.js.map +1 -1
- package/dist/react.cjs +41 -14
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +38 -2
- package/dist/react.js.map +1 -1
- package/dist/{types-hdR_wQ1B.d.cts → types-BQRgqD4n.d.cts} +70 -4
- package/dist/{types-hdR_wQ1B.d.ts → types-BQRgqD4n.d.ts} +70 -4
- package/package.json +1 -1
- package/dist/chunk-7ENX2QZK.js +0 -193
- package/dist/chunk-7ENX2QZK.js.map +0 -1
- package/dist/chunk-CMHPVBEF.js.map +0 -1
- package/dist/chunk-GCU5OBSZ.js +0 -40
- package/dist/chunk-GCU5OBSZ.js.map +0 -1
- package/dist/chunk-HJPH4GNS.cjs +0 -196
- package/dist/chunk-HJPH4GNS.cjs.map +0 -1
- package/dist/chunk-IMPMGYCG.cjs.map +0 -1
- package/dist/chunk-JQMJMSFT.cjs +0 -46
- package/dist/chunk-JQMJMSFT.cjs.map +0 -1
- package/dist/custom-element-BZAUI4Dc.d.cts +0 -121
- package/dist/custom-element-PL2IXpG2.d.ts +0 -121
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
// src/utils/css-length.ts
|
|
2
|
+
var UNIT = /^-?(?:\d+\.?\d*|\.\d+)(?:px|rem|em|%|vh|vw|dvh|dvw|svh|lvh|ch|pt|cm|mm|in)$/i;
|
|
3
|
+
var BARE_NUMBER = /^-?(?:\d+\.?\d*|\.\d+)$/;
|
|
4
|
+
var FUNCTION = /^(?:calc|min|max|clamp)\((?:[^;{}()]|\([^;{}()]*\))*\)$/i;
|
|
5
|
+
function cssLength(value, allowFunctions = true) {
|
|
6
|
+
if (value === null || value === void 0) return null;
|
|
7
|
+
const raw = String(value).trim();
|
|
8
|
+
if (!raw) return null;
|
|
9
|
+
if (BARE_NUMBER.test(raw)) return `${raw}px`;
|
|
10
|
+
if (UNIT.test(raw)) return raw;
|
|
11
|
+
if (allowFunctions && FUNCTION.test(raw)) return raw;
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
1
15
|
// src/api/agent-api.ts
|
|
2
16
|
var DabaFetchError = class extends Error {
|
|
3
17
|
constructor(dabaError, cause) {
|
|
@@ -292,6 +306,7 @@ async function sendChatTurn(gatewayUrl, projectId, apiKey, body) {
|
|
|
292
306
|
// src/voice/live-transport.ts
|
|
293
307
|
var DATA_CHANNEL = "oai-events";
|
|
294
308
|
var ICE_TIMEOUT_MS = 2e3;
|
|
309
|
+
var TURN_END_MS = 3500;
|
|
295
310
|
var LiveTransport = class {
|
|
296
311
|
constructor(options) {
|
|
297
312
|
this.options = options;
|
|
@@ -300,6 +315,8 @@ var LiveTransport = class {
|
|
|
300
315
|
this.micStream = null;
|
|
301
316
|
this.audioEl = null;
|
|
302
317
|
this.stopped = false;
|
|
318
|
+
this.turnTimers = {};
|
|
319
|
+
this.openTurns = /* @__PURE__ */ new Set();
|
|
303
320
|
}
|
|
304
321
|
get isActive() {
|
|
305
322
|
return this.pc !== null && !this.stopped;
|
|
@@ -402,21 +419,28 @@ var LiveTransport = class {
|
|
|
402
419
|
} catch {
|
|
403
420
|
return;
|
|
404
421
|
}
|
|
422
|
+
this.handleEvent(msg);
|
|
423
|
+
}
|
|
424
|
+
handleEvent(msg) {
|
|
425
|
+
if (msg.type === "response.event") {
|
|
426
|
+
const inner = msg.event;
|
|
427
|
+
if (inner && typeof inner === "object") this.handleEvent(inner);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
405
430
|
const { handlers } = this.options;
|
|
406
431
|
switch (msg.type) {
|
|
407
432
|
case "session.input_transcript.delta":
|
|
408
|
-
this.
|
|
433
|
+
this.onDelta("user", msg);
|
|
409
434
|
break;
|
|
410
435
|
case "session.input_transcript.done":
|
|
411
|
-
this.
|
|
436
|
+
this.endTurn("user");
|
|
412
437
|
break;
|
|
413
438
|
case "session.output_transcript.delta":
|
|
414
439
|
handlers.onStatus("speaking");
|
|
415
|
-
this.
|
|
440
|
+
this.onDelta("agent", msg);
|
|
416
441
|
break;
|
|
417
442
|
case "session.output_transcript.done":
|
|
418
|
-
this.
|
|
419
|
-
handlers.onStatus("listening");
|
|
443
|
+
this.endTurn("agent");
|
|
420
444
|
break;
|
|
421
445
|
case "response.output_item.done":
|
|
422
446
|
this.emitToolCall(msg);
|
|
@@ -431,6 +455,20 @@ var LiveTransport = class {
|
|
|
431
455
|
}
|
|
432
456
|
}
|
|
433
457
|
}
|
|
458
|
+
onDelta(role, msg) {
|
|
459
|
+
this.endTurn(role === "user" ? "agent" : "user");
|
|
460
|
+
this.emitTranscript(role, msg, false);
|
|
461
|
+
this.openTurns.add(role);
|
|
462
|
+
window.clearTimeout(this.turnTimers[role]);
|
|
463
|
+
this.turnTimers[role] = window.setTimeout(() => this.endTurn(role), TURN_END_MS);
|
|
464
|
+
}
|
|
465
|
+
endTurn(role) {
|
|
466
|
+
window.clearTimeout(this.turnTimers[role]);
|
|
467
|
+
this.turnTimers[role] = void 0;
|
|
468
|
+
if (!this.openTurns.delete(role)) return;
|
|
469
|
+
this.options.handlers.onTranscript(role, "", true);
|
|
470
|
+
if (role === "agent") this.options.handlers.onStatus("listening");
|
|
471
|
+
}
|
|
434
472
|
emitTranscript(role, msg, final) {
|
|
435
473
|
const text = msg.delta ?? msg.transcript ?? msg.text;
|
|
436
474
|
if (!text && !final) return;
|
|
@@ -451,6 +489,10 @@ var LiveTransport = class {
|
|
|
451
489
|
teardown() {
|
|
452
490
|
if (this.stopped) return;
|
|
453
491
|
this.stopped = true;
|
|
492
|
+
window.clearTimeout(this.turnTimers.user);
|
|
493
|
+
window.clearTimeout(this.turnTimers.agent);
|
|
494
|
+
this.turnTimers = {};
|
|
495
|
+
this.openTurns.clear();
|
|
454
496
|
this.channel?.close();
|
|
455
497
|
this.channel = null;
|
|
456
498
|
this.micStream?.getTracks().forEach((track) => track.stop());
|
|
@@ -581,8 +623,8 @@ function labelForField(el) {
|
|
|
581
623
|
}
|
|
582
624
|
const closestLabel = el.closest("label");
|
|
583
625
|
if (closestLabel && closestLabel.textContent) return cleanText(closestLabel.textContent);
|
|
584
|
-
const
|
|
585
|
-
if (
|
|
626
|
+
const ariaLabel2 = el.getAttribute("aria-label");
|
|
627
|
+
if (ariaLabel2) return cleanText(ariaLabel2);
|
|
586
628
|
const placeholder = el.getAttribute("placeholder");
|
|
587
629
|
if (placeholder) return cleanText(placeholder);
|
|
588
630
|
const name = el.getAttribute("name");
|
|
@@ -644,8 +686,8 @@ function labelForField2(el) {
|
|
|
644
686
|
}
|
|
645
687
|
const closestLabel = el.closest("label");
|
|
646
688
|
if (closestLabel && closestLabel.textContent) return cleanText2(closestLabel.textContent);
|
|
647
|
-
const
|
|
648
|
-
if (
|
|
689
|
+
const ariaLabel2 = el.getAttribute("aria-label");
|
|
690
|
+
if (ariaLabel2) return cleanText2(ariaLabel2);
|
|
649
691
|
const placeholder = el.getAttribute("placeholder");
|
|
650
692
|
if (placeholder) return cleanText2(placeholder);
|
|
651
693
|
const name = el.getAttribute("name");
|
|
@@ -1084,16 +1126,22 @@ var MAX_TRANSCRIPT_BYTES = 96 * 1024;
|
|
|
1084
1126
|
function transcriptKey(projectId, conversationId) {
|
|
1085
1127
|
return `${TRANSCRIPT_KEY_PREFIX}${projectId}:${conversationId}`;
|
|
1086
1128
|
}
|
|
1129
|
+
function boundTranscript(messages) {
|
|
1130
|
+
let slice = messages.slice(-40);
|
|
1131
|
+
let raw = JSON.stringify(slice);
|
|
1132
|
+
while (raw.length > MAX_TRANSCRIPT_BYTES && slice.length > 1) {
|
|
1133
|
+
slice = slice.slice(1);
|
|
1134
|
+
raw = JSON.stringify(slice);
|
|
1135
|
+
}
|
|
1136
|
+
return slice;
|
|
1137
|
+
}
|
|
1087
1138
|
function persistTranscript(projectId, conversationId, messages) {
|
|
1088
1139
|
if (typeof sessionStorage === "undefined") return;
|
|
1089
|
-
let slice = messages.slice(-40);
|
|
1090
1140
|
try {
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
}
|
|
1096
|
-
sessionStorage.setItem(transcriptKey(projectId, conversationId), raw);
|
|
1141
|
+
sessionStorage.setItem(
|
|
1142
|
+
transcriptKey(projectId, conversationId),
|
|
1143
|
+
JSON.stringify(boundTranscript(messages))
|
|
1144
|
+
);
|
|
1097
1145
|
} catch {
|
|
1098
1146
|
}
|
|
1099
1147
|
}
|
|
@@ -1118,6 +1166,110 @@ function clearTranscript(projectId, conversationId) {
|
|
|
1118
1166
|
} catch {
|
|
1119
1167
|
}
|
|
1120
1168
|
}
|
|
1169
|
+
var HISTORY_INDEX_PREFIX = "daba-agent:history:";
|
|
1170
|
+
var HISTORY_BODY_PREFIX = "daba-agent:history-body:";
|
|
1171
|
+
var MAX_CONVERSATIONS = 20;
|
|
1172
|
+
var MAX_HISTORY_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
1173
|
+
var MAX_TITLE_CHARS = 60;
|
|
1174
|
+
function indexKey(projectId) {
|
|
1175
|
+
return HISTORY_INDEX_PREFIX + projectId;
|
|
1176
|
+
}
|
|
1177
|
+
function bodyKey(projectId, conversationId) {
|
|
1178
|
+
return `${HISTORY_BODY_PREFIX}${projectId}:${conversationId}`;
|
|
1179
|
+
}
|
|
1180
|
+
function deriveTitle(messages, fallback) {
|
|
1181
|
+
const first = messages.find((m) => m.role === "user" && m.text.trim());
|
|
1182
|
+
const text = first?.text.trim().replace(/\s+/g, " ") ?? "";
|
|
1183
|
+
if (!text) return fallback;
|
|
1184
|
+
const chars = [...text];
|
|
1185
|
+
return chars.length > MAX_TITLE_CHARS ? `${chars.slice(0, MAX_TITLE_CHARS).join("")}\u2026` : text;
|
|
1186
|
+
}
|
|
1187
|
+
function readIndex(projectId) {
|
|
1188
|
+
if (typeof localStorage === "undefined") return [];
|
|
1189
|
+
try {
|
|
1190
|
+
const raw = localStorage.getItem(indexKey(projectId));
|
|
1191
|
+
if (!raw) return [];
|
|
1192
|
+
const parsed = JSON.parse(raw);
|
|
1193
|
+
if (!Array.isArray(parsed)) return [];
|
|
1194
|
+
return parsed.filter(
|
|
1195
|
+
(c) => !!c && typeof c === "object" && typeof c.id === "string"
|
|
1196
|
+
);
|
|
1197
|
+
} catch {
|
|
1198
|
+
return [];
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
function writeIndex(projectId, entries) {
|
|
1202
|
+
if (typeof localStorage === "undefined") return [];
|
|
1203
|
+
const cutoff = Date.now() - MAX_HISTORY_AGE_MS;
|
|
1204
|
+
const kept = entries.filter((c) => c.updatedAt > cutoff).sort((a, b) => b.updatedAt - a.updatedAt).slice(0, MAX_CONVERSATIONS);
|
|
1205
|
+
const keptIds = new Set(kept.map((c) => c.id));
|
|
1206
|
+
for (const dropped of entries) {
|
|
1207
|
+
if (keptIds.has(dropped.id)) continue;
|
|
1208
|
+
try {
|
|
1209
|
+
localStorage.removeItem(bodyKey(projectId, dropped.id));
|
|
1210
|
+
} catch {
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
try {
|
|
1214
|
+
localStorage.setItem(indexKey(projectId), JSON.stringify(kept));
|
|
1215
|
+
} catch {
|
|
1216
|
+
}
|
|
1217
|
+
return kept;
|
|
1218
|
+
}
|
|
1219
|
+
function archiveConversation(projectId, conversationId, messages, path, fallbackTitle) {
|
|
1220
|
+
if (typeof localStorage === "undefined") return;
|
|
1221
|
+
const body = boundTranscript(messages);
|
|
1222
|
+
if (!body.length) return;
|
|
1223
|
+
try {
|
|
1224
|
+
localStorage.setItem(bodyKey(projectId, conversationId), JSON.stringify(body));
|
|
1225
|
+
} catch {
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
const entry = {
|
|
1229
|
+
id: conversationId,
|
|
1230
|
+
title: deriveTitle(body, fallbackTitle),
|
|
1231
|
+
updatedAt: Date.now(),
|
|
1232
|
+
messageCount: body.length,
|
|
1233
|
+
path: path.split("?")[0].split("#")[0]
|
|
1234
|
+
};
|
|
1235
|
+
const others = readIndex(projectId).filter((c) => c.id !== conversationId);
|
|
1236
|
+
writeIndex(projectId, [entry, ...others]);
|
|
1237
|
+
}
|
|
1238
|
+
function listConversations(projectId) {
|
|
1239
|
+
return writeIndex(projectId, readIndex(projectId));
|
|
1240
|
+
}
|
|
1241
|
+
function readConversation(projectId, conversationId) {
|
|
1242
|
+
if (typeof localStorage === "undefined") return [];
|
|
1243
|
+
try {
|
|
1244
|
+
const raw = localStorage.getItem(bodyKey(projectId, conversationId));
|
|
1245
|
+
if (!raw) return [];
|
|
1246
|
+
const parsed = JSON.parse(raw);
|
|
1247
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
1248
|
+
} catch {
|
|
1249
|
+
return [];
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
function deleteConversation(projectId, conversationId) {
|
|
1253
|
+
if (typeof localStorage === "undefined") return;
|
|
1254
|
+
try {
|
|
1255
|
+
localStorage.removeItem(bodyKey(projectId, conversationId));
|
|
1256
|
+
} catch {
|
|
1257
|
+
}
|
|
1258
|
+
writeIndex(projectId, readIndex(projectId).filter((c) => c.id !== conversationId));
|
|
1259
|
+
}
|
|
1260
|
+
function clearConversations(projectId) {
|
|
1261
|
+
if (typeof localStorage === "undefined") return;
|
|
1262
|
+
for (const entry of readIndex(projectId)) {
|
|
1263
|
+
try {
|
|
1264
|
+
localStorage.removeItem(bodyKey(projectId, entry.id));
|
|
1265
|
+
} catch {
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
try {
|
|
1269
|
+
localStorage.removeItem(indexKey(projectId));
|
|
1270
|
+
} catch {
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1121
1273
|
|
|
1122
1274
|
// src/ui/styles.ts
|
|
1123
1275
|
var STYLE_ELEMENT_ID = "daba-agent-styles";
|
|
@@ -1164,8 +1316,15 @@ var KNOWN_TOKENS = /* @__PURE__ */ new Set([
|
|
|
1164
1316
|
"inset",
|
|
1165
1317
|
"gap",
|
|
1166
1318
|
"badge-size",
|
|
1319
|
+
"badge-icon-size",
|
|
1320
|
+
"badge-radius",
|
|
1167
1321
|
"panel-w",
|
|
1168
|
-
"panel-h"
|
|
1322
|
+
"panel-h",
|
|
1323
|
+
// The trigger icon's two recolourable fills. Written on the wrapper so
|
|
1324
|
+
// the panel header and intro marks pick them up too, not just the
|
|
1325
|
+
// launcher — see ui/icon.ts.
|
|
1326
|
+
"icon-bg",
|
|
1327
|
+
"icon-mark"
|
|
1169
1328
|
]);
|
|
1170
1329
|
var UNSAFE_TOKEN_VALUE = /[;{}<>]|url\s*\(|expression\s*\(/i;
|
|
1171
1330
|
function tokenProperty(key) {
|
|
@@ -1235,8 +1394,10 @@ var SHEET = `
|
|
|
1235
1394
|
--daba-agent-inset: 20px;
|
|
1236
1395
|
--daba-agent-gap: 12px;
|
|
1237
1396
|
--daba-agent-badge-size: 56px;
|
|
1238
|
-
--daba-agent-
|
|
1239
|
-
--daba-agent-
|
|
1397
|
+
--daba-agent-badge-icon-size: 100%;
|
|
1398
|
+
--daba-agent-badge-radius: 10px;
|
|
1399
|
+
--daba-agent-panel-w: 400px;
|
|
1400
|
+
--daba-agent-panel-h: 740px;
|
|
1240
1401
|
--daba-agent-anchor: flex-end;
|
|
1241
1402
|
}
|
|
1242
1403
|
|
|
@@ -1405,27 +1566,34 @@ h1, h2, h3, h4, h5, h6) {
|
|
|
1405
1566
|
}
|
|
1406
1567
|
|
|
1407
1568
|
.daba-agent-badge--circle {
|
|
1408
|
-
|
|
1569
|
+
--daba-agent-badge-radius: var(--daba-agent-radius-pill);
|
|
1409
1570
|
}
|
|
1410
1571
|
.daba-agent-badge--rounded {
|
|
1411
|
-
|
|
1572
|
+
--daba-agent-badge-radius: calc(var(--daba-agent-radius) * 0.95);
|
|
1412
1573
|
}
|
|
1413
1574
|
.daba-agent-badge--pill {
|
|
1575
|
+
--daba-agent-badge-radius: var(--daba-agent-radius-pill);
|
|
1414
1576
|
width: auto;
|
|
1415
1577
|
height: calc(var(--daba-agent-badge-size) * 0.82);
|
|
1416
1578
|
padding-inline: 8px 18px;
|
|
1417
1579
|
gap: 10px;
|
|
1418
|
-
border-radius: var(--daba-agent-radius-pill);
|
|
1419
1580
|
}
|
|
1420
1581
|
|
|
1421
1582
|
.daba-agent-badge__icon {
|
|
1422
1583
|
display: block;
|
|
1423
|
-
width:
|
|
1424
|
-
height:
|
|
1584
|
+
width: var(--daba-agent-badge-icon-size);
|
|
1585
|
+
height: var(--daba-agent-badge-icon-size);
|
|
1586
|
+
margin: auto;
|
|
1425
1587
|
border-radius: inherit;
|
|
1426
1588
|
overflow: hidden;
|
|
1427
1589
|
line-height: 0;
|
|
1428
1590
|
}
|
|
1591
|
+
.daba-agent-badge__icon--text {
|
|
1592
|
+
display: grid;
|
|
1593
|
+
place-items: center;
|
|
1594
|
+
font-size: calc(var(--daba-agent-badge-size) * 0.48);
|
|
1595
|
+
line-height: 1;
|
|
1596
|
+
}
|
|
1429
1597
|
.daba-agent-badge--pill .daba-agent-badge__icon {
|
|
1430
1598
|
width: calc(var(--daba-agent-badge-size) * 0.55);
|
|
1431
1599
|
height: calc(var(--daba-agent-badge-size) * 0.55);
|
|
@@ -1509,10 +1677,6 @@ h1, h2, h3, h4, h5, h6) {
|
|
|
1509
1677
|
.daba-agent-window {
|
|
1510
1678
|
display: flex;
|
|
1511
1679
|
flex-direction: column;
|
|
1512
|
-
width: var(--daba-agent-panel-w);
|
|
1513
|
-
height: min(var(--daba-agent-panel-h), calc(100vh - 140px));
|
|
1514
|
-
max-width: calc(100vw - 24px);
|
|
1515
|
-
max-height: calc(100vh - 120px);
|
|
1516
1680
|
background: var(--daba-agent-surface);
|
|
1517
1681
|
color: var(--daba-agent-text);
|
|
1518
1682
|
border: 1px solid var(--daba-agent-border);
|
|
@@ -2407,8 +2571,8 @@ h1, h2, h3, h4, h5, h6) {
|
|
|
2407
2571
|
--ref-mark: #2b2b2b;
|
|
2408
2572
|
--ref-user: #f2f2f2;
|
|
2409
2573
|
|
|
2410
|
-
width:
|
|
2411
|
-
height:
|
|
2574
|
+
width: var(--daba-agent-panel-w);
|
|
2575
|
+
height: var(--daba-agent-panel-h);
|
|
2412
2576
|
/* The launcher sits above the panel in the same column, so the panel
|
|
2413
2577
|
must leave room for it plus the viewport margins \u2014 otherwise on a
|
|
2414
2578
|
laptop screen the two overlap at the corner. 40px badge + 12px gap
|
|
@@ -2832,9 +2996,121 @@ h1, h2, h3, h4, h5, h6) {
|
|
|
2832
2996
|
background: #ffffff;
|
|
2833
2997
|
}
|
|
2834
2998
|
|
|
2999
|
+
/* --- history: the same sheet, one level in -------------------------------- */
|
|
3000
|
+
.daba-agent-history {
|
|
3001
|
+
display: flex;
|
|
3002
|
+
flex-direction: column;
|
|
3003
|
+
flex: 1;
|
|
3004
|
+
min-height: 0;
|
|
3005
|
+
background: var(--daba-agent-surface);
|
|
3006
|
+
}
|
|
3007
|
+
.daba-agent-history__head {
|
|
3008
|
+
display: flex;
|
|
3009
|
+
align-items: center;
|
|
3010
|
+
gap: 8px;
|
|
3011
|
+
padding: 10px 12px;
|
|
3012
|
+
border-block-end: 1px solid var(--ref-line);
|
|
3013
|
+
}
|
|
3014
|
+
.daba-agent-history__title {
|
|
3015
|
+
margin: 0;
|
|
3016
|
+
font-size: 14px;
|
|
3017
|
+
font-weight: 600;
|
|
3018
|
+
color: var(--ref-ink);
|
|
3019
|
+
}
|
|
3020
|
+
.daba-agent-history__title:focus-visible {
|
|
3021
|
+
outline: 2px solid var(--daba-agent-accent);
|
|
3022
|
+
outline-offset: 2px;
|
|
3023
|
+
}
|
|
3024
|
+
.daba-agent-history__back {
|
|
3025
|
+
display: grid;
|
|
3026
|
+
place-items: center;
|
|
3027
|
+
width: 28px;
|
|
3028
|
+
height: 28px;
|
|
3029
|
+
border: 0;
|
|
3030
|
+
border-radius: var(--daba-agent-radius-sm);
|
|
3031
|
+
background: transparent;
|
|
3032
|
+
color: var(--ref-muted);
|
|
3033
|
+
cursor: pointer;
|
|
3034
|
+
}
|
|
3035
|
+
.daba-agent-history__back:hover { color: var(--ref-ink); background: var(--ref-user); }
|
|
3036
|
+
.daba-agent-history__list {
|
|
3037
|
+
flex: 1;
|
|
3038
|
+
min-height: 0;
|
|
3039
|
+
overflow-y: auto;
|
|
3040
|
+
padding: 6px;
|
|
3041
|
+
}
|
|
3042
|
+
.daba-agent-history__item {
|
|
3043
|
+
display: flex;
|
|
3044
|
+
align-items: stretch;
|
|
3045
|
+
gap: 2px;
|
|
3046
|
+
border-radius: var(--daba-agent-radius-sm);
|
|
3047
|
+
}
|
|
3048
|
+
.daba-agent-history__item:hover { background: var(--ref-user); }
|
|
3049
|
+
.daba-agent-history__open {
|
|
3050
|
+
flex: 1;
|
|
3051
|
+
min-width: 0;
|
|
3052
|
+
display: flex;
|
|
3053
|
+
flex-direction: column;
|
|
3054
|
+
gap: 2px;
|
|
3055
|
+
padding: 10px;
|
|
3056
|
+
border: 0;
|
|
3057
|
+
background: transparent;
|
|
3058
|
+
font: inherit;
|
|
3059
|
+
text-align: start;
|
|
3060
|
+
cursor: pointer;
|
|
3061
|
+
}
|
|
3062
|
+
.daba-agent-history__name {
|
|
3063
|
+
overflow: hidden;
|
|
3064
|
+
text-overflow: ellipsis;
|
|
3065
|
+
white-space: nowrap;
|
|
3066
|
+
font-size: 13px;
|
|
3067
|
+
color: var(--ref-ink);
|
|
3068
|
+
}
|
|
3069
|
+
.daba-agent-history__meta {
|
|
3070
|
+
font-size: 11px;
|
|
3071
|
+
color: var(--ref-faint);
|
|
3072
|
+
}
|
|
3073
|
+
.daba-agent-history__delete {
|
|
3074
|
+
display: grid;
|
|
3075
|
+
place-items: center;
|
|
3076
|
+
width: 32px;
|
|
3077
|
+
border: 0;
|
|
3078
|
+
border-radius: var(--daba-agent-radius-sm);
|
|
3079
|
+
background: transparent;
|
|
3080
|
+
color: var(--ref-faint);
|
|
3081
|
+
cursor: pointer;
|
|
3082
|
+
/* Revealed on hover: a delete button beside every row turns a list of
|
|
3083
|
+
conversations into a list of ways to lose one. */
|
|
3084
|
+
opacity: 0;
|
|
3085
|
+
}
|
|
3086
|
+
.daba-agent-history__item:hover .daba-agent-history__delete,
|
|
3087
|
+
.daba-agent-history__delete:focus-visible { opacity: 1; }
|
|
3088
|
+
.daba-agent-history__delete:hover { color: var(--daba-agent-danger); }
|
|
3089
|
+
.daba-agent-history__empty {
|
|
3090
|
+
margin: 0;
|
|
3091
|
+
padding: 24px 12px;
|
|
3092
|
+
text-align: center;
|
|
3093
|
+
font-size: 13px;
|
|
3094
|
+
color: var(--ref-muted);
|
|
3095
|
+
}
|
|
3096
|
+
.daba-agent-history__clear {
|
|
3097
|
+
display: block;
|
|
3098
|
+
width: 100%;
|
|
3099
|
+
margin-block-start: 8px;
|
|
3100
|
+
padding: 10px;
|
|
3101
|
+
border: 0;
|
|
3102
|
+
border-radius: var(--daba-agent-radius-sm);
|
|
3103
|
+
background: transparent;
|
|
3104
|
+
font: inherit;
|
|
3105
|
+
font-size: 12px;
|
|
3106
|
+
color: var(--ref-muted);
|
|
3107
|
+
cursor: pointer;
|
|
3108
|
+
}
|
|
3109
|
+
.daba-agent-history__clear:hover { color: var(--daba-agent-danger); }
|
|
3110
|
+
|
|
2835
3111
|
/* --- launcher: darkens toward black, same hue ----------------------------- */
|
|
2836
3112
|
.daba-agent-badge {
|
|
2837
|
-
border-radius:
|
|
3113
|
+
border-radius: var(--daba-agent-badge-radius);
|
|
2838
3114
|
transition: background-color var(--daba-ms) var(--daba-ease);
|
|
2839
3115
|
}
|
|
2840
3116
|
.daba-agent-badge:hover { background: color-mix(in srgb, var(--daba-agent-accent) 92%, #000000); }
|
|
@@ -3076,6 +3352,42 @@ var AGENT_LOGO_BADGE_SVG = `<svg viewBox="0 0 469 469" xmlns="http://www.w3.org/
|
|
|
3076
3352
|
<g transform="translate(94 94) scale(1.905)"><path d="M73.751 0C114.483 0 147.502 33.0194 147.502 73.751C147.502 114.483 114.483 147.502 73.751 147.502C33.0194 147.502 0 114.483 0 73.751C8.24653e-06 33.0194 33.0194 8.2476e-06 73.751 0ZM73.751 116.118C60.7517 116.118 50.2141 120.334 50.2139 125.533C50.2139 130.733 60.7515 134.948 73.751 134.948C86.7504 134.948 97.2881 130.733 97.2881 125.533C97.2878 120.334 86.7502 116.118 73.751 116.118ZM38.9844 31.3828C27.962 31.3828 12.5537 47.8829 12.5537 73.751C12.5538 99.619 27.9621 116.118 38.9844 116.118C51.1171 116.118 56.4902 92.4737 56.4902 73.751C56.4902 55.0282 51.1171 31.3829 38.9844 31.3828ZM108.518 31.3828C96.3849 31.3831 91.0117 55.0283 91.0117 73.751C91.0117 92.4736 96.385 116.118 108.518 116.118C119.54 116.118 134.948 99.619 134.948 73.751C134.948 47.8829 119.54 31.3828 108.518 31.3828Z" fill="var(--daba-agent-icon-mark, #ffffff)"/></g>
|
|
3077
3353
|
</svg>`;
|
|
3078
3354
|
|
|
3355
|
+
// src/utils/sanitize-svg.ts
|
|
3356
|
+
var BANNED_TAGS = ["script", "foreignobject", "iframe", "object", "embed", "animate", "set", "handler"];
|
|
3357
|
+
function sanitizeSvg(markup) {
|
|
3358
|
+
if (!markup) return null;
|
|
3359
|
+
const source = String(markup).trim();
|
|
3360
|
+
if (!source.startsWith("<")) return null;
|
|
3361
|
+
if (typeof DOMParser === "undefined") return null;
|
|
3362
|
+
let doc;
|
|
3363
|
+
try {
|
|
3364
|
+
doc = new DOMParser().parseFromString(source, "image/svg+xml");
|
|
3365
|
+
} catch {
|
|
3366
|
+
return null;
|
|
3367
|
+
}
|
|
3368
|
+
if (doc.querySelector("parsererror")) return null;
|
|
3369
|
+
const root = doc.documentElement;
|
|
3370
|
+
if (!root || root.nodeName.toLowerCase() !== "svg") return null;
|
|
3371
|
+
for (const el of Array.from(root.querySelectorAll("*")).concat(root)) {
|
|
3372
|
+
if (BANNED_TAGS.includes(el.nodeName.toLowerCase())) {
|
|
3373
|
+
el.remove();
|
|
3374
|
+
continue;
|
|
3375
|
+
}
|
|
3376
|
+
for (const attr of Array.from(el.attributes)) {
|
|
3377
|
+
const name = attr.name.toLowerCase();
|
|
3378
|
+
const value = attr.value.trim();
|
|
3379
|
+
const isReference = name === "href" || name.endsWith(":href") || name === "src";
|
|
3380
|
+
if (name.startsWith("on") || name === "style" || isReference && !value.startsWith("#")) {
|
|
3381
|
+
el.removeAttribute(attr.name);
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
}
|
|
3385
|
+
if (!root.children.length) return null;
|
|
3386
|
+
root.setAttribute("aria-hidden", "true");
|
|
3387
|
+
root.setAttribute("focusable", "false");
|
|
3388
|
+
return root.outerHTML;
|
|
3389
|
+
}
|
|
3390
|
+
|
|
3079
3391
|
// src/ui/badge.ts
|
|
3080
3392
|
var STATUS_TEXT = {
|
|
3081
3393
|
idle: "Click and talk",
|
|
@@ -3084,13 +3396,24 @@ var STATUS_TEXT = {
|
|
|
3084
3396
|
thinking: "Thinking\u2026",
|
|
3085
3397
|
speaking: "Speaking\u2026"
|
|
3086
3398
|
};
|
|
3087
|
-
|
|
3399
|
+
var ACTION_TEXT = {
|
|
3400
|
+
idle: "Click and talk",
|
|
3401
|
+
connecting: "Click to cancel",
|
|
3402
|
+
listening: "Click to end the conversation",
|
|
3403
|
+
thinking: "Click to end the conversation",
|
|
3404
|
+
speaking: "Click to end the conversation"
|
|
3405
|
+
};
|
|
3406
|
+
function ariaLabel(status, hotkeyLabel2) {
|
|
3407
|
+
const action = status === "idle" ? "Talk to AI Assistant" : "End the conversation with AI Assistant";
|
|
3408
|
+
return hotkeyLabel2 ? `${action} (${hotkeyLabel2})` : action;
|
|
3409
|
+
}
|
|
3410
|
+
function buildBadge(position, mode, accentColor, iconBackgroundColor, iconMarkColor, hotkeyLabel2) {
|
|
3088
3411
|
injectAgentStyles();
|
|
3089
3412
|
const root = document.createElement("button");
|
|
3090
3413
|
root.type = "button";
|
|
3091
3414
|
root.className = `daba-agent-badge daba-agent-badge--idle daba-agent-badge--pos-${position}`;
|
|
3092
|
-
root.setAttribute("aria-label", "
|
|
3093
|
-
root.title =
|
|
3415
|
+
root.setAttribute("aria-label", ariaLabel("idle", hotkeyLabel2));
|
|
3416
|
+
root.title = ACTION_TEXT.idle;
|
|
3094
3417
|
if (accentColor) root.style.setProperty("--daba-agent-accent", accentColor);
|
|
3095
3418
|
if (iconBackgroundColor) root.style.setProperty("--daba-agent-icon-bg", iconBackgroundColor);
|
|
3096
3419
|
if (iconMarkColor) root.style.setProperty("--daba-agent-icon-mark", iconMarkColor);
|
|
@@ -3107,28 +3430,41 @@ function buildBadge(position, mode, accentColor, iconBackgroundColor, iconMarkCo
|
|
|
3107
3430
|
root.appendChild(label);
|
|
3108
3431
|
return { root, label };
|
|
3109
3432
|
}
|
|
3110
|
-
function updateBadge(root, label, status, position) {
|
|
3433
|
+
function updateBadge(root, label, status, position, hotkeyLabel2) {
|
|
3111
3434
|
root.className = `daba-agent-badge daba-agent-badge--${status} daba-agent-badge--pos-${position}`;
|
|
3112
|
-
root.title =
|
|
3435
|
+
root.title = ACTION_TEXT[status];
|
|
3436
|
+
root.setAttribute("aria-label", ariaLabel(status, hotkeyLabel2));
|
|
3113
3437
|
label.textContent = STATUS_TEXT[status];
|
|
3114
3438
|
}
|
|
3115
|
-
function setBadgeIcon(root,
|
|
3439
|
+
function setBadgeIcon(root, mark) {
|
|
3116
3440
|
const slot = root.querySelector(".daba-agent-badge__icon");
|
|
3117
3441
|
if (!slot) return;
|
|
3118
|
-
|
|
3119
|
-
|
|
3442
|
+
slot.textContent = "";
|
|
3443
|
+
slot.classList.remove("daba-agent-badge__icon--text");
|
|
3444
|
+
const svg = sanitizeSvg(mark.svg);
|
|
3445
|
+
if (svg) {
|
|
3446
|
+
slot.innerHTML = svg;
|
|
3120
3447
|
return;
|
|
3121
3448
|
}
|
|
3122
|
-
const
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3449
|
+
const text = mark.text?.trim();
|
|
3450
|
+
if (text) {
|
|
3451
|
+
slot.classList.add("daba-agent-badge__icon--text");
|
|
3452
|
+
slot.textContent = text;
|
|
3453
|
+
return;
|
|
3454
|
+
}
|
|
3455
|
+
if (mark.url) {
|
|
3456
|
+
const img = document.createElement("img");
|
|
3457
|
+
img.className = "daba-agent-badge__img";
|
|
3458
|
+
img.alt = "";
|
|
3459
|
+
img.decoding = "async";
|
|
3460
|
+
img.addEventListener("error", () => {
|
|
3461
|
+
slot.innerHTML = AGENT_LOGO_BADGE_SVG;
|
|
3462
|
+
});
|
|
3463
|
+
img.src = mark.url;
|
|
3464
|
+
slot.appendChild(img);
|
|
3465
|
+
return;
|
|
3466
|
+
}
|
|
3467
|
+
slot.innerHTML = AGENT_LOGO_BADGE_SVG;
|
|
3132
3468
|
}
|
|
3133
3469
|
|
|
3134
3470
|
// src/ui/cards.ts
|
|
@@ -3616,6 +3952,9 @@ var ICON = {
|
|
|
3616
3952
|
ticket: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 9V7a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 0 0 6v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-2a2 2 0 0 0 0-6z"/><path d="M12 7v2M12 15v2"/></svg>`,
|
|
3617
3953
|
clock: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 1.8"/></svg>`,
|
|
3618
3954
|
chevron: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>`,
|
|
3955
|
+
history: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 4v4h4"/><path d="M12 8v4l3 2"/></svg>`,
|
|
3956
|
+
back: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5l-7 7 7 7"/></svg>`,
|
|
3957
|
+
trash: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h16"/><path d="M9 7V5h6v2"/><path d="M6 7l1 12h10l1-12"/></svg>`,
|
|
3619
3958
|
keys: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="6" width="18" height="12" rx="2.5"/><path d="M7 10h.01M11 10h.01M15 10h.01M7 14h10"/></svg>`,
|
|
3620
3959
|
pin: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 21s7-5.7 7-11a7 7 0 1 0-14 0c0 5.3 7 11 7 11z"/><circle cx="12" cy="10" r="2.5"/></svg>`
|
|
3621
3960
|
};
|
|
@@ -3653,11 +3992,17 @@ function buildChatWindow(options) {
|
|
|
3653
3992
|
mode,
|
|
3654
3993
|
intro,
|
|
3655
3994
|
logoUrl,
|
|
3995
|
+
logoSvg,
|
|
3656
3996
|
hotkeyLabel: hotkeyLabel2,
|
|
3997
|
+
historyEnabled,
|
|
3657
3998
|
onSendText,
|
|
3658
3999
|
onMicClick,
|
|
3659
4000
|
onCloseClick,
|
|
3660
|
-
onNewConversation
|
|
4001
|
+
onNewConversation,
|
|
4002
|
+
onListHistory,
|
|
4003
|
+
onOpenConversation,
|
|
4004
|
+
onDeleteConversation,
|
|
4005
|
+
onClearHistory
|
|
3661
4006
|
} = options;
|
|
3662
4007
|
const voiceAvailable = mode !== "chat";
|
|
3663
4008
|
const chatWindow = document.createElement("div");
|
|
@@ -3675,7 +4020,10 @@ function buildChatWindow(options) {
|
|
|
3675
4020
|
headerLeft.appendChild(headerMarkSlot);
|
|
3676
4021
|
const setHeaderLogo = (url) => {
|
|
3677
4022
|
headerMarkSlot.textContent = "";
|
|
3678
|
-
|
|
4023
|
+
const svg = sanitizeSvg(logoSvg);
|
|
4024
|
+
if (svg) {
|
|
4025
|
+
headerMarkSlot.appendChild(icon(svg, "daba-agent-header__mark"));
|
|
4026
|
+
} else if (url) {
|
|
3679
4027
|
const logo = document.createElement("img");
|
|
3680
4028
|
logo.className = "daba-agent-header__logo";
|
|
3681
4029
|
logo.alt = "";
|
|
@@ -3699,6 +4047,14 @@ function buildChatWindow(options) {
|
|
|
3699
4047
|
headerRight.className = "daba-agent-header__right";
|
|
3700
4048
|
const micBtn = iconButton(ICON.mic, strings.startVoice, "daba-agent-header__btn daba-agent-header__btn--mic", onMicClick);
|
|
3701
4049
|
micBtn.hidden = true;
|
|
4050
|
+
const historyBtn = iconButton(
|
|
4051
|
+
ICON.history,
|
|
4052
|
+
strings.history,
|
|
4053
|
+
"daba-agent-header__btn",
|
|
4054
|
+
() => setHistoryVisible(!historyOpen)
|
|
4055
|
+
);
|
|
4056
|
+
historyBtn.hidden = true;
|
|
4057
|
+
if (historyEnabled) headerRight.appendChild(historyBtn);
|
|
3702
4058
|
headerRight.appendChild(
|
|
3703
4059
|
iconButton(ICON.grid, strings.newConversation, "daba-agent-header__btn", onNewConversation)
|
|
3704
4060
|
);
|
|
@@ -3717,7 +4073,10 @@ function buildChatWindow(options) {
|
|
|
3717
4073
|
const setIntroLogo = (url) => {
|
|
3718
4074
|
if (!introMarkSlot) return;
|
|
3719
4075
|
introMarkSlot.textContent = "";
|
|
3720
|
-
|
|
4076
|
+
const svg = sanitizeSvg(logoSvg);
|
|
4077
|
+
if (svg) {
|
|
4078
|
+
introMarkSlot.appendChild(icon(svg, "daba-agent-intro__mark"));
|
|
4079
|
+
} else if (url) {
|
|
3721
4080
|
const img = document.createElement("img");
|
|
3722
4081
|
img.className = "daba-agent-intro__mark daba-agent-intro__logo";
|
|
3723
4082
|
img.alt = "";
|
|
@@ -3821,6 +4180,104 @@ function buildChatWindow(options) {
|
|
|
3821
4180
|
thinkingEl?.remove();
|
|
3822
4181
|
thinkingEl = null;
|
|
3823
4182
|
};
|
|
4183
|
+
const historyEl = document.createElement("div");
|
|
4184
|
+
historyEl.className = "daba-agent-history";
|
|
4185
|
+
historyEl.hidden = true;
|
|
4186
|
+
const historyHead = document.createElement("div");
|
|
4187
|
+
historyHead.className = "daba-agent-history__head";
|
|
4188
|
+
const historyBack = iconButton(
|
|
4189
|
+
ICON.back,
|
|
4190
|
+
strings.historyBack,
|
|
4191
|
+
"daba-agent-history__back",
|
|
4192
|
+
() => setHistoryVisible(false)
|
|
4193
|
+
);
|
|
4194
|
+
historyHead.appendChild(historyBack);
|
|
4195
|
+
const historyTitle = document.createElement("h2");
|
|
4196
|
+
historyTitle.className = "daba-agent-history__title";
|
|
4197
|
+
historyTitle.textContent = strings.history;
|
|
4198
|
+
historyTitle.tabIndex = -1;
|
|
4199
|
+
historyHead.appendChild(historyTitle);
|
|
4200
|
+
historyEl.appendChild(historyHead);
|
|
4201
|
+
const historyList = document.createElement("div");
|
|
4202
|
+
historyList.className = "daba-agent-history__list";
|
|
4203
|
+
historyEl.appendChild(historyList);
|
|
4204
|
+
let historyOpen = false;
|
|
4205
|
+
const when = (ts) => {
|
|
4206
|
+
const day = 24 * 60 * 60 * 1e3;
|
|
4207
|
+
const age = Date.now() - ts;
|
|
4208
|
+
try {
|
|
4209
|
+
const rtf = new Intl.RelativeTimeFormat(lang, { numeric: "auto" });
|
|
4210
|
+
if (age < 60 * 60 * 1e3) return rtf.format(-Math.round(age / (60 * 1e3)) || 0, "minute");
|
|
4211
|
+
if (age < day) return rtf.format(-Math.round(age / (60 * 60 * 1e3)), "hour");
|
|
4212
|
+
if (age < 7 * day) return rtf.format(-Math.round(age / day), "day");
|
|
4213
|
+
return new Intl.DateTimeFormat(lang, { month: "short", day: "numeric" }).format(ts);
|
|
4214
|
+
} catch {
|
|
4215
|
+
return new Date(ts).toLocaleDateString();
|
|
4216
|
+
}
|
|
4217
|
+
};
|
|
4218
|
+
const renderHistory = () => {
|
|
4219
|
+
const entries = onListHistory?.() ?? [];
|
|
4220
|
+
historyList.textContent = "";
|
|
4221
|
+
if (!entries.length) {
|
|
4222
|
+
const empty = document.createElement("p");
|
|
4223
|
+
empty.className = "daba-agent-history__empty";
|
|
4224
|
+
empty.textContent = strings.historyEmpty;
|
|
4225
|
+
historyList.appendChild(empty);
|
|
4226
|
+
return entries;
|
|
4227
|
+
}
|
|
4228
|
+
for (const entry of entries) {
|
|
4229
|
+
const row = document.createElement("div");
|
|
4230
|
+
row.className = "daba-agent-history__item";
|
|
4231
|
+
const open = document.createElement("button");
|
|
4232
|
+
open.type = "button";
|
|
4233
|
+
open.className = "daba-agent-history__open";
|
|
4234
|
+
const name = document.createElement("span");
|
|
4235
|
+
name.className = "daba-agent-history__name";
|
|
4236
|
+
name.textContent = entry.title;
|
|
4237
|
+
const meta = document.createElement("span");
|
|
4238
|
+
meta.className = "daba-agent-history__meta";
|
|
4239
|
+
meta.textContent = when(entry.updatedAt);
|
|
4240
|
+
open.append(name, meta);
|
|
4241
|
+
open.addEventListener("click", () => {
|
|
4242
|
+
onOpenConversation?.(entry.id);
|
|
4243
|
+
setHistoryVisible(false);
|
|
4244
|
+
});
|
|
4245
|
+
row.appendChild(open);
|
|
4246
|
+
const remove = iconButton(ICON.trash, strings.historyDelete, "daba-agent-history__delete", () => {
|
|
4247
|
+
onDeleteConversation?.(entry.id);
|
|
4248
|
+
renderHistory();
|
|
4249
|
+
});
|
|
4250
|
+
row.appendChild(remove);
|
|
4251
|
+
historyList.appendChild(row);
|
|
4252
|
+
}
|
|
4253
|
+
const clear = document.createElement("button");
|
|
4254
|
+
clear.type = "button";
|
|
4255
|
+
clear.className = "daba-agent-history__clear";
|
|
4256
|
+
clear.textContent = strings.historyClear;
|
|
4257
|
+
clear.addEventListener("click", () => {
|
|
4258
|
+
onClearHistory?.();
|
|
4259
|
+
renderHistory();
|
|
4260
|
+
refreshHistory();
|
|
4261
|
+
});
|
|
4262
|
+
historyList.appendChild(clear);
|
|
4263
|
+
return entries;
|
|
4264
|
+
};
|
|
4265
|
+
const setHistoryVisible = (visible) => {
|
|
4266
|
+
if (!historyEnabled) return;
|
|
4267
|
+
historyOpen = visible;
|
|
4268
|
+
if (visible) renderHistory();
|
|
4269
|
+
historyEl.hidden = !visible;
|
|
4270
|
+
messagesContainer.hidden = visible;
|
|
4271
|
+
composer.hidden = visible;
|
|
4272
|
+
historyBtn.setAttribute("aria-expanded", String(visible));
|
|
4273
|
+
if (visible) historyTitle.focus();
|
|
4274
|
+
else inputElement.focus();
|
|
4275
|
+
};
|
|
4276
|
+
const refreshHistory = () => {
|
|
4277
|
+
if (!historyEnabled) return;
|
|
4278
|
+
historyBtn.hidden = (onListHistory?.() ?? []).length === 0;
|
|
4279
|
+
if (historyOpen) renderHistory();
|
|
4280
|
+
};
|
|
3824
4281
|
const composer = document.createElement("div");
|
|
3825
4282
|
composer.className = "daba-agent-composer";
|
|
3826
4283
|
const inputForm = document.createElement("form");
|
|
@@ -3878,6 +4335,7 @@ function buildChatWindow(options) {
|
|
|
3878
4335
|
footer.appendChild(footerRight);
|
|
3879
4336
|
composer.appendChild(footer);
|
|
3880
4337
|
chatWindow.appendChild(composer);
|
|
4338
|
+
if (historyEnabled) chatWindow.insertBefore(historyEl, composer);
|
|
3881
4339
|
return {
|
|
3882
4340
|
chatWindow,
|
|
3883
4341
|
messagesContainer,
|
|
@@ -3896,6 +4354,14 @@ function buildChatWindow(options) {
|
|
|
3896
4354
|
setStatusText(text) {
|
|
3897
4355
|
statusEl.textContent = text;
|
|
3898
4356
|
},
|
|
4357
|
+
clearMessages() {
|
|
4358
|
+
for (const child of Array.from(messagesContainer.children)) {
|
|
4359
|
+
if (child !== introEl) child.remove();
|
|
4360
|
+
}
|
|
4361
|
+
},
|
|
4362
|
+
setHistoryVisible,
|
|
4363
|
+
isHistoryVisible: () => historyOpen,
|
|
4364
|
+
refreshHistory,
|
|
3899
4365
|
applyConfig(config) {
|
|
3900
4366
|
if (config.logoUrl !== void 0) {
|
|
3901
4367
|
setHeaderLogo(config.logoUrl);
|
|
@@ -3968,7 +4434,7 @@ var STRINGS = {
|
|
|
3968
4434
|
close: "Close",
|
|
3969
4435
|
minimize: "Minimize",
|
|
3970
4436
|
newConversation: "New conversation",
|
|
3971
|
-
poweredBy: "Powered by
|
|
4437
|
+
poweredBy: "Powered by DabaLabs",
|
|
3972
4438
|
errorGeneric: "Something went wrong. Please try again.",
|
|
3973
4439
|
errorMicDenied: "Microphone access was blocked. Allow it in your browser settings to talk.",
|
|
3974
4440
|
errorOffline: "You appear to be offline. Check your connection.",
|
|
@@ -3985,7 +4451,13 @@ var STRINGS = {
|
|
|
3985
4451
|
retry: "Try again",
|
|
3986
4452
|
typeOrTalk: "Type, or tap the mic to talk",
|
|
3987
4453
|
voiceUnavailable: "Voice is unavailable on this device.",
|
|
3988
|
-
cardsLabel: "Results"
|
|
4454
|
+
cardsLabel: "Results",
|
|
4455
|
+
history: "History",
|
|
4456
|
+
historyBack: "Back",
|
|
4457
|
+
historyEmpty: "No past conversations yet.",
|
|
4458
|
+
historyDelete: "Delete",
|
|
4459
|
+
historyClear: "Clear all",
|
|
4460
|
+
untitledConversation: "Untitled conversation"
|
|
3989
4461
|
},
|
|
3990
4462
|
ar: {
|
|
3991
4463
|
assistantTitle: "\u0627\u0644\u0645\u0633\u0627\u0639\u062F \u0627\u0644\u0630\u0643\u064A",
|
|
@@ -4000,7 +4472,7 @@ var STRINGS = {
|
|
|
4000
4472
|
close: "\u0625\u063A\u0644\u0627\u0642",
|
|
4001
4473
|
minimize: "\u062A\u0635\u063A\u064A\u0631",
|
|
4002
4474
|
newConversation: "\u0645\u062D\u0627\u062F\u062B\u0629 \u062C\u062F\u064A\u062F\u0629",
|
|
4003
|
-
poweredBy: "\u0645\u062F\u0639\u0648\u0645 \u0645\u0646
|
|
4475
|
+
poweredBy: "\u0645\u062F\u0639\u0648\u0645 \u0645\u0646 DabaLabs",
|
|
4004
4476
|
errorGeneric: "\u062D\u062F\u062B \u062E\u0637\u0623 \u0645\u0627. \u064A\u0631\u062C\u0649 \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649.",
|
|
4005
4477
|
errorMicDenied: "\u062A\u0645 \u062D\u0638\u0631 \u0627\u0644\u0648\u0635\u0648\u0644 \u0625\u0644\u0649 \u0627\u0644\u0645\u064A\u0643\u0631\u0648\u0641\u0648\u0646. \u0627\u0633\u0645\u062D \u0628\u0647 \u0645\u0646 \u0625\u0639\u062F\u0627\u062F\u0627\u062A \u0627\u0644\u0645\u062A\u0635\u0641\u062D \u0644\u0644\u062A\u062D\u062F\u062B.",
|
|
4006
4478
|
errorOffline: "\u064A\u0628\u062F\u0648 \u0623\u0646\u0643 \u063A\u064A\u0631 \u0645\u062A\u0635\u0644 \u0628\u0627\u0644\u0625\u0646\u062A\u0631\u0646\u062A. \u062A\u062D\u0642\u0642 \u0645\u0646 \u0627\u062A\u0635\u0627\u0644\u0643.",
|
|
@@ -4017,7 +4489,13 @@ var STRINGS = {
|
|
|
4017
4489
|
retry: "\u0623\u0639\u062F \u0627\u0644\u0645\u062D\u0627\u0648\u0644\u0629",
|
|
4018
4490
|
typeOrTalk: "\u0627\u0643\u062A\u0628 \u0623\u0648 \u0627\u0636\u063A\u0637 \u0639\u0644\u0649 \u0627\u0644\u0645\u064A\u0643\u0631\u0648\u0641\u0648\u0646 \u0644\u0644\u062A\u062D\u062F\u062B",
|
|
4019
4491
|
voiceUnavailable: "\u0627\u0644\u0645\u062D\u0627\u062F\u062B\u0629 \u0627\u0644\u0635\u0648\u062A\u064A\u0629 \u063A\u064A\u0631 \u0645\u062A\u0627\u062D\u0629 \u0639\u0644\u0649 \u0647\u0630\u0627 \u0627\u0644\u062C\u0647\u0627\u0632.",
|
|
4020
|
-
cardsLabel: "\u0627\u0644\u0646\u062A\u0627\u0626\u062C"
|
|
4492
|
+
cardsLabel: "\u0627\u0644\u0646\u062A\u0627\u0626\u062C",
|
|
4493
|
+
history: "\u0627\u0644\u0633\u062C\u0644",
|
|
4494
|
+
historyBack: "\u0631\u062C\u0648\u0639",
|
|
4495
|
+
historyEmpty: "\u0644\u0627 \u062A\u0648\u062C\u062F \u0645\u062D\u0627\u062F\u062B\u0627\u062A \u0633\u0627\u0628\u0642\u0629 \u0628\u0639\u062F.",
|
|
4496
|
+
historyDelete: "\u062D\u0630\u0641",
|
|
4497
|
+
historyClear: "\u0645\u0633\u062D \u0627\u0644\u0643\u0644",
|
|
4498
|
+
untitledConversation: "\u0645\u062D\u0627\u062F\u062B\u0629 \u0628\u062F\u0648\u0646 \u0639\u0646\u0648\u0627\u0646"
|
|
4021
4499
|
},
|
|
4022
4500
|
fr: {
|
|
4023
4501
|
assistantTitle: "Assistant IA",
|
|
@@ -4032,7 +4510,7 @@ var STRINGS = {
|
|
|
4032
4510
|
close: "Fermer",
|
|
4033
4511
|
minimize: "R\xE9duire",
|
|
4034
4512
|
newConversation: "Nouvelle conversation",
|
|
4035
|
-
poweredBy: "Propuls\xE9 par
|
|
4513
|
+
poweredBy: "Propuls\xE9 par DabaLabs",
|
|
4036
4514
|
errorGeneric: "Une erreur s'est produite. Veuillez r\xE9essayer.",
|
|
4037
4515
|
errorMicDenied: "L'acc\xE8s au microphone a \xE9t\xE9 bloqu\xE9. Autorisez-le dans les param\xE8tres du navigateur pour parler.",
|
|
4038
4516
|
errorOffline: "Vous semblez \xEAtre hors ligne. V\xE9rifiez votre connexion.",
|
|
@@ -4049,7 +4527,13 @@ var STRINGS = {
|
|
|
4049
4527
|
retry: "R\xE9essayer",
|
|
4050
4528
|
typeOrTalk: "\xC9crivez, ou appuyez sur le micro pour parler",
|
|
4051
4529
|
voiceUnavailable: "La voix n'est pas disponible sur cet appareil.",
|
|
4052
|
-
cardsLabel: "R\xE9sultats"
|
|
4530
|
+
cardsLabel: "R\xE9sultats",
|
|
4531
|
+
history: "Historique",
|
|
4532
|
+
historyBack: "Retour",
|
|
4533
|
+
historyEmpty: "Aucune conversation pass\xE9e pour l'instant.",
|
|
4534
|
+
historyDelete: "Supprimer",
|
|
4535
|
+
historyClear: "Tout effacer",
|
|
4536
|
+
untitledConversation: "Conversation sans titre"
|
|
4053
4537
|
},
|
|
4054
4538
|
es: {
|
|
4055
4539
|
assistantTitle: "Asistente de IA",
|
|
@@ -4064,7 +4548,7 @@ var STRINGS = {
|
|
|
4064
4548
|
close: "Cerrar",
|
|
4065
4549
|
minimize: "Minimizar",
|
|
4066
4550
|
newConversation: "Nueva conversaci\xF3n",
|
|
4067
|
-
poweredBy: "Con tecnolog\xEDa de
|
|
4551
|
+
poweredBy: "Con tecnolog\xEDa de DabaLabs",
|
|
4068
4552
|
errorGeneric: "Algo sali\xF3 mal. Int\xE9ntalo de nuevo.",
|
|
4069
4553
|
errorMicDenied: "Se bloque\xF3 el acceso al micr\xF3fono. Perm\xEDtelo en la configuraci\xF3n del navegador para hablar.",
|
|
4070
4554
|
errorOffline: "Parece que no tienes conexi\xF3n. Comprueba tu red.",
|
|
@@ -4081,7 +4565,13 @@ var STRINGS = {
|
|
|
4081
4565
|
retry: "Reintentar",
|
|
4082
4566
|
typeOrTalk: "Escribe, o toca el micr\xF3fono para hablar",
|
|
4083
4567
|
voiceUnavailable: "La voz no est\xE1 disponible en este dispositivo.",
|
|
4084
|
-
cardsLabel: "Resultados"
|
|
4568
|
+
cardsLabel: "Resultados",
|
|
4569
|
+
history: "Historial",
|
|
4570
|
+
historyBack: "Atr\xE1s",
|
|
4571
|
+
historyEmpty: "A\xFAn no hay conversaciones anteriores.",
|
|
4572
|
+
historyDelete: "Eliminar",
|
|
4573
|
+
historyClear: "Borrar todo",
|
|
4574
|
+
untitledConversation: "Conversaci\xF3n sin t\xEDtulo"
|
|
4085
4575
|
},
|
|
4086
4576
|
de: {
|
|
4087
4577
|
assistantTitle: "KI-Assistent",
|
|
@@ -4096,7 +4586,7 @@ var STRINGS = {
|
|
|
4096
4586
|
close: "Schlie\xDFen",
|
|
4097
4587
|
minimize: "Minimieren",
|
|
4098
4588
|
newConversation: "Neue Unterhaltung",
|
|
4099
|
-
poweredBy: "Bereitgestellt von
|
|
4589
|
+
poweredBy: "Bereitgestellt von DabaLabs",
|
|
4100
4590
|
errorGeneric: "Etwas ist schiefgelaufen. Bitte versuchen Sie es erneut.",
|
|
4101
4591
|
errorMicDenied: "Der Mikrofonzugriff wurde blockiert. Erlauben Sie ihn in den Browsereinstellungen, um zu sprechen.",
|
|
4102
4592
|
errorOffline: "Sie scheinen offline zu sein. Pr\xFCfen Sie Ihre Verbindung.",
|
|
@@ -4113,7 +4603,13 @@ var STRINGS = {
|
|
|
4113
4603
|
retry: "Erneut versuchen",
|
|
4114
4604
|
typeOrTalk: "Schreiben oder aufs Mikrofon tippen, um zu sprechen",
|
|
4115
4605
|
voiceUnavailable: "Die Sprachfunktion ist auf diesem Ger\xE4t nicht verf\xFCgbar.",
|
|
4116
|
-
cardsLabel: "Ergebnisse"
|
|
4606
|
+
cardsLabel: "Ergebnisse",
|
|
4607
|
+
history: "Verlauf",
|
|
4608
|
+
historyBack: "Zur\xFCck",
|
|
4609
|
+
historyEmpty: "Noch keine fr\xFCheren Unterhaltungen.",
|
|
4610
|
+
historyDelete: "L\xF6schen",
|
|
4611
|
+
historyClear: "Alle l\xF6schen",
|
|
4612
|
+
untitledConversation: "Unbenannte Unterhaltung"
|
|
4117
4613
|
},
|
|
4118
4614
|
ru: {
|
|
4119
4615
|
assistantTitle: "\u0418\u0418-\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043D\u0442",
|
|
@@ -4128,7 +4624,7 @@ var STRINGS = {
|
|
|
4128
4624
|
close: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C",
|
|
4129
4625
|
minimize: "\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C",
|
|
4130
4626
|
newConversation: "\u041D\u043E\u0432\u044B\u0439 \u0434\u0438\u0430\u043B\u043E\u0433",
|
|
4131
|
-
poweredBy: "\u0420\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043D\u0430
|
|
4627
|
+
poweredBy: "\u0420\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043D\u0430 DabaLabs",
|
|
4132
4628
|
errorGeneric: "\u0427\u0442\u043E-\u0442\u043E \u043F\u043E\u0448\u043B\u043E \u043D\u0435 \u0442\u0430\u043A. \u041F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437.",
|
|
4133
4629
|
errorMicDenied: "\u0414\u043E\u0441\u0442\u0443\u043F \u043A \u043C\u0438\u043A\u0440\u043E\u0444\u043E\u043D\u0443 \u0437\u0430\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u043D. \u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u0435 \u0435\u0433\u043E \u0432 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430, \u0447\u0442\u043E\u0431\u044B \u0433\u043E\u0432\u043E\u0440\u0438\u0442\u044C.",
|
|
4134
4630
|
errorOffline: "\u041F\u043E\u0445\u043E\u0436\u0435, \u0432\u044B \u043D\u0435 \u0432 \u0441\u0435\u0442\u0438. \u041F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435.",
|
|
@@ -4145,7 +4641,13 @@ var STRINGS = {
|
|
|
4145
4641
|
retry: "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C",
|
|
4146
4642
|
typeOrTalk: "\u041D\u0430\u043F\u0438\u0448\u0438\u0442\u0435 \u0438\u043B\u0438 \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u043D\u0430 \u043C\u0438\u043A\u0440\u043E\u0444\u043E\u043D, \u0447\u0442\u043E\u0431\u044B \u0433\u043E\u0432\u043E\u0440\u0438\u0442\u044C",
|
|
4147
4643
|
voiceUnavailable: "\u0413\u043E\u043B\u043E\u0441\u043E\u0432\u043E\u0439 \u0440\u0435\u0436\u0438\u043C \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D \u043D\u0430 \u044D\u0442\u043E\u043C \u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u0435.",
|
|
4148
|
-
cardsLabel: "\u0420\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u044B"
|
|
4644
|
+
cardsLabel: "\u0420\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u044B",
|
|
4645
|
+
history: "\u0418\u0441\u0442\u043E\u0440\u0438\u044F",
|
|
4646
|
+
historyBack: "\u041D\u0430\u0437\u0430\u0434",
|
|
4647
|
+
historyEmpty: "\u041F\u0440\u043E\u0448\u043B\u044B\u0445 \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u043E\u0432 \u043F\u043E\u043A\u0430 \u043D\u0435\u0442.",
|
|
4648
|
+
historyDelete: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C",
|
|
4649
|
+
historyClear: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0432\u0441\u0435",
|
|
4650
|
+
untitledConversation: "\u0420\u0430\u0437\u0433\u043E\u0432\u043E\u0440 \u0431\u0435\u0437 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u044F"
|
|
4149
4651
|
},
|
|
4150
4652
|
tr: {
|
|
4151
4653
|
assistantTitle: "Yapay Zek\xE2 Asistan\u0131",
|
|
@@ -4160,7 +4662,7 @@ var STRINGS = {
|
|
|
4160
4662
|
close: "Kapat",
|
|
4161
4663
|
minimize: "K\xFC\xE7\xFClt",
|
|
4162
4664
|
newConversation: "Yeni sohbet",
|
|
4163
|
-
poweredBy: "
|
|
4665
|
+
poweredBy: "DabaLabs taraf\u0131ndan sa\u011Flan\u0131r",
|
|
4164
4666
|
errorGeneric: "Bir \u015Feyler ters gitti. L\xFCtfen tekrar deneyin.",
|
|
4165
4667
|
errorMicDenied: "Mikrofon eri\u015Fimi engellendi. Konu\u015Fmak i\xE7in taray\u0131c\u0131 ayarlar\u0131ndan izin verin.",
|
|
4166
4668
|
errorOffline: "\xC7evrimd\u0131\u015F\u0131 g\xF6r\xFCn\xFCyorsunuz. Ba\u011Flant\u0131n\u0131z\u0131 kontrol edin.",
|
|
@@ -4177,7 +4679,13 @@ var STRINGS = {
|
|
|
4177
4679
|
retry: "Tekrar dene",
|
|
4178
4680
|
typeOrTalk: "Yaz\u0131n veya konu\u015Fmak i\xE7in mikrofona dokunun",
|
|
4179
4681
|
voiceUnavailable: "Sesli g\xF6r\xFC\u015Fme bu cihazda kullan\u0131lam\u0131yor.",
|
|
4180
|
-
cardsLabel: "Sonu\xE7lar"
|
|
4682
|
+
cardsLabel: "Sonu\xE7lar",
|
|
4683
|
+
history: "Ge\xE7mi\u015F",
|
|
4684
|
+
historyBack: "Geri",
|
|
4685
|
+
historyEmpty: "Hen\xFCz ge\xE7mi\u015F sohbet yok.",
|
|
4686
|
+
historyDelete: "Sil",
|
|
4687
|
+
historyClear: "T\xFCm\xFCn\xFC temizle",
|
|
4688
|
+
untitledConversation: "Ads\u0131z sohbet"
|
|
4181
4689
|
},
|
|
4182
4690
|
ur: {
|
|
4183
4691
|
assistantTitle: "\u0627\u06D2 \u0622\u0626\u06CC \u0627\u0633\u0633\u0679\u0646\u0679",
|
|
@@ -4192,7 +4700,7 @@ var STRINGS = {
|
|
|
4192
4700
|
close: "\u0628\u0646\u062F \u06A9\u0631\u06CC\u06BA",
|
|
4193
4701
|
minimize: "\u0686\u06BE\u0648\u0679\u0627 \u06A9\u0631\u06CC\u06BA",
|
|
4194
4702
|
newConversation: "\u0646\u0626\u06CC \u06AF\u0641\u062A\u06AF\u0648",
|
|
4195
|
-
poweredBy: "
|
|
4703
|
+
poweredBy: "DabaLabs \u06A9\u06D2 \u062A\u0639\u0627\u0648\u0646 \u0633\u06D2",
|
|
4196
4704
|
errorGeneric: "\u06A9\u0686\u06BE \u063A\u0644\u0637 \u06C1\u0648 \u06AF\u06CC\u0627\u06D4 \u0628\u0631\u0627\u06C1 \u06A9\u0631\u0645 \u062F\u0648\u0628\u0627\u0631\u06C1 \u06A9\u0648\u0634\u0634 \u06A9\u0631\u06CC\u06BA\u06D4",
|
|
4197
4705
|
errorMicDenied: "\u0645\u0627\u0626\u06CC\u06A9\u0631\u0648\u0641\u0648\u0646 \u062A\u06A9 \u0631\u0633\u0627\u0626\u06CC \u0628\u0644\u0627\u06A9 \u06A9\u0631 \u062F\u06CC \u06AF\u0626\u06CC \u06C1\u06D2\u06D4 \u0628\u0627\u062A \u06A9\u0631\u0646\u06D2 \u06A9\u06D2 \u0644\u06CC\u06D2 \u0628\u0631\u0627\u0624\u0632\u0631 \u06A9\u06CC \u062A\u0631\u062A\u06CC\u0628\u0627\u062A \u0645\u06CC\u06BA \u0627\u062C\u0627\u0632\u062A \u062F\u06CC\u06BA\u06D4",
|
|
4198
4706
|
errorOffline: "\u0644\u06AF\u062A\u0627 \u06C1\u06D2 \u0622\u067E \u0622\u0641 \u0644\u0627\u0626\u0646 \u06C1\u06CC\u06BA\u06D4 \u0627\u067E\u0646\u0627 \u06A9\u0646\u06A9\u0634\u0646 \u0686\u06CC\u06A9 \u06A9\u0631\u06CC\u06BA\u06D4",
|
|
@@ -4209,7 +4717,13 @@ var STRINGS = {
|
|
|
4209
4717
|
retry: "\u062F\u0648\u0628\u0627\u0631\u06C1 \u06A9\u0648\u0634\u0634 \u06A9\u0631\u06CC\u06BA",
|
|
4210
4718
|
typeOrTalk: "\u0644\u06A9\u06BE\u06CC\u06BA \u06CC\u0627 \u0628\u0627\u062A \u06A9\u0631\u0646\u06D2 \u06A9\u06D2 \u0644\u06CC\u06D2 \u0645\u0627\u0626\u06CC\u06A9\u0631\u0648\u0641\u0648\u0646 \u062F\u0628\u0627\u0626\u06CC\u06BA",
|
|
4211
4719
|
voiceUnavailable: "\u0627\u0633 \u0688\u06CC\u0648\u0627\u0626\u0633 \u067E\u0631 \u0635\u0648\u062A\u06CC \u06AF\u0641\u062A\u06AF\u0648 \u062F\u0633\u062A\u06CC\u0627\u0628 \u0646\u06C1\u06CC\u06BA \u06C1\u06D2\u06D4",
|
|
4212
|
-
cardsLabel: "\u0646\u062A\u0627\u0626\u062C"
|
|
4720
|
+
cardsLabel: "\u0646\u062A\u0627\u0626\u062C",
|
|
4721
|
+
history: "\u062A\u0627\u0631\u06CC\u062E",
|
|
4722
|
+
historyBack: "\u0648\u0627\u067E\u0633",
|
|
4723
|
+
historyEmpty: "\u0627\u0628\u06BE\u06CC \u062A\u06A9 \u06A9\u0648\u0626\u06CC \u067E\u0686\u06BE\u0644\u06CC \u06AF\u0641\u062A\u06AF\u0648 \u0646\u06C1\u06CC\u06BA\u06D4",
|
|
4724
|
+
historyDelete: "\u062D\u0630\u0641 \u06A9\u0631\u06CC\u06BA",
|
|
4725
|
+
historyClear: "\u0633\u0628 \u0635\u0627\u0641 \u06A9\u0631\u06CC\u06BA",
|
|
4726
|
+
untitledConversation: "\u0628\u0644\u0627 \u0639\u0646\u0648\u0627\u0646 \u06AF\u0641\u062A\u06AF\u0648"
|
|
4213
4727
|
},
|
|
4214
4728
|
hi: {
|
|
4215
4729
|
assistantTitle: "\u090F\u0906\u0908 \u0938\u0939\u093E\u092F\u0915",
|
|
@@ -4224,7 +4738,7 @@ var STRINGS = {
|
|
|
4224
4738
|
close: "\u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
|
|
4225
4739
|
minimize: "\u091B\u094B\u091F\u093E \u0915\u0930\u0947\u0902",
|
|
4226
4740
|
newConversation: "\u0928\u0908 \u092C\u093E\u0924\u091A\u0940\u0924",
|
|
4227
|
-
poweredBy: "
|
|
4741
|
+
poweredBy: "DabaLabs \u0926\u094D\u0935\u093E\u0930\u093E \u0938\u0902\u091A\u093E\u0932\u093F\u0924",
|
|
4228
4742
|
errorGeneric: "\u0915\u0941\u091B \u0917\u0921\u093C\u092C\u0921\u093C \u0939\u094B \u0917\u0908\u0964 \u0915\u0943\u092A\u092F\u093E \u092B\u093F\u0930 \u0938\u0947 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0947\u0902\u0964",
|
|
4229
4743
|
errorMicDenied: "\u092E\u093E\u0907\u0915\u094D\u0930\u094B\u092B\u093C\u094B\u0928 \u0915\u0940 \u0905\u0928\u0941\u092E\u0924\u093F \u0930\u094B\u0915 \u0926\u0940 \u0917\u0908 \u0939\u0948\u0964 \u092C\u093E\u0924 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u092C\u094D\u0930\u093E\u0909\u091C\u093C\u0930 \u0938\u0947\u091F\u093F\u0902\u0917\u094D\u0938 \u092E\u0947\u0902 \u0907\u0938\u0947 \u0905\u0928\u0941\u092E\u0924\u093F \u0926\u0947\u0902\u0964",
|
|
4230
4744
|
errorOffline: "\u0906\u092A \u0911\u092B\u093C\u0932\u093E\u0907\u0928 \u0932\u0917 \u0930\u0939\u0947 \u0939\u0948\u0902\u0964 \u0905\u092A\u0928\u093E \u0915\u0928\u0947\u0915\u094D\u0936\u0928 \u091C\u093E\u0901\u091A\u0947\u0902\u0964",
|
|
@@ -4241,7 +4755,13 @@ var STRINGS = {
|
|
|
4241
4755
|
retry: "\u092B\u093F\u0930 \u0938\u0947 \u0915\u094B\u0936\u093F\u0936 \u0915\u0930\u0947\u0902",
|
|
4242
4756
|
typeOrTalk: "\u0932\u093F\u0916\u0947\u0902 \u092F\u093E \u092C\u093E\u0924 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u092E\u093E\u0907\u0915\u094D\u0930\u094B\u092B\u093C\u094B\u0928 \u0926\u092C\u093E\u090F\u0901",
|
|
4243
4757
|
voiceUnavailable: "\u0907\u0938 \u0921\u093F\u0935\u093E\u0907\u0938 \u092A\u0930 \u0935\u0949\u0907\u0938 \u0909\u092A\u0932\u092C\u094D\u0927 \u0928\u0939\u0940\u0902 \u0939\u0948\u0964",
|
|
4244
|
-
cardsLabel: "\u092A\u0930\u093F\u0923\u093E\u092E"
|
|
4758
|
+
cardsLabel: "\u092A\u0930\u093F\u0923\u093E\u092E",
|
|
4759
|
+
history: "\u0907\u0924\u093F\u0939\u093E\u0938",
|
|
4760
|
+
historyBack: "\u0935\u093E\u092A\u0938",
|
|
4761
|
+
historyEmpty: "\u0905\u092D\u0940 \u0924\u0915 \u0915\u094B\u0908 \u092A\u093F\u091B\u0932\u0940 \u092C\u093E\u0924\u091A\u0940\u0924 \u0928\u0939\u0940\u0902\u0964",
|
|
4762
|
+
historyDelete: "\u0939\u091F\u093E\u090F\u0901",
|
|
4763
|
+
historyClear: "\u0938\u092D\u0940 \u0938\u093E\u092B\u093C \u0915\u0930\u0947\u0902",
|
|
4764
|
+
untitledConversation: "\u092C\u093F\u0928\u093E \u0936\u0940\u0930\u094D\u0937\u0915 \u092C\u093E\u0924\u091A\u0940\u0924"
|
|
4245
4765
|
},
|
|
4246
4766
|
zh: {
|
|
4247
4767
|
assistantTitle: "AI \u52A9\u624B",
|
|
@@ -4256,7 +4776,7 @@ var STRINGS = {
|
|
|
4256
4776
|
close: "\u5173\u95ED",
|
|
4257
4777
|
minimize: "\u6700\u5C0F\u5316",
|
|
4258
4778
|
newConversation: "\u65B0\u5BF9\u8BDD",
|
|
4259
|
-
poweredBy: "\u7531
|
|
4779
|
+
poweredBy: "\u7531 DabaLabs \u63D0\u4F9B\u652F\u6301",
|
|
4260
4780
|
errorGeneric: "\u51FA\u4E86\u70B9\u95EE\u9898\uFF0C\u8BF7\u91CD\u8BD5\u3002",
|
|
4261
4781
|
errorMicDenied: "\u9EA6\u514B\u98CE\u6743\u9650\u88AB\u62D2\u7EDD\u3002\u8BF7\u5728\u6D4F\u89C8\u5668\u8BBE\u7F6E\u4E2D\u5141\u8BB8\u540E\u518D\u4F7F\u7528\u8BED\u97F3\u3002",
|
|
4262
4782
|
errorOffline: "\u4F60\u4F3C\u4E4E\u5DF2\u79BB\u7EBF\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u3002",
|
|
@@ -4273,7 +4793,13 @@ var STRINGS = {
|
|
|
4273
4793
|
retry: "\u91CD\u8BD5",
|
|
4274
4794
|
typeOrTalk: "\u8F93\u5165\u95EE\u9898\uFF0C\u6216\u70B9\u51FB\u9EA6\u514B\u98CE\u8BF4\u8BDD",
|
|
4275
4795
|
voiceUnavailable: "\u6B64\u8BBE\u5907\u4E0D\u652F\u6301\u8BED\u97F3\u529F\u80FD\u3002",
|
|
4276
|
-
cardsLabel: "\u7ED3\u679C"
|
|
4796
|
+
cardsLabel: "\u7ED3\u679C",
|
|
4797
|
+
history: "\u5386\u53F2\u8BB0\u5F55",
|
|
4798
|
+
historyBack: "\u8FD4\u56DE",
|
|
4799
|
+
historyEmpty: "\u8FD8\u6CA1\u6709\u5386\u53F2\u5BF9\u8BDD\u3002",
|
|
4800
|
+
historyDelete: "\u5220\u9664",
|
|
4801
|
+
historyClear: "\u5168\u90E8\u6E05\u9664",
|
|
4802
|
+
untitledConversation: "\u672A\u547D\u540D\u5BF9\u8BDD"
|
|
4277
4803
|
},
|
|
4278
4804
|
pt: {
|
|
4279
4805
|
assistantTitle: "Assistente de IA",
|
|
@@ -4288,7 +4814,7 @@ var STRINGS = {
|
|
|
4288
4814
|
close: "Fechar",
|
|
4289
4815
|
minimize: "Minimizar",
|
|
4290
4816
|
newConversation: "Nova conversa",
|
|
4291
|
-
poweredBy: "Com tecnologia da
|
|
4817
|
+
poweredBy: "Com tecnologia da DabaLabs",
|
|
4292
4818
|
errorGeneric: "Algo deu errado. Tente novamente.",
|
|
4293
4819
|
errorMicDenied: "O acesso ao microfone foi bloqueado. Permita-o nas configura\xE7\xF5es do navegador para falar.",
|
|
4294
4820
|
errorOffline: "Parece que voc\xEA est\xE1 offline. Verifique sua conex\xE3o.",
|
|
@@ -4305,7 +4831,13 @@ var STRINGS = {
|
|
|
4305
4831
|
retry: "Tentar novamente",
|
|
4306
4832
|
typeOrTalk: "Escreva, ou toque no microfone para falar",
|
|
4307
4833
|
voiceUnavailable: "A voz n\xE3o est\xE1 dispon\xEDvel neste dispositivo.",
|
|
4308
|
-
cardsLabel: "Resultados"
|
|
4834
|
+
cardsLabel: "Resultados",
|
|
4835
|
+
history: "Hist\xF3rico",
|
|
4836
|
+
historyBack: "Voltar",
|
|
4837
|
+
historyEmpty: "Ainda n\xE3o h\xE1 conversas anteriores.",
|
|
4838
|
+
historyDelete: "Excluir",
|
|
4839
|
+
historyClear: "Limpar tudo",
|
|
4840
|
+
untitledConversation: "Conversa sem t\xEDtulo"
|
|
4309
4841
|
},
|
|
4310
4842
|
id: {
|
|
4311
4843
|
assistantTitle: "Asisten AI",
|
|
@@ -4320,7 +4852,7 @@ var STRINGS = {
|
|
|
4320
4852
|
close: "Tutup",
|
|
4321
4853
|
minimize: "Perkecil",
|
|
4322
4854
|
newConversation: "Percakapan baru",
|
|
4323
|
-
poweredBy: "Didukung oleh
|
|
4855
|
+
poweredBy: "Didukung oleh DabaLabs",
|
|
4324
4856
|
errorGeneric: "Terjadi kesalahan. Silakan coba lagi.",
|
|
4325
4857
|
errorMicDenied: "Akses mikrofon diblokir. Izinkan di pengaturan browser untuk berbicara.",
|
|
4326
4858
|
errorOffline: "Sepertinya Anda sedang offline. Periksa koneksi Anda.",
|
|
@@ -4337,7 +4869,13 @@ var STRINGS = {
|
|
|
4337
4869
|
retry: "Coba lagi",
|
|
4338
4870
|
typeOrTalk: "Ketik, atau ketuk mikrofon untuk berbicara",
|
|
4339
4871
|
voiceUnavailable: "Suara tidak tersedia di perangkat ini.",
|
|
4340
|
-
cardsLabel: "Hasil"
|
|
4872
|
+
cardsLabel: "Hasil",
|
|
4873
|
+
history: "Riwayat",
|
|
4874
|
+
historyBack: "Kembali",
|
|
4875
|
+
historyEmpty: "Belum ada percakapan sebelumnya.",
|
|
4876
|
+
historyDelete: "Hapus",
|
|
4877
|
+
historyClear: "Hapus semua",
|
|
4878
|
+
untitledConversation: "Percakapan tanpa judul"
|
|
4341
4879
|
}
|
|
4342
4880
|
};
|
|
4343
4881
|
var RTL_SUBTAGS = /* @__PURE__ */ new Set(["ar", "arc", "ckb", "dv", "fa", "he", "iw", "ku", "prs", "ps", "sd", "ug", "ur", "yi", "ji"]);
|
|
@@ -4390,9 +4928,41 @@ function stringsFor(lang) {
|
|
|
4390
4928
|
}
|
|
4391
4929
|
|
|
4392
4930
|
// src/utils/hotkey.ts
|
|
4931
|
+
var HOLD_MS = 600;
|
|
4932
|
+
var HOLD_KEYS = {
|
|
4933
|
+
ctrl: ["Control"],
|
|
4934
|
+
alt: ["Alt"],
|
|
4935
|
+
shift: ["Shift"],
|
|
4936
|
+
meta: ["Meta", "OS"]
|
|
4937
|
+
};
|
|
4938
|
+
function holdModifier(hotkey) {
|
|
4939
|
+
if (!hotkey.hold) return null;
|
|
4940
|
+
if (hotkey.ctrl) return "ctrl";
|
|
4941
|
+
if (hotkey.alt) return "alt";
|
|
4942
|
+
if (hotkey.shift) return "shift";
|
|
4943
|
+
if (hotkey.meta) return "meta";
|
|
4944
|
+
return null;
|
|
4945
|
+
}
|
|
4946
|
+
function holdHotkeyProblem(hotkey) {
|
|
4947
|
+
const parsed = parseHotkey(hotkey);
|
|
4948
|
+
if (!parsed.hold) return null;
|
|
4949
|
+
if (parsed.key !== "") {
|
|
4950
|
+
return `"hold:" waits on a modifier held by itself, so it cannot also carry the key "${parsed.key}"`;
|
|
4951
|
+
}
|
|
4952
|
+
const count = [parsed.ctrl, parsed.alt, parsed.shift, parsed.meta].filter(Boolean).length;
|
|
4953
|
+
if (count === 0) return `"hold:" needs one of ctrl, alt, shift or cmd after it`;
|
|
4954
|
+
if (count > 1) return `"hold:" waits on a single modifier, not a combination`;
|
|
4955
|
+
return null;
|
|
4956
|
+
}
|
|
4957
|
+
function isHoldKey(e, modifier) {
|
|
4958
|
+
return HOLD_KEYS[modifier].includes(e.key);
|
|
4959
|
+
}
|
|
4393
4960
|
function parseHotkey(hotkey) {
|
|
4394
|
-
const
|
|
4961
|
+
const raw = hotkey.toLowerCase().trim();
|
|
4962
|
+
const hold = raw.startsWith("hold:");
|
|
4963
|
+
const parts = (hold ? raw.slice(5) : raw).split("+").map((p) => p.trim());
|
|
4395
4964
|
return {
|
|
4965
|
+
hold,
|
|
4396
4966
|
ctrl: parts.includes("ctrl") || parts.includes("control"),
|
|
4397
4967
|
alt: parts.includes("alt"),
|
|
4398
4968
|
shift: parts.includes("shift"),
|
|
@@ -4421,6 +4991,11 @@ function defaultHotkey() {
|
|
|
4421
4991
|
}
|
|
4422
4992
|
function hotkeyLabel(hotkey) {
|
|
4423
4993
|
const parsed = parseHotkey(hotkey);
|
|
4994
|
+
const held = holdModifier(parsed);
|
|
4995
|
+
if (held) {
|
|
4996
|
+
const name = isApplePlatform() ? { ctrl: "\u2303", alt: "\u2325", shift: "\u21E7", meta: "\u2318" }[held] : { ctrl: "Ctrl", alt: "Alt", shift: "Shift", meta: "Win" }[held];
|
|
4997
|
+
return `Hold ${name}`;
|
|
4998
|
+
}
|
|
4424
4999
|
const keyName = parsed.key === "space" ? "Space" : parsed.key.length === 1 ? parsed.key.toUpperCase() : parsed.key;
|
|
4425
5000
|
if (isApplePlatform()) {
|
|
4426
5001
|
const mods2 = [parsed.ctrl && "\u2303", parsed.alt && "\u2325", parsed.shift && "\u21E7", parsed.meta && "\u2318"].filter(Boolean);
|
|
@@ -4475,6 +5050,13 @@ function readConversationId(projectId) {
|
|
|
4475
5050
|
var DabaAgent = class {
|
|
4476
5051
|
constructor(options) {
|
|
4477
5052
|
this.keydownHandler = (e) => this.handleKeydown(e);
|
|
5053
|
+
this.keyupHandler = (e) => this.handleKeyup(e);
|
|
5054
|
+
this.blurHandler = () => this.cancelHold();
|
|
5055
|
+
this.holdTimer = null;
|
|
5056
|
+
/** Set the moment a hold activates and cleared only on the matching
|
|
5057
|
+
* keyup, so one physical press cannot start two sessions if the browser
|
|
5058
|
+
* repeats the modifier keydown. */
|
|
5059
|
+
this.holdFired = false;
|
|
4478
5060
|
this.status = "idle";
|
|
4479
5061
|
this.isOpen = false;
|
|
4480
5062
|
this.destroyed = false;
|
|
@@ -4487,6 +5069,7 @@ var DabaAgent = class {
|
|
|
4487
5069
|
this.messages = [];
|
|
4488
5070
|
this.currentStreamBubble = null;
|
|
4489
5071
|
this.currentStreamRole = null;
|
|
5072
|
+
this.currentStreamText = "";
|
|
4490
5073
|
this.chatInFlight = false;
|
|
4491
5074
|
this.remoteConfig = null;
|
|
4492
5075
|
this.live = null;
|
|
@@ -4508,6 +5091,16 @@ var DabaAgent = class {
|
|
|
4508
5091
|
this.strings = stringsFor(this.uiLang);
|
|
4509
5092
|
this.conversationId = readConversationId(options.projectId);
|
|
4510
5093
|
this.restricted = isPageRestricted();
|
|
5094
|
+
const requested = options.hotkey ?? defaultHotkey();
|
|
5095
|
+
const holdProblem = options.hotkey === null ? null : holdHotkeyProblem(requested);
|
|
5096
|
+
if (holdProblem) {
|
|
5097
|
+
console.error(`daba-agent: ignoring hotkey "${requested}" \u2014 ${holdProblem}. Falling back to ${defaultHotkey()}.`);
|
|
5098
|
+
}
|
|
5099
|
+
const effective = holdProblem ? defaultHotkey() : requested;
|
|
5100
|
+
this.parsedHotkey = options.hotkey === null ? null : parseHotkey(effective);
|
|
5101
|
+
this.heldModifier = this.parsedHotkey ? holdModifier(this.parsedHotkey) : null;
|
|
5102
|
+
const touchOnly = typeof window.matchMedia === "function" && window.matchMedia("(hover: none) and (pointer: coarse)").matches;
|
|
5103
|
+
this.hotkeyText = this.parsedHotkey && !touchOnly ? hotkeyLabel(effective) : null;
|
|
4511
5104
|
if (this.restricted) {
|
|
4512
5105
|
console.warn(
|
|
4513
5106
|
"daba-agent: this page has data-daba-agent-restricted set \u2014 the assistant will not read this page or start a session here."
|
|
@@ -4531,6 +5124,13 @@ var DabaAgent = class {
|
|
|
4531
5124
|
},
|
|
4532
5125
|
setStatusText: () => {
|
|
4533
5126
|
},
|
|
5127
|
+
clearMessages: () => {
|
|
5128
|
+
},
|
|
5129
|
+
setHistoryVisible: () => {
|
|
5130
|
+
},
|
|
5131
|
+
isHistoryVisible: () => false,
|
|
5132
|
+
refreshHistory: () => {
|
|
5133
|
+
},
|
|
4534
5134
|
applyConfig: () => {
|
|
4535
5135
|
}
|
|
4536
5136
|
};
|
|
@@ -4544,7 +5144,8 @@ var DabaAgent = class {
|
|
|
4544
5144
|
this.mode,
|
|
4545
5145
|
options.accentColor,
|
|
4546
5146
|
options.iconBackgroundColor,
|
|
4547
|
-
options.iconMarkColor
|
|
5147
|
+
options.iconMarkColor,
|
|
5148
|
+
this.hotkeyText
|
|
4548
5149
|
);
|
|
4549
5150
|
this.badge = badgeUI.root;
|
|
4550
5151
|
this.badgeLabel = badgeUI.label;
|
|
@@ -4564,6 +5165,20 @@ var DabaAgent = class {
|
|
|
4564
5165
|
}
|
|
4565
5166
|
if (options.theme) applyThemeTokens(wrapper, options.theme);
|
|
4566
5167
|
if (options.accentColor) applyThemeTokens(wrapper, { accent: options.accentColor });
|
|
5168
|
+
applyThemeTokens(wrapper, {
|
|
5169
|
+
"icon-bg": options.iconBackgroundColor,
|
|
5170
|
+
"icon-mark": options.iconMarkColor,
|
|
5171
|
+
"badge-size": cssLength(options.launcher?.size),
|
|
5172
|
+
"badge-icon-size": cssLength(options.launcher?.iconSize),
|
|
5173
|
+
"panel-w": cssLength(options.panel?.width),
|
|
5174
|
+
"panel-h": cssLength(options.panel?.height)
|
|
5175
|
+
});
|
|
5176
|
+
const mark = {
|
|
5177
|
+
svg: options.launcher?.iconSvg,
|
|
5178
|
+
text: options.launcher?.iconText,
|
|
5179
|
+
url: options.launcher?.iconUrl
|
|
5180
|
+
};
|
|
5181
|
+
if (mark.svg || mark.text || mark.url) setBadgeIcon(this.badge, mark);
|
|
4567
5182
|
const chatUI = buildChatWindow({
|
|
4568
5183
|
title: options.title ?? this.strings.assistantTitle,
|
|
4569
5184
|
placeholder: options.placeholder ?? (this.mode === "chat" ? this.strings.inputPlaceholder : this.strings.typeOrTalk),
|
|
@@ -4573,12 +5188,18 @@ var DabaAgent = class {
|
|
|
4573
5188
|
mode: this.mode,
|
|
4574
5189
|
intro: options.intro ?? {},
|
|
4575
5190
|
logoUrl: options.logoUrl,
|
|
5191
|
+
logoSvg: options.logoSvg,
|
|
4576
5192
|
// null disables the shortcut entirely; the hint disappears with it.
|
|
4577
|
-
hotkeyLabel:
|
|
5193
|
+
hotkeyLabel: this.hotkeyText,
|
|
4578
5194
|
onSendText: (text) => void this.sendText(text),
|
|
4579
5195
|
onMicClick: () => void this.toggleVoice(),
|
|
4580
5196
|
onCloseClick: () => this.closeChat(),
|
|
4581
|
-
|
|
5197
|
+
historyEnabled: options.historyEnabled === true,
|
|
5198
|
+
onNewConversation: () => this.resetConversation(),
|
|
5199
|
+
onListHistory: () => this.listConversations(),
|
|
5200
|
+
onOpenConversation: (id) => this.openConversation(id),
|
|
5201
|
+
onDeleteConversation: (id) => this.deleteConversation(id),
|
|
5202
|
+
onClearHistory: () => this.clearHistory()
|
|
4582
5203
|
});
|
|
4583
5204
|
this.ui = chatUI;
|
|
4584
5205
|
this.chatWindow = chatUI.chatWindow;
|
|
@@ -4592,8 +5213,13 @@ var DabaAgent = class {
|
|
|
4592
5213
|
}
|
|
4593
5214
|
if (options.hotkey !== null) {
|
|
4594
5215
|
document.addEventListener("keydown", this.keydownHandler);
|
|
5216
|
+
document.addEventListener("keyup", this.keyupHandler);
|
|
5217
|
+
window.addEventListener("blur", this.blurHandler);
|
|
5218
|
+
document.addEventListener("pointerdown", this.blurHandler, true);
|
|
5219
|
+
document.addEventListener("visibilitychange", this.blurHandler);
|
|
4595
5220
|
}
|
|
4596
5221
|
this.restoreTranscript();
|
|
5222
|
+
this.ui.refreshHistory();
|
|
4597
5223
|
void this.tryReattach();
|
|
4598
5224
|
void this.loadRemoteConfig();
|
|
4599
5225
|
}
|
|
@@ -4601,7 +5227,12 @@ var DabaAgent = class {
|
|
|
4601
5227
|
* navigate() lands the visitor mid-conversation, not on a blank intro
|
|
4602
5228
|
* while the model silently remembers the last four turns. */
|
|
4603
5229
|
restoreTranscript() {
|
|
4604
|
-
|
|
5230
|
+
this.renderMessages(readTranscript(this.options.projectId, this.conversationId));
|
|
5231
|
+
}
|
|
5232
|
+
/** Put a stored thread on screen and into `messages`. Shared by the
|
|
5233
|
+
* reload path and by opening something out of the archive, so a
|
|
5234
|
+
* reopened conversation behaves exactly like a resumed one. */
|
|
5235
|
+
renderMessages(saved) {
|
|
4605
5236
|
if (!saved.length) return;
|
|
4606
5237
|
for (const m of saved) {
|
|
4607
5238
|
const cards = Array.isArray(m.cards) ? m.cards : [];
|
|
@@ -4625,11 +5256,54 @@ var DabaAgent = class {
|
|
|
4625
5256
|
}
|
|
4626
5257
|
saveTranscript() {
|
|
4627
5258
|
persistConversationId(this.options.projectId, this.conversationId);
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
5259
|
+
const stored = this.messages.filter((m) => m.role !== "system").map((m) => ({ role: m.role, text: m.text, cards: m.cards, suggestions: m.suggestions, ts: m.timestamp }));
|
|
5260
|
+
persistTranscript(this.options.projectId, this.conversationId, stored);
|
|
5261
|
+
if (this.options.historyEnabled) {
|
|
5262
|
+
archiveConversation(
|
|
5263
|
+
this.options.projectId,
|
|
5264
|
+
this.conversationId,
|
|
5265
|
+
stored,
|
|
5266
|
+
window.location.pathname,
|
|
5267
|
+
this.strings.untitledConversation
|
|
5268
|
+
);
|
|
5269
|
+
this.ui.refreshHistory();
|
|
5270
|
+
}
|
|
5271
|
+
}
|
|
5272
|
+
/** The archive, newest first. Empty unless the embed opted in. */
|
|
5273
|
+
listConversations() {
|
|
5274
|
+
if (!this.options.historyEnabled || this.restricted) return [];
|
|
5275
|
+
return listConversations(this.options.projectId);
|
|
5276
|
+
}
|
|
5277
|
+
/**
|
|
5278
|
+
* Reopen an archived conversation as the LIVE one.
|
|
5279
|
+
*
|
|
5280
|
+
* Resuming rather than previewing: the gateway keeps its own thread
|
|
5281
|
+
* state keyed on the conversation id, so restoring the id means the
|
|
5282
|
+
* model still has the context the visitor is looking at. A read-only
|
|
5283
|
+
* view would show a conversation they cannot continue, which is the one
|
|
5284
|
+
* thing "go back to my chat" does not mean.
|
|
5285
|
+
*/
|
|
5286
|
+
openConversation(id) {
|
|
5287
|
+
if (!this.options.historyEnabled || this.restricted) return;
|
|
5288
|
+
const saved = readConversation(this.options.projectId, id);
|
|
5289
|
+
if (!saved.length) return;
|
|
5290
|
+
this.messages = [];
|
|
5291
|
+
this.ui.clearMessages();
|
|
5292
|
+
this.conversationId = id;
|
|
5293
|
+
persistConversationId(this.options.projectId, id);
|
|
5294
|
+
persistTranscript(this.options.projectId, id, saved);
|
|
5295
|
+
this.renderMessages(saved);
|
|
5296
|
+
}
|
|
5297
|
+
deleteConversation(id) {
|
|
5298
|
+
if (!this.options.historyEnabled) return;
|
|
5299
|
+
deleteConversation(this.options.projectId, id);
|
|
5300
|
+
if (id === this.conversationId) this.resetConversation();
|
|
5301
|
+
this.ui.refreshHistory();
|
|
5302
|
+
}
|
|
5303
|
+
clearHistory() {
|
|
5304
|
+
if (!this.options.historyEnabled) return;
|
|
5305
|
+
clearConversations(this.options.projectId);
|
|
5306
|
+
this.ui.refreshHistory();
|
|
4633
5307
|
}
|
|
4634
5308
|
/**
|
|
4635
5309
|
* Pull the project's own mode, theme, intro and locale from the gateway.
|
|
@@ -4668,8 +5342,11 @@ var DabaAgent = class {
|
|
|
4668
5342
|
this.mode = config.mode;
|
|
4669
5343
|
this.applyMode();
|
|
4670
5344
|
}
|
|
4671
|
-
|
|
4672
|
-
|
|
5345
|
+
setBadgeIcon(this.badge, {
|
|
5346
|
+
svg: this.options.launcher?.iconSvg,
|
|
5347
|
+
text: this.options.launcher?.iconText,
|
|
5348
|
+
url: this.options.launcher?.iconUrl ?? a.launcherIconUrl
|
|
5349
|
+
});
|
|
4673
5350
|
this.ui.applyConfig({
|
|
4674
5351
|
logoUrl: this.options.logoUrl ?? a.logoUrl,
|
|
4675
5352
|
title: this.options.title ?? config.title,
|
|
@@ -4693,17 +5370,60 @@ var DabaAgent = class {
|
|
|
4693
5370
|
if (this.ui.composerMicBtn) this.ui.composerMicBtn.hidden = !showVoice;
|
|
4694
5371
|
}
|
|
4695
5372
|
handleKeydown(e) {
|
|
4696
|
-
if (this.destroyed || this.restricted) return;
|
|
5373
|
+
if (this.destroyed || this.restricted || !this.parsedHotkey) return;
|
|
5374
|
+
if (this.heldModifier) {
|
|
5375
|
+
if (!isHoldKey(e, this.heldModifier)) {
|
|
5376
|
+
this.cancelHold();
|
|
5377
|
+
return;
|
|
5378
|
+
}
|
|
5379
|
+
if (e.repeat || this.holdTimer !== null || this.holdFired) return;
|
|
5380
|
+
this.holdTimer = window.setTimeout(() => {
|
|
5381
|
+
this.holdTimer = null;
|
|
5382
|
+
this.holdFired = true;
|
|
5383
|
+
void this.activate();
|
|
5384
|
+
}, HOLD_MS);
|
|
5385
|
+
return;
|
|
5386
|
+
}
|
|
4697
5387
|
if (isEditableTarget(e.target) && e.target !== this.inputElement) return;
|
|
4698
5388
|
if (e.repeat) return;
|
|
4699
|
-
|
|
4700
|
-
if (!matchesHotkey(e, hotkey)) return;
|
|
5389
|
+
if (!matchesHotkey(e, this.parsedHotkey)) return;
|
|
4701
5390
|
e.preventDefault();
|
|
4702
5391
|
void this.toggle();
|
|
4703
5392
|
}
|
|
5393
|
+
handleKeyup(e) {
|
|
5394
|
+
if (!this.heldModifier || !isHoldKey(e, this.heldModifier)) return;
|
|
5395
|
+
this.cancelHold();
|
|
5396
|
+
this.holdFired = false;
|
|
5397
|
+
}
|
|
5398
|
+
/**
|
|
5399
|
+
* What a completed hold does: START talking, never stop.
|
|
5400
|
+
*
|
|
5401
|
+
* The panel advertises this as "Hold ^ to talk". A visitor who keeps
|
|
5402
|
+
* holding while they speak — which is what those words invite — was
|
|
5403
|
+
* hanging up on themselves, because the hold used to call toggle() and
|
|
5404
|
+
* the second completed hold ended the session. Ending a conversation is
|
|
5405
|
+
* the badge's job, and the badge tooltip already says so.
|
|
5406
|
+
*/
|
|
5407
|
+
async activate() {
|
|
5408
|
+
if (this.destroyed || this.restricted) return;
|
|
5409
|
+
if (this.mode === "chat") {
|
|
5410
|
+
this.openChat();
|
|
5411
|
+
return;
|
|
5412
|
+
}
|
|
5413
|
+
if (this.isActive) return;
|
|
5414
|
+
await this.startSession();
|
|
5415
|
+
}
|
|
5416
|
+
/** Releasing early, pressing another key, or leaving the tab all mean the
|
|
5417
|
+
* hold did not happen. Letting a stale timer survive any of those is how
|
|
5418
|
+
* a widget opens itself for no reason the visitor can see. */
|
|
5419
|
+
cancelHold() {
|
|
5420
|
+
if (this.holdTimer === null) return;
|
|
5421
|
+
window.clearTimeout(this.holdTimer);
|
|
5422
|
+
this.holdTimer = null;
|
|
5423
|
+
}
|
|
4704
5424
|
setStatus(status) {
|
|
4705
5425
|
this.status = status;
|
|
4706
|
-
updateBadge(this.badge, this.badgeLabel, status, this.position);
|
|
5426
|
+
updateBadge(this.badge, this.badgeLabel, status, this.position, this.hotkeyText);
|
|
4707
5427
|
this.options.onStatusChange?.(status);
|
|
4708
5428
|
if (status === "listening" || status === "speaking") {
|
|
4709
5429
|
this.micBtn.classList.add("daba-agent-header__btn--active");
|
|
@@ -4847,11 +5567,10 @@ var DabaAgent = class {
|
|
|
4847
5567
|
this.messages = [];
|
|
4848
5568
|
this.conversationId = newConversationId();
|
|
4849
5569
|
persistConversationId(this.options.projectId, this.conversationId);
|
|
4850
|
-
|
|
4851
|
-
if (child !== this.ui.introEl) child.remove();
|
|
4852
|
-
}
|
|
5570
|
+
this.ui.clearMessages();
|
|
4853
5571
|
this.ui.setIntroVisible(true);
|
|
4854
5572
|
this.ui.setTyping(false);
|
|
5573
|
+
this.ui.refreshHistory();
|
|
4855
5574
|
}
|
|
4856
5575
|
/** Voice, explicitly. Never reached in chat mode — the controls that
|
|
4857
5576
|
* would call it are not rendered there. */
|
|
@@ -4863,14 +5582,28 @@ var DabaAgent = class {
|
|
|
4863
5582
|
if (this.currentStreamRole !== role || !this.currentStreamBubble) {
|
|
4864
5583
|
this.currentStreamBubble = appendMessage(this.messagesContainer, "", role);
|
|
4865
5584
|
this.currentStreamRole = role;
|
|
5585
|
+
this.currentStreamText = "";
|
|
4866
5586
|
}
|
|
4867
5587
|
if (this.currentStreamBubble) {
|
|
5588
|
+
this.currentStreamText += text;
|
|
4868
5589
|
this.currentStreamBubble.textContent += text;
|
|
4869
5590
|
this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
|
|
4870
5591
|
}
|
|
4871
5592
|
if (isFinal) {
|
|
5593
|
+
const spoken = this.currentStreamText.trim();
|
|
5594
|
+
if (spoken) {
|
|
5595
|
+
this.messages.push({
|
|
5596
|
+
id: `${role}-${this.messages.length}-${Date.now()}`,
|
|
5597
|
+
role,
|
|
5598
|
+
text: spoken,
|
|
5599
|
+
timestamp: Date.now(),
|
|
5600
|
+
isFinal: true
|
|
5601
|
+
});
|
|
5602
|
+
this.saveTranscript();
|
|
5603
|
+
}
|
|
4872
5604
|
this.currentStreamBubble = null;
|
|
4873
5605
|
this.currentStreamRole = null;
|
|
5606
|
+
this.currentStreamText = "";
|
|
4874
5607
|
}
|
|
4875
5608
|
}
|
|
4876
5609
|
async toggle() {
|
|
@@ -5137,6 +5870,9 @@ Allow this?`);
|
|
|
5137
5870
|
}
|
|
5138
5871
|
}
|
|
5139
5872
|
stopSession() {
|
|
5873
|
+
const live = this.live;
|
|
5874
|
+
this.live = null;
|
|
5875
|
+
live?.stop();
|
|
5140
5876
|
this.ws?.close(HARD_STOP_CLOSE_CODE, "user_stopped");
|
|
5141
5877
|
clearPersistedSession(this.options.projectId);
|
|
5142
5878
|
this.cleanupAfterClose();
|
|
@@ -5165,7 +5901,7 @@ Allow this?`);
|
|
|
5165
5901
|
window.setTimeout(() => {
|
|
5166
5902
|
this.badge.classList.remove("daba-agent-badge--error");
|
|
5167
5903
|
if (this.status === "idle") {
|
|
5168
|
-
updateBadge(this.badge, this.badgeLabel, "idle", this.position);
|
|
5904
|
+
updateBadge(this.badge, this.badgeLabel, "idle", this.position, this.hotkeyText);
|
|
5169
5905
|
}
|
|
5170
5906
|
}, 4e3);
|
|
5171
5907
|
}
|
|
@@ -5184,12 +5920,17 @@ Allow this?`);
|
|
|
5184
5920
|
destroy() {
|
|
5185
5921
|
this.destroyed = true;
|
|
5186
5922
|
document.removeEventListener("keydown", this.keydownHandler);
|
|
5187
|
-
this.
|
|
5923
|
+
document.removeEventListener("keyup", this.keyupHandler);
|
|
5924
|
+
window.removeEventListener("blur", this.blurHandler);
|
|
5925
|
+
document.removeEventListener("pointerdown", this.blurHandler, true);
|
|
5926
|
+
document.removeEventListener("visibilitychange", this.blurHandler);
|
|
5927
|
+
this.cancelHold();
|
|
5928
|
+
if (this.isActive || this.ws || this.live) this.stopSession();
|
|
5188
5929
|
this.badge.parentElement?.remove();
|
|
5189
5930
|
this.badge.remove();
|
|
5190
5931
|
}
|
|
5191
5932
|
};
|
|
5192
5933
|
|
|
5193
|
-
export { DabaAgent };
|
|
5194
|
-
//# sourceMappingURL=chunk-
|
|
5195
|
-
//# sourceMappingURL=chunk-
|
|
5934
|
+
export { DabaAgent, cssLength };
|
|
5935
|
+
//# sourceMappingURL=chunk-ETI4LRM7.js.map
|
|
5936
|
+
//# sourceMappingURL=chunk-ETI4LRM7.js.map
|