_OriginCheckMiddleware returned early for GET/HEAD/OPTIONS, and again whenever a
request carried no Origin, so only writes were validated. Every read endpoint of
`adk web` / `adk api_server` was served to a page that reached the server by
rebinding a hostname to 127.0.0.1.
Origin cannot close that, because browsers omit it on requests they consider
same-origin, as they do a rebound page's. So check Host on every request: a
loopback bind is reachable only from this machine, so a request naming any other
host was pointed here by rebound DNS. Only the real Host header counts, since it
is a forbidden request header whereas a same-origin fetch() can set
X-Forwarded-Host or Forwarded freely. The safe-method exemption is gone, and the
/run_live handshake gets the same check.
Serving another hostname from a loopback bind now means naming it in
--allow_origins, which vouches for that origin's host rather than switching the
guard off; only "*" opts out entirely.
Both checks key off the bind address instead of scope["server"] - ASGI servers
fill that from the accepted socket, so a --host=0.0.0.0 server reports 127.0.0.1
for any loopback connection and looked local-only behind a same-machine proxy.
The bind arrives through a new get_fast_api_app(bind_host=...) that the CLI
passes. The existing host parameter keeps its 127.0.0.1 default and its meaning:
an embedder that binds elsewhere without passing it would otherwise have the
guard keyed to a loopback bind it does not have, and reject all of its own
traffic.
Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 964277197
The candidate was cut yesterday and the release slipped a day, so it no
longer carried everything on main. This takes main's tree wholesale and
keeps the Release-As footer that pins the version to 2.7.0.
_run_async_impl hard-coded the module-global `Agent`, so the class a turn runs
on could only be changed by patching the module. A `_sdk_agent_cls` property
names it instead, resolved per access.
Behaviour is unchanged: the property returns the same global, and the eight
existing tests that patch `_antigravity_agent.Agent` pass untouched. A property
rather than a ClassVar precisely so that stays true -- a ClassVar default binds
at class-creation time and would have broken all eight.
Co-authored-by: Haran Rajkumar <haranrk@google.com>
PiperOrigin-RevId: 964166386
Merge https://github.com/google/adk-python/pull/6231
Scope the skip_summarization text-append to AgentTool. This prevents other tools that set skip_summarization (like UI tools) from having their internal acknowledgements surfaced as visible text.
Fixes#6230
PiperOrigin-RevId: 964110832
Merge https://github.com/google/adk-python/pull/6600
**1\. Link to an existing issue (if applicable):**
- Related: google/adk-docs\#2045 (Addresses technical verification feedback in [https://github.com/google/adk-docs/pull/2045\#issuecomment-5184438669](https://github.com/google/adk-docs/pull/2045#issuecomment-5184438669))
**2\. Or, if no issue exists, describe the change:**
**Problem:**
1. Callable attribute bindings in `CloudEventAttributesBinding` were always evaluated against the event `payload`. This prevented developers from correlating CloudEvents with ADK runtime telemetry (such as session IDs or invocation IDs from `Context`).
2. Setting `time=OMIT` or `datacontenttype=OMIT` in `CloudEventAttributesBinding` skipped adding keyword arguments when calling `publish_message`. Because `publish_message` auto-generates default UTC timestamps and content types when arguments are `None` or omitted, `time=OMIT` generated a timestamp instead of omitting the header.
3. Sample READMEs omitted the required `pip install "google-adk[gcp]"` prerequisite step needed for Eventarc publishing.
**Solution:**
1. Added automatic signature inspection (`0-arg`, `1-arg`, and `2-arg` callables) to `CloudEventAttributesBinding` so callables can receive the event `payload`, the runtime `Context` (`tool_context`), or both, while preserving full backward compatibility with existing payload callbacks.
2. Setting `time=OMIT` or `datacontenttype=OMIT` now explicitly passes empty string (`""`) to `publish_message` so attributes are omitted from published CloudEvents. Explicitly setting required CloudEvent specification headers (`id=OMIT`, `specversion=OMIT`) now raises a `TypeError` at tool build time.
3. Updated sample agents and sample READMEs (`domain_specific_agent` and `generic_agent`) to demonstrate `Context` callables, `time=OMIT`, and GCP extra prerequisites.
### Testing Plan
**Unit Tests:**
- I have added or updated unit tests for my change.
- All unit tests pass locally.
Summary of passed `pytest` results:
```
uv run --all-extras pytest tests/unittests/integrations/eventarc -v
======================== 63 passed, 4 warnings, 13 subtests passed in 3.14s ========================
```
- Added `test_runtime_execution_with_context_and_payload_lambdas` to verify 1-parameter (`payload` or `Context`) and 2-parameter callables.
- Added `test_time_and_datacontenttype_omit_pass_empty_string` to verify omission of `time` and `datacontenttype`.
- Added `test_id_and_specversion_omit_raise_typeerror` to verify static validation against omitting mandatory CloudEvent specification headers.
**Manual End-to-End (E2E) Tests:**
- Verified that sample agent tools in `contributing/samples/integrations/eventarc/domain_specific_agent/agent.py` build and run correctly.
- Confirmed that `complete_outreach_lambda_tool` correctly injects `Context.session_id` into the event source and that `ping_system_tool` emits events without a timestamp header when configured with `time=OMIT`.
### Checklist
- [x] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
- [x] I have performed a self-review of my own code.
- [x] I have commented my code, particularly in hard-to-understand areas.
- [x] I have added tests that prove my fix is effective or that my feature works.
- [x] New and existing unit tests pass locally with my changes.
- [x] I have manually tested my changes end-to-end.
- [x] Any dependent changes have been merged and published in downstream modules.
Additional context
Addresses the technical verification report on google/adk-docs#2045 comment.
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/6600 from milenvk:main 647744f65452358842982b4d88cd1401d4143c42
PiperOrigin-RevId: 964084439
Extend the `execute_tool load_skill` span by adding new skill-related attributes. Adds new experimental attributes, and new namespace for them.
PiperOrigin-RevId: 964033870
PreloadMemoryTool appended recalled memory to system_instruction, but explicit caches fingerprint and store that system prefix, so memory picked for one query could destabilize cache identity or stick to a reusable prefix on later turns. This inserts recalled memory into the trailing user-context batch for the current request instead, which the cache manager already excludes, through one typed internal LlmRequest seam that dynamic user instructions also reuse.
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 963713313
The only breaking marker in this range is a packaging change: pyarrow moved
out of the gcp extra into a new bigquery-analytics extra. Users keep their
>=2,<3 pins, and the artifact check keeps a baseline to compare against.
Release-As: 2.7.0
ComputerUseToolset passed the url the model supplied straight to the
browser driver, without checking it. Now navigate runs the same checks
load_web_page does. A url that fails returns an error to the model
instead of reaching the driver.
If the agent is meant to drive the browser against an internal host,
pass allow_private_network_access=True
Co-authored-by: Jason Zhang <jasoncz@google.com>
PiperOrigin-RevId: 963643277
VertexAiRagMemoryService ran top-k retrieval across the whole configured
corpus and dropped the other tenants' contexts afterwards. The response filter
made the result correct, but ranking still competed against every app and user
in the corpus, so a busy corpus could crowd a caller's own memories out of the
top-k entirely, and foreign context was transferred only to be discarded. This
is a recall and data transfer problem, not a disclosure one: no memory
belonging to another app or user was ever returned to the caller.
search_memory now lists the corpus, keeps the files whose display name names
the requesting app and user, and passes those file ids to VertexRagStore so
ranking happens inside that set. When the caller owns no files, retrieval is
skipped and an empty response is returned. Callers can now see memories that
the previous ranking crowded out, so result counts can go up.
Scoping is best effort and adds no permission requirement, but it does add up
to 10 list calls to each search. Those calls run on the SDK async surface, so
they are awaited rather than blocking the event loop. Scoping is abandoned,
rather than applied to the files listed so far, whenever the listing cannot be
completed: either a listing failure, such as a deployment whose credentials
can retrieve but not list, or a corpus larger than the roughly 1000 files that
page budget covers. Retrieval then runs unscoped exactly as it did before,
which the response filter still makes correct, and the reason is logged.
Applying a partial listing would instead hide the caller's own memories.
Corpora past that size therefore keep the old ranking behavior permanently.
Server-side metadata filtering was considered and rejected: it matches on the
RagFile user_metadata field, which is output only on uploaded files and which
this service has never populated, so it would exclude every memory already
stored.
No public interface changes.
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 963641027
The PR and issue triaging agents each kept their own copy of the component
-> owner map and they had drifted: the PR agent was missing several
components (skills, auth, bq, cli, integrations, workflow), and its
ALLOWED_LABELS gate -- which controls what the agent may apply -- was also
stale, so those labels could be neither applied nor assigned (a skills PR
was labeled "core" and assigned to the wrong owner).
Move the map into component_owners.py as the single source of truth and
import it verbatim as LABEL_TO_OWNER in both agents, so the two are always
identical and cannot drift. Derive the PR agent's ALLOWED_LABELS from
LABEL_TO_OWNER so a newly-owned component is allowed automatically.
Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 963611217
Concurrent session writers can append against a stale revision, and the different session backends surfaced that conflict inconsistently. A stale post-response compaction write could then fail a turn that had already completed. This raises a consistent StaleSessionError (still a ValueError subclass) across the database, SQLite, and Firestore services, and discards only the stale compaction summary while keeping the raw turns.
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 963599677
Some MCP servers declare a string-typed field whose enum lists integer
values. Gemini requires enum members to match the declared string type, so
the tool declaration was rejected and the integration failed. Normalize enum
values to their string form when the effective (non-null) type is string,
leaving numeric enums on numeric types untouched.
Close#3401
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 963579568