Skip to content

feat(client)!: replace google-generativeai formatter with google-genai - #15085

Merged
RogerHYang merged 25 commits into
mainfrom
claude/github-issue-15040-r2t4zg
Aug 11, 2026
Merged

feat(client)!: replace google-generativeai formatter with google-genai#15085
RogerHYang merged 25 commits into
mainfrom
claude/github-issue-15040-r2t4zg

Conversation

@mikeldking

@mikeldking mikeldking commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Resolves #15040

Summary

Phoenix prompt formatting now supports only the maintained google-genai SDK. This removes the deprecated google-generativeai formatter, whose protobuf constraint conflicts with LangGraph environments requiring protobuf 6 or newer.

Breaking change

  • PromptVersion.format(sdk=\"google_generativeai\") is removed.
  • PromptVersion.from_google_generativeai() is removed.
  • Google prompts now format through google-genai; install google-genai and call PromptVersion.format() (or pass sdk=\"google_genai\").

Changes

  • Delete the legacy formatter, its canary tests, test environment, and development requirement.
  • Route model_provider=\"GOOGLE\" directly to the Google Gen AI formatter.
  • Update API documentation and record the migration in the client changelog.

Testing

  • uvx tox run -e phoenix_client_canary_tests_sdk_google_genai
  • uvx tox run -e phoenix_client -- -ra -x

Adds a new `google_genai` SDK option for prompt formatting that uses the
new `google-genai` package (google.genai.types) instead of the legacy
`google-generativeai` package, which conflicts with modern protobuf
requirements (e.g. langgraph-api requires protobuf>=6 while the legacy
SDK requires protobuf<6).

- Add phoenix.client.helpers.sdk.google_genai.generate_content with
  message, tool, tool-config, and schema conversions targeting
  google.genai.types
- Route PromptVersion.format(sdk="google_genai") to the new formatter
  via a new GoogleGenAIPrompt dataclass
- Keep GOOGLE's default SDK as google_generativeai for backwards
  compatibility, falling back to google_genai when only the new
  package is installed
- Wire tools and tool_config into GenerateContentConfig, and extract
  system messages into config.system_instruction without going through
  role conversion (which rejects the system role)
- Add canary tests, tox env, and CI matrix entry for google_genai

Fixes #15040

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6GyGpRZboFCLUJnjbLND1
@mintlify

mintlify Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
arize-phoenix 🟢 Ready View Preview Aug 5, 2026, 4:01 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Addresses review findings on the new google_genai formatter, using the
server-side converter in playground_clients.py as the reference:

- Emit function_call / function_response parts for tool_call and
  tool_result content instead of dropping them. Previously such messages
  collapsed to Content(parts=[]), which Gemini rejects, so every
  multi-turn tool-calling prompt failed at call time. Tool results are
  matched to their originating call by function name, which is how Google
  identifies them, and never yield an empty Content.
- Send tool parameters via FunctionDeclaration.parameters_json_schema so
  constructs genai_types.Schema cannot express (anyOf, $ref/$defs,
  default) survive verbatim. An Optional[...] property previously became
  an empty untyped Schema. The lossy Schema.to_google direction is now
  unused and removed; from_google is kept for the reverse direction.
- Propagate the thinking_config invocation parameter, guarding
  thinking_level behind google-genai>=1.50.0 where it was introduced.
- Propagate response_format as response_mime_type/response_json_schema,
  matching the OpenAI formatter.
- Support raw tools via Tool.model_validate, omit tool_config when no
  function declarations are present (Google rejects it for built-in tools
  such as google_search), and stop emitting a degenerate
  Tool(function_declarations=[]).
- Correct the _default_google_sdk docstring: the two Google SDKs do not
  conflict with each other; the legacy package's protobuf<6 pin is what
  conflicts with protobuf>=6 consumers.

Tests now cover the to_google direction, which the round-trip tests
could not reach.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6GyGpRZboFCLUJnjbLND1

Copy link
Copy Markdown
Collaborator Author

Pushed b9c441c, which closes six conversion gaps found while reviewing the new formatter. I used the server-side converter in playground_clients.py as the reference for each, since it already handles them correctly.

Two were functional bugs I reproduced before fixing:

  • Tool messages produced Content(parts=[]). tool_call/tool_result parts were skipped, so a message containing only those collapsed to empty parts, which Gemini rejects — every multi-turn tool-calling prompt would have failed at call time. These now become function_call/function_response parts, matched to the originating call by function name (Google identifies responses by name, not call id).
  • Tool parameters lost anyOf/$ref/default. The hand-rolled Schema conversion turned an Optional[str] property into an empty untyped Schema(). Parameters now go through parameters_json_schema, so JSON schema passes through verbatim. The lossy direction is removed; the reverse direction is kept.

Also: thinking_config and response_format are now propagated (the latter matching the OpenAI formatter), raw tools are supported, tool_config is omitted when there are no function declarations (Google rejects it for built-in tools like google_search), and the degenerate empty Tool is gone.

I also corrected the _default_google_sdk docstring. The original rationale was wrong: the two Google SDKs co-install cleanly — it's the legacy package's protobuf<6 pin that conflicts with protobuf>=6 consumers like langgraph-cli[inmem].

One finding I deliberately left alone, since it's your call: _default_google_sdk still prefers the legacy SDK whenever it's importable, so the new path is only auto-selected when the legacy package is absent. That's what fixes the reported issue (the reporter can't install the legacy SDK), and it keeps format()'s return type stable for existing users. But google-generativeai is deprecated and its formatter is strictly worse — it never attaches tools and raises NotImplementedError on system messages — so there's a reasonable argument for flipping the default to google_genai when both are installed. That's a breaking change for anyone relying on the current default, so I didn't do it unilaterally. Happy to flip it if you'd prefer.

Tests now cover the to_google direction, which the round-trip tests structurally couldn't reach: 18 canary tests, plus strict pyright/mypy clean on the helper, tests, and prompts.py.


Generated by Claude Code

@mikeldking mikeldking moved this from 📘 Todo to 🔍. Needs Review in phoenix Aug 5, 2026
@mikeldking

Copy link
Copy Markdown
Collaborator Author

Flagged priority: high@RogerHYang you're the assignee on this one, please take a review pass.

Raised during standup triage on 2026-08-10.

The maintained google-genai integration is now the sole Google formatter,
removing the deprecated SDK and its incompatible protobuf constraint.
@RogerHYang RogerHYang changed the title feat(client): add google_genai SDK support to prompt formatters feat(client)!: replace legacy Google prompt formatter Aug 10, 2026
Release automation owns the client changelog, so the breaking change remains
communicated through the pull request description.
Keep package instructions and prompt examples aligned with the maintained
Google SDK after removing the legacy formatter.
@review-notebook-app

Copy link
Copy Markdown

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

RogerHYang and others added 3 commits August 10, 2026 16:24
Run client and canary formatter checks against the current supported Google
GenAI SDK release.
Test-environment maintenance should not trigger an arize-phoenix release.
…ebook

The Google migration rewrote the import cell and dropped
`to_chat_messages_and_kwargs`, leaving five cells (OpenAI, Anthropic,
HuggingFace, Ollama, Mistral) calling an undefined name, which failed ruff
F821 and the Format and Lint gate.

Rather than restore that import, those cells now use
`prompt_version.format(variables=..., sdk=...)`, matching the migrated
Google cell. The old helper was imported from `phoenix.client.utils`, which
has never exported it, so the cells were broken at runtime regardless.

Also runs ruff format/check and the notebook cleaner over the two notebooks
touched by the migration, so `Format and Lint` and `Clean Jupyter Notebooks`
both pass with no residual diff.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6GyGpRZboFCLUJnjbLND1

Copy link
Copy Markdown
Collaborator Author

Pushed fe04d0d to green up Format and Lint and Clean Jupyter Notebooks, both of which were failing on the docs migration commit (eac2429).

What was broken: the migration rewrote cell 0's imports in examples/prompts/prompts_for_various_SDKs.ipynb and dropped to_chat_messages_and_kwargs, but five cells still called it — OpenAI, Anthropic, HuggingFace, Ollama, Mistral — so ruff failed with five F821s.

How I fixed it: rather than restore that import, those five cells now use prompt_version.format(variables=..., sdk=...), matching your migrated Google cell. Worth flagging why: the old helper was imported from phoenix.client.utils, which has never exported it (utils exposes only config, executors, template_formatters, etc.). So restoring the import would have satisfied ruff while leaving the cells broken at runtime — those five had been dead since before this PR. Happy to swap in a plain import restore instead if you'd rather keep the diff minimal.

I also ran ruff format/check and the notebook cleaner over both notebooks the migration touched. The import ordering (from google import genai) needed sorting in both, and neither notebook had been run through make clean-notebooks, which is what the clean gate checks. Verified the cleaner is now a no-op on both, so git diff --exit-code passes.

Confirmed locally on top of e12fdb1: ruff format --check and ruff check clean repo-wide, the 18 google_genai canary tests pass, and _to_sdk("GOOGLE") now resolves to google_genai with no dangling references to the removed legacy API anywhere in the tree.

Two notes on the earlier red checks, for the record: most of the Python CI Required failures were the aggregate gate reporting One or more CI jobs were cancelled — the test-python-${{ github.head_ref }} concurrency group cancels in-flight runs, so each rapid push superseded the previous run rather than genuinely failing. And the card-link-check failure was an external huggingface.co HTTP 500 in a docs file this PR doesn't touch; it has since gone green on its own.


Generated by Claude Code

Exercise the public PromptVersion path so Google prompts use the maintained
SDK without an explicit formatter selection.
@RogerHYang
RogerHYang marked this pull request as ready for review August 10, 2026 23:33
@RogerHYang
RogerHYang requested review from a team as code owners August 10, 2026 23:33
@dosubot dosubot Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Aug 10, 2026
RogerHYang and others added 9 commits August 10, 2026 16:38
Exercise persisted Google prompts through the same public-client integration suite as other prompt round-trip behavior.
Support creating prompt versions from Google GenAI generate-content parameters and validate the public client round trip.
Reject unsupported content explicitly and extend round-trip coverage so Google prompt imports do not silently lose data.
Raise a stable error for file-based system instructions rather than crashing while converting them.
The new Google GenAI integration coverage placed the phoenix.client imports
after pydantic and typing_extensions, which ruff's isort rules reject in this
directory. Applies `ruff check --fix` so `Format and Lint` passes with no
residual diff.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6GyGpRZboFCLUJnjbLND1
Preserve supported schemas and tool results, while rejecting forms Phoenix cannot represent faithfully.
Fail explicitly for thought and unsupported response-format inputs rather than dropping their semantics.
Use function names as stable Phoenix tool-call keys when the Google SDK omits response IDs.
The id-less function response guard exceeded the 100 character line limit,
failing `Format and Lint`. Rewraps the string without changing the message,
so the `pytest.raises(match="id, name")` assertion still holds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6GyGpRZboFCLUJnjbLND1

Copy link
Copy Markdown
Collaborator Author

@RogerHYang I've pushed two follow-up commits to keep Format and Lint green — 19baf66 (isort in tests/integration/client/test_prompts.py) and 0b5318e (an E501 in the id-less function-response guard, rewrapped so the pytest.raises(match="id, name") assertion still holds).

One request that would save us both a round trip: running make format-python && make lint-python before pushing would catch these locally. That job runs both and then git diff --exit-code, so anything the fixers would change fails the gate. Worth noting E501 in particular isn't auto-fixable — ruff check --fix won't catch it, so it needs the manual wrap.

I reviewed the conversion work in e80bcf0, 8d3d6dd, d13a1d0, f9ad471, and 31fe20e and it looks sound to me. Resolving id-less function responses by name against preceding calls is the right call — Google matches on name, and the paired NotImplementedError for a response with neither an id, a name, nor a matching prior call is better than silently emitting something Gemini would reject. Same for rejecting thought parts rather than dropping them. Verified locally on 0b5318e: 38 canary tests pass, pyright strict clean on both the helper and its tests, and both lint gates clean repo-wide.

Also flagging one stale line in the PR description, since it's now the reviewer-facing record: it says the migration is recorded in the client changelog, but 87e6f90 removed that entry on the grounds that release automation owns it.


Generated by Claude Code

Keep explicit null schema defaults and id-less tool calls stable across round trips while aligning server types and tutorial usage with the current SDK.
@RogerHYang RogerHYang changed the title feat(client)!: replace legacy Google prompt formatter feat(client)!: replace google-generativeai formatter with google-genai Aug 11, 2026
@github-project-automation github-project-automation Bot moved this from 🔍. Needs Review to 👍 Approved in phoenix Aug 11, 2026
claude and others added 5 commits August 11, 2026 00:36
The canary pyright config pins pythonVersion to 3.9, so the `str | None`
annotation added for the id-less function response assertions failed the
`google_genai` canary job with reportGeneralTypeIssues. Uses `Optional[str]`
instead and notes why.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6GyGpRZboFCLUJnjbLND1
Align SDK checks with the supported Python 3.10 floor and satisfy the newer release's stricter unknown-type diagnostics.
The latest release surfaces 51 existing strict-mode diagnostics in the client package; defer that upgrade to a dedicated cleanup.
Preserve empty text parts and reject empty messages instead of silently dropping them during prompt conversion.
@github-actions

Copy link
Copy Markdown
Contributor

Card links check

No broken Card links found. Checked external links in 16.9s

@RogerHYang
RogerHYang merged commit 5cf9829 into main Aug 11, 2026
63 checks passed
@RogerHYang
RogerHYang deleted the claude/github-issue-15040-r2t4zg branch August 11, 2026 01:34
@github-project-automation github-project-automation Bot moved this from 👍 Approved to ✅ Done in phoenix Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: high size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

[BUG]: fix(google-genai): Add support for new SDK to resolve protobuf version conflict with langgraph

3 participants