Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions desktop/src/renderer/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,9 @@ export function App() {
if (provider?.model) {
form.setValue("model", provider.model, { shouldValidate: true });
}
if (provider) {
form.setValue("apiBase", provider.apiBase, { shouldValidate: true });
}
return;
}

Expand All @@ -493,6 +496,9 @@ export function App() {
if (provider?.model) {
form.setValue("workerModel", provider.model, { shouldValidate: true });
}
if (provider) {
form.setValue("workerApiBase", provider.apiBase, { shouldValidate: true });
}
}

function toggleSearchProvider(providerId: "brave" | "firecrawl") {
Expand Down
33 changes: 22 additions & 11 deletions desktop/src/renderer/src/lib/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,26 @@ export function isExistingSecret(value: string | undefined | null): boolean {
}

export const providers = [
{ id: "openrouter", label: "OpenRouter", model: "anthropic/claude-sonnet-4" },
{ id: "zai", label: "Z.AI", model: "glm-4.6" },
{ id: "openai", label: "OpenAI", model: "gpt-5.2" },
{ id: "anthropic", label: "Anthropic", model: "claude-sonnet-4-5" },
{ id: "google", label: "Google Gemini", model: "gemini-2.5-pro" },
{ id: "mistral", label: "Mistral", model: "mistral-large-latest" },
{ id: "together", label: "Together AI", model: "meta-llama/Llama-3.3-70B-Instruct-Turbo" },
{ id: "groq", label: "Groq", model: "llama-3.3-70b-versatile" },
{ id: "custom", label: "Custom LiteLLM", model: "" },
{
id: "openrouter",
label: "OpenRouter",
model: "x-ai/grok-4.3",
apiBase: "https://openrouter.ai/api/v1",
},
{ id: "zai", label: "Z.AI", model: "glm-5.1", apiBase: "https://api.z.ai/api/coding/paas/v4" },
{ id: "openai", label: "OpenAI", model: "gpt-5.5", apiBase: "https://api.openai.com/v1" },
{ id: "anthropic", label: "Anthropic", model: "claude-opus-4-7", apiBase: "https://api.anthropic.com" },
{ id: "google", label: "Google Gemini", model: "gemini-3.1-pro-preview", apiBase: "" },
{ id: "mistral", label: "Mistral", model: "mistral-medium-3-5+1", apiBase: "https://api.mistral.ai/v1" },
{
id: "together",
label: "Together AI",
model: "moonshotai/Kimi-K2.5",
apiBase: "https://api.together.xyz/v1",
},
{ id: "groq", label: "Groq", model: "openai/gpt-oss-120b", apiBase: "https://api.groq.com/openai/v1" },
{ id: "minimax", label: "Minimax", model: "MiniMax-M2.7", apiBase: "https://api.minimax.io/anthropic/v1" },
{ id: "custom", label: "Custom LiteLLM", model: "", apiBase: "" },
] as const;

export const searchProviders = [
Expand Down Expand Up @@ -151,12 +162,12 @@ export const defaultInstallValues: InstallForm = {
whatsappMode: "separate",
whatsappAllowedNumbers: "",
providerId: "openrouter",
model: "anthropic/claude-sonnet-4",
model: "x-ai/grok-4.3",
apiKey: "",
apiBase: "",
sameWorker: false,
workerProviderId: "openrouter",
workerModel: "anthropic/claude-sonnet-4",
workerModel: "x-ai/grok-4.3",
workerApiKey: "",
workerApiBase: "",
searchProvider: undefined,
Expand Down
4 changes: 2 additions & 2 deletions src/octopal/infrastructure/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class Settings(BaseSettings):
# OpenRouter Settings (used via LiteLLM with openrouter/ model prefix)
openrouter_api_key: str | None = Field(default=None, alias="OPENROUTER_API_KEY")
openrouter_base_url: str = Field("https://openrouter.ai/api/v1", alias="OPENROUTER_BASE_URL")
openrouter_model: str = Field("anthropic/claude-sonnet-4", alias="OPENROUTER_MODEL")
openrouter_model: str = Field("x-ai/grok-4.3", alias="OPENROUTER_MODEL")
openrouter_timeout: float = Field(120.0, alias="OPENROUTER_TIMEOUT")

# Legacy ZAI Settings (used as defaults for LiteLLM)
Expand All @@ -58,7 +58,7 @@ class Settings(BaseSettings):
zai_timeout_seconds: float = Field(45.0, alias="ZAI_TIMEOUT_SECONDS")
zai_connect_timeout_seconds: float = Field(15.0, alias="ZAI_CONNECT_TIMEOUT_SECONDS")
zai_accept_language: str = Field("en-US,en", alias="ZAI_ACCEPT_LANGUAGE")
zai_model: str = Field("glm-5", alias="ZAI_MODEL")
zai_model: str = Field("glm-5.1", alias="ZAI_MODEL")

minimax_api_key: str | None = Field(default=None, alias="MINIMAX_API_KEY")

Expand Down
20 changes: 10 additions & 10 deletions src/octopal/infrastructure/providers/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class ProviderCatalogEntry:
id="openrouter",
label="OpenRouter",
description="Hosted model router with OpenRouter model ids.",
default_model="anthropic/claude-sonnet-4",
default_model="x-ai/grok-4.3",
model_prefix="openrouter",
always_prefix_model=True,
default_api_base="https://openrouter.ai/api/v1",
Expand All @@ -38,7 +38,7 @@ class ProviderCatalogEntry:
id="zai",
label="Z.ai (Coding plan)",
description="GLM and Coding Plan endpoints via OpenAI-compatible LiteLLM routing.",
default_model="glm-5",
default_model="glm-5.1",
model_prefix="openai",
default_api_base="https://api.z.ai/api/coding/paas/v4",
api_key_label="Z.ai API key",
Expand All @@ -49,7 +49,7 @@ class ProviderCatalogEntry:
id="openai",
label="OpenAI",
description="Direct OpenAI API access through LiteLLM.",
default_model="gpt-4.1-mini",
default_model="gpt-5.5",
model_prefix="openai",
default_api_base="https://api.openai.com/v1",
api_key_label="OpenAI API key",
Expand All @@ -60,7 +60,7 @@ class ProviderCatalogEntry:
id="anthropic",
label="Anthropic",
description="Direct Anthropic Messages API through LiteLLM.",
default_model="claude-sonnet-4-20250514",
default_model="claude-opus-4-7",
model_prefix="anthropic",
default_api_base="https://api.anthropic.com",
api_key_label="Anthropic API key",
Expand All @@ -71,7 +71,7 @@ class ProviderCatalogEntry:
id="google",
label="Google Gemini",
description="Gemini API via LiteLLM.",
default_model="gemini-2.0-flash",
default_model="gemini-3.1-pro-preview",
model_prefix="gemini",
default_api_base=None,
supports_custom_base_url=False,
Expand All @@ -82,7 +82,7 @@ class ProviderCatalogEntry:
id="mistral",
label="Mistral AI",
description="Hosted Mistral API.",
default_model="mistral-medium-latest",
default_model="mistral-medium-3-5+1",
model_prefix="mistral",
default_api_base="https://api.mistral.ai/v1",
api_key_label="Mistral API key",
Expand All @@ -93,7 +93,7 @@ class ProviderCatalogEntry:
id="together",
label="Together AI",
description="Hosted open-model access through Together AI.",
default_model="meta-llama/Llama-3.3-70B-Instruct-Turbo",
default_model="moonshotai/Kimi-K2.5",
model_prefix="together_ai",
default_api_base="https://api.together.xyz/v1",
api_key_label="Together API key",
Expand All @@ -104,7 +104,7 @@ class ProviderCatalogEntry:
id="groq",
label="Groq",
description="Fast hosted inference with OpenAI-compatible API surface.",
default_model="llama-3.3-70b-versatile",
default_model="openai/gpt-oss-120b",
model_prefix="groq",
default_api_base="https://api.groq.com/openai/v1",
api_key_label="Groq API key",
Expand All @@ -127,7 +127,7 @@ class ProviderCatalogEntry:
id="minimax",
label="Minimax (Token plan)",
description="MiniMax API (M2.5, M2.7, etc.) via LiteLLM.",
default_model="minimax-m2.5",
default_model="MiniMax-M2.7",
model_prefix="minimax",
default_api_base="https://api.minimax.io/anthropic/v1",
api_key_label="Minimax API key",
Expand All @@ -138,7 +138,7 @@ class ProviderCatalogEntry:
id="custom",
label="Custom OpenAI-compatible",
description="Any custom LiteLLM target with configurable base URL and model prefix.",
default_model="gpt-4.1-mini",
default_model="gpt-5.5",
model_prefix="openai",
default_api_base="http://localhost:8000/v1",
requires_api_key=False,
Expand Down
4 changes: 2 additions & 2 deletions tests/test_configure_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def test_configure_llm_keeps_existing_custom_base_url_for_same_provider(monkeypa
prompt_answers = iter(
[
"router-key",
"anthropic/claude-sonnet-4",
"x-ai/grok-4.3",
"https://custom.router/v1",
]
)
Expand Down Expand Up @@ -49,7 +49,7 @@ def fake_prompt_ask(message: str, default: str | None = None, password: bool = F
if message == "Minimax API key":
return "mini-key"
if message == "Minimax model":
return "minimax-m2.5"
return "MiniMax-M2.7"
if message == "Minimax base URL":
captured_defaults["base_url"] = default or ""
return default or ""
Expand Down
12 changes: 6 additions & 6 deletions tests/test_litellm_profile_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ def _base_settings(**overrides) -> Settings:
"litellm_rate_limit_base_delay_seconds": 1.0,
"litellm_rate_limit_max_delay_seconds": 30.0,
"openrouter_api_key": None,
"openrouter_model": "anthropic/claude-sonnet-4",
"openrouter_model": "x-ai/grok-4.3",
"openrouter_base_url": "https://openrouter.ai/api/v1",
"openrouter_timeout": 30.0,
"zai_api_key": None,
"zai_model": "glm-5",
"zai_model": "glm-5.1",
"zai_base_url": "https://api.z.ai/api/paas/v4/",
"zai_chat_path": "/chat/completions",
"zai_timeout_seconds": 45.0,
Expand Down Expand Up @@ -69,7 +69,7 @@ def test_resolver_falls_back_to_legacy_openrouter_mode() -> None:

assert profile.provider_id == "openrouter"
assert profile.source == "legacy"
assert profile.model == "openrouter/anthropic/claude-sonnet-4"
assert profile.model == "openrouter/x-ai/grok-4.3"
assert profile.api_key == "legacy-openrouter-key"


Expand All @@ -92,12 +92,12 @@ def test_resolver_supports_local_ollama_without_api_key() -> None:
def test_worker_override_does_not_inherit_octo_unified_api_key_for_other_provider() -> None:
settings = _base_settings(
litellm_provider_id="zai",
litellm_model="glm-5",
litellm_model="glm-5.1",
litellm_api_key="octo-zai-key",
openrouter_api_key=None,
config_obj=OctopalConfig(
llm=LLMConfig(provider_id="zai", model="glm-5", api_key="octo-zai-key"),
worker_llm_default=LLMConfig(provider_id="openrouter", model="anthropic/claude-sonnet-4"),
llm=LLMConfig(provider_id="zai", model="glm-5.1", api_key="octo-zai-key"),
worker_llm_default=LLMConfig(provider_id="openrouter", model="x-ai/grok-4.3"),
),
)

Expand Down
4 changes: 2 additions & 2 deletions tests/test_litellm_provider_payload_hardening.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ def _settings() -> Settings:
litellm_drop_params=True,
litellm_caching=False,
openrouter_api_key=None,
openrouter_model="anthropic/claude-sonnet-4",
openrouter_model="x-ai/grok-4.3",
openrouter_base_url="https://openrouter.ai/api/v1",
openrouter_timeout=30.0,
zai_api_key="z-test",
zai_model="glm-5",
zai_model="glm-5.1",
zai_base_url="https://api.z.ai/api/paas/v4/",
zai_chat_path="/chat/completions",
zai_timeout_seconds=45.0,
Expand Down
6 changes: 3 additions & 3 deletions tests/test_openrouter_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ def _settings(**overrides) -> Settings:
"litellm_drop_params": True,
"litellm_caching": False,
"openrouter_api_key": "router-key",
"openrouter_model": "anthropic/claude-sonnet-4",
"openrouter_model": "x-ai/grok-4.3",
"openrouter_base_url": "https://openrouter.ai/api/v1/",
"openrouter_timeout": 30.0,
"zai_api_key": None,
"zai_model": "glm-5",
"zai_model": "glm-5.1",
"zai_base_url": "https://api.z.ai/api/paas/v4/",
"zai_chat_path": "/chat/completions",
"zai_timeout_seconds": 45.0,
Expand Down Expand Up @@ -131,7 +131,7 @@ def test_complete_posts_expected_payload(monkeypatch) -> None:
assert call["base_url"] == "https://openrouter.ai/api/v1"
assert call["path"] == "/chat/completions"
assert call["headers"]["Authorization"] == "Bearer router-key"
assert call["json"]["model"] == "anthropic/claude-sonnet-4"
assert call["json"]["model"] == "x-ai/grok-4.3"
assert call["json"]["temperature"] == 0.7
assert call["json"]["messages"] == [{"role": "user", "content": "hello"}]

Expand Down
6 changes: 3 additions & 3 deletions tests/test_runtime_mcp_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -769,8 +769,8 @@ def grant_capabilities(self, capabilities):

settings = Settings(
config_obj=OctopalConfig(
llm=LLMConfig(provider_id="zai", model="glm-5"),
worker_llm_default=LLMConfig(provider_id="openrouter", model="anthropic/claude-sonnet-4"),
llm=LLMConfig(provider_id="zai", model="glm-5.1"),
worker_llm_default=LLMConfig(provider_id="openrouter", model="x-ai/grok-4.3"),
)
)
runtime = WorkerRuntime(
Expand All @@ -794,7 +794,7 @@ async def _fake_run(spec, approval_requester=None):

spec = captured["spec"]
assert spec.model is None
assert spec.llm_config.model == "anthropic/claude-sonnet-4"
assert spec.llm_config.model == "x-ai/grok-4.3"


def test_runtime_rejects_task_tool_override_that_widens_template(tmp_path: Path) -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_settings_config_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def test_load_settings_prefers_config_json_telegram_values(tmp_path, monkeypatch
},
"llm": {
"provider_id": "zai",
"model": "glm-5",
"model": "glm-5.1",
},
}
),
Expand Down