code-puppy 0.0.365__py3-none-any.whl → 0.0.367__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
code_puppy/http_utils.py CHANGED
@@ -9,11 +9,12 @@ import os
9
9
  import socket
10
10
  import time
11
11
  from dataclasses import dataclass
12
- from typing import Any, Dict, Optional, Union
12
+ from typing import TYPE_CHECKING, Any, Dict, Optional, Union
13
13
 
14
14
  import httpx
15
- import requests
16
15
 
16
+ if TYPE_CHECKING:
17
+ import requests
17
18
  from code_puppy.config import get_http2
18
19
 
19
20
 
@@ -246,7 +247,9 @@ def create_requests_session(
246
247
  timeout: float = 5.0,
247
248
  verify: Union[bool, str] = None,
248
249
  headers: Optional[Dict[str, str]] = None,
249
- ) -> requests.Session:
250
+ ) -> "requests.Session":
251
+ import requests
252
+
250
253
  session = requests.Session()
251
254
 
252
255
  if verify is None:
@@ -7,7 +7,6 @@ from typing import Any, Dict
7
7
  from anthropic import AsyncAnthropic
8
8
  from openai import AsyncAzureOpenAI
9
9
  from pydantic_ai.models.anthropic import AnthropicModel, AnthropicModelSettings
10
- from pydantic_ai.models.google import GoogleModel
11
10
  from pydantic_ai.models.openai import (
12
11
  OpenAIChatModel,
13
12
  OpenAIChatModelSettings,
@@ -16,11 +15,11 @@ from pydantic_ai.models.openai import (
16
15
  from pydantic_ai.profiles import ModelProfile
17
16
  from pydantic_ai.providers.anthropic import AnthropicProvider
18
17
  from pydantic_ai.providers.cerebras import CerebrasProvider
19
- from pydantic_ai.providers.google import GoogleProvider
20
18
  from pydantic_ai.providers.openai import OpenAIProvider
21
19
  from pydantic_ai.providers.openrouter import OpenRouterProvider
22
20
  from pydantic_ai.settings import ModelSettings
23
21
 
22
+ from code_puppy.gemini_model import GeminiModel
24
23
  from code_puppy.messaging import emit_warning
25
24
 
26
25
  from . import callbacks
@@ -29,6 +28,8 @@ from .config import EXTRA_MODELS_FILE, get_value
29
28
  from .http_utils import create_async_client, get_cert_bundle_path, get_http2
30
29
  from .round_robin_model import RoundRobinModel
31
30
 
31
+ logger = logging.getLogger(__name__)
32
+
32
33
 
33
34
  def get_api_key(env_var_name: str) -> str | None:
34
35
  """Get an API key from config first, then fall back to environment variable.
@@ -288,9 +289,7 @@ class ModelFactory:
288
289
  )
289
290
  return None
290
291
 
291
- provider = GoogleProvider(api_key=api_key)
292
- model = GoogleModel(model_name=model_config["name"], provider=provider)
293
- setattr(model, "provider", provider)
292
+ model = GeminiModel(model_name=model_config["name"], api_key=api_key)
294
293
  return model
295
294
 
296
295
  elif model_type == "openai":
@@ -615,11 +614,13 @@ class ModelFactory:
615
614
  refresh_token = tokens.get("refresh_token", "")
616
615
  expires_at = tokens.get("expires_at")
617
616
 
618
- # Refresh if expired or about to expire
617
+ # Refresh if expired or about to expire (initial check)
619
618
  if is_token_expired(expires_at):
620
619
  new_tokens = refresh_access_token(refresh_token)
621
620
  if new_tokens:
622
621
  access_token = new_tokens.access_token
622
+ refresh_token = new_tokens.refresh_token
623
+ expires_at = new_tokens.expires_at
623
624
  tokens["access_token"] = new_tokens.access_token
624
625
  tokens["refresh_token"] = new_tokens.refresh_token
625
626
  tokens["expires_at"] = new_tokens.expires_at
@@ -630,6 +631,21 @@ class ModelFactory:
630
631
  )
631
632
  return None
632
633
 
634
+ # Callback to persist tokens when proactively refreshed during session
635
+ def on_token_refreshed(new_tokens):
636
+ """Persist new tokens when proactively refreshed."""
637
+ try:
638
+ updated_tokens = load_stored_tokens() or {}
639
+ updated_tokens["access_token"] = new_tokens.access_token
640
+ updated_tokens["refresh_token"] = new_tokens.refresh_token
641
+ updated_tokens["expires_at"] = new_tokens.expires_at
642
+ save_tokens(updated_tokens)
643
+ logger.debug(
644
+ "Persisted proactively refreshed Antigravity tokens"
645
+ )
646
+ except Exception as e:
647
+ logger.warning("Failed to persist refreshed tokens: %s", e)
648
+
633
649
  project_id = tokens.get(
634
650
  "project_id", model_config.get("project_id", "")
635
651
  )
@@ -639,20 +655,26 @@ class ModelFactory:
639
655
  model_name=model_config["name"],
640
656
  base_url=url,
641
657
  headers=headers,
658
+ refresh_token=refresh_token,
659
+ expires_at=expires_at,
660
+ on_token_refreshed=on_token_refreshed,
642
661
  )
643
662
 
644
- provider = GoogleProvider(
645
- api_key=api_key, base_url=url, http_client=client
646
- )
647
-
648
- # Use custom model if available to preserve thinking signatures
663
+ # Use custom model with direct httpx client
649
664
  if AntigravityModel:
650
665
  model = AntigravityModel(
651
- model_name=model_config["name"], provider=provider
666
+ model_name=model_config["name"],
667
+ api_key=api_key
668
+ or "", # Antigravity uses OAuth, key may be empty
669
+ base_url=url,
670
+ http_client=client,
652
671
  )
653
672
  else:
654
- model = GoogleModel(
655
- model_name=model_config["name"], provider=provider
673
+ model = GeminiModel(
674
+ model_name=model_config["name"],
675
+ api_key=api_key or "",
676
+ base_url=url,
677
+ http_client=client,
656
678
  )
657
679
 
658
680
  return model
@@ -665,8 +687,12 @@ class ModelFactory:
665
687
  else:
666
688
  client = create_async_client(headers=headers, verify=verify)
667
689
 
668
- provider = GoogleProvider(api_key=api_key, base_url=url, http_client=client)
669
- model = GoogleModel(model_name=model_config["name"], provider=provider)
690
+ model = GeminiModel(
691
+ model_name=model_config["name"],
692
+ api_key=api_key,
693
+ base_url=url,
694
+ http_client=client,
695
+ )
670
696
  return model
671
697
  elif model_type == "cerebras":
672
698