diff --git a/letta/embeddings.py b/letta/embeddings.py index 6541cea36..e8d1f54d9 100644 --- a/letta/embeddings.py +++ b/letta/embeddings.py @@ -188,6 +188,19 @@ class GoogleEmbeddings: return response_json["embedding"]["values"] +class GoogleVertexEmbeddings: + + def __init__(self, model: str, project_id: str, region: str): + from google import genai + + self.client = genai.Client(vertexai=True, project=project_id, location=region, http_options={"api_version": "v1"}) + self.model = model + + def get_text_embedding(self, text: str): + response = self.client.generate_embeddings(content=text, model=self.model) + return response.embeddings[0].embedding + + def query_embedding(embedding_model, query_text: str): """Generate padded embedding for querying database""" query_vec = embedding_model.get_text_embedding(query_text) @@ -267,5 +280,13 @@ def embedding_model(config: EmbeddingConfig, user_id: Optional[uuid.UUID] = None ) return model + elif endpoint_type == "google_vertex": + model = GoogleVertexEmbeddings( + model=config.embedding_model, + api_key=model_settings.gemini_api_key, + base_url=model_settings.gemini_base_url, + ) + return model + else: raise ValueError(f"Unknown endpoint type {endpoint_type}") diff --git a/letta/llm_api/google_vertex.py b/letta/llm_api/google_vertex.py new file mode 100644 index 000000000..7b551af25 --- /dev/null +++ b/letta/llm_api/google_vertex.py @@ -0,0 +1,330 @@ +import uuid +from typing import List, Optional, Tuple + +import requests + +from letta.constants import NON_USER_MSG_PREFIX +from letta.local_llm.json_parser import clean_json_string_extra_backslash +from letta.local_llm.utils import count_tokens +from letta.schemas.openai.chat_completion_request import Tool +from letta.schemas.openai.chat_completion_response import ChatCompletionResponse, Choice, FunctionCall, Message, ToolCall, UsageStatistics +from letta.utils import get_tool_call_id, get_utc_time, json_dumps + + +def add_dummy_model_messages(messages: List[dict]) -> List[dict]: + """Google AI API requires all function call returns are immediately followed by a 'model' role message. + + In Letta, the 'model' will often call a function (e.g. send_message) that itself yields to the user, + so there is no natural follow-up 'model' role message. + + To satisfy the Google AI API restrictions, we can add a dummy 'yield' message + with role == 'model' that is placed in-betweeen and function output + (role == 'tool') and user message (role == 'user'). + """ + dummy_yield_message = {"role": "model", "parts": [{"text": f"{NON_USER_MSG_PREFIX}Function call returned, waiting for user response."}]} + messages_with_padding = [] + for i, message in enumerate(messages): + messages_with_padding.append(message) + # Check if the current message role is 'tool' and the next message role is 'user' + if message["role"] in ["tool", "function"] and (i + 1 < len(messages) and messages[i + 1]["role"] == "user"): + messages_with_padding.append(dummy_yield_message) + + return messages_with_padding + + +# TODO use pydantic model as input +def to_google_ai(openai_message_dict: dict) -> dict: + + # TODO supports "parts" as part of multimodal support + assert not isinstance(openai_message_dict["content"], list), "Multi-part content is message not yet supported" + if openai_message_dict["role"] == "user": + google_ai_message_dict = { + "role": "user", + "parts": [{"text": openai_message_dict["content"]}], + } + elif openai_message_dict["role"] == "assistant": + google_ai_message_dict = { + "role": "model", # NOTE: diff + "parts": [{"text": openai_message_dict["content"]}], + } + elif openai_message_dict["role"] == "tool": + google_ai_message_dict = { + "role": "function", # NOTE: diff + "parts": [{"text": openai_message_dict["content"]}], + } + else: + raise ValueError(f"Unsupported conversion (OpenAI -> Google AI) from role {openai_message_dict['role']}") + + +# TODO convert return type to pydantic +def convert_tools_to_google_ai_format(tools: List[Tool], inner_thoughts_in_kwargs: Optional[bool] = True) -> List[dict]: + """ + OpenAI style: + "tools": [{ + "type": "function", + "function": { + "name": "find_movies", + "description": "find ....", + "parameters": { + "type": "object", + "properties": { + PARAM: { + "type": PARAM_TYPE, # eg "string" + "description": PARAM_DESCRIPTION, + }, + ... + }, + "required": List[str], + } + } + } + ] + + Google AI style: + "tools": [{ + "functionDeclarations": [{ + "name": "find_movies", + "description": "find movie titles currently playing in theaters based on any description, genre, title words, etc.", + "parameters": { + "type": "OBJECT", + "properties": { + "location": { + "type": "STRING", + "description": "The city and state, e.g. San Francisco, CA or a zip code e.g. 95616" + }, + "description": { + "type": "STRING", + "description": "Any kind of description including category or genre, title words, attributes, etc." + } + }, + "required": ["description"] + } + }, { + "name": "find_theaters", + ... + """ + function_list = [ + dict( + name=t.function.name, + description=t.function.description, + parameters=t.function.parameters, # TODO need to unpack + ) + for t in tools + ] + + # Correct casing + add inner thoughts if needed + for func in function_list: + func["parameters"]["type"] = "OBJECT" + for param_name, param_fields in func["parameters"]["properties"].items(): + param_fields["type"] = param_fields["type"].upper() + # Add inner thoughts + if inner_thoughts_in_kwargs: + from letta.local_llm.constants import INNER_THOUGHTS_KWARG, INNER_THOUGHTS_KWARG_DESCRIPTION + + func["parameters"]["properties"][INNER_THOUGHTS_KWARG] = { + "type": "STRING", + "description": INNER_THOUGHTS_KWARG_DESCRIPTION, + } + func["parameters"]["required"].append(INNER_THOUGHTS_KWARG) + + return [{"functionDeclarations": function_list}] + + +def convert_google_ai_response_to_chatcompletion( + response, + model: str, # Required since not returned + input_messages: Optional[List[dict]] = None, # Required if the API doesn't return UsageMetadata + pull_inner_thoughts_from_args: Optional[bool] = True, +) -> ChatCompletionResponse: + """Google AI API response format is not the same as ChatCompletion, requires unpacking + + Example: + { + "candidates": [ + { + "content": { + "parts": [ + { + "text": " OK. Barbie is showing in two theaters in Mountain View, CA: AMC Mountain View 16 and Regal Edwards 14." + } + ] + } + } + ], + "usageMetadata": { + "promptTokenCount": 9, + "candidatesTokenCount": 27, + "totalTokenCount": 36 + } + } + """ + try: + choices = [] + index = 0 + for candidate in response.candidates: + content = candidate.content + + role = content.role + assert role == "model", f"Unknown role in response: {role}" + + parts = content.parts + # TODO support parts / multimodal + # TODO support parallel tool calling natively + # TODO Alternative here is to throw away everything else except for the first part + for response_message in parts: + # Convert the actual message style to OpenAI style + if response_message.function_call: + function_call = response_message.function_call + function_name = function_call.name + function_args = function_call.args + assert isinstance(function_args, dict), function_args + + # NOTE: this also involves stripping the inner monologue out of the function + if pull_inner_thoughts_from_args: + from letta.local_llm.constants import INNER_THOUGHTS_KWARG + + assert INNER_THOUGHTS_KWARG in function_args, f"Couldn't find inner thoughts in function args:\n{function_call}" + inner_thoughts = function_args.pop(INNER_THOUGHTS_KWARG) + assert inner_thoughts is not None, f"Expected non-null inner thoughts function arg:\n{function_call}" + else: + inner_thoughts = None + + # Google AI API doesn't generate tool call IDs + openai_response_message = Message( + role="assistant", # NOTE: "model" -> "assistant" + content=inner_thoughts, + tool_calls=[ + ToolCall( + id=get_tool_call_id(), + type="function", + function=FunctionCall( + name=function_name, + arguments=clean_json_string_extra_backslash(json_dumps(function_args)), + ), + ) + ], + ) + + else: + + # Inner thoughts are the content by default + inner_thoughts = response_message.text + + # Google AI API doesn't generate tool call IDs + openai_response_message = Message( + role="assistant", # NOTE: "model" -> "assistant" + content=inner_thoughts, + ) + + # Google AI API uses different finish reason strings than OpenAI + # OpenAI: 'stop', 'length', 'function_call', 'content_filter', null + # see: https://platform.openai.com/docs/guides/text-generation/chat-completions-api + # Google AI API: FINISH_REASON_UNSPECIFIED, STOP, MAX_TOKENS, SAFETY, RECITATION, OTHER + # see: https://ai.google.dev/api/python/google/ai/generativelanguage/Candidate/FinishReason + finish_reason = candidate.finish_reason.value + if finish_reason == "STOP": + openai_finish_reason = ( + "function_call" + if openai_response_message.tool_calls is not None and len(openai_response_message.tool_calls) > 0 + else "stop" + ) + elif finish_reason == "MAX_TOKENS": + openai_finish_reason = "length" + elif finish_reason == "SAFETY": + openai_finish_reason = "content_filter" + elif finish_reason == "RECITATION": + openai_finish_reason = "content_filter" + else: + raise ValueError(f"Unrecognized finish reason in Google AI response: {finish_reason}") + + choices.append( + Choice( + finish_reason=openai_finish_reason, + index=index, + message=openai_response_message, + ) + ) + index += 1 + + # if len(choices) > 1: + # raise UserWarning(f"Unexpected number of candidates in response (expected 1, got {len(choices)})") + + # NOTE: some of the Google AI APIs show UsageMetadata in the response, but it seems to not exist? + # "usageMetadata": { + # "promptTokenCount": 9, + # "candidatesTokenCount": 27, + # "totalTokenCount": 36 + # } + if response.usage_metadata: + usage = UsageStatistics( + prompt_tokens=response.usage_metadata.prompt_token_count, + completion_tokens=response.usage_metadata.candidates_token_count, + total_tokens=response.usage_metadata.total_token_count, + ) + else: + # Count it ourselves + assert input_messages is not None, f"Didn't get UsageMetadata from the API response, so input_messages is required" + prompt_tokens = count_tokens(json_dumps(input_messages)) # NOTE: this is a very rough approximation + completion_tokens = count_tokens(json_dumps(openai_response_message.model_dump())) # NOTE: this is also approximate + total_tokens = prompt_tokens + completion_tokens + usage = UsageStatistics( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=total_tokens, + ) + + response_id = str(uuid.uuid4()) + return ChatCompletionResponse( + id=response_id, + choices=choices, + model=model, # NOTE: Google API doesn't pass back model in the response + created=get_utc_time(), + usage=usage, + ) + except KeyError as e: + raise e + + +# TODO convert 'data' type to pydantic +def google_vertex_chat_completions_request( + model: str, + project_id: str, + region: str, + contents: List[dict], + config: dict, + add_postfunc_model_messages: bool = True, + # NOTE: Google AI API doesn't support mixing parts 'text' and 'function', + # so there's no clean way to put inner thoughts in the same message as a function call + inner_thoughts_in_kwargs: bool = True, +) -> ChatCompletionResponse: + """https://ai.google.dev/docs/function_calling + + From https://ai.google.dev/api/rest#service-endpoint: + "A service endpoint is a base URL that specifies the network address of an API service. + One service might have multiple service endpoints. + This service has the following service endpoint and all URIs below are relative to this service endpoint: + https://xxx.googleapis.com + """ + + from google import genai + + client = genai.Client(vertexai=True, project=project_id, location=region, http_options={"api_version": "v1"}) + # add dummy model messages to the end of the input + if add_postfunc_model_messages: + contents = add_dummy_model_messages(contents) + + # make request to client + response = client.models.generate_content(model=model, contents=contents, config=config) + print(response) + + # convert back response + try: + return convert_google_ai_response_to_chatcompletion( + response=response, + model=model, + input_messages=contents, + pull_inner_thoughts_from_args=inner_thoughts_in_kwargs, + ) + except Exception as conversion_error: + print(f"Error during response conversion: {conversion_error}") + raise conversion_error diff --git a/letta/llm_api/llm_api_tools.py b/letta/llm_api/llm_api_tools.py index 77ba4839d..65bdc1f12 100644 --- a/letta/llm_api/llm_api_tools.py +++ b/letta/llm_api/llm_api_tools.py @@ -252,6 +252,32 @@ def create( inner_thoughts_in_kwargs=llm_config.put_inner_thoughts_in_kwargs, ) + elif llm_config.model_endpoint_type == "google_vertex": + from letta.llm_api.google_vertex import google_vertex_chat_completions_request + + if stream: + raise NotImplementedError(f"Streaming not yet implemented for {llm_config.model_endpoint_type}") + if not use_tool_naming: + raise NotImplementedError("Only tool calling supported on Google Vertex AI API requests") + + if functions is not None: + tools = [{"type": "function", "function": f} for f in functions] + tools = [Tool(**t) for t in tools] + tools = convert_tools_to_google_ai_format(tools, inner_thoughts_in_kwargs=llm_config.put_inner_thoughts_in_kwargs) + else: + tools = None + + config = {"tools": tools, "temperature": llm_config.temperature, "max_output_tokens": llm_config.max_tokens} + + return google_vertex_chat_completions_request( + model=llm_config.model, + project_id=model_settings.google_cloud_project, + region=model_settings.google_cloud_location, + contents=[m.to_google_ai_dict() for m in messages], + config=config, + inner_thoughts_in_kwargs=llm_config.put_inner_thoughts_in_kwargs, + ) + elif llm_config.model_endpoint_type == "anthropic": if not use_tool_naming: raise NotImplementedError("Only tool calling supported on Anthropic API requests") diff --git a/letta/schemas/embedding_config.py b/letta/schemas/embedding_config.py index c0a569a7b..25162d0b8 100644 --- a/letta/schemas/embedding_config.py +++ b/letta/schemas/embedding_config.py @@ -26,6 +26,7 @@ class EmbeddingConfig(BaseModel): "bedrock", "cohere", "google_ai", + "google_vertex", "azure", "groq", "ollama", diff --git a/letta/schemas/llm_config.py b/letta/schemas/llm_config.py index e3877389a..8e44b25e8 100644 --- a/letta/schemas/llm_config.py +++ b/letta/schemas/llm_config.py @@ -25,6 +25,7 @@ class LLMConfig(BaseModel): "anthropic", "cohere", "google_ai", + "google_vertex", "azure", "groq", "ollama", diff --git a/letta/schemas/providers.py b/letta/schemas/providers.py index e96787598..621958cc7 100644 --- a/letta/schemas/providers.py +++ b/letta/schemas/providers.py @@ -327,7 +327,7 @@ class LMStudioOpenAIProvider(OpenAIProvider): embedding_endpoint_type="openai", embedding_endpoint=self.base_url, embedding_dim=context_window_size, - embedding_chunk_size=300, + embedding_chunk_size=300, # NOTE: max is 2048 handle=self.get_handle(model_name), ), ) @@ -737,6 +737,45 @@ class GoogleAIProvider(Provider): return google_ai_get_model_context_window(self.base_url, self.api_key, model_name) +class GoogleVertexProvider(Provider): + name: str = "google_vertex" + google_cloud_project: str = Field(..., description="GCP project ID for the Google Vertex API.") + google_cloud_location: str = Field(..., description="GCP region for the Google Vertex API.") + + def list_llm_models(self) -> List[LLMConfig]: + from letta.llm_api.google_constants import GOOGLE_MODEL_TO_CONTEXT_LENGTH + + configs = [] + for model, context_length in GOOGLE_MODEL_TO_CONTEXT_LENGTH.items(): + configs.append( + LLMConfig( + model=model, + model_endpoint_type="google_vertex", + model_endpoint=f"https://{self.google_cloud_location}-aiplatform.googleapis.com/v1/projects/{self.google_cloud_project}/locations/{self.google_cloud_location}", + context_window=context_length, + handle=self.get_handle(model), + ) + ) + return configs + + def list_embedding_models(self) -> List[EmbeddingConfig]: + from letta.llm_api.google_constants import GOOGLE_EMBEDING_MODEL_TO_DIM + + configs = [] + for model, dim in GOOGLE_EMBEDING_MODEL_TO_DIM.items(): + configs.append( + EmbeddingConfig( + embedding_model=model, + embedding_endpoint_type="google_vertex", + embedding_endpoint=f"https://{self.google_cloud_location}-aiplatform.googleapis.com/v1/projects/{self.google_cloud_project}/locations/{self.google_cloud_location}", + embedding_dim=dim, + embedding_chunk_size=300, # NOTE: max is 2048 + handle=self.get_handle(model, is_embedding=True), + ) + ) + return configs + + class AzureProvider(Provider): name: str = "azure" latest_api_version: str = "2024-09-01-preview" # https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation @@ -792,8 +831,8 @@ class AzureProvider(Provider): embedding_endpoint=model_endpoint, embedding_dim=768, embedding_chunk_size=300, # NOTE: max is 2048 - handle=self.get_handle(model_name, is_embedding=True), - ) + handle=self.get_handle(model_name), + ), ) return configs diff --git a/letta/server/server.py b/letta/server/server.py index 75ac63bbc..5c32182a8 100644 --- a/letta/server/server.py +++ b/letta/server/server.py @@ -47,6 +47,7 @@ from letta.schemas.providers import ( AnthropicProvider, AzureProvider, GoogleAIProvider, + GoogleVertexProvider, GroqProvider, LettaProvider, LMStudioOpenAIProvider, @@ -352,6 +353,13 @@ class SyncServer(Server): api_key=model_settings.gemini_api_key, ) ) + if model_settings.google_cloud_location and model_settings.google_cloud_project: + self._enabled_providers.append( + GoogleVertexProvider( + google_cloud_project=model_settings.google_cloud_project, + google_cloud_location=model_settings.google_cloud_location, + ) + ) if model_settings.azure_api_key and model_settings.azure_base_url: assert model_settings.azure_api_version, "AZURE_API_VERSION is required" self._enabled_providers.append( diff --git a/letta/settings.py b/letta/settings.py index 4fda300c2..4e9f0d0b9 100644 --- a/letta/settings.py +++ b/letta/settings.py @@ -86,6 +86,11 @@ class ModelSettings(BaseSettings): # google ai gemini_api_key: Optional[str] = None gemini_base_url: str = "https://generativelanguage.googleapis.com/" + + # google vertex + google_cloud_project: Optional[str] = None + google_cloud_location: Optional[str] = None + # together together_api_key: Optional[str] = None diff --git a/poetry.lock b/poetry.lock index a03ffeb1a..89003d564 100644 --- a/poetry.lock +++ b/poetry.lock @@ -539,6 +539,17 @@ files = [ {file = "Brotli-1.1.0.tar.gz", hash = "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724"}, ] +[[package]] +name = "cachetools" +version = "5.5.1" +description = "Extensible memoizing collections and decorators" +optional = true +python-versions = ">=3.7" +files = [ + {file = "cachetools-5.5.1-py3-none-any.whl", hash = "sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb"}, + {file = "cachetools-5.5.1.tar.gz", hash = "sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95"}, +] + [[package]] name = "certifi" version = "2025.1.31" @@ -1606,6 +1617,47 @@ benchmarks = ["httplib2", "httpx", "requests", "urllib3"] dev = ["dpkt", "pytest", "requests"] examples = ["oauth2"] +[[package]] +name = "google-auth" +version = "2.38.0" +description = "Google Authentication Library" +optional = true +python-versions = ">=3.7" +files = [ + {file = "google_auth-2.38.0-py2.py3-none-any.whl", hash = "sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a"}, + {file = "google_auth-2.38.0.tar.gz", hash = "sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4"}, +] + +[package.dependencies] +cachetools = ">=2.0.0,<6.0" +pyasn1-modules = ">=0.2.1" +rsa = ">=3.1.4,<5" + +[package.extras] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] +enterprise-cert = ["cryptography", "pyopenssl"] +pyjwt = ["cryptography (>=38.0.3)", "pyjwt (>=2.0)"] +pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +reauth = ["pyu2f (>=0.1.5)"] +requests = ["requests (>=2.20.0,<3.0.0.dev0)"] + +[[package]] +name = "google-genai" +version = "1.2.0" +description = "GenAI Python SDK" +optional = true +python-versions = ">=3.9" +files = [ + {file = "google_genai-1.2.0-py3-none-any.whl", hash = "sha256:609d61bee73f1a6ae5b47e9c7dd4b469d50318f050c5ceacf835b0f80f79d2d9"}, +] + +[package.dependencies] +google-auth = ">=2.14.1,<3.0.0dev" +pydantic = ">=2.0.0,<3.0.0dev" +requests = ">=2.28.1,<3.0.0dev" +typing-extensions = ">=4.11.0,<5.0.0dev" +websockets = ">=13.0,<15.0dev" + [[package]] name = "greenlet" version = "3.1.1" @@ -2481,13 +2533,13 @@ tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10" [[package]] name = "langchain-core" -version = "0.3.34" +version = "0.3.35" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "langchain_core-0.3.34-py3-none-any.whl", hash = "sha256:a057ebeddd2158d3be14bde341b25640ddf958b6989bd6e47160396f5a8202ae"}, - {file = "langchain_core-0.3.34.tar.gz", hash = "sha256:26504cf1e8e6c310adad907b890d4e3c147581cfa7434114f6dc1134fe4bc6d3"}, + {file = "langchain_core-0.3.35-py3-none-any.whl", hash = "sha256:81a4097226e180fa6c64e2d2ab38dcacbbc23b64fc109fb15622910fe8951670"}, + {file = "langchain_core-0.3.35.tar.gz", hash = "sha256:328688228ece259da734417d477994a69cf8202dea9ed4271f2d792e3575c6fc"}, ] [package.dependencies] @@ -2576,13 +2628,13 @@ pytest = ["pytest (>=7.0.0)", "rich (>=13.9.4,<14.0.0)"] [[package]] name = "letta-client" -version = "0.1.27" +version = "0.1.29" description = "" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "letta_client-0.1.27-py3-none-any.whl", hash = "sha256:dbd8ac70993f8b2776bf2203e46e6d637a216a7b85974217534b3cf29479fabf"}, - {file = "letta_client-0.1.27.tar.gz", hash = "sha256:191b29810c02e4b4818542affca41da4a2f2de97d05aac04fdab32b5b52a5da5"}, + {file = "letta_client-0.1.29-py3-none-any.whl", hash = "sha256:72b1b5d69c9277e19fdb0ddeeb572fd0b8d10bd644ec6fd7ddf32c3704052ec6"}, + {file = "letta_client-0.1.29.tar.gz", hash = "sha256:3fa4c9522be20457887142d24f579bc246244d713bd0d92c253785f007446f67"}, ] [package.dependencies] @@ -2610,13 +2662,13 @@ pydantic = ">=1.10" [[package]] name = "llama-cloud-services" -version = "0.6.0" +version = "0.6.1" description = "Tailored SDK clients for LlamaCloud services." optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "llama_cloud_services-0.6.0-py3-none-any.whl", hash = "sha256:b9647e236ba4e13d0b04bf336ed4023e422a2a48d363258924056ef9eb8f688d"}, - {file = "llama_cloud_services-0.6.0.tar.gz", hash = "sha256:9c1ed2849f8ba7374df16bdfda69bed145eb4a425b546048f5e751c48efe293a"}, + {file = "llama_cloud_services-0.6.1-py3-none-any.whl", hash = "sha256:0427c98284bbfedbdf1686d29729d04b13e13f72017e184057892c8583c2b195"}, + {file = "llama_cloud_services-0.6.1.tar.gz", hash = "sha256:92c7ee4fcc80adaa60f26c0da805182fa56d771fff11e9abb873f9ddb11b5e37"}, ] [package.dependencies] @@ -2628,19 +2680,19 @@ python-dotenv = ">=1.0.1,<2.0.0" [[package]] name = "llama-index" -version = "0.12.16" +version = "0.12.17" description = "Interface between LLMs and your data" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "llama_index-0.12.16-py3-none-any.whl", hash = "sha256:c94d0cf6735219d97d91e2eca5bcfac89ec1583990917f934b075d5a45686cf6"}, - {file = "llama_index-0.12.16.tar.gz", hash = "sha256:4fd5f5b94eb3f8dd470bb8cc0e1b985d931e8f31473266ef69855488fd8ae3f2"}, + {file = "llama_index-0.12.17-py3-none-any.whl", hash = "sha256:d8938e5e6e5ff78b6865f7890a01d1a40818a5df798555ee6eb7f2c5ab65aeb0"}, + {file = "llama_index-0.12.17.tar.gz", hash = "sha256:761a2dad3eb74bd5242ecf8fd28337c0c8745fc8d39d2f9f9b18bf733ad679f4"}, ] [package.dependencies] llama-index-agent-openai = ">=0.4.0,<0.5.0" llama-index-cli = ">=0.4.0,<0.5.0" -llama-index-core = ">=0.12.16,<0.13.0" +llama-index-core = ">=0.12.17,<0.13.0" llama-index-embeddings-openai = ">=0.3.0,<0.4.0" llama-index-indices-managed-llama-cloud = ">=0.4.0" llama-index-llms-openai = ">=0.3.0,<0.4.0" @@ -2750,17 +2802,17 @@ llama-index-core = ">=0.12.0,<0.13.0" [[package]] name = "llama-index-llms-openai" -version = "0.3.18" +version = "0.3.19" description = "llama-index llms openai integration" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "llama_index_llms_openai-0.3.18-py3-none-any.whl", hash = "sha256:e2e78ab94fafda8ac99fbfea1b19c5ba4e49d292557d2bdd9c7cc4b445f8745f"}, - {file = "llama_index_llms_openai-0.3.18.tar.gz", hash = "sha256:81807ba318bac28aca67873228c55242c5fe55f8beba35d23828af6e03b1b234"}, + {file = "llama_index_llms_openai-0.3.19-py3-none-any.whl", hash = "sha256:ad3c4a8c86aef181eba6b34cfff995a7c288d6bd5b99207438e25c051d80532d"}, + {file = "llama_index_llms_openai-0.3.19.tar.gz", hash = "sha256:2e2dad70e7a9cb7a1519be1af4ba60c651a0039bc88888332a17922be00b0299"}, ] [package.dependencies] -llama-index-core = ">=0.12.4,<0.13.0" +llama-index-core = ">=0.12.17,<0.13.0" openai = ">=1.58.1,<2.0.0" [[package]] @@ -2848,17 +2900,17 @@ llama-parse = ">=0.5.0" [[package]] name = "llama-parse" -version = "0.6.0" +version = "0.6.1" description = "Parse files into RAG-Optimized formats." optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "llama_parse-0.6.0-py3-none-any.whl", hash = "sha256:786f3b5cb0afdb784cd3d4b8b03489573b56d7d574212cc88a2eda508965121d"}, - {file = "llama_parse-0.6.0.tar.gz", hash = "sha256:ac54ce4a43929b401a3ae4643e02ba4214e14814efb06062586263e13996ec54"}, + {file = "llama_parse-0.6.1-py3-none-any.whl", hash = "sha256:5f96c2951bc3ad514b67bb6886c99224f567d08290fc016e5c8de22c2df60e90"}, + {file = "llama_parse-0.6.1.tar.gz", hash = "sha256:bd848d3ab7460f70f9e9acaef057fb14ae45f976bdf91830db86a8c40883ef34"}, ] [package.dependencies] -llama-cloud-services = "*" +llama-cloud-services = ">=0.6.1" [[package]] name = "locust" @@ -3376,13 +3428,13 @@ files = [ [[package]] name = "openai" -version = "1.61.1" +version = "1.62.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.8" files = [ - {file = "openai-1.61.1-py3-none-any.whl", hash = "sha256:72b0826240ce26026ac2cd17951691f046e5be82ad122d20a8e1b30ca18bd11e"}, - {file = "openai-1.61.1.tar.gz", hash = "sha256:ce1851507218209961f89f3520e06726c0aa7d0512386f0f977e3ac3e4f2472e"}, + {file = "openai-1.62.0-py3-none-any.whl", hash = "sha256:dcb7f9fb4fbc3f27e3ffd2d7bf045be9211510d7fafefcef7ad2302cb27484e0"}, + {file = "openai-1.62.0.tar.gz", hash = "sha256:ef3f6864ae2f75fa6296bc9811acf684b95557fcb611fe95734215a8b9150b43"}, ] [package.dependencies] @@ -4192,6 +4244,31 @@ files = [ [package.extras] test = ["cffi", "hypothesis", "pandas", "pytest", "pytz"] +[[package]] +name = "pyasn1" +version = "0.6.1" +description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" +optional = true +python-versions = ">=3.8" +files = [ + {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, + {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.1" +description = "A collection of ASN.1-based protocols modules" +optional = true +python-versions = ">=3.8" +files = [ + {file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, + {file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, +] + +[package.dependencies] +pyasn1 = ">=0.4.6,<0.7.0" + [[package]] name = "pycparser" version = "2.22" @@ -4443,13 +4520,13 @@ files = [ [[package]] name = "pyright" -version = "1.1.393" +version = "1.1.394" description = "Command line wrapper for pyright" optional = true python-versions = ">=3.7" files = [ - {file = "pyright-1.1.393-py3-none-any.whl", hash = "sha256:8320629bb7a44ca90944ba599390162bf59307f3d9fb6e27da3b7011b8c17ae5"}, - {file = "pyright-1.1.393.tar.gz", hash = "sha256:aeeb7ff4e0364775ef416a80111613f91a05c8e01e58ecfefc370ca0db7aed9c"}, + {file = "pyright-1.1.394-py3-none-any.whl", hash = "sha256:5f74cce0a795a295fb768759bbeeec62561215dea657edcaab48a932b031ddbb"}, + {file = "pyright-1.1.394.tar.gz", hash = "sha256:56f2a3ab88c5214a451eb71d8f2792b7700434f841ea219119ade7f42ca93608"}, ] [package.dependencies] @@ -5191,6 +5268,20 @@ files = [ {file = "rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d"}, ] +[[package]] +name = "rsa" +version = "4.9" +description = "Pure-Python RSA implementation" +optional = true +python-versions = ">=3.6,<4" +files = [ + {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, + {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, +] + +[package.dependencies] +pyasn1 = ">=0.1.3" + [[package]] name = "scramp" version = "1.4.5" @@ -5862,83 +5953,80 @@ test = ["websockets"] [[package]] name = "websockets" -version = "12.0" +version = "14.2" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"}, - {file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"}, - {file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"}, - {file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"}, - {file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"}, - {file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"}, - {file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"}, - {file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"}, - {file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"}, - {file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"}, - {file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"}, - {file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"}, - {file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"}, - {file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"}, - {file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"}, - {file = "websockets-12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5f6ffe2c6598f7f7207eef9a1228b6f5c818f9f4d53ee920aacd35cec8110438"}, - {file = "websockets-12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9edf3fc590cc2ec20dc9d7a45108b5bbaf21c0d89f9fd3fd1685e223771dc0b2"}, - {file = "websockets-12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8572132c7be52632201a35f5e08348137f658e5ffd21f51f94572ca6c05ea81d"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604428d1b87edbf02b233e2c207d7d528460fa978f9e391bd8aaf9c8311de137"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a9d160fd080c6285e202327aba140fc9a0d910b09e423afff4ae5cbbf1c7205"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b4aafed34653e465eb77b7c93ef058516cb5acf3eb21e42f33928616172def"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b2ee7288b85959797970114deae81ab41b731f19ebcd3bd499ae9ca0e3f1d2c8"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7fa3d25e81bfe6a89718e9791128398a50dec6d57faf23770787ff441d851967"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a571f035a47212288e3b3519944f6bf4ac7bc7553243e41eac50dd48552b6df7"}, - {file = "websockets-12.0-cp38-cp38-win32.whl", hash = "sha256:3c6cc1360c10c17463aadd29dd3af332d4a1adaa8796f6b0e9f9df1fdb0bad62"}, - {file = "websockets-12.0-cp38-cp38-win_amd64.whl", hash = "sha256:1bf386089178ea69d720f8db6199a0504a406209a0fc23e603b27b300fdd6892"}, - {file = "websockets-12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab3d732ad50a4fbd04a4490ef08acd0517b6ae6b77eb967251f4c263011a990d"}, - {file = "websockets-12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1d9697f3337a89691e3bd8dc56dea45a6f6d975f92e7d5f773bc715c15dde28"}, - {file = "websockets-12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1df2fbd2c8a98d38a66f5238484405b8d1d16f929bb7a33ed73e4801222a6f53"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23509452b3bc38e3a057382c2e941d5ac2e01e251acce7adc74011d7d8de434c"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e5fc14ec6ea568200ea4ef46545073da81900a2b67b3e666f04adf53ad452ec"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46e71dbbd12850224243f5d2aeec90f0aaa0f2dde5aeeb8fc8df21e04d99eff9"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b81f90dcc6c85a9b7f29873beb56c94c85d6f0dac2ea8b60d995bd18bf3e2aae"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a02413bc474feda2849c59ed2dfb2cddb4cd3d2f03a2fedec51d6e959d9b608b"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bbe6013f9f791944ed31ca08b077e26249309639313fff132bfbf3ba105673b9"}, - {file = "websockets-12.0-cp39-cp39-win32.whl", hash = "sha256:cbe83a6bbdf207ff0541de01e11904827540aa069293696dd528a6640bd6a5f6"}, - {file = "websockets-12.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc4e7fa5414512b481a2483775a8e8be7803a35b30ca805afa4998a84f9fd9e8"}, - {file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b"}, - {file = "websockets-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"}, - {file = "websockets-12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2"}, - {file = "websockets-12.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468"}, - {file = "websockets-12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611"}, - {file = "websockets-12.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370"}, - {file = "websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e"}, - {file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"}, + {file = "websockets-14.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e8179f95323b9ab1c11723e5d91a89403903f7b001828161b480a7810b334885"}, + {file = "websockets-14.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d8c3e2cdb38f31d8bd7d9d28908005f6fa9def3324edb9bf336d7e4266fd397"}, + {file = "websockets-14.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:714a9b682deb4339d39ffa674f7b674230227d981a37d5d174a4a83e3978a610"}, + {file = "websockets-14.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e53c72052f2596fb792a7acd9704cbc549bf70fcde8a99e899311455974ca3"}, + {file = "websockets-14.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fbd68850c837e57373d95c8fe352203a512b6e49eaae4c2f4088ef8cf21980"}, + {file = "websockets-14.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b27ece32f63150c268593d5fdb82819584831a83a3f5809b7521df0685cd5d8"}, + {file = "websockets-14.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4daa0faea5424d8713142b33825fff03c736f781690d90652d2c8b053345b0e7"}, + {file = "websockets-14.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:bc63cee8596a6ec84d9753fd0fcfa0452ee12f317afe4beae6b157f0070c6c7f"}, + {file = "websockets-14.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a570862c325af2111343cc9b0257b7119b904823c675b22d4ac547163088d0d"}, + {file = "websockets-14.2-cp310-cp310-win32.whl", hash = "sha256:75862126b3d2d505e895893e3deac0a9339ce750bd27b4ba515f008b5acf832d"}, + {file = "websockets-14.2-cp310-cp310-win_amd64.whl", hash = "sha256:cc45afb9c9b2dc0852d5c8b5321759cf825f82a31bfaf506b65bf4668c96f8b2"}, + {file = "websockets-14.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3bdc8c692c866ce5fefcaf07d2b55c91d6922ac397e031ef9b774e5b9ea42166"}, + {file = "websockets-14.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c93215fac5dadc63e51bcc6dceca72e72267c11def401d6668622b47675b097f"}, + {file = "websockets-14.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c9b6535c0e2cf8a6bf938064fb754aaceb1e6a4a51a80d884cd5db569886910"}, + {file = "websockets-14.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a52a6d7cf6938e04e9dceb949d35fbdf58ac14deea26e685ab6368e73744e4c"}, + {file = "websockets-14.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f05702e93203a6ff5226e21d9b40c037761b2cfb637187c9802c10f58e40473"}, + {file = "websockets-14.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22441c81a6748a53bfcb98951d58d1af0661ab47a536af08920d129b4d1c3473"}, + {file = "websockets-14.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd9b868d78b194790e6236d9cbc46d68aba4b75b22497eb4ab64fa640c3af56"}, + {file = "websockets-14.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a5a20d5843886d34ff8c57424cc65a1deda4375729cbca4cb6b3353f3ce4142"}, + {file = "websockets-14.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:34277a29f5303d54ec6468fb525d99c99938607bc96b8d72d675dee2b9f5bf1d"}, + {file = "websockets-14.2-cp311-cp311-win32.whl", hash = "sha256:02687db35dbc7d25fd541a602b5f8e451a238ffa033030b172ff86a93cb5dc2a"}, + {file = "websockets-14.2-cp311-cp311-win_amd64.whl", hash = "sha256:862e9967b46c07d4dcd2532e9e8e3c2825e004ffbf91a5ef9dde519ee2effb0b"}, + {file = "websockets-14.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f20522e624d7ffbdbe259c6b6a65d73c895045f76a93719aa10cd93b3de100c"}, + {file = "websockets-14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:647b573f7d3ada919fd60e64d533409a79dcf1ea21daeb4542d1d996519ca967"}, + {file = "websockets-14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6af99a38e49f66be5a64b1e890208ad026cda49355661549c507152113049990"}, + {file = "websockets-14.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:091ab63dfc8cea748cc22c1db2814eadb77ccbf82829bac6b2fbe3401d548eda"}, + {file = "websockets-14.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b374e8953ad477d17e4851cdc66d83fdc2db88d9e73abf755c94510ebddceb95"}, + {file = "websockets-14.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a39d7eceeea35db85b85e1169011bb4321c32e673920ae9c1b6e0978590012a3"}, + {file = "websockets-14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a6f3efd47ffd0d12080594f434faf1cd2549b31e54870b8470b28cc1d3817d9"}, + {file = "websockets-14.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:065ce275e7c4ffb42cb738dd6b20726ac26ac9ad0a2a48e33ca632351a737267"}, + {file = "websockets-14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e9d0e53530ba7b8b5e389c02282f9d2aa47581514bd6049d3a7cffe1385cf5fe"}, + {file = "websockets-14.2-cp312-cp312-win32.whl", hash = "sha256:20e6dd0984d7ca3037afcb4494e48c74ffb51e8013cac71cf607fffe11df7205"}, + {file = "websockets-14.2-cp312-cp312-win_amd64.whl", hash = "sha256:44bba1a956c2c9d268bdcdf234d5e5ff4c9b6dc3e300545cbe99af59dda9dcce"}, + {file = "websockets-14.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f1372e511c7409a542291bce92d6c83320e02c9cf392223272287ce55bc224e"}, + {file = "websockets-14.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4da98b72009836179bb596a92297b1a61bb5a830c0e483a7d0766d45070a08ad"}, + {file = "websockets-14.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8a86a269759026d2bde227652b87be79f8a734e582debf64c9d302faa1e9f03"}, + {file = "websockets-14.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86cf1aaeca909bf6815ea714d5c5736c8d6dd3a13770e885aafe062ecbd04f1f"}, + {file = "websockets-14.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b0f6c3ba3b1240f602ebb3971d45b02cc12bd1845466dd783496b3b05783a5"}, + {file = "websockets-14.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669c3e101c246aa85bc8534e495952e2ca208bd87994650b90a23d745902db9a"}, + {file = "websockets-14.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eabdb28b972f3729348e632ab08f2a7b616c7e53d5414c12108c29972e655b20"}, + {file = "websockets-14.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2066dc4cbcc19f32c12a5a0e8cc1b7ac734e5b64ac0a325ff8353451c4b15ef2"}, + {file = "websockets-14.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab95d357cd471df61873dadf66dd05dd4709cae001dd6342edafc8dc6382f307"}, + {file = "websockets-14.2-cp313-cp313-win32.whl", hash = "sha256:a9e72fb63e5f3feacdcf5b4ff53199ec8c18d66e325c34ee4c551ca748623bbc"}, + {file = "websockets-14.2-cp313-cp313-win_amd64.whl", hash = "sha256:b439ea828c4ba99bb3176dc8d9b933392a2413c0f6b149fdcba48393f573377f"}, + {file = "websockets-14.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7cd5706caec1686c5d233bc76243ff64b1c0dc445339bd538f30547e787c11fe"}, + {file = "websockets-14.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ec607328ce95a2f12b595f7ae4c5d71bf502212bddcea528290b35c286932b12"}, + {file = "websockets-14.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da85651270c6bfb630136423037dd4975199e5d4114cae6d3066641adcc9d1c7"}, + {file = "websockets-14.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ecadc7ce90accf39903815697917643f5b7cfb73c96702318a096c00aa71f5"}, + {file = "websockets-14.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1979bee04af6a78608024bad6dfcc0cc930ce819f9e10342a29a05b5320355d0"}, + {file = "websockets-14.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dddacad58e2614a24938a50b85969d56f88e620e3f897b7d80ac0d8a5800258"}, + {file = "websockets-14.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:89a71173caaf75fa71a09a5f614f450ba3ec84ad9fca47cb2422a860676716f0"}, + {file = "websockets-14.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6af6a4b26eea4fc06c6818a6b962a952441e0e39548b44773502761ded8cc1d4"}, + {file = "websockets-14.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:80c8efa38957f20bba0117b48737993643204645e9ec45512579132508477cfc"}, + {file = "websockets-14.2-cp39-cp39-win32.whl", hash = "sha256:2e20c5f517e2163d76e2729104abc42639c41cf91f7b1839295be43302713661"}, + {file = "websockets-14.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4c8cef610e8d7c70dea92e62b6814a8cd24fbd01d7103cc89308d2bfe1659ef"}, + {file = "websockets-14.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d7d9cafbccba46e768be8a8ad4635fa3eae1ffac4c6e7cb4eb276ba41297ed29"}, + {file = "websockets-14.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c76193c1c044bd1e9b3316dcc34b174bbf9664598791e6fb606d8d29000e070c"}, + {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd475a974d5352390baf865309fe37dec6831aafc3014ffac1eea99e84e83fc2"}, + {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6c0097a41968b2e2b54ed3424739aab0b762ca92af2379f152c1aef0187e1c"}, + {file = "websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7ff794c8b36bc402f2e07c0b2ceb4a2424147ed4785ff03e2a7af03711d60a"}, + {file = "websockets-14.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dec254fcabc7bd488dab64846f588fc5b6fe0d78f641180030f8ea27b76d72c3"}, + {file = "websockets-14.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bbe03eb853e17fd5b15448328b4ec7fb2407d45fb0245036d06a3af251f8e48f"}, + {file = "websockets-14.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3c4aa3428b904d5404a0ed85f3644d37e2cb25996b7f096d77caeb0e96a3b42"}, + {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:577a4cebf1ceaf0b65ffc42c54856214165fb8ceeba3935852fc33f6b0c55e7f"}, + {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad1c1d02357b7665e700eca43a31d52814ad9ad9b89b58118bdabc365454b574"}, + {file = "websockets-14.2-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f390024a47d904613577df83ba700bd189eedc09c57af0a904e5c39624621270"}, + {file = "websockets-14.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3c1426c021c38cf92b453cdf371228d3430acd775edee6bac5a4d577efc72365"}, + {file = "websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b"}, + {file = "websockets-14.2.tar.gz", hash = "sha256:5059ed9c54945efb321f097084b4c7e52c246f2c869815876a69d1efc4ad6eb5"}, ] [[package]] @@ -6492,17 +6580,18 @@ cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\ cffi = ["cffi (>=1.11)"] [extras] -all = ["autoflake", "black", "datasets", "docker", "fastapi", "isort", "langchain", "langchain-community", "locust", "pexpect", "pg8000", "pgvector", "pre-commit", "psycopg2", "psycopg2-binary", "pyright", "pytest-asyncio", "pytest-order", "uvicorn", "websockets", "wikipedia"] +all = ["autoflake", "black", "datasets", "docker", "fastapi", "isort", "langchain", "langchain-community", "locust", "pexpect", "pg8000", "pgvector", "pre-commit", "psycopg2", "psycopg2-binary", "pyright", "pytest-asyncio", "pytest-order", "uvicorn", "wikipedia"] bedrock = [] cloud-tool-sandbox = ["e2b-code-interpreter"] dev = ["autoflake", "black", "datasets", "isort", "locust", "pexpect", "pre-commit", "pyright", "pytest-asyncio", "pytest-order"] external-tools = ["docker", "langchain", "langchain-community", "wikipedia"] +google = ["google-genai"] postgres = ["pg8000", "pgvector", "psycopg2", "psycopg2-binary"] qdrant = ["qdrant-client"] -server = ["fastapi", "uvicorn", "websockets"] +server = ["fastapi", "uvicorn"] tests = ["wikipedia"] [metadata] lock-version = "2.0" python-versions = "<3.14,>=3.10" -content-hash = "1cb8ed2407a871e0753b46cd32454b0c78fb166fe60624b12265f800430e6d28" +content-hash = "45a69f6422acba29dff7f93352c2b8a42d1ce6e1a5f1b0549bc86c12a2aee3b6" diff --git a/pyproject.toml b/pyproject.toml index 7921d6edb..d97ab6b75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,6 @@ prettytable = "^3.9.0" pgvector = { version = "^0.2.3", optional = true } pre-commit = {version = "^3.5.0", optional = true } pg8000 = {version = "^1.30.3", optional = true} -websockets = {version = "^12.0", optional = true} docstring-parser = ">=0.16,<0.17" httpx = "^0.28.0" numpy = "^1.26.2" @@ -79,6 +78,7 @@ e2b-code-interpreter = {version = "^1.0.3", optional = true} anthropic = "^0.43.0" letta_client = "^0.1.23" openai = "^1.60.0" +google-genai = {version = "^1.1.0", optional = true} faker = "^36.1.0" colorama = "^0.4.6" @@ -93,6 +93,7 @@ external-tools = ["docker", "langchain", "wikipedia", "langchain-community"] tests = ["wikipedia"] all = ["pgvector", "pg8000", "psycopg2-binary", "psycopg2", "pytest", "pytest-asyncio", "pexpect", "black", "pre-commit", "datasets", "pyright", "pytest-order", "autoflake", "isort", "websockets", "fastapi", "uvicorn", "docker", "langchain", "wikipedia", "langchain-community", "locust"] bedrock = ["boto3"] +google = ["google-genai"] [tool.poetry.group.dev.dependencies] black = "^24.4.2" diff --git a/tests/configs/llm_model_configs/gemini-vertex.json b/tests/configs/llm_model_configs/gemini-vertex.json new file mode 100644 index 000000000..a9a1f2aff --- /dev/null +++ b/tests/configs/llm_model_configs/gemini-vertex.json @@ -0,0 +1,7 @@ +{ + "model": "gemini-2.0-pro-exp-02-05", + "model_endpoint_type": "google_vertex", + "model_endpoint": "https://us-central1-aiplatform.googleapis.com/v1/projects/memgpt-428419/locations/us-central1", + "context_window": 2097152, + "put_inner_thoughts_in_kwargs": true +} diff --git a/tests/test_model_letta_performance.py b/tests/test_model_letta_performance.py index bcc5c5f69..369552c6d 100644 --- a/tests/test_model_letta_performance.py +++ b/tests/test_model_letta_performance.py @@ -303,6 +303,18 @@ def test_gemini_pro_15_edit_core_memory(): print(f"Got successful response from client: \n\n{response}") +# ====================================================================================================================== +# GOOGLE VERTEX TESTS +# ====================================================================================================================== +@pytest.mark.vertex_basic +@retry_until_success(max_attempts=1, sleep_time_seconds=2) +def test_vertex_gemini_pro_20_returns_valid_first_message(): + filename = os.path.join(llm_config_dir, "gemini-vertex.json") + response = check_first_response_is_valid_for_llm_endpoint(filename) + # Log out successful response + print(f"Got successful response from client: \n\n{response}") + + # ====================================================================================================================== # TOGETHER TESTS # ====================================================================================================================== diff --git a/tests/test_providers.py b/tests/test_providers.py index a575fba54..5dd99fbe4 100644 --- a/tests/test_providers.py +++ b/tests/test_providers.py @@ -5,6 +5,7 @@ from letta.schemas.providers import ( AnthropicProvider, AzureProvider, GoogleAIProvider, + GoogleVertexProvider, GroqProvider, MistralProvider, OllamaProvider, @@ -66,6 +67,16 @@ def test_googleai(): provider.list_embedding_models() +def test_google_vertex(): + provider = GoogleVertexProvider(google_cloud_project=os.getenv("GCP_PROJECT_ID"), google_cloud_location=os.getenv("GCP_REGION")) + models = provider.list_llm_models() + print(models) + print([m.model for m in models]) + + embedding_models = provider.list_embedding_models() + print([m.embedding_model for m in embedding_models]) + + def test_mistral(): provider = MistralProvider(api_key=os.getenv("MISTRAL_API_KEY")) models = provider.list_llm_models()