google / google/adk-python

Live multi-agent runs turn audio transcription back on after the caller disabled it

Ouverte
#6,827 0 commentaires 0 réactions 1 personne assignée Réclamée par @wuliang229 Voir sur GitHub
live
Langage dominant
Python
Étoiles
21.5k
Forks
4k
Merge moyen
1 j 14 h
PR mergées (30 j)
37

Description

`_new_invocation_context_for_live()` (`runners.py:2371`) forces `input_audio_transcription` / `output_audio_transcription` on for live multi-agent runs, overwriting an explicit `None`. It writes into the `RunConfig` it was given, so the caller's object is modified too.

`None` is the only way to say "off": both fields are `Field(default_factory=types.AudioTranscriptionConfig)`, so the default is already truthy. `if not run_config.input_audio_transcription:` can't tell "off" from "unset". The block is a no-op for a default `RunConfig` — it only fires when someone deliberately turned transcription off.

**Expected:** `None` stays `None` for the run, and the caller's `RunConfig` is not mutated. (`0b39e728` already copies before filling the AUDIO default at `runners.py:1899` for that reason.)

**Observed:**

```
response_modalities=[]
caller's cfg.input_audio_transcription = AudioTranscriptionConfig()
run's ic.run_config.input_audio_transcription = AudioTranscriptionConfig()
response_modalities=None
caller's cfg.input_audio_transcription = AudioTranscriptionConfig()
run's ic.run_config.input_audio_transcription = AudioTranscriptionConfig()
```

Going through `run_live()` instead, the caller is shielded when `response_modalities` is unset because `runners.py:1899` copies first. The config the run actually uses has transcription on either way, and a reused `RunConfig` carries it forward.

```python
from google.adk.agents.live_request_queue import LiveRequestQueue
from google.adk.agents.llm_agent import LlmAgent
from google.adk.agents.run_config import RunConfig
from google.adk.runners import InMemoryRunner
from google.adk.sessions.session import Session
from google.genai import types

MODEL = "gemini-2.0-flash-live-001"

root = LlmAgent(name="root", model=MODEL,
sub_agents=[LlmAgent(name="child", model=MODEL)])
runner = InMemoryRunner(agent=root, app_name="app")
session = Session(id="s", app_name="app", user_id="u")

for modalities in ([types.Modality.AUDIO], None):
cfg = RunConfig(response_modalities=modalities,
input_audio_transcription=None,
output_audio_transcription=None)
ic = runner._new_invocation_context_for_live(
session, live_request_queue=LiveRequestQueue(), run_config=cfg)
print(f"response_modalities={modalities}")
print(f" caller's cfg.input_audio_transcription = "
f"{cfg.input_audio_transcription!r}")
print(f" run's ic.run_config.input_audio_transcription = "
f"{ic.run_config.input_audio_transcription!r}")
```

`39f78dc2` added the force-on when both fields still defaulted to `None`. `ab69ef8d` later switched them to `default_factory`, which is why the block can only fire on an explicit opt-out. `0b39e728` fixed the same class of write for `response_modalities`; this site was not included.

Fix: don't write when the field is in `model_fields_set`, and `model_copy` before any update so the caller is left alone. Deleting the block also works — the defaults already provide what it's trying to force. If transfer actually requires transcription, raise or warn instead of silently flipping it.

ADK `v2.7.1` / `v1.39.0` / `main` (`4599a526`). macOS, Python 3.13.1. Model never reached — this happens while building the invocation context.

Guide de contribution

Ouvrir le guide de contribution

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.