@agentprojectcontext/apx 1.50.1 → 1.51.1

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.
@@ -25,6 +25,8 @@ export function VoiceScreen() {
25
25
  mutate: mutateProviders,
26
26
  } = useSWR("/tts/providers", () => Voice.providers());
27
27
 
28
+ // editing holds the engine id being configured. "__new__" opens the modal in
29
+ // "create custom provider" mode.
28
30
  const [editing, setEditing] = useState<string | null>(null);
29
31
  const [busyDefault, setBusyDefault] = useState(false);
30
32
 
@@ -42,16 +44,22 @@ export function VoiceScreen() {
42
44
  const order = providersData?.order || [];
43
45
 
44
46
  const editingConfig = useMemo<Record<string, unknown>>(() => {
45
- if (!editing) return {};
47
+ if (!editing || editing === "__new__") return {};
48
+ if (editing.startsWith("custom:")) {
49
+ return (voiceCfg.custom?.[editing.slice(7)] as unknown as Record<string, unknown>) || {};
50
+ }
46
51
  return (voiceCfg as Record<string, unknown>)[editing] as Record<string, unknown> || {};
47
52
  }, [editing, voiceCfg]);
48
53
 
49
- const setDefault = async (id: string) => {
54
+ const toggleEnabled = async (id: string, enabled: boolean) => {
50
55
  setBusyDefault(true);
51
56
  try {
52
- await patch({ "voice.tts.provider": id, "voice.tts.mode": "single" });
57
+ // custom:<slug> lives under voice.tts.custom.<slug>; built-ins are flat.
58
+ const key = id.startsWith("custom:")
59
+ ? `voice.tts.custom.${id.slice(7)}.enabled`
60
+ : `voice.tts.${id}.enabled`;
61
+ await patch({ [key]: enabled });
53
62
  await mutateProviders();
54
- toast.success(t("voice_ui.toast_default_engine", { id }));
55
63
  } catch (e) {
56
64
  toast.error((e as Error).message);
57
65
  } finally {
@@ -59,19 +67,11 @@ export function VoiceScreen() {
59
67
  }
60
68
  };
61
69
 
62
- const setMode = async (next: TtsMode) => {
70
+ const reorder = async (nextOrder: string[]) => {
63
71
  setBusyDefault(true);
64
72
  try {
65
- const set: Record<string, unknown> = { "voice.tts.mode": next };
66
- // Switching to single needs a concrete default; pick the first available
67
- // (or first listed) engine when none is set yet.
68
- if (next === "single" && (configuredProvider === "auto" || !configuredProvider)) {
69
- const pick = engines.find((e) => e.available)?.id || order[0] || "mock";
70
- set["voice.tts.provider"] = pick;
71
- }
72
- await patch(set);
73
+ await patch({ "voice.tts.order": nextOrder });
73
74
  await mutateProviders();
74
- toast.success(next === "chain" ? t("voice_ui.toast_mode_chain") : t("voice_ui.toast_mode_single"));
75
75
  } catch (e) {
76
76
  toast.error((e as Error).message);
77
77
  } finally {
@@ -79,23 +79,24 @@ export function VoiceScreen() {
79
79
  }
80
80
  };
81
81
 
82
- const toggleEnabled = async (id: string, enabled: boolean) => {
83
- setBusyDefault(true);
84
- try {
85
- await patch({ [`voice.tts.${id}.enabled`]: enabled });
86
- await mutateProviders();
87
- } catch (e) {
88
- toast.error((e as Error).message);
89
- } finally {
90
- setBusyDefault(false);
91
- }
82
+ const saveProvider = async ({ set, unset }: VoiceProviderSave) => {
83
+ await patch(set, unset.length ? unset : undefined);
84
+ await mutateProviders();
85
+ await mutateCfg();
86
+ toast.success(t("voice_ui.toast_config_saved"));
92
87
  };
93
88
 
94
- const reorder = async (nextOrder: string[]) => {
89
+ const removeCustom = async (id: string) => {
90
+ if (!id.startsWith("custom:")) return;
91
+ if (!window.confirm(t("voice_ui.remove_confirm"))) return;
95
92
  setBusyDefault(true);
96
93
  try {
97
- await patch({ "voice.tts.order": nextOrder });
94
+ const slug = id.slice(7);
95
+ // Drop the config block and any reference to it in the chain order.
96
+ await patch({ "voice.tts.order": order.filter((x) => x !== id) }, [`voice.tts.custom.${slug}`]);
98
97
  await mutateProviders();
98
+ await mutateCfg();
99
+ toast.success(t("voice_ui.toast_provider_removed"));
99
100
  } catch (e) {
100
101
  toast.error((e as Error).message);
101
102
  } finally {
@@ -103,13 +104,6 @@ export function VoiceScreen() {
103
104
  }
104
105
  };
105
106
 
106
- const saveProvider = async ({ set, unset }: VoiceProviderSave) => {
107
- await patch(set, unset.length ? unset : undefined);
108
- await mutateProviders();
109
- await mutateCfg();
110
- toast.success(t("voice_ui.toast_config_saved"));
111
- };
112
-
113
107
  const patchStt = async (set: Record<string, unknown>, unset?: string[]) => {
114
108
  try {
115
109
  await patch(set, unset);
@@ -135,13 +129,11 @@ export function VoiceScreen() {
135
129
  <VoiceProviderList
136
130
  engines={engines}
137
131
  order={order}
138
- mode={mode}
139
- configuredProvider={configuredProvider}
140
- onSetMode={setMode}
141
- onSetDefault={setDefault}
142
132
  onToggleEnabled={toggleEnabled}
143
133
  onReorder={reorder}
144
134
  onConfigure={(id) => setEditing(id)}
135
+ onRemove={removeCustom}
136
+ onAddNew={() => setEditing("__new__")}
145
137
  busy={busyDefault}
146
138
  />
147
139
  )}