Skip to content

fix(a2a): Port event action allowlist, agent card description source and resume flattening to v1 - #6801

Merged
GWeale merged 4 commits into
v1from
backport-v1-pr12
Aug 19, 2026
Merged

fix(a2a): Port event action allowlist, agent card description source and resume flattening to v1#6801
GWeale merged 4 commits into
v1from
backport-v1-pr12

Conversation

@GWeale

@GWeale GWeale commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Ports three A2A changes from main to the v1 branch, one commit each.

  1. Restrict which event action fields are rebuilt from peer metadata (0ba7d3cb, test cfd09e09)

    • A peer's adk_actions metadata sets only escalate and skip_summarization; other fields are dropped with a debug log. All four converters share the allowlist, so a field added later is denied by default.
    • Breaking: state_delta, artifact_delta and the other eight action fields no longer cross the peer boundary, with no flag to restore them. Have the A2A sub-agent return that data in its response content and let the parent write it into its own session.
  2. Build the agent card skill description from agent.description only (efdecf4c)

    • The primary skill's description is agent.description; examples come from a declared ExampleTool.
    • Breaking: the card served by to_a2a() no longer carries instruction text or examples mined from it. Put publishable text in agent.description and declare an ExampleTool for examples.
  3. Flatten human-input responses on resume (aec7aa33)

    • Human-input pause responses are flattened to text before forwarding, and credential payloads are dropped by call name and by AuthConfig shape.
    • Long-running tool responses are preserved as data with their ids; a resume left with no parts returns None and falls back to history reconstruction.

GWeale added 3 commits August 17, 2026 22:59
Port of the same fix from main.

Before, `_extract_event_actions` rebuilt an `EventActions` from whatever the
remote peer put in the `adk_actions` metadata of a message, task, status
update or artifact update, and every field on it was honored. A peer could
therefore set the calling agent's session state and artifact deltas, request
credentials or tool confirmations on the caller's behalf, transfer the caller
to another agent, overwrite agent state, inject a compaction, or rewind the
caller's invocation. Now only an explicit allowlist of inert fields
(`escalate` and `skip_summarization`, in both spellings) is honored and
everything else is dropped with a debug log. Because it is an allowlist, a
field added to `EventActions` later is denied by default.

Behaviour change: an ADK agent calling another ADK agent over A2A no longer
has the peer's `state_delta` and `artifact_delta` applied to its own session.
Event actions describe the sending agent's own session and no longer cross the
peer boundary. The sending side is unchanged, so the metadata is still
serialized outbound; only the receiving side ignores it. There is no flag to
restore the old behaviour.

Also ports the follow-up test that pins the allowlist against regressions.
Port of the same fix from main.

The agent card served by `to_a2a()` at the well-known card path is a
discovery document with no authentication in front of it. Before, the primary
skill's description was built by concatenating the agent's description, its
`instruction` and its `global_instruction` with the pronouns rewritten, and
when no ExampleTool was declared the skill's `examples` were mined out of the
instruction text with a regex looking for quoted `Example Query:` pairs. Both
published the agent's system prompt. Now the description comes from
`agent.description` alone and examples come only from a declared ExampleTool.

Behaviour change: the card no longer contains `agent.instruction` or
`agent.global_instruction`, and no longer contains examples mined out of the
instruction text. Cards for agents that set an instruction get shorter and
some `examples` lists become empty. To publish richer card text, put it in
`agent.description`; to publish examples, declare an ExampleTool. Only
`to_a2a()` is affected, because `adk api_server` serves a static agent.json
and does not use the builder.

Removes `_build_llm_agent_description_with_instructions`,
`_replace_pronouns` and `_extract_examples_from_instruction`, along with the
now-unused `re` import.
Port of the same fix from main.

Before, when an invocation resumed after a pause, RemoteA2aAgent only rewrote
the function response to text if the pausing call was the mock input-required
call, and forwarded everything else to the remote peer exactly as it sat in
the session. A reply to adk_request_credential is a serialized AuthConfig
carrying raw_auth_credential and exchanged_auth_credential, so the user's
access tokens and client secrets were shipped to the peer. A reply to
adk_request_input or adk_request_confirmation was forwarded as a function
response beside the user's text, which is the combination Runner rejects with
"Message cannot contain both function responses and text".

Now every human-input pause response is matched by the pending function call
name and flattened to text before forwarding. Credential payloads are dropped
rather than forwarded, recognized both by call name and by the shape of a
serialized AuthConfig, so a credential arriving under an innocuous name is
still dropped. Genuine long-running tool responses are preserved as data so
the peer can still resume them by id, and when any response is preserved the
message stays a pure resume with no text alongside it. A second guard in the
history-reconstruction fallback stops a dropped credential re-entering that
way.

Behaviour change: a peer that was receiving human-input function responses as
structured data now receives the answer as a text part, so a peer parsing the
{"result": ...} envelope has to read the text instead. A resume that carried
nothing but a credential now produces no message at all and falls through to
history reconstruction.

Also fixes a latent crash that the sanitizer makes reachable: this branch
dereferenced the converted message without checking it, and the converter
returns None for an event with no parts, so a resume whose parts were all
dropped raised AttributeError. It now returns None and lets the caller fall
back to history.
@GWeale GWeale changed the title fix(a2a): Port peer boundary hardening for event actions, agent card and resume to v1 fix(a2a): Port event action allowlist, agent card description source and resume flattening to v1 Aug 19, 2026
@GWeale
GWeale merged commit 1f898a6 into v1 Aug 19, 2026
13 checks passed
@GWeale
GWeale deleted the backport-v1-pr12 branch August 20, 2026 00:04
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