diff --git a/docs/autogen.md b/docs/autogen.md index c4d14d13c7..8c59cd59a0 100644 --- a/docs/autogen.md +++ b/docs/autogen.md @@ -8,7 +8,7 @@ The MemGPT+AutoGen integration was last tested using AutoGen version v0.2.0. - If you are having issues, please first try installing the specific version of AutoGen using `pip install pyautogen==0.2.0` + You can run the `poetry install -E autogen` to install all the dependencies related to autogen module. If you are having issues, then try installing the specific version of AutoGen using `pip install pyautogen==0.2.0`. ## Overview diff --git a/memgpt/agent.py b/memgpt/agent.py index 3777cb4436..3ac0262cd5 100644 --- a/memgpt/agent.py +++ b/memgpt/agent.py @@ -6,10 +6,22 @@ from memgpt.persistence_manager import LocalStateManager from memgpt.config import AgentConfig, MemGPTConfig -from memgpt.system import get_login_event, package_function_response, package_summarize_message, get_initial_boot_messages +from memgpt.system import ( + get_login_event, + package_function_response, + package_summarize_message, + get_initial_boot_messages, +) from memgpt.memory import CoreMemory as Memory, summarize_messages from memgpt.openai_tools import create, is_context_overflow_error -from memgpt.utils import get_local_time, parse_json, united_diff, printd, count_tokens, get_schema_diff +from memgpt.utils import ( + get_local_time, + parse_json, + united_diff, + printd, + count_tokens, + get_schema_diff, +) from memgpt.constants import ( FIRST_MESSAGE_ATTEMPTS, MESSAGE_SUMMARY_WARNING_FRAC, @@ -29,13 +41,23 @@ def initialize_memory(ai_notes, human_notes): raise ValueError(ai_notes) if human_notes is None: raise ValueError(human_notes) - memory = Memory(human_char_limit=CORE_MEMORY_HUMAN_CHAR_LIMIT, persona_char_limit=CORE_MEMORY_PERSONA_CHAR_LIMIT) + memory = Memory( + human_char_limit=CORE_MEMORY_HUMAN_CHAR_LIMIT, + persona_char_limit=CORE_MEMORY_PERSONA_CHAR_LIMIT, + ) memory.edit_persona(ai_notes) memory.edit_human(human_notes) return memory -def construct_system_with_memory(system, memory, memory_edit_timestamp, archival_memory=None, recall_memory=None, include_char_count=True): +def construct_system_with_memory( + system, + memory, + memory_edit_timestamp, + archival_memory=None, + recall_memory=None, + include_char_count=True, +): full_system_message = "\n".join( [ system, @@ -68,7 +90,11 @@ def initialize_message_sequence( memory_edit_timestamp = get_local_time() full_system_message = construct_system_with_memory( - system, memory, memory_edit_timestamp, archival_memory=archival_memory, recall_memory=recall_memory + system, + memory, + memory_edit_timestamp, + archival_memory=archival_memory, + recall_memory=recall_memory, ) first_user_message = get_login_event() # event letting MemGPT know the user just logged in @@ -486,7 +512,11 @@ def handle_ai_response(self, response_message): } ) # extend conversation with function response self.interface.function_message(f"Error: {error_msg}") - return messages, None, True # force a heartbeat to allow agent to handle error + return ( + messages, + None, + True, + ) # force a heartbeat to allow agent to handle error # Failure case 2: function name is OK, but function args are bad JSON try: @@ -503,7 +533,11 @@ def handle_ai_response(self, response_message): } ) # extend conversation with function response self.interface.function_message(f"Error: {error_msg}") - return messages, None, True # force a heartbeat to allow agent to handle error + return ( + messages, + None, + True, + ) # force a heartbeat to allow agent to handle error # (Still parsing function args) # Handle requests for immediate heartbeat @@ -538,7 +572,11 @@ def handle_ai_response(self, response_message): } ) # extend conversation with function response self.interface.function_message(f"Error: {error_msg}") - return messages, None, True # force a heartbeat to allow agent to handle error + return ( + messages, + None, + True, + ) # force a heartbeat to allow agent to handle error # If no failures happened along the way: ... # Step 4: send the info on the function call and function response to GPT @@ -560,7 +598,13 @@ def handle_ai_response(self, response_message): return messages, heartbeat_request, function_failed - def step(self, user_message, first_message=False, first_message_retry_limit=FIRST_MESSAGE_ATTEMPTS, skip_verify=False): + def step( + self, + user_message, + first_message=False, + first_message_retry_limit=FIRST_MESSAGE_ATTEMPTS, + skip_verify=False, + ): """Top-level event message handler for the MemGPT agent""" try: @@ -611,7 +655,11 @@ def step(self, user_message, first_message=False, first_message_retry_limit=FIRS # (if yes) Step 4: send the info on the function call and function response to LLM response_message = response.choices[0].message response_message_copy = response_message.copy() - all_response_messages, heartbeat_request, function_failed = self.handle_ai_response(response_message) + ( + all_response_messages, + heartbeat_request, + function_failed, + ) = self.handle_ai_response(response_message) # Add the extra metadata to the assistant response # (e.g. enough metadata to enable recreating the API call) @@ -657,7 +705,12 @@ def step(self, user_message, first_message=False, first_message_retry_limit=FIRS ) self.append_to_messages(all_new_messages) - return all_new_messages, heartbeat_request, function_failed, active_memory_warning + return ( + all_new_messages, + heartbeat_request, + function_failed, + active_memory_warning, + ) except Exception as e: printd(f"step() failed\nuser_message = {user_message}\nerror = {e}") @@ -735,7 +788,10 @@ def summarize_messages_inplace(self, cutoff=None, preserve_last_N_messages=True) if (self.model is not None and self.model in LLM_MAX_TOKENS) else str(LLM_MAX_TOKENS["DEFAULT"]) ) - summary = summarize_messages(agent_config=self.config, message_sequence_to_summarize=message_sequence_to_summarize) + summary = summarize_messages( + agent_config=self.config, + message_sequence_to_summarize=message_sequence_to_summarize, + ) printd(f"Got summary: {summary}") # Metadata that's useful for the agent to see diff --git a/memgpt/autogen/examples/agent_docs.py b/memgpt/autogen/examples/agent_docs.py index 97833ece26..6a83077435 100644 --- a/memgpt/autogen/examples/agent_docs.py +++ b/memgpt/autogen/examples/agent_docs.py @@ -157,7 +157,12 @@ memgpt_agent.load_and_attach("memgpt_research_paper", "directory") # Initialize the group chat between the agents -groupchat = autogen.GroupChat(agents=[user_proxy, memgpt_agent], messages=[], max_round=12, speaker_selection_method="round_robin") +groupchat = autogen.GroupChat( + agents=[user_proxy, memgpt_agent], + messages=[], + max_round=12, + speaker_selection_method="round_robin", +) manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config) # Begin the group chat with a message from the user diff --git a/memgpt/autogen/memgpt_agent.py b/memgpt/autogen/memgpt_agent.py index 20fb9da02b..15a4084faa 100644 --- a/memgpt/autogen/memgpt_agent.py +++ b/memgpt/autogen/memgpt_agent.py @@ -1,4 +1,10 @@ -from autogen.agentchat import Agent, ConversableAgent, UserProxyAgent, GroupChat, GroupChatManager +from autogen.agentchat import ( + Agent, + ConversableAgent, + UserProxyAgent, + GroupChat, + GroupChatManager, +) from memgpt.agent import Agent as _Agent from typing import Callable, Optional, List, Dict, Union, Any, Tuple @@ -11,7 +17,13 @@ import memgpt.presets.presets as presets from memgpt.config import AgentConfig, MemGPTConfig from memgpt.cli.cli import attach -from memgpt.cli.cli_load import load_directory, load_webpage, load_index, load_database, load_vector_database +from memgpt.cli.cli_load import ( + load_directory, + load_webpage, + load_index, + load_database, + load_vector_database, +) from memgpt.connectors.storage import StorageConnector diff --git a/memgpt/cli/cli.py b/memgpt/cli/cli.py index 71fea45849..ed49d997fe 100644 --- a/memgpt/cli/cli.py +++ b/memgpt/cli/cli.py @@ -30,10 +30,16 @@ def run( model_wrapper: str = typer.Option(None, help="Specify the LLM model wrapper"), model_endpoint: str = typer.Option(None, help="Specify the LLM model endpoint"), model_endpoint_type: str = typer.Option(None, help="Specify the LLM model endpoint type"), - context_window: int = typer.Option(None, help="The context window of the LLM you are using (e.g. 8k for most Mistral 7B variants)"), + context_window: int = typer.Option( + None, + help="The context window of the LLM you are using (e.g. 8k for most Mistral 7B variants)", + ), # other first: bool = typer.Option(False, "--first", help="Use --first to send the first message in the sequence"), - strip_ui: bool = typer.Option(False, help="Remove all the bells and whistles in CLI output (helpful for testing)"), + strip_ui: bool = typer.Option( + False, + help="Remove all the bells and whistles in CLI output (helpful for testing)", + ), debug: bool = typer.Option(False, "--debug", help="Use --debug to enable debugging output"), no_verify: bool = typer.Option(False, help="Bypass message verification"), yes: bool = typer.Option(False, "-y", help="Skip confirmation prompt and use defaults"), @@ -68,7 +74,10 @@ def run( # force re-configuration is config is from old version if config.memgpt_version is None: # TODO: eventually add checks for older versions, if config changes again - typer.secho("MemGPT has been updated to a newer version, so re-running configuration.", fg=typer.colors.YELLOW) + typer.secho( + "MemGPT has been updated to a newer version, so re-running configuration.", + fg=typer.colors.YELLOW, + ) configure() config = MemGPTConfig.load() @@ -107,17 +116,26 @@ def run( # persistence_manager = LocalStateManager(agent_config).load() # TODO: implement load # TODO: load prior agent state if persona and persona != agent_config.persona: - typer.secho(f"{CLI_WARNING_PREFIX}Overriding existing persona {agent_config.persona} with {persona}", fg=typer.colors.YELLOW) + typer.secho( + f"{CLI_WARNING_PREFIX}Overriding existing persona {agent_config.persona} with {persona}", + fg=typer.colors.YELLOW, + ) agent_config.persona = persona # raise ValueError(f"Cannot override {agent_config.name} existing persona {agent_config.persona} with {persona}") if human and human != agent_config.human: - typer.secho(f"{CLI_WARNING_PREFIX}Overriding existing human {agent_config.human} with {human}", fg=typer.colors.YELLOW) + typer.secho( + f"{CLI_WARNING_PREFIX}Overriding existing human {agent_config.human} with {human}", + fg=typer.colors.YELLOW, + ) agent_config.human = human # raise ValueError(f"Cannot override {agent_config.name} existing human {agent_config.human} with {human}") # Allow overriding model specifics (model, model wrapper, model endpoint IP + type, context_window) if model and model != agent_config.model: - typer.secho(f"{CLI_WARNING_PREFIX}Overriding existing model {agent_config.model} with {model}", fg=typer.colors.YELLOW) + typer.secho( + f"{CLI_WARNING_PREFIX}Overriding existing model {agent_config.model} with {model}", + fg=typer.colors.YELLOW, + ) agent_config.model = model if context_window is not None and int(context_window) != agent_config.context_window: typer.secho( diff --git a/memgpt/cli/cli_config.py b/memgpt/cli/cli_config.py index 787d6bb590..bee759e1b3 100644 --- a/memgpt/cli/cli_config.py +++ b/memgpt/cli/cli_config.py @@ -12,7 +12,11 @@ from memgpt.constants import MEMGPT_DIR from memgpt.connectors.storage import StorageConnector from memgpt.constants import LLM_MAX_TOKENS -from memgpt.local_llm.constants import DEFAULT_ENDPOINTS, DEFAULT_OLLAMA_MODEL, DEFAULT_WRAPPER_NAME +from memgpt.local_llm.constants import ( + DEFAULT_ENDPOINTS, + DEFAULT_OLLAMA_MODEL, + DEFAULT_WRAPPER_NAME, +) from memgpt.local_llm.utils import get_available_wrappers app = typer.Typer() @@ -43,11 +47,16 @@ def configure_llm_endpoint(config: MemGPTConfig): # get default default_model_endpoint_type = config.model_endpoint_type - if config.model_endpoint_type is not None and config.model_endpoint_type not in ["openai", "azure"]: # local model + if config.model_endpoint_type is not None and config.model_endpoint_type not in [ + "openai", + "azure", + ]: # local model default_model_endpoint_type = "local" provider = questionary.select( - "Select LLM inference provider:", choices=["openai", "azure", "local"], default=default_model_endpoint_type + "Select LLM inference provider:", + choices=["openai", "azure", "local"], + default=default_model_endpoint_type, ).ask() # set: model_endpoint_type, model_endpoint @@ -60,7 +69,16 @@ def configure_llm_endpoint(config: MemGPTConfig): model_endpoint_type = "azure" model_endpoint = get_azure_credentials()["azure_endpoint"] else: # local models - backend_options = ["webui", "webui-legacy", "llamacpp", "koboldcpp", "ollama", "lmstudio", "vllm", "openai"] + backend_options = [ + "webui", + "webui-legacy", + "llamacpp", + "koboldcpp", + "ollama", + "lmstudio", + "vllm", + "openai", + ] default_model_endpoint_type = None if config.model_endpoint_type in backend_options: # set from previous config @@ -100,11 +118,18 @@ def configure_model(config: MemGPTConfig, model_endpoint_type: str): # set: model, model_wrapper model, model_wrapper = None, None if model_endpoint_type == "openai" or model_endpoint_type == "azure": - model_options = ["gpt-4", "gpt-4-1106-preview", "gpt-3.5-turbo", "gpt-3.5-turbo-16k"] + model_options = [ + "gpt-4", + "gpt-4-1106-preview", + "gpt-3.5-turbo", + "gpt-3.5-turbo-16k", + ] # TODO: select valid_model = config.model in model_options model = questionary.select( - "Select default model (recommended: gpt-4):", choices=model_options, default=config.model if valid_model else model_options[0] + "Select default model (recommended: gpt-4):", + choices=model_options, + default=config.model if valid_model else model_options[0], ).ask() else: # local models # ollama also needs model type @@ -174,9 +199,16 @@ def configure_embedding_endpoint(config: MemGPTConfig): default_embedding_endpoint_type = config.embedding_endpoint_type - embedding_endpoint_type, embedding_endpoint, embedding_dim, embedding_model = None, None, None, None + embedding_endpoint_type, embedding_endpoint, embedding_dim, embedding_model = ( + None, + None, + None, + None, + ) embedding_provider = questionary.select( - "Select embedding provider:", choices=["openai", "azure", "hugging-face", "local"], default=default_embedding_endpoint_type + "Select embedding provider:", + choices=["openai", "azure", "hugging-face", "local"], + default=default_embedding_endpoint_type, ).ask() if embedding_provider == "openai": embedding_endpoint_type = "openai" @@ -207,7 +239,10 @@ def configure_embedding_endpoint(config: MemGPTConfig): # get model dimentions default_embedding_dim = config.embedding_dim if config.embedding_dim else "1024" - embedding_dim = questionary.text("Enter embedding model dimentions (e.g. 1024):", default=str(default_embedding_dim)).ask() + embedding_dim = questionary.text( + "Enter embedding model dimentions (e.g. 1024):", + default=str(default_embedding_dim), + ).ask() try: embedding_dim = int(embedding_dim) except Exception as e: @@ -248,7 +283,9 @@ def configure_archival_storage(config: MemGPTConfig): # Configure archival storage backend archival_storage_options = ["local", "lancedb", "postgres", "chroma"] archival_storage_type = questionary.select( - "Select storage backend for archival data:", archival_storage_options, default=config.archival_storage_type + "Select storage backend for archival data:", + archival_storage_options, + default=config.archival_storage_type, ).ask() archival_storage_uri, archival_storage_path = None, None @@ -277,7 +314,10 @@ def configure_archival_storage(config: MemGPTConfig): config.archival_storage_path if config.archival_storage_path else os.path.join(config.config_path, "chroma") ) print(default_archival_storage_path) - archival_storage_path = questionary.text("Enter persistent storage location:", default=default_archival_storage_path).ask() + archival_storage_path = questionary.text( + "Enter persistent storage location:", + default=default_archival_storage_path, + ).ask() return archival_storage_type, archival_storage_uri, archival_storage_path @@ -294,19 +334,39 @@ def configure(): config = MemGPTConfig.load() model_endpoint_type, model_endpoint = configure_llm_endpoint(config) model, model_wrapper, context_window = configure_model(config, model_endpoint_type) - embedding_endpoint_type, embedding_endpoint, embedding_dim, embedding_model = configure_embedding_endpoint(config) + ( + embedding_endpoint_type, + embedding_endpoint, + embedding_dim, + embedding_model, + ) = configure_embedding_endpoint(config) default_preset, default_persona, default_human, default_agent = configure_cli(config) - archival_storage_type, archival_storage_uri, archival_storage_path = configure_archival_storage(config) + ( + archival_storage_type, + archival_storage_uri, + archival_storage_path, + ) = configure_archival_storage(config) # check credentials azure_creds = get_azure_credentials() # azure_key, azure_endpoint, azure_version, azure_deployment, azure_embedding_deployment = get_azure_credentials() openai_key = get_openai_credentials() if model_endpoint_type == "azure" or embedding_endpoint_type == "azure": - if all([azure_creds["azure_key"], azure_creds["azure_endpoint"], azure_creds["azure_version"]]): + if all( + [ + azure_creds["azure_key"], + azure_creds["azure_endpoint"], + azure_creds["azure_version"], + ] + ): print(f"Using Microsoft endpoint {azure_creds['azure_endpoint']}.") # Deployment can optionally customize your endpoint model name - if all([azure_creds["azure_deployment"], azure_creds["azure_embedding_deployment"]]): + if all( + [ + azure_creds["azure_deployment"], + azure_creds["azure_embedding_deployment"], + ] + ): print(f"Using deployment id {azure_creds['azure_deployment']}") else: raise ValueError( @@ -356,7 +416,14 @@ def list(option: str): if option == "agents": """List all agents""" table = PrettyTable() - table.field_names = ["Name", "Model", "Persona", "Human", "Data Source", "Create Time"] + table.field_names = [ + "Name", + "Model", + "Persona", + "Human", + "Data Source", + "Create Time", + ] for agent_file in utils.list_agent_config_files(): agent_name = os.path.basename(agent_file).replace(".json", "") agent_config = AgentConfig.load(agent_name) diff --git a/memgpt/cli/cli_load.py b/memgpt/cli/cli_load.py index 780a28a0fe..406643be47 100644 --- a/memgpt/cli/cli_load.py +++ b/memgpt/cli/cli_load.py @@ -56,7 +56,8 @@ def store_docs(name, docs, show_progress=True): @app.command("index") def load_index( - name: str = typer.Option(help="Name of dataset to load."), dir: str = typer.Option(help="Path to directory containing index.") + name: str = typer.Option(help="Name of dataset to load."), + dir: str = typer.Option(help="Path to directory containing index."), ): """Load a LlamaIndex saved VectorIndex into MemGPT""" # load index data @@ -189,7 +190,10 @@ def load_vector_database( config = MemGPTConfig.load() # Prepare a select statement - select_statement = select(table.c[text_column], table.c[embedding_column].cast(Vector(config.embedding_dim))) + select_statement = select( + table.c[text_column], + table.c[embedding_column].cast(Vector(config.embedding_dim)), + ) # Execute the query and fetch the results with engine.connect() as connection: diff --git a/memgpt/config.py b/memgpt/config.py index 63c5fc1c1d..ec988c74e0 100644 --- a/memgpt/config.py +++ b/memgpt/config.py @@ -213,7 +213,15 @@ def create_config_dir(): if not os.path.exists(MEMGPT_DIR): os.makedirs(MEMGPT_DIR, exist_ok=True) - folders = ["personas", "humans", "archival", "agents", "functions", "system_prompts", "presets"] + folders = [ + "personas", + "humans", + "archival", + "agents", + "functions", + "system_prompts", + "presets", + ] for folder in folders: if not os.path.exists(os.path.join(MEMGPT_DIR, folder)): os.makedirs(os.path.join(MEMGPT_DIR, folder)) diff --git a/memgpt/connectors/chroma.py b/memgpt/connectors/chroma.py index 8db7aa2ee2..7b7a8a101b 100644 --- a/memgpt/connectors/chroma.py +++ b/memgpt/connectors/chroma.py @@ -69,17 +69,27 @@ def get(self, id: str) -> Optional[Passage]: return [Passage(text=text, embedding=embedding) for (text, embedding) in zip(results["documents"], results["embeddings"])] def insert(self, passage: Passage): - self.collection.add(documents=[passage.text], embeddings=[passage.embedding], ids=[str(self.collection.count())]) + self.collection.add( + documents=[passage.text], + embeddings=[passage.embedding], + ids=[str(self.collection.count())], + ) def insert_many(self, passages: List[Passage], show_progress=True): count = self.collection.count() ids = [str(count + i) for i in range(len(passages))] self.collection.add( - documents=[passage.text for passage in passages], embeddings=[passage.embedding for passage in passages], ids=ids + documents=[passage.text for passage in passages], + embeddings=[passage.embedding for passage in passages], + ids=ids, ) def query(self, query: str, query_vec: List[float], top_k: int = 10) -> List[Passage]: - results = self.collection.query(query_embeddings=[query_vec], n_results=top_k, include=["embeddings", "documents"]) + results = self.collection.query( + query_embeddings=[query_vec], + n_results=top_k, + include=["embeddings", "documents"], + ) # get index [0] since query is passed as list return [Passage(text=text, embedding=embedding) for (text, embedding) in zip(results["documents"][0], results["embeddings"][0])] diff --git a/memgpt/connectors/db.py b/memgpt/connectors/db.py index ac09e4ddcd..e2abf2c384 100644 --- a/memgpt/connectors/db.py +++ b/memgpt/connectors/db.py @@ -44,7 +44,11 @@ def __repr__(self): """Create database model for table_name""" class_name = f"{table_name.capitalize()}Model" - Model = type(class_name, (PassageModel,), {"__tablename__": table_name, "__table_args__": {"extend_existing": True}}) + Model = type( + class_name, + (PassageModel,), + {"__tablename__": table_name, "__table_args__": {"extend_existing": True}}, + ) return Model @@ -105,7 +109,12 @@ def get(self, id: str) -> Optional[Passage]: db_passage = session.query(self.db_model).get(id) if db_passage is None: return None - return Passage(text=db_passage.text, embedding=db_passage.embedding, doc_id=db_passage.doc_id, passage_id=db_passage.passage_id) + return Passage( + text=db_passage.text, + embedding=db_passage.embedding, + doc_id=db_passage.doc_id, + passage_id=db_passage.passage_id, + ) def size(self) -> int: # return size of table @@ -133,7 +142,12 @@ def query(self, query: str, query_vec: List[float], top_k: int = 10) -> List[Pas # Convert the results into Passage objects passages = [ - Passage(text=result.text, embedding=np.frombuffer(result.embedding), doc_id=result.doc_id, passage_id=result.id) + Passage( + text=result.text, + embedding=np.frombuffer(result.embedding), + doc_id=result.doc_id, + passage_id=result.id, + ) for result in results ] return passages @@ -228,7 +242,13 @@ def get_all_paginated(self, page_size: int) -> Iterator[List[Passage]]: # Yield a list of Passage objects converted from the chunk yield [ - Passage(text=p["text"], embedding=p["vector"], doc_id=p["doc_id"], passage_id=p["passage_id"]) for p in db_passages_chunk + Passage( + text=p["text"], + embedding=p["vector"], + doc_id=p["doc_id"], + passage_id=p["passage_id"], + ) + for p in db_passages_chunk ] # Increment the offset to get the next chunk in the next iteration @@ -236,14 +256,25 @@ def get_all_paginated(self, page_size: int) -> Iterator[List[Passage]]: def get_all(self, limit=10) -> List[Passage]: db_passages = self.table.to_lance().to_table(limit=limit).to_pylist() - return [Passage(text=p["text"], embedding=p["vector"], doc_id=p["doc_id"], passage_id=p["passage_id"]) for p in db_passages] + return [ + Passage( + text=p["text"], + embedding=p["vector"], + doc_id=p["doc_id"], + passage_id=p["passage_id"], + ) + for p in db_passages + ] def get(self, id: str) -> Optional[Passage]: db_passage = self.table.where(f"passage_id={id}").to_list() if len(db_passage) == 0: return None return Passage( - text=db_passage["text"], embedding=db_passage["embedding"], doc_id=db_passage["doc_id"], passage_id=db_passage["passage_id"] + text=db_passage["text"], + embedding=db_passage["embedding"], + doc_id=db_passage["doc_id"], + passage_id=db_passage["passage_id"], ) def size(self) -> int: @@ -255,7 +286,14 @@ def size(self) -> int: return 0 def insert(self, passage: Passage): - data = [{"doc_id": passage.doc_id, "text": passage.text, "passage_id": passage.passage_id, "vector": passage.embedding}] + data = [ + { + "doc_id": passage.doc_id, + "text": passage.text, + "passage_id": passage.passage_id, + "vector": passage.embedding, + } + ] if self.table is not None: self.table.add(data) @@ -266,7 +304,12 @@ def insert_many(self, passages: List[Passage], show_progress=True): data = [] iterable = tqdm(passages) if show_progress else passages for passage in iterable: - temp_dict = {"doc_id": passage.doc_id, "text": passage.text, "passage_id": passage.passage_id, "vector": passage.embedding} + temp_dict = { + "doc_id": passage.doc_id, + "text": passage.text, + "passage_id": passage.passage_id, + "vector": passage.embedding, + } data.append(temp_dict) if self.table is not None: @@ -279,7 +322,12 @@ def query(self, query: str, query_vec: List[float], top_k: int = 10) -> List[Pas results = self.table.search(query_vec).limit(top_k).to_list() # Convert the results into Passage objects passages = [ - Passage(text=result["text"], embedding=result["vector"], doc_id=result["doc_id"], passage_id=result["passage_id"]) + Passage( + text=result["text"], + embedding=result["vector"], + doc_id=result["doc_id"], + passage_id=result["passage_id"], + ) for result in results ] return passages diff --git a/memgpt/connectors/local.py b/memgpt/connectors/local.py index a773c38063..af5d694d41 100644 --- a/memgpt/connectors/local.py +++ b/memgpt/connectors/local.py @@ -38,7 +38,11 @@ def __init__(self, name: Optional[str] = None, agent_config: Optional[AgentConfi # llama index contexts self.embed_model = embedding_model() - self.service_context = ServiceContext.from_defaults(llm=None, embed_model=self.embed_model, chunk_size=config.embedding_chunk_size) + self.service_context = ServiceContext.from_defaults( + llm=None, + embed_model=self.embed_model, + chunk_size=config.embedding_chunk_size, + ) set_global_service_context(self.service_context) # load/create index diff --git a/memgpt/connectors/storage.py b/memgpt/connectors/storage.py index dc9089fce8..9322e7ea14 100644 --- a/memgpt/connectors/storage.py +++ b/memgpt/connectors/storage.py @@ -26,7 +26,13 @@ class Passage: It is a string of text with an associated embedding. """ - def __init__(self, text: str, embedding: np.ndarray, doc_id: Optional[str] = None, passage_id: Optional[str] = None): + def __init__( + self, + text: str, + embedding: np.ndarray, + doc_id: Optional[str] = None, + passage_id: Optional[str] = None, + ): self.text = text self.embedding = embedding self.doc_id = doc_id diff --git a/memgpt/embeddings.py b/memgpt/embeddings.py index fc3023d434..dd07b72944 100644 --- a/memgpt/embeddings.py +++ b/memgpt/embeddings.py @@ -101,7 +101,9 @@ def embedding_model(): endpoint = config.embedding_endpoint_type if endpoint == "openai": model = OpenAIEmbedding( - api_base=config.embedding_endpoint, api_key=config.openai_key, additional_kwargs={"user": config.anon_clientid} + api_base=config.embedding_endpoint, + api_key=config.openai_key, + additional_kwargs={"user": config.anon_clientid}, ) return model elif endpoint == "azure": @@ -116,7 +118,11 @@ def embedding_model(): api_version=config.azure_version, ) elif endpoint == "hugging-face": - embed_model = EmbeddingEndpoint(model=config.embedding_model, base_url=config.embedding_endpoint, user=config.anon_clientid) + embed_model = EmbeddingEndpoint( + model=config.embedding_model, + base_url=config.embedding_endpoint, + user=config.anon_clientid, + ) return embed_model else: # default to hugging face model running local diff --git a/memgpt/functions/function_sets/extras.py b/memgpt/functions/function_sets/extras.py index 21ef96d548..1177e82050 100644 --- a/memgpt/functions/function_sets/extras.py +++ b/memgpt/functions/function_sets/extras.py @@ -4,7 +4,11 @@ import requests -from memgpt.constants import MESSAGE_CHATGPT_FUNCTION_MODEL, MESSAGE_CHATGPT_FUNCTION_SYSTEM_MESSAGE, MAX_PAUSE_HEARTBEATS +from memgpt.constants import ( + MESSAGE_CHATGPT_FUNCTION_MODEL, + MESSAGE_CHATGPT_FUNCTION_SYSTEM_MESSAGE, + MAX_PAUSE_HEARTBEATS, +) from memgpt.openai_tools import create @@ -121,6 +125,10 @@ def http_request(self, method: str, url: str, payload_json: Optional[str] = None print(f"[HTTP] launching {method} request to {url}, payload=\n{json.dumps(payload, indent=2)}") response = requests.request(method, url, json=payload, headers=headers) - return {"status_code": response.status_code, "headers": dict(response.headers), "body": response.text} + return { + "status_code": response.status_code, + "headers": dict(response.headers), + "body": response.text, + } except Exception as e: return {"error": str(e)} diff --git a/memgpt/functions/functions.py b/memgpt/functions/functions.py index e5296f7a28..2a92079766 100644 --- a/memgpt/functions/functions.py +++ b/memgpt/functions/functions.py @@ -56,7 +56,10 @@ def load_all_function_sets(merge=True): sys.path.append(user_scripts_dir) schemas_and_functions = {} - for dir_path, module_files in [(function_sets_dir, example_module_files), (user_scripts_dir, user_module_files)]: + for dir_path, module_files in [ + (function_sets_dir, example_module_files), + (user_scripts_dir, user_module_files), + ]: for file in module_files: module_name = file[:-3] # Remove '.py' from filename if dir_path == user_scripts_dir: diff --git a/memgpt/functions/schema_generator.py b/memgpt/functions/schema_generator.py index 1a111da220..97d60e474e 100644 --- a/memgpt/functions/schema_generator.py +++ b/memgpt/functions/schema_generator.py @@ -4,7 +4,11 @@ from docstring_parser import parse -from memgpt.constants import FUNCTION_PARAM_NAME_REQ_HEARTBEAT, FUNCTION_PARAM_TYPE_REQ_HEARTBEAT, FUNCTION_PARAM_DESCRIPTION_REQ_HEARTBEAT +from memgpt.constants import ( + FUNCTION_PARAM_NAME_REQ_HEARTBEAT, + FUNCTION_PARAM_TYPE_REQ_HEARTBEAT, + FUNCTION_PARAM_DESCRIPTION_REQ_HEARTBEAT, +) NO_HEARTBEAT_FUNCTIONS = ["send_message", "pause_heartbeats"] diff --git a/memgpt/local_llm/chat_completion_proxy.py b/memgpt/local_llm/chat_completion_proxy.py index b4fd794fe1..a33b6b2529 100644 --- a/memgpt/local_llm/chat_completion_proxy.py +++ b/memgpt/local_llm/chat_completion_proxy.py @@ -7,7 +7,9 @@ from box import Box from memgpt.local_llm.webui.api import get_webui_completion -from memgpt.local_llm.webui.legacy_api import get_webui_completion as get_webui_completion_legacy +from memgpt.local_llm.webui.legacy_api import ( + get_webui_completion as get_webui_completion_legacy, +) from memgpt.local_llm.lmstudio.api import get_lmstudio_completion from memgpt.local_llm.llamacpp.api import get_llamacpp_completion from memgpt.local_llm.koboldcpp.api import get_koboldcpp_completion @@ -72,7 +74,11 @@ def get_chat_completion( if "grammar" in wrapper: grammar_name = "json_func_calls_with_inner_thoughts" - if grammar_name is not None and endpoint_type not in ["koboldcpp", "llamacpp", "webui"]: + if grammar_name is not None and endpoint_type not in [ + "koboldcpp", + "llamacpp", + "webui", + ]: print(f"{CLI_WARNING_PREFIX}grammars are currently only supported when using llama.cpp as the MemGPT local LLM backend") # First step: turn the message sequence into a prompt that the model expects diff --git a/memgpt/main.py b/memgpt/main.py index 9bc7fdbc46..823d24539c 100644 --- a/memgpt/main.py +++ b/memgpt/main.py @@ -127,7 +127,10 @@ def run_agent_loop(memgpt_agent, first, no_verify=False, cfg=None, strip_ui=Fals if amount == 0: interface.print_messages(memgpt_agent.messages, dump=True) else: - interface.print_messages(memgpt_agent.messages[-min(amount, len(memgpt_agent.messages)) :], dump=True) + interface.print_messages( + memgpt_agent.messages[-min(amount, len(memgpt_agent.messages)) :], + dump=True, + ) continue elif user_input.lower() == "/dumpraw": @@ -236,9 +239,12 @@ def run_agent_loop(memgpt_agent, first, no_verify=False, cfg=None, strip_ui=Fals skip_next_user_input = False def process_agent_step(user_message, no_verify): - new_messages, heartbeat_request, function_failed, token_warning = memgpt_agent.step( - user_message, first_message=False, skip_verify=no_verify - ) + ( + new_messages, + heartbeat_request, + function_failed, + token_warning, + ) = memgpt_agent.step(user_message, first_message=False, skip_verify=no_verify) skip_next_user_input = False if token_warning: @@ -256,11 +262,19 @@ def process_agent_step(user_message, no_verify): while True: try: if strip_ui: - new_messages, user_message, skip_next_user_input = process_agent_step(user_message, no_verify) + ( + new_messages, + user_message, + skip_next_user_input, + ) = process_agent_step(user_message, no_verify) break else: with console.status("[bold cyan]Thinking...") as status: - new_messages, user_message, skip_next_user_input = process_agent_step(user_message, no_verify) + ( + new_messages, + user_message, + skip_next_user_input, + ) = process_agent_step(user_message, no_verify) break except KeyboardInterrupt: print("User interrupt occured.") diff --git a/memgpt/memory.py b/memgpt/memory.py index 27fb1b634e..353664acaf 100644 --- a/memgpt/memory.py +++ b/memgpt/memory.py @@ -22,7 +22,14 @@ class CoreMemory(object): and any other baseline data you deem necessary for the AI's basic functioning. """ - def __init__(self, persona=None, human=None, persona_char_limit=None, human_char_limit=None, archival_memory_exists=True): + def __init__( + self, + persona=None, + human=None, + persona_char_limit=None, + human_char_limit=None, + archival_memory_exists=True, + ): self.persona = persona self.human = human self.persona_char_limit = persona_char_limit @@ -114,7 +121,12 @@ def summarize_messages( trunc_ratio = (MESSAGE_SUMMARY_WARNING_FRAC * context_window / summary_input_tkns) * 0.8 # For good measure... cutoff = int(len(message_sequence_to_summarize) * trunc_ratio) summary_input = str( - [summarize_messages(agent_config=agent_config, message_sequence_to_summarize=message_sequence_to_summarize[:cutoff])] + [ + summarize_messages( + agent_config=agent_config, + message_sequence_to_summarize=message_sequence_to_summarize[:cutoff], + ) + ] + message_sequence_to_summarize[cutoff:] ) message_sequence = [ @@ -335,7 +347,13 @@ def insert(self, memory_string): # breakup string into passages for node in parser.get_nodes_from_documents([Document(text=memory_string)]): embedding = self.embed_model.get_text_embedding(node.text) - passages.append(Passage(text=node.text, embedding=embedding, doc_id=f"agent_{self.agent_config.name}_memory")) + passages.append( + Passage( + text=node.text, + embedding=embedding, + doc_id=f"agent_{self.agent_config.name}_memory", + ) + ) # insert passages self.storage.insert_many(passages) diff --git a/memgpt/persistence_manager.py b/memgpt/persistence_manager.py index 1138a10937..38660ef31c 100644 --- a/memgpt/persistence_manager.py +++ b/memgpt/persistence_manager.py @@ -108,7 +108,10 @@ def append_to_messages(self, added_messages): def swap_system_message(self, new_system_message): # first tag with timestamps - new_system_message = {"timestamp": get_local_time(), "message": new_system_message} + new_system_message = { + "timestamp": get_local_time(), + "message": new_system_message, + } printd(f"{self.__class__.__name__}.swap_system_message") self.messages[0] = new_system_message diff --git a/memgpt/server/rest_api/server.py b/memgpt/server/rest_api/server.py index ca23e0994b..37d28819fa 100644 --- a/memgpt/server/rest_api/server.py +++ b/memgpt/server/rest_api/server.py @@ -74,7 +74,13 @@ async def user_message(body: UserMessage): # Check if server.user_message is an async function if asyncio.iscoroutinefunction(server.user_message): # Start the async task - asyncio.create_task(server.user_message(user_id=body.user_id, agent_id=body.agent_id, message=body.message)) + asyncio.create_task( + server.user_message( + user_id=body.user_id, + agent_id=body.agent_id, + message=body.message, + ) + ) else: # Run the synchronous function in a thread pool loop = asyncio.get_event_loop() diff --git a/memgpt/server/server.py b/memgpt/server/server.py index 0de45e8614..2f4b3dbff5 100644 --- a/memgpt/server/server.py +++ b/memgpt/server/server.py @@ -146,9 +146,12 @@ def _step(self, user_id: str, agent_id: str, input_message: str) -> None: next_input_message = input_message counter = 0 while True: - new_messages, heartbeat_request, function_failed, token_warning = memgpt_agent.step( - next_input_message, first_message=False, skip_verify=no_verify - ) + ( + new_messages, + heartbeat_request, + function_failed, + token_warning, + ) = memgpt_agent.step(next_input_message, first_message=False, skip_verify=no_verify) counter += 1 # Chain stops @@ -225,7 +228,10 @@ def _command(self, user_id: str, agent_id: str, command: str) -> Union[str, None if amount == 0: memgpt_agent.interface.print_messages(memgpt_agent.messages, dump=True) else: - memgpt_agent.interface.print_messages(memgpt_agent.messages[-min(amount, len(memgpt_agent.messages)) :], dump=True) + memgpt_agent.interface.print_messages( + memgpt_agent.messages[-min(amount, len(memgpt_agent.messages)) :], + dump=True, + ) elif command.lower() == "dumpraw": memgpt_agent.interface.print_messages_raw(memgpt_agent.messages) diff --git a/memgpt/server/utils.py b/memgpt/server/utils.py index cc444166c2..33006baab7 100644 --- a/memgpt/server/utils.py +++ b/memgpt/server/utils.py @@ -1,6 +1,11 @@ def condition_to_stop_receiving(response): """Determines when to stop listening to the server""" - if response.get("type") in ["agent_response_end", "agent_response_error", "command_response", "server_error"]: + if response.get("type") in [ + "agent_response_end", + "agent_response_error", + "command_response", + "server_error", + ]: return True else: return False diff --git a/memgpt/server/ws_api/example_client.py b/memgpt/server/ws_api/example_client.py index e8b4d39384..8bae33e4d2 100644 --- a/memgpt/server/ws_api/example_client.py +++ b/memgpt/server/ws_api/example_client.py @@ -77,7 +77,11 @@ async def basic_cli_client(): # Send a message to the agent try: - await send_message_and_print_replies(websocket=websocket, user_message=user_input, agent_id=AGENT_NAME) + await send_message_and_print_replies( + websocket=websocket, + user_message=user_input, + agent_id=AGENT_NAME, + ) retry_attempts = 0 except websockets.exceptions.ConnectionClosedError: print("Connection to server was lost. Attempting to reconnect...") diff --git a/memgpt/server/ws_api/server.py b/memgpt/server/ws_api/server.py index 3cecc1c807..5502c8fdc1 100644 --- a/memgpt/server/ws_api/server.py +++ b/memgpt/server/ws_api/server.py @@ -83,7 +83,11 @@ async def handle_client(self, websocket, path): await websocket.send(protocol.server_agent_response_start()) try: # self.run_step(user_message) - self.server.user_message(user_id="NULL", agent_id=data["agent_id"], message=user_message) + self.server.user_message( + user_id="NULL", + agent_id=data["agent_id"], + message=user_message, + ) except Exception as e: print(f"[server] self.server.user_message failed with:\n{e}") print(f"{traceback.format_exc()}") diff --git a/memgpt/system.py b/memgpt/system.py index 22e205980b..bbf2577dcd 100644 --- a/memgpt/system.py +++ b/memgpt/system.py @@ -28,7 +28,11 @@ def get_initial_boot_messages(version="startup"): }, }, # obligatory function return message - {"role": "function", "name": "send_message", "content": package_function_response(True, None)}, + { + "role": "function", + "name": "send_message", + "content": package_function_response(True, None), + }, ] elif version == "startup_with_send_message_gpt35": @@ -37,10 +41,17 @@ def get_initial_boot_messages(version="startup"): { "role": "assistant", "content": "*inner thoughts* Still waiting on the user. Sending a message with function.", - "function_call": {"name": "send_message", "arguments": '{\n "message": "' + f"Hi, is anyone there?" + '"\n}'}, + "function_call": { + "name": "send_message", + "arguments": '{\n "message": "' + f"Hi, is anyone there?" + '"\n}', + }, }, # obligatory function return message - {"role": "function", "name": "send_message", "content": package_function_response(True, None)}, + { + "role": "function", + "name": "send_message", + "content": package_function_response(True, None), + }, ] else: @@ -49,7 +60,11 @@ def get_initial_boot_messages(version="startup"): return messages -def get_heartbeat(reason="Automated timer", include_location=False, location_name="San Francisco, CA, USA"): +def get_heartbeat( + reason="Automated timer", + include_location=False, + location_name="San Francisco, CA, USA", +): # Package the message with time and location formatted_time = get_local_time() packaged_message = { @@ -64,7 +79,11 @@ def get_heartbeat(reason="Automated timer", include_location=False, location_nam return json.dumps(packaged_message) -def get_login_event(last_login="Never (first login)", include_location=False, location_name="San Francisco, CA, USA"): +def get_login_event( + last_login="Never (first login)", + include_location=False, + location_name="San Francisco, CA, USA", +): # Package the message with time and location formatted_time = get_local_time() packaged_message = { @@ -79,7 +98,13 @@ def get_login_event(last_login="Never (first login)", include_location=False, lo return json.dumps(packaged_message) -def package_user_message(user_message, time=None, include_location=False, location_name="San Francisco, CA, USA", name=None): +def package_user_message( + user_message, + time=None, + include_location=False, + location_name="San Francisco, CA, USA", + name=None, +): # Package the message with time and location formatted_time = time if time else get_local_time() packaged_message = { diff --git a/memgpt/utils.py b/memgpt/utils.py index 7b0ea1b8b0..89e63add99 100644 --- a/memgpt/utils.py +++ b/memgpt/utils.py @@ -165,7 +165,12 @@ def get_schema_diff(schema_a, schema_b): linked_function_json = json.dumps(schema_b, indent=2) # Compute the difference using difflib - difference = list(difflib.ndiff(f_schema_json.splitlines(keepends=True), linked_function_json.splitlines(keepends=True))) + difference = list( + difflib.ndiff( + f_schema_json.splitlines(keepends=True), + linked_function_json.splitlines(keepends=True), + ) + ) # Filter out lines that don't represent changes difference = [line for line in difference if line.startswith("+ ") or line.startswith("- ")] diff --git a/poetry.lock b/poetry.lock index 6bd13a3396..190f0206fa 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "aiohttp" @@ -688,6 +688,17 @@ files = [ [package.extras] graph = ["objgraph (>=1.7.2)"] +[[package]] +name = "diskcache" +version = "5.6.3" +description = "Disk Cache -- Disk and file backed persistent cache." +optional = true +python-versions = ">=3" +files = [ + {file = "diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19"}, + {file = "diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc"}, +] + [[package]] name = "distlib" version = "0.3.7" @@ -771,6 +782,43 @@ docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1 testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] +[[package]] +name = "flaml" +version = "2.1.1" +description = "A fast library for automated machine learning and tuning" +optional = true +python-versions = ">=3.6" +files = [ + {file = "FLAML-2.1.1-py3-none-any.whl", hash = "sha256:ba34f1a06f3cbc6bb23a2ea4830a264375f6bba497f402122a73e42647a15535"}, + {file = "FLAML-2.1.1.tar.gz", hash = "sha256:53e94aacc996da80fe779bc6833d3b25c80c77fe11667d0912798e49293282eb"}, +] + +[package.dependencies] +NumPy = ">=1.17.0rc1" + +[package.extras] +autogen = ["diskcache", "openai (==0.27.8)", "termcolor"] +automl = ["lightgbm (>=2.3.1)", "pandas (>=1.1.4)", "scikit-learn (>=0.24)", "scipy (>=1.4.1)", "xgboost (>=0.90)"] +autozero = ["packaging", "pandas", "scikit-learn"] +azureml = ["azureml-mlflow"] +benchmark = ["catboost (>=0.26)", "pandas (==1.1.4)", "psutil (==5.8.0)", "xgboost (==1.3.3)"] +blendsearch = ["optuna (==2.8.0)", "packaging"] +catboost = ["catboost (>=0.26)"] +forecast = ["hcrystalball (==0.1.10)", "holidays (<0.14)", "prophet (>=1.0.1)", "pytorch-forecasting (>=0.9.0)", "pytorch-lightning (==1.9.0)", "statsmodels (>=0.12.2)", "tensorboardX (==2.6)"] +hf = ["datasets", "nltk", "rouge-score", "seqeval", "transformers[torch] (==4.26)"] +mathchat = ["diskcache", "openai (==0.27.8)", "pydantic (==1.10.9)", "sympy", "termcolor", "wolframalpha"] +nlp = ["datasets", "nltk", "rouge-score", "seqeval", "transformers[torch] (==4.26)"] +nni = ["nni"] +notebook = ["jupyter"] +openai = ["diskcache", "openai (==0.27.8)"] +ray = ["ray[tune] (>=1.13,<2.0)"] +retrievechat = ["chromadb", "diskcache", "openai (==0.27.8)", "sentence-transformers", "termcolor", "tiktoken"] +spark = ["joblib (<1.3.0)", "joblibspark (>=0.5.0)", "pyspark (>=3.2.0)"] +synapse = ["joblib (<1.3.0)", "joblibspark (>=0.5.0)", "optuna (==2.8.0)", "pyspark (>=3.2.0)"] +test = ["catboost (>=0.26,<1.2)", "coverage (>=5.3)", "dataclasses", "datasets", "hcrystalball (==0.1.10)", "ipykernel", "joblib (<1.3.0)", "joblibspark (>=0.5.0)", "lightgbm (>=2.3.1)", "mlflow", "nbconvert", "nbformat", "nltk", "openml", "optuna (==2.8.0)", "packaging", "pandas (>=1.1.4)", "pre-commit", "psutil (==5.8.0)", "pydantic (==1.10.9)", "pyspark (>=3.2.0)", "pytest (>=6.1.1)", "pytorch-forecasting (>=0.9.0,<=0.10.1)", "pytorch-lightning (<1.9.1)", "requests (<2.29.0)", "rgf-python", "rouge-score", "scikit-learn (>=0.24)", "scipy (>=1.4.1)", "seqeval", "statsmodels (>=0.12.2)", "sympy", "tensorboardX (==2.6)", "thop", "torch", "torchvision", "transformers[torch] (==4.26)", "wolframalpha", "xgboost (>=0.90)"] +ts-forecast = ["hcrystalball (==0.1.10)", "holidays (<0.14)", "prophet (>=1.0.1)", "statsmodels (>=0.12.2)"] +vw = ["scikit-learn", "vowpalwabbit (>=8.10.0,<9.0.0)"] + [[package]] name = "flatbuffers" version = "23.5.26" @@ -2837,6 +2885,34 @@ files = [ [package.dependencies] pyasn1 = ">=0.4.6,<0.6.0" +[[package]] +name = "pyautogen" +version = "0.2.0" +description = "Enabling Next-Gen LLM Applications via Multi-Agent Conversation Framework" +optional = true +python-versions = ">=3.8, <3.12" +files = [ + {file = "pyautogen-0.2.0-py3-none-any.whl", hash = "sha256:d7bf4d239f85152e191026d8173f649e256c431cf31b93ca3629cd2f0c525a46"}, + {file = "pyautogen-0.2.0.tar.gz", hash = "sha256:858f2d15eaa68f043f7b67b975a6d27f738c98ca4d7e0e96b400061c0ac3e692"}, +] + +[package.dependencies] +diskcache = "*" +flaml = "*" +openai = ">=1.2,<2.0" +python-dotenv = "*" +termcolor = "*" +tiktoken = "*" + +[package.extras] +blendsearch = ["flaml[blendsearch]"] +graphs = ["matplotlib (>=3.8.1,<3.9.0)", "networkx (>=3.2.1,<3.3.0)"] +lmm = ["pillow", "replicate"] +mathchat = ["pydantic (==1.10.9)", "sympy", "wolframalpha"] +retrievechat = ["chromadb", "ipython", "pypdf", "sentence-transformers"] +teachable = ["chromadb"] +test = ["coverage (>=5.3)", "ipykernel", "nbconvert", "nbformat", "pre-commit", "pytest (>=6.1.1)", "pytest-asyncio"] + [[package]] name = "pydantic" version = "2.5.2" @@ -3771,6 +3847,20 @@ files = [ [package.extras] doc = ["reno", "sphinx", "tornado (>=4.5)"] +[[package]] +name = "termcolor" +version = "2.4.0" +description = "ANSI color formatting for output in terminal" +optional = true +python-versions = ">=3.8" +files = [ + {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, + {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, +] + +[package.extras] +tests = ["pytest", "pytest-cov"] + [[package]] name = "tiktoken" version = "0.5.2" @@ -4793,6 +4883,7 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.link testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] [extras] +autogen = ["pyautogen"] dev = ["black", "datasets", "pre-commit", "pytest", "pytest-asyncio"] local = ["huggingface-hub", "torch", "transformers"] postgres = ["pg8000", "pgvector", "psycopg", "psycopg-binary", "psycopg2-binary"] @@ -4801,4 +4892,4 @@ server = ["fastapi", "uvicorn", "websockets"] [metadata] lock-version = "2.0" python-versions = "<3.12,>=3.9" -content-hash = "4f675213d5a79f001bfb7441c9fba23ae114079ec61a30b0c88833c5427f152e" +content-hash = "3f018f93bdcd9a1f104116a79bcfd1847cde22ee9f35912447e0c132846358c8" diff --git a/pyproject.toml b/pyproject.toml index 00ac4d9c7c..b7d3c00d02 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,12 +54,14 @@ uvicorn = {version = "^0.24.0.post1", optional = true} chromadb = "^0.4.18" pytest-asyncio = {version = "^0.23.2", optional = true} pydantic = "^2.5.2" +pyautogen = {version = "0.2.0", optional = true} [tool.poetry.extras] local = ["torch", "huggingface-hub", "transformers"] postgres = ["pgvector", "psycopg", "psycopg-binary", "psycopg2-binary", "pg8000"] dev = ["pytest", "pytest-asyncio", "black", "pre-commit", "datasets"] server = ["websockets", "fastapi", "uvicorn"] +autogen = ["pyautogen"] [build-system] requires = ["poetry-core"] diff --git a/tests/test_schema_generator.py b/tests/test_schema_generator.py index a68d241b56..448ab248e4 100644 --- a/tests/test_schema_generator.py +++ b/tests/test_schema_generator.py @@ -43,7 +43,12 @@ def test_schema_generator(): "description": "Sends a message to the human user.", "parameters": { "type": "object", - "properties": {"message": {"type": "string", "description": "Message contents. All unicode (including emojis) are supported."}}, + "properties": { + "message": { + "type": "string", + "description": "Message contents. All unicode (including emojis) are supported.", + } + }, "required": ["message"], }, } diff --git a/tests/test_storage.py b/tests/test_storage.py index fc941fa13b..360434f2f3 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -19,7 +19,10 @@ import argparse -@pytest.mark.skipif(not os.getenv("PGVECTOR_TEST_DB_URL") or not os.getenv("OPENAI_API_KEY"), reason="Missing PG URI and/or OpenAI API key") +@pytest.mark.skipif( + not os.getenv("PGVECTOR_TEST_DB_URL") or not os.getenv("OPENAI_API_KEY"), + reason="Missing PG URI and/or OpenAI API key", +) def test_postgres_openai(): if not os.getenv("PGVECTOR_TEST_DB_URL"): return # soft pass @@ -27,7 +30,10 @@ def test_postgres_openai(): return # soft pass # os.environ["MEMGPT_CONFIG_PATH"] = "./config" - config = MemGPTConfig(archival_storage_type="postgres", archival_storage_uri=os.getenv("PGVECTOR_TEST_DB_URL")) + config = MemGPTConfig( + archival_storage_type="postgres", + archival_storage_uri=os.getenv("PGVECTOR_TEST_DB_URL"), + ) print(config.config_path) assert config.archival_storage_uri is not None config.archival_storage_uri = config.archival_storage_uri.replace( @@ -38,7 +44,11 @@ def test_postgres_openai(): embed_model = embedding_model() - passage = ["This is a test passage", "This is another test passage", "Cinderella wept"] + passage = [ + "This is a test passage", + "This is another test passage", + "Cinderella wept", + ] db = PostgresStorageConnector(name="test-openai") @@ -77,7 +87,11 @@ def test_chroma_openai(): config.save() embed_model = embedding_model() - passage = ["This is a test passage", "This is another test passage", "Cinderella wept"] + passage = [ + "This is a test passage", + "This is another test passage", + "Cinderella wept", + ] db = ChromaStorageConnector(name="test-openai") @@ -98,21 +112,29 @@ def test_chroma_openai(): @pytest.mark.skipif( - not os.getenv("LANCEDB_TEST_URL") or not os.getenv("OPENAI_API_KEY"), reason="Missing LANCEDB URI and/or OpenAI API key" + not os.getenv("LANCEDB_TEST_URL") or not os.getenv("OPENAI_API_KEY"), + reason="Missing LANCEDB URI and/or OpenAI API key", ) def test_lancedb_openai(): assert os.getenv("LANCEDB_TEST_URL") is not None if os.getenv("OPENAI_API_KEY") is None: return # soft pass - config = MemGPTConfig(archival_storage_type="lancedb", archival_storage_uri=os.getenv("LANCEDB_TEST_URL")) + config = MemGPTConfig( + archival_storage_type="lancedb", + archival_storage_uri=os.getenv("LANCEDB_TEST_URL"), + ) print(config.config_path) assert config.archival_storage_uri is not None print(config) embed_model = embedding_model() - passage = ["This is a test passage", "This is another test passage", "Cinderella wept"] + passage = [ + "This is a test passage", + "This is another test passage", + "Cinderella wept", + ] db = LanceDBConnector(name="test-openai") @@ -151,7 +173,11 @@ def test_postgres_local(): embed_model = embedding_model() - passage = ["This is a test passage", "This is another test passage", "Cinderella wept"] + passage = [ + "This is a test passage", + "This is another test passage", + "Cinderella wept", + ] db = PostgresStorageConnector(name="test-local") @@ -188,7 +214,11 @@ def test_lancedb_local(): embed_model = embedding_model() - passage = ["This is a test passage", "This is another test passage", "Cinderella wept"] + passage = [ + "This is a test passage", + "This is another test passage", + "Cinderella wept", + ] db = LanceDBConnector(name="test-local")