chore: remove duplicate class definitions (#1942)
This commit is contained in:
@@ -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.")
|
||||
|
||||
Reference in New Issue
Block a user