Skip to content

chore: sync vzgpt-core with upstream ADK 2.9 lifecycle - #4

Merged
lwangverizon merged 229 commits into
vzgpt-corefrom
review/vzgpt-core-adk29-sync
Sep 21, 2026
Merged

lwangverizon merged 229 commits into
vzgpt-corefrom
review/vzgpt-core-adk29-sync

Conversation

@lwangverizon

Copy link
Copy Markdown
Owner

Description

Publish the previously prepared upstream sync (6747f6b) as the prerequisite for a narrowly scoped session-initialization fix. Incorporates upstream d57c84f and retains the local session merge_state extension. This PR contains the already-integrated SDK source baseline, not the subsequent deadlock fix.

Testing Plan

Historical installed-wheel session/skill selection: 610 passed, 16 skipped, 3 xfailed. Local scripted replay verified lifecycle mechanics but did NOT validate concurrent PostgreSQL index migration.

Known blocker

This baseline alone includes unsafe automatic removal of a superseded events index during lazy session setup. A dependent fix PR will remove that DROP INDEX and serialize PostgreSQL check/create operations, with real local PostgreSQL regressions. Do not treat this baseline alone as release-ready.

No merge or deployment is requested by this PR.

GWeale and others added 30 commits September 2, 2026 11:01
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 975222176
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 975228947
Add developer unit guide explaining how to expose ADK workflows
and deterministic nodes as agent tools. Covers implicit wrapping,
input schema definition, isolated sub-branch event scoping, and
human-in-the-loop interruption and resumption.

Also updates the guides index and links the guide in the node_as_tool
workflow sample documentation.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 975237687
… module

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 975257909
…tead of reconnecting or busy-waiting

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 975287942
Merge google#4795

## Summary
- Adds `ignore_args` boolean field to `ToolTrajectoryCriterion` (defaults to `False`)
- When `True`, trajectory evaluation compares only tool names, skipping argument matching
- Works with all three match types: `EXACT`, `IN_ORDER`, `ANY_ORDER`

Closes google#4794

## Usage
```json
{
  "tool_trajectory_avg_score": {
    "threshold": 0.8,
    "match_type": "IN_ORDER",
    "ignore_args": true
  }
}
```

## Test plan
- [x] All 31 existing trajectory evaluator tests pass (no regressions)
- [x] 13 new tests covering `ignore_args=True` across all match types
- [x] Full test suite passes (4995 passed via `scripts/unittests.sh --version 3.12`)

Co-authored-by: Yi Liu <yiliuly@google.com>
COPYBARA_INTEGRATE_REVIEW=google#4795 from abhinavmaddineni:abhinavmaddineni/eval-skip-arg-match 0027e4a
PiperOrigin-RevId: 975330582
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 975350988
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 975379309
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 975385607
`_resume_utils.decide_step_resume` now owns the whole resume decision, so
`_run_one_step_async` keeps only the dispatch and its two duplicate replay
loops collapse into one.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 975413737
Merge google#6474

_AuthLlmRequestProcessor.run_async resumes and executes a tool call found by ID in session history, but did not check that the call was authored by the current agent before doing so.

request_confirmation.py's equivalent resume path already validates this (original_fc_event.author != agent.name). This applies the same check here, consistent with that existing pattern.

PiperOrigin-RevId: 975415423
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 975419807
Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 975487915
…ap edge cases

Unify callable introspection, docstring resolution, signature analysis, and type
hint caching between FunctionTool and FunctionNode into a shared helper module
adk/utils/_callable_utils.py, and place tool argument preprocessing in _schema_utils.py.

Key changes:
- Add `_callable_utils.py` defining `unwrap_callable`, `get_type_hints_cached`,
  and `CallableSpec` strictly focused on callable introspection and signature analysis.
- Place tool argument preprocessing logic (`preprocess_args`) in `_schema_utils.py`.
- Refactor `FunctionTool` to leverage `CallableSpec` for docstring resolution,
  signature analysis, and type hint caching, and `_schema_utils.preprocess_args`
  for model coercion.
- Refactor `FunctionNode` to use `CallableSpec` for docstring, signature, type
  hints, and context parameter detection, and cache `spec.unwrapped_func`.
- Fix `FunctionTool` description fallback to empty string for undocumented callables
  whose wrapper docstrings match default object/routine docstrings.
- Fix unwrapping loops and signature introspection for builtin functions like `min`,
  gracefully handling signature-less callables in `FunctionTool.run_async`.
- Robust type hint unwrapping: unwrapping `functools.partial` in `CallableSpec`
  enables resolving annotations under `from __future__ import annotations`,
  consistently activating Pydantic model coercion in `preprocess_args` where
  `typing.get_type_hints` previously failed with `TypeError`.
- Add comprehensive unit tests in `tests/unittests/utils/test_callable_utils.py`
  and `tests/unittests/utils/test_schema_utils.py`.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 975495673
…he first chunk

Three assumptions in the inference telemetry were wrong for a streaming model.

The inference was treated as over at the first response not marked `partial`,
and streamed chunks were skipped by the same test. `partial` is set by the
aggregator in front of the model, not by the model, so a backend reaching this
code without one leaves it unset on every chunk. Chunk one then looked like the
whole answer: it ended the span, and everything after it was dropped.

`partial` is no longer read here at all. The end of an inference is the
response that says why generation stopped, which the model itself reports, and
that is what ends the span now. Ending there rather than at teardown keeps the
tool the model just asked for out of the inference's duration and out of its
subtree, which is what ending early was always for.

`FINISH_REASON_UNSPECIFIED` was published as a stop reason. It is the proto3
zero value and it is truthy, so a response that had not reported one yet was
recorded as a failed generation: `error` in the completion log, and the
non-standard `finish_reason_unspecified` on the span. Both now treat it as
absent and omit the attribute. This is also what makes the new rule work: a
chunk mid-stream is exactly a response with no reason to report.

The output messages were replaced per response rather than accumulated, so a
turn delivered as several responses was reported as whichever arrived last.
Every response now contributes one message and one choice event, which is how
opentelemetry-instrumentation-google-genai reports a stream as well, so the two
describe a streamed turn the same way.

Co-authored-by: Max Ind <maxind@google.com>
PiperOrigin-RevId: 975821757
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 975823229
Merge google#5720

VertexAiSessionService built its API client with no retry configuration, so a
429 RESOURCE_EXHAUSTED failed on the first response. It now retries 429 once.
A call that keeps getting 429 therefore issues one extra request and takes
about a second longer before it raises.

This does not resolve google#5714, which asks for batched or windowed event replay.
That replay loop is in the vertexai SDK's _init_session, not here, and the
issue notes each retry consumes more of the same per-minute quota, which is
why the retry is bounded to a single attempt.

PiperOrigin-RevId: 975844908
McpTool.run_async requests confirmation and returns the pause error, but leaves
skip_summarization unset. The flow then treats the pause as an ordinary tool
result, re-invokes the model, and the model calls the tool again -- a
confirmation loop that never settles. FunctionTool already sets the flag on its
matching path.

Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 975857178
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 975885218
Close google#5896

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 975892890
Widen the pin to `mcp>=1.24,<3` and make the MCP tooling run on either major.
2.0 renamed three symbols and two model fields; ADK already read those fields
under both spellings, so what remained was the import surface, one timeout
type, and the tests.

The `dependencies` seam resolves the moved names once, at import: `McpError`
became `MCPError`, and `mcp.server.fastmcp.FastMCP` became
`mcp.server.mcpserver.MCPServer`. The other fourteen names ADK uses sit at
the same path in both.

The seam also picks the HTTP client library. 2.x is built against `httpx2`
rather than `httpx`, and the client ADK constructs is passed to the SDK's
transport, so the two must agree. The choice keys off the installed SDK, not
off which library is importable -- a 1.x install can have `httpx2` present for
unrelated reasons.

That pairing costs one thing on 2.x. The OpenTelemetry httpx instrumentor is
built against `httpx`; handed an `httpx2` client it wraps without complaint
and then fails on the first request. MCP HTTP calls go untraced under 2.x
rather than broken, until an `httpx2` instrumentor exists.

`ClientSession(read_timeout_seconds=...)` is the one place the majors accept
disjoint types: `timedelta` in 1.x, `float` in 2.x. The seam publishes which,
and the single existing conversion point reads it.

BREAKING CHANGE: under MCP SDK 2.x, fields a server sends that the SDK does
not declare no longer reach the caller. 2.x closed its models, so an unknown
key on a `CallToolResult`, or on a tool declaration read via `raw_mcp_tool`,
is discarded during validation before ADK sees it. `_meta` is unaffected: it
is a declared field and still arrives. Nothing in ADK can restore the others;
a server that relies on vendor extensions should move them under `_meta`. On
1.x they still arrive as before.

Also under 2.x: the HTTP client types on the public surface become `httpx2`
ones. A caller passing its own `httpx_client_factory` or `mtls_transport`
built on `httpx` hands the SDK's transport a client it cannot use. Those
callers have to follow the SDK. On 1.x nothing changes.

`McpToolset.read_resource` hands back the SDK's own content models rather
than a dump, so their field spellings follow the resolved major: `mimeType`
on 1.x, `mime_type` on 2.x. It is the same unnormalized escape hatch as
`raw_mcp_tool`. ADK's own reader, `load_mcp_resource_tool`, takes both
spellings; a caller reading the models directly has to as well.

And 2.x retyped `Resource.uri` from `AnyUrl` to `str`, so the URI reaches
callers as the server declared it -- `get_resource_info()["uri"]` is
`file://report.json` where 1.x normalized it to `file://report.json/`. A
caller comparing that string, or keying a cache on it, sees a different
value. ADK feeds it straight back to `read_resource`, so its own round trip
is unaffected.

`McpTool` now puts a dumped tool in the MCP Apps widget payload rather than
the model. The payload is a plain dict, so a model left in it was serialized
by whichever sink wrote the event, and those disagree: the sinks passing
`by_alias` published `inputSchema` while the session stores published
`input_schema`. One dump means every sink sees the 1.x spellings. A consumer
reading `payload["tool"]` gets a dict on both majors now; every serialized
form of it already was one.

The result dict is unchanged on both, and on 1.x that is now true by
construction: the normalizing is gated on the major, so a 1.x install makes
exactly the dump call ADK always made. It has to be gated. 1.x models are
`extra="allow"`, so a vendor field a server sent arrives as an extra, and
walking it would rename keys inside data ADK is only passing through -- and
would drop a vendor field that happened to be called `resultType`. 2.x models
are closed, so no extra can reach the dump and every key the walk sees is a
declared field.

On 2.x the dump goes by alias. 2.x renames the wire fields to snake_case --
`isError` and `structuredContent`, and `mimeType` on nested content -- and
both majors alias every one of them to the 1.x camelCase spelling, so one
aliased dump restores the whole tree rather than a key at a time. `meta` is
put back afterwards, at every level: it aliases to `_meta` under both majors,
so it is not a 2.x difference and must not follow, and sixty-odd models
declare it, content blocks included. That walk stops at every entry holding
server data rather than models -- a `_meta` payload, `structuredContent`, and
the two schema fields, where a property may legally be called `_meta`. 2.x's
`resultType` is dropped there too: 1.x has no such field, and acting on
`input_required` is a feature rather than compatibility.

`McpToolset.get_resource_info` returns a dumped `Resource`, which carries
`mimeType`, so it needed the same treatment. All three dump sites share one
gated helper now, so a fourth cannot be written without it.

One more latent bug goes with all of this: `load_mcp_resource_tool` read
`mimeType` unconditionally, and 2.x renamed it. The `except` around that read
turned the `AttributeError` into placeholder text, so every binary resource
looked undecodable. It reads both spellings now.

Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 975915236
…ogue test

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 975935579
Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 975936661
Close google#6530

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 975964724
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 975986183
wyf7107 and others added 29 commits September 17, 2026 16:51
Co-authored-by: Yifan Wang <wanyif@google.com>
PiperOrigin-RevId: 983500048
Every skill a session ever loads stays active for the rest of it, so its
`adk_additional_tools` keep being declared on every later request. Long
sessions accumulate tool declarations nobody is using.

Adds `SkillLifecycleMode` and a `SkillLifecycleConfig`, passed to SkillToolset
as `lifecycle_config`: `enabled`, `default_mode`, `max_active_skills` and
`skill_overrides`. A BOUNDED skill is released once more than
`max_active_skills` of them are active, least recently loaded first; reloading
one counts as a use. PERSISTENT skills, the default, neither count against the
cap nor get evicted, so behavior is unchanged unless a caller opts in.
`load_skill` reports what it released in `unloaded_skills`, so the model is
told its tools are going.

Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 983532420
…lace agent mutation

- Extract BaseAgent._run_with_lifecycle to deduplicate run_async and run_live callback, tracing, cancellation, and error handling boilerplate.
- Consolidate Runner._append_user_event, _append_state_delta_event, and _append_new_message_to_session into _build_and_append_user_event, fixing missing isolation_scope stamping in _append_new_message_to_session.
- Extract _wrap_base_node_as_tool in llm_agent.py to unify BaseNode-to-NodeTool conversion across _convert_tool_union_to_tools and _pre_validate_tools.
- Resolve BuiltInCodeExecutor dynamically for support_cfc runs in _code_execution.py without mutating Runner.agent.code_executor in place.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 983541532
Unloading a skill releases its tools, but the SKILL.md body it was loaded with
stays in the transcript, so the model keeps reading rules for a skill whose
tools are gone.

Every `load_skill` response for a skill that is no longer active is now
replaced, in the outgoing request only, by a short notice that it was unloaded.
The response is rewritten rather than dropped, so the call it answers is not
orphaned, and the session's own events are left as they were.

Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 983544035
…deScheduler

Previously, `Context.run_node` routed through a 4-layer forwarding chain (`Context.run_node` -> `ScheduleDynamicNode` protocol -> `_Workflow._make_schedule_dynamic_node` closure -> `DynamicNodeScheduler` -> `_dynamic_node_executor` -> `NodeRunner`), where `ScheduleDynamicNode` had only a single implementation and `_dynamic_node_executor.py` acted as a pass-through wrapper.

- Remove the single-implementor `ScheduleDynamicNode` protocol (`workflow/_schedule_dynamic_node.py`) and `_Workflow._make_schedule_dynamic_node` closure, typing `Context._workflow_scheduler` directly as `DynamicNodeScheduler | None`.
- Fold `run_node_internal` and `run_node_standalone` from `workflow/_dynamic_node_executor.py` into `workflow/_dynamic_node_scheduler.py` and delete `workflow/_dynamic_node_executor.py`.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 983548450
Previously, `basic.py` and `_schema.py` maintained mirrored boolean checks to decide whether `output_schema` could be passed natively in `LlmRequest.config` or required the `set_model_response` tool workaround. Additionally, structured model outputs were validated and deserialized up to three times across `check_and_handle_output_schema`, `LlmAgent.__maybe_save_output_to_state`, and `Workflow` node execution (`process_llm_agent_output`).

- Extract `can_set_native_output_schema` in `flows/llm_flows/prompt/_schema.py` as the single source of truth for both `basic.py` and `_OutputSchemaRequestProcessor`.
- Preserve the already-validated payload via `_validated_output` on the `Event` across `create_final_model_response_event`, `LlmAgent.__maybe_save_output_to_state`, and `process_llm_agent_output` so `output_schema` validation is not duplicated on the same response event.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 983562218
GCPBatchLogRecordProcessor cleared every record's `event_name`, so that Cloud
Logging would name the log after `gcp.log_name` instead. Agent Engine needs
that: all records have to land in the single
`aiplatform.googleapis.com/reasoning_engine_stdout` log the stdout pipeline
produced. Everywhere else it silently renamed the log.

Off Agent Engine, CloudLoggingExporter derived the log id from the record's
event name, so `gen_ai.client.inference.operation.details` records landed in a
log of that name -- and anything named after the log id followed it, including
a Cloud Logging to BigQuery sink writing a
`gen_ai_client_inference_operation_details` table. Forcing the name to
`adk-otel` left that table empty, and started an `adk_otel` table nothing
queries.

The event name is now cleared only on Agent Engine. `gcp.log_name` is still
stamped everywhere, so records that carry no event name keep the default log
name the old exporter gave them.

Co-authored-by: Max Ind <maxind@google.com>
PiperOrigin-RevId: 983826787
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 983922758
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 983937162
Three docstrings documented an argument name the functions do not take.

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 983942558
…eRunner

- Lazily index earliest event indices by invocation_id in _apply_rewinds to turn multi-rewind resolution from O(N^2) into O(N) while keeping the no-rewind path zero-allocation.
- Skip full _reconstruct_node_states scans in NodeRunner._create_child_context when no prior events exist under ctx.node_path (checked via _NodePathBuilder), and short-circuit user event inspection in _reconstruct_node_states when no interrupts or states are tracked.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 984008538
…True

Consulting check_require_confirmation for every tool also held back any tool
whose hook answers with a truthy non-bool, which is what a mocked tool does, so
tests that drive a mock through the flow stopped running their tool at all. The
tool caller now treats only True as a request for a human, and FunctionTool and
McpTool still apply their own check, so nothing they gate today changes.

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 984022121
Define __deepcopy__ on _AbortState to return self, preventing deepcopy
and model_copy(deep=True) on InvocationContext from traversing the active
asyncio event loop and failing on unpicklable objects like async generators.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 984024337
…on calls

Non-blocking function calls previously depended on the `response_scheduling` field, which prevents live models that do not support
response scheduling from making non-blocking function calls.

The behavior field makes this separation more explicit. It is assumed
that when `response_scheduling` is set, the behavior is non-blocking.

Co-authored-by: Jason Zhang <jasoncz@google.com>
PiperOrigin-RevId: 984024449
The 2.0 migration warning is the first thing a new reader meets in the README,
where it is noise for anyone who never used 1.x. This deletes the callout and
the two horizontal rules that framed it, so the intro paragraph runs straight
into the feature list.

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 984024677
A persisted eval_config.json carrying "num_samples": 0 will now raise ValidationError on load instead of quietly yielding an empty EvaluationResult.

Merge google#6939

PiperOrigin-RevId: 984030495
- Cache Pydantic TypeAdapter instances via functools.lru_cache in _validate_state_entry to avoid reconstructing validators on every state write.
- Implement __iter__ on State to iterate over state keys while preserving truthiness on empty state.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 984032425
…and exclude temp keys from rewind delta

- Extract BaseSessionService._commit_event_to_session so SqliteSessionService, DatabaseSessionService, and FirestoreSessionService do not re-run _apply_temp_state and _trim_temp_delta_state a second time after persisting the event, while unifying in-memory event commits across backends (including VertexAiSessionService).
- Exclude temp:-prefixed state keys when computing rewind state deltas in compute_state_delta_for_rewind.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 984048354
Merge google#7061

Fixes google#7060

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 984061664
A skill loaded for one question stays active for the rest of the session, so
its tools keep being declared long after the model is done with it. Unloading
it is the model's job to remember.

EPHEMERAL gives a skill exactly the turn it was loaded in: active for every
model step of that turn, released from the next one on. Loading it again gives
it another turn. Like PERSISTENT, it does not count against `max_active_skills`
-- it is already bounded, by time.

Which turn a skill was loaded in is kept per agent in
`_adk_skill_meta_<agent>`, written only for ephemeral skills.

Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 984066086
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 984068598
Previously, `basic.py` and `_schema.py` maintained mirrored boolean checks to decide whether `output_schema` could be passed natively in `LlmRequest.config` or required the `set_model_response` tool workaround. Additionally, structured model outputs were validated and deserialized up to three times across `check_and_handle_output_schema`, `LlmAgent.__maybe_save_output_to_state`, and `Workflow` node execution (`process_llm_agent_output`).

- Extract `can_set_native_output_schema` in `flows/llm_flows/prompt/_schema.py` as the single source of truth for both `basic.py` and `_OutputSchemaRequestProcessor`.
- Preserve the already-validated payload via `_validated_output` on the `Event` across `create_final_model_response_event`, `LlmAgent.__maybe_save_output_to_state`, and `process_llm_agent_output` so `output_schema` validation is not duplicated on the same response event.

PiperOrigin-RevId: 984076911
Co-authored-by: Yifan Wang <wanyif@google.com>
PiperOrigin-RevId: 984110412
…olete unit tests

- Remove deprecated Runner._validate_runner_params and unused Runner._is_transferable_across_agent_tree wrapper, and update test_runners.py to call Runner._resolve_app directly.
- Remove unused DynamicNodeState.get_run_counter, ReplayManager.recovered_executions, and _BranchPath.parent along with their legacy unit test assertions.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 984121726
Extract the three hard-coded tool-resolution calls in
`BaseLlmFlow._preprocess_async` (`_resolve_toolsets_and_auth`,
`_attach_agent_tools`, and `_finalize_dynamic_instructions`) into standalone
request processors (`_toolset_auth.request_processor`,
`_agent_tools.request_processor`, and `_dynamic_instructions.request_processor`)
held in `BaseLlmFlow.tool_request_processors`, and unify `_preprocess_async`
into a single loop over `self._iter_request_processors()`.

Keeping `request_processors` and `tool_request_processors` as two lists that run
back-to-back preserves the invariant that subclasses appending custom processors
to `self.request_processors` always run before toolset authentication and tool
resolution populate `llm_request.tools_dict`.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 984130302
Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 984244091
Replace the local `_use_otel_context` helper in `BaseLlmFlow._call_llm_async` with `_with_caller_context(_call_llm_with_tracing(), caller_context)` so `call_llm` shares the same caller-context isolation as `Runner`, `BaseAgent`, and `Workflow`.

Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 984472547
Merge upstream/main at d57c84f. Replace the local skill rolling window and its tests with upstream's lifecycle implementation. Retain the session merge_state API, which is not upstream.

Validation: staged diff whitespace and Python syntax checks passed. Targeted session and skill tests were blocked during collection because the existing environment has google-genai 1.75.0, while upstream requires >=2.19,<3.
@lwangverizon
lwangverizon merged commit 6747f6b into vzgpt-core Sep 21, 2026
1 check failed
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.