Skip to content

Add Google ADK adapter plugin prototype#5108

Open
SebastianBoehler wants to merge 1 commit intolivekit:mainfrom
SebastianBoehler:codex/google-adk-plugin
Open

Add Google ADK adapter plugin prototype#5108
SebastianBoehler wants to merge 1 commit intolivekit:mainfrom
SebastianBoehler:codex/google-adk-plugin

Conversation

@SebastianBoehler
Copy link

Summary

  • add a new livekit-plugins-google-adk plugin package
  • add a text-focused google_adk.LLMAdapter that wraps an ADK runner/agent behind LiveKit's llm.LLM interface
  • add focused tests for prompt translation, history reconstruction, and owned-runner cleanup

Motivation

This is a prototype for first-class Google ADK support, similar in spirit to the existing LangChain plugin.

Issue: #5107

Notes

  • the adapter reconstructs an ephemeral ADK session from the LiveKit ChatContext for each chat() call
  • LiveKit function tools are not forwarded; tool execution is expected to happen inside ADK
  • the plugin lazy-loads google-adk instead of declaring it as a hard workspace dependency because ADK currently pins opentelemetry-api / opentelemetry-sdk to <1.39, which conflicts with this repo's ~=1.39.0 pins
  • because of that dependency conflict, users currently need to install google-adk separately alongside this plugin

Validation

  • uv run pytest tests/test_google_adk.py
  • uv run ruff check livekit-plugins/livekit-plugins-google-adk tests/test_google_adk.py

@CLAassistant
Copy link

CLAassistant commented Mar 13, 2026

CLA assistant check
All committers have signed the CLA.

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +318 to +323
def _delta_text(text: str, emitted_text: str) -> tuple[str, str]:
if text.startswith(emitted_text):
delta = text[len(emitted_text) :]
return delta, text

return text, emitted_text + text
Copy link
Contributor

Choose a reason for hiding this comment

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

πŸ”΄ _delta_text fallback causes duplicate text emission when ADK produces multiple invocations with cumulative events

When an ADK run_async call produces events from multiple invocations (e.g., multi-agent or tool-calling scenarios where the model responds, invokes a tool, then responds again), _delta_text emits duplicate text. The function tracks all emitted text via concatenation in the fallback path (return text, emitted_text + text at line 323). When a second invocation starts with fresh cumulative text, its partial events don't start with the accumulated emitted_text, so they hit the fallback and are emitted in full. Then the next cumulative event from the same invocation also can't match emitted_text (which now includes text from both invocations), so it's also emitted in full β€” duplicating the partial text.

Concrete trace showing the duplication

ADK events: inv1 partial text="A", inv1 final text="AB", inv2 partial text="C", inv2 final text="CD"

  1. text="A", emitted="" β†’ startswith("") βœ“ β†’ delta="A", emitted="A"
  2. text="AB", emitted="A" β†’ startswith("A") βœ“ β†’ delta="B", emitted="AB"
  3. text="C", emitted="AB" β†’ startswith("AB") βœ— β†’ fallback β†’ delta="C", emitted="ABC"
  4. text="CD", emitted="ABC" β†’ startswith("ABC") βœ— β†’ fallback β†’ delta="CD", emitted="ABCCD"

Consumer receives: "A"+"B"+"C"+"CD" = "ABCCD" instead of expected "ABCD". The "C" prefix is duplicated.

Prompt for agents
In livekit-plugins/livekit-plugins-google-adk/livekit/plugins/google_adk/adk.py, the _delta_text function (lines 318-323) needs to be reworked to properly handle multi-invocation scenarios where cumulative text resets. One approach is to track the previous event's full text separately from total emitted text: when the new text doesn't start with the previous full text, treat it as a fresh invocation and reset the cumulative tracking. Alternatively, use the ADK event's invocation_id to detect invocation boundaries and reset emitted_text tracking on each new invocation. The _run method (line 182 onward) would need to pass the invocation_id context into the delta tracking logic.
Open in Devin Review

Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

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.

2 participants