@unctad-ai/voice-agent-ui 5.4.7 → 5.5.0

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.
@@ -1,5 +1,5 @@
1
1
  // src/components/VoiceSettingsView.tsx
2
- import { useState as useState3, useEffect as useEffect2, useCallback as useCallback3 } from "react";
2
+ import { useState as useState4, useEffect as useEffect3, useCallback as useCallback4 } from "react";
3
3
  import { motion, AnimatePresence } from "motion/react";
4
4
  import {
5
5
  ArrowLeft,
@@ -7,7 +7,7 @@ import {
7
7
  Volume2,
8
8
  Gauge,
9
9
  AudioLines,
10
- Sparkles,
10
+ Sparkles as Sparkles2,
11
11
  Mic,
12
12
  Timer,
13
13
  MessageSquare,
@@ -27,7 +27,7 @@ import {
27
27
  Headphones,
28
28
  SlidersHorizontal,
29
29
  Wrench,
30
- Globe,
30
+ Globe as Globe2,
31
31
  Type,
32
32
  TextCursorInput,
33
33
  Sparkle
@@ -156,7 +156,7 @@ function useVoiceSettings() {
156
156
  }
157
157
 
158
158
  // src/components/VoiceSettingsView.tsx
159
- import { VAD, useSiteConfig as useSiteConfig2, usePersonaContext as usePersonaContext2 } from "@unctad-ai/voice-agent-core";
159
+ import { VAD, useSiteConfig as useSiteConfig3, usePersonaContext as usePersonaContext2 } from "@unctad-ai/voice-agent-core";
160
160
 
161
161
  // src/components/PersonaSettings.tsx
162
162
  import { useState as useState2, useRef as useRef2, useEffect, useCallback as useCallback2 } from "react";
@@ -1079,9 +1079,109 @@ function QualityBadge({ warning }) {
1079
1079
  ] });
1080
1080
  }
1081
1081
 
1082
+ // src/components/LlmSettings.tsx
1083
+ import { useState as useState3, useEffect as useEffect2, useCallback as useCallback3 } from "react";
1084
+ import { Globe, Sparkles } from "lucide-react";
1085
+ import { useSiteConfig as useSiteConfig2 } from "@unctad-ai/voice-agent-core";
1086
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1087
+ var BACKEND_URL = import.meta.env?.VITE_BACKEND_URL || "";
1088
+ var API_KEY = import.meta.env?.VITE_API_KEY || "";
1089
+ var iconStyle = { width: 18, height: 18, color: "var(--copilot-color, #DB2129)" };
1090
+ function LlmSettings({ adminPassword }) {
1091
+ const config = useSiteConfig2();
1092
+ const endpoint = config.personaEndpoint;
1093
+ if (!endpoint) return null;
1094
+ if (!adminPassword) return null;
1095
+ return /* @__PURE__ */ jsx3(LlmSettingsInner, { endpoint, adminPassword });
1096
+ }
1097
+ function LlmSettingsInner({
1098
+ endpoint,
1099
+ adminPassword
1100
+ }) {
1101
+ const [state, setState] = useState3(null);
1102
+ const [error, setError] = useState3(null);
1103
+ const url = `${BACKEND_URL}${endpoint}/llm`;
1104
+ useEffect2(() => {
1105
+ let cancelled = false;
1106
+ fetch(url, { headers: API_KEY ? { "X-API-Key": API_KEY } : {} }).then((r) => r.json()).then((data) => {
1107
+ if (!cancelled) setState(data);
1108
+ }).catch((err) => !cancelled && setError(err.message));
1109
+ return () => {
1110
+ cancelled = true;
1111
+ };
1112
+ }, [url]);
1113
+ const apply = useCallback3(async (next) => {
1114
+ setError(null);
1115
+ setState((prev) => prev ? { ...prev, current: next } : prev);
1116
+ try {
1117
+ const res = await fetch(url, {
1118
+ method: "PATCH",
1119
+ headers: {
1120
+ "Content-Type": "application/json",
1121
+ "X-Admin-Password": adminPassword,
1122
+ ...API_KEY ? { "X-API-Key": API_KEY } : {}
1123
+ },
1124
+ body: JSON.stringify(next)
1125
+ });
1126
+ const data = await res.json();
1127
+ if (!res.ok) throw new Error(data.error || `Save failed: ${res.status}`);
1128
+ setState(data);
1129
+ } catch (err) {
1130
+ setError(err instanceof Error ? err.message : String(err));
1131
+ fetch(url, { headers: API_KEY ? { "X-API-Key": API_KEY } : {} }).then((r) => r.json()).then((data) => setState(data)).catch(() => {
1132
+ });
1133
+ }
1134
+ }, [url, adminPassword]);
1135
+ if (!state) return null;
1136
+ const onProviderChange = (provider) => {
1137
+ const preset = state.providers.find((p) => p.id === provider);
1138
+ if (!preset || !preset.configured) return;
1139
+ apply({ provider, model: preset.models[0].id });
1140
+ };
1141
+ const onModelChange = (model) => {
1142
+ apply({ provider: state.current.provider, model });
1143
+ };
1144
+ const providerOptions = state.providers.map((p) => ({
1145
+ value: p.id,
1146
+ label: p.configured ? p.label : `${p.label} (no API key)`,
1147
+ disabled: !p.configured
1148
+ }));
1149
+ const currentProvider = state.providers.find((p) => p.id === state.current.provider);
1150
+ const modelOptions = (currentProvider?.models ?? []).map((m) => ({
1151
+ value: m.id,
1152
+ label: m.qualifier ? `${m.id} \u2014 ${m.qualifier}` : m.id
1153
+ }));
1154
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
1155
+ /* @__PURE__ */ jsx3(
1156
+ SelectSetting,
1157
+ {
1158
+ icon: /* @__PURE__ */ jsx3(Globe, { style: iconStyle }),
1159
+ label: "Provider",
1160
+ value: state.current.provider,
1161
+ onChange: onProviderChange,
1162
+ options: providerOptions,
1163
+ width: 180
1164
+ }
1165
+ ),
1166
+ /* @__PURE__ */ jsx3(Divider, {}),
1167
+ /* @__PURE__ */ jsx3(
1168
+ SelectSetting,
1169
+ {
1170
+ icon: /* @__PURE__ */ jsx3(Sparkles, { style: iconStyle }),
1171
+ label: "Model",
1172
+ value: state.current.model,
1173
+ onChange: onModelChange,
1174
+ options: modelOptions,
1175
+ width: 260
1176
+ }
1177
+ ),
1178
+ error && /* @__PURE__ */ jsx3("div", { style: { fontSize: 11, color: "#dc2626", padding: "4px 0" }, children: error })
1179
+ ] });
1180
+ }
1181
+
1082
1182
  // src/components/VoiceSettingsView.tsx
1083
1183
  import { Lock, Unlock } from "lucide-react";
1084
- import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1184
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1085
1185
  function expressivenessLabel(v) {
1086
1186
  if (v <= 0.15) return "Low";
1087
1187
  if (v <= 0.4) return "Medium";
@@ -1176,13 +1276,13 @@ function SliderSetting({
1176
1276
  }) {
1177
1277
  ensureSliderStyles();
1178
1278
  const pct = (value - min) / (max - min) * 100;
1179
- return /* @__PURE__ */ jsxs2("div", { style: { paddingTop: 12, paddingBottom: 12, display: "flex", flexDirection: "column", gap: 10 }, children: [
1180
- /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
1279
+ return /* @__PURE__ */ jsxs3("div", { style: { paddingTop: 12, paddingBottom: 12, display: "flex", flexDirection: "column", gap: 10 }, children: [
1280
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
1181
1281
  icon,
1182
- /* @__PURE__ */ jsx3("span", { style: { flex: 1, fontSize: 13, fontWeight: 500, color: "#111827" }, children: label }),
1183
- /* @__PURE__ */ jsx3("span", { style: { fontSize: 11, fontWeight: 500, fontVariantNumeric: "tabular-nums", color: "var(--voice-settings-accent, #DB2129)" }, children: displayValue })
1282
+ /* @__PURE__ */ jsx4("span", { style: { flex: 1, fontSize: 13, fontWeight: 500, color: "#111827" }, children: label }),
1283
+ /* @__PURE__ */ jsx4("span", { style: { fontSize: 11, fontWeight: 500, fontVariantNumeric: "tabular-nums", color: "var(--voice-settings-accent, #DB2129)" }, children: displayValue })
1184
1284
  ] }),
1185
- /* @__PURE__ */ jsx3(
1285
+ /* @__PURE__ */ jsx4(
1186
1286
  "input",
1187
1287
  {
1188
1288
  type: "range",
@@ -1206,13 +1306,13 @@ function ToggleSetting({
1206
1306
  checked,
1207
1307
  onChange
1208
1308
  }) {
1209
- return /* @__PURE__ */ jsxs2("label", { style: { paddingTop: 12, paddingBottom: 12, display: "flex", alignItems: "center", gap: 12, cursor: "pointer" }, children: [
1309
+ return /* @__PURE__ */ jsxs3("label", { style: { paddingTop: 12, paddingBottom: 12, display: "flex", alignItems: "center", gap: 12, cursor: "pointer" }, children: [
1210
1310
  icon,
1211
- /* @__PURE__ */ jsxs2("div", { style: { flex: 1, minWidth: 0 }, children: [
1212
- /* @__PURE__ */ jsx3("div", { style: { fontSize: 13, fontWeight: 500, color: "#111827" }, children: label }),
1213
- /* @__PURE__ */ jsx3("div", { style: { fontSize: 11, color: "#6b7280" }, children: description })
1311
+ /* @__PURE__ */ jsxs3("div", { style: { flex: 1, minWidth: 0 }, children: [
1312
+ /* @__PURE__ */ jsx4("div", { style: { fontSize: 13, fontWeight: 500, color: "#111827" }, children: label }),
1313
+ /* @__PURE__ */ jsx4("div", { style: { fontSize: 11, color: "#6b7280" }, children: description })
1214
1314
  ] }),
1215
- /* @__PURE__ */ jsx3(
1315
+ /* @__PURE__ */ jsx4(
1216
1316
  "button",
1217
1317
  {
1218
1318
  role: "switch",
@@ -1232,7 +1332,7 @@ function ToggleSetting({
1232
1332
  transition: "background-color 0.2s",
1233
1333
  flexShrink: 0
1234
1334
  },
1235
- children: /* @__PURE__ */ jsx3(
1335
+ children: /* @__PURE__ */ jsx4(
1236
1336
  "span",
1237
1337
  {
1238
1338
  style: {
@@ -1256,26 +1356,31 @@ function SelectSetting({
1256
1356
  label,
1257
1357
  value,
1258
1358
  onChange,
1259
- options
1359
+ options,
1360
+ width = 110,
1361
+ disabled = false
1260
1362
  }) {
1261
- return /* @__PURE__ */ jsxs2("div", { style: { paddingTop: 12, paddingBottom: 12, display: "flex", alignItems: "center", gap: 12 }, children: [
1363
+ return /* @__PURE__ */ jsxs3("div", { style: { paddingTop: 12, paddingBottom: 12, display: "flex", alignItems: "center", gap: 12 }, children: [
1262
1364
  icon,
1263
- /* @__PURE__ */ jsx3("span", { style: { flex: 1, fontSize: 13, fontWeight: 500, color: "#111827", minWidth: 0 }, children: label }),
1264
- /* @__PURE__ */ jsx3(
1365
+ /* @__PURE__ */ jsx4("span", { style: { flex: 1, fontSize: 13, fontWeight: 500, color: "#111827", minWidth: 0 }, children: label }),
1366
+ /* @__PURE__ */ jsx4(
1265
1367
  "select",
1266
1368
  {
1267
1369
  value,
1370
+ disabled,
1268
1371
  onChange: (e) => onChange(e.target.value),
1269
1372
  onMouseEnter: (e) => {
1373
+ if (disabled) return;
1270
1374
  e.currentTarget.style.borderColor = "#d1d5db";
1271
1375
  e.currentTarget.style.backgroundColor = "#f3f4f6";
1272
1376
  },
1273
1377
  onMouseLeave: (e) => {
1378
+ if (disabled) return;
1274
1379
  e.currentTarget.style.borderColor = "#e5e7eb";
1275
1380
  e.currentTarget.style.backgroundColor = "#f9fafb";
1276
1381
  },
1277
1382
  onFocus: (e) => {
1278
- e.currentTarget.style.borderColor = "#9ca3af";
1383
+ if (!disabled) e.currentTarget.style.borderColor = "#9ca3af";
1279
1384
  },
1280
1385
  onBlur: (e) => {
1281
1386
  e.currentTarget.style.borderColor = "#e5e7eb";
@@ -1285,7 +1390,7 @@ function SelectSetting({
1285
1390
  lineHeight: "34px",
1286
1391
  fontSize: 12,
1287
1392
  fontWeight: 500,
1288
- color: "#374151",
1393
+ color: disabled ? "#9ca3af" : "#374151",
1289
1394
  borderRadius: 9999,
1290
1395
  border: "1px solid #e5e7eb",
1291
1396
  backgroundColor: "#f9fafb",
@@ -1296,15 +1401,15 @@ function SelectSetting({
1296
1401
  outline: "none",
1297
1402
  WebkitAppearance: "none",
1298
1403
  appearance: "none",
1299
- cursor: "pointer",
1404
+ cursor: disabled ? "not-allowed" : "pointer",
1300
1405
  flexShrink: 0,
1301
- width: 110,
1406
+ width,
1302
1407
  transition: "border-color 0.15s, background-color 0.15s",
1303
1408
  backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")`,
1304
1409
  backgroundRepeat: "no-repeat",
1305
1410
  backgroundPosition: "right 8px center"
1306
1411
  },
1307
- children: options.map((opt) => /* @__PURE__ */ jsx3("option", { value: opt.value, children: opt.label }, opt.value))
1412
+ children: options.map((opt) => /* @__PURE__ */ jsx4("option", { value: opt.value, disabled: opt.disabled, children: opt.label }, opt.value))
1308
1413
  }
1309
1414
  )
1310
1415
  ] });
@@ -1318,13 +1423,13 @@ function TextInputSetting({
1318
1423
  multiline,
1319
1424
  rows = 2
1320
1425
  }) {
1321
- const [local, setLocal] = useState3(value);
1322
- const [focused, setFocused] = useState3(false);
1323
- const [saveStatus, setSaveStatus] = useState3("idle");
1324
- useEffect2(() => {
1426
+ const [local, setLocal] = useState4(value);
1427
+ const [focused, setFocused] = useState4(false);
1428
+ const [saveStatus, setSaveStatus] = useState4("idle");
1429
+ useEffect3(() => {
1325
1430
  setLocal(value);
1326
1431
  }, [value]);
1327
- useEffect2(() => {
1432
+ useEffect3(() => {
1328
1433
  if (saveStatus === "saved") {
1329
1434
  const t = setTimeout(() => setSaveStatus("idle"), 1500);
1330
1435
  return () => clearTimeout(t);
@@ -1352,21 +1457,21 @@ function TextInputSetting({
1352
1457
  resize: multiline ? "vertical" : "none",
1353
1458
  transition: "border-color 0.15s"
1354
1459
  };
1355
- return /* @__PURE__ */ jsxs2("div", { style: { paddingTop: 10, paddingBottom: 10, display: "flex", flexDirection: "column", gap: 8 }, children: [
1356
- /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "flex-start", gap: 12 }, children: [
1357
- /* @__PURE__ */ jsx3("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: 16, height: 20, flexShrink: 0 }, children: icon }),
1358
- /* @__PURE__ */ jsxs2("div", { style: { flex: 1 }, children: [
1359
- /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "baseline", gap: 6, minHeight: 20 }, children: [
1360
- /* @__PURE__ */ jsx3("span", { style: { fontSize: 13, fontWeight: 500, color: "#111827" }, children: label }),
1361
- /* @__PURE__ */ jsxs2(AnimatePresence, { children: [
1362
- saveStatus === "saved" && /* @__PURE__ */ jsx3(motion.span, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.2 }, style: { fontSize: 11, color: "#22c55e", fontWeight: 400 }, children: "Saved" }, "saved"),
1363
- saveStatus === "error" && /* @__PURE__ */ jsx3(motion.span, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.2 }, style: { fontSize: 11, color: "#ef4444", fontWeight: 400 }, children: "Save failed" }, "error")
1460
+ return /* @__PURE__ */ jsxs3("div", { style: { paddingTop: 10, paddingBottom: 10, display: "flex", flexDirection: "column", gap: 8 }, children: [
1461
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "flex-start", gap: 12 }, children: [
1462
+ /* @__PURE__ */ jsx4("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", width: 16, height: 20, flexShrink: 0 }, children: icon }),
1463
+ /* @__PURE__ */ jsxs3("div", { style: { flex: 1 }, children: [
1464
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "baseline", gap: 6, minHeight: 20 }, children: [
1465
+ /* @__PURE__ */ jsx4("span", { style: { fontSize: 13, fontWeight: 500, color: "#111827" }, children: label }),
1466
+ /* @__PURE__ */ jsxs3(AnimatePresence, { children: [
1467
+ saveStatus === "saved" && /* @__PURE__ */ jsx4(motion.span, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.2 }, style: { fontSize: 11, color: "#22c55e", fontWeight: 400 }, children: "Saved" }, "saved"),
1468
+ saveStatus === "error" && /* @__PURE__ */ jsx4(motion.span, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.2 }, style: { fontSize: 11, color: "#ef4444", fontWeight: 400 }, children: "Save failed" }, "error")
1364
1469
  ] })
1365
1470
  ] }),
1366
- description && /* @__PURE__ */ jsx3("p", { style: { fontSize: 11, color: "#9ca3af", margin: "2px 0 0", lineHeight: 1.4 }, children: description })
1471
+ description && /* @__PURE__ */ jsx4("p", { style: { fontSize: 11, color: "#9ca3af", margin: "2px 0 0", lineHeight: 1.4 }, children: description })
1367
1472
  ] })
1368
1473
  ] }),
1369
- multiline ? /* @__PURE__ */ jsx3(
1474
+ multiline ? /* @__PURE__ */ jsx4(
1370
1475
  "textarea",
1371
1476
  {
1372
1477
  value: local,
@@ -1379,7 +1484,7 @@ function TextInputSetting({
1379
1484
  rows,
1380
1485
  style: inputStyle
1381
1486
  }
1382
- ) : /* @__PURE__ */ jsx3(
1487
+ ) : /* @__PURE__ */ jsx4(
1383
1488
  "input",
1384
1489
  {
1385
1490
  type: "text",
@@ -1397,25 +1502,25 @@ function TextInputSetting({
1397
1502
  }
1398
1503
  function VoiceSettingsView({ onBack, onVolumeChange }) {
1399
1504
  const { settings, updateSetting, resetSettings } = useVoiceSettings();
1400
- const config = useSiteConfig2();
1505
+ const config = useSiteConfig3();
1401
1506
  const persona = usePersonaContext2();
1402
1507
  const { colors } = config;
1403
- const [openSection, setOpenSection] = useState3(null);
1404
- const iconStyle = { width: 16, height: 16, flexShrink: 0, color: colors.primary };
1508
+ const [openSection, setOpenSection] = useState4(null);
1509
+ const iconStyle2 = { width: 16, height: 16, flexShrink: 0, color: colors.primary };
1405
1510
  const sectionIconStyle = { width: 16, height: 16, flexShrink: 0, color: colors.primary };
1406
1511
  const sectionProps = (id) => ({
1407
1512
  open: openSection === id,
1408
1513
  onToggle: () => setOpenSection(openSection === id ? null : id)
1409
1514
  });
1410
- const [adminPassword, setAdminPassword] = useState3(
1515
+ const [adminPassword, setAdminPassword] = useState4(
1411
1516
  () => sessionStorage.getItem("voice-admin-pw")
1412
1517
  );
1413
- const [showPasswordInput, setShowPasswordInput] = useState3(false);
1414
- const [passwordInput, setPasswordInput] = useState3("");
1415
- const [authError, setAuthError] = useState3("");
1518
+ const [showPasswordInput, setShowPasswordInput] = useState4(false);
1519
+ const [passwordInput, setPasswordInput] = useState4("");
1520
+ const [authError, setAuthError] = useState4("");
1416
1521
  const isAdmin = adminPassword !== null;
1417
1522
  const updateConfigFn = persona?.updateConfig;
1418
- const handleSharedSave = useCallback3(async (fields) => {
1523
+ const handleSharedSave = useCallback4(async (fields) => {
1419
1524
  if (!adminPassword || !updateConfigFn) return false;
1420
1525
  try {
1421
1526
  await updateConfigFn(fields, adminPassword);
@@ -1425,7 +1530,7 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1425
1530
  return false;
1426
1531
  }
1427
1532
  }, [adminPassword, updateConfigFn]);
1428
- const handleAdminLogin = useCallback3(async (pw) => {
1533
+ const handleAdminLogin = useCallback4(async (pw) => {
1429
1534
  if (!persona) return;
1430
1535
  try {
1431
1536
  await persona.updateConfig({}, pw);
@@ -1438,7 +1543,7 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1438
1543
  setAuthError("Invalid password");
1439
1544
  }
1440
1545
  }, [persona]);
1441
- const handleAdminToggle = useCallback3(() => {
1546
+ const handleAdminToggle = useCallback4(() => {
1442
1547
  if (isAdmin) {
1443
1548
  sessionStorage.removeItem("voice-admin-pw");
1444
1549
  setAdminPassword(null);
@@ -1448,7 +1553,7 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1448
1553
  setShowPasswordInput(true);
1449
1554
  }
1450
1555
  }, [isAdmin]);
1451
- return /* @__PURE__ */ jsxs2(
1556
+ return /* @__PURE__ */ jsxs3(
1452
1557
  motion.div,
1453
1558
  {
1454
1559
  initial: { opacity: 0, x: 20 },
@@ -1467,12 +1572,12 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1467
1572
  "--voice-settings-accent": colors.primary
1468
1573
  },
1469
1574
  children: [
1470
- /* @__PURE__ */ jsxs2(
1575
+ /* @__PURE__ */ jsxs3(
1471
1576
  "div",
1472
1577
  {
1473
1578
  style: { display: "flex", alignItems: "center", gap: 10, flexShrink: 0, paddingLeft: 16, paddingRight: 16, height: 56, borderBottom: "1px solid #e5e7eb" },
1474
1579
  children: [
1475
- /* @__PURE__ */ jsx3(
1580
+ /* @__PURE__ */ jsx4(
1476
1581
  "button",
1477
1582
  {
1478
1583
  onClick: onBack,
@@ -1484,11 +1589,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1484
1589
  e.currentTarget.style.color = "#6b7280";
1485
1590
  },
1486
1591
  "aria-label": "Back to conversation",
1487
- children: /* @__PURE__ */ jsx3(ArrowLeft, { style: { width: 16, height: 16 } })
1592
+ children: /* @__PURE__ */ jsx4(ArrowLeft, { style: { width: 16, height: 16 } })
1488
1593
  }
1489
1594
  ),
1490
- /* @__PURE__ */ jsx3("span", { style: { flex: 1, fontSize: 13, fontWeight: 600, color: "#111827" }, children: "Settings" }),
1491
- /* @__PURE__ */ jsx3(
1595
+ /* @__PURE__ */ jsx4("span", { style: { flex: 1, fontSize: 13, fontWeight: 600, color: "#111827" }, children: "Settings" }),
1596
+ /* @__PURE__ */ jsx4(
1492
1597
  "button",
1493
1598
  {
1494
1599
  onClick: resetSettings,
@@ -1501,41 +1606,41 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1501
1606
  },
1502
1607
  "aria-label": "Reset all settings",
1503
1608
  title: "Reset to defaults",
1504
- children: /* @__PURE__ */ jsx3(RotateCcw, { style: { width: 14, height: 14 } })
1609
+ children: /* @__PURE__ */ jsx4(RotateCcw, { style: { width: 14, height: 14 } })
1505
1610
  }
1506
1611
  )
1507
1612
  ]
1508
1613
  }
1509
1614
  ),
1510
- /* @__PURE__ */ jsxs2("div", { style: { flex: 1, minHeight: 0, overflowY: "auto" }, children: [
1511
- config.personaEndpoint && /* @__PURE__ */ jsx3(SettingsSection, { title: "Persona", icon: /* @__PURE__ */ jsx3(User, { style: sectionIconStyle }), ...sectionProps("persona"), children: /* @__PURE__ */ jsx3(PersonaSettings, { adminPassword }) }),
1512
- config.personaEndpoint && isAdmin && persona?.persona && /* @__PURE__ */ jsxs2(SettingsSection, { title: "Agent", icon: /* @__PURE__ */ jsx3(Sparkle, { style: sectionIconStyle }), ...sectionProps("agent"), children: [
1513
- /* @__PURE__ */ jsx3(
1615
+ /* @__PURE__ */ jsxs3("div", { style: { flex: 1, minHeight: 0, overflowY: "auto" }, children: [
1616
+ config.personaEndpoint && /* @__PURE__ */ jsx4(SettingsSection, { title: "Persona", icon: /* @__PURE__ */ jsx4(User, { style: sectionIconStyle }), ...sectionProps("persona"), children: /* @__PURE__ */ jsx4(PersonaSettings, { adminPassword }) }),
1617
+ config.personaEndpoint && isAdmin && persona?.persona && /* @__PURE__ */ jsxs3(SettingsSection, { title: "Agent", icon: /* @__PURE__ */ jsx4(Sparkle, { style: sectionIconStyle }), ...sectionProps("agent"), children: [
1618
+ /* @__PURE__ */ jsx4(
1514
1619
  TextInputSetting,
1515
1620
  {
1516
- icon: /* @__PURE__ */ jsx3(Type, { style: iconStyle }),
1621
+ icon: /* @__PURE__ */ jsx4(Type, { style: iconStyle2 }),
1517
1622
  label: "Portal context",
1518
1623
  description: "What this portal offers \u2014 helps the AI understand the domain",
1519
1624
  value: persona.persona.siteTitle || config.siteTitle || "",
1520
1625
  onSave: (v) => handleSharedSave({ siteTitle: v })
1521
1626
  }
1522
1627
  ),
1523
- /* @__PURE__ */ jsx3(Divider, {}),
1524
- /* @__PURE__ */ jsx3(
1628
+ /* @__PURE__ */ jsx4(Divider, {}),
1629
+ /* @__PURE__ */ jsx4(
1525
1630
  TextInputSetting,
1526
1631
  {
1527
- icon: /* @__PURE__ */ jsx3(MessageSquare, { style: iconStyle }),
1632
+ icon: /* @__PURE__ */ jsx4(MessageSquare, { style: iconStyle2 }),
1528
1633
  label: "Greeting",
1529
1634
  description: "Shown when the panel opens with no conversation",
1530
1635
  value: persona.persona.greetingMessage || config.greetingMessage || "",
1531
1636
  onSave: (v) => handleSharedSave({ greetingMessage: v })
1532
1637
  }
1533
1638
  ),
1534
- /* @__PURE__ */ jsx3(Divider, {}),
1535
- /* @__PURE__ */ jsx3(
1639
+ /* @__PURE__ */ jsx4(Divider, {}),
1640
+ /* @__PURE__ */ jsx4(
1536
1641
  TextInputSetting,
1537
1642
  {
1538
- icon: /* @__PURE__ */ jsx3(TextCursorInput, { style: iconStyle }),
1643
+ icon: /* @__PURE__ */ jsx4(TextCursorInput, { style: iconStyle2 }),
1539
1644
  label: "Suggested prompts",
1540
1645
  description: "Tappable chips in the empty state (one per line)",
1541
1646
  value: persona.persona.suggestedPrompts || config.suggestedPrompts?.join("\n") || "",
@@ -1544,11 +1649,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1544
1649
  rows: 3
1545
1650
  }
1546
1651
  ),
1547
- /* @__PURE__ */ jsx3(Divider, {}),
1548
- /* @__PURE__ */ jsx3(
1652
+ /* @__PURE__ */ jsx4(Divider, {}),
1653
+ /* @__PURE__ */ jsx4(
1549
1654
  TextInputSetting,
1550
1655
  {
1551
- icon: /* @__PURE__ */ jsx3(Info, { style: iconStyle }),
1656
+ icon: /* @__PURE__ */ jsx4(Info, { style: iconStyle2 }),
1552
1657
  label: "System prompt intro",
1553
1658
  description: "Prefixed to every LLM conversation. Use {name} for the agent's name.",
1554
1659
  value: persona.persona.systemPromptIntro || config.systemPromptIntro || "",
@@ -1557,11 +1662,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1557
1662
  rows: 4
1558
1663
  }
1559
1664
  ),
1560
- /* @__PURE__ */ jsx3(Divider, {}),
1561
- /* @__PURE__ */ jsx3(
1665
+ /* @__PURE__ */ jsx4(Divider, {}),
1666
+ /* @__PURE__ */ jsx4(
1562
1667
  SelectSetting,
1563
1668
  {
1564
- icon: /* @__PURE__ */ jsx3(Globe, { style: iconStyle }),
1669
+ icon: /* @__PURE__ */ jsx4(Globe2, { style: iconStyle2 }),
1565
1670
  label: "Default language",
1566
1671
  value: persona.persona.language || config.language || "en",
1567
1672
  onChange: (v) => handleSharedSave({ language: v }),
@@ -1569,11 +1674,12 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1569
1674
  }
1570
1675
  )
1571
1676
  ] }),
1572
- /* @__PURE__ */ jsxs2(SettingsSection, { title: "Conversation", icon: /* @__PURE__ */ jsx3(MessageCircle, { style: sectionIconStyle }), ...sectionProps("conversation"), children: [
1573
- /* @__PURE__ */ jsx3(
1677
+ config.personaEndpoint && isAdmin && /* @__PURE__ */ jsx4(SettingsSection, { title: "Language model", icon: /* @__PURE__ */ jsx4(Cpu, { style: sectionIconStyle }), ...sectionProps("llm"), children: /* @__PURE__ */ jsx4(LlmSettings, { adminPassword }) }),
1678
+ /* @__PURE__ */ jsxs3(SettingsSection, { title: "Conversation", icon: /* @__PURE__ */ jsx4(MessageCircle, { style: sectionIconStyle }), ...sectionProps("conversation"), children: [
1679
+ /* @__PURE__ */ jsx4(
1574
1680
  SelectSetting,
1575
1681
  {
1576
- icon: /* @__PURE__ */ jsx3(MessageSquare, { style: iconStyle }),
1682
+ icon: /* @__PURE__ */ jsx4(MessageSquare, { style: iconStyle2 }),
1577
1683
  label: "Response length",
1578
1684
  value: String(settings.responseLength),
1579
1685
  onChange: (v) => updateSetting("responseLength", Number(v)),
@@ -1584,11 +1690,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1584
1690
  ]
1585
1691
  }
1586
1692
  ),
1587
- /* @__PURE__ */ jsx3(Divider, {}),
1588
- /* @__PURE__ */ jsx3(
1693
+ /* @__PURE__ */ jsx4(Divider, {}),
1694
+ /* @__PURE__ */ jsx4(
1589
1695
  SelectSetting,
1590
1696
  {
1591
- icon: /* @__PURE__ */ jsx3(History, { style: iconStyle }),
1697
+ icon: /* @__PURE__ */ jsx4(History, { style: iconStyle2 }),
1592
1698
  label: "Chat memory",
1593
1699
  value: String(settings.maxHistoryMessages),
1594
1700
  onChange: (v) => updateSetting("maxHistoryMessages", Number(v)),
@@ -1601,33 +1707,33 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1601
1707
  }
1602
1708
  )
1603
1709
  ] }),
1604
- /* @__PURE__ */ jsxs2(SettingsSection, { title: "Listening", icon: /* @__PURE__ */ jsx3(Headphones, { style: sectionIconStyle }), ...sectionProps("listening"), children: [
1605
- /* @__PURE__ */ jsx3(
1710
+ /* @__PURE__ */ jsxs3(SettingsSection, { title: "Listening", icon: /* @__PURE__ */ jsx4(Headphones, { style: sectionIconStyle }), ...sectionProps("listening"), children: [
1711
+ /* @__PURE__ */ jsx4(
1606
1712
  SelectSetting,
1607
1713
  {
1608
- icon: /* @__PURE__ */ jsx3(Globe, { style: iconStyle }),
1714
+ icon: /* @__PURE__ */ jsx4(Globe2, { style: iconStyle2 }),
1609
1715
  label: "Language",
1610
1716
  value: settings.language,
1611
1717
  onChange: (v) => updateSetting("language", v),
1612
1718
  options: LANGUAGE_OPTIONS
1613
1719
  }
1614
1720
  ),
1615
- /* @__PURE__ */ jsx3(Divider, {}),
1616
- /* @__PURE__ */ jsx3(
1721
+ /* @__PURE__ */ jsx4(Divider, {}),
1722
+ /* @__PURE__ */ jsx4(
1617
1723
  ToggleSetting,
1618
1724
  {
1619
- icon: /* @__PURE__ */ jsx3(Mic, { style: iconStyle }),
1725
+ icon: /* @__PURE__ */ jsx4(Mic, { style: iconStyle2 }),
1620
1726
  label: "Auto-listen",
1621
1727
  description: "Start mic when panel opens",
1622
1728
  checked: settings.autoListen,
1623
1729
  onChange: (v) => updateSetting("autoListen", v)
1624
1730
  }
1625
1731
  ),
1626
- /* @__PURE__ */ jsx3(Divider, {}),
1627
- /* @__PURE__ */ jsx3(
1732
+ /* @__PURE__ */ jsx4(Divider, {}),
1733
+ /* @__PURE__ */ jsx4(
1628
1734
  SliderSetting,
1629
1735
  {
1630
- icon: /* @__PURE__ */ jsx3(Ear, { style: iconStyle }),
1736
+ icon: /* @__PURE__ */ jsx4(Ear, { style: iconStyle2 }),
1631
1737
  label: "Speech threshold",
1632
1738
  value: settings.speechThreshold * 100,
1633
1739
  displayValue: speechThresholdLabel(settings.speechThreshold),
@@ -1637,11 +1743,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1637
1743
  onChange: (v) => updateSetting("speechThreshold", v / 100)
1638
1744
  }
1639
1745
  ),
1640
- /* @__PURE__ */ jsx3(Divider, {}),
1641
- /* @__PURE__ */ jsx3(
1746
+ /* @__PURE__ */ jsx4(Divider, {}),
1747
+ /* @__PURE__ */ jsx4(
1642
1748
  SelectSetting,
1643
1749
  {
1644
- icon: /* @__PURE__ */ jsx3(Clock, { style: iconStyle }),
1750
+ icon: /* @__PURE__ */ jsx4(Clock, { style: iconStyle2 }),
1645
1751
  label: "Pause tolerance",
1646
1752
  value: String(settings.pauseToleranceMs),
1647
1753
  onChange: (v) => updateSetting("pauseToleranceMs", Number(v)),
@@ -1653,11 +1759,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1653
1759
  ]
1654
1760
  }
1655
1761
  ),
1656
- /* @__PURE__ */ jsx3(Divider, {}),
1657
- /* @__PURE__ */ jsx3(
1762
+ /* @__PURE__ */ jsx4(Divider, {}),
1763
+ /* @__PURE__ */ jsx4(
1658
1764
  SliderSetting,
1659
1765
  {
1660
- icon: /* @__PURE__ */ jsx3(Zap, { style: iconStyle }),
1766
+ icon: /* @__PURE__ */ jsx4(Zap, { style: iconStyle2 }),
1661
1767
  label: "Barge-in threshold",
1662
1768
  value: settings.bargeInThreshold * 100,
1663
1769
  displayValue: bargeInLabel(settings.bargeInThreshold),
@@ -1668,22 +1774,22 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1668
1774
  }
1669
1775
  )
1670
1776
  ] }),
1671
- /* @__PURE__ */ jsxs2(SettingsSection, { title: "Speaking", icon: /* @__PURE__ */ jsx3(Volume2, { style: sectionIconStyle }), ...sectionProps("speaking"), children: [
1672
- /* @__PURE__ */ jsx3(
1777
+ /* @__PURE__ */ jsxs3(SettingsSection, { title: "Speaking", icon: /* @__PURE__ */ jsx4(Volume2, { style: sectionIconStyle }), ...sectionProps("speaking"), children: [
1778
+ /* @__PURE__ */ jsx4(
1673
1779
  ToggleSetting,
1674
1780
  {
1675
- icon: /* @__PURE__ */ jsx3(AudioLines, { style: iconStyle }),
1781
+ icon: /* @__PURE__ */ jsx4(AudioLines, { style: iconStyle2 }),
1676
1782
  label: "Text-to-speech",
1677
1783
  description: "Speak responses aloud",
1678
1784
  checked: settings.ttsEnabled,
1679
1785
  onChange: (v) => updateSetting("ttsEnabled", v)
1680
1786
  }
1681
1787
  ),
1682
- /* @__PURE__ */ jsx3(Divider, {}),
1683
- /* @__PURE__ */ jsx3(
1788
+ /* @__PURE__ */ jsx4(Divider, {}),
1789
+ /* @__PURE__ */ jsx4(
1684
1790
  SliderSetting,
1685
1791
  {
1686
- icon: /* @__PURE__ */ jsx3(Volume2, { style: iconStyle }),
1792
+ icon: /* @__PURE__ */ jsx4(Volume2, { style: iconStyle2 }),
1687
1793
  label: "Volume",
1688
1794
  value: settings.volume * 100,
1689
1795
  displayValue: `${Math.round(settings.volume * 100)}%`,
@@ -1696,11 +1802,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1696
1802
  }
1697
1803
  }
1698
1804
  ),
1699
- /* @__PURE__ */ jsx3(Divider, {}),
1700
- /* @__PURE__ */ jsx3(
1805
+ /* @__PURE__ */ jsx4(Divider, {}),
1806
+ /* @__PURE__ */ jsx4(
1701
1807
  SliderSetting,
1702
1808
  {
1703
- icon: /* @__PURE__ */ jsx3(Gauge, { style: iconStyle }),
1809
+ icon: /* @__PURE__ */ jsx4(Gauge, { style: iconStyle2 }),
1704
1810
  label: "Speed",
1705
1811
  value: settings.playbackSpeed * 100,
1706
1812
  displayValue: `${settings.playbackSpeed.toFixed(2)}x`,
@@ -1710,11 +1816,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1710
1816
  onChange: (v) => updateSetting("playbackSpeed", v / 100)
1711
1817
  }
1712
1818
  ),
1713
- /* @__PURE__ */ jsx3(Divider, {}),
1714
- /* @__PURE__ */ jsx3(
1819
+ /* @__PURE__ */ jsx4(Divider, {}),
1820
+ /* @__PURE__ */ jsx4(
1715
1821
  SliderSetting,
1716
1822
  {
1717
- icon: /* @__PURE__ */ jsx3(Sparkles, { style: iconStyle }),
1823
+ icon: /* @__PURE__ */ jsx4(Sparkles2, { style: iconStyle2 }),
1718
1824
  label: "Expressiveness",
1719
1825
  value: settings.expressiveness * 100,
1720
1826
  displayValue: expressivenessLabel(settings.expressiveness),
@@ -1725,11 +1831,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1725
1831
  }
1726
1832
  )
1727
1833
  ] }),
1728
- /* @__PURE__ */ jsxs2(SettingsSection, { title: "Behavior", icon: /* @__PURE__ */ jsx3(SlidersHorizontal, { style: sectionIconStyle }), ...sectionProps("behavior"), children: [
1729
- /* @__PURE__ */ jsx3(
1834
+ /* @__PURE__ */ jsxs3(SettingsSection, { title: "Behavior", icon: /* @__PURE__ */ jsx4(SlidersHorizontal, { style: sectionIconStyle }), ...sectionProps("behavior"), children: [
1835
+ /* @__PURE__ */ jsx4(
1730
1836
  SelectSetting,
1731
1837
  {
1732
- icon: /* @__PURE__ */ jsx3(Timer, { style: iconStyle }),
1838
+ icon: /* @__PURE__ */ jsx4(Timer, { style: iconStyle2 }),
1733
1839
  label: "Idle timeout",
1734
1840
  value: String(settings.idleTimeoutMs),
1735
1841
  onChange: (v) => updateSetting("idleTimeoutMs", Number(v)),
@@ -1741,11 +1847,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1741
1847
  ]
1742
1848
  }
1743
1849
  ),
1744
- /* @__PURE__ */ jsx3(Divider, {}),
1745
- /* @__PURE__ */ jsx3(
1850
+ /* @__PURE__ */ jsx4(Divider, {}),
1851
+ /* @__PURE__ */ jsx4(
1746
1852
  SelectSetting,
1747
1853
  {
1748
- icon: /* @__PURE__ */ jsx3(Minimize2, { style: iconStyle }),
1854
+ icon: /* @__PURE__ */ jsx4(Minimize2, { style: iconStyle2 }),
1749
1855
  label: "Auto-collapse",
1750
1856
  value: String(settings.panelCollapseTimeoutMs),
1751
1857
  onChange: (v) => updateSetting("panelCollapseTimeoutMs", Number(v)),
@@ -1758,22 +1864,22 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1758
1864
  }
1759
1865
  )
1760
1866
  ] }),
1761
- /* @__PURE__ */ jsxs2(SettingsSection, { title: "Developer", icon: /* @__PURE__ */ jsx3(Wrench, { style: sectionIconStyle }), ...sectionProps("developer"), last: true, children: [
1762
- /* @__PURE__ */ jsx3(
1867
+ /* @__PURE__ */ jsxs3(SettingsSection, { title: "Developer", icon: /* @__PURE__ */ jsx4(Wrench, { style: sectionIconStyle }), ...sectionProps("developer"), last: true, children: [
1868
+ /* @__PURE__ */ jsx4(
1763
1869
  ToggleSetting,
1764
1870
  {
1765
- icon: /* @__PURE__ */ jsx3(Activity, { style: iconStyle }),
1871
+ icon: /* @__PURE__ */ jsx4(Activity, { style: iconStyle2 }),
1766
1872
  label: "Pipeline metrics",
1767
1873
  description: "Show STT / LLM / TTS timings",
1768
1874
  checked: settings.showPipelineMetrics,
1769
1875
  onChange: (v) => updateSetting("showPipelineMetrics", v)
1770
1876
  }
1771
1877
  ),
1772
- /* @__PURE__ */ jsx3(Divider, {}),
1773
- /* @__PURE__ */ jsx3(
1878
+ /* @__PURE__ */ jsx4(Divider, {}),
1879
+ /* @__PURE__ */ jsx4(
1774
1880
  SelectSetting,
1775
1881
  {
1776
- icon: /* @__PURE__ */ jsx3(EyeOff, { style: iconStyle }),
1882
+ icon: /* @__PURE__ */ jsx4(EyeOff, { style: iconStyle2 }),
1777
1883
  label: "Auto-hide metrics",
1778
1884
  value: String(settings.pipelineMetricsAutoHideMs),
1779
1885
  onChange: (v) => updateSetting("pipelineMetricsAutoHideMs", Number(v)),
@@ -1785,11 +1891,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1785
1891
  ]
1786
1892
  }
1787
1893
  ),
1788
- /* @__PURE__ */ jsx3(Divider, {}),
1789
- /* @__PURE__ */ jsx3(
1894
+ /* @__PURE__ */ jsx4(Divider, {}),
1895
+ /* @__PURE__ */ jsx4(
1790
1896
  SelectSetting,
1791
1897
  {
1792
- icon: /* @__PURE__ */ jsx3(Mic, { style: iconStyle }),
1898
+ icon: /* @__PURE__ */ jsx4(Mic, { style: iconStyle2 }),
1793
1899
  label: "STT timeout",
1794
1900
  value: String(settings.sttTimeoutMs),
1795
1901
  onChange: (v) => updateSetting("sttTimeoutMs", Number(v)),
@@ -1800,11 +1906,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1800
1906
  ]
1801
1907
  }
1802
1908
  ),
1803
- /* @__PURE__ */ jsx3(Divider, {}),
1804
- /* @__PURE__ */ jsx3(
1909
+ /* @__PURE__ */ jsx4(Divider, {}),
1910
+ /* @__PURE__ */ jsx4(
1805
1911
  SelectSetting,
1806
1912
  {
1807
- icon: /* @__PURE__ */ jsx3(AudioLines, { style: iconStyle }),
1913
+ icon: /* @__PURE__ */ jsx4(AudioLines, { style: iconStyle2 }),
1808
1914
  label: "TTS timeout",
1809
1915
  value: String(settings.ttsTimeoutMs),
1810
1916
  onChange: (v) => updateSetting("ttsTimeoutMs", Number(v)),
@@ -1815,11 +1921,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1815
1921
  ]
1816
1922
  }
1817
1923
  ),
1818
- /* @__PURE__ */ jsx3(Divider, {}),
1819
- /* @__PURE__ */ jsx3(
1924
+ /* @__PURE__ */ jsx4(Divider, {}),
1925
+ /* @__PURE__ */ jsx4(
1820
1926
  SelectSetting,
1821
1927
  {
1822
- icon: /* @__PURE__ */ jsx3(Cpu, { style: iconStyle }),
1928
+ icon: /* @__PURE__ */ jsx4(Cpu, { style: iconStyle2 }),
1823
1929
  label: "LLM timeout",
1824
1930
  value: String(settings.llmTimeoutMs),
1825
1931
  onChange: (v) => updateSetting("llmTimeoutMs", Number(v)),
@@ -1831,11 +1937,11 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1831
1937
  ]
1832
1938
  }
1833
1939
  ),
1834
- /* @__PURE__ */ jsx3(Divider, {}),
1835
- /* @__PURE__ */ jsx3(
1940
+ /* @__PURE__ */ jsx4(Divider, {}),
1941
+ /* @__PURE__ */ jsx4(
1836
1942
  SelectSetting,
1837
1943
  {
1838
- icon: /* @__PURE__ */ jsx3(Signal, { style: iconStyle }),
1944
+ icon: /* @__PURE__ */ jsx4(Signal, { style: iconStyle2 }),
1839
1945
  label: "Min audio level",
1840
1946
  value: String(settings.minAudioRms),
1841
1947
  onChange: (v) => updateSetting("minAudioRms", Number(v)),
@@ -1847,15 +1953,15 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1847
1953
  ]
1848
1954
  }
1849
1955
  ),
1850
- /* @__PURE__ */ jsx3(Divider, {}),
1851
- /* @__PURE__ */ jsxs2("div", { style: { paddingTop: 8, paddingBottom: 4, fontSize: 11, color: "#9ca3af" }, children: [
1956
+ /* @__PURE__ */ jsx4(Divider, {}),
1957
+ /* @__PURE__ */ jsxs3("div", { style: { paddingTop: 8, paddingBottom: 4, fontSize: 11, color: "#9ca3af" }, children: [
1852
1958
  "VAD Threshold: ",
1853
- /* @__PURE__ */ jsx3("span", { style: { fontWeight: 500, color: "#6b7280" }, children: VAD.positiveSpeechThreshold })
1959
+ /* @__PURE__ */ jsx4("span", { style: { fontWeight: 500, color: "#6b7280" }, children: VAD.positiveSpeechThreshold })
1854
1960
  ] })
1855
1961
  ] })
1856
1962
  ] }),
1857
- /* @__PURE__ */ jsx3("div", { style: { flexShrink: 0, padding: "8px 16px", fontSize: 11, color: "#9ca3af", borderTop: "1px solid #f3f4f6" }, children: showPasswordInput ? /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 6, alignItems: "center", justifyContent: "center", padding: "4px 0" }, children: [
1858
- /* @__PURE__ */ jsx3(
1963
+ /* @__PURE__ */ jsx4("div", { style: { flexShrink: 0, padding: "8px 16px", fontSize: 11, color: "#9ca3af", borderTop: "1px solid #f3f4f6" }, children: showPasswordInput ? /* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: 6, alignItems: "center", justifyContent: "center", padding: "4px 0" }, children: [
1964
+ /* @__PURE__ */ jsx4(
1859
1965
  "input",
1860
1966
  {
1861
1967
  type: "text",
@@ -1889,7 +1995,7 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1889
1995
  }
1890
1996
  }
1891
1997
  ),
1892
- /* @__PURE__ */ jsx3(
1998
+ /* @__PURE__ */ jsx4(
1893
1999
  "button",
1894
2000
  {
1895
2001
  onClick: () => handleAdminLogin(passwordInput),
@@ -1907,7 +2013,7 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1907
2013
  children: "OK"
1908
2014
  }
1909
2015
  ),
1910
- /* @__PURE__ */ jsx3(
2016
+ /* @__PURE__ */ jsx4(
1911
2017
  "button",
1912
2018
  {
1913
2019
  onClick: () => {
@@ -1919,9 +2025,9 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1919
2025
  children: "Cancel"
1920
2026
  }
1921
2027
  ),
1922
- authError && /* @__PURE__ */ jsx3("span", { style: { fontSize: 10, color: "#ef4444" }, children: authError })
1923
- ] }) : /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1924
- config.personaEndpoint ? /* @__PURE__ */ jsx3(
2028
+ authError && /* @__PURE__ */ jsx4("span", { style: { fontSize: 10, color: "#ef4444" }, children: authError })
2029
+ ] }) : /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
2030
+ config.personaEndpoint ? /* @__PURE__ */ jsx4(
1925
2031
  "button",
1926
2032
  {
1927
2033
  onClick: handleAdminToggle,
@@ -1938,18 +2044,18 @@ function VoiceSettingsView({ onBack, onVolumeChange }) {
1938
2044
  padding: 0,
1939
2045
  transition: "color 0.15s"
1940
2046
  },
1941
- children: isAdmin ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1942
- /* @__PURE__ */ jsx3(Unlock, { style: { width: 12, height: 12 } }),
2047
+ children: isAdmin ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
2048
+ /* @__PURE__ */ jsx4(Unlock, { style: { width: 12, height: 12 } }),
1943
2049
  " Admin mode"
1944
- ] }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
1945
- /* @__PURE__ */ jsx3(Lock, { style: { width: 12, height: 12 } }),
2050
+ ] }) : /* @__PURE__ */ jsxs3(Fragment3, { children: [
2051
+ /* @__PURE__ */ jsx4(Lock, { style: { width: 12, height: 12 } }),
1946
2052
  " Admin mode"
1947
2053
  ] })
1948
2054
  }
1949
- ) : /* @__PURE__ */ jsx3("span", {}),
1950
- /* @__PURE__ */ jsxs2("span", { children: [
2055
+ ) : /* @__PURE__ */ jsx4("span", {}),
2056
+ /* @__PURE__ */ jsxs3("span", { children: [
1951
2057
  "Kit v",
1952
- /* @__PURE__ */ jsx3("span", { style: { fontWeight: 500, color: "#6b7280" }, children: "5.4.7" })
2058
+ /* @__PURE__ */ jsx4("span", { style: { fontWeight: 500, color: "#6b7280" }, children: "5.5.0" })
1953
2059
  ] })
1954
2060
  ] }) })
1955
2061
  ]
@@ -1964,9 +2070,9 @@ function SettingsSection({
1964
2070
  open = false,
1965
2071
  onToggle
1966
2072
  }) {
1967
- const [hovered, setHovered] = useState3(false);
1968
- return /* @__PURE__ */ jsxs2("div", { style: { borderBottom: last ? "none" : "1px solid #e5e7eb" }, children: [
1969
- /* @__PURE__ */ jsxs2(
2073
+ const [hovered, setHovered] = useState4(false);
2074
+ return /* @__PURE__ */ jsxs3("div", { style: { borderBottom: last ? "none" : "1px solid #e5e7eb" }, children: [
2075
+ /* @__PURE__ */ jsxs3(
1970
2076
  "button",
1971
2077
  {
1972
2078
  onClick: onToggle,
@@ -1989,14 +2095,14 @@ function SettingsSection({
1989
2095
  },
1990
2096
  children: [
1991
2097
  icon,
1992
- /* @__PURE__ */ jsx3("span", { style: {
2098
+ /* @__PURE__ */ jsx4("span", { style: {
1993
2099
  flex: 1,
1994
2100
  textAlign: "left",
1995
2101
  fontSize: 13,
1996
2102
  fontWeight: 600,
1997
2103
  color: "#374151"
1998
2104
  }, children: title }),
1999
- /* @__PURE__ */ jsx3(ChevronDown, { style: {
2105
+ /* @__PURE__ */ jsx4(ChevronDown, { style: {
2000
2106
  width: 14,
2001
2107
  height: 14,
2002
2108
  color: "#9ca3af",
@@ -2006,7 +2112,7 @@ function SettingsSection({
2006
2112
  ]
2007
2113
  }
2008
2114
  ),
2009
- /* @__PURE__ */ jsx3(AnimatePresence, { initial: false, children: open && /* @__PURE__ */ jsx3(
2115
+ /* @__PURE__ */ jsx4(AnimatePresence, { initial: false, children: open && /* @__PURE__ */ jsx4(
2010
2116
  motion.div,
2011
2117
  {
2012
2118
  initial: { height: 0, opacity: 0 },
@@ -2014,7 +2120,7 @@ function SettingsSection({
2014
2120
  exit: { height: 0, opacity: 0 },
2015
2121
  transition: { duration: 0.2, ease: [0.22, 1, 0.36, 1] },
2016
2122
  style: { overflow: "hidden" },
2017
- children: /* @__PURE__ */ jsx3("div", { style: {
2123
+ children: /* @__PURE__ */ jsx4("div", { style: {
2018
2124
  paddingLeft: 16,
2019
2125
  paddingRight: 16,
2020
2126
  paddingTop: 4,
@@ -2027,13 +2133,14 @@ function SettingsSection({
2027
2133
  ] });
2028
2134
  }
2029
2135
  function Divider() {
2030
- return /* @__PURE__ */ jsx3("div", { style: { height: 1, backgroundColor: "#f3f4f6" } });
2136
+ return /* @__PURE__ */ jsx4("div", { style: { height: 1, backgroundColor: "#f3f4f6" } });
2031
2137
  }
2032
2138
 
2033
2139
  export {
2034
2140
  VoiceSettingsProvider,
2035
2141
  useVoiceSettings,
2036
2142
  PersonaSettings,
2143
+ LlmSettings,
2037
2144
  SliderSetting,
2038
2145
  ToggleSetting,
2039
2146
  SelectSetting,
@@ -2041,4 +2148,4 @@ export {
2041
2148
  SettingsSection,
2042
2149
  Divider
2043
2150
  };
2044
- //# sourceMappingURL=chunk-YWDI7ZAG.js.map
2151
+ //# sourceMappingURL=chunk-FDCCCMUD.js.map