agent-relay-server 0.14.0 → 0.15.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.
- package/package.json +1 -1
- package/public/index.html +50 -2
- package/src/db.ts +5 -0
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -11963,6 +11963,7 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
11963
11963
|
voiceTtsLang: "en-US",
|
|
11964
11964
|
voiceTtsMode: "kokoro",
|
|
11965
11965
|
voiceTtsKokoroVoice: "am_michael",
|
|
11966
|
+
voiceInputMode: "compose",
|
|
11966
11967
|
agentSort: "status",
|
|
11967
11968
|
agentSortDir: "asc",
|
|
11968
11969
|
agentPresetFilter: "",
|
|
@@ -12166,6 +12167,9 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
12166
12167
|
voiceTts.setKokoroVoice(voice);
|
|
12167
12168
|
set({ voiceTtsKokoroVoice: voice });
|
|
12168
12169
|
},
|
|
12170
|
+
setVoiceInputMode(mode) {
|
|
12171
|
+
set({ voiceInputMode: mode });
|
|
12172
|
+
},
|
|
12169
12173
|
async init() {
|
|
12170
12174
|
if (!useRelayStore.persist.hasHydrated()) await new Promise((resolve) => {
|
|
12171
12175
|
const unsub = useRelayStore.persist.onFinishHydration(() => {
|
|
@@ -14270,6 +14274,7 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
14270
14274
|
voiceTtsLang: state.voiceTtsLang,
|
|
14271
14275
|
voiceTtsMode: state.voiceTtsMode,
|
|
14272
14276
|
voiceTtsKokoroVoice: state.voiceTtsKokoroVoice,
|
|
14277
|
+
voiceInputMode: state.voiceInputMode,
|
|
14273
14278
|
agentSort: state.agentSort,
|
|
14274
14279
|
agentSortDir: state.agentSortDir,
|
|
14275
14280
|
agentPresetFilter: state.agentPresetFilter,
|
|
@@ -126759,6 +126764,7 @@ function ChatPanel({ threads, onBack, showBackButton }) {
|
|
|
126759
126764
|
const setVoiceTtsMode = useRelayStore((s) => s.setVoiceTtsMode);
|
|
126760
126765
|
const voiceTtsKokoroVoice = useRelayStore((s) => s.voiceTtsKokoroVoice);
|
|
126761
126766
|
const setVoiceTtsKokoroVoice = useRelayStore((s) => s.setVoiceTtsKokoroVoice);
|
|
126767
|
+
const voiceInputMode = useRelayStore((s) => s.voiceInputMode);
|
|
126762
126768
|
const [speechLangs, setSpeechLangs] = (0, import_react.useState)(() => availableSpeechLangs());
|
|
126763
126769
|
(0, import_react.useEffect)(() => {
|
|
126764
126770
|
if (!voiceTts.available) return;
|
|
@@ -127083,7 +127089,21 @@ function ChatPanel({ threads, onBack, showBackButton }) {
|
|
|
127083
127089
|
const clip = await recorder.stop();
|
|
127084
127090
|
if (!clip) return;
|
|
127085
127091
|
const text = await transcribeClip(clip);
|
|
127086
|
-
if (text)
|
|
127092
|
+
if (!text) return;
|
|
127093
|
+
const combined = draft ? `${draft} ${text}` : text;
|
|
127094
|
+
if (voiceInputMode === "autosend" && !chatSending && !hasPendingUploads) {
|
|
127095
|
+
const attachments = readyAttachments.map((item) => ({
|
|
127096
|
+
artifactId: item.artifact.id,
|
|
127097
|
+
kind: item.artifact.kind,
|
|
127098
|
+
role: "media",
|
|
127099
|
+
title: item.artifact.filename || item.fileName
|
|
127100
|
+
}));
|
|
127101
|
+
sendChatMessage(combined, {
|
|
127102
|
+
peer: selectedInboxThread,
|
|
127103
|
+
lastMessage: thread?.lastMessage || null
|
|
127104
|
+
}, attachments);
|
|
127105
|
+
clearPendingAttachments();
|
|
127106
|
+
} else setReplyDraft(selectedInboxThread, combined);
|
|
127087
127107
|
} catch (e) {
|
|
127088
127108
|
showError("Transcription failed", e?.message || "Could not transcribe audio.");
|
|
127089
127109
|
} finally {
|
|
@@ -153662,10 +153682,38 @@ function SettingsView() {
|
|
|
153662
153682
|
]
|
|
153663
153683
|
})]
|
|
153664
153684
|
}),
|
|
153665
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StewardSettings, {})
|
|
153685
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StewardSettings, {}),
|
|
153686
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(VoiceSettings, {})
|
|
153666
153687
|
]
|
|
153667
153688
|
});
|
|
153668
153689
|
}
|
|
153690
|
+
function VoiceSettings() {
|
|
153691
|
+
const voiceInputMode = useRelayStore((s) => s.voiceInputMode);
|
|
153692
|
+
const setVoiceInputMode = useRelayStore((s) => s.setVoiceInputMode);
|
|
153693
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
153694
|
+
className: "space-y-3 rounded-lg border p-4",
|
|
153695
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
|
|
153696
|
+
className: "text-sm font-semibold",
|
|
153697
|
+
children: "Voice"
|
|
153698
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
153699
|
+
className: "text-xs text-muted-foreground",
|
|
153700
|
+
children: "How push-to-talk behaves in chat."
|
|
153701
|
+
})] }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, {
|
|
153702
|
+
label: "Push-to-talk input",
|
|
153703
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
|
|
153704
|
+
value: voiceInputMode,
|
|
153705
|
+
onValueChange: (v) => setVoiceInputMode(v),
|
|
153706
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, {}) }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectContent, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
153707
|
+
value: "compose",
|
|
153708
|
+
children: "Fill the message box (review, then Enter)"
|
|
153709
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
153710
|
+
value: "autosend",
|
|
153711
|
+
children: "Send immediately (speak-and-send)"
|
|
153712
|
+
})] })]
|
|
153713
|
+
})
|
|
153714
|
+
})]
|
|
153715
|
+
});
|
|
153716
|
+
}
|
|
153669
153717
|
var EFFORTS = [
|
|
153670
153718
|
"low",
|
|
153671
153719
|
"medium",
|
package/src/db.ts
CHANGED
|
@@ -193,6 +193,11 @@ export function initDb(path: string = "agent-relay.db"): Database {
|
|
|
193
193
|
CREATE INDEX IF NOT EXISTS idx_msg_to ON messages(to_target);
|
|
194
194
|
CREATE INDEX IF NOT EXISTS idx_msg_created ON messages(created_at);
|
|
195
195
|
CREATE INDEX IF NOT EXISTS idx_msg_channel ON messages(channel);
|
|
196
|
+
-- (reply_to, from_agent) powers the reply-obligation NOT EXISTS subquery in
|
|
197
|
+
-- listPendingReplyObligations. Without it that subquery full-scans messages
|
|
198
|
+
-- per candidate row (O(n^2)): ~8.6s at 4k rows, which blew the 5s Stop-hook
|
|
199
|
+
-- timeout and wedged turns in "busy" (#199).
|
|
200
|
+
CREATE INDEX IF NOT EXISTS idx_msg_reply_to ON messages(reply_to, from_agent);
|
|
196
201
|
|
|
197
202
|
CREATE TABLE IF NOT EXISTS message_reactions (
|
|
198
203
|
message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
|