Compare commits

...

1 Commits

5 changed files with 32 additions and 2 deletions

View File

@@ -23,6 +23,7 @@ export const MAP_PROVIDER = {
replicate: "Replicate",
voyage: "Voyage AI",
openrouter: "OpenRouter",
openhands: "OpenHands",
};
export const mapProvider = (provider: string) =>

View File

@@ -1,5 +1,5 @@
// Here are the list of verified models and providers that we know work well with OpenHands.
export const VERIFIED_PROVIDERS = ["openai", "azure", "anthropic", "deepseek"];
export const VERIFIED_PROVIDERS = ["openai", "azure", "anthropic", "deepseek", "openhands"];
export const VERIFIED_MODELS = [
"o3-mini-2025-01-31",
"o3-2025-04-16",
@@ -8,6 +8,8 @@ export const VERIFIED_MODELS = [
"claude-3-7-sonnet-20250219",
"claude-sonnet-4-20250514",
"claude-opus-4-20250514",
"gemini-2.5-pro",
"o4-mini",
"deepseek-chat",
];

View File

@@ -15,6 +15,7 @@ from openhands.cli.utils import (
VERIFIED_ANTHROPIC_MODELS,
VERIFIED_MISTRAL_MODELS,
VERIFIED_OPENAI_MODELS,
VERIFIED_OPENHANDS_MODELS,
VERIFIED_PROVIDERS,
organize_models_and_providers,
)
@@ -234,6 +235,11 @@ async def modify_llm_settings_basic(
m for m in provider_models if m not in VERIFIED_MISTRAL_MODELS
]
provider_models = VERIFIED_MISTRAL_MODELS + provider_models
if provider == 'openhands':
provider_models = [
m for m in provider_models if m not in VERIFIED_OPENHANDS_MODELS
]
provider_models = VERIFIED_OPENHANDS_MODELS + provider_models
# Set default model to the best verified model for the provider
if provider == 'anthropic' and VERIFIED_ANTHROPIC_MODELS:
@@ -245,6 +251,9 @@ async def modify_llm_settings_basic(
elif provider == 'mistral' and VERIFIED_MISTRAL_MODELS:
# Use the first model in the VERIFIED_MISTRAL_MODELS list as it's the best/newest
default_model = VERIFIED_MISTRAL_MODELS[0]
elif provider == 'openhands' and VERIFIED_OPENHANDS_MODELS:
# Use the first model in the VERIFIED_OPENHANDS_MODELS list as it's the best/newest
default_model = VERIFIED_OPENHANDS_MODELS[0]
else:
# For other providers, use the first model in the list
default_model = (

View File

@@ -104,6 +104,8 @@ def extract_model_and_provider(model: str) -> ModelInfo:
return ModelInfo(provider='anthropic', model=split[0], separator='/')
if split[0] in VERIFIED_MISTRAL_MODELS:
return ModelInfo(provider='mistral', model=split[0], separator='/')
if split[0] in VERIFIED_OPENHANDS_MODELS:
return ModelInfo(provider='openhands', model=split[0], separator='/')
# return as model only
return ModelInfo(provider='', model=model, separator='')
@@ -145,7 +147,7 @@ def organize_models_and_providers(
return result_dict
VERIFIED_PROVIDERS = ['anthropic', 'openai', 'mistral']
VERIFIED_PROVIDERS = ['anthropic', 'openai', 'mistral', 'openhands']
VERIFIED_OPENAI_MODELS = [
'o4-mini',
@@ -178,6 +180,13 @@ VERIFIED_MISTRAL_MODELS = [
'devstral-small-2505',
]
VERIFIED_OPENHANDS_MODELS = [
'claude-sonnet-4-20250514',
'claude-opus-4-20250514',
'gemini-2.5-pro',
'o4-mini',
]
class ProviderInfo(BaseModel):
"""Information about a provider and its models."""

View File

@@ -170,6 +170,15 @@ class LLM(RetryMixin, DebugMixin):
# litellm will handle it a bit differently than the openai-compatible params
kwargs['top_k'] = self.config.top_k
# Handle OpenHands provider - rewrite to litellm_proxy
if self.config.model.startswith('openhands/'):
model_name = self.config.model.removeprefix('openhands/')
self.config.model = f'litellm_proxy/{model_name}'
self.config.base_url = 'https://llm-proxy.app.all-hands.dev/'
logger.debug(
f'Rewrote openhands/{model_name} to {self.config.model} with base URL {self.config.base_url}'
)
if (
self.config.model.lower() in REASONING_EFFORT_SUPPORTED_MODELS
or self.config.model.split('/')[-1] in REASONING_EFFORT_SUPPORTED_MODELS