fix(cli): honor env precedence for LLM and run config
Interactive selections and flag defaults overrode TRADINGAGENTS_* env vars. Rule: an explicit env value or CLI flag wins; otherwise the env-applied default is kept. - Research depth: skip the prompt when both round-count env vars are set, and stop overwriting them (#977). - Checkpoint: --checkpoint/--no-checkpoint is tri-state; omitting it keeps TRADINGAGENTS_CHECKPOINT_ENABLED (#976). - Docker ollama: use TRADINGAGENTS_LLM_PROVIDER + OLLAMA_BASE_URL, not a bare LLM_PROVIDER the overlay never reads (#975). - Reasoning/thinking knobs: settable via env; the prompt is skipped when set. - Effort gating: forward effort only to models that accept it (Anthropic Opus 4.5+/Sonnet 4.6+, OpenAI reasoning models); drop it elsewhere. - Boolean env values: raise a named error on invalid input instead of silently becoming False.
This commit is contained in:
11 files changed
+363
-59
No files matched your search
@@ -12,20 +12,27 @@ _PASSTHROUGH_KWARGS = (
|
||||
)
|
||||
|
||||
# Anthropic's extended-thinking ``effort`` parameter is accepted by Opus 4.5+
|
||||
# and Sonnet 4.5+ only. Haiku (any version shipped to date) 400s with
|
||||
# ``"This model does not support the effort parameter"`` (#831). Future
|
||||
# ``claude-{opus,sonnet}-X-Y`` releases inherit effort support via the
|
||||
# forward-compat pattern below; future Haiku stays excluded by default.
|
||||
# and Sonnet 4.6+ only. Sonnet 4.5 and any Haiku version 400 with
|
||||
# ``"This model does not support the effort parameter"`` (#831). The per-family
|
||||
# minimum version below is forward-compatible: future ``claude-{opus,sonnet}-X-Y``
|
||||
# releases inherit support automatically, while Sonnet 4.5 and Haiku stay excluded.
|
||||
_EFFORT_EXACT = {
|
||||
"claude-mythos-preview", # non-standard preview name; effort-capable
|
||||
}
|
||||
_EFFORT_PATTERN = re.compile(r"^claude-(opus|sonnet)-\d+-\d+$")
|
||||
_EFFORT_MODEL = re.compile(r"^claude-(opus|sonnet)-(\d+)-(\d+)$")
|
||||
_EFFORT_MIN_VERSION = {"opus": (4, 5), "sonnet": (4, 6)}
|
||||
|
||||
|
||||
def _supports_effort(model: str) -> bool:
|
||||
"""Whether Anthropic accepts the ``effort`` parameter for this model."""
|
||||
model_lc = model.lower()
|
||||
return model_lc in _EFFORT_EXACT or bool(_EFFORT_PATTERN.match(model_lc))
|
||||
if model_lc in _EFFORT_EXACT:
|
||||
return True
|
||||
match = _EFFORT_MODEL.match(model_lc)
|
||||
if not match:
|
||||
return False
|
||||
family, major, minor = match.group(1), int(match.group(2)), int(match.group(3))
|
||||
return (major, minor) >= _EFFORT_MIN_VERSION[family]
|
||||
|
||||
|
||||
class NormalizedChatAnthropic(ChatAnthropic):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
from urllib.parse import urlparse
|
||||
@@ -150,6 +151,18 @@ _PASSTHROUGH_KWARGS = (
|
||||
"api_key", "callbacks", "http_client", "http_async_client",
|
||||
)
|
||||
|
||||
# OpenAI's ``reasoning_effort`` is only accepted by reasoning models — the GPT-5
|
||||
# family and the o-series. Non-reasoning models (gpt-4.1, gpt-4o, ...) 400 with
|
||||
# "Unsupported parameter: 'reasoning.effort' is not supported with this model".
|
||||
# Drop the kwarg for those rather than crash the run.
|
||||
_OPENAI_REASONING_MODEL = re.compile(r"^(gpt-5|o[1-9])")
|
||||
|
||||
|
||||
def _supports_reasoning_effort(model: str) -> bool:
|
||||
"""Whether the (native OpenAI) model accepts ``reasoning_effort``."""
|
||||
return bool(_OPENAI_REASONING_MODEL.match(model.lower().strip()))
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ProviderSpec:
|
||||
"""Declarative config for one OpenAI-compatible provider.
|
||||
@@ -291,8 +304,11 @@ class OpenAIClient(BaseLLMClient):
|
||||
|
||||
# Forward user-provided kwargs
|
||||
for key in _PASSTHROUGH_KWARGS:
|
||||
if key in self.kwargs:
|
||||
llm_kwargs[key] = self.kwargs[key]
|
||||
if key not in self.kwargs:
|
||||
continue
|
||||
if key == "reasoning_effort" and not _supports_reasoning_effort(self.model):
|
||||
continue
|
||||
llm_kwargs[key] = self.kwargs[key]
|
||||
|
||||
# The subclass (provider quirks) comes from the registry spec.
|
||||
return chat_cls(**llm_kwargs)
|
||||
|
||||
Reference in new issue
Block a user