argo-proxy 3.2.0a0__tar.gz → 3.2.1__tar.gz

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.
Files changed (47) hide show
  1. {argo_proxy-3.2.0a0/src/argo_proxy.egg-info → argo_proxy-3.2.1}/PKG-INFO +2 -2
  2. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/pyproject.toml +1 -1
  3. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1/src/argo_proxy.egg-info}/PKG-INFO +2 -2
  4. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argo_proxy.egg-info/requires.txt +1 -1
  5. argo_proxy-3.2.1/src/argoproxy/__init__.py +1 -0
  6. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/app.py +0 -1
  7. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/config/model.py +4 -0
  8. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/endpoints/dispatch.py +5 -0
  9. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/models.py +18 -5
  10. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/performance.py +0 -4
  11. argo_proxy-3.2.0a0/src/argoproxy/__init__.py +0 -1
  12. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/LICENSE +0 -0
  13. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/README.md +0 -0
  14. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/setup.cfg +0 -0
  15. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argo_proxy.egg-info/SOURCES.txt +0 -0
  16. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argo_proxy.egg-info/dependency_links.txt +0 -0
  17. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argo_proxy.egg-info/entry_points.txt +0 -0
  18. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argo_proxy.egg-info/top_level.txt +0 -0
  19. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/_vendor/__init__.py +0 -0
  20. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/_vendor/semver.py +0 -0
  21. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/_vendor/yaml.py +0 -0
  22. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/cli/__init__.py +0 -0
  23. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/cli/display.py +0 -0
  24. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/cli/handlers.py +0 -0
  25. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/cli/parser.py +0 -0
  26. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/config/__init__.py +0 -0
  27. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/config/interactive.py +0 -0
  28. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/config/io.py +0 -0
  29. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/config/validation.py +0 -0
  30. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/endpoints/dev_proxy.py +0 -0
  31. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/endpoints/extras.py +0 -0
  32. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/endpoints/passthrough.py +0 -0
  33. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/py.typed +0 -0
  34. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/utils/attack_logger.py +0 -0
  35. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/utils/image_processing.py +0 -0
  36. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/utils/logging.py +0 -0
  37. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/utils/misc.py +0 -0
  38. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/utils/models.py +0 -0
  39. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/src/argoproxy/utils/transports.py +0 -0
  40. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/test/test_chat_completions.py +0 -0
  41. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/test/test_embeddings.py +0 -0
  42. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/test/test_function_calling_multiple.py +0 -0
  43. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/test/test_function_calling_single.py +0 -0
  44. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/test/test_leaked_tool_parser.py +0 -0
  45. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/test/test_model_resolution.py +0 -0
  46. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/tests/test_config_migrate.py +0 -0
  47. {argo_proxy-3.2.0a0 → argo_proxy-3.2.1}/tests/test_unix_socket.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: argo-proxy
3
- Version: 3.2.0a0
3
+ Version: 3.2.1
4
4
  Summary: Proxy server to Argo API, OpenAI format compatible
5
5
  Author-email: Peng Ding <oaklight@gmx.com>
6
6
  License-Expression: MIT
@@ -15,7 +15,7 @@ Requires-Python: >=3.10
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
17
  Requires-Dist: aiohttp>=3.12.2
18
- Requires-Dist: llm-rosetta>=0.7.0a0
18
+ Requires-Dist: llm-rosetta>=0.7.0
19
19
  Requires-Dist: pydantic>=2.11.7
20
20
  Requires-Dist: tiktoken>=0.9.0
21
21
  Requires-Dist: tqdm>=4.67.1
@@ -20,7 +20,7 @@ classifiers = [
20
20
 
21
21
  dependencies = [
22
22
  "aiohttp>=3.12.2",
23
- "llm-rosetta>=0.7.0a0",
23
+ "llm-rosetta>=0.7.0",
24
24
  "pydantic>=2.11.7",
25
25
  "tiktoken>=0.9.0",
26
26
  "tqdm>=4.67.1",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: argo-proxy
3
- Version: 3.2.0a0
3
+ Version: 3.2.1
4
4
  Summary: Proxy server to Argo API, OpenAI format compatible
5
5
  Author-email: Peng Ding <oaklight@gmx.com>
6
6
  License-Expression: MIT
@@ -15,7 +15,7 @@ Requires-Python: >=3.10
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
17
  Requires-Dist: aiohttp>=3.12.2
18
- Requires-Dist: llm-rosetta>=0.7.0a0
18
+ Requires-Dist: llm-rosetta>=0.7.0
19
19
  Requires-Dist: pydantic>=2.11.7
20
20
  Requires-Dist: tiktoken>=0.9.0
21
21
  Requires-Dist: tqdm>=4.67.1
@@ -1,5 +1,5 @@
1
1
  aiohttp>=3.12.2
2
- llm-rosetta>=0.7.0a0
2
+ llm-rosetta>=0.7.0
3
3
  pydantic>=2.11.7
4
4
  tiktoken>=0.9.0
5
5
  tqdm>=4.67.1
@@ -0,0 +1 @@
1
+ __version__ = "3.2.1"
@@ -92,7 +92,6 @@ async def prepare_app(app):
92
92
  # Create optimized HTTP session
93
93
  resolve_overrides = getattr(app["config"], "resolve_overrides", None)
94
94
  http_session_manager = OptimizedHTTPSession(
95
- user_agent=f"argo-proxy/{__version__}",
96
95
  resolve_overrides=resolve_overrides if resolve_overrides else None,
97
96
  **perf_config,
98
97
  )
@@ -76,6 +76,10 @@ class ArgoConfig:
76
76
  # Model list auto-refresh
77
77
  model_refresh_interval_hours: float = 24 # 0 to disable
78
78
 
79
+ # Fallback models — used when an unrecognized model name is requested
80
+ default_chat_model: str = "argo:gpt-5.4-nano"
81
+ default_embed_model: str = "argo:text-embedding-3-small"
82
+
79
83
  # Image processing settings
80
84
  enable_payload_control: bool = False # Enable automatic payload size control
81
85
  max_payload_size: int = 20 # MB default (total for all images)
@@ -288,6 +288,11 @@ def _build_upstream_headers(
288
288
  """Build HTTP headers for the upstream API request."""
289
289
  headers: dict[str, str] = {"Content-Type": "application/json"}
290
290
 
291
+ # Pass through client's User-Agent to upstream (transparent proxy)
292
+ client_ua = request.headers.get("User-Agent")
293
+ if client_ua:
294
+ headers["User-Agent"] = client_ua
295
+
291
296
  if should_use_username_passthrough():
292
297
  api_key = _extract_client_credential(request, target_provider) or fallback_user
293
298
  else:
@@ -51,6 +51,7 @@ _DEFAULT_CHAT_MODELS = flatten_mapping(
51
51
  "gpt51": "argo:gpt-5.1",
52
52
  "gpt52": "argo:gpt-5.2",
53
53
  "gpt54": "argo:gpt-5.4",
54
+ "gpt54nano": "argo:gpt-5.4-nano",
54
55
  "gpt55": "argo:gpt-5.5",
55
56
  # gemini
56
57
  "gemini25pro": "argo:gemini-2.5-pro",
@@ -308,7 +309,6 @@ async def get_upstream_model_list_async(
308
309
  async with aiohttp.ClientSession(
309
310
  connector=connector,
310
311
  timeout=client_timeout,
311
- headers={"User-Agent": "argo-proxy/1.0"},
312
312
  ) as session:
313
313
  log_debug(f"Sending request to: {url}", context="models")
314
314
 
@@ -480,7 +480,7 @@ def _categorize_results(
480
480
  unavailable.clear()
481
481
  else:
482
482
  log_error(
483
- "Proceeding without unavailable models. Subsequent calls to these models will be replaced with argo:gpt-5-nano",
483
+ "Proceeding without unavailable models. Subsequent calls to these models will use the configured default fallback",
484
484
  context="models",
485
485
  )
486
486
 
@@ -781,14 +781,27 @@ class ModelRegistry:
781
781
  return model_name
782
782
 
783
783
  if model_type == "chat":
784
- default_model = "argo:gpt-5-nano"
784
+ default_model = self._config.default_chat_model
785
785
  elif model_type == "embed":
786
- default_model = "argo:text-embedding-3-small"
786
+ default_model = self._config.default_embed_model
787
+ else:
788
+ default_model = self._config.default_chat_model
789
+ log_warning(
790
+ f"Unknown model_type '{model_type}', using chat fallback",
791
+ context="ModelRegistry",
792
+ )
787
793
  log_warning(
788
794
  f"Model '{model_name}' not found in registry, falling back to {default_model}",
789
795
  context="ModelRegistry",
790
796
  )
791
- return self.available_models[default_model]
797
+ if default_model in self.available_models:
798
+ return self.available_models[default_model]
799
+ # Default model itself not in registry — return its name as-is
800
+ log_warning(
801
+ f"Default fallback model '{default_model}' not in registry either",
802
+ context="ModelRegistry",
803
+ )
804
+ return default_model
792
805
 
793
806
  def as_openai_list(self) -> dict[str, Any]:
794
807
  # Mock data for available models
@@ -93,7 +93,6 @@ class OptimizedHTTPSession:
93
93
  read_timeout: Socket read timeout in seconds.
94
94
  total_timeout: Total request timeout in seconds.
95
95
  dns_cache_ttl: DNS cache TTL in seconds.
96
- user_agent: User agent string.
97
96
  resolve_overrides: Optional dict mapping "host:port" to IP address
98
97
  for custom DNS resolution (similar to curl --resolve).
99
98
  """
@@ -108,7 +107,6 @@ class OptimizedHTTPSession:
108
107
  read_timeout: int = 30,
109
108
  total_timeout: int = 60,
110
109
  dns_cache_ttl: int = 300,
111
- user_agent: str = "argo-proxy",
112
110
  resolve_overrides: dict[str, str] | None = None,
113
111
  ):
114
112
  connector_kwargs: dict = {
@@ -137,7 +135,6 @@ class OptimizedHTTPSession:
137
135
  )
138
136
 
139
137
  self.session: aiohttp.ClientSession | None = None
140
- self.user_agent = user_agent
141
138
 
142
139
  async def create_session(self) -> aiohttp.ClientSession:
143
140
  """Create and return the HTTP session."""
@@ -145,7 +142,6 @@ class OptimizedHTTPSession:
145
142
  self.session = aiohttp.ClientSession(
146
143
  connector=self.connector,
147
144
  timeout=self.timeout,
148
- headers={"User-Agent": self.user_agent},
149
145
  )
150
146
  log_debug(
151
147
  f"HTTP session created: {self.connector.limit} total, "
@@ -1 +0,0 @@
1
- __version__ = "3.2.0a0"
File without changes
File without changes
File without changes