feat(bqaa): ADK 2.0 minimum producer cut (#293 v5)#6015
Closed
caohy1988 wants to merge 1 commit into
Closed
Conversation
Implements the customer-driven mid-June producer-only subset of the ADK 2.0 observability work tracked in google#293 (parent google#190). The customer needs these specific fields visible in BigQuery before their ADK 2.0 production cutover; full v15 contract (google#190) lands incrementally. This change is producer-only. No consumer-side SDK / typed-view work is included — the customer reads base-table JSON directly during the mid-June window. What lands ---------- A1/A2 — every ADK-enriched row carries the attributes.adk envelope: attributes.adk.schema_version (_ADK_ENVELOPE_SCHEMA_VERSION = "1") attributes.adk.app_name (from InvocationContext.session.app_name) A3 — rows from on_event_callback additionally carry: attributes.adk.source_event_id (Event.id, reliable join key) Note: never fabricated — callback rows without an originating Event leave it JSON-null. C1 — attributes.adk.node = {path, run_id, parent_path}. parent_path is derived from path; default-empty path (NodeInfo.path = "") is preserved verbatim with parent_path = null, no synthesis. C2 — attributes.adk.branch (absent stays JSON null). C3 — attributes.adk.scope = null | {id, kind} per google#198 / google#293 v5 derivation order: (1) None → null, (2) name@run_id / path/name@run_id → node_run, (3) any other non-empty string → function_call (model-provided FC IDs match here), (4) empty/non-string → unknown with warning. C4 — emit AGENT_TRANSFER from event.actions.transfer_to_agent. Payload pinned: from_agent = event.author, to_agent = the target. Verified against EventActions.transfer_to_agent which stores the target only. C5 — emit EVENT_COMPACTION from event.actions.compaction. Float start_timestamp / end_timestamp preserved with fractional precision (consumer view conversion deferred). C6 — emit AGENT_STATE_CHECKPOINT when actions.agent_state is not None OR actions.end_of_agent is True. Allows {agent_state: null, end_of_agent: true} payloads. Inline payload only; GCS offload for oversized state deferred. C7 — emit TOOL_PAUSED for each event.long_running_tool_ids id, with attributes.pause_kind (derived from function_call NAME via _HITL_PAUSE_KIND_MAP — hitl_* for adk_request_*, tool otherwise) and attributes.function_call_id. HITL routing is unchanged: HITL function_responses stay on HITL_*_COMPLETED, NEVER emit TOOL_COMPLETED. Non-HITL function_responses arriving via on_user_message_callback emit TOOL_COMPLETED with pause_kind='tool' so the customer can pair (TOOL_PAUSED ↔ TOOL_COMPLETED) on (app_name, user_id, session_id, function_call_id) directly in SQL. Pause registry / pause_orphan semantics deferred to google#206. C8 — attributes.adk.{route, render_ui_widgets, rewind_before_invocation_id} mirror EventActions, flat-with-prefix per google#203 (matches the rest of the attributes.adk.* envelope convention). D1 — delete the deprecated on_state_change_callback stub (never called by ADK 2.0; verified no callers). Compatibility ------------- * AGENT_RESPONSE retains the legacy flat extras (source_event_id, source_event_author, source_event_branch) for backward compat. The canonical keys are now under attributes.adk.*. * The HITL test fixtures use Mock events without long_running_tool_ids or .id; the envelope helper is defensive against missing attrs. * No EventData / _log_event signature change. Added one optional field EventData.source_event: Optional[Event] = None — a minimal B0 (google#194) step. Callbacks that have access to the source Event pass it through; others leave it None (and the envelope correctly leaves A3/C1/C2/C3 null on those rows). Tests ----- 257 plugin tests pass (238 existing + 19 new): * envelope shape on event-originating and non-event-originating rows * node parent_path derivation with both empty and nested paths * _derive_scope for None, bare node, path/node, FC IDs, empty string * C4/C5/C6 emit paths * C5 fractional float-epoch precision round-trip * C6 both-shape coverage + id-stabilization regression guard (Event.model_post_init auto-assigns id even when constructor omits it) * C7 TOOL_PAUSED pause_kind derivation for non-HITL and HITL * C7 HITL non-routing: HITL function_response → HITL_*_COMPLETED only, NEVER TOOL_COMPLETED * C7 user-message TOOL_COMPLETED with pause_kind='tool' * C8 flat-with-prefix route / rewind_before_invocation_id * D1: on_state_change_callback removed from the public surface Refs: google#293 (v5), google#190, google#194, google#196, google#197, google#198, google#199, google#200, google#201, google#202, google#203, google#206 (deferred orphan semantics), #207 (deferred workflow nodes).
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft — for review/iteration before mid-June customer cutover.
This PR implements the customer-driven minimum producer subset of the ADK 2.0 observability work tracked in GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK#293 (parent: #190). The customer needs these specific fields visible in BigQuery before their ADK 2.0 production cutover; the full v15 contract lands incrementally.
Producer-only — no consumer-side SDK / typed-view work is needed for the customer to query the new data; they read base-table JSON directly during the mid-June window.
What lands
attributes.adk.{schema_version, app_name}on_event_callbackrows carryattributes.adk.source_event_id— never fabricated on callback-only rowsattributes.adk.node = {path, run_id, parent_path}— default-empty path preserved verbatim, no synthesisattributes.adk.branch(absent stays JSON null)attributes.adk.scope = null | {id, kind}per #198 / #293 v5 derivationAGENT_TRANSFER(from_agent = event.author,to_agent = actions.transfer_to_agent)EVENT_COMPACTION— fractional float-epoch seconds preservedAGENT_STATE_CHECKPOINT(both{agent_state, end_of_agent}shapes), inline payload onlyTOOL_PAUSEDwithpause_kind(HITL-aware via_HITL_PAUSE_KIND_MAP) +function_call_id; user-messageTOOL_COMPLETEDwithpause_kind='tool'for non-HITL; HITLfunction_responsesstay onHITL_*_COMPLETED, never emitTOOL_COMPLETEDattributes.adk.{route, render_ui_widgets, rewind_before_invocation_id}mirroron_state_change_callbackstubExplicitly deferred (post-mid-June, per #293 v5)
WORKFLOW_NODE_STARTING/COMPLETEDevent typesattributes.adk.nodetoday.pause_orphansemantics / read-after-write visibilityTOOL_PAUSED ↔ TOOL_COMPLETEDSQL joins.attributes.adk.otel_span_idsource_event_id↔ ADK's span-sideassociated_event_ids.AGENT_STATE_CHECKPOINTB0 (#194)plumbing for non-on_event_callbackpathsEventData.source_event: Optional[Event] = Noneas a minimal step; full per-callback coverage matrix lands with #194.Compatibility
AGENT_RESPONSEretains the legacy flat extras (source_event_id,source_event_author,source_event_branch) for backward compat alongside the new canonicalattributes.adk.*envelope. Existing consumers continue to work.EventDatasignature gains one optional field (source_event). No breaking change.Tests
257 plugin tests pass (238 existing + 19 new):
node.parent_pathderivation with both empty and nested paths_derive_scopeforNone, bare node, path/node, FC IDs, empty stringEvent.model_post_initauto-assignsideven when the constructor omits it —_create_agent_state_eventis covered)TOOL_PAUSEDpause_kindderivation for non-HITL and HITLfunction_response→HITL_*_COMPLETEDonly, neverTOOL_COMPLETEDTOOL_COMPLETEDwithpause_kind='tool'route/rewind_before_invocation_idon_state_change_callbackremoved from the public surfaceReferences
Test plan
pytest tests/unittests/plugins/test_bigquery_agent_analytics_plugin.py— 257/257 passpyink --config pyproject.toml src/ tests/+isort src/ tests/— clean🤖 Generated with Claude Code