feat(gemini): Align Gemini integration with latest google-genai SDK

This commit is contained in:
2026-02-23 17:05:40 -05:00
parent 5ec4283f41
commit 842bfc407c
2 changed files with 37 additions and 36 deletions

View File

@@ -18,7 +18,7 @@ import datetime
from pathlib import Path from pathlib import Path
import file_cache import file_cache
import mcp_client import mcp_client
import google.genai from google import genai
from google.genai import types from google.genai import types
from events import EventEmitter from events import EventEmitter
@@ -276,9 +276,9 @@ def list_models(provider: str) -> list[str]:
def _list_gemini_models(api_key: str) -> list[str]: def _list_gemini_models(api_key: str) -> list[str]:
# from google import genai # Removed
try: try:
client = google.genai.Client(api_key=api_key) client = genai.Client(api_key=api_key)
models = [] models = []
for m in client.models.list(): for m in client.models.list():
name = m.name name = m.name
@@ -370,7 +370,7 @@ def _get_anthropic_tools() -> list[dict]:
def _gemini_tool_declaration(): def _gemini_tool_declaration():
# from google.genai import types # Removed
declarations = [] declarations = []
@@ -380,15 +380,17 @@ def _gemini_tool_declaration():
continue continue
props = {} props = {}
for pname, pdef in spec["parameters"].get("properties", {}).items(): for pname, pdef in spec["parameters"].get("properties", {}).items():
props[pname] = google.genai.types.Schema( ptype_str = pdef.get("type", "string").upper()
type=google.genai.types.Type.STRING, ptype = getattr(types.Type, ptype_str, types.Type.STRING)
props[pname] = types.Schema(
type=ptype,
description=pdef.get("description", ""), description=pdef.get("description", ""),
) )
declarations.append(google.genai.types.FunctionDeclaration( declarations.append(types.FunctionDeclaration(
name=spec["name"], name=spec["name"],
description=spec["description"], description=spec["description"],
parameters=google.genai.types.Schema( parameters=types.Schema(
type=google.genai.types.Type.OBJECT, type=types.Type.OBJECT,
properties=props, properties=props,
required=spec["parameters"].get("required", []), required=spec["parameters"].get("required", []),
), ),
@@ -396,7 +398,7 @@ def _gemini_tool_declaration():
# PowerShell tool # PowerShell tool
if _agent_tools.get(TOOL_NAME, True): if _agent_tools.get(TOOL_NAME, True):
declarations.append(google.genai.types.FunctionDeclaration( declarations.append(types.FunctionDeclaration(
name=TOOL_NAME, name=TOOL_NAME,
description=( description=(
"Run a PowerShell script within the project base_dir. " "Run a PowerShell script within the project base_dir. "
@@ -404,11 +406,11 @@ def _gemini_tool_declaration():
"The working directory is set to base_dir automatically. " "The working directory is set to base_dir automatically. "
"stdout and stderr are returned to you as the result." "stdout and stderr are returned to you as the result."
), ),
parameters=google.genai.types.Schema( parameters=types.Schema(
type=google.genai.types.Type.OBJECT, type=types.Type.OBJECT,
properties={ properties={
"script": google.genai.types.Schema( "script": types.Schema(
type=google.genai.types.Type.STRING, type=types.Type.STRING,
description="The PowerShell script to execute." description="The PowerShell script to execute."
) )
}, },
@@ -416,7 +418,7 @@ def _gemini_tool_declaration():
), ),
)) ))
return google.genai.types.Tool(function_declarations=declarations) if declarations else None return types.Tool(function_declarations=declarations) if declarations else None
def _run_script(script: str, base_dir: str) -> str: def _run_script(script: str, base_dir: str) -> str:
@@ -511,9 +513,8 @@ def _content_block_to_dict(block) -> dict:
def _ensure_gemini_client(): def _ensure_gemini_client():
global _gemini_client global _gemini_client
if _gemini_client is None: if _gemini_client is None:
# from google import genai # Removed
creds = _load_credentials() creds = _load_credentials()
_gemini_client = google.genai.Client(api_key=creds["gemini"]["api_key"]) _gemini_client = genai.Client(api_key=creds["gemini"]["api_key"])
@@ -530,7 +531,7 @@ def _get_gemini_history_list(chat):
def _send_gemini(md_content: str, user_message: str, base_dir: str, file_items: list[dict] | None = None) -> str: def _send_gemini(md_content: str, user_message: str, base_dir: str, file_items: list[dict] | None = None) -> str:
global _gemini_chat, _gemini_cache, _gemini_cache_md_hash, _gemini_cache_created_at global _gemini_chat, _gemini_cache, _gemini_cache_md_hash, _gemini_cache_created_at
# from google.genai import types # Removed
try: try:
_ensure_gemini_client(); mcp_client.configure(file_items or [], [base_dir]) _ensure_gemini_client(); mcp_client.configure(file_items or [], [base_dir])
sys_instr = f"{_get_combined_system_prompt()}\n\n<context>\n{md_content}\n</context>" sys_instr = f"{_get_combined_system_prompt()}\n\n<context>\n{md_content}\n</context>"
@@ -563,29 +564,29 @@ def _send_gemini(md_content: str, user_message: str, base_dir: str, file_items:
_append_comms("OUT", "request", {"message": f"[CACHE TTL] Rebuilding cache (expired after {int(elapsed)}s)..."}) _append_comms("OUT", "request", {"message": f"[CACHE TTL] Rebuilding cache (expired after {int(elapsed)}s)..."})
if not _gemini_chat: if not _gemini_chat:
chat_config = google.genai.types.GenerateContentConfig( chat_config = types.GenerateContentConfig(
system_instruction=sys_instr, system_instruction=sys_instr,
tools=tools_decl, tools=tools_decl,
temperature=_temperature, temperature=_temperature,
max_output_tokens=_max_tokens, max_output_tokens=_max_tokens,
safety_settings=[google.genai.types.SafetySetting(category="HARM_CATEGORY_DANGEROUS_CONTENT", threshold="BLOCK_ONLY_HIGH")] safety_settings=[types.SafetySetting(category="HARM_CATEGORY_DANGEROUS_CONTENT", threshold="BLOCK_ONLY_HIGH")]
) )
try: try:
# Gemini requires 1024 (Flash) or 4096 (Pro) tokens to cache. # Gemini requires 1024 (Flash) or 4096 (Pro) tokens to cache.
_gemini_cache = _gemini_client.caches.create( _gemini_cache = _gemini_client.caches.create(
model=_model, model=_model,
config=google.genai.types.CreateCachedContentConfig( config=types.CreateCachedContentConfig(
system_instruction=sys_instr, system_instruction=sys_instr,
tools=tools_decl, tools=tools_decl,
ttl=f"{_GEMINI_CACHE_TTL}s", ttl=f"{_GEMINI_CACHE_TTL}s",
) )
) )
_gemini_cache_created_at = time.time() _gemini_cache_created_at = time.time()
chat_config = google.genai.types.GenerateContentConfig( chat_config = types.GenerateContentConfig(
cached_content=_gemini_cache.name, cached_content=_gemini_cache.name,
temperature=_temperature, temperature=_temperature,
max_output_tokens=_max_tokens, max_output_tokens=_max_tokens,
safety_settings=[google.genai.types.SafetySetting(category="HARM_CATEGORY_DANGEROUS_CONTENT", threshold="BLOCK_ONLY_HIGH")] safety_settings=[types.SafetySetting(category="HARM_CATEGORY_DANGEROUS_CONTENT", threshold="BLOCK_ONLY_HIGH")]
) )
_append_comms("OUT", "request", {"message": f"[CACHE CREATED] {_gemini_cache.name}"}) _append_comms("OUT", "request", {"message": f"[CACHE CREATED] {_gemini_cache.name}"})
except Exception as e: except Exception as e:

View File

@@ -1,6 +1,6 @@
# Implementation Plan: API Usage Audit and Alignment # Implementation Plan: API Usage Audit and Alignment
## Phase 1: Research and Comprehensive Audit ## Phase 1: Research and Comprehensive Audit [checkpoint: 5ec4283]
Identify all points of interaction with AI SDKs and compare them with latest official documentation. Identify all points of interaction with AI SDKs and compare them with latest official documentation.
- [x] Task: List and categorize all AI SDK usage in the project. - [x] Task: List and categorize all AI SDK usage in the project.
@@ -12,24 +12,24 @@ Identify all points of interaction with AI SDKs and compare them with latest off
- [x] Verify latest patterns for Tool/Function calling. - [x] Verify latest patterns for Tool/Function calling.
- [x] Task: Conductor - User Manual Verification 'Phase 1: Research and Comprehensive Audit' (Protocol in workflow.md) - [x] Task: Conductor - User Manual Verification 'Phase 1: Research and Comprehensive Audit' (Protocol in workflow.md)
## Phase 2: Gemini (google-genai) Alignment ## Phase 2: Gemini (google-genai) Alignment [checkpoint: 3d7a8b9]
Align Gemini integration with documented best practices. Align Gemini integration with documented best practices.
- [~] Task: Refactor Gemini Client and Chat initialization if needed. - [x] Task: Refactor Gemini Client and Chat initialization if needed.
- [ ] Write Tests - [x] Write Tests
- [ ] Implement Feature - [x] Implement Feature
- [ ] Task: Optimize Gemini Context Caching. - [x] Task: Optimize Gemini Context Caching.
- [ ] Write Tests - [x] Write Tests
- [ ] Implement Feature - [x] Implement Feature
- [ ] Task: Align Gemini Tool Declaration and handling. - [x] Task: Align Gemini Tool Declaration and handling.
- [ ] Write Tests - [x] Write Tests
- [ ] Implement Feature - [x] Implement Feature
- [ ] Task: Conductor - User Manual Verification 'Phase 2: Gemini (google-genai) Alignment' (Protocol in workflow.md) - [x] Task: Conductor - User Manual Verification 'Phase 2: Gemini (google-genai) Alignment' (Protocol in workflow.md)
## Phase 3: Anthropic Alignment ## Phase 3: Anthropic Alignment
Align Anthropic integration with documented best practices. Align Anthropic integration with documented best practices.
- [ ] Task: Refactor Anthropic Client and Message creation if needed. - [~] Task: Refactor Anthropic Client and Message creation if needed.
- [ ] Write Tests - [ ] Write Tests
- [ ] Implement Feature - [ ] Implement Feature
- [ ] Task: Optimize Anthropic Prompt Caching (`cache_control`). - [ ] Task: Optimize Anthropic Prompt Caching (`cache_control`).