-
Notifications
You must be signed in to change notification settings - Fork 2.6k
LemonSlice Plugin #4539
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LemonSlice Plugin #4539
Conversation
📝 WalkthroughWalkthroughAdds a LemonSlice virtual-avatar plugin and example integration: new plugin package (API client, avatar session, logging, version, packaging), a LemonSlice-powered agent worker example, and related documentation and READMEs. Changes
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: instantiate (STT, LLM, TTS)
Worker->>Avatar: instantiate (image_url, prompt)
Avatar->>Avatar: ensure aiohttp session
Avatar->>Avatar: build LiveKit AccessToken (JWT)
Avatar->>API: start_agent_session(payload with livekit token)
API->>API: POST request (retry/backoff)
API-->>Avatar: return session_id
Avatar->>Output: create DataStreamAudioOutput (sample_rate, destination)
Output->>Room: attach/bind to room (publish on behalf)
Worker->>Agent: start AgentSession in room
Agent->>Room: publish audio/text events
Room->>Output: route audio to LemonSlice avatar
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
✏️ Tip: You can disable this entire section by setting Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this 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 toentrypoint.
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 leakingNOT_GIVENinto credentials/payload.
UsingorwithNOT_GIVENcan keep the sentinel (if it’s truthy), andlivekit_url/tokenare always serialized into JSON even when not provided. Safer to useutils.is_givenfor 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: Manageaiohttp.ClientSessionlifecycle.
Creating a session internally without a close path can leak sockets. Consider addingclose()/ async context manager support whensessionisn’t provided.livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py (2)
56-77: Preferutils.is_givenfor NOT_GIVEN defaults.
UsingorwithNOT_GIVENcan keep the sentinel (if it’s truthy), which may bypass required config checks and leak into identity fields. Safer to useutils.is_givenconsistently.🔧 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 tostart().
As per coding guidelines, public methods should include Google-style docstrings.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
uv.lockis excluded by!**/*.lock
📒 Files selected for processing (12)
examples/avatar_agents/README.mdexamples/avatar_agents/lemonslice/README.mdexamples/avatar_agents/lemonslice/agent_worker.pylivekit-plugins/livekit-plugins-lemonslice/README.mdlivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/__init__.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/log.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/py.typedlivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/version.pylivekit-plugins/livekit-plugins-lemonslice/pyproject.tomlpyproject.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.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/__init__.pyexamples/avatar_agents/lemonslice/agent_worker.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/log.pylivekit-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
Pluginbase 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.
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/__init__.py
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
`@livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py`:
- Around line 41-44: LemonSliceAPI currently instantiates self._session =
session or aiohttp.ClientSession() but never closes it; add ownership tracking
(e.g., self._owns_session = session is None) in the constructor, implement an
async close method (async def close(self):) that awaits self._session.close()
only when self._owns_session is True, and optionally implement async context
manager methods (__aenter__ returning self and __aexit__ calling await
self.close()) so callers can use "async with LemonSliceAPI(...)" to ensure
proper cleanup; update any usage/tests to call await api.close() or use the
async context manager.
- Around line 62-67: The payload currently always includes livekit_url and
livekit_token which may be NotGivenOr[str] sentinels and will break JSON
serialization; update the payload construction in the function that builds the
transport payload (look for the payload dict in
livekit/plugins/lemonslice/api.py) to only add "livekit_url" and "livekit_token"
inside "properties" when utils.is_given(livekit_url) and
utils.is_given(livekit_token) are true, mirroring how
agent_id/agent_image_url/agent_prompt/idle_timeout are conditionally appended.
🧹 Nitpick comments (4)
examples/avatar_agents/lemonslice/agent_worker.py (2)
18-19: Add return type annotation and docstring.Per coding guidelines, functions should have type hints and Google-style docstrings. The return type annotation is missing.
♻️ Suggested fix
`@server.rtc_session`() -async def entrypoint(ctx: JobContext): +async def entrypoint(ctx: JobContext) -> None: + """LemonSlice avatar agent entrypoint. + + Args: + ctx: The job context containing room and session information. + """ session = AgentSession(
30-33: Line exceeds 100 character limit.Line 32 exceeds the 100-character maximum specified in the coding guidelines. Consider extracting the prompt to a constant or moving the comment.
♻️ Suggested fix
+ # Prompt to guide the avatar's movements + avatar_prompt = "Be expressive in your movements and use your hands while talking." 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 + agent_prompt=avatar_prompt, )livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py (2)
45-55: Add a Google-style docstring forstart_agent_session.
This is a public API surface and should be documented consistently.As per coding guidelines, please ensure Google-style docstrings for public methods.
27-39: Consider usingutils.is_given()for consistency with the rest of the codebase. The currentapi_key or os.getenv(...)pattern works correctly sinceNOT_GIVENis falsy, but the codebase consistently usesutils.is_given()forNotGivenOrchecks (as seen instart_agent_sessionmethod). Using the same pattern here improves readability and consistency.🔧 Suggested refactoring
- ls_api_key = api_key or os.getenv("LEMONSLICE_API_KEY") - if ls_api_key is None: + if utils.is_given(api_key): + ls_api_key = api_key + else: + ls_api_key = os.getenv("LEMONSLICE_API_KEY") + if not ls_api_key: raise LemonSliceException("LEMONSLICE_API_KEY must be set")
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
examples/avatar_agents/lemonslice/agent_worker.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/__init__.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py
🧰 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/__init__.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.pyexamples/avatar_agents/lemonslice/agent_worker.py
🧬 Code graph analysis (1)
examples/avatar_agents/lemonslice/agent_worker.py (1)
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py (2)
AvatarSession(27-111)start(65-111)
🔇 Additional comments (7)
examples/avatar_agents/lemonslice/agent_worker.py (6)
1-7: LGTM!Imports are well-organized following the standard convention (stdlib → third-party → local packages).
9-10: LGTM!Named logger with appropriate log level for an example application.
12-15: LGTM!Module-level
load_dotenv()andAgentServer()initialization is appropriate for this decorator-based pattern.
46-47: LGTM!Standard CLI entry point for running the agent server.
27-29: LGTM!The validation for
LEMONSLICE_IMAGE_URLis now properly in place, failing fast with a clear error message if the environment variable is unset.
43-43: No action needed.generate_reply()returnsasyncio.Futureand is designed to support both fire-and-forget (without await) and awaiting patterns. Not awaiting the call is intentional and correct—the reply generation proceeds asynchronously via event loop callbacks. This pattern is used consistently throughout the codebase.livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/__init__.py (1)
15-40: LGTM — clean public surface and plugin registration.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py
Outdated
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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
`@livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py`:
- Around line 32-54: The constructor currently uses "or" which can leave the
NOT_GIVEN sentinel in place for api_key/api_url; change the resolution in the
LemonSliceAPI initializer to explicitly check the sentinel (use
utils.is_given(api_key) and utils.is_given(api_url)) and then fall back to
os.getenv("LEMONSLICE_API_KEY") or DEFAULT_API_URL respectively, validate the
resolved values are non-empty strings, and raise LemonSliceException if api_key
ends up missing; ensure self._api_key and self._api_url never receive the
NOT_GIVEN sentinel so they aren't leaked into headers or URLs.
- Line 36: Replace PEP 604 union syntax with typing generics for Python 3.9
compatibility: change any parameter or return annotation that uses the `|` union
(e.g., the `session: aiohttp.ClientSession | None` parameter) to use
typing.Optional (import Optional from typing) as
`Optional[aiohttp.ClientSession]`; likewise replace `dict[str, Any]` with
`Dict[str, Any]` (import Dict, Any) and any other `X | None` annotations to
`Optional[X]`; update imports to include Optional, Dict, Type, Any as needed and
adjust annotations in the functions/methods that reference these symbols (for
example the session parameter, any headers/json params and typed returns) to
ensure full Python 3.9 compatibility.
In
`@livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py`:
- Around line 51-70: The start method currently uses `or` to fallback to
environment variables which can preserve the NOT_GIVEN sentinel; change the
assignments for `livekit_url`, `livekit_api_key`, and `livekit_api_secret` to
use `utils.is_given` to detect provided values and only when not given read the
env (e.g. if not utils.is_given(livekit_url) then set from os.getenv(...) ),
then validate with `utils.is_given` (or truthiness if env returned a real
string) and raise the existing LemonSliceException if any remain unset; update
references in the `start` method where `_avatar_participant_identity`/name or
credential checks rely on these variables.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
examples/avatar_agents/lemonslice/agent_worker.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py
🧰 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:
examples/avatar_agents/lemonslice/agent_worker.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.pylivekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py
🧬 Code graph analysis (1)
examples/avatar_agents/lemonslice/agent_worker.py (2)
livekit-agents/livekit/agents/worker.py (1)
AgentServer(253-1317)livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py (2)
AvatarSession(26-106)start(54-106)
🔇 Additional comments (5)
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/api.py (2)
69-121:start_agent_sessionpayload gating looks solid.Conditional inclusion of optional fields prevents sending
NOT_GIVENand keeps the transport properties clean.
158-171: Preserve task cancellation in the retry loop.
except Exceptionwill swallowasyncio.CancelledErroron Python 3.9, preventing cancellation and causing unwanted retries.🐛 Proposed fix
- except Exception as e: + except asyncio.CancelledError: + raise + except Exception as e:Likely an incorrect or invalid review comment.
livekit-plugins/livekit-plugins-lemonslice/livekit/plugins/lemonslice/avatar.py (2)
100-106: Media output wiring looks good.Clear, explicit attachment of the avatar audio stream to the participant identity.
3-5: The code is already Python 3.9 compatible. The file usesfrom __future__ import annotations(line 1), which defers all type annotations to strings per PEP 563. This means the PEP 604 union syntax (aiohttp.ClientSession | None) at line 48 is safe on Python 3.9 and does not need to be changed toOptional.Likely an incorrect or invalid review comment.
examples/avatar_agents/lemonslice/agent_worker.py (1)
18-45: Example flow is clear and fails fast on missing config.The session setup and avatar start sequence is straightforward and readable for users.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
LemonSlice Integration Docs
LemonSlice API Docs
Summary by CodeRabbit
New Features
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.