mirror of
https://github.com/usestrix/strix.git
synced 2026-09-26 01:11:25 +00:00
Add custom headers from the env var LLM_EXTRA_HEADERS
This commit is contained in:
parent
6b9bd4d5f2
commit
3a5e0439a7
7 changed files with 69 additions and 9 deletions
|
|
@ -35,6 +35,11 @@ Configure Strix using environment variables or a config file.
|
|||
Timeout in seconds for memory compression operations (context summarization).
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="LLM_EXTRA_HEADERS" type="string">
|
||||
Custom HTTP headers to include in every LiteLLM request. Accepts a JSON object,
|
||||
e.g. `{"x-my-header": "value"}`.
|
||||
</ParamField>
|
||||
|
||||
## Optional Features
|
||||
|
||||
<ParamField path="PERPLEXITY_API_KEY" type="string">
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class Config:
|
|||
openai_api_base = None
|
||||
litellm_base_url = None
|
||||
ollama_api_base = None
|
||||
llm_extra_headers = None
|
||||
strix_reasoning_effort = "high"
|
||||
strix_llm_max_retries = "5"
|
||||
strix_memory_compressor_timeout = "30"
|
||||
|
|
@ -29,6 +30,7 @@ class Config:
|
|||
"openai_api_base",
|
||||
"litellm_base_url",
|
||||
"ollama_api_base",
|
||||
"llm_extra_headers",
|
||||
"strix_reasoning_effort",
|
||||
"strix_llm_max_retries",
|
||||
"strix_memory_compressor_timeout",
|
||||
|
|
@ -196,18 +198,20 @@ def save_current_config() -> bool:
|
|||
return Config.save_current()
|
||||
|
||||
|
||||
def resolve_llm_config() -> tuple[str | None, str | None, str | None]:
|
||||
"""Resolve LLM model, api_key, and api_base based on STRIX_LLM prefix.
|
||||
def resolve_llm_config() -> tuple[str | None, str | None, str | None, dict[str, str] | None]:
|
||||
"""Resolve LLM model, api_key, api_base based on STRIX_LLM prefix
|
||||
and extra_headers for LiteLLM calls.
|
||||
|
||||
Returns:
|
||||
tuple: (model_name, api_key, api_base)
|
||||
tuple: (model_name, api_key, api_base, extra_headers)
|
||||
- model_name: Original model name (strix/ prefix preserved for display)
|
||||
- api_key: LLM API key
|
||||
- api_base: API base URL (auto-set to STRIX_API_BASE for strix/ models)
|
||||
- extra_headers : Custom headers
|
||||
"""
|
||||
model = Config.get("strix_llm")
|
||||
if not model:
|
||||
return None, None, None
|
||||
return None, None, None, None
|
||||
|
||||
api_key = Config.get("llm_api_key")
|
||||
|
||||
|
|
@ -221,4 +225,16 @@ def resolve_llm_config() -> tuple[str | None, str | None, str | None]:
|
|||
or Config.get("ollama_api_base")
|
||||
)
|
||||
|
||||
return model, api_key, api_base
|
||||
extra_headers: dict[str, str] = {}
|
||||
raw_headers = Config.get("llm_extra_headers") or ""
|
||||
if raw_headers.strip():
|
||||
try:
|
||||
parsed = json.loads(raw_headers)
|
||||
if isinstance(parsed, dict):
|
||||
extra_headers = {str(k): str(v) for k, v in parsed.items() if v is not None}
|
||||
else:
|
||||
raise TypeError("LLM_EXTRA_HEADERS must be a JSON object")
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(f"Invalid LLM_EXTRA_HEADERS JSON: {e}") from e
|
||||
|
||||
return model, api_key, api_base, extra_headers
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ Strix Agent Interface
|
|||
|
||||
import argparse
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
|
|
@ -82,6 +83,36 @@ def validate_environment() -> None: # noqa: PLR0912, PLR0915
|
|||
if not Config.get("strix_reasoning_effort"):
|
||||
missing_optional_vars.append("STRIX_REASONING_EFFORT")
|
||||
|
||||
raw_headers = Config.get("llm_extra_headers") or ""
|
||||
if raw_headers.strip():
|
||||
try:
|
||||
parsed = json.loads(raw_headers)
|
||||
if not isinstance(parsed, dict):
|
||||
raise TypeError("LLM_EXTRA_HEADERS must be a JSON object, got a non-dict value")
|
||||
except (json.JSONDecodeError, ValueError) as e:
|
||||
error_text = Text()
|
||||
error_text.append("INVALID LLM_EXTRA_HEADERS", style="bold red")
|
||||
error_text.append("\n\n", style="white")
|
||||
error_text.append("LLM_EXTRA_HEADERS must be a valid JSON object.\n", style="white")
|
||||
error_text.append(f"Error: {e}\n", style="white")
|
||||
error_text.append("\nExample:\n", style="white")
|
||||
error_text.append(
|
||||
'export LLM_EXTRA_HEADERS={"x-my-header": "value"}\n',
|
||||
style="dim white",
|
||||
)
|
||||
|
||||
panel = Panel(
|
||||
error_text,
|
||||
title="[bold white]STRIX",
|
||||
title_align="left",
|
||||
border_style="red",
|
||||
padding=(1, 2),
|
||||
)
|
||||
console.print("\n")
|
||||
console.print(panel)
|
||||
console.print()
|
||||
sys.exit(1)
|
||||
|
||||
if missing_required_vars:
|
||||
error_text = Text()
|
||||
error_text.append("MISSING REQUIRED ENVIRONMENT VARIABLES", style="bold red")
|
||||
|
|
@ -208,7 +239,7 @@ async def warm_up_llm() -> None:
|
|||
console = Console()
|
||||
|
||||
try:
|
||||
model_name, api_key, api_base = resolve_llm_config()
|
||||
model_name, api_key, api_base, extra_headers = resolve_llm_config()
|
||||
litellm_model, _ = resolve_strix_model(model_name)
|
||||
litellm_model = litellm_model or model_name
|
||||
|
||||
|
|
@ -228,6 +259,8 @@ async def warm_up_llm() -> None:
|
|||
completion_kwargs["api_key"] = api_key
|
||||
if api_base:
|
||||
completion_kwargs["api_base"] = api_base
|
||||
if extra_headers:
|
||||
completion_kwargs["extra_headers"] = extra_headers
|
||||
|
||||
response = litellm.completion(**completion_kwargs)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class LLMConfig:
|
|||
reasoning_effort: str | None = None,
|
||||
system_prompt_context: dict[str, Any] | None = None,
|
||||
):
|
||||
resolved_model, self.api_key, self.api_base = resolve_llm_config()
|
||||
resolved_model, self.api_key, self.api_base, self.extra_headers = resolve_llm_config()
|
||||
self.model_name = model_name or resolved_model
|
||||
|
||||
if not self.model_name:
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ def check_duplicate(
|
|||
|
||||
comparison_data = {"candidate": candidate_cleaned, "existing_reports": existing_cleaned}
|
||||
|
||||
model_name, api_key, api_base = resolve_llm_config()
|
||||
model_name, api_key, api_base, extra_headers = resolve_llm_config()
|
||||
litellm_model, _ = resolve_strix_model(model_name)
|
||||
litellm_model = litellm_model or model_name
|
||||
|
||||
|
|
@ -181,6 +181,8 @@ def check_duplicate(
|
|||
completion_kwargs["api_key"] = api_key
|
||||
if api_base:
|
||||
completion_kwargs["api_base"] = api_base
|
||||
if extra_headers:
|
||||
completion_kwargs["extra_headers"] = extra_headers
|
||||
|
||||
response = litellm.completion(**completion_kwargs)
|
||||
|
||||
|
|
|
|||
|
|
@ -286,6 +286,8 @@ class LLM:
|
|||
args["api_key"] = self.config.api_key
|
||||
if self.config.api_base:
|
||||
args["api_base"] = self.config.api_base
|
||||
if self.config.extra_headers:
|
||||
args["extra_headers"] = self.config.extra_headers
|
||||
if self._supports_reasoning():
|
||||
args["reasoning_effort"] = self._reasoning_effort
|
||||
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ def _summarize_messages(
|
|||
conversation = "\n".join(formatted)
|
||||
prompt = SUMMARY_PROMPT_TEMPLATE.format(conversation=conversation)
|
||||
|
||||
_, api_key, api_base = resolve_llm_config()
|
||||
_, api_key, api_base, extra_headers = resolve_llm_config()
|
||||
|
||||
try:
|
||||
completion_args: dict[str, Any] = {
|
||||
|
|
@ -116,6 +116,8 @@ def _summarize_messages(
|
|||
completion_args["api_key"] = api_key
|
||||
if api_base:
|
||||
completion_args["api_base"] = api_base
|
||||
if extra_headers:
|
||||
completion_args["extra_headers"] = extra_headers
|
||||
|
||||
response = litellm.completion(**completion_args)
|
||||
summary = response.choices[0].message.content or ""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue