Agent Developer Guide¶
This guide walks you through building and deploying an AI agent that connects to Bayer's LiveKit infrastructure using the Bayer LiveKit SDK and the LiveKit Platform Service (LKPS).
Table of Contents¶
- Overview
- Prerequisites
- How Agent Registration Works
- Artifactory Access
- Step 1 — Install the Bayer LiveKit SDK
- Step 2 — Configure Environment Variables
- Step 3 — Build Your Agent
- Step 4 — Run Your Agent
- Step 5 — Verify Agent Registration
- Agent Registration API Reference
- Token Lifecycle
- Security Notes
- Troubleshooting
- Next Steps
Overview¶
As an agent developer, your workflow is:
- Develop your agent using the Bayer LiveKit SDK (Python).
- Authenticate with Microsoft Entra ID using your agent's app registration credentials.
- Register with LKPS — the SDK handles this automatically and receives a scoped, time-limited LiveKit token.
- Connect to the LiveKit server — the SDK connects using the token and waits for session dispatches.
- Serve sessions — when a client starts a session targeting your agent, LiveKit dispatches your agent into the room.
Important
You never handle LiveKit API keys or secrets. The SDK calls /api/agent/register; Ocelot verifies agent identity, LKPS issues the agent token, and the SDK registers the agent.
Tip
For detailed SDK documentation including authentication modes, plugin support, migration guides, and advanced configuration, see the Bayer LiveKit SDK Overview.
Prerequisites¶
Before building your agent, ensure you have completed:
- BEAT registration and Entra ID app registration
- Ocelot access for your agent's client ID
- Client-to-Agent Authorization (if you want to enforce client authorization)
- Python 3.10 or later installed
- Access to Bayer's internal Artifactory for SDK installation
How Agent Registration Works¶
The Bayer LiveKit SDK handles all of this automatically. You only write your agent logic — the SDK manages authentication, registration, and token renewal.
Artifactory Access¶
The Bayer LiveKit SDK is hosted on Bayer's internal JFrog Artifactory. You need read access to the repository, an Identity Token, and properly configured environment variables to install it.
1. Get Read Access to Artifactory¶
The SDK repository (agenticlabs-pypi-prod-bayerlivekitsdk) is a private repository. You need to complete both of the following:
a) Request general Artifactory read access via one of:
b) Request SDK repository access from the Bayer LiveKit Platform team
General Artifactory read access does not cover private repositories. Contact the Bayer LiveKit Platform team ⧉ to get your account added to the agenticlabs-pypi-prod-bayerlivekitsdk permission target.
Tip
If you can log in to Artifactory and generate a token but pip install returns "no matching distribution found", this means you are missing step (b).
2. Log in to Artifactory¶
Navigate to artifactory.bayer.com ⧉ and click SAML SSO to log in with your Bayer identity.
3. Generate an Identity Token¶
- Click your username in the top-right corner and select Edit Profile.
- Click Generate an Identity Token, give it a meaningful name (e.g.,
livekit-sdk), and click Next. - Copy the token immediately — it is displayed only once. Store it in a password manager.
4. Set Environment Variables¶
Export the credentials so the pip install command in the next step can authenticate.
Important
The @ in your email must be URL-encoded as %40 in the username variable, since it is used inside a pip index URL.
export ARTIFACTORY_USER_NAME=jane.doe%40bayer.com # Replace with your email, using %40 instead of @
export ARTIFACTORY_USER_TOKEN=<your-identity-token>
Tip
For CI/CD pipelines, use a Transient User (Bearer Token) instead of a personal token. See the Artifactory token generation guide ⧉ for details.
Info
For the full Artifactory documentation (JFrog CLI setup, .netrc configuration, repository requests, etc.), see Bayer Cloud Docs — Artifactory ⧉.
Step 1 — Install the Bayer LiveKit SDK¶
Install the SDK from Bayer's internal Artifactory. Make sure ARTIFACTORY_USER_NAME and ARTIFACTORY_USER_TOKEN are set (see Artifactory Access above).
Note
You must use --extra-index-url (not --index-url) so that pip can also resolve dependencies from PyPI.
pip install bayer-livekit-sdk \
--extra-index-url "https://${ARTIFACTORY_USER_NAME}:${ARTIFACTORY_USER_TOKEN}@artifactory.bayer.com/artifactory/api/pypi/agenticlabs-pypi-prod-bayerlivekitsdk/simple"
With plugins (e.g., for OpenAI, AWS services):
pip install "bayer-livekit-sdk[openai,aws]" \
--extra-index-url "https://${ARTIFACTORY_USER_NAME}:${ARTIFACTORY_USER_TOKEN}@artifactory.bayer.com/artifactory/api/pypi/agenticlabs-pypi-prod-bayerlivekitsdk/simple"
See the Bayer LiveKit SDK — Plugin Ecosystem for the full list of available plugin extras.
Step 2 — Configure Environment Variables¶
Create a .env file or set these environment variables:
# Entra ID credentials (your agent's app registration)
AZURE_CLIENT_ID=<your-agent-client-id>
AZURE_CLIENT_SECRET=<your-agent-client-secret>
AZURE_TENANT_ID=fcb2b37b-5da0-466b-9b83-0014b67a7c78
# LiveKit Platform Service
LKPS_URL=https://eu-livekit-platform-service-np.int.bayer.com
# API audience (used for token acquisition — must match environment)
AZURE_API_AUDIENCE=api://livekit-platform-service-np.int.bayer.com
| Variable | Required | Description |
|---|---|---|
AZURE_CLIENT_ID |
Yes ¹ | Your agent's Entra app registration Client ID |
AZURE_CLIENT_SECRET |
Yes ¹ | Your agent's Entra app registration Client Secret |
AZURE_TENANT_ID |
No | Bayer Entra tenant ID (defaults to Bayer tenant) |
LKPS_URL |
No | LKPS base URL (defaults to EU production) |
AZURE_API_AUDIENCE |
No | Token audience — use api://livekit-platform-service-np.int.bayer.com for non-prod, api://livekit-platform-service.int.bayer.com for prod |
ENFORCE_CLIENT_AUTHZ |
No | When true (default), LKPS validates client identity before allowing sessions |
Note
¹ Required when authenticating as a service principal (CI/CD, production). Omit when using az login (local dev) or Managed Identity (Azure-hosted workloads) — the SDK falls back to DefaultAzureCredential automatically. See Authentication Modes for details.
Tip
Start with the non-production environment for development and testing. See Environments & URLs for all available endpoints.
Step 3 — Build Your Agent¶
Here is a minimal agent that responds to voice input:
from bayer_livekit_sdk import Worker, CLI
from bayer_livekit_sdk.agents import AgentSession, Agent, function_tool, RunContext
from bayer_livekit_sdk.plugins import openai as openai_plugin
# Define your agent
class MyAgent(Agent):
def __init__(self):
super().__init__(
instructions="You are a helpful assistant for Bayer employees."
)
@function_tool
async def get_greeting(self, context: RunContext) -> str:
"""Return a friendly greeting."""
return "Hello! I'm your LiveKit-powered assistant."
# Entrypoint called for each session
async def entrypoint(ctx):
# Wait for a participant to join
participant = await ctx.wait_for_participant(timeout=20)
# Create and start a session
session = AgentSession(
llm=openai_plugin.LLM(model="gpt-4o"),
)
agent = MyAgent()
await session.start(agent=agent, room=ctx.room)
# Bootstrap
if __name__ == "__main__":
worker = Worker()
worker.rtc_session(entrypoint)
CLI().run_app(worker)
Note
The Worker class handles Entra ID authentication, agent registration, and token renewal internally. You only need to define your agent's behavior.
Tip
For more realistic examples including voice assistants and video agents, see the official LiveKit Python agent examples ⧉.
Step 4 — Run Your Agent¶
Development Mode¶
python agent.py dev
Development mode provides verbose logging, which is helpful for debugging authentication and registration issues.
Production Mode¶
python agent.py start
Console Mode (Local Testing)¶
python agent.py console
Console mode lets you test your agent locally using your microphone and speakers (or text mode) without needing a client application.
Step 5 — Verify Agent Registration¶
Once your agent is running, verify it registered successfully:
-
Check the agent logs for a successful registration message:
INFO Registration successful — livekit_token received, expires_in=3600 -
Test with a session start request against your target LKPS environment:
curl -X POST <lkps-url>/api/session/start \ -H "Authorization: Bearer <your-client-entra-token>" \ -H "Content-Type: application/json" \ -d '{"agent_entra_app_id": "<your-agent-client-id>"}'Note
Replace
<lkps-url>with the appropriate environment URL (see Environments & URLs). If client-side integration is complete, use the<your-client-entra-token>your client application already acquires at runtime. -
A
200 OKresponse withroom_name,livekit_url, andparticipant_tokenconfirms the agent is registered and reachable. -
A
404 Not Foundindicates the agent has not registered or the registration token has expired.
Agent Registration API Reference¶
Note
The Bayer LiveKit SDK calls this endpoint automatically. This reference is provided for understanding and debugging.
POST /api/agent/register
Content-Type: application/json
Authorization: Bearer <entra_jwt>
Request body (optional):
{
"service_config": {
"enforce_client_authz": true
}
}
| Field | Type | Default | Description |
|---|---|---|---|
service_config.enforce_client_authz |
boolean | true |
When true, LKPS validates that client applications are pre-authorized before allowing sessions. |
Response 200 OK:
{
"livekit_token": "eyJhbGciOiJIUzI1NiJ9...",
"livekit_url": "wss://eu.livekit-np.int.bayer.com",
"expires_in": 3600
}
| Field | Description |
|---|---|
livekit_token |
Scoped LiveKit JWT with agent grants (agent, canPublish, canSubscribe, canPublishData) |
livekit_url |
LiveKit server WebSocket URL |
expires_in |
Token TTL in seconds (default: 3600) |
Identity resolution:
The agent's identity is derived from Ocelot-injected headers (not from the request body):
| Header | Used as |
|---|---|
client-id (from Entra appid claim) |
Agent app ID (app_id) |
Token Lifecycle¶
| Phase | What happens |
|---|---|
| Initial registration | SDK authenticates with Entra ID, calls /api/agent/register, receives a LiveKit token valid for 1 hour (default). |
| Active service | Agent is connected to the LiveKit server and serving sessions. |
| Token renewal | SDK automatically re-registers 5 minutes before token expiry. A new token is obtained and applied seamlessly — no downtime. |
| Failure handling | If renewal fails, the SDK retries. If the Entra app is disabled or removed, the agent can no longer register. |
Security Notes¶
- No static LiveKit credentials — your agent never holds
LIVEKIT_API_KEYorLIVEKIT_API_SECRET. ctx.apiis blocked — the SDK'sJobContextintentionally prevents direct LiveKit REST API access to enforce security boundaries.- Scoped tokens — each registration token grants only agent-level permissions (join rooms, publish/subscribe). No room management or admin capabilities.
- Audit trail — every registration is persisted in the LKPS database with your agent's app ID, email, timestamp, and worker identity.
- Instant revocation — disabling your Entra app registration immediately prevents further registrations. No secret rotation required.
Troubleshooting¶
Authentication Errors¶
| Error | Possible Cause | Resolution |
|---|---|---|
AADSTS70011: Invalid scope |
Incorrect API audience | Verify AZURE_API_AUDIENCE matches your environment — api://livekit-platform-service-np.int.bayer.com for non-prod, api://livekit-platform-service.int.bayer.com for prod |
AADSTS700016: Application not found |
Wrong client ID or tenant | Verify AZURE_CLIENT_ID and AZURE_TENANT_ID |
AADSTS7000215: Invalid client secret |
Expired or incorrect secret | Generate a new client secret in the Azure Portal |
Registration Errors¶
| Error | Possible Cause | Resolution |
|---|---|---|
401 Unauthorized |
Entra token not accepted by Ocelot | Verify your client ID is in the LKPS Ocelot route's Client Access List |
403 Forbidden (from Ocelot) |
Client ID not in Ocelot access list | Request access to the LKPS Ocelot route (self-service) |
Connection Errors¶
| Error | Possible Cause | Resolution |
|---|---|---|
| Agent registers but no sessions arrive | Agent name mismatch | Ensure clients use your agent's Entra App ID as agent_entra_app_id |
| Token expired / disconnected | Renewal loop not running | Check logs for renewal errors; verify Entra credentials are still valid |
Tip
For additional troubleshooting scenarios, see the Bayer LiveKit SDK Overview.
Next Steps¶
| Next | Guide |
|---|---|
| Detailed SDK documentation | Bayer LiveKit SDK Overview |
| SDK architecture and flows | Bayer LiveKit SDK — System Architecture |
| Full LKPS API reference | LiveKit Platform Service — API Reference |
| Configure client authorization | Client-to-Agent Authorization |
| View all environment URLs | Environments & URLs |