Skip to content

AdaptiveInterruptionDetector ignores LIVEKIT_INFERENCE_API_KEY when LIVEKIT_API_KEY is set #1353

@ralonsom

Description

@ralonsom

Summary

@livekit/agents exposes LIVEKIT_INFERENCE_API_KEY / LIVEKIT_INFERENCE_API_SECRET so users with a self-hosted SFU and a separate LK Cloud project for inference can authenticate against the inference gateway with different credentials. This works correctly for inference/llm.ts, inference/tts.ts and inference/stt.ts, but is broken in inference/interruption/interruption_detector.ts: when LIVEKIT_API_KEY is set (e.g. SFU creds), LIVEKIT_INFERENCE_API_KEY is silently ignored and the SDK signs the inference JWT with the SFU credentials, causing WebSocket connection rejected with status 401 and a fallback to VAD-based interruption.

Root cause

In agents/src/inference/interruption/defaults.ts the interruptionOptionDefaults object is initialised at module load with:

```ts
apiKey: process.env.LIVEKIT_API_KEY || "",
apiSecret: process.env.LIVEKIT_API_SECRET || "",
```

Then in agents/src/inference/interruption/interruption_detector.ts:

```ts
const { apiKey, apiSecret, ... } = { ...interruptionOptionDefaults, ...options };
// ...
lkApiKey = apiKey ?? process.env.LIVEKIT_INFERENCE_API_KEY ?? process.env.LIVEKIT_API_KEY ?? '';
```

Because apiKey already received process.env.LIVEKIT_API_KEY from the defaults, the ?? chain never falls back to LIVEKIT_INFERENCE_API_KEY.

The other three inference plugins use the correct precedence with ||:

```ts
// llm.ts, tts.ts, stt.ts
const lkApiKey = apiKey || process.env.LIVEKIT_INFERENCE_API_KEY || process.env.LIVEKIT_API_KEY;
```

Reproduction

  1. Self-host the LiveKit SFU (creds A).
  2. Create an LK Cloud project and grab a separate set of creds (creds B).
  3. Set both pairs in the agent environment:
    ```
    LIVEKIT_URL=ws://my-self-hosted:7880
    LIVEKIT_API_KEY=A_key
    LIVEKIT_API_SECRET=A_secret
    LIVEKIT_INFERENCE_API_KEY=B_key
    LIVEKIT_INFERENCE_API_SECRET=B_secret
    ```
  4. Configure `interruption: { mode: 'adaptive' }` and place a call.
  5. Worker registers fine against the SFU, but on the first overlap the adaptive detector fails with `WebSocket connection rejected with status 401` and falls back to VAD.

Suggested fix

Align defaults.ts with the precedence used by the other inference plugins:

```ts
apiKey: process.env.LIVEKIT_INFERENCE_API_KEY || process.env.LIVEKIT_API_KEY || "",
apiSecret: process.env.LIVEKIT_INFERENCE_API_SECRET || process.env.LIVEKIT_API_SECRET || "",
```

Or alternatively keep defaults.ts neutral (empty strings) and let the ?? chain in interruption_detector.ts actually fall through to the env vars.

Environment

  • `@livekit/agents` 1.3.0
  • Node 24
  • LK Cloud project for inference; self-hosted SFU (`livekit/livekit-server:v1.11.0`)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions