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/gemini_model.py +706 -0
- code_puppy/http_utils.py +6 -3
- code_puppy/model_factory.py +42 -16
- code_puppy/plugins/antigravity_oauth/antigravity_model.py +128 -165
- code_puppy/plugins/antigravity_oauth/transport.py +235 -45
- {code_puppy-0.0.365.dist-info → code_puppy-0.0.367.dist-info}/METADATA +3 -3
- {code_puppy-0.0.365.dist-info → code_puppy-0.0.367.dist-info}/RECORD +12 -11
- {code_puppy-0.0.365.data → code_puppy-0.0.367.data}/data/code_puppy/models.json +0 -0
- {code_puppy-0.0.365.data → code_puppy-0.0.367.data}/data/code_puppy/models_dev_api.json +0 -0
- {code_puppy-0.0.365.dist-info → code_puppy-0.0.367.dist-info}/WHEEL +0 -0
- {code_puppy-0.0.365.dist-info → code_puppy-0.0.367.dist-info}/entry_points.txt +0 -0
- {code_puppy-0.0.365.dist-info → code_puppy-0.0.367.dist-info}/licenses/LICENSE +0 -0
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:
|
code_puppy/model_factory.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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"],
|
|
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 =
|
|
655
|
-
model_name=model_config["name"],
|
|
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
|
-
|
|
669
|
-
|
|
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
|
|