mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
Merge 7baadbbb34 into 5085022580
This commit is contained in:
commit
6c30712128
15 changed files with 218 additions and 0 deletions
|
|
@ -393,6 +393,7 @@ Set `LITELLM_PROXY_API_BASE` and `LITELLM_PROXY_API_KEY` and every model call th
|
|||
| [Dashscope (`dashscope`)](https://docs.litellm.ai/docs/providers/dashscope) | ✅ | ✅ | ✅ | ✅ | | | | | | ✅ |
|
||||
| [Databricks (`databricks`)](https://docs.litellm.ai/docs/providers/databricks) | ✅ | ✅ | ✅ | | | | | | | |
|
||||
| [DataRobot (`datarobot`)](https://docs.litellm.ai/docs/providers/datarobot) | ✅ | ✅ | ✅ | | | | | | | |
|
||||
| [Decision Models (`decisionmodels`)](https://decisionmodels.io) | | | | | | | | | | |
|
||||
| [Deepgram (`deepgram`)](https://docs.litellm.ai/docs/providers/deepgram) | ✅ | ✅ | ✅ | | | ✅ | | | | |
|
||||
| [DeepInfra (`deepinfra`)](https://docs.litellm.ai/docs/providers/deepinfra) | ✅ | ✅ | ✅ | | | | | | | |
|
||||
| [Deepseek (`deepseek`)](https://docs.litellm.ai/docs/providers/deepseek) | ✅ | ✅ | ✅ | | | | | | | |
|
||||
|
|
|
|||
|
|
@ -1763,6 +1763,9 @@ if TYPE_CHECKING:
|
|||
from .llms.parallel_ai.decisions.transformation import (
|
||||
ParallelAIDecisionsConfig as ParallelAIDecisionsConfig,
|
||||
)
|
||||
from .llms.decisionmodels.decisions.transformation import (
|
||||
DecisionModelsDecisionsConfig as DecisionModelsDecisionsConfig,
|
||||
)
|
||||
from .llms.openrouter.decisions.transformation import (
|
||||
OpenRouterDecisionsConfig as OpenRouterDecisionsConfig,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@ LLM_CONFIG_NAMES: Final = (
|
|||
"TypeSafeDecisionsConfig",
|
||||
"ParallelAIDecisionsConfig",
|
||||
"NaceDecisionsConfig",
|
||||
"DecisionModelsDecisionsConfig",
|
||||
"OpenRouterDecisionsConfig",
|
||||
"FireworksAIDecisionsConfig",
|
||||
"CloudflareDecisionsConfig",
|
||||
|
|
@ -743,6 +744,7 @@ _LLM_CONFIGS_IMPORT_MAP: Final = {
|
|||
"NaceDecisionsConfig": (".llms.nace.decisions.transformation", "NaceDecisionsConfig"),
|
||||
"TypeSafeDecisionsConfig": (".llms.typesafe.decisions.transformation", "TypeSafeDecisionsConfig"),
|
||||
"ParallelAIDecisionsConfig": (".llms.parallel_ai.decisions.transformation", "ParallelAIDecisionsConfig"),
|
||||
"DecisionModelsDecisionsConfig": (".llms.decisionmodels.decisions.transformation", "DecisionModelsDecisionsConfig"),
|
||||
"OpenRouterDecisionsConfig": (".llms.openrouter.decisions.transformation", "OpenRouterDecisionsConfig"),
|
||||
"FireworksAIDecisionsConfig": (".llms.fireworks_ai.decisions.transformation", "FireworksAIDecisionsConfig"),
|
||||
"CloudflareDecisionsConfig": (".llms.cloudflare.decisions.transformation", "CloudflareDecisionsConfig"),
|
||||
|
|
|
|||
9
litellm/llms/decisionmodels/decisions/transformation.py
Normal file
9
litellm/llms/decisionmodels/decisions/transformation.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
from litellm.llms.base_llm.decisions.transformation import BaseDecisionsConfig
|
||||
|
||||
|
||||
class DecisionModelsDecisionsConfig(BaseDecisionsConfig):
|
||||
api_key_env = ("DECISIONMODELS_API_KEY",)
|
||||
api_base_env = ("DECISIONMODELS_API_BASE",)
|
||||
|
||||
def get_default_api_base(self) -> str | None:
|
||||
return "https://api.decisionmodels.io"
|
||||
|
|
@ -74117,6 +74117,38 @@
|
|||
"output_cost_per_token": 0.0,
|
||||
"source": "https://console.nace.ai/docs/drex/reference/models"
|
||||
},
|
||||
"decisionmodels/s1-fast": {
|
||||
"input_cost_per_token": 1.9e-08,
|
||||
"litellm_provider": "decisionmodels",
|
||||
"max_input_tokens": 16192,
|
||||
"mode": "evaluation",
|
||||
"output_cost_per_token": 0.0,
|
||||
"source": "https://api.decisionmodels.io/v1/models"
|
||||
},
|
||||
"decisionmodels/s1-pro": {
|
||||
"input_cost_per_token": 8e-08,
|
||||
"litellm_provider": "decisionmodels",
|
||||
"max_input_tokens": 8192,
|
||||
"mode": "evaluation",
|
||||
"output_cost_per_token": 0.0,
|
||||
"source": "https://api.decisionmodels.io/v1/models"
|
||||
},
|
||||
"decisionmodels/reax-1": {
|
||||
"input_cost_per_token": 8e-08,
|
||||
"litellm_provider": "decisionmodels",
|
||||
"max_input_tokens": 8192,
|
||||
"mode": "evaluation",
|
||||
"output_cost_per_token": 0.0,
|
||||
"source": "https://api.decisionmodels.io/v1/models"
|
||||
},
|
||||
"decisionmodels/s1-llm-auto-router": {
|
||||
"input_cost_per_token": 1e-09,
|
||||
"litellm_provider": "decisionmodels",
|
||||
"max_input_tokens": 8192,
|
||||
"mode": "evaluation",
|
||||
"output_cost_per_token": 0.0,
|
||||
"source": "https://api.decisionmodels.io/v1/models"
|
||||
},
|
||||
"typesafe/jev-1.13.0": {
|
||||
"input_cost_per_token": 4.2e-08,
|
||||
"litellm_provider": "typesafe",
|
||||
|
|
|
|||
|
|
@ -1397,6 +1397,34 @@
|
|||
],
|
||||
"default_model_placeholder": "gpt-3.5-turbo"
|
||||
},
|
||||
{
|
||||
"provider": "DecisionModels",
|
||||
"provider_display_name": "Decision Models",
|
||||
"litellm_provider": "decisionmodels",
|
||||
"credential_fields": [
|
||||
{
|
||||
"key": "api_base",
|
||||
"label": "API Base",
|
||||
"placeholder": "https://api.decisionmodels.io",
|
||||
"tooltip": null,
|
||||
"required": false,
|
||||
"field_type": "text",
|
||||
"options": null,
|
||||
"default_value": null
|
||||
},
|
||||
{
|
||||
"key": "api_key",
|
||||
"label": "API Key",
|
||||
"placeholder": null,
|
||||
"tooltip": null,
|
||||
"required": true,
|
||||
"field_type": "password",
|
||||
"options": null,
|
||||
"default_value": null
|
||||
}
|
||||
],
|
||||
"default_model_placeholder": "decisionmodels/s1-fast"
|
||||
},
|
||||
{
|
||||
"provider": "Deepgram",
|
||||
"provider_display_name": "Deepgram",
|
||||
|
|
|
|||
|
|
@ -4654,6 +4654,7 @@ class LlmProviders(str, Enum):
|
|||
TYPESAFE = "typesafe"
|
||||
PARALLEL_AI = "parallel_ai"
|
||||
NACE = "nace"
|
||||
DECISIONMODELS = "decisionmodels"
|
||||
STRANDS_DECIDER = "strands_decider"
|
||||
LAYA = "laya"
|
||||
BESPOKE = "bespoke"
|
||||
|
|
|
|||
|
|
@ -10320,6 +10320,7 @@ class ProviderConfigManager:
|
|||
LlmProviders.AZURE_AI,
|
||||
LlmProviders.EU_JEV,
|
||||
LlmProviders.PARALLEL_AI,
|
||||
LlmProviders.DECISIONMODELS,
|
||||
):
|
||||
configs: Final = {
|
||||
LlmProviders.EMPIRIOLABS: litellm.EmpirioLabsDecisionsConfig,
|
||||
|
|
@ -10328,6 +10329,7 @@ class ProviderConfigManager:
|
|||
LlmProviders.AZURE_AI: litellm.AzureAIDecisionsConfig,
|
||||
LlmProviders.EU_JEV: litellm.EuJevDecisionsConfig,
|
||||
LlmProviders.PARALLEL_AI: litellm.ParallelAIDecisionsConfig,
|
||||
LlmProviders.DECISIONMODELS: litellm.DecisionModelsDecisionsConfig,
|
||||
}
|
||||
return configs[provider]()
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -74117,6 +74117,38 @@
|
|||
"output_cost_per_token": 0.0,
|
||||
"source": "https://console.nace.ai/docs/drex/reference/models"
|
||||
},
|
||||
"decisionmodels/s1-fast": {
|
||||
"input_cost_per_token": 1.9e-08,
|
||||
"litellm_provider": "decisionmodels",
|
||||
"max_input_tokens": 16192,
|
||||
"mode": "evaluation",
|
||||
"output_cost_per_token": 0.0,
|
||||
"source": "https://api.decisionmodels.io/v1/models"
|
||||
},
|
||||
"decisionmodels/s1-pro": {
|
||||
"input_cost_per_token": 8e-08,
|
||||
"litellm_provider": "decisionmodels",
|
||||
"max_input_tokens": 8192,
|
||||
"mode": "evaluation",
|
||||
"output_cost_per_token": 0.0,
|
||||
"source": "https://api.decisionmodels.io/v1/models"
|
||||
},
|
||||
"decisionmodels/reax-1": {
|
||||
"input_cost_per_token": 8e-08,
|
||||
"litellm_provider": "decisionmodels",
|
||||
"max_input_tokens": 8192,
|
||||
"mode": "evaluation",
|
||||
"output_cost_per_token": 0.0,
|
||||
"source": "https://api.decisionmodels.io/v1/models"
|
||||
},
|
||||
"decisionmodels/s1-llm-auto-router": {
|
||||
"input_cost_per_token": 1e-09,
|
||||
"litellm_provider": "decisionmodels",
|
||||
"max_input_tokens": 8192,
|
||||
"mode": "evaluation",
|
||||
"output_cost_per_token": 0.0,
|
||||
"source": "https://api.decisionmodels.io/v1/models"
|
||||
},
|
||||
"typesafe/jev-1.13.0": {
|
||||
"input_cost_per_token": 4.2e-08,
|
||||
"litellm_provider": "typesafe",
|
||||
|
|
|
|||
|
|
@ -4046,6 +4046,13 @@
|
|||
"generateContent": false
|
||||
}
|
||||
},
|
||||
"decisionmodels": {
|
||||
"display_name": "Decision Models (`decisionmodels`)",
|
||||
"url": "https://decisionmodels.io",
|
||||
"endpoints": {
|
||||
"systemone": true
|
||||
}
|
||||
},
|
||||
"typesafe": {
|
||||
"display_name": "TypeSafe (`typesafe`)",
|
||||
"url": "https://docs.typesafe.ai/models",
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ _PROVIDERS: Final = (
|
|||
),
|
||||
_Provider("typesafe", "typesafe/jev-1.13.0", "/v1/systemone", "jev-1.13.0", _API_KEY, False, "typesafe/jev-1.13.0"),
|
||||
_Provider("nace", "nace/drex-v2.0", "/v1/systemone", "drex-v2.0", _API_KEY, False, "nace/drex-v2.0"),
|
||||
_Provider(
|
||||
"decisionmodels", "decisionmodels/s1-fast", "/v1/systemone", "s1-fast", _API_KEY, False, "decisionmodels/s1-fast"
|
||||
),
|
||||
_Provider(
|
||||
"openrouter",
|
||||
"openrouter/typesafe/jev-1.13",
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ _PROVIDERS: Final[tuple[tuple[str, str, str, str], ...]] = (
|
|||
("typesafe", "typesafe/jev-1.13", "https://api.typesafe.ai/v1/systemone", "jev-1.13"),
|
||||
("nace", "nace/drex-v2.0", "https://console.nace.ai/v1/systemone", "drex-v2.0"),
|
||||
("eu_jev", "eu_jev/eu-jeff-latest", "https://eu-jev.com/v1/systemone", "eu-jeff-latest"),
|
||||
("decisionmodels", "decisionmodels/s1-fast", "https://api.decisionmodels.io/v1/systemone", "s1-fast"),
|
||||
(
|
||||
"openrouter",
|
||||
"openrouter/typesafe/jev-1.13",
|
||||
|
|
@ -4905,3 +4906,85 @@ def test_hosted_vllm_systemone_maps_image_rejection_to_bad_request(
|
|||
|
||||
assert caught.value.status_code == 400
|
||||
assert route.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("model", ("s1-fast", "s1-pro", "reax-1", "s1-llm-auto-router"))
|
||||
def test_decisionmodels_prices_are_input_only(model: str) -> None:
|
||||
entry: Final = litellm.model_cost[f"decisionmodels/{model}"]
|
||||
|
||||
assert entry["litellm_provider"] == "decisionmodels"
|
||||
assert entry["mode"] == "evaluation"
|
||||
assert entry["max_input_tokens"] > 0
|
||||
assert entry["input_cost_per_token"] > 0
|
||||
assert entry["output_cost_per_token"] == 0
|
||||
|
||||
|
||||
def test_decisionmodels_sync_call_uses_default_base_and_environment_key(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
respx_mock: respx.MockRouter,
|
||||
) -> None:
|
||||
monkeypatch.setenv("DECISIONMODELS_API_KEY", "environment-key")
|
||||
monkeypatch.delenv("DECISIONMODELS_API_BASE", raising=False)
|
||||
upstream: Final = respx_mock.post("https://api.decisionmodels.io/v1/systemone").respond(json=_RESPONSE)
|
||||
response: Final = litellm.systemone(
|
||||
model="decisionmodels/s1-fast",
|
||||
state="damaged order",
|
||||
questions={"is_defect": {"type": "noul", "instructions": "Is this a defect?"}},
|
||||
)
|
||||
assert response.answers["is_defect"] == NoulAnswer(type="noul", noul=0.9)
|
||||
assert upstream.calls[0].request.headers["authorization"] == "Bearer environment-key"
|
||||
assert json.loads(upstream.calls[0].request.content) == {
|
||||
"model": "s1-fast",
|
||||
"state": "damaged order",
|
||||
"questions": {"is_defect": {"type": "noul", "instructions": "Is this a defect?"}},
|
||||
}
|
||||
|
||||
|
||||
def test_decisionmodels_environment_base_and_explicit_key_win(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
respx_mock: respx.MockRouter,
|
||||
) -> None:
|
||||
monkeypatch.setenv("DECISIONMODELS_API_BASE", "https://decisionmodels.example/")
|
||||
monkeypatch.setenv("DECISIONMODELS_API_KEY", "environment-key")
|
||||
upstream: Final = respx_mock.post("https://decisionmodels.example/v1/systemone").respond(json=_RESPONSE)
|
||||
litellm.systemone(
|
||||
model="decisionmodels/s1-pro",
|
||||
state={"message": "damaged order"},
|
||||
api_key="explicit-key",
|
||||
questions={"is_defect": {"type": "noul", "criteria": {"true": "damaged", "false": "intact"}}},
|
||||
)
|
||||
assert upstream.calls[0].request.headers["authorization"] == "Bearer explicit-key"
|
||||
assert json.loads(upstream.calls[0].request.content)["model"] == "s1-pro"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("status", "exception"),
|
||||
(
|
||||
(401, litellm.AuthenticationError),
|
||||
(402, litellm.PaymentRequiredError),
|
||||
(422, litellm.BadRequestError),
|
||||
(429, litellm.RateLimitError),
|
||||
),
|
||||
)
|
||||
def test_decisionmodels_upstream_failures_preserve_status_and_message(
|
||||
status: int,
|
||||
exception: type[Exception],
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
respx_mock: respx.MockRouter,
|
||||
) -> None:
|
||||
monkeypatch.delenv("DECISIONMODELS_API_BASE", raising=False)
|
||||
upstream: Final = respx_mock.post("https://api.decisionmodels.io/v1/systemone").respond(
|
||||
status,
|
||||
json={"detail": {"error_type": "test_error", "message": "decision rejected"}},
|
||||
headers={"retry-after": "1"},
|
||||
)
|
||||
with pytest.raises(exception, match="decision rejected") as error:
|
||||
litellm.systemone(
|
||||
model="decisionmodels/s1-fast",
|
||||
state="text",
|
||||
api_key="test-key",
|
||||
questions={"a": {"type": "noul", "instructions": "Is it urgent?"}},
|
||||
num_retries=0,
|
||||
)
|
||||
assert error.value.status_code == status
|
||||
assert upstream.call_count == 1
|
||||
|
|
|
|||
|
|
@ -532,6 +532,7 @@ def _decisions_provider_entry(provider: str) -> ProviderCreateInfo:
|
|||
("PARALLEL_AI", "Parallel AI", LlmProviders.PARALLEL_AI),
|
||||
("EU_JEV", "eu/jev", LlmProviders.EU_JEV),
|
||||
("EMPIRIOLABS", "EmpirioLabs AI", LlmProviders.EMPIRIOLABS),
|
||||
("DecisionModels", "Decision Models", LlmProviders.DECISIONMODELS),
|
||||
),
|
||||
)
|
||||
def test_decisions_provider_fields(provider_key: str, display_name: str, provider: LlmProviders) -> None:
|
||||
|
|
|
|||
|
|
@ -250,6 +250,7 @@ describe("provider_info_helpers", () => {
|
|||
Providers.COMPACTIFAI,
|
||||
Providers.CORALBRICKS,
|
||||
Providers.DATAROBOT,
|
||||
Providers.DecisionModels,
|
||||
Providers.DOCKER_MODEL_RUNNER,
|
||||
Providers.DOTPROMPT,
|
||||
Providers.EMPIRIOLABS,
|
||||
|
|
@ -604,6 +605,16 @@ describe("provider_info_helpers", () => {
|
|||
expect(getPlaceholder("Nace")).toBe("nace/drex-latest");
|
||||
});
|
||||
|
||||
it("lists Decision Models decision models and resolves the provider name and model placeholder", () => {
|
||||
const modelMap = {
|
||||
"decisionmodels/s1-fast": { litellm_provider: "decisionmodels", mode: "evaluation" },
|
||||
"typesafe/jev-latest": { litellm_provider: "typesafe", mode: "evaluation" },
|
||||
};
|
||||
expect(getProviderModels("DecisionModels" as Providers, modelMap)).toEqual(["decisionmodels/s1-fast"]);
|
||||
expect(getProviderLogoAndName("decisionmodels").displayName).toBe("Decision Models");
|
||||
expect(getPlaceholder("DecisionModels")).toBe("decisionmodels/s1-fast");
|
||||
});
|
||||
|
||||
it("should list only typesafe decision models for the 'TypeSafe' provider key, not the OpenRouter-hosted one", () => {
|
||||
const modelMap = {
|
||||
"typesafe/jev-latest": { litellm_provider: "typesafe", mode: "evaluation" },
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ export enum Providers {
|
|||
Dashscope = "Dashscope",
|
||||
Databricks = "Databricks (Qwen API)",
|
||||
DATAROBOT = "Datarobot",
|
||||
DecisionModels = "Decision Models",
|
||||
DeepInfra = "DeepInfra",
|
||||
Deepgram = "Deepgram",
|
||||
Deepseek = "Deepseek",
|
||||
|
|
@ -246,6 +247,7 @@ export const provider_map: Record<string, string> = {
|
|||
Dashscope: "dashscope",
|
||||
Databricks: "databricks",
|
||||
DATAROBOT: "datarobot",
|
||||
DecisionModels: "decisionmodels",
|
||||
DeepInfra: "deepinfra",
|
||||
Deepgram: "deepgram",
|
||||
Deepseek: "deepseek",
|
||||
|
|
@ -499,6 +501,7 @@ const providerPlaceholderMap: Partial<Record<Providers, string>> = {
|
|||
[Providers.Cognition]: "cognition/swe-1.7",
|
||||
[Providers.CORALBRICKS]: "coralbricks/glm-5.3-fast",
|
||||
[Providers.Cursor]: "cursor/claude-4-sonnet",
|
||||
[Providers.DecisionModels]: "decisionmodels/s1-fast",
|
||||
[Providers.DeepInfra]: "deepinfra/<any-model-on-deepinfra>",
|
||||
[Providers.EDENAI]: "edenai/openai/gpt-mini-latest",
|
||||
[Providers.EMPIRIOLABS]: "empiriolabs/aplomb-1",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue