90 Commits

Author SHA1 Message Date
chelsealong 775c1bd36e feat: support opt-in session retention in MultimodalToolResultsPlugin
Merge https://github.com/google/adk-python/pull/6698

Adds a `retention` parameter to `MultimodalToolResultsPlugin` to allow
tool-returned parts to persist across turns in a session.

Fixes #6695

PiperOrigin-RevId: 968187977
2026-08-20 18:57:27 -07:00
George Weale fd44a633d6 fix: redact credential values from auto-tracing span attributes
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 964126426
2026-08-13 09:25:27 -07:00
Haiyuan Cao 04b8b72709 feat(plugins): add BigQuery Agent Analytics delivery and termination observability
Add an unconditional per-row event_id assigned before enqueue so Storage Write
API retry duplicates are identifiable, and add an opt-in exactly_once_delivery
mode that uses one loop-local committed stream with explicit offsets, sticky
ambiguous-send state, an offset_conflict drop bucket, and non-blocking stream
rotation. Expose finish_reason and sanitized error_message on final LLM
responses only, so progressive SSE does not double count. Emit NODE_OUTPUT and
NODE_ERROR for final workflow-node results while keeping model finish and block
diagnostics classified as LLM_RESPONSE. Remove the dead module-level
OpenTelemetry tracer allocation.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 962420983
2026-08-10 16:07:31 -07:00
George Weale 5072828f70 feat: record implicit vs explicit context cache type in analytics
Cached token counts alone cannot distinguish Gemini provider-side
implicit prefix caching from ADK-managed explicit CachedContent. Derive a
cache_type (explicit/implicit/none) on the final response and expose it
in the BigQuery analytics view so the two can be reported separately.

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 962267586
2026-08-10 11:27:33 -07:00
Google Team Member 6fd7eaf92a fix(bqaa): skip synchronous log flush to prevent blocking responses
Implements an architectural fix to eliminate the 10-second post-agent latency bottleneck. Skips the synchronous flush() during the run-end callbacks when the decoupling feature flag is enabled. The gRPC response returns instantly, and logs are safely drained by the autonomous background batch processor.

Note on presubmits: The failure in local_integration_test_guitar (test_freeform_chat_discovery_multi_query) is a known baseline flake that passes on retry and is unrelated to this change.

PiperOrigin-RevId: 960491696
2026-08-06 14:07:38 -07:00
George Weale 456524d714 test: add unit tests for public symbols that had no coverage
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 960421043
2026-08-06 11:41:06 -07:00
AakashSuresh2003 98277905ba fix: add 20MB file size validation to SaveFilesAsArtifactsPlugin
Merge https://github.com/google/adk-python/pull/3781

Closes #3751

PiperOrigin-RevId: 957295472
2026-07-31 13:06:04 -07:00
George Weale 83b71e68a9 chore: remove tracker references from comments and docstrings
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 956763571
2026-07-30 15:20:54 -07:00
Lucas Kang a58220cd05 feat: add capability to log commands run in CLI
- Wrap main Click group execution with a custom TelemetryGroup class to track CLI execution metrics.
- Record command name, subcommand, flags, duration, exit code, and exception type when consent is enabled.
- Exclude 'telemetry' command from metrics logging.

Co-authored-by: Lucas Kang <lucaskang@google.com>
PiperOrigin-RevId: 956018260
2026-07-29 12:10:46 -07:00
George Weale 40ec9a85d1 test(plugins): mock the BigQuery plugin collaborators from their real contracts
Five tests passed vacuously. The plugin logs and swallows exceptions from
shutdown() and from on_event_callback, so mocks that violated the real
collaborator contract aborted the code under test instead of failing the test.

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 955359560
2026-07-28 11:06:59 -07:00
Jason Zhang 66a72337b3 fix(plugins): restore failure counter properties on retry tool plugin
Restore private `_scoped_failure_counters` and `_lock` properties
on `ReflectAndRetryToolPlugin` for backward compatibility.

Keep scoped failure counters after creation.

Co-authored-by: Jason Zhang <jasoncz@google.com>
PiperOrigin-RevId: 955323115
2026-07-28 10:07:59 -07:00
Haiyuan Cao 9adf0113ea fix(plugins): complete BigQuery Agent Analytics privacy and shutdown hardening
Harden BigQueryAgentAnalyticsPlugin so it fails closed around formatter and
parser output, redacts sensitive mappings, diagnostic text, signed URIs, and
raw prompt text before inline or GCS storage, validates existing table schema
type and mode recursively at startup, and reports shutdown success only after
all owned work, clients, and executors are drained or closed. Queue accounting
is O(1), JSON nesting is bounded consistently across Python versions, and remote
drains are created and finalized on their owning event loop.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 954858186
2026-07-27 15:22:12 -07:00
George Weale 5a248de58f fix: guard multimodal tool results plugin against empty contents
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 954740117
2026-07-27 11:34:16 -07:00
Jason Zhang 322f45591c feat: Add ReflectAndRetryModelPlugin for self-healing model errors
Introduces the `ReflectAndRetryModelPlugin`, which provides error recovery
for model failures (such as malformed function calls). When a configured model
error occurs, the plugin intercepts it, provides reflection guidance to
the model via a reserved tool call, and retries the operation.

Key features:
- Configurable max retries for model errors.
- Customizable list of FinishReasons to treat as errors.
- Support for both invocation-level and global-level tracking scopes.
- Interception of direct calls to the reserved retry tool to prevent misuse.

Co-authored-by: Jason Zhang <jasoncz@google.com>
PiperOrigin-RevId: 954695655
2026-07-27 10:15:36 -07:00
George Weale 8addc44798 test: wait on the writer instead of guessing at it in the BigQuery plugin tests
27 tests logged an event and then slept for a fixed 50ms before asserting
on what the batch writer had written. The sleep was standing in for a
barrier, so each of these assertions held only while the runner stayed
faster than the guess, and the suite runs on shared runners under
xdist where it sometimes is not.

The plugin already exposes the barrier these tests want: flush() joins
the write queue, and the queue is only marked done after the write
attempt completes. Several tests in this file already used it. Use it
everywhere the sleep was standing in for it.

The sleeps that remain are doing something else: forcing an interleave
between concurrent tasks, simulating setup latency, or hanging a writer
on purpose to exercise a timeout. Those are left alone.

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 953909736
2026-07-25 10:56:23 -07:00
George Weale fabf0fd552 test: stop the cross-loop startup tests from racing on their own mock
Both cross-loop startup tests entered mock.patch.object on the shared
plugin instance from inside each worker thread. patch.object swaps and
restores one attribute on one object and is not thread safe: when two
threads read the original before either installs its mock, both record
that the attribute was absent from the instance, and both delete it on
exit. The second delete raises, so the test failed with

  AttributeError: object has no attribute "_lazy_setup"

which is the mock unwinding itself, not anything about coalescing.

Install the mock once from the test thread and let the worker threads
race only on _ensure_started, which is what these tests are for. The
behaviour under test is unchanged: both loops still call in concurrently
and setup still has to coalesce to a single run.

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 953746627
2026-07-24 23:42:32 -07:00
Haiyuan Cao 07455ee62c feat: add opt-in final_response_tool_names to BigQueryAgentAnalyticsPlugin
Agents that deliver their final answer through a dedicated tool (e.g. a
submit_final_response tool) instead of a plain-text final event do not trigger
the on-event AGENT_RESPONSE path, so the response text is not captured. Add an
opt-in BigQueryLoggerConfig.final_response_tool_names: when a completed tool's
name is in the set, after_tool_callback logs its call args as an AGENT_RESPONSE
event. The default (empty) preserves existing behavior.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 953043855
2026-07-23 17:28:24 -07:00
George Weale 6e43800fcb fix: wait for in-flight BigQuery writes
BatchProcessor.flush() checked Queue.empty(), which only reports whether an item is still waiting, so it could return after a writer dequeued an item but before that write finished. This waits on the queue's unfinished-task count with Queue.join() so flush() blocks until in-flight writes complete.

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 951620765
2026-07-21 11:59:58 -07:00
George Weale 2dc07457b0 test: synchronize BigQuery write assertions
The BigQuery analytics plugin test relied on fixed 10ms sleeps to wait for asynchronous writes, which is not a valid completion signal and produced timing-dependent failures and leaked Queue.get coroutine warnings. This replaces the sleeps with the plugin's flush() synchronization boundary and shuts the loop-owned worker down before closing the event loop.

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 951592599
2026-07-21 11:10:59 -07:00
George Weale 5b89e4e0a7 test: route unit-test threads through the platform thread helper
Spawn the threads in these concurrency tests via
google.adk.platform.thread.create_thread instead of constructing
threading.Thread directly. Behavior is unchanged: create_thread returns a
real OS thread, and the tests still use threading.Event/Barrier for
coordination.

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 951583146
2026-07-21 10:55:46 -07:00
Haiyuan Cao 2919bf5b8d fix(plugins): harden BigQuery agent analytics against fail-open privacy, GCS concurrency, and startup-loss gaps
Close several correctness and privacy gaps in the BigQuery agent analytics
plugin:

- content_formatter failures fail closed with a [FORMATTER_FAILED] sentinel
  instead of falling back to the unformatted payload; the exception is logged
  without the payload and counted as formatter_failed in get_drop_stats().
- A final sanitizer pass runs over the fully assembled attributes tree before
  json.dumps, covering state deltas, custom tags, labels, nested structures,
  and temp:-scoped keys. A new _sanitize_json_blob redacts sensitive keys
  inside JSON-encoded string blobs (e.g. cached credential JSON): it decodes
  container-shaped strings first, enforces max_content_length before
  json.loads, and fails closed to [UNPARSEABLE_JSON_BLOB] for anything it
  cannot parse and verify.
- GCS offload paths are call-local: parse() and _parse_content_object() take
  trace_id/span_id as keyword arguments and build every object path from
  those values, so concurrent two-part offloads never collide on an object
  name.
- Table readiness becomes a startup requirement with bounded retry:
  _ensure_schema_exists raises on failure, and _ensure_started records it,
  keeps _started False, and retries on a later event after exponential
  backoff (2s to 60s cap). Setup is coalesced across event loops and threads,
  so a persistent outage costs one setup RPC per backoff window. Rows
  arriving while setup is unavailable are counted as setup_unavailable.

Also: enabled=False is a hard no-op with zero side effects, runtime settings
are validated at construction, and plugin-level drop counters survive
shutdown.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 949235728
2026-07-16 17:03:14 -07:00
Haiyuan Cao 7d0ae63ab1 feat(plugins): add on_agent_error_callback and on_run_error_callback
Adds two notification-only plugin lifecycle callbacks that close the
error-coverage gap at the agent and runner levels (the model and tool layers
already have error callbacks), giving analytics plugins such as
BigQueryAgentAnalyticsPlugin complete observability of failure paths so
INVOCATION_STARTING / AGENT_STARTING events always get a terminal error event.
Implements RFC #5044; fixes #4863. Fully backward compatible: the new
BasePlugin methods default to no-ops.

Framework:
- BasePlugin: on_agent_error_callback / on_run_error_callback (no-op).
- PluginManager: run_on_agent_error_callback / run_on_run_error_callback plus
  _run_notification_callbacks (best-effort: always notifies every plugin,
  ignores return values, logs plugin failures, never masks the original
  exception).
- base_agent: wrap the full agent lifecycle (before/impl/after callbacks) for
  both run_async and run_live and dispatch on_agent_error_callback.
- runners: dispatch on_run_error_callback at every run-level site --
  _exec_with_plugin (legacy/live agent), _run_node_async (LlmAgent chat +
  workflows) and _run_node_live (live workflows). after_run and compaction
  failures on the success path also notify on_run_error. after_* stay
  success-only; catches Exception (not BaseException) so cancellation and
  early-stop are excluded.

BigQueryAgentAnalyticsPlugin:
- Emit AGENT_ERROR / INVOCATION_ERROR events with error_message and a
  (truncatable) error_traceback; failure-path cleanup runs even if logging
  fails; v_agent_error / v_invocation_error views expose error_traceback.
- kind-guarded span ownership so a failure in another plugin's
  before_agent_callback cannot make BQAA consume the invocation span and
  corrupt INVOCATION_ERROR span/latency data.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 945361746
2026-07-09 15:59:13 -07:00
Haiyuan Cao ecef5f859f feat(bigquery): log tool descriptions and parameter schemas in LLM_REQUEST
The BigQueryAgentAnalyticsPlugin previously recorded only tool names in the
attributes.tools field of LLM_REQUEST events. Downstream consumers such as
online evaluation need the tool description and parameter schema to judge
whether the model selected and invoked the correct tool.

Emit one structured entry per tool ({name, description?, parameters?}) instead
of a bare name. name is always present; description comes from the tool
(falling back to the FunctionDeclaration description). The parameter schema is
taken from the tool's FunctionDeclaration, preferring parameters_json_schema
(a raw JSON-schema dict) when present -- several tools (MCP, OpenAPI, skill,
node, environment tools) populate only that field and the model adapters prefer
it -- and otherwise falling back to parameters.model_dump(exclude_none=True,
mode="json"). Extraction is best-effort and per-tool, so a tool without a
declaration still contributes name/description and one failing tool never drops
the whole tools attribute. The result is routed through the plugin's existing
truncation + sensitive-key redaction pipeline.

This changes attributes.tools from a JSON array of strings to a JSON array of
objects. No BigQuery table schema migration is required because attributes is a
JSON column and the analytics view reads it with
JSON_QUERY(attributes, '$.tools').

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 943995097
2026-07-07 11:13:11 -07:00
Haiyuan Cao c14258dffc feat(bigquery): expose thinking and tool-use token columns in analytics views
Add usage_thinking_tokens and usage_tool_use_tokens to the LLM_RESPONSE
analytics view, sourced from the usage_metadata proto the plugin already logs
to attributes.usage_metadata (thoughts_token_count and
tool_use_prompt_token_count).

Per the genai GenerateContentResponseUsageMetadata contract, total_token_count =
prompt_token_count + candidates_token_count + tool_use_prompt_token_count +
thoughts_token_count, so thinking and tool-use tokens are separate addends
rather than subsets of prompt/candidates. Surfacing them lets analytics account
for them without double counting. Both fields are optional and resolve to NULL
for models/responses that do not report them, so the change stays
model-agnostic. No plugin logging change is needed since the full usage_metadata
is already persisted to attributes.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 943493796
2026-07-06 14:21:30 -07:00
Haiyuan Cao 38d715cbae feat(plugins): add otel correlation, custom_metadata allowlist, and column projection to BigQuery analytics
Add three additive, off-by-default observability controls to
BigQueryAgentAnalyticsPlugin:

- Span-level Cloud Trace correlation: opt in via `enable_otel_correlation`
  (default off) to capture the ambient OpenTelemetry span context into
  attributes.otel.{span_id,trace_id} when valid (a best-effort join key). The
  typed span_id/parent_span_id columns remain the plugin's internal execution
  tree; their schema descriptions are corrected to say so and to point
  consumers at attributes.otel.span_id for span-level joins. No plugin-owned
  span is created.
- custom_metadata_allowlist: capture allowlisted event.custom_metadata keys
  (exact keys, or explicit "prefix:*" patterns) into
  attributes.custom_metadata.* through the existing truncation + sensitive-key
  redaction pipeline. Truncation sets is_truncated; redaction does not.
- payload_column_denylist: project payload columns (content, content_parts,
  attributes, latency_ms) out of the table at write time. Applied schema-first
  so the table schema, Arrow schema, row dict, and views stay consistent;
  identity/correlation columns are protected and raise ValueError. Denying
  content_parts disables GCS offload, and denying attributes alongside a
  non-empty custom_metadata_allowlist is rejected.

Default behavior is unchanged when none of the three configs are set.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 940629822
2026-06-30 13:32:02 -07:00
George Weale 3c7d65a59e chore: drop GitHub issue links from test docstrings
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 938669352
2026-06-26 10:50:23 -07:00
Haegyun Lee d00ad67e40 fix: N sized sliding window
This fix allows for more efficient interaction with Context Caching, as Context Windows are removed when they exceed N, rather than immediately when they exceed the desired number.

Adapted to the new baseline (using invocation_start_indices instead of num_model_turns).

Merges https://github.com/google/adk-python/pull/3271

Co-authored-by: Shangjie Chen <deanchen@google.com>
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/3271 from UlookEE:n_sized_sliding_window 25429aa7298c6cdbc93b1ef267475fe358257646
PiperOrigin-RevId: 936165882
2026-06-22 11:38:46 -07:00
Wei Sun (Jack) f9dd9ae747 style: apply pre-commit formatting to GCP auth provider files
Co-authored-by: Wei Sun (Jack) <weisun@google.com>
PiperOrigin-RevId: 931321657
2026-06-12 14:04:46 -07:00
Haiyuan Cao bc08f46a8c fix(plugins): write BigQuery analytics rows when invocation agent is None
Workflow-driven invocations with deterministic nodes leave
InvocationContext.agent as None, so reading ReadonlyContext.agent_name raised
AttributeError and BigQueryAgentAnalyticsPlugin silently dropped the event row.
Resolve the agent column defensively (running agent name, else the source
Event.author, else null) so rows are written regardless of agent being None.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 930097637
2026-06-10 15:03:25 -07:00
Haiyuan Cao e2676fcbe6 feat(plugins): ADK 2.0 minimum producer cut for the BigQuery Agent Analytics plugin
Customer-driven minimum producer subset of the ADK 2.0 observability work: the
smallest set of event types and `attributes.adk.*` envelope fields a customer
needs in BigQuery to take ADK 2.0 to production. Producer-only and strictly
additive — no BigQuery row-schema column changes; consumers read base-table JSON.

What lands:

1. `attributes.adk.*` envelope on every ADK-enriched row.
   - A1/A2: `schema_version` and `app_name` always.
   - A3/C1/C2/C3: `source_event_id`, `node = {path, run_id, parent_run_id}`,
     `branch`, `scope = null | {id, kind}` only on rows with an originating
     Event. Callback-only rows omit these keys (never fabricated); an omitted
     key resolves to SQL NULL via `JSON_VALUE(attributes, '$.adk.<field>')`.
   - `node.run_id` / `node.parent_run_id` mirror ADK's `NodeInfo` `@property`
     values (parsed from `node_info.path`), read explicitly rather than via
     `model_dump`.

2. Four new event types from previously-unlogged `EventActions`/`Event`
   surfaces:
   - `AGENT_TRANSFER` (`from_agent = event.author`,
     `to_agent = actions.transfer_to_agent`).
   - `EVENT_COMPACTION` (fractional float-epoch seconds preserved).
   - `AGENT_STATE_CHECKPOINT` (both `{agent_state, end_of_agent}` shapes,
     inline payload only).
   - `TOOL_PAUSED` per `long_running_tool_id`, with HITL-aware `pause_kind`
     (via `_HITL_PAUSE_KIND_MAP`, derived from the function-call NAME) and a
     `function_call_id` pair key; plus an unmatched-id fallback row.

3. Pair-key resume path: a non-HITL `function_response` arriving in a user
   message emits `TOOL_COMPLETED` with `attributes.adk.{pause_kind='tool',
   function_call_id}` so the `TOOL_PAUSED` ↔ `TOOL_COMPLETED` join works in
   plain SQL.

4. HITL routing preserved: HITL `function_response`s continue routing to
   `HITL_*_COMPLETED` only, never `TOOL_COMPLETED`.

5. Action-attribute mirror: `attributes.adk.{route, render_ui_widgets,
   rewind_before_invocation_id}` (flat-with-prefix).

6. Cleanup: delete the deprecated, never-invoked `on_state_change_callback`
   stub.

`_EVENT_VIEW_DEFS` is extended for the four new types (and `TOOL_COMPLETED`
gains the pair keys), so the plugin's per-event-type views expose the new
fields. `AGENT_RESPONSE` retains its legacy flat `source_event_*` extras for
backward compatibility alongside the canonical `attributes.adk.*` envelope.

Deferred (tracked separately): dedicated `WORKFLOW_NODE_STARTING/COMPLETED`
events, pause-registry `pause_orphan` semantics, oversized-state GCS offload,
OTel `otel_span_id`, and consumer typed views.

Ported from caohy1988/adk-python#6, validated against current ADK HEAD; uses
ADK's `NodeInfo.parent_run_id` for the node envelope's third key.

All paths covered by unit tests.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 929590673
2026-06-09 21:45:39 -07:00
Wei Sun (Jack) fd0a11d8c0 build: exclude BUILD files globally
Co-authored-by: Wei Sun (Jack) <weisun@google.com>
PiperOrigin-RevId: 928854636
2026-06-08 17:20:34 -07:00
George Weale cb48d015d8 fix: restore GitHub-only changes dropped during v2 bring-over
Re-aligns two files with GitHub main so the piper-to-github cutover does not
silently revert them: the _ALLOWED_PICKLE_GLOBALS type annotation and a stray
f-string prefix in skill_toolset.

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 928768999
2026-06-08 16:49:54 -07:00
Haiyuan Cao a5fa3da021 feat: BigQuery Agent Analytics reliability fixes
Three related reliability/observability fixes to the BigQuery Agent
Analytics plugin.

1. Dropped-event observability. BigQuery logging is best-effort: events
   are dropped when the in-memory queue overflows or a write ultimately
   fails, and only a log line records the loss. Track dropped rows in
   BatchProcessor by reason (queue_full, arrow_prep_failed,
   retry_exhausted, non_retryable, unexpected_error), include the
   running total in each drop log line, and expose the counts via
   BatchProcessor.get_drop_stats()/dropped_event_count and an
   aggregating BigQueryAgentAnalyticsPlugin.get_drop_stats() so a host
   can poll them and export to its own monitoring.

2. Cross-region Storage Write API routing. The AppendRows streaming RPC
   does not auto-populate the request-routing header, so writes to a
   dataset outside the US multiregion could fail with a "session not
   found" / stream-not-found error and silently drop every row. Set
   x-goog-request-params: write_stream=<stream> on the append_rows call
   so the request reaches the region that owns the write stream.
   US-multiregion behavior is unchanged.

3. Stop exporting plugin-owned OTel spans. When Agent Engine telemetry
   is enabled (GOOGLE_CLOUD_AGENT_ENGINE_ENABLE_TELEMETRY=true) with
   Cloud Trace export on the global tracer provider, the plugin's
   ID-carrier spans were exported alongside the framework's real spans,
   producing a duplicate span for every instrumented operation. The
   plugin now tracks span_id / trace_id on its own contextvar stack
   without creating OTel spans; trace_id is inherited from the ambient
   span, so BigQuery rows still join to Cloud Trace by trace_id and the
   LLM/tool span_id-sharing contracts are preserved.

All paths covered by unit tests.

Change-Id: Ia7b73d816b14c574ef856a4c88c57243f6f38f7f
2026-06-03 14:19:05 -07:00
shukladivyansh bc3a4fab80 feat: add AutoTracingPlugin for OpenTelemetry auto-instrumentation
Monkey-patches in-scope Python functions to emit an OpenTelemetry span
per call, capturing args/return/exception as span attributes. Scope is
auto-discovered from the agent tree. No-op when the tracer is not
recording.

Change-Id: I103678b2189a75dcd74af51deb75eb4346c20551
2026-06-01 09:40:00 -07:00
thacht 2a68c4e746 fix(tools): don't close parent's plugins from AgentTool's sub-Runner
AgentTool.run_async spins up a sub-Runner per call that, with the
default include_plugins=True, shares the parent runner's plugin
instances. On exit the sub-Runner's close() tore down those shared
plugins, so long-lived plugins (e.g. observability exporters) hit the
5s plugin_close_timeout and surfaced as
"RuntimeError: Failed to close plugins: 'X': TimeoutError" on the
parent's tool call.

Add PluginManager.set_skip_closing_plugins(value); when set to True,
close() is a no-op. AgentTool calls it on the sub-Runner's
plugin_manager after construction (only when include_plugins=True) so
inherited plugins are no longer closed by the sub-Runner.

Change-Id: I94f81a33e7f6acef728855eaa9237a93a17b66ec
2026-05-28 18:10:50 +00:00
Sasha Sobran 162279358c chore: switch main to v2.0.0 GA (transition to v2)
Co-authored-by: Bo Yang <ybo@google.com>
Co-authored-by: Wei Sun (Jack) <weisun@google.com>
Co-authored-by: George Weale <gweale@google.com>
Co-authored-by: Swapnil Agarwal <swapnilag@google.com>
Co-authored-by: Xuan Yang <xygoogle@google.com>
Co-authored-by: Shangjie Chen <deanchen@google.com>
Co-authored-by: Yifan Wang <wanyif@google.com>
Co-authored-by: Kathy Wu <wukathy@google.com>
2026-05-19 02:01:33 +00:00
Wei Sun (Jack) 3117e09136 chore: further fix header-check via 2025 --> 2026
Co-authored-by: Wei Sun (Jack) <weisun@google.com>
PiperOrigin-RevId: 911737937
2026-05-06 22:16:55 -07:00
Haiyuan Cao 9d1bb4b487 fix: fix fork detection, correct offload limits, and add response logging in BigQuery plugin
This PR addresses three distinct issues in the BigQuery Agent Analytics Plugin:

1. Fix false-positive fork detection:
When the plugin is deployed via Vertex AI Agent Engine, it undergoes a pickle/unpickle lifecycle which resets `_init_pid` to 0. Previously, `_ensure_started()` would incorrectly detect this as a fork since `os.getpid()` is never 0, causing unnecessary cold-start latency and log noise. The PID check now distinguishes `_init_pid == 0` (unpickled) from a real fork.

2. Correct GCS offload unit mismatch:
Separates the evaluation limits for offloading text content to GCS. It evaluates the byte-based storage guard (`inline_text_limit`) and the character-based truncation limit (`max_length`) independently, preventing mismatched unit comparisons.

3. Add AGENT_RESPONSE logging:
Logs final response events emitted by agents to BigQuery. This explicitly filters out intermediate steps such as function calls/responses, streaming partials, and invisible internal reasoning ("thoughts") so that only the final visible response text is captured.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 910770002
2026-05-05 10:28:30 -07:00
Google Team Member ed8b31ce5f chore: migrate from gemini-1.* and gemini-2.0* to gemini-2.5-*
`gemini-1.*` and `gemini-2.0*` models are respectively deprecated and scheduled for shutdown on June 1, 2026. `gemini-2.5*` models are their successors.
No regressions in unit tests:
```
========================================================================================== 5583 passed, 2237 warnings in 84.91s (0:01:24) ===========================================================================================
```

PiperOrigin-RevId: 907663315
2026-04-29 10:34:22 -07:00
Xuan Yang 1deab6d0bf fix: Fix exception handling and argument order in ReflectRetryToolPlugin
Co-authored-by: Xuan Yang <xygoogle@google.com>
PiperOrigin-RevId: 906753501
2026-04-27 23:14:28 -07:00
Google Team Member 02deeb98a0 feat(analytics): add support for logging LLM cache metadata to BigQuery
PiperOrigin-RevId: 905280434
2026-04-24 16:47:22 -07:00
Haiyuan Cao c263426fe1 fix: fix dataset location handling in BigQueryAgentAnalyticsPlugin
Remove `location=self.location` from the `bigquery.Client()` constructor. When the client has no default location and `client.query(sql)` is called without an explicit `location` parameter, the BQ API infers the job location from the dataset referenced in the DDL statement.

Traced through the BQ Python client:
1. `client.query(sql)` — `location` param defaults to `None`, falls back to `self.location` which is also `None`
2. `_to_query_request()` — when `location is None`, the `"location"` key is **not included** in the API request
3. BQ API — infers location from the dataset referenced in `CREATE OR REPLACE VIEW`

**One line of production code changed.** Everything else is test updates.

| Operation | Before | After |
|---|---|---|
| Table CRUD | Works | Same |
| Storage Write API | Works | Same |
| View creation (non-US dataset) | **Silent failure** | **Works** — BQ infers location |

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 905242480
2026-04-24 15:14:56 -07:00
Haiyuan Cao a69f8612fa fix: fix lifecycle issues with credentials in BigQuery Agent Analytics Plugin
### Changes

**1. Pickle safety — try-preserve, fallback-drop**

`__getstate__` tests whether `_user_credentials` is picklable:
- **Picklable** (service-account, `AnonymousCredentials`): preserved — survives pickle and restored via `__setstate__` so the plugin uses the user's identity after unpickle.
- **Non-picklable** (`compute_engine.Credentials` with `requests.Session`): dropped gracefully — falls back to ADC after unpickle.

`_credentials` (the active/resolved credentials) is always cleared since it may hold resolved ADC state. On unpickle, `__setstate__` restores it from `_user_credentials` when available.

**2. Fork safety — documented user-provided credential limitation**

`_reset_runtime_state()` sets `_credentials = _user_credentials`. For ADC-resolved credentials (`_user_credentials is None`), this clears stale credentials for re-resolution. For user-provided credentials, the original object is kept — we cannot re-create it. The comment documents this: the user is responsible for providing fork-safe credentials.

**3. GCS client — credentials passed correctly**

`GCSOffloader.__init__` always creates a `storage.Client` eagerly (`storage_client or storage.Client(...)` at line 1329). This was also true before the credentials commit. The fix passes explicit credentials when available and lets ADC resolve when not, matching the `bigquery.Client` and `BigQueryWriteAsyncClient` patterns.

**4. Benign race on `_credentials` resolution documented**

When multiple event loops call `_create_loop_state()` concurrently, both can resolve ADC redundantly. This is idempotent and benign, now documented.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 905111076
2026-04-24 10:42:23 -07:00
Google Team Member 34713fb4cc feat: add credentials parameter to BigQueryAgentAnalyticsPlugin
PiperOrigin-RevId: 903949028
2026-04-22 11:24:19 -07:00
Mimi Sun 987c809bfc feat: Add an option to prevent the SaveFilesAsArtifactsPlugin from attaching reference file parts to the message
Default is True to match existing behavior. Setting it to False prevents the model from loading artifact directly from a provided canonical URI, and makes the behavior consistent between InMemoryArtifactService and other services with canonical URIs.

PiperOrigin-RevId: 901061080
2026-04-16 21:38:52 -07:00
Haiyuan Cao 9ca8c38432 fix: Resolve BigQuery plugin issues with A2A transfers, spans, and metadata
Fixes #5073, #5310, and #5311 with three targeted updates to the `BigQueryAgentAnalyticsPlugin` (no changes to ADK core):
- Classifies `TransferToAgentTool` transfers to `RemoteA2aAgent` as `TRANSFER_A2A` instead of the generic `TRANSFER_AGENT` by resolving the target agent at the call level.
- Ensures a self-consistent BigQuery span tree by preferring the plugin's internal span stack over ambient OTel spans, resolving dangling `parent_span_id` references.
- Surfaces remote A2A interaction metadata (`a2a:request`, `a2a:response`, etc.) in BigQuery by detecting them in custom metadata and logging new `A2A_INTERACTION` events.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 900224778
2026-04-15 10:10:54 -07:00
Google Team Member 20748894cd feat: Support loading agents from Visual Builder with BigQuery-powered logging
PiperOrigin-RevId: 896612027
2026-04-08 11:33:55 -07:00
Haiyuan Cao 37973daff4 feat: Add configurable view_prefix to BigQueryLoggerConfig
Adds a configurable `view_prefix` field to `BigQueryLoggerConfig` (default `"v"`) so that multiple plugin instances sharing a dataset can use distinct prefixes to avoid overwriting each other's auto-created analytics views
- Validates that `view_prefix` is non-empty at init time
- Wires `view_prefix` into `_create_analytics_views` in place of the hardcoded `"v_"` prefix

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 894331973
2026-04-03 17:58:57 -07:00
Haiyuan Cao a27ce4771f fix(adk): redact credentials in BigQuery analytics plugin
Fixes an issue where the Agent Analytics plugin could log plain-text
OAuth credentials and access tokens to BigQuery. Sensitive keys are
now redacted.

Co-authored-by: Haiyuan Cao <haiyuan@google.com>
PiperOrigin-RevId: 891963630
2026-03-31 13:56:02 -07:00
Kevin Hsieh d6f31be554 fix: In SaveFilesAsArtifactsPlugin, write the artifact delta to state then event actions so that the plugin works with ADK Web UI's artifacts panel
PiperOrigin-RevId: 881064565
2026-03-09 15:24:44 -07:00