fix(bourse): register provider and enable tool calling

Addresses the Greptile review on #43675.

- Add BOURSE to LlmProviders so code paths that build
  LlmProviders(custom_llm_provider) resolve instead of raising.
- Add "bourse" to openai_compatible_providers, like the other
  JSON-configured providers.
- Set provider_info.supports_function_calling so requests with tools
  are not dropped for models missing from the cost map.
- Use distinct names in test_bourse_dynamic_config instead of
  reassigning locals, and add tests for the registration and tools.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
glatinone 2026-10-30 22:32:14 +08:00
parent 40f662feab
commit 92fe66b80e
4 changed files with 27 additions and 5 deletions

View file

@ -1165,6 +1165,7 @@ openai_compatible_providers: Final[list[str]] = [
"sail",
"reka",
"streamlake",
"bourse",
]
OPENAI_AUDIO_TRANSCRIPTION_PROVIDERS: Final = frozenset({"openai"} | frozenset(openai_compatible_providers))

View file

@ -299,6 +299,9 @@
"api_base_env": "BOURSE_API_BASE",
"param_mappings": {
"max_completion_tokens": "max_tokens"
},
"provider_info": {
"supports_function_calling": true
}
}
}

View file

@ -4638,6 +4638,7 @@ class LlmProviders(str, Enum):
OPENINFER = "openinfer"
INFERENCEAPIS = "inferenceapis"
ZEROGPU = "zerogpu"
BOURSE = "bourse"
DARKBLOOM = "darkbloom"
META = "meta"
SAIL = "sail"

View file

@ -344,14 +344,14 @@ class TestBourse:
config_class = create_config_class(provider)
config = config_class()
api_base, api_key = config._get_openai_compatible_provider_info(None, None)
assert api_base == "https://api.bourse.run/v1"
default_base, _ = config._get_openai_compatible_provider_info(None, None)
assert default_base == "https://api.bourse.run/v1"
api_base, api_key = config._get_openai_compatible_provider_info(
custom_base, custom_key = config._get_openai_compatible_provider_info(
"https://custom.bourse.run/v1", "test-key"
)
assert api_base == "https://custom.bourse.run/v1"
assert api_key == "test-key"
assert custom_base == "https://custom.bourse.run/v1"
assert custom_key == "test-key"
def test_bourse_complete_url_appends_endpoint(self):
from litellm.llms.openai_like.dynamic_config import create_config_class
@ -390,3 +390,20 @@ class TestBourse:
assert result["max_tokens"] == 100
assert "max_completion_tokens" not in result
assert result["temperature"] == 0.7
def test_bourse_registered_as_openai_compatible(self):
import litellm
from litellm.types.utils import LlmProviders
assert LlmProviders("bourse") == LlmProviders.BOURSE
assert "bourse" in litellm.openai_compatible_providers
def test_bourse_accepts_tools(self):
from litellm.utils import get_optional_params
tools = [{"type": "function", "function": {"name": "lookup", "parameters": {}}}]
params = get_optional_params(
model="claude-opus-5", custom_llm_provider="bourse", tools=tools
)
assert params["tools"] == tools