feat: add tool-call fallback and resilient batch exports

This commit is contained in:
chenmingxuan committed 2026-09-29 19:53:20 +08:00
1 parent ab066733b8
commit d31eb2a19d
32 files changed
+538 -72

No files matched your search

@@ -23,6 +23,13 @@ class ModelSettingsUpdate(BaseModel):
timeout_seconds: float = Field(default=300, gt=0, le=3600)
max_retries: int = Field(default=5, ge=0, le=10)
retry_interval_seconds: float = Field(default=10, ge=0, le=300)
rate_limit_retry_seconds: float | None = Field(default=None, ge=0, le=3600)
tool_fallback_model: str | None = Field(default=None, min_length=1, max_length=200)
tool_fallback_reasoning_effort: (
Literal["default", "none", "minimal", "low", "medium", "high", "xhigh", "max"] | None
) = None
tool_fallback_max_retries: int | None = Field(default=None, ge=0, le=10)
tool_fallback_no_progress_attempts: int | None = Field(default=None, ge=1, le=10)
reasoning_effort: Literal[
"default", "none", "minimal", "low", "medium", "high", "xhigh", "max"
] = "high"
@@ -45,9 +52,11 @@ class ModelSettingsUpdate(BaseModel):
raise ValueError("请输入接口根地址,例如 https://api-n-cd.playones.com/v1")
return value
@field_validator("model")
@field_validator("model", "tool_fallback_model")
@classmethod
def validate_model(cls, value: str) -> str:
def validate_model(cls, value: str | None) -> str | None:
if value is None:
return None
value = value.strip()
if not value or any(c in value for c in "\r\n\x00"):
raise ValueError("模型名称不能为空或包含换行")
@@ -64,6 +73,11 @@ def get_model_settings() -> dict:
"timeout_seconds": settings.OPENAI_TIMEOUT_SECONDS,
"max_retries": settings.OPENAI_MAX_RETRIES,
"retry_interval_seconds": settings.OPENAI_RETRY_INTERVAL_SECONDS,
"rate_limit_retry_seconds": settings.OPENAI_RATE_LIMIT_RETRY_SECONDS,
"tool_fallback_model": settings.OPENAI_TOOL_FALLBACK_MODEL,
"tool_fallback_reasoning_effort": settings.OPENAI_TOOL_FALLBACK_REASONING_EFFORT,
"tool_fallback_max_retries": settings.OPENAI_TOOL_FALLBACK_MAX_RETRIES,
"tool_fallback_no_progress_attempts": settings.ARTEMIS_TOOL_FALLBACK_MAX_NO_PROGRESS_ATTEMPTS,
"reasoning_effort": settings.OPENAI_REASONING_EFFORT,
"model_presets": [
"gpt-5.6-luna",
@@ -86,6 +100,20 @@ def save_model_settings(update: ModelSettingsUpdate) -> dict:
"OPENAI_RETRY_INTERVAL_SECONDS": str(update.retry_interval_seconds),
"OPENAI_REASONING_EFFORT": update.reasoning_effort,
}
optional_settings = {
"rate_limit_retry_seconds": ("OPENAI_RATE_LIMIT_RETRY_SECONDS", float),
"tool_fallback_model": ("OPENAI_TOOL_FALLBACK_MODEL", str),
"tool_fallback_reasoning_effort": ("OPENAI_TOOL_FALLBACK_REASONING_EFFORT", str),
"tool_fallback_max_retries": ("OPENAI_TOOL_FALLBACK_MAX_RETRIES", int),
"tool_fallback_no_progress_attempts": (
"ARTEMIS_TOOL_FALLBACK_MAX_NO_PROGRESS_ATTEMPTS",
int,
),
}
for field_name, (env_name, expected_type) in optional_settings.items():
value = getattr(update, field_name)
if value is not None:
values[env_name] = str(value)
if update.api_key and update.api_key.get_secret_value().strip():
values["OPENAI_API_KEY"] = update.api_key.get_secret_value().strip()
persist_environment(values)
@@ -95,6 +123,10 @@ def save_model_settings(update: ModelSettingsUpdate) -> dict:
settings.OPENAI_MAX_RETRIES = update.max_retries
settings.OPENAI_RETRY_INTERVAL_SECONDS = update.retry_interval_seconds
settings.OPENAI_REASONING_EFFORT = update.reasoning_effort
for field_name, (env_name, expected_type) in optional_settings.items():
value = getattr(update, field_name)
if value is not None:
setattr(settings, env_name, expected_type(value))
if "OPENAI_API_KEY" in values:
settings.OPENAI_API_KEY = SecretStr(values["OPENAI_API_KEY"])
from artemis.llm.router import ModelFactory