-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat: avatario avatar plugin #4114
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
Conversation
|
@Saksham209 is it possible get a loom recording as a demo for this avatar plugin please? you can also add an example here |
|
Hi @i25959341. I have added the example file in the specified folder. Here is the loom link for our product: |
|
@i25959341 please let me know if there is anything required from our end. |
|
Hi @Saksham209, apology on this, can you show your plugin is working by running your example script and do a conversation on the agent playground? similar to this loom video on this PR. |
|
Hi @karlsonlee-livekit would this demo work: loom ? I removed this line from my experiment script for this demo : as it was generating speech in a different language |
|
Hi, thank you for creating this PR! Could you also edit these files and add the plugin: https://github.com/livekit/agents/blob/main/pyproject.toml |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
📝 WalkthroughWalkthroughAdds a new Avatario LiveKit plugin and example integration: async Avatario API client, AvatarSession that builds JWTs and starts remote avatar sessions, package metadata/typing, logging, docs, and an example agent worker that composes AvatarSession with AgentSession to join LiveKit rooms. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as RTC Client
participant Agent as Agent Worker
participant Avatar as AvatarSession
participant AvatarioAPI as Avatario API
participant LiveKit as LiveKit Server
Client->>Agent: Connect RTC session
Agent->>Avatar: Instantiate AvatarSession (avatar_id, video_info)
Avatar->>Avatar: _ensure_http_session()
Avatar->>Avatar: Build JWT (identity, grants, publish-on-behalf)
Avatar->>AvatarioAPI: POST /start-session (payload: avatar_id, token, livekit_url, video_info)
AvatarioAPI-->>Avatar: Session started (response)
Avatar->>Agent: Configure DataStreamAudioOutput (route audio to avatar)
Agent->>LiveKit: Join room / publish tracks
LiveKit-->>Agent: Room joined / participant events
Agent->>Client: Agent/Avatar audio/video streams active
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
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 nitpick comments
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used📓 Path-based instructions (1)**/*.py📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (1)📚 Learning: 2026-01-16T07:44:56.353ZApplied to files:
⏰ 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)
🔇 Additional comments (5)
✏️ Tip: You can disable this entire section by setting Comment |
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/avatario/README.md`:
- Around line 1-3: Replace the incorrect phrase "a animated" in the README
header/intro with the grammatically correct "an animated"; locate the string "a
animated avatar" in the README content (under the "LiveKit Avatario Avatar
Agent" title) and update it to "an animated avatar".
In `@livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py`:
- Around line 28-48: The __init__ currently uses Python 3.10 union types,
mis-handles the NOT_GIVEN sentinel, and leaks aiohttp sessions; update the
signature to use Optional[aiohttp.ClientSession] for Python 3.9 compatibility,
replace truthy checks with utils.is_given(...) when handling api_key and
avatar_id so the NOT_GIVEN sentinel isn't lost (e.g., in AvatarioAPI.__init__
check utils.is_given(avatar_id) and utils.is_given(api_key) before falling back
to env), and track session ownership by adding a boolean like self._owns_session
when you create a new aiohttp.ClientSession so you can implement an async
aclose(self) method that closes the session only if owned and not already
closed.
In `@livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py`:
- Around line 69-85: The start method currently uses "livekit_url = livekit_url
or os.getenv(...)" which fails when the sentinel NOT_GIVEN is truthy; update the
fallback logic to explicitly check for the NOT_GIVEN sentinel for livekit_url,
livekit_api_key, and livekit_api_secret (e.g., if livekit_url is NOT_GIVEN then
set it from os.getenv, otherwise keep the provided value), then validate and
raise AvatarioException if any final value is missing; reference the start
method and the variables livekit_url, livekit_api_key, livekit_api_secret and
the AvatarioException to locate where to change the assignments.
🧹 Nitpick comments (1)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (1)
73-113: Tighten retry semantics and fix docstring drift.
The docstring mentions anendpointarg that doesn’t exist. Also, ifmax_retryrepresents “number of retries,” the loop should attemptmax_retry + 1total tries and honor an immediate first retry perAPIConnectOptionsdocs.♻️ Suggested refactor
- endpoint: API endpoint path (without leading slash) payload: JSON payload for the request @@ - for i in range(self._conn_options.max_retry): + for i in range(self._conn_options.max_retry + 1): @@ - if i < self._conn_options.max_retry - 1: - await asyncio.sleep(self._conn_options.retry_interval) + if i < self._conn_options.max_retry: + await asyncio.sleep(0.1 if i == 0 else self._conn_options.retry_interval)
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
examples/avatar_agents/avatario/README.mdexamples/avatar_agents/avatario/agent_worker.pylivekit-plugins/livekit-plugins-avatario/README.mdlivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/__init__.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/log.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/py.typedlivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/version.pylivekit-plugins/livekit-plugins-avatario/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-avatario/livekit/plugins/avatario/log.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/version.pyexamples/avatar_agents/avatario/agent_worker.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/__init__.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
🧬 Code graph analysis (4)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (6)
livekit-agents/livekit/agents/job.py (2)
api(276-284)get_job_context(56-63)livekit-agents/livekit/agents/types.py (1)
APIConnectOptions(54-88)livekit-agents/livekit/agents/voice/avatar/_datastream_io.py (1)
DataStreamAudioOutput(23-260)livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (3)
AvatarioAPI(27-113)AvatarioException(20-21)start_session(49-71)livekit-agents/livekit/agents/utils/misc.py (1)
is_given(25-26)livekit-agents/livekit/agents/utils/http_context.py (1)
http_session(40-51)
examples/avatar_agents/avatario/agent_worker.py (4)
livekit-agents/livekit/agents/voice/agent.py (2)
Agent(40-638)instructions(105-110)livekit-agents/livekit/agents/worker.py (1)
AgentServer(253-1310)livekit-agents/livekit/agents/voice/agent_session.py (1)
AgentSession(135-1314)livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (1)
VideoInfo(33-36)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/__init__.py (3)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (1)
AvatarioException(20-21)livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (1)
AvatarSession(29-113)livekit-agents/livekit/agents/plugin.py (2)
Plugin(13-56)register_plugin(31-36)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (4)
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)livekit-agents/livekit/agents/utils/aio/sleep.py (1)
sleep(68-69)
🔇 Additional comments (17)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/log.py (1)
1-3: LGTM — consistent module-level logger.livekit-plugins/livekit-plugins-avatario/README.md (1)
1-3: LGTM — concise README intro.livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/py.typed (1)
1-1: LGTM — PEP 561 marker included.livekit-plugins/livekit-plugins-avatario/pyproject.toml (1)
1-39: LGTM — clean packaging metadata.livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/version.py (1)
1-15: LGTM — version constant defined.livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/__init__.py (3)
1-9: Exports look correct.
__all__cleanly exposes the intended public API for the plugin.
16-18: AvatarioPlugin wrapper is clean.
The thin wrapper aroundPluginis straightforward and clear.
21-21: Auto-registration matches the plugin pattern.
Import-time registration aligns with how plugins are typically surfaced.examples/avatar_agents/avatario/agent_worker.py (4)
1-15: Example setup is straightforward.
Logger, dotenv load, and server init are clear and minimal.
17-39: Entrypoint flow looks sensible.
Starting the avatar session before the agent session is a clear, workable sequence.
44-45: CLI entrypoint is fine.
Standard__main__guard andcli.run_appusage.
41-41: Remove this suggestion.session.generate_reply()is a synchronous method that returns aSpeechHandleimmediately; it does not need to be awaited. The method signature atlivekit-agents/livekit/agents/voice/agent_session.py:906confirmsdef generate_reply(...) -> SpeechHandle:is non-async. WhileSpeechHandlecontains internal asyncio state, it is not an awaitable object, and the current code is correct.Likely an incorrect or invalid review comment.
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (2)
20-25: Exception type + default URL are fine.
Clear, simple definitions for the public API surface.
49-71: The review comment is incorrect. The current code already properly handles NOT_GIVEN values and does not need the proposed fix.Why the current code is correct:
Line 55 (
if not livekit_agent_identity): TheNotGivenclass defines__bool__()to returnFalse, sonot NOT_GIVENevaluates toTrue. This condition correctly catches and rejectsNOT_GIVEN.Line 61 (
properties = properties or {}): Python'soroperator evaluatesNOT_GIVENasFalse(via__bool__()), so it returns the right operand{}. The sentinel value is never used.Line 69 (
if utils.is_given(self._video_info)): This properly guards the code, preventingNOT_GIVENfrom being added to the payload.JSON serialization: Sentinel values never reach the payload. They are either caught by conditionals (raising exceptions) or converted to default values before payload construction.
The proposed fix introduces unnecessary complexity and redundancy without addressing a real issue.
Likely an incorrect or invalid review comment.
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (3)
29-37: VideoInfo defaults look good.
Simple, sensible defaults for avatar video parameters.
63-67: HTTP session retrieval is fine.
Using the job-context HTTP session is consistent with other plugins.
38-62: The current implementation correctly handles the sentinel value without issues.
avatar_participant_identity or _AVATAR_AGENT_IDENTITYworks as intended becauseNOT_GIVENis falsy (its__bool__()method returnsFalse). Theoroperator will correctly use the default value whenNOT_GIVENis passed, so sentinel values cannot leak into token creation. The proposed fix is unnecessary for the stated concern.Likely an incorrect or invalid review comment.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py
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: 8
🤖 Fix all issues with AI agents
In `@examples/avatar_agents/README.md`:
- Line 12: The markdown list item for Avatario contains a formatting typo:
change the substring "-[Platform]" to " - [Platform]" in the Avatario entry (the
line containing "**[Avatario](./avatario/)** -[Platform](https://avatario.ai/) |
[Integration Guide](https://avatario.ai/docs/integrations/livekit)") so it
matches the other entries' " - " spacing.
In `@livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py`:
- Line 29: Remove the trailing whitespace on the blank module-level line in the
avatario API module (livekit.plugins.avatario.api) flagged by ruff: delete the
stray spaces on the empty line near the top of the file so the line is truly
empty (or run a whitespace-trimming/save to strip trailing spaces).
- Line 57: Remove the trailing whitespace that ruff flagged in
livekit.plugins.avatario.api (a blank line in api.py); open the file and delete
the extra space characters at the end of the empty line so the file contains a
true blank line without trailing spaces, then save and run the linter again to
confirm the warning is gone.
- Line 84: The code uses "properties = properties or {}" which fails when the
sentinel NOT_GIVEN (truthy) is passed; change this to detect the sentinel using
utils.is_given and only set an empty dict when properties was not given (e.g.,
if not utils.is_given(properties): properties = {}), keeping the rest of the
function logic the same and using the existing utils.is_given() helper
referenced elsewhere in the file.
- Around line 58-59: The union type in the async context manager signature
(__aexit__) uses Python 3.10+ syntax (e.g., "type | None") which breaks 3.9; fix
by either adding "from __future__ import annotations" at the top of the module
to enable postponed evaluation of annotations, or change the annotation in the
__aexit__ definition to use typing.Optional/Union (e.g., Optional[type] and
Optional[Exception]) and import Optional from typing so the code remains Python
3.9 compatible.
- Around line 110-120: The start_session method (inside AvatarioAPI) can call
self._session.post when self._session is None if the instance wasn't entered via
__aenter__; add a runtime guard at the start of start_session (and any other
public methods that use self._session like _post) that checks if self._session
is not None and raises a clear RuntimeError (or ValueError) instructing users to
use the class as an async context manager (or call the initializer), or
alternatively lazily create the aiohttp session; reference the
attributes/methods self._session, start_session, __aenter__, and _post when
applying the check so the error is raised early with a descriptive message.
In `@livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py`:
- Around line 71-79: The NOT_GIVEN sentinel is handled incorrectly and checks
are inconsistent: ensure both avatar_id and avatario_api_key use the
utils.is_given() helper when resolving inputs and environment variables (replace
the `a or (os.getenv(...) or NOT_GIVEN)` pattern with explicit resolution that
prefers the provided argument, then falls back to os.getenv(...), and finally
NOT_GIVEN), and then validate with utils.is_given() before raising
AvatarioException for missing AVATARIO_AVATAR_ID and AVATARIO_API_KEY; finally
assign to self._avatar_id and self._api_key only after those validated resolved
values.
In `@pyproject.toml`:
- Line 29: The dependency declaration for livekit-plugins-lemonslice in
pyproject.toml has a formatting inconsistency (missing space before the closing
brace); update the entry for livekit-plugins-lemonslice = { workspace = true} to
follow the project style by adding a space before the closing brace so it reads
with consistent spacing around braces for that dependency declaration.
♻️ Duplicate comments (1)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (1)
101-110: NOT_GIVEN handling still incorrect for LiveKit credentials.Same issue as the
__init__method—the patternlivekit_url = livekit_url or (os.getenv(...) or NOT_GIVEN)doesn't work becauseNOT_GIVENis truthy. This was flagged in a previous review but the fix appears incomplete.🛠️ Proposed fix
- 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 - ) - if not livekit_url or not livekit_api_key or not livekit_api_secret: + livekit_url = ( + livekit_url if utils.is_given(livekit_url) else os.getenv("LIVEKIT_URL") + ) + livekit_api_key = ( + livekit_api_key + if utils.is_given(livekit_api_key) + else os.getenv("LIVEKIT_API_KEY") + ) + livekit_api_secret = ( + livekit_api_secret + if utils.is_given(livekit_api_secret) + else os.getenv("LIVEKIT_API_SECRET") + ) + if not livekit_url or not livekit_api_key or not livekit_api_secret: raise AvatarioException( "livekit_url, livekit_api_key, and livekit_api_secret must be set " "by arguments or environment variables" )
🧹 Nitpick comments (2)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (1)
129-138: Retry logic retries all exceptions, including non-retryable ones.The current implementation catches all exceptions and retries, but
APIStatusErrorfrom 4xx responses hasretryable=False. Consider checkinge.retryablebefore retrying to avoid wasting retries on client errors like 401 Unauthorized or 400 Bad Request.♻️ Proposed improvement
except Exception as e: - if isinstance(e, APIConnectionError): + if isinstance(e, (APIConnectionError, APIStatusError)): + if not e.retryable: + raise logger.warning( "failed to call Avatario API", extra={"error": str(e)} ) else: logger.exception("failed to call avatario api") + raise # Don't retry unexpected exceptions if i < self._conn_options.max_retry - 1: await asyncio.sleep(self._conn_options.retry_interval)livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (1)
81-84: NOT_GIVEN handling for participant identity/name is inconsistent.Using
orworks here because these fall back to string constants (which are truthy), but it's inconsistent with theutils.is_given()pattern used elsewhere. IfNOT_GIVENis passed, theorshort-circuits correctly only because the fallback is truthy.♻️ Suggested improvement for consistency
self._avatar_participant_identity = ( - avatar_participant_identity or _AVATAR_AGENT_IDENTITY + avatar_participant_identity + if utils.is_given(avatar_participant_identity) + else _AVATAR_AGENT_IDENTITY ) - self._avatar_participant_name = avatar_participant_name or _AVATAR_AGENT_NAME + self._avatar_participant_name = ( + avatar_participant_name + if utils.is_given(avatar_participant_name) + else _AVATAR_AGENT_NAME + )
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
examples/README.mdexamples/avatar_agents/README.mdexamples/avatar_agents/avatario/README.mdlivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/version.pylivekit-plugins/livekit-plugins-avatario/pyproject.tomlpyproject.toml
🚧 Files skipped from review as they are similar to previous changes (3)
- livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/version.py
- livekit-plugins/livekit-plugins-avatario/pyproject.toml
- examples/avatar_agents/avatario/README.md
🧰 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-avatario/livekit/plugins/avatario/avatar.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
🧠 Learnings (2)
📓 Common learnings
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
📚 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 (1)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (4)
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)livekit-agents/livekit/agents/utils/aio/sleep.py (1)
sleep(68-69)
🪛 GitHub Check: ruff
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
[failure] 57-57: Ruff (W293)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py:57:1: W293 Blank line contains whitespace
[failure] 29-29: Ruff (W293)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py:29:1: W293 Blank line contains whitespace
⏰ 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)
- GitHub Check: unit-tests
- GitHub Check: type-check (3.13)
- GitHub Check: type-check (3.9)
🔇 Additional comments (3)
examples/README.md (1)
13-13: LGTM — clear provider list update.pyproject.toml (1)
9-9: LGTM!The Avatario plugin workspace entry follows the established pattern and is correctly placed in alphabetical order.
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (1)
139-144: LGTM!The
DataStreamAudioOutputconfiguration correctly routes audio to the avatar participant with the appropriate sample rate and video track synchronization.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
Outdated
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
Outdated
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
Outdated
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py
Outdated
Show resolved
Hide resolved
| livekit-plugins-hume = { workspace = true } | ||
| livekit-plugins-inworld = { workspace = true } | ||
| livekit-plugins-langchain = { workspace = true } | ||
| livekit-plugins-lemonslice = { workspace = true} |
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.
Minor formatting inconsistency: missing space before closing brace.
📝 Proposed fix
-livekit-plugins-lemonslice = { workspace = true}
+livekit-plugins-lemonslice = { workspace = true }📝 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.
| livekit-plugins-lemonslice = { workspace = true} | |
| livekit-plugins-lemonslice = { workspace = true } |
🤖 Prompt for AI Agents
In `@pyproject.toml` at line 29, The dependency declaration for
livekit-plugins-lemonslice in pyproject.toml has a formatting inconsistency
(missing space before the closing brace); update the entry for
livekit-plugins-lemonslice = { workspace = true} to follow the project style by
adding a space before the closing brace so it reads with consistent spacing
around braces for that dependency declaration.
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-avatario/livekit/plugins/avatario/api.py`:
- Line 149: The file ends without a trailing newline causing ruff W292; update
the function that raises APIConnectionError (the line containing raise
APIConnectionError("Failed to call Avatario API after all retries")) to ensure
the file ends with a single trailing newline character (add a newline at EOF).
In `@livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py`:
- Around line 85-88: The current assignments for _avatar_participant_identity
and _avatar_participant_name use "or" which treats the NOT_GIVEN sentinel as
truthy and can pass the sentinel through; change them to use utils.is_given() so
the defaults (_AVATAR_AGENT_IDENTITY and _AVATAR_AGENT_NAME) are applied only
when avatar_participant_identity / avatar_participant_name are not given. Locate
the assignments to self._avatar_participant_identity and
self._avatar_participant_name in avatar.py and replace the "or" logic with a
conditional that calls utils.is_given(avatar_participant_identity) and
utils.is_given(avatar_participant_name) respectively, setting the default only
when is_given returns False.
♻️ Duplicate comments (2)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (1)
105-110: Correct LiveKit env fallback when args are NOT_GIVEN.
NOT_GIVENis truthy, so the currentorchain skips env vars and the subsequent falsy check won’t catch missing values, leading to invalid token construction.🛠️ Proposed fix
- 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) and livekit_url else os.getenv("LIVEKIT_URL") + ) + livekit_api_key = ( + livekit_api_key + if utils.is_given(livekit_api_key) and livekit_api_key + else os.getenv("LIVEKIT_API_KEY") + ) + livekit_api_secret = ( + livekit_api_secret + if utils.is_given(livekit_api_secret) and livekit_api_secret + else os.getenv("LIVEKIT_API_SECRET") + )livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (1)
60-64: AvoidX | Nonesyntax to keep Python 3.9 compatibility.Python 3.9 can’t parse union types with
|, even withfrom __future__ import annotations. UseOptional[...]instead. As per coding guidelines, Python 3.9+ compatibility is required.🛠️ Proposed fix
async def __aexit__( - self, exc_type: type | None, exc_val: Exception | None, exc_tb: Any + self, + exc_type: Optional[type], + exc_val: Optional[Exception], + exc_tb: Any, ) -> None:#!/bin/bash # Verify declared Python version requirements in packaging metadata. rg -n "requires-python|python_requires" -g 'pyproject.toml' -g 'setup.cfg' -g 'setup.py'
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/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:
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py
🧠 Learnings (2)
📓 Common learnings
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
📚 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: Applies to **/*.py : Ensure Python 3.9+ compatibility
Applied to files:
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
🧬 Code graph analysis (1)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (6)
livekit-agents/livekit/agents/job.py (3)
api(276-284)get_job_context(56-63)local_participant_identity(315-319)livekit-agents/livekit/agents/voice/agent_session.py (4)
AgentSession(135-1314)room_io(721-727)conn_options(399-400)output(391-392)livekit-agents/livekit/agents/voice/avatar/_datastream_io.py (1)
DataStreamAudioOutput(23-260)livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (3)
AvatarioAPI(28-149)AvatarioException(21-22)start_session(66-96)livekit-agents/livekit/agents/utils/misc.py (1)
is_given(25-26)livekit-agents/livekit/agents/utils/http_context.py (1)
http_session(40-51)
🪛 GitHub Check: ruff
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
[failure] 149-149: Ruff (W292)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py:149:82: W292 No newline at end of file
[failure] 42-42: Ruff (UP007)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py:42:18: UP007 Use X | Y for type annotations
⏰ 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)
- GitHub Check: unit-tests
- GitHub Check: type-check (3.9)
- GitHub Check: type-check (3.13)
🔇 Additional comments (3)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (1)
90-94: Lazy HTTP session initialization looks good.livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (2)
35-54: Session ownership tracking is clean and readable.
66-96: Input validation and payload assembly look good.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
Outdated
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.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-avatario/livekit/plugins/avatario/api.py`:
- Around line 118-149: The loop currently catches all exceptions and converts
APIStatusError into a generic APIConnectionError and always retries; change the
error handling to first catch APIStatusError (the one raised when response.ok is
false) and re-raise it immediately so callers keep status/body, then in the
broader exception handler inspect retryability (check for a .retryable attribute
or treat APIConnectionError as retryable) and only sleep/retry when the
exception is retryable; if not retryable, re-raise the exception. Update the
try/except around the _session.post block (referencing _conn_options.max_retry,
self._session.post, APIStatusError, APIConnectionError) to implement this flow
and preserve original error details when re-raising.
In `@livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py`:
- Around line 32-36: Replace all PEP 604 union annotations with typing.Optional
to restore Python 3.9 compatibility: change VideoInfo fields using "str | None"
to "Optional[str]" and any usages like "aiohttp.ClientSession | None" to
"Optional[aiohttp.ClientSession]"; add "from typing import Optional" to the
imports if missing. Update the annotations in the VideoInfo dataclass and in the
class/attribute where the aiohttp.ClientSession is declared (refer to VideoInfo
and the attribute using ClientSession) so all None-able types use Optional[...]
instead of the "|" syntax.
♻️ Duplicate comments (2)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (1)
42-43: Align typing syntax with the supported Python version
type | Noneis Python 3.10+ syntax and will be a SyntaxError on 3.9, while UP007 asks forX | Y(also 3.10+). Please confirm the minimum Python version; if 3.9 is still supported, keepOptional[...]and update__aexit__accordingly (and adjust UP007/target-version in lint config). As per coding guidelines, please confirm 3.9 compatibility.🛠️ Suggested 3.9-safe adjustment
async def __aexit__( - self, exc_type: type | None, exc_val: Exception | None, exc_tb: Any + self, exc_type: Optional[type], exc_val: Optional[Exception], exc_tb: Any ) -> None:Also applies to: 60-61
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (1)
103-113: Fix NOT_GIVEN fallbacks for LiveKit credentials
NOT_GIVENis truthy, so the currentordefaults can short‑circuit and skip env fallbacks, and the subsequentif not ...checks won’t catch missing values. Useutils.is_given()to resolve values before validation.🛠️ Proposed fix
- 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) and livekit_url + else os.getenv("LIVEKIT_URL") + ) + livekit_api_key = ( + livekit_api_key + if utils.is_given(livekit_api_key) and livekit_api_key + else os.getenv("LIVEKIT_API_KEY") + ) + livekit_api_secret = ( + livekit_api_secret + if utils.is_given(livekit_api_secret) and livekit_api_secret + else os.getenv("LIVEKIT_API_SECRET") + )
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
examples/avatar_agents/README.mdlivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py
🚧 Files skipped from review as they are similar to previous changes (1)
- examples/avatar_agents/README.md
🧰 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-avatario/livekit/plugins/avatario/api.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py
🧠 Learnings (2)
📓 Common learnings
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
📚 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: Applies to **/*.py : Ensure Python 3.9+ compatibility
Applied to files:
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
🧬 Code graph analysis (1)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/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)
🪛 GitHub Check: ruff
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
[failure] 42-42: Ruff (UP007)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py:42:18: UP007 Use X | Y for type annotations
⏰ 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)
- GitHub Check: type-check (3.9)
- GitHub Check: type-check (3.13)
- GitHub Check: unit-tests
🔇 Additional comments (2)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (1)
66-97: LGTM: start_session payload assembly and validationThe
utils.is_givenchecks and payload construction look solid.livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (1)
92-96: LGTM: lazy session initializationUsing the shared
http_contextsession here is clean and consistent.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py
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-avatario/livekit/plugins/avatario/api.py`:
- Around line 98-152: The _post method's docstring incorrectly references an
endpoint argument that doesn't exist; update the docstring in async def
_post(self, payload: dict[str, Any]) to remove the "endpoint" entry and document
only the actual parameters (payload), return value, and raised exceptions (e.g.
APIConnectionError, APIStatusError) so the doc matches the function signature
and behavior.
- Around line 66-96: In start_session, validate self._avatar_id before
constructing payload: check utils.is_given(self._avatar_id) (or equivalent) and
raise AvatarioException with a clear message if it's NOT_GIVEN so the default
sentinel is not included in the JSON request; reference the start_session method
and self._avatar_id to locate the change and ensure the payload only uses a real
avatar id.
In `@livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py`:
- Around line 1-23: Reorder the imports at the top of the module to satisfy ruff
I001: group and sort standard library imports (from __future__, os, typing,
dataclasses), then third-party packages (aiohttp, livekit and its submodules),
then local package imports (from .api import AvatarioAPI, AvatarioException and
from .log import logger); ensure related symbol imports like
DataStreamAudioOutput and ATTRIBUTE_PUBLISH_ON_BEHALF remain with their livekit
package imports, and run ruff/format (or apply the project's import sorting
tool) to automatically fix ordering.
♻️ Duplicate comments (1)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (1)
99-152: Fix NOT_GIVEN handling for LiveKit credentials.
NOT_GIVENis truthy, so the currentorchain skips env fallbacks and can pass the sentinel intoAccessToken, which breaks auth. Useutils.is_given()to decide when to fall back.🛠️ Proposed fix
- 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) and livekit_url + else os.getenv("LIVEKIT_URL") + ) + livekit_api_key = ( + livekit_api_key + if utils.is_given(livekit_api_key) and livekit_api_key + else os.getenv("LIVEKIT_API_KEY") + ) + livekit_api_secret = ( + livekit_api_secret + if utils.is_given(livekit_api_secret) and livekit_api_secret + else os.getenv("LIVEKIT_API_SECRET") + )
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/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:
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.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: Applies to **/*.py : Ensure Python 3.9+ compatibility
Applied to files:
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.pylivekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py
🧬 Code graph analysis (2)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/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)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (4)
livekit-agents/livekit/agents/job.py (2)
api(276-284)get_job_context(56-63)livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (3)
AvatarioAPI(28-152)AvatarioException(21-22)start_session(66-96)livekit-agents/livekit/agents/utils/misc.py (1)
is_given(25-26)livekit-agents/livekit/agents/utils/http_context.py (1)
http_session(40-51)
🪛 GitHub Check: ruff
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
[failure] 117-117: Ruff (UP007)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py:117:19: UP007 Use X | Y for type annotations
[failure] 61-61: Ruff (UP007)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py:61:50: UP007 Use X | Y for type annotations
[failure] 61-61: Ruff (UP007)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py:61:25: UP007 Use X | Y for type annotations
[failure] 42-42: Ruff (UP007)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py:42:18: UP007 Use X | Y for type annotations
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py
[failure] 67-67: Ruff (UP007)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py:67:29: UP007 Use X | Y for type annotations
[failure] 37-37: Ruff (UP007)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py:37:32: UP007 Use X | Y for type annotations
[failure] 1-23: Ruff (I001)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py:1:1: I001 Import block is un-sorted or un-formatted
⏰ 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)
- GitHub Check: type-check (3.9)
- GitHub Check: type-check (3.13)
- GitHub Check: unit-tests
🔇 Additional comments (6)
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py (3)
21-25: Clear exception type and default endpoint constant.
35-54: Initialization wiring looks good.
55-64: Context manager lifecycle is clean.livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py (3)
33-37: VideoInfo defaults look good.
39-92: Initialization and env fallbacks are clean.
93-97: HTTP session initialization is straightforward.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
Show resolved
Hide resolved
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/avatar.py
Show resolved
Hide resolved
|
Hi @tinalenguyen I have made the required changes you requested. Please let me know if there is anything else needed |
|
thanks for iterating, can you run |
|
The ruff checks that are failing are in places where CodeRabbit is identifying them as a problem. For example it mentions using |
|
@tinalenguyen I have merged the ruff based changes and its passing, can we merge this PR now? |
livekit-plugins/livekit-plugins-avatario/livekit/plugins/avatario/api.py
Outdated
Show resolved
Hide resolved
tinalenguyen
left a comment
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.
thank you for creating this PR and iterating! looks good to me, could you just commit the typo fix? and then this plugin can be included in the next release. if possible, do you have a smaller logo to be included in our docs website?
Co-authored-by: Tina Nguyen <[email protected]>
@tinalenguyen this is the logo for avatario |

Summary by CodeRabbit
New Features
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.