fix: route voice wake to main

This commit is contained in:
Peter Steinberger
2025-12-20 15:30:45 +01:00
parent 066a2828c4
commit cf96ad8ef9
4 changed files with 53 additions and 4 deletions

View File

@@ -38,8 +38,7 @@ final class NodeAppModel {
init() {
self.voiceWake.configure { [weak self] cmd in
guard let self else { return }
let nodeId = UserDefaults.standard.string(forKey: "node.instanceId") ?? "ios-node"
let sessionKey = "node-\(nodeId)"
let sessionKey = "main"
do {
try await self.sendVoiceTranscript(text: cmd, sessionKey: sessionKey)
} catch {

View File

@@ -179,7 +179,7 @@ actor BridgeServer {
guard !text.isEmpty else { return }
let sessionKey = payload.sessionKey?.trimmingCharacters(in: .whitespacesAndNewlines).nonEmpty
?? "node-\(nodeId)"
?? "main"
_ = await GatewayConnection.shared.sendAgent(GatewayAgentInvocation(
message: text,

View File

@@ -2793,6 +2793,54 @@ describe("gateway server", () => {
await server.close();
});
test("bridge voice transcript defaults to main session", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-"));
testSessionStorePath = path.join(dir, "sessions.json");
await fs.writeFile(
testSessionStorePath,
JSON.stringify(
{
main: {
sessionId: "sess-main",
updatedAt: Date.now(),
lastChannel: "whatsapp",
lastTo: "+1555",
},
},
null,
2,
),
"utf-8",
);
const port = await getFreePort();
const server = await startGatewayServer(port);
const bridgeCall = bridgeStartCalls.at(-1);
expect(bridgeCall?.onEvent).toBeDefined();
const spy = vi.mocked(agentCommand);
const beforeCalls = spy.mock.calls.length;
await bridgeCall?.onEvent?.("ios-node", {
event: "voice.transcript",
payloadJSON: JSON.stringify({ text: "hello" }),
});
expect(spy.mock.calls.length).toBe(beforeCalls + 1);
const call = spy.mock.calls.at(-1)?.[0] as Record<string, unknown>;
expect(call.sessionId).toBe("sess-main");
expect(call.deliver).toBe(false);
expect(call.surface).toBe("Node");
const stored = JSON.parse(
await fs.readFile(testSessionStorePath, "utf-8"),
) as Record<string, { sessionId?: string } | undefined>;
expect(stored.main?.sessionId).toBe("sess-main");
expect(stored["node-ios-node"]).toBeUndefined();
await server.close();
});
test("bridge chat.abort cancels while saving the session store", async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdis-gw-"));
testSessionStorePath = path.join(dir, "sessions.json");

View File

@@ -1800,8 +1800,10 @@ export async function startGatewayServer(
if (text.length > 20_000) return;
const sessionKeyRaw =
typeof obj.sessionKey === "string" ? obj.sessionKey.trim() : "";
const mainKey =
(loadConfig().inbound?.session?.mainKey ?? "main").trim() || "main";
const sessionKey =
sessionKeyRaw.length > 0 ? sessionKeyRaw : `node-${nodeId}`;
sessionKeyRaw.length > 0 ? sessionKeyRaw : mainKey;
const { storePath, store, entry } = loadSessionEntry(sessionKey);
const now = Date.now();
const sessionId = entry?.sessionId ?? randomUUID();