Skip to content

bug: StreamingMode.SSE breaks Interactions API function calling — interaction_id not propagated to session events #5169

@gamepop

Description

@gamepop

Description

When using Gemini(use_interactions_api=True) with RunConfig(streaming_mode=StreamingMode.SSE), the ReAct loop (function_call → execute tool → function_result → resume) fails because interaction_id from the first LLM response is not saved to session events. The same code works with StreamingMode.NONE.

ADK Version

  • google-adk: 1.28.1
  • google-genai: 1.70.0
  • Python: 3.14.2

Reproduction

from google.adk.agents import LlmAgent
from google.adk.models import Gemini
from google.adk.runners import InMemoryRunner
from google.adk.agents.run_config import RunConfig, StreamingMode
from google.genai import types
import asyncio

def get_weather(city: str) -> dict:
    """Get weather for a city."""
    return {"city": city, "temp": 72, "condition": "Sunny"}

agent = LlmAgent(
    model=Gemini(model="gemini-2.5-flash", use_interactions_api=True),
    name="test_agent",
    instruction="Use get_weather when asked about weather. Be concise.",
    tools=[get_weather],
)

async def test():
    runner = InMemoryRunner(agent=agent, app_name="test")
    session = await runner.session_service.create_session(
        user_id="user1", app_name="test"
    )

    # WORKS
    # run_config = RunConfig(streaming_mode=StreamingMode.NONE)

    # FAILS
    run_config = RunConfig(streaming_mode=StreamingMode.SSE)

    async for event in runner.run_async(
        user_id="user1",
        session_id=session.id,
        new_message=types.Content(
            role="user", parts=[types.Part(text="Weather in Tokyo?")]
        ),
        run_config=run_config,
    ):
        if event.get_function_calls():
            for fc in event.get_function_calls():
                print(f"Tool: {fc.name}({fc.args})")
        if (event.content and event.content.parts
            and not event.partial and event.author != "user"):
            for p in event.content.parts:
                if p.text:
                    print(f"Response: {p.text[:100]}")

asyncio.run(test())

Expected Behavior

With StreamingMode.SSE, the agent should call get_weather, receive the result, and stream the text response with partial events — same behavior as StreamingMode.NONE but with token-level streaming.

Actual Behavior

The function_call is generated and the tool executes, but the function_result round-trip fails:

google.genai._interactions.BadRequestError: event: error
data: {"error":{"message":"Request contains an invalid argument.","code":"invalid_request"}}

Root Cause (from debug logs)

The InteractionsRequestProcessor._find_previous_interaction_id() iterates session events to find the chain ID for the second LLM call. In SSE mode, all events have interaction_id=None:

# SSE mode — interaction_id not propagated to events
Finding previous_interaction_id: agent=test_agent, num_events=5
Checking event: author=test_agent, interaction_id=None    ← Should have interaction_id
Checking event: author=test_agent, interaction_id=None
Checking event: author=user, interaction_id=None
Sending request, previous_interaction_id: None             ← No chain → 400 error

In NONE mode, interaction_id is correctly propagated:

# NONE mode — interaction_id correctly saved to events
Checking event: author=test_agent, interaction_id=v1_ChdzM...  ← Correct
Found previous_interaction_id: v1_ChdzM...
Sending request, previous_interaction_id: v1_ChdzM...          ← Chain works → Success

Results

StreamingMode Interactions API + Function Calling
NONE ✅ Works — interaction_id propagated correctly
SSE ❌ Fails — interaction_id=None on all session events

Affected Code

google/adk/flows/llm_flows/interactions_processor.py_find_previous_interaction_id() relies on event.interaction_id being set, but SSE streaming events don't carry it from the Interactions API response into the session event store.

Workaround

Use StreamingMode.NONE when the Interactions API is enabled. Token-level streaming is lost, but function calling works correctly.

Metadata

Metadata

Assignees

Labels

live[Component] This issue is related to live, voice and video chat

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions