Summary
The ADK middleware never emits REASONING_ENCRYPTED_VALUE, even with Gemini thinking enabled, because it only reads thought_signature from thought-text parts. Gemini attaches the signature to function_call parts (and to the final answer part), so REASONING_ENCRYPTED_VALUE is never produced and the encrypted reasoning is silently dropped.
Environment
ag-ui-adk 0.7.0 (bug also present on main)
google-adk 2.3.0, google-genai (current)
- Gemini 2.5 Flash via Vertex AI
- Agent:
LlmAgent(planner=BuiltInPlanner(thinking_config=ThinkingConfig(include_thoughts=True)))
Root cause
In integrations/adk-middleware/python/src/ag_ui_adk/event_translator.py, the thought signature is captured only inside the if is_thought: branch (~L544–548) and later emitted at ~L790–800 with subtype="message":
if is_thought:
thought_parts.append(part.text)
sig = getattr(part, 'thought_signature', None) # ← only thought-TEXT parts
thought_signatures.append(sig)
But in practice Gemini does not attach the signature to thought-text parts — it attaches it to function_call parts. So thought_signatures ends up all None and nothing is emitted.
Evidence
Probe over runner.run_async(...) (SSE streaming, one turn with 2 tool calls), inspecting every part:
part kind=text thought=True thought_signature=None
part kind=function_call thought=None thought_signature=446 bytes ← signature HERE
part kind=function_call thought=None thought_signature=336 bytes
part kind=text thought=None thought_signature=385 bytes
REASONING_ENCRYPTED_VALUE count in the SSE stream across 3 separate runs: 0.
Expected behaviour
The AG-UI ReasoningEncryptedValueEvent already defines subtype: "tool-call" for exactly this case (a signature bound to a tool call). The middleware should emit:
ReasoningEncryptedValueEvent(
subtype="tool-call",
entity_id=<toolCallId>,
encrypted_value=<base64(thought_signature)>,
)
whenever a function_call part carries a thought_signature, mirroring the existing subtype="message" emission for thought-text parts.
Proposed fix
In the function-call translation path, read part.thought_signature from function_call parts and emit ReasoningEncryptedValueEvent(subtype="tool-call", entity_id=tool_call_id, ...). Happy to send a PR (branch + focused test).
Summary
The ADK middleware never emits
REASONING_ENCRYPTED_VALUE, even with Gemini thinking enabled, because it only readsthought_signaturefrom thought-text parts. Gemini attaches the signature tofunction_callparts (and to the final answer part), soREASONING_ENCRYPTED_VALUEis never produced and the encrypted reasoning is silently dropped.Environment
ag-ui-adk0.7.0 (bug also present onmain)google-adk2.3.0,google-genai(current)LlmAgent(planner=BuiltInPlanner(thinking_config=ThinkingConfig(include_thoughts=True)))Root cause
In
integrations/adk-middleware/python/src/ag_ui_adk/event_translator.py, the thought signature is captured only inside theif is_thought:branch (~L544–548) and later emitted at ~L790–800 withsubtype="message":But in practice Gemini does not attach the signature to thought-text parts — it attaches it to
function_callparts. Sothought_signaturesends up allNoneand nothing is emitted.Evidence
Probe over
runner.run_async(...)(SSE streaming, one turn with 2 tool calls), inspecting everypart:REASONING_ENCRYPTED_VALUEcount in the SSE stream across 3 separate runs: 0.Expected behaviour
The AG-UI
ReasoningEncryptedValueEventalready definessubtype: "tool-call"for exactly this case (a signature bound to a tool call). The middleware should emit:whenever a
function_callpart carries athought_signature, mirroring the existingsubtype="message"emission for thought-text parts.Proposed fix
In the function-call translation path, read
part.thought_signaturefromfunction_callparts and emitReasoningEncryptedValueEvent(subtype="tool-call", entity_id=tool_call_id, ...). Happy to send a PR (branch + focused test).