Skip to content
Open
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
24 changes: 24 additions & 0 deletions plugins/model-providers/evolink/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""EvoLink provider profile."""

from providers import register_provider
from providers.base import ProviderProfile

evolink = ProviderProfile(
name="evolink",
aliases=("evolink-ai", "evolinkai", "evo-link", "evo_link"),
display_name="EvoLink",
description="EvoLink (OpenAI-compatible multi-model API)",
signup_url="https://evolink.ai/dashboard/keys",
env_vars=("EVOLINK_API_KEY", "EVOLINK_BASE_URL"),
base_url="https://direct.evolink.ai/v1",
auth_type="api_key",
default_aux_model="gpt-5.2",
fallback_models=(
"gpt-5.2",
"gpt-5.1",
"gemini-3.1-flash-lite-preview",
"deepseek-v4-flash",
),
)

register_provider(evolink)
5 changes: 5 additions & 0 deletions plugins/model-providers/evolink/plugin.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: evolink-provider
kind: model-provider
version: 1.0.0
description: EvoLink OpenAI-compatible multi-model API
author: EvoLinkAI
8 changes: 4 additions & 4 deletions tests/providers/test_plugin_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,19 @@ def test_bundled_plugins_discovered():
assert (child / "plugin.yaml").exists(), f"{child.name} missing plugin.yaml"


def test_all_34_profiles_register():
"""After discovery, the registry must contain exactly 34 distinct profiles."""
def test_all_35_profiles_register():
"""After discovery, the registry must contain exactly 35 distinct profiles."""
_clear_provider_caches()
from providers import list_providers

profiles = list_providers()
names = sorted(p.name for p in profiles)
assert len(names) == 34, f"Expected 34 profiles, got {len(names)}: {names}"
assert len(names) == 35, f"Expected 35 profiles, got {len(names)}: {names}"

# Spot-check representative providers from different categories
for required in (
"openrouter", "anthropic", "custom", "bedrock", "openai-codex",
"minimax-oauth", "gmi", "xiaomi", "alibaba-coding-plan",
"minimax-oauth", "gmi", "xiaomi", "alibaba-coding-plan", "evolink",
):
assert required in names, f"Missing profile: {required}"

Expand Down
22 changes: 22 additions & 0 deletions tests/providers/test_provider_profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,28 @@ def test_grok_reasoning_and_header_together(self):
assert tl["extra_headers"]["x-grok-conv-id"] == "sess-123"


class TestEvoLinkProfile:
def test_profile_defaults(self):
p = get_provider_profile("evolink")
assert p is not None
assert p.display_name == "EvoLink"
assert p.base_url == "https://direct.evolink.ai/v1"
assert p.env_vars == ("EVOLINK_API_KEY", "EVOLINK_BASE_URL")
assert p.default_aux_model == "gpt-5.2"
assert p.fallback_models == (
"gpt-5.2",
"gpt-5.1",
"gemini-3.1-flash-lite-preview",
"deepseek-v4-flash",
)

def test_aliases(self):
assert get_provider_profile("evolink-ai").name == "evolink"
assert get_provider_profile("evolinkai").name == "evolink"
assert get_provider_profile("evo-link").name == "evolink"
assert get_provider_profile("evo_link").name == "evolink"


class TestNousProfile:
def test_tags(self):
from agent.portal_tags import nous_portal_tags
Expand Down