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