Improve OpenRouter and Groq provider requests
This commit is contained in:
@@ -125,15 +125,19 @@ def build_chat_url(base: str) -> str:
|
|||||||
|
|
||||||
def build_headers(api_key: Optional[str], base: str) -> Dict[str, str]:
|
def build_headers(api_key: Optional[str], base: str) -> Dict[str, str]:
|
||||||
"""Build auth headers for an endpoint."""
|
"""Build auth headers for an endpoint."""
|
||||||
if not api_key:
|
|
||||||
return {}
|
|
||||||
provider = _detect_provider(base)
|
provider = _detect_provider(base)
|
||||||
|
headers: Dict[str, str] = {}
|
||||||
if provider == "anthropic":
|
if provider == "anthropic":
|
||||||
return {
|
if api_key:
|
||||||
"x-api-key": api_key,
|
headers["x-api-key"] = api_key
|
||||||
"anthropic-version": "2023-06-01",
|
headers["anthropic-version"] = "2023-06-01"
|
||||||
}
|
return headers
|
||||||
return {"Authorization": f"Bearer {api_key}"}
|
if api_key:
|
||||||
|
headers["Authorization"] = f"Bearer {api_key}"
|
||||||
|
if provider == "openrouter":
|
||||||
|
headers.setdefault("HTTP-Referer", "https://github.com/pewdiepie-archdaemon/odysseus")
|
||||||
|
headers.setdefault("X-OpenRouter-Title", "Odysseus")
|
||||||
|
return headers
|
||||||
|
|
||||||
|
|
||||||
def resolve_endpoint(
|
def resolve_endpoint(
|
||||||
|
|||||||
@@ -142,11 +142,26 @@ ANTHROPIC_MODELS = [
|
|||||||
|
|
||||||
def _detect_provider(url: str) -> str:
|
def _detect_provider(url: str) -> str:
|
||||||
"""Detect API provider from URL."""
|
"""Detect API provider from URL."""
|
||||||
if "anthropic.com" in (url or ""):
|
u = (url or "").lower()
|
||||||
|
if "anthropic.com" in u:
|
||||||
return "anthropic"
|
return "anthropic"
|
||||||
|
if "openrouter.ai" in u:
|
||||||
|
return "openrouter"
|
||||||
|
if "groq.com" in u:
|
||||||
|
return "groq"
|
||||||
return "openai"
|
return "openai"
|
||||||
|
|
||||||
|
|
||||||
|
def _provider_headers(provider: str, headers: Optional[Dict] = None) -> Dict[str, str]:
|
||||||
|
h = {"Content-Type": "application/json"}
|
||||||
|
if isinstance(headers, dict):
|
||||||
|
h.update(headers)
|
||||||
|
if provider == "openrouter":
|
||||||
|
h.setdefault("HTTP-Referer", "https://github.com/pewdiepie-archdaemon/odysseus")
|
||||||
|
h.setdefault("X-OpenRouter-Title", "Odysseus")
|
||||||
|
return h
|
||||||
|
|
||||||
|
|
||||||
def _provider_label(url: str) -> str:
|
def _provider_label(url: str) -> str:
|
||||||
"""Human-friendly provider name for error messages."""
|
"""Human-friendly provider name for error messages."""
|
||||||
u = (url or "").lower()
|
u = (url or "").lower()
|
||||||
@@ -423,7 +438,7 @@ def llm_call(url: str, model: str, messages: List[Dict], temperature: float = LL
|
|||||||
max_tokens: int = LLMConfig.DEFAULT_MAX_TOKENS, headers: Optional[Dict] = None,
|
max_tokens: int = LLMConfig.DEFAULT_MAX_TOKENS, headers: Optional[Dict] = None,
|
||||||
timeout: int = LLMConfig.DEFAULT_TIMEOUT, prompt_type: Optional[str] = None) -> str:
|
timeout: int = LLMConfig.DEFAULT_TIMEOUT, prompt_type: Optional[str] = None) -> str:
|
||||||
"""Synchronous LLM call with optional prompt type enhancement."""
|
"""Synchronous LLM call with optional prompt type enhancement."""
|
||||||
h = {"Content-Type": "application/json"}
|
h = _provider_headers(_detect_provider(url))
|
||||||
# Tolerate headers that arrive as a JSON string (some sessions stored them
|
# Tolerate headers that arrive as a JSON string (some sessions stored them
|
||||||
# double-encoded) — otherwise h.update() throws "dictionary update sequence
|
# double-encoded) — otherwise h.update() throws "dictionary update sequence
|
||||||
# element #0 has length 1; 2 is required".
|
# element #0 has length 1; 2 is required".
|
||||||
@@ -570,9 +585,7 @@ async def llm_call_async(
|
|||||||
payload = _build_anthropic_payload(model, messages_copy, temperature, max_tokens)
|
payload = _build_anthropic_payload(model, messages_copy, temperature, max_tokens)
|
||||||
else:
|
else:
|
||||||
target_url = url
|
target_url = url
|
||||||
h = {"Content-Type": "application/json"}
|
h = _provider_headers(provider, headers)
|
||||||
if headers:
|
|
||||||
h.update(headers)
|
|
||||||
payload = {
|
payload = {
|
||||||
"model": model,
|
"model": model,
|
||||||
"messages": messages_copy,
|
"messages": messages_copy,
|
||||||
@@ -667,16 +680,15 @@ async def stream_llm(url: str, model: str, messages: List[Dict], temperature: fl
|
|||||||
"messages": messages_copy,
|
"messages": messages_copy,
|
||||||
"temperature": temperature,
|
"temperature": temperature,
|
||||||
"stream": True,
|
"stream": True,
|
||||||
"stream_options": {"include_usage": True},
|
|
||||||
}
|
}
|
||||||
|
if provider not in {"openrouter", "groq"}:
|
||||||
|
payload["stream_options"] = {"include_usage": True}
|
||||||
if max_tokens and max_tokens > 0:
|
if max_tokens and max_tokens > 0:
|
||||||
tok_key = "max_completion_tokens" if _uses_max_completion_tokens(model) else "max_tokens"
|
tok_key = "max_completion_tokens" if _uses_max_completion_tokens(model) else "max_tokens"
|
||||||
payload[tok_key] = max_tokens
|
payload[tok_key] = max_tokens
|
||||||
if tools:
|
if tools:
|
||||||
payload["tools"] = tools
|
payload["tools"] = tools
|
||||||
h = {"Content-Type": "application/json"}
|
h = _provider_headers(provider, headers)
|
||||||
if headers:
|
|
||||||
h.update(headers)
|
|
||||||
|
|
||||||
# Short connect timeout: a reachable peer answers SYN in <100ms even on
|
# Short connect timeout: a reachable peer answers SYN in <100ms even on
|
||||||
# Tailscale. 3s is plenty; 30s let one dead upstream wedge the UI.
|
# Tailscale. 3s is plenty; 30s let one dead upstream wedge the UI.
|
||||||
|
|||||||
Reference in New Issue
Block a user