Skip to content

feat(py/plugins/google-genai): Deep Research, Antigravity, and Lyria interaction models - #5856

Open
cabljac wants to merge 1 commit into
jh-interactions-2-transportfrom
jh-interactions-3-models
Open

feat(py/plugins/google-genai): Deep Research, Antigravity, and Lyria interaction models#5856
cabljac wants to merge 1 commit into
jh-interactions-2-transportfrom
jh-interactions-3-models

Conversation

@cabljac

@cabljac cabljac commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Third slice of the #5806 split: Deep Research background model with cancel support, Antigravity and Lyria foreground models on the Interactions transport, and a registry of known models with capability metadata. Rewrites lyria.py from the legacy Vertex-only LyriaModel. Model-level tests included here; plugin wiring and its integration tests land in the next slice.

Part of the stack splitting #5806; recombined it reproduces that PR byte-for-byte. Co-authored with @huangjeff5.

Breaking changes

  • LyriaModel is removed from genkit_google_genai.models.lyria; Lyria is now served by the Interactions-backed implementation (create_lyria_action). The package-level exports LyriaConfig and LyriaVersion are unchanged.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for Google AI Interactions models, including the new Antigravity and Deep Research models, and refactors the existing Lyria model to use the Interactions API. It also centralizes model metadata in a new registry and adds comprehensive unit tests. The review feedback highlights a few important issues: ensuring that Pydantic models are dumped using aliases (by_alias=True) so that camelCase keys are preserved for the API, avoiding redundant dictionary wrapping, and copying the mutable module-level DEFAULT_ENVIRONMENT dictionary to prevent unintended side effects from shared state mutation.

Comment on lines +149 to +152
if config.file_search is not None:
tools.append({'type': 'file_search', **config.file_search.model_dump(exclude_none=True)})
for mcp_server in config.mcp_servers or []:
tools.append({'type': 'mcp_server', **mcp_server.model_dump(exclude_none=True)})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The FileSearchConfig and McpServerConfig models define an alias_generator to produce camelCase keys (e.g., fileSearchStoreNames, allowedTools) for the wire format. However, calling model_dump(exclude_none=True) without by_alias=True serializes these configurations with snake_case keys (e.g., file_search_store_names, allowed_tools). This will cause the Google AI Interactions API to reject or ignore these settings. Passing by_alias=True ensures they are correctly serialized to camelCase.

Suggested change
if config.file_search is not None:
tools.append({'type': 'file_search', **config.file_search.model_dump(exclude_none=True)})
for mcp_server in config.mcp_servers or []:
tools.append({'type': 'mcp_server', **mcp_server.model_dump(exclude_none=True)})
if config.file_search is not None:
tools.append({'type': 'file_search', **config.file_search.model_dump(by_alias=True, exclude_none=True)})
for mcp_server in config.mcp_servers or []:
tools.append({'type': 'mcp_server', **mcp_server.model_dump(by_alias=True, exclude_none=True)})

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suggestion would break these requests rather than fix them. This body goes over a raw HTTP client verbatim, and the whole create payload is snake_case (agent_config, previous_interaction_id, user_input, mime_type in the content blocks), so camelCasing only these two nested blocks would produce a mixed-casing body. The SDK's own FileSearchDict/McpServerDict types also take snake_case keys. The alias_generator on these models handles the input direction (camelCased request config), not serialization.

Comment on lines +140 to +141
if request.tools:
tools.extend(dict(to_interaction_tool(tool_def)) for tool_def in request.tools)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

to_interaction_tool(tool_def) returns a FunctionParam which is a TypedDict (inheriting from dict at runtime). Wrapping it in dict(...) is redundant and creates an unnecessary shallow copy of the dictionary. You can safely pass the returned dictionary directly to tools.extend.

Suggested change
if request.tools:
tools.extend(dict(to_interaction_tool(tool_def)) for tool_def in request.tools)
if request.tools:
tools.extend(to_interaction_tool(tool_def) for tool_def in request.tools)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct that the copy is a no-op (to_interaction_tool builds a fresh dict per call). No functional difference; will drop it in the next tidy commit on this slice.

Comment on lines +118 to +119
# Default missing environment to remote; the API rejects unsupported values.
create_kwargs.setdefault('environment', DEFAULT_ENVIRONMENT)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

DEFAULT_ENVIRONMENT is a mutable module-level dictionary. Using it directly in setdefault means that if any downstream code or library mutates the environment dictionary inside create_kwargs, it will inadvertently mutate the shared DEFAULT_ENVIRONMENT constant, affecting all subsequent requests. It is safer to use .copy() to avoid shared mutable state.

Suggested change
# Default missing environment to remote; the API rejects unsupported values.
create_kwargs.setdefault('environment', DEFAULT_ENVIRONMENT)
# Default missing environment to remote; the API rejects unsupported values.
create_kwargs.setdefault('environment', DEFAULT_ENVIRONMENT.copy())

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing mutates the environment dict downstream today (the body goes straight to JSON serialization), but the shared-reference risk is real and the fix is cheap. Will take this.

…interaction models

Model layer extracted from #5806: Deep Research background model with
cancel support, Antigravity and Lyria foreground models backed by the
Interactions transport, and a shared registry of known models with
capability metadata. Rewrites lyria.py from the legacy Vertex-only
LyriaModel to the Interactions-backed implementation.

Plugin wiring into GoogleAI init/resolve/list_actions lands in the next
slice of the stack, together with its integration tests.

Co-authored-by: Jeff Huang <huangjeff@google.com>
@cabljac
cabljac force-pushed the jh-interactions-3-models branch from 65d52d6 to a4b2a47 Compare July 30, 2026 12:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant