Skip to content

eval generate: 'Malformed agent event: missing content' for any agent with before_agent_callback #82

Description

@sloopec

Summary

agents-cli eval generate fails on every case with Malformed agent event: missing content. as soon as the evaluated agent (root or nested) has a before_agent_callback set — even on an otherwise trivial, working agent. agents-cli run (interactive) handles the same SSE event fine; the problem is specific to the eval generate code path.

Root cause

google/agents/cli/eval/cmd_generate.py::_parse_sse_event requires a content field on every event received over /run_sse:

def _parse_sse_event(event: dict) -> evals_types.AgentEvent:
    ...
    missing = [field for field in ("author", "content") if not event.get(field)]
    if missing:
        raise ValueError(f"Malformed agent event: missing {' and '.join(missing)}.")

    return evals_types.AgentEvent(
        author=event.get("author"), content=event.get("content")
    )

ADK legitimately emits an event with no content when a before_agent_callback mutates session state: a pure bookkeeping event carrying actions.stateDelta (whatever the callback wrote), with author present but no top-level content. This is the first event of the SSE stream, before any model response. Example, captured directly from /run_sse:

data: {"invocationId":"e-...","author":"root_agent","actions":{"stateDelta":{"foo":"bar"},"artifactDelta":{},"requestedAuthConfigs":{},"requestedToolConfirmations":{}},"nodeInfo":{"path":"root_agent@1"},"id":"...","timestamp":...}

_parse_sse_event raises on this event, which aborts inference for the entire case.

Minimal reproduction (independent of any specific project)

Created via agents-cli scaffold create <name> --adk -y (default scaffold, no project-specific changes). Only change to the generated app/agent.py: add a before_agent_callback that sets a single state variable.

async def _init_state(callback_context) -> None:
    if "foo" not in callback_context.state:
        callback_context.state["foo"] = "bar"


root_agent = Agent(
    name="root_agent",
    model=Gemini(model=MODEL, retry_options=types.HttpRetryOptions(attempts=3)),
    instruction="You are a helpful AI assistant.",
    tools=[get_weather],
    before_agent_callback=_init_state,   # <-- only change
)

tests/eval/datasets/repro.json:

{
  "eval_cases": [
    {
      "eval_case_id": "hello",
      "prompt": {"role": "user", "parts": [{"text": "Hello, what can you help me with?"}]}
    }
  ]
}
agents-cli eval generate --dataset tests/eval/datasets/repro.json -o /tmp/repro_traces

With before_agent_callback:

[generate] case[0] FAILED: Malformed agent event: missing content.
Inference summary: 0/1 succeeded, 1 failed.
Error: Inference failed: 0 of 1 cases succeeded.

Control run (identical code, only before_agent_callback=_init_state, removed):

[generate] case[0] done
Traces saved to /tmp/repro_traces

Isolated via bisection

The following were each tested individually against the same scaffold baseline (real Gemini API, gemini-3.6-flash) and all passed eval generate successfully:

  • sub_agents=[<plain Agent>], unused
  • sub_agents=[<plain Agent>] + actual delegation via transfer_to_agent
  • tools=[AgentTool(<plain Agent>)] + actual tool call
  • sub_agents=[<SequentialAgent>], unused, combined with AgentTool + tools
  • sub_agents=[<Agent with output_schema>], unused

Only adding before_agent_callback (alone, without any of the above) reliably triggers the failure — this is the minimal sufficient condition.

Expected vs. actual

  • Expected: agents-cli eval generate works for any agent with before_agent_callback (a documented, common ADK pattern for state initialization) just as it does without one.
  • Actual: The very first event of the stream aborts the entire case before any model response is even generated. Affects every case in the dataset equally (0 of N succeed).

Environment

Component Version
agents-cli 1.4.0 (also reproducible on 1.3.1 — same missing check present unchanged)
google-adk 2.7.0
Python 3.13.14
Model gemini-3.6-flash (scaffold default), reproduced independent of model
OS macOS 26.5.2 (Darwin)
Provider Gemini API / AI Studio (GEMINI_API_KEY), no Vertex AI

Suggested fix

_parse_sse_event should recognize events with no content but a valid author and (optionally) actions.stateDelta/actions.endOfAgent as pure bookkeeping/callback events, and either (a) skip them (they carry no AgentEvent-relevant model/tool content) or (b) construct the AgentEvent with an empty/synthetic content instead of raising. Alternatively, make content optional in AgentEvent construction if the downstream data structure allows it.

Impact

This blocks agents-cli eval generate — and by extension eval run, which calls generate internally — for any agent using the documented before_agent_callback state-initialization pattern, which is not an uncommon setup.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions