Skip to content

Commit ae2b452

Browse files
committed
fix(showcase/ms-agent-python): pin transcription baseURL to real OpenAI
The voice route's `GuardedOpenAITranscriptionService` was constructing `new OpenAI({ apiKey })` without a `baseURL` override. The OpenAI client falls back to the `OPENAI_BASE_URL` env var, which production docker/Railway sets to `http://aimock:4010/v1` so LLM completions stay deterministic. aimock's transcription handler then returned a 502 "Invalid file format" (or a canned "What is the weather in Tokyo?" fixture on dev), surfacing as "CopilotChat: Transcription failed" on every mic recording. Mirrored langgraph-python's voice route: read `OPENAI_TRANSCRIPTION_BASE_URL` first, fall back to `https://api.openai.com/v1`. The sample-audio button stays deterministic (synchronous text injection); the mic now exercises real Whisper.
1 parent 6a1fceb commit ae2b452

1 file changed

Lines changed: 25 additions & 1 deletion

File tree

  • showcase/integrations/ms-agent-python/src/app/api/copilotkit-voice/[[...slug]]

showcase/integrations/ms-agent-python/src/app/api/copilotkit-voice/[[...slug]]/route.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,38 @@ const AGENT_URL = process.env.AGENT_URL || "http://localhost:8000";
3131
// response instead of a tool call that the agent can't summarize.
3232
const voiceDemoAgent = new HttpAgent({ url: `${AGENT_URL}/voice/` });
3333

34+
/**
35+
* Transcription service wrapper that reports a clean, typed auth error when
36+
* OPENAI_API_KEY is not configured. When the key is present we delegate to
37+
* the real OpenAI-backed service; any upstream Whisper error keeps its
38+
* natural categorization.
39+
*
40+
* Note: We pin `baseURL` to real OpenAI (or `OPENAI_TRANSCRIPTION_BASE_URL`
41+
* when explicitly set) instead of falling through to `OPENAI_BASE_URL`. In
42+
* local docker / Railway preview environments `OPENAI_BASE_URL` points at
43+
* aimock so LLM completions stay deterministic, but aimock has a catchall
44+
* `endpoint: "transcription"` fixture that would otherwise intercept every
45+
* real mic recording and return the canned "What is the weather in Tokyo?"
46+
* phrase regardless of what the user actually said — and on production
47+
* aimock's transcription proxy returns a 502 "Invalid file format" before
48+
* any phrase reaches the user. The sample-audio button is the deterministic
49+
* affordance (synchronous text injection); the mic is the only path that
50+
* should exercise real Whisper.
51+
*
52+
* Mirrors langgraph-python's voice route exactly.
53+
*/
3454
class GuardedOpenAITranscriptionService extends TranscriptionService {
3555
private delegate: TranscriptionServiceOpenAI | null;
3656

3757
constructor() {
3858
super();
3959
const apiKey = process.env.OPENAI_API_KEY;
60+
const baseURL =
61+
process.env.OPENAI_TRANSCRIPTION_BASE_URL ?? "https://api.openai.com/v1";
4062
this.delegate = apiKey
41-
? new TranscriptionServiceOpenAI({ openai: new OpenAI({ apiKey }) })
63+
? new TranscriptionServiceOpenAI({
64+
openai: new OpenAI({ apiKey, baseURL }),
65+
})
4266
: null;
4367
}
4468

0 commit comments

Comments
 (0)