Reuse Athena router key for OpenClaw dictation

This commit is contained in:
Mikei386
2026-09-16 15:28:10 +02:00
parent ba68d4e8fb
commit 8df3e1ad43
6 changed files with 50 additions and 9 deletions
+4 -2
View File
@@ -67,8 +67,10 @@ the 8 kHz G.711 audio through the Gateway. The plugin converts it to PCM WAV
and calls the same Athena `/audio/transcriptions` endpoint used by Talk. The
transcribed text is returned to the composer; this path does not invoke the
agent or TTS. The transcription provider reuses `talk.realtime.providers.athena-talk`
and the configured model provider for its URL/key, so no second credential is
needed. In `talk.catalog`, it appears under `transcription.providers`. OpenClaw
and the configured model provider for its URL/key. If that model provider has
no key, it reuses `tts.providers.openai.apiKey` only when the TTS and STT URLs
have the same origin. No second credential is needed. In `talk.catalog`, it
appears under `transcription.providers`. OpenClaw
currently gives a transcription provider five seconds to return its final text
after recording stops; the plugin caps its Whisper request at 4.5 seconds.
+11 -2
View File
@@ -95,10 +95,19 @@ function resolveModelProvider(cfg, requested) {
function resolveConfig(req) {
const raw = record(req.providerConfig);
const modelProvider = resolveModelProvider(req.cfg, raw.modelProvider);
const baseUrl = String(raw.baseUrl || modelProvider.baseUrl || "http://192.168.1.212:8081/v1").replace(/\/$/, "");
const tts = record(record(record(req.cfg).tts).providers).openai;
let sharedTtsKey = "";
try {
if (new URL(String(record(tts).baseUrl)).origin === new URL(baseUrl).origin) {
sharedTtsKey = typeof record(tts).apiKey === "string" ? record(tts).apiKey : "";
}
}
catch { /* The TTS provider may be absent or use another URL. */ }
return {
modelProvider: String(raw.modelProvider || ""),
baseUrl: String(raw.baseUrl || modelProvider.baseUrl || "http://192.168.1.212:8081/v1").replace(/\/$/, ""),
apiKey: String(raw.apiKey || modelProvider.apiKey || ""),
baseUrl,
apiKey: String(raw.apiKey || modelProvider.apiKey || sharedTtsKey || ""),
voice: String(raw.voice || req.voice || "alloy"),
language: String(raw.language || req.language || "de"),
vadThreshold: Number(raw.vadThreshold ?? 0.018),
+10 -2
View File
@@ -114,10 +114,18 @@ function resolveModelProvider(cfg: unknown, requested?: unknown): Record<string,
function resolveConfig(req: any): Required<ProviderConfig> {
const raw = record(req.providerConfig);
const modelProvider = resolveModelProvider(req.cfg, raw.modelProvider);
const baseUrl = String(raw.baseUrl || modelProvider.baseUrl || "http://192.168.1.212:8081/v1").replace(/\/$/, "");
const tts = record(record(record(req.cfg).tts).providers).openai;
let sharedTtsKey = "";
try {
if (new URL(String(record(tts).baseUrl)).origin === new URL(baseUrl).origin) {
sharedTtsKey = typeof record(tts).apiKey === "string" ? record(tts).apiKey : "";
}
} catch { /* The TTS provider may be absent or use another URL. */ }
return {
modelProvider: String(raw.modelProvider || ""),
baseUrl: String(raw.baseUrl || modelProvider.baseUrl || "http://192.168.1.212:8081/v1").replace(/\/$/, ""),
apiKey: String(raw.apiKey || modelProvider.apiKey || ""),
baseUrl,
apiKey: String(raw.apiKey || modelProvider.apiKey || sharedTtsKey || ""),
voice: String(raw.voice || req.voice || "alloy"),
language: String(raw.language || req.language || "de"),
vadThreshold: Number(raw.vadThreshold ?? 0.018),
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@casaderoll/openclaw-athena-talk",
"version": "1.2.0",
"version": "1.2.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@casaderoll/openclaw-athena-talk",
"version": "1.2.0",
"version": "1.2.1",
"devDependencies": {
"@types/node": "^24.0.0",
"openclaw": "2026.9.4",
@@ -1,6 +1,6 @@
{
"name": "@casaderoll/openclaw-athena-talk",
"version": "1.2.0",
"version": "1.2.1",
"private": true,
"description": "Local OpenClaw Talk provider backed by Athena Whisper and Qwen3-TTS",
"type": "module",
@@ -57,3 +57,25 @@ test("dictation registers separately and sends G.711 audio to Athena Whisper", a
await new Promise((resolve) => server.close(resolve));
}
});
test("dictation reuses only a TTS key for the same Athena origin", () => {
let transcription;
plugin.register({
registerRealtimeTranscriptionProvider: (value) => { transcription = value; },
registerRealtimeVoiceProvider: () => {},
registerHttpRoute: () => {},
});
const base = {
talk: { realtime: { providers: { "athena-talk": { modelProvider: "llama-cpp" } } } },
models: { providers: { "llama-cpp": { baseUrl: "http://athena:8081/v1" } } },
};
const withTts = (baseUrl) => ({ ...base, tts: { providers: { openai: {
baseUrl, apiKey: "shared-key",
} } } });
assert.equal(transcription.resolveConfig({
cfg: withTts("http://athena:8081/v1"), rawConfig: {},
}).apiKey, "shared-key");
assert.equal(transcription.resolveConfig({
cfg: withTts("http://other:8081/v1"), rawConfig: {},
}).apiKey, "");
});