@agentprojectcontext/apx 1.51.1 → 1.53.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,7 +1,7 @@
1
1
  import { type ReactElement } from "react";
2
2
  import { useLocation, useNavigate } from "react-router-dom";
3
3
  import {
4
- Bot, Cpu, Database, KeyRound, LayoutGrid, MessageCircle, Mic, Monitor, Palette, ScrollText, Send, Smartphone, Sparkles, User,
4
+ Bot, Cpu, Database, Globe, KeyRound, LayoutGrid, MessageCircle, Mic, Monitor, ScrollText, Send, Smartphone, Sparkles, User,
5
5
  } from "lucide-react";
6
6
  import { useNavCollapse, type TabSection } from "../components/common/TabNav";
7
7
  import { TabLayout } from "../components/common/TabLayout";
@@ -13,7 +13,7 @@ import { ModelsTab } from "./base/ModelsTab";
13
13
  import { TelegramSettingsTabs } from "../components/settings/TelegramSettingsTabs";
14
14
  import { DevicesPanel } from "../components/settings/DevicesPanel";
15
15
  import { AdvancedPanel } from "../components/settings/AdvancedPanel";
16
- import { AppearancePanel } from "../components/settings/AppearancePanel";
16
+ import { WebPanel } from "../components/settings/WebPanel";
17
17
  import { DesktopSettingsPanel } from "../components/settings/DesktopSettingsPanel";
18
18
  import { VoiceScreen } from "./modules/VoiceScreen";
19
19
  import { DeckScreen } from "./modules/DeckScreen";
@@ -22,14 +22,13 @@ import { t } from "../i18n";
22
22
 
23
23
  type TabKey =
24
24
  | "identity" | "super_agent" | "engines" | "memory" | "skills" | "telegram" | "devices"
25
- | "voice" | "deck" | "desktop" | "appearance" | "advanced";
25
+ | "voice" | "deck" | "desktop" | "web" | "advanced";
26
26
 
27
27
  const SECTIONS: TabSection[] = [
28
28
  {
29
29
  title: t("settings.account_section"),
30
30
  items: [
31
31
  { key: "identity", label: t("settings.tabs.identity"), icon: User },
32
- { key: "appearance", label: t("settings.appearance"), icon: Palette },
33
32
  ],
34
33
  },
35
34
  {
@@ -54,6 +53,7 @@ const SECTIONS: TabSection[] = [
54
53
  { key: "voice", label: t("nav.modules.voice"), icon: Mic },
55
54
  { key: "desktop", label: t("nav.modules.desktop"), icon: Monitor },
56
55
  { key: "deck", label: t("nav.modules.deck"), icon: LayoutGrid },
56
+ { key: "web", label: t("nav.modules.web"), icon: Globe },
57
57
  ],
58
58
  },
59
59
  {
@@ -68,7 +68,7 @@ const SECTIONS: TabSection[] = [
68
68
  // on xl (and so wants full available width). Single-section panels (identity,
69
69
  // super agent, devices, advanced) keep a cosier reading width so wide displays
70
70
  // don't blow form fields up to absurd widths.
71
- const WIDE_TABS = new Set<TabKey>(["engines", "telegram", "memory", "skills", "appearance", "voice"]);
71
+ const WIDE_TABS = new Set<TabKey>(["engines", "telegram", "memory", "skills", "web", "voice"]);
72
72
 
73
73
  const PANELS: Record<TabKey, () => ReactElement> = {
74
74
  identity: () => <IdentityPanel />,
@@ -81,7 +81,7 @@ const PANELS: Record<TabKey, () => ReactElement> = {
81
81
  voice: () => <VoiceScreen />,
82
82
  deck: () => <DeckScreen />,
83
83
  desktop: () => <DesktopSettingsPanel />,
84
- appearance: () => <AppearancePanel />,
84
+ web: () => <WebPanel />,
85
85
  advanced: () => <AdvancedPanel />,
86
86
  };
87
87
 
@@ -121,7 +121,8 @@ function tabFromPath(pathname: string): TabKey {
121
121
  case "voice": return "voice";
122
122
  case "deck": return "deck";
123
123
  case "desktop": return "desktop";
124
- case "appearance": return "appearance";
124
+ case "web": return "web";
125
+ case "appearance": return "web"; // legacy route → Web module
125
126
  case "config":
126
127
  case "advanced": return "advanced";
127
128
  default: return "identity";
@@ -40,9 +40,20 @@ export function VoiceScreen() {
40
40
  const transcriptionCfg = (cfgView.transcription || {}) as TranscriptionConfig;
41
41
  const configuredProvider = providersData?.configured_provider || voiceCfg.provider || "auto";
42
42
  const mode: TtsMode = providersData?.mode || voiceCfg.mode || "chain";
43
- const engines = providersData?.engines || [];
44
43
  const order = providersData?.order || [];
45
44
 
45
+ // Enrich the daemon's engine list with the emotion-tags state read straight
46
+ // from config (so the in-row toggle is live without a daemon round-trip).
47
+ // Only custom + Gemini parse inline [tags].
48
+ const engines = (providersData?.engines || []).map((e) => {
49
+ const applicable = !!e.custom || e.id === "gemini";
50
+ if (!applicable) return e;
51
+ const block = e.custom
52
+ ? voiceCfg.custom?.[e.id.slice(7)]
53
+ : voiceCfg.gemini;
54
+ return { ...e, emotionsApplicable: true, emotionsOn: !!block?.emotions?.enabled };
55
+ });
56
+
46
57
  const editingConfig = useMemo<Record<string, unknown>>(() => {
47
58
  if (!editing || editing === "__new__") return {};
48
59
  if (editing.startsWith("custom:")) {
@@ -67,6 +78,22 @@ export function VoiceScreen() {
67
78
  }
68
79
  };
69
80
 
81
+ const toggleEmotions = async (id: string, enabled: boolean) => {
82
+ setBusyDefault(true);
83
+ try {
84
+ const key = id.startsWith("custom:")
85
+ ? `voice.tts.custom.${id.slice(7)}.emotions.enabled`
86
+ : `voice.tts.${id}.emotions.enabled`;
87
+ await patch({ [key]: enabled });
88
+ await mutateProviders();
89
+ await mutateCfg();
90
+ } catch (e) {
91
+ toast.error((e as Error).message);
92
+ } finally {
93
+ setBusyDefault(false);
94
+ }
95
+ };
96
+
70
97
  const reorder = async (nextOrder: string[]) => {
71
98
  setBusyDefault(true);
72
99
  try {
@@ -130,6 +157,7 @@ export function VoiceScreen() {
130
157
  engines={engines}
131
158
  order={order}
132
159
  onToggleEnabled={toggleEnabled}
160
+ onToggleEmotions={toggleEmotions}
133
161
  onReorder={reorder}
134
162
  onConfigure={(id) => setEditing(id)}
135
163
  onRemove={removeCustom}