Skip to content

Conversation

@jp-lemon
Copy link

@jp-lemon jp-lemon commented Jan 16, 2026

LemonSlice Integration Docs
LemonSlice API Docs

Summary by CodeRabbit

Release Notes

  • New Features

    • Added LemonSlice virtual avatar support for LiveKit Agents with cloud-based provisioning
    • Support for custom avatar IDs and image upload configurations
  • Documentation

    • Added README documentation for LemonSlice avatar plugin integration
    • Added example agent worker implementation with configuration guides

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 16, 2026

📝 Walkthrough

Walkthrough

A new LemonSlice avatar plugin for LiveKit Agents is introduced, including comprehensive documentation, an example agent worker, API client implementation with retry logic, avatar session management with JWT credential handling, and workspace integration configuration.

Changes

Cohort / File(s) Summary
Documentation & Examples
examples/avatar_agents/README.md, examples/avatar_agents/lemonslice/README.md
Added LemonSlice provider entries in avatar provider guide; new README documenting environment variables and agent worker execution for LemonSlice avatars.
Plugin Bootstrap & Module Setup
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/__init__.py, livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/log.py, livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/version.py
Plugin initialization with class LemonSlicePlugin, public exports (AvatarSession, LemonSliceException), module-level logger, and version constant ("1.3.11").
API Client Implementation
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py
New LemonSliceAPI class with start_agent_session() method; implements HTTP client with retry logic, error handling (LemonSliceException, APIStatusError), JWT payload construction, and configurable API endpoints.
Avatar Session
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py
New AvatarSession class managing avatar instantiation; generates LiveKit access tokens with JWT, validates credentials from environment or arguments, initializes DataStreamAudioOutput for avatar media streaming to room.
Example Agent Worker
examples/avatar_agents/lemonslice/agent_worker.py
New agent worker demonstrating usage: orchestrates AgentSession (STT/LLM/TTS), AvatarSession, and Agent lifecycle within a single rtc_session() context.
Plugin Package Configuration
livekit-plugins/livekit-plugins-lemonslice/README.md, livekit-plugins/livekit-plugins-lemonslice/pyproject.toml
Plugin README and pyproject.toml defining package metadata, build system (hatchling), dependencies, versioning path, and workspace inclusion.
Workspace Integration
pyproject.toml
Added livekit-plugins-lemonslice to workspace sources.

Sequence Diagram(s)

sequenceDiagram
    participant Worker as Agent Worker
    participant Agent as AgentSession
    participant Avatar as AvatarSession
    participant API as LemonSlice API
    participant Room as LiveKit Room
    participant Output as DataStreamAudioOutput

    Worker->>Agent: Create with STT/LLM/TTS
    Worker->>Avatar: Create with image_url, prompt
    Avatar->>Avatar: Ensure HTTP session
    Avatar->>Avatar: Build JWT AccessToken
    Avatar->>API: start_agent_session(agent_id/image_url, prompt, livekit_url/token)
    API->>API: POST with retry logic
    API-->>Avatar: return session_id
    Avatar->>Output: Configure audio stream (sample_rate, identity)
    Output->>Room: Bind to room, await participant
    Worker->>Agent: Start agent in room
    Worker->>Room: Agent publishes messages
    Room->>Output: Route audio to avatar destination
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 LemonSlice avatars hop into sight,
With APIs and tokens, they dance just right,
From streams to the room where agents convene,
A plugin so clever, a LiveKit dream! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'LemonSlice Plugin' directly corresponds to the main change: introducing a new LemonSlice plugin for LiveKit Agents with supporting avatar session integration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@CLAassistant
Copy link

CLAassistant commented Jan 16, 2026

CLA assistant check
All committers have signed the CLA.

@davidzhao
Copy link
Member

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@examples/avatar_agents/lemonslice/agent_worker.py`:
- Around line 27-31: The environment variable lemonslice_image_url (from
os.getenv("LEMONSLICE_IMAGE_URL")) is used directly as agent_image_url when
constructing lemonslice.AvatarSession which can pass None to the API; add a
validation check after reading lemonslice_image_url to verify it is non-empty
and raise a clear exception (or call sys.exit) if missing, so
AvatarSession(agent_image_url=lemonslice_image_url, ...) is only called with a
valid URL.

In
`@livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/__init__.py`:
- Around line 15-18: The module docstring in __init__.py contains a malformed
documentation URL with a duplicated "https://"
("https://https://docs.livekit.io/..."); update the docstring to remove the
extra scheme so the link reads
"https://docs.livekit.io/agents/models/avatar/plugins/lemonslice/" - edit the
top-level string literal in livekit/plugins/lemonslice/__init__.py accordingly.

In
`@livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py`:
- Around line 96-121: The retry loop currently iterates
range(self._conn_options.max_retry) and always retries; update it to
range(self._conn_options.max_retry + 1) so attempts = max_retry + 1, and when
catching exceptions, if isinstance(e, APIStatusError) and not e.retryable:
re-raise to avoid retrying 4xx non-retryable errors; keep handling
APIConnectionError separately as before. Replace usage of
self._conn_options.retry_interval with self._conn_options._interval_for_retry(i)
for backoff, and change the sleep/continue condition to i <
self._conn_options.max_retry so you only sleep when another attempt remains.
Ensure these changes are applied around the async with self._session.post(...)
block and the except handler where APIStatusError, APIConnectionError, and i are
referenced.
🧹 Nitpick comments (8)
pyproject.toml (1)

28-28: Minor formatting inconsistency.

Missing space before the closing brace. Other entries use { workspace = true } (with space).

🔧 Suggested fix
-livekit-plugins-lemonslice = { workspace = true}
+livekit-plugins-lemonslice = { workspace = true }
livekit-plugins/livekit-plugins-lemonslice/pyproject.toml (2)

13-13: Minor formatting: missing space after comma in keywords.

🔧 Suggested fix
-keywords = ["voice", "ai", "realtime", "audio", "video", "livekit", "webrtc", "avatar", "agent","lemonslice"]
+keywords = ["voice", "ai", "realtime", "audio", "video", "livekit", "webrtc", "avatar", "agent", "lemonslice"]

20-23: Consider adding classifiers for Python 3.11 and 3.12.

Since requires-python = ">=3.9.0", the package supports newer Python versions. Adding classifiers improves discoverability on PyPI.

🔧 Suggested addition
     "Programming Language :: Python :: 3",
     "Programming Language :: Python :: 3.9",
     "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
     "Programming Language :: Python :: 3 :: Only",
examples/avatar_agents/lemonslice/agent_worker.py (1)

18-41: Add a Google-style docstring to entrypoint.
As per coding guidelines, public entrypoints should have Google-style docstrings.

livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py (2)

30-67: Avoid leaking NOT_GIVEN into credentials/payload.
Using or with NOT_GIVEN can keep the sentinel (if it’s truthy), and livekit_url/token are always serialized into JSON even when not provided. Safer to use utils.is_given for defaults and only include provided fields.

🔧 Suggested fix
-        ls_api_key = api_key or os.getenv("LEMONSLICE_API_KEY")
+        ls_api_key = api_key if utils.is_given(api_key) else os.getenv("LEMONSLICE_API_KEY")
         if ls_api_key is None:
             raise LemonSliceException("LEMONSLICE_API_KEY must be set")
         self._api_key = ls_api_key

-        self._api_url = api_url or DEFAULT_API_URL
+        self._api_url = api_url if utils.is_given(api_url) else DEFAULT_API_URL
-        payload: dict[str, Any] = {
-            "transport_type": "livekit",
-            "properties": {
-                "livekit_url": livekit_url,
-                "livekit_token": livekit_token,
-            },
-        }
+        payload: dict[str, Any] = {"transport_type": "livekit", "properties": {}}
+        if utils.is_given(livekit_url):
+            payload["properties"]["livekit_url"] = livekit_url
+        if utils.is_given(livekit_token):
+            payload["properties"]["livekit_token"] = livekit_token
+        if not payload["properties"]:
+            payload.pop("properties")

34-44: Manage aiohttp.ClientSession lifecycle.
Creating a session internally without a close path can leak sockets. Consider adding close() / async context manager support when session isn’t provided.

livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py (2)

56-77: Prefer utils.is_given for NOT_GIVEN defaults.
Using or with NOT_GIVEN can keep the sentinel (if it’s truthy), which may bypass required config checks and leak into identity fields. Safer to use utils.is_given consistently.

🔧 Suggested fix
-        self._avatar_participant_identity = avatar_participant_identity or _AVATAR_AGENT_IDENTITY
-        self._avatar_participant_name = avatar_participant_name or _AVATAR_AGENT_NAME
+        self._avatar_participant_identity = (
+            avatar_participant_identity
+            if utils.is_given(avatar_participant_identity)
+            else _AVATAR_AGENT_IDENTITY
+        )
+        self._avatar_participant_name = (
+            avatar_participant_name if utils.is_given(avatar_participant_name) else _AVATAR_AGENT_NAME
+        )
-        livekit_url = livekit_url or (os.getenv("LIVEKIT_URL") or NOT_GIVEN)
-        livekit_api_key = livekit_api_key or (os.getenv("LIVEKIT_API_KEY") or NOT_GIVEN)
-        livekit_api_secret = livekit_api_secret or (os.getenv("LIVEKIT_API_SECRET") or NOT_GIVEN)
+        livekit_url = (
+            livekit_url if utils.is_given(livekit_url) else (os.getenv("LIVEKIT_URL") or NOT_GIVEN)
+        )
+        livekit_api_key = (
+            livekit_api_key
+            if utils.is_given(livekit_api_key)
+            else (os.getenv("LIVEKIT_API_KEY") or NOT_GIVEN)
+        )
+        livekit_api_secret = (
+            livekit_api_secret
+            if utils.is_given(livekit_api_secret)
+            else (os.getenv("LIVEKIT_API_SECRET") or NOT_GIVEN)
+        )

65-73: Add a Google-style docstring to start().
As per coding guidelines, public methods should include Google-style docstrings.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d97b05 and ccd7a69.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • examples/avatar_agents/README.md
  • examples/avatar_agents/lemonslice/README.md
  • examples/avatar_agents/lemonslice/agent_worker.py
  • livekit-plugins/livekit-plugins-lemonslice/README.md
  • livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/__init__.py
  • livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py
  • livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py
  • livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/log.py
  • livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/py.typed
  • livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/version.py
  • livekit-plugins/livekit-plugins-lemonslice/pyproject.toml
  • pyproject.toml
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Format code with ruff
Run ruff linter and auto-fix issues
Run mypy type checker in strict mode
Maintain line length of 100 characters maximum
Ensure Python 3.9+ compatibility
Use Google-style docstrings

Files:

  • livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/version.py
  • livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/__init__.py
  • examples/avatar_agents/lemonslice/agent_worker.py
  • livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py
  • livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/log.py
  • livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py
🧠 Learnings (1)
📚 Learning: 2026-01-16T07:44:56.353Z
Learnt from: CR
Repo: livekit/agents PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-16T07:44:56.353Z
Learning: Follow the Plugin System pattern where plugins in livekit-plugins/ are separate packages registered via the Plugin base class

Applied to files:

  • pyproject.toml
🧬 Code graph analysis (3)
examples/avatar_agents/lemonslice/agent_worker.py (3)
livekit-agents/livekit/agents/voice/agent.py (2)
  • Agent (34-642)
  • instructions (99-104)
livekit-agents/livekit/agents/job.py (1)
  • JobContext (132-598)
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py (2)
  • AvatarSession (27-111)
  • start (65-111)
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py (3)
livekit-agents/livekit/agents/job.py (2)
  • api (288-296)
  • get_job_context (56-63)
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py (3)
  • LemonSliceAPI (27-122)
  • LemonSliceException (20-21)
  • start_agent_session (45-81)
livekit-agents/livekit/agents/utils/http_context.py (1)
  • http_session (40-51)
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py (3)
livekit-agents/livekit/agents/_exceptions.py (2)
  • APIConnectionError (84-88)
  • APIStatusError (45-81)
livekit-agents/livekit/agents/types.py (1)
  • APIConnectOptions (54-88)
livekit-agents/livekit/agents/utils/misc.py (1)
  • is_given (25-26)
🔇 Additional comments (5)
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/log.py (1)

1-3: LGTM!

Standard logger setup following the established plugin pattern with the correct namespace.

livekit-plugins/livekit-plugins-lemonslice/README.md (1)

1-5: LGTM!

README follows the standard plugin documentation pattern with appropriate links.

examples/avatar_agents/lemonslice/README.md (1)

1-28: LGTM!

Clear documentation with all required environment variables and startup command.

livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/__init__.py (1)

20-40: LGTM!

Plugin structure correctly follows the established pattern with proper exports and auto-registration. Based on learnings, this aligns with the Plugin System pattern where plugins are registered via the Plugin base class.

livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/version.py (1)

15-15: Version constant looks good.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +27 to +31
lemonslice_image_url = os.getenv("LEMONSLICE_IMAGE_URL")
avatar = lemonslice.AvatarSession(
agent_image_url=lemonslice_image_url,
agent_prompt="Be expressive in your movements and use your hands while talking.", # Prompt to guide the avatar's movements
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Validate LEMONSLICE_IMAGE_URL before use.
If the env var is unset, None will be treated as a provided value and sent to the API, leading to a runtime failure. Fail fast with a clearer error.

🔧 Suggested fix
-    lemonslice_image_url = os.getenv("LEMONSLICE_IMAGE_URL")
+    lemonslice_image_url = os.getenv("LEMONSLICE_IMAGE_URL")
+    if not lemonslice_image_url:
+        raise ValueError("LEMONSLICE_IMAGE_URL must be set")
     avatar = lemonslice.AvatarSession(
         agent_image_url=lemonslice_image_url,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
lemonslice_image_url = os.getenv("LEMONSLICE_IMAGE_URL")
avatar = lemonslice.AvatarSession(
agent_image_url=lemonslice_image_url,
agent_prompt="Be expressive in your movements and use your hands while talking.", # Prompt to guide the avatar's movements
)
lemonslice_image_url = os.getenv("LEMONSLICE_IMAGE_URL")
if not lemonslice_image_url:
raise ValueError("LEMONSLICE_IMAGE_URL must be set")
avatar = lemonslice.AvatarSession(
agent_image_url=lemonslice_image_url,
agent_prompt="Be expressive in your movements and use your hands while talking.", # Prompt to guide the avatar's movements
)
🤖 Prompt for AI Agents
In `@examples/avatar_agents/lemonslice/agent_worker.py` around lines 27 - 31, The
environment variable lemonslice_image_url (from
os.getenv("LEMONSLICE_IMAGE_URL")) is used directly as agent_image_url when
constructing lemonslice.AvatarSession which can pass None to the API; add a
validation check after reading lemonslice_image_url to verify it is non-empty
and raise a clear exception (or call sys.exit) if missing, so
AvatarSession(agent_image_url=lemonslice_image_url, ...) is only called with a
valid URL.

Comment on lines +15 to +18
"""LemonSlice virtual avatar plugin for LiveKit Agents

See https://https://docs.livekit.io/agents/models/avatar/plugins/lemonslice/ for more information.
"""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix duplicate https:// in documentation URL.

The URL has a typo with double https:// prefix.

🔧 Suggested fix
 """LemonSlice virtual avatar plugin for LiveKit Agents
 
-See https://https://docs.livekit.io/agents/models/avatar/plugins/lemonslice/ for more information.
+See https://docs.livekit.io/agents/models/avatar/plugins/lemonslice/ for more information.
 """
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"""LemonSlice virtual avatar plugin for LiveKit Agents
See https://https://docs.livekit.io/agents/models/avatar/plugins/lemonslice/ for more information.
"""
"""LemonSlice virtual avatar plugin for LiveKit Agents
See https://docs.livekit.io/agents/models/avatar/plugins/lemonslice/ for more information.
"""
🤖 Prompt for AI Agents
In
`@livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/__init__.py`
around lines 15 - 18, The module docstring in __init__.py contains a malformed
documentation URL with a duplicated "https://"
("https://https://docs.livekit.io/..."); update the docstring to remove the
extra scheme so the link reads
"https://docs.livekit.io/agents/models/avatar/plugins/lemonslice/" - edit the
top-level string literal in livekit/plugins/lemonslice/__init__.py accordingly.

Comment on lines +96 to +121
for i in range(self._conn_options.max_retry):
try:
async with self._session.post(
self._api_url,
headers={
"Content-Type": "application/json",
"X-API-Key": self._api_key,
},
json=payload,
timeout=aiohttp.ClientTimeout(sock_connect=self._conn_options.timeout),
) as response:
if not response.ok:
text = await response.text()
raise APIStatusError(
"Server returned an error", status_code=response.status, body=text
)
return await response.json() # type: ignore
except Exception as e:
if isinstance(e, APIConnectionError):
logger.warning("failed to call LemonSlice api", extra={"error": str(e)})
else:
logger.exception("failed to call lemonslice api")

if i < self._conn_options.max_retry - 1:
await asyncio.sleep(self._conn_options.retry_interval)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "api.py" | grep lemonslice

Repository: livekit/agents

Length of output: 136


🏁 Script executed:

git ls-files | grep -i lemonslice | head -20

Repository: livekit/agents

Length of output: 738


🏁 Script executed:

# Check the file structure
fd "api.py" --path "*lemonslice*"

Repository: livekit/agents

Length of output: 273


🏁 Script executed:

cat -n ./livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py | head -130

Repository: livekit/agents

Length of output: 5209


🏁 Script executed:

# Find APIStatusError definition
rg "class APIStatusError" --type py

Repository: livekit/agents

Length of output: 134


🏁 Script executed:

# Find conn_options definition
rg "_conn_options\|class.*ConnOptions" --type py -A 5 | head -50

Repository: livekit/agents

Length of output: 40


🏁 Script executed:

cat ./livekit-agents/livekit/agents/_exceptions.py

Repository: livekit/agents

Length of output: 2755


🏁 Script executed:

# Find APIConnectOptions definition
rg "class APIConnectOptions" --type py -A 20

Repository: livekit/agents

Length of output: 1381


🏁 Script executed:

# Check full APIConnectOptions class definition
rg "class APIConnectOptions" --type py -A 50 | head -60

Repository: livekit/agents

Length of output: 3490


🏁 Script executed:

# Search for _interval_for_retry method anywhere in the codebase
rg "_interval_for_retry" --type py

Repository: livekit/agents

Length of output: 1318


🏁 Script executed:

# Check if there are other API implementations in the codebase to see retry patterns
rg "for i in range.*max_retry" --type py -B 2 -A 15 | head -100

Repository: livekit/agents

Length of output: 10495


🏁 Script executed:

# Verify the sleep condition logic
# With range(max_retry + 1) and i < max_retry, when max_retry=3:
# i=0: sleep (0 < 3) ✓
# i=1: sleep (1 < 3) ✓
# i=2: sleep (2 < 3) ✓
# i=3: no sleep (3 < 3) ✗
# This means 3 sleeps for 4 attempts, which is correct

# Check if there are any ruff formatting issues in the file
rg "for i in range" ./livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py -A 30 | wc -l

Repository: livekit/agents

Length of output: 60


Fix retry loop semantics and respect non-retryable errors.

The retry loop should allow max_retry retries (i.e., max_retry + 1 total attempts), and should not retry 4xx client errors which are marked as non-retryable in APIStatusError. Additionally, use _interval_for_retry() for backoff consistency with other API integrations in the codebase.

Changes needed:

  1. Change range(self._conn_options.max_retry) to range(self._conn_options.max_retry + 1) to allow proper retry semantics
  2. Check if isinstance(e, APIStatusError) and not e.retryable: raise to respect non-retryable errors (4xx responses)
  3. Replace self._conn_options.retry_interval with self._conn_options._interval_for_retry(i) for consistent backoff
  4. Update sleep condition from i < self._conn_options.max_retry - 1 to i < self._conn_options.max_retry
🤖 Prompt for AI Agents
In `@livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py`
around lines 96 - 121, The retry loop currently iterates
range(self._conn_options.max_retry) and always retries; update it to
range(self._conn_options.max_retry + 1) so attempts = max_retry + 1, and when
catching exceptions, if isinstance(e, APIStatusError) and not e.retryable:
re-raise to avoid retrying 4xx non-retryable errors; keep handling
APIConnectionError separately as before. Replace usage of
self._conn_options.retry_interval with self._conn_options._interval_for_retry(i)
for backoff, and change the sleep/continue condition to i <
self._conn_options.max_retry so you only sleep when another attempt remains.
Ensure these changes are applied around the async with self._session.post(...)
block and the except handler where APIStatusError, APIConnectionError, and i are
referenced.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants