From 903611940a39e716df9d02fdcba189c6a88e18df Mon Sep 17 00:00:00 2001 From: cthomas Date: Tue, 29 Apr 2025 17:09:48 -0700 Subject: [PATCH] chore: remove duplicate class definitions (#1942) --- letta/schemas/providers.py | 193 ------------------------------------- 1 file changed, 193 deletions(-) diff --git a/letta/schemas/providers.py b/letta/schemas/providers.py index f5198d7f..a985a412 100644 --- a/letta/schemas/providers.py +++ b/letta/schemas/providers.py @@ -486,199 +486,6 @@ class XAIProvider(OpenAIProvider): return [] -class DeepSeekProvider(OpenAIProvider): - """ - DeepSeek ChatCompletions API is similar to OpenAI's reasoning API, - but with slight differences: - * For example, DeepSeek's API requires perfect interleaving of user/assistant - * It also does not support native function calling - """ - - name: str = "deepseek" - base_url: str = Field("https://api.deepseek.com/v1", description="Base URL for the DeepSeek API.") - api_key: str = Field(..., description="API key for the DeepSeek API.") - - def get_model_context_window_size(self, model_name: str) -> Optional[int]: - # DeepSeek doesn't return context window in the model listing, - # so these are hardcoded from their website - if model_name == "deepseek-reasoner": - return 64000 - elif model_name == "deepseek-chat": - return 64000 - else: - return None - - def list_llm_models(self) -> List[LLMConfig]: - from letta.llm_api.openai import openai_get_model_list - - response = openai_get_model_list(self.base_url, api_key=self.api_key) - - if "data" in response: - data = response["data"] - else: - data = response - - configs = [] - for model in data: - assert "id" in model, f"DeepSeek model missing 'id' field: {model}" - model_name = model["id"] - - # In case DeepSeek starts supporting it in the future: - if "context_length" in model: - # Context length is returned in OpenRouter as "context_length" - context_window_size = model["context_length"] - else: - context_window_size = self.get_model_context_window_size(model_name) - - if not context_window_size: - warnings.warn(f"Couldn't find context window size for model {model_name}") - continue - - # Not used for deepseek-reasoner, but otherwise is true - put_inner_thoughts_in_kwargs = False if model_name == "deepseek-reasoner" else True - - configs.append( - LLMConfig( - model=model_name, - model_endpoint_type="deepseek", - model_endpoint=self.base_url, - context_window=context_window_size, - handle=self.get_handle(model_name), - put_inner_thoughts_in_kwargs=put_inner_thoughts_in_kwargs, - ) - ) - - return configs - - def list_embedding_models(self) -> List[EmbeddingConfig]: - # No embeddings supported - return [] - - -class LMStudioOpenAIProvider(OpenAIProvider): - name: str = "lmstudio-openai" - base_url: str = Field(..., description="Base URL for the LMStudio OpenAI API.") - api_key: Optional[str] = Field(None, description="API key for the LMStudio API.") - - def list_llm_models(self) -> List[LLMConfig]: - from letta.llm_api.openai import openai_get_model_list - - # For LMStudio, we want to hit 'GET /api/v0/models' instead of 'GET /v1/models' - MODEL_ENDPOINT_URL = f"{self.base_url.strip('/v1')}/api/v0" - response = openai_get_model_list(MODEL_ENDPOINT_URL) - - """ - Example response: - - { - "object": "list", - "data": [ - { - "id": "qwen2-vl-7b-instruct", - "object": "model", - "type": "vlm", - "publisher": "mlx-community", - "arch": "qwen2_vl", - "compatibility_type": "mlx", - "quantization": "4bit", - "state": "not-loaded", - "max_context_length": 32768 - }, - ... - """ - if "data" not in response: - warnings.warn(f"LMStudio OpenAI model query response missing 'data' field: {response}") - return [] - - configs = [] - for model in response["data"]: - assert "id" in model, f"Model missing 'id' field: {model}" - model_name = model["id"] - - if "type" not in model: - warnings.warn(f"LMStudio OpenAI model missing 'type' field: {model}") - continue - elif model["type"] not in ["vlm", "llm"]: - continue - - if "max_context_length" in model: - context_window_size = model["max_context_length"] - else: - warnings.warn(f"LMStudio OpenAI model missing 'max_context_length' field: {model}") - continue - - configs.append( - LLMConfig( - model=model_name, - model_endpoint_type="openai", - model_endpoint=self.base_url, - context_window=context_window_size, - handle=self.get_handle(model_name), - ) - ) - - return configs - - def list_embedding_models(self) -> List[EmbeddingConfig]: - from letta.llm_api.openai import openai_get_model_list - - # For LMStudio, we want to hit 'GET /api/v0/models' instead of 'GET /v1/models' - MODEL_ENDPOINT_URL = f"{self.base_url.strip('/v1')}/api/v0" - response = openai_get_model_list(MODEL_ENDPOINT_URL) - - """ - Example response: - { - "object": "list", - "data": [ - { - "id": "text-embedding-nomic-embed-text-v1.5", - "object": "model", - "type": "embeddings", - "publisher": "nomic-ai", - "arch": "nomic-bert", - "compatibility_type": "gguf", - "quantization": "Q4_0", - "state": "not-loaded", - "max_context_length": 2048 - } - ... - """ - if "data" not in response: - warnings.warn(f"LMStudio OpenAI model query response missing 'data' field: {response}") - return [] - - configs = [] - for model in response["data"]: - assert "id" in model, f"Model missing 'id' field: {model}" - model_name = model["id"] - - if "type" not in model: - warnings.warn(f"LMStudio OpenAI model missing 'type' field: {model}") - continue - elif model["type"] not in ["embeddings"]: - continue - - if "max_context_length" in model: - context_window_size = model["max_context_length"] - else: - warnings.warn(f"LMStudio OpenAI model missing 'max_context_length' field: {model}") - continue - - configs.append( - EmbeddingConfig( - embedding_model=model_name, - embedding_endpoint_type="openai", - embedding_endpoint=self.base_url, - embedding_dim=context_window_size, - embedding_chunk_size=300, # NOTE: max is 2048 - handle=self.get_handle(model_name), - ), - ) - - return configs - - class AnthropicProvider(Provider): name: str = "anthropic" api_key: str = Field(..., description="API key for the Anthropic API.")