Skip to content

fix(agent): route cua/ prefix Gemini models through correct agent loop - #1117

Merged
ddupont808 merged 1 commit into
trycua:mainfrom
sarinali:fix/gemini-cua-routing
Feb 26, 2026
Merged

fix(agent): route cua/ prefix Gemini models through correct agent loop#1117
ddupont808 merged 1 commit into
trycua:mainfrom
sarinali:fix/gemini-cua-routing

Conversation

@sarinali

@sarinali sarinali commented Feb 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fix model routing for cua/ prefix models: cua/google/gemini-3-flash-preview was falling through to GenericVlmConfig instead of GeminiComputerUseConfig because find_agent_config() didn't strip the routing prefix before regex matching. All Gemini-specific features (function declarations, ComputerUse tool, thinking traces) were silently unused.
  • Add CUA inference proxy support to Gemini loop: New _create_gemini_client() helper detects the cua/ prefix and configures the Google GenAI SDK to route through {CUA_BASE_URL}/gemini, matching how other loops (Anthropic, OpenAI) transparently route through litellm's CUA adapter. Single code path for both direct-Google and CUA-routed models.
  • Improve Gemini 3 coordinate precision, fix LiteLLM warnings, and extract thinking traces (see details below).

Problem

When using cua/google/gemini-3-flash-preview (CUA inference API routing):

  1. Wrong agent loop: find_agent_config() matched the raw cua/google/gemini-3-flash-preview string against registered patterns. The Gemini loop's anchored regex ^(gemini-2\.5-computer-use-preview.*|gemini-3-flash-preview.*|...)$ didn't match, so the model fell through to GenericVlmConfig's catch-all (?i).* at priority -100.

  2. No CUA proxy support in Gemini loop: Even after fixing routing, the Gemini loop called the Google SDK directly (client.models.generate_content()), unlike Anthropic/OpenAI loops which use litellm (which transparently routes cua/ models through CUAAdapter). So cua/ prefix models would fail authentication since GOOGLE_API_KEY contained a CUA key, not a real Google key.

Changes

libs/python/agent/agent/decorators.py

  • _strip_cua_prefix(model): Strips cua/<provider>/ routing prefix → bare model name (e.g. cua/google/gemini-3-flash-previewgemini-3-flash-preview)
  • find_agent_config(model): For each config in priority order, tries original string first, then stripped. This ensures specialized loops match before the catch-all, without breaking direct model strings.

libs/python/agent/agent/loops/gemini.py

  • _create_gemini_client(): Shared helper for predict_step and predict_click. Detects cua/ prefix → configures Google GenAI SDK with http_options={"base_url": f"{CUA_BASE_URL}/gemini"} and CUA API key. Falls back to standard GOOGLE_API_KEY / Vertex AI for non-CUA models.
  • System instruction: Adds screen resolution context and coordinate system description for Gemini 3 models to improve click precision.
  • Enhanced function declarations: All coordinate-based functions (click_at, type_text_at, hover_at, scroll_at, drag_and_drop) now include explicit 0-999 edge semantics.
  • Screenshot text part: Added types.Part(text="[screenshot]") alongside image parts in computer_call_output to fix LiteLLM content-part warnings.
  • Thinking extraction: Added make_reasoning_item import and getattr(p, "thought", False) check to capture Gemini's thinking traces in trajectory output.

Design Decision

All other agent loops pass the raw model string to litellm, which detects the cua/ prefix and routes through CUAAdapter. The Gemini loop is unique in using the Google GenAI SDK directly (for native ComputerUse tool support, function declarations, thinking config, etc.). Rather than rewriting it to use litellm, we configure the Google SDK to point at the CUA inference proxy — same endpoint, same format, single code path for both direct and CUA-routed models.

Test plan

  • Verified cua/google/gemini-3-flash-preview routes to GeminiComputerUseConfig (not GenericVlmConfig)
  • End-to-end test: model clicked "Learn more" on example.com in 2 turns through CUA inference API
  • Trajectory confirms agent_loop: "GeminiComputerUseConfig" in metadata
  • Verify direct GOOGLE_API_KEY path still works (no cua/ prefix)
  • Verify Gemini 2.5 ComputerUse model path is unaffected

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for Gemini 3 models with enhanced system instructions and improved reasoning/thinking content recognition.
    • Extended model routing to support alternative model naming conventions for improved configuration flexibility.
  • Refactor

    • Improved client creation logic for better authentication and routing handling.

@vercel

vercel Bot commented Feb 26, 2026

Copy link
Copy Markdown
Contributor

@sarinali is attempting to deploy a commit to the Cua Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Feb 26, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The changes introduce CUA (Cloud Universal API) routing support across the agent system. A helper function strips CUA prefixes from model names to align routed models with bare configurations. The Gemini implementation adds centralized client creation, system instruction support for Gemini 3 models, enhanced reasoning content extraction, and expanded function declarations with coordinate semantics.

Changes

Cohort / File(s) Summary
CUA Routing Configuration
libs/python/agent/agent/decorators.py
Introduces _strip_cua_prefix() helper and extends find_agent_config() to match both original and stripped model names, enabling routed models to resolve to configurations of their bare counterparts.
Gemini Client and Model Handling
libs/python/agent/agent/loops/gemini.py
Adds _create_gemini_client() for centralized CUA-aware client creation; introduces system instruction support for Gemini 3 with computed screen dimensions; enhances reasoning content extraction from model outputs; expands function declarations with explicit coordinate descriptions; improves logging around function calls and model decisions.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant ConfigFinder as Config Finder<br/>(find_agent_config)
    participant CUAHandler as CUA Handler<br/>(_strip_cua_prefix)
    participant ClientFactory as Client Factory<br/>(_create_gemini_client)
    participant GeminiAPI as Gemini API

    Caller->>ConfigFinder: find_agent_config(cua/provider/model)
    ConfigFinder->>CUAHandler: _strip_cua_prefix(cua/provider/model)
    CUAHandler-->>ConfigFinder: bare_model
    ConfigFinder->>ConfigFinder: Try original, then stripped
    ConfigFinder-->>Caller: agent_config

    Caller->>ClientFactory: _create_gemini_client(cua/provider/model, ...)
    ClientFactory->>ClientFactory: Detect CUA prefix
    ClientFactory->>ClientFactory: Set CUA auth & routing
    ClientFactory-->>Caller: (gemini_client, bare_model)

    Caller->>GeminiAPI: GenerateContent(with system_instruction)
    GeminiAPI-->>Caller: Response with reasoning
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A rabbit hops through prefixes stripped,
CUA routes now seamlessly equipped,
Gemini speaks with system instruction,
Reasoning blooms—pure construction!
From bare to routed, logic aligned,
One config for every model-kind. 🌟

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: enabling CUA-prefixed Gemini models to route through the correct Gemini agent loop instead of falling back to generic handling.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sentry

sentry Bot commented Feb 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 20.00000% with 32 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
libs/python/agent/agent/loops/gemini.py 6.25% 30 Missing ⚠️
libs/python/agent/agent/decorators.py 75.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
libs/python/agent/agent/loops/gemini.py (1)

941-958: Consider extracting click_at declaration to reduce duplication.

The click_at function declaration here duplicates the one in _build_custom_function_declarations (lines 358-375). If the description or parameters change, both locations need updating.

♻️ Extract shared click_at declaration
+def _get_click_at_declaration(types: Any) -> Any:
+    """Return the click_at function declaration for Gemini 3 models."""
+    return types.FunctionDeclaration(
+        name="click_at",
+        description="Click at the specified x,y coordinates on the screen. x and y are normalized 0-999 where 0 is the left/top edge and 999 is the right/bottom edge of the screen. Look carefully at the screenshot to identify the exact position of the target element before clicking.",
+        parameters={
+            "type": "object",
+            "properties": {
+                "x": {
+                    "type": "integer",
+                    "description": "X coordinate (0-999 normalized). 0 is the left edge, 999 is the right edge.",
+                },
+                "y": {
+                    "type": "integer",
+                    "description": "Y coordinate (0-999 normalized). 0 is the top edge, 999 is the bottom edge.",
+                },
+            },
+            "required": ["x", "y"],
+        },
+    )

Then use _get_click_at_declaration(types) in both _build_custom_function_declarations and predict_click.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@libs/python/agent/agent/loops/gemini.py` around lines 941 - 958, Extract the
duplicated click_at FunctionDeclaration into a single helper function named
_get_click_at_declaration(types) and return the FunctionDeclaration object from
it; then replace the inline click_at declarations in
_build_custom_function_declarations and predict_click with calls to
_get_click_at_declaration(types). Ensure the helper accepts the same `types`
argument used where FunctionDeclaration is constructed and keep the original
description, parameter schema and required fields unchanged so both callers get
the identical declaration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@libs/python/agent/agent/loops/gemini.py`:
- Around line 941-958: Extract the duplicated click_at FunctionDeclaration into
a single helper function named _get_click_at_declaration(types) and return the
FunctionDeclaration object from it; then replace the inline click_at
declarations in _build_custom_function_declarations and predict_click with calls
to _get_click_at_declaration(types). Ensure the helper accepts the same `types`
argument used where FunctionDeclaration is constructed and keep the original
description, parameter schema and required fields unchanged so both callers get
the identical declaration.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d52e02 and ea051d8.

📒 Files selected for processing (2)
  • libs/python/agent/agent/decorators.py
  • libs/python/agent/agent/loops/gemini.py

@sarinali
sarinali force-pushed the fix/gemini-cua-routing branch from d73a2eb to 189516b Compare February 26, 2026 08:45
@sarinali
sarinali requested a review from ddupont808 February 26, 2026 08:46
@ddupont808
ddupont808 merged commit a5495b2 into trycua:main Feb 26, 2026
30 of 35 checks passed
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.

2 participants