Merge origin/main into codex/align-codex-provider-conventions-mainrepo

This commit is contained in:
George Pickett
2026-02-25 19:28:44 -08:00
5 changed files with 40 additions and 1 deletions

View File

@@ -35,6 +35,14 @@ _OR_HEADERS = {
"X-OpenRouter-Categories": "cli-agent",
}
# Nous Portal extra_body for product attribution.
# Callers should pass this as extra_body in chat.completions.create()
# when the auxiliary client is backed by Nous Portal.
NOUS_EXTRA_BODY = {"tags": ["product=hermes-agent"]}
# Set at resolve time — True if the auxiliary client points to Nous Portal
auxiliary_is_nous: bool = False
# Default auxiliary models per provider
_OPENROUTER_MODEL = "google/gemini-3-flash-preview"
_NOUS_MODEL = "gemini-3-flash"
@@ -91,6 +99,8 @@ def get_text_auxiliary_client() -> Tuple[Optional[OpenAI], Optional[str]]:
# 2. Nous Portal
nous = _read_nous_auth()
if nous:
global auxiliary_is_nous
auxiliary_is_nous = True
logger.debug("Auxiliary text client: Nous Portal")
return (
OpenAI(api_key=_nous_api_key(nous), base_url=_nous_base_url()),
@@ -135,3 +145,12 @@ def get_vision_auxiliary_client() -> Tuple[Optional[OpenAI], Optional[str]]:
# 3. Nothing suitable
logger.debug("Auxiliary vision client: none available")
return None, None
def get_auxiliary_extra_body() -> dict:
"""Return extra_body kwargs for auxiliary API calls.
Includes Nous Portal product tags when the auxiliary client is backed
by Nous Portal. Returns empty dict otherwise.
"""
return dict(NOUS_EXTRA_BODY) if auxiliary_is_nous else {}

View File

@@ -25,7 +25,15 @@ def get_async_client() -> AsyncOpenAI:
api_key = os.getenv("OPENROUTER_API_KEY")
if not api_key:
raise ValueError("OPENROUTER_API_KEY environment variable not set")
_client = AsyncOpenAI(api_key=api_key, base_url=OPENROUTER_BASE_URL)
_client = AsyncOpenAI(
api_key=api_key,
base_url=OPENROUTER_BASE_URL,
default_headers={
"HTTP-Referer": "https://github.com/NousResearch/hermes-agent",
"X-OpenRouter-Title": "Hermes Agent",
"X-OpenRouter-Categories": "cli-agent",
},
)
return _client

View File

@@ -170,12 +170,15 @@ async def _summarize_session(
max_retries = 3
for attempt in range(max_retries):
try:
from agent.auxiliary_client import get_auxiliary_extra_body
_extra = get_auxiliary_extra_body()
response = await _async_aux_client.chat.completions.create(
model=_SUMMARIZER_MODEL,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
**({} if not _extra else {"extra_body": _extra}),
temperature=0.1,
max_tokens=MAX_SUMMARY_TOKENS,
)

View File

@@ -314,11 +314,14 @@ async def vision_analyze_tool(
logger.info("Processing image with %s...", model)
# Call the vision API
from agent.auxiliary_client import get_auxiliary_extra_body
_extra = get_auxiliary_extra_body()
response = await _aux_async_client.chat.completions.create(
model=model,
messages=messages,
temperature=0.1,
max_tokens=2000,
**({} if not _extra else {"extra_body": _extra}),
)
# Extract the analysis

View File

@@ -242,6 +242,8 @@ Create a markdown summary that captures all key information in a well-organized,
if _aux_async_client is None:
logger.warning("No auxiliary model available for web content processing")
return None
from agent.auxiliary_client import get_auxiliary_extra_body
_extra = get_auxiliary_extra_body()
response = await _aux_async_client.chat.completions.create(
model=model,
messages=[
@@ -250,6 +252,7 @@ Create a markdown summary that captures all key information in a well-organized,
],
temperature=0.1,
max_tokens=max_tokens,
**({} if not _extra else {"extra_body": _extra}),
)
return response.choices[0].message.content.strip()
except Exception as api_error:
@@ -362,6 +365,8 @@ Create a single, unified markdown summary."""
fallback = fallback[:max_output_size] + "\n\n[... truncated ...]"
return fallback
from agent.auxiliary_client import get_auxiliary_extra_body
_extra = get_auxiliary_extra_body()
response = await _aux_async_client.chat.completions.create(
model=model,
messages=[
@@ -370,6 +375,7 @@ Create a single, unified markdown summary."""
],
temperature=0.1,
max_tokens=4000,
**({} if not _extra else {"extra_body": _extra}),
)
final_summary = response.choices[0].message.content.strip()